UnityでFirebaseプラグインを新しくしたら、XCodeのビルドでエラーが出た件
_objc_class_$_firanalytics", referenced from unity
というようなリンカエラー。
Unity-iPhone.xcodeprojの方でビルドしようとしたいたんですが、pod installしてUnity-iPhone.xcworkspaceを生成して、そっちでビルドすればOKというとこまではわかった。
しかし、pod installをしようとすると、
Firebase pod install - pod 'Firebase/Analytics' - Required a higher minimum deployment target Specs satisfying the `Firebase/Analytics (= 4.1.0)` dependency were found, but they required a higher minimum deployment target.
というエラーがでる。
Podfileの
platform :ios, '6.0'
を
platform :ios, '7.0'
にすることで解決した。が、何で解決したのか、よくわかっていない。
Unityで作ったアプリでExperiaでのみAdMobのバナーがちょっと上に出る問題
ExperiaでのみAdMobのバナーがちょっと上に出るという問題が以前からちょこちょこと報告が上がっていたんですが、一体どうしてExperiaでのみそんなことになるのか分からず途方にくれていました。
こんなふうに表示されてしまう↓
ただしくはこう↓
場合によってはゲームのUIとも被ってしまって困っていたんですが、ふとしたことで直りました。
それは、AndroidManifest.xmlのapplicationタグ部分が
<application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false">
だったのをandroid:theme="@android:style/Theme.NoTitleBar"を追加して、
<application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:theme="@android:style/Theme.NoTitleBar" >
こうしたら直りました。
Androidの仕様に疎く、なぜこれで直ったのか分からないのですが、とりあえず直ったので共有しておきます。
UnityでiOSとかでよくあるトグルスイッチを作りたい。
iOSとかである、こーいうトグルスイッチを作りたい!っと思って作ってみました。
まず画から。
こーいう緑色で楕円のONの画像に、
こーいう灰色で楕円のOFFの画像を被せ、
さらに白い丸いボタン画像を載せます。
Scriptで、タッチするとボタンが右に行って、OFF画像が縮小して消え、もう一回押すとボタンが左に行ってOFF画像が拡大して現れるようにします。
ソースはだいたいこんな感じ↓(Tweenアニメするためにオレオレライブラリが入ってますが、そこはDoTweenとかのメジャーなやつに置き換えてもらえばうまく動くかと思います。)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using WK.Tween; public class ToggleSwitchController : MonoBehaviour, IPointerClickHandler { [SerializeField] Transform button; [SerializeField] Transform inactiveBackground; [SerializeField] float duration = 0.1f; [SerializeField] UnityEvent onEvent; [SerializeField] UnityEvent offEvent; bool currToggle = false; public bool CurrToggle { get { return currToggle; } } private enum EState { idle , gotoOn , gotoOff } private EState currState = 0; private EState nextState = 0; private int stateCounter = 0; static readonly Vector3 cOnPos = new Vector3( 100.0f, 0.0f, 0.0f ); static readonly Vector3 cOffPos = new Vector3( -100.0f, 0.0f, 0.0f ); //------------------------------------------------------------------------------ void Awake() { stateCounter = 0; currState = EState.idle; nextState = EState.idle; } //------------------------------------------------------------------------------ void Update() { ++stateCounter; if( currState != nextState ) { currState = nextState; stateCounter = 0; } switch( currState ) { case EState.gotoOn: updateGoToOn(); break; case EState.gotoOff: updateGoToOff(); break; } } //------------------------------------------------------------------------------ private void changeState( EState next_state ) { nextState = next_state; } //------------------------------------------------------------------------------ private void updateGoToOn() { if( stateCounter == 0 ) { inactiveBackground.TwScale( Vector3.zero, duration ); button.TwMove( cOnPos, duration ).OnComplete( () => { changeState( EState.idle ); onEvent.Invoke(); } ); } } //------------------------------------------------------------------------------ private void updateGoToOff() { if( stateCounter == 0 ) { inactiveBackground.TwScale( Vector3.one, duration ); button.TwMove( cOffPos, duration ).OnComplete( () => { changeState( EState.idle ); offEvent.Invoke(); } ); } } //------------------------------------------------------------------------------ public bool GoToOnImmediately() { if( currState == EState.idle || nextState == EState.idle ) { inactiveBackground.localScale = Vector3.zero; button.localPosition = cOnPos; currToggle = true; changeState( EState.idle ); return true; } return false; } //------------------------------------------------------------------------------ public bool GoToOffImmediately() { if( currState == EState.idle || nextState == EState.idle ) { inactiveBackground.localScale = Vector3.one; button.localPosition = cOffPos; currToggle = false; changeState( EState.idle ); return true; } return false; } //------------------------------------------------------------------------------ public bool GoToOn() { if( currState == EState.idle ) { changeState( EState.gotoOn ); return true; } return false; } //------------------------------------------------------------------------------ public bool GoToOff() { if( currState == EState.idle ) { changeState( EState.gotoOff ); return true; } return false; } //------------------------------------------------------------------------------ public virtual void OnPointerClick( PointerEventData event_data ) { if( currState == EState.idle ) { currToggle ^= true; if( currToggle ) { GoToOn(); } else { GoToOff(); } } } }
こちらにソース一式があります。
github.com
UnityでBGMのイントロ付きループに挑戦
最初に試したのはループ終端まで来たのを確認してAudioSource.timeをループ開始地点に飛ばす方法
www.shibuya24.info
次に試したのが、イントロ用とループ用でAudioSourceを2つ用意してループ用のAudioSourceをPlayScheduledでイントロ長分ずらして再生する方法。
qiita.com
自分の実装が良くなかったのかもしれないのですが、どちらの方法でもstreaming再生した時に音がプツッと途切れる事案が発生して断念。
結局Assetを購入して解決。
https://www.assetstore.unity3d.com/en/#!/content/51095
$21.6しましたが、今のところ途切れることはなく順調に動いているので満足してます。
UnityでビルドしたiOS版アプリがcompute_class_bitmap: Invalid type 13 for fieldと言われて落ちる
UnityでビルドしたiOS版アプリでcompute_class_bitmap: Invalid type 13 for fieldと言われて落ちる事案が発生しました。
IL2CPPでビルドすれば大丈夫。けどMonoだとアウト。Monoのほうがビルドが爆速なので、私、実機で動作確認する際は結構Monoでビルドするのです。
調べていくとどうも自作のTreeコンテナクラスが悪いようでした。
public class TreeContainer<T> { private List<TreeContainer<T>> children; ...
childrenのとこの括弧が二重になっているGenericが駄目みたいです。
こちらの記事によると、generic of genericはAOTコンパイルではうまくいかないんだそうです。なのでiOS以外では問題なく動いていたと。
悩ましい。
Mac OS Sierraで「ろ」のキーにbackslashを割り当てる
今までKarabiner-Elementsでなんとかしようとしてたけどうまくいかなくて鬱屈とした日々を送っていたのですが、今日ひさしぶりにトライしてみようとググってみたら、こんな記事を見つけました。
「英かな」というアプリを使うといけると。
早速試してみたら簡単に導入できて快適。
元記事では直接バックスラッシュ指定していなかったけど、直接バックスラッシュ指定しても問題なさそうだったのでそういうふうにしています。
こんな感じ↑
数字が徐々に変わって目的の数値に行くスクリプト
ゲームのUIで、こんな感じの演出ってよくあると思います。スクリプトを書きました。
以下のスクリプトをTextコンポーネントを持ったオブジェクトに貼り付けて、SlideToNumber( from_number, to_number, duration )を呼べば、from_numberからto_numberへduration秒かけて遷移します。
using System; using System.Collections; using UnityEngine; using UnityEngine.UI; [RequireComponent(typeof(Text))] public class SlideNumberEffectController : MonoBehaviour { public Action OnComplete = null;//終わった時のコールバック private Text text; private float speed; private float number; private float targetNumber; private Coroutine playCoroutine = null; #if UNITY_EDITOR [SerializeField] private int debugToNumber = 10; [SerializeField] private float debugDuration = 1.0f; #endif void Awake() { text = GetComponent<Text>(); } // // 数値をすぐにセット // public void SetNumber( int n ) { number = (float)n; text.text = ( (int)number ).ToString(); if( playCoroutine != null ) { StopCoroutine( playCoroutine ); playCoroutine = null; } } // // from_number から to_number に徐々に移行 // public void SlideToNumber( int from_number, int to_number, float duration ) { SetNumber( from_number ); SlideToNumber( to_number, duration ); } // // 今の値から から to_number に徐々に移行 // public void SlideToNumber( int to_number, float duration ) { targetNumber = to_number; speed = ( ( targetNumber - number ) / duration ); if( playCoroutine != null ) { StopCoroutine( playCoroutine ); } playCoroutine = StartCoroutine( "slideTo" ); } private IEnumerator slideTo() { while( true ) { var delta = speed * Time.deltaTime; var next_number = number + delta; text.text = ( (int)next_number ).ToString(); number = next_number; if( UnityEngine.Mathf.Sign( speed ) * ( targetNumber - number ) <= 0.0f ) { break; } yield return null; } playCoroutine = null;; number = targetNumber; text.text = ( (int)number ).ToString(); if( OnComplete != null ) { OnComplete(); OnComplete = null; } } #if UNITY_EDITOR [ContextMenu( "Test" )] void Test() { SlideToNumber( debugToNumber, debugDuration ); } #endif }
おわり。