後もう少しで坊主アプリの検証は終わらせます。
//tips
//AnimatorStateInfoの使い方
AnimatorStateInfoはアニメーターコントローラの現在のステートの情報を表す型で、現在のAnimatorがどのレイヤーにおり、レイヤーの一つのボックスを指定し、どのような条件で動作させるのかを、記述したい時に使う。
AnimatorStateInfo stateInfo =
imageMokugyo.GetComponent<animator>.GetCurrentAnimatorStateInfo(0)
imageMokugyoのオブジェクトに組み込まれたアニメーターをGetComponent<animator>で呼び出し、そのアニメーターのレイヤー0番(初期状態)をGetCurrentAnimatorStateInfo(0)を取り、変数stateInfoに代入する。
このレイヤーは作成したAnimatorのparametersの横にあるLayersで編集できる。
今回はレイヤーをいじっていないのでBase Layerのままとなる。
imageMokugyoオブジェクトに付加したアニメーションのBase Layerの中には現在、
Entry,NewState,get@ImageMokugyo,AnyStateがある。
get@ImageMokugyoは木魚の画像の大きさを大きくしたり小さくしたりするアニメーションの名前である。
このBase Layerのget@ImageMokugyoを基準として、
stateInfo.fullpathHash==Animator.StringToHash(“Base Layer.get@ImageMokugyo”)
fullpathHashプロパティが「Base Layer.get@ImageMokugyo」と一致しているかを確認する。
fullpathHashは現在のアニメーションの「レイヤー名.ステート名」をIDに変換したものなので、右辺に確認したい“Base Layer.get@ImageMokugyo”、つまりアニメーションが再生されている状態を入れる。
“Base Layer.get@ImageMokugyo”をそのまま入れるだけではダメで、右辺もfullpathHashのIDの型と同じに直す必要があり、その際にAnimator.StringToHashメソッドが用いられる。
左辺で現在のレイヤー名.ステート名(どのボックスにいる状況か)を調べ、右辺の状態と一致した際に条件発生とするのが一般的なやり方となる。
木魚スクリプトの場合
AnimatorStateInfo stateInfo =
imageMokugyo.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0);
if(stateInfo.fullPathHash==
Animator.StringToHash(“Base Layer.get@ImageMokugyo”))
{
imageMokugyo.GetComponent<Animator>().Play(stateInfo.fullPathHash,0,0f);
}
else
{
imageMokugyo.GetComponent<Animator>().SetTrigger(“isGetScore”);
}
結果の部分で出てきたPlay()はアニメーションの際に使うもので
Animatorコンポーネント.Play(ステートのID,レイヤー番号,再生時間の位置)
と表される。
上のifの結果はBase Layer.get@ImageMokugyoの0秒目、最初から再生する指示。
else以下は遷移の名前としてAnimationに設置したisGetScoreを呼び遷移。
animator.SetTrigger("Triggerの名前”);で遷移できる。
下記に一般的な例も見かけたので引用する。
STATE_PLAYER GetAnimState() {
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (Animator.StringToHash("Base Layer.Panch") == stateInfo.fullPathHash) {
return STATE_PLAYER.PANCH;
} else if (Animator.StringToHash("Base Layer.Walk") == stateInfo.fullPathHash) {
return STATE_PLAYER.WALK;
} else if (Animator.StringToHash("Base Layer.Idle") == stateInfo.fullPathHash) {
return STATE_PLAYER.IDLE;
} else {
return STATE_PLAYER.NONE;
}
}
http://blog.livedoor.jp/f_paul/archives/27309591.html
//主に位置や移動に用いるVector3の使い方
Vector3は何となく使ってしがいがちだが、いくつかのルールを覚えておくとミスが減るので記載する。
Vector3 vec = new Vector3(1.0f,2.0f,3.0f);
このVector3内部のx,y,z変数は小数点まで含む数字を扱うfloat型となっているので.0fを忘れない。
Vectorの素晴らしいところは初期設定のポジションを変更できるところで、transformの場合、下記のようにしてしまうとエラーになる。
初期設定のポジション(0,0,0)のものを(3,4,0)に開始時移動。
void Start()
{
transform.position.x = 3.0f;
transform.position.y = 4.0f;
}
これはエラーとなる。
一方で、Vector3で再定義する形にするときちんと機能する。
void Start()
{
transform.position = new Vector3(3.0f, 4.0f,0.0f);
}
//Vectorを活用し、物体の移動を加工するアニメーションDOTweenを実行
アセットストアで公開されているDOtweenはオブジェクトに特殊な動きを付与することができるクラスやメソッドの集まりである。
DOtweenをダウンロード後、スクリプトに反映するには
using DG.Tweening;
を最初に宣言する必要がある。
public void TouchOrb()
{
・・・
RectTransform rect=GetComponent<RectTransform>();
Vector3[]path=
{
new Vector3(rect.localPosition.x*1.5f,300f,0f), //アクションの中間経由点
new Vector(0f,150f,0f) //アクションの終点
};
ここではVector3の配列でオーブの動きの軌跡の中間点と終点を定義している。
rect.localPositionで現時点のx座標を調べ、その座標を1.5倍したものとy座標を組み合わせている。
これらの中間点と終点へ現時点のオーブを曲線を描くようにして飛ばしたい時にDOTweenが役に立つ。
軌跡に沿った動きをさせるためにDOTweenのメソッドである
Transform.DOLocalPath(座標配列,時間,パスタイプ);
を使用する。
rect.DOLocalPath(path, 0.5f, PathType.CatmullRom)
.SetEase(Ease.OutQuad)
.OnComplete(AddorbPoint);
pathは先ほどの座標配列のことで、0.5fは処理を0.5秒で行うことを示し、PathType.CatmullRomはCatmullRom曲線軌道を表す。
直線軌道は、Linearである。
その後に続く、SetEaseメソッドは処理を等速ではなく、加速減速を交えて、より動きに現実味を持たせるもの。
OnCompleteメソッドはアニメーションの終了時に呼び出すもので、今回はAddOrbPointメソッドを呼び出して、ポイント獲得処理に移らせている。
rect.DOScale
(
new Vector3(0.5f,0.5f,0f),
0.5f
)
この処理はオーブを徐々に小さくするアニメーションで
Transform.DOScale(目標サイズ,目標サイズまでの到達時間);
となり、上下左右半分になるまでに0.5秒の時間をかけると記載してある。
//UnityのPlayerPrefsによる保存
プレイデータを保存するためにはUnityのPlayerPrefsを使用し、これは各OSの特定の場所にデータを保存する。
この際、データはアプリごとに独立しているため、他のデータとの混線は避けられる。
PlayerPrefsは「書き込み」と「読み出し」をキーを通して行う。
例えば、
PlayerPrefs.SetInt(“TEST”,100); //TESTキーで書き込み
int v = PlayerPrefs.GetInt(“TEST”); //TESTキーで読み出し
となり、
値を設定するSet~と値を読み取るGet~があり、それぞれ型に対応している。
Setメソッドで書き込んだものは基本的にアプリ終了時に保存されるようになっているが、保存前にクラッシュしてしまう恐れもあるので、大事なデータは変更された値をその時点で保存するsaveを使う。
データを保存したい場合には、保存用の器が必要となり、定数で用意されることが多い。
「スコア」「レベル」「オーブ数」「時間」をPlayerPrefsに保存したい場合は、
private const string KEY_SCORE=“SCORE”;
private const string KEY_LEVEL=“LEVEL”;
private const string KEY_ORB=“ORB”;
private const string KEY_TIME=“TIME”;
と先に宣言しておく。
SaveGameDataメソッドを新たに作ると
void SaveGameData(){
PlayerPrefs.SetInt(KEY_SCORE, score);
PlayerPrefs.SetInt(KEY_LEVEL, templeLevel);
PlayerPrefs.SetInt(KEY_ORB, currentOrb);
PlayerPrefs.SetInt(KEY_TIME, lastDateTime.ToBinary().ToString());
一通り定数のワードをキーにして、数値を保有する変数を書き込むようにされている。
最後のlastDateTime.ToBinary().ToString())はlastDateTimeがDateTime型なので、PlayerPrefsが保存できる32ビットまで落とすために、ToBinaryで64ビットのバイナリ値という整数の一種に変換し、ToStringで文字列にすることで64ビットをさらに32ビットまで落とすことで文字列データとして保存する。
バイナリ値とは2進法のことで1000100などのような0と1で表される値を指す。
コンピュータのソフトウェアでは全て数値で表され、その数値を演算することで出力時に音や色を出すことができる。
この数値は2進数の有限な桁数(ビット数)での表現となり、各型には表される上限の桁数を持つ。
例えば、
小数点まで表されるfloat型、整数を表すint型はビット数32となる。
これらのサイズまで62または64ビットあるDateTime型のサイズ落としてあげる処理を.ToBinary().ToString()で行っている。
これらが書き込めたら最後に
PlayerPrefs.Save();
でセーブを行う。
逆に初期設定は
score = PlayerPrefs.GetInt(KEY_SCORE,0);
templeLevel = PlayerPrefs.GetInt(KEY_LEVEL,0);
currentOrb = PlayerPrefs.GetInt(KEY_ORB,0);
string time =PlayerPrefs.GetString(KEY_TIME,””);
if(time=“”)
{
lastDateTime=DateTime.UtcNow;
}
else
{
long temp = Convert.ToInt64(time);
lastDateTime=DateTime.FromBinary(temp);
}
もし、時間が空白であったらその時点の記録を作り、それ以外の記録がある場合は、その32ビットのStringで記載された内容を64ビットの数値データに直し、その数値データからDateTime構造体に直している。