なかなか坊主アプリのコードのtipsまとめが終わらないですが、やっといた方がオリジナル作成の精度が上がるのでやります。
この際、今まで作成したのも全て見直そうかと思います。
//tips
//Datetime 構造体でゲーム内外の時間経過を管理する
時間計算のために.NET FrameworkにあるDateTimeとTimeSpanを使うので
最初にusing System;を宣言に追加する。
次のオーブが発生する秒数を定数であるRESPAWN_TIMEとし、定数なのでvoid Start(){}の前で
private const int RESPAWN_TIME = 5;
5秒間隔でオーブが発生するようにする。
現在のオーブの数も変数で管理し、
private int currentOrb = 0;
現在のオーブは0と設定しておく。
前回のオーブ生成時間も記録し、そこから5秒たっていれば次のオーブが発生するようにするので
private DateTime lastDateTime;
で前回の生成時間を設定する。
このDateTimeは型の一つで、intやstringのような性質を持つ。
そのためstringで扱う必要がある際には.ToStringとして型を変更して時間表示をする。
lastDateTime = DateTime.UtcNow;
UtcNowはその時点での時刻を取得できるので、これによりlastDateTimeにその時刻のDateTime構造体をはめ込む。
5秒おきに増やす処理をDateTime.UtcNow - lastDateTimeで管理するので
void Update()
{
if(currentOrb < MAX_ORB)
{
TimeSpan timespan = DateTime.UtcNow - lastDateTime;
}
if(timeSpan >= TimeSpan.FromSeconds(RESPAWN_TIME))
{
while (timespan >= TimeSpan.FromSeconds(RESPAWN_TIME))
{
CreateNewOrb();
timeSpan-= TimeSpan.FromSeconds(RESPAWN_TIME);
}
}
}
TimeSpan型を用いるのはDateTime型同士の引き算をするとTimeSpan型になってしまうので、最初からTimeSpan型に代入するようにしている。
得られたtimeSpanと定数であるRESPAWN_TIMEを比べるためにRESPAWN_TIMEをTimeSpan.FromSeconds()に入れることでTimeSpan型に直している。
timeSpanがRESPAWN_TIME以上の際には新しくオーブを作り、作成後にtimeSpanから5秒分引き再度whileの処理に戻る形態をとっている。
//画像をトリガーによって切り替える。
画像取り扱うSprite型配列のメンバー変数を定義する。
今回は切替画像を3つに分けたいので
public Sprite[] templePicture = new Sprite[3];
となる。
レベルに合わせて寺の絵を切り替えるメソッドSetTemplePictureとスコアに応じて寺の絵を拡大するメソッドSetTempleScaleを別途定義する。
public void SetTemplePicture(int level)
{
GetComponent<Image>().sprite = templePicture[level];
}
指定したlevelを、先に指定したSprite配列の画像呼び出しに使用する。
public void SetTempleScale(int score, int nextscore)
{
float scale = 0.5f + (((float)score/(float)nextscore)/2.0f);
transform.localScale = new Vector3(scale, scale,1.0f);
}
SetTempleScaleは現在のスコア/目標スコア/2でスコアにより、0~0.5を推移する数字ができ、さらに定数0.5を足すことで50~100%を推移させる数字ができることを利用してscaleを変化させている。
メソッドの引数をどのように取るかも念のため調べましたが色々なバリエーションがありそうです。下記に参考になったものを記載します。
http://dotnetcsharptips.seesaa.net/article/428311640.html
https://ufcpp.net/study/csharp/oo_reference.html
//レベルアップ処理
scoreがnextscoreを越えたらtempleLevelを1増やし、scoreを0に戻す処理を行う。
処理前に下記を追加。
private const int MAX_LEVEL = 2;
Private int nextScore=10;
private int templeLevel=0;
private int[]nextScoreTable=new int[]{10,10,10};
void Start()以下に処理の下記を追加。
nextScore=nextScoreTable[templeLevel];
nextScoreをレベル数値で指定して配列から取得。
imageTemple.GetComponent<TempleManager>().SetTemplePicture(templeLevel);
レベル数値をもとに画像を取得。
imageTemple.GetComponent<TempleManager>().SetTempleScale(score,nextScore);
現在のscoreと先に得られたnextScoreをもとにSetTempleScaleを呼び出し、画像の縮尺の変更。
//エフェクトの重ね順
UIのCanvas内ではヒエラルキー内のオブジェクトの順番でレイヤーが決まるので、かなりわかりやすい。
このオブジェクトのレイヤー順はスクリプトでも操作でき、transform.SetSiblingIndexが使える。transform.SetSiblingIndex(0)が最前面レイヤーとなり、数字が増えるごとに後ろに下がっていく。
また、SetSiblingIndex()は意味の通り兄弟内の順序にしか影響を与えないのでcanvas下に並列に置かれている子オブジェクト内での順序を決める際に役に立つ。
void TempleLevelUpEffect()
{
GameObject smoke=(GameObject)Instantiate(smokePrefab);
→smokePrefabのクローン作成
Smoke.transform.SetParent(canvasGame.transform,false);
→canvasGameの座標に合わせローカル座標として記述すると定義
smoke.transform.SetSiblingIndex(2);
smokeインスタンスのレイヤーを最前面から2個後ろにづらす
Destroy(smoke,0.5f)
Destroyに第二引数をつけた場合、対象を破壊するまでの時間を表す。
}
//列挙体と配列の違い
配列は中身に変数を格納するため各要素の値を自由に変更可能だが、列挙体は定数を並べたもの。
enum <列挙体の名前>{<定数1,定数2..>};と表される。
public enum ORB_KIND
{
BLUE,
GREEN,
PURPLE,
}
private ORB_KIND orbKind;
さらに列挙体はswitch-case文と合わせてよく用いられる。caseの値にenumの列挙子を指定することで、条件の場合分けが読みやすくなる。
switch(orbKind)
{
case ORB_KIND.BLUE:
gameManager.GetComponent<GameManager>().GetOrb(1);
break;
case ORB_KIND.GREEN:
gameManager.GetComponent<GameManager>().GetOrb(5);
break;
case ORB_KIND.PURPLE:
gameManager.GetComponent<GameManager>().GetOrb(10);
break;
}
//switch-caseの構造
Switch文は、switch()で受け取った変数値を元に、{}移行で、実行する処理を変えたいときに使用する。
Switch文の構文は
switch( 変数 )
{
case 値A: //変数が値Aのとき実行される
文A
break; // 文Aの実行が終わったらswitchから抜ける。
case 値B:
文B
break;
default: //上記の条件に変数がどれも当てはまらない場合に実行される。
文C
break;
}
コードの見やすさ上
①単純な2分岐であれば、if文
②多分岐(3分岐)以上であればswitch文
などと使い分けられているようです。
//スポーン位置を範囲内にランダムに設定
オーブを範囲内にランダムにスポーンさせたい場合のRandomの使い方を記載。
GameManagerでオーブを生成するメソッドを書く際に、下記のようにCreateOrbを記載している。
public void CreateOrb ()
{
GameObject orb=(GameObject)Instantiate(orbPrefab);
クローンのオーブ生成
orb.transform.SetParent(canvasGame.transform,false);
オーブの座標をcanvasのローカル座標に設定
orb.transform.localPosition=new Vector
(
UnityEngine.Random.Range(-300.0f,300.0f),
UnityEngine.Random.Range(-140.0f,-500.0f),
0f);
}
Random.Range(最小値,最大値)で乱数の範囲を決めることができるのでSetParentでローカル座標に設定した意味がわかる。
今回はRandom.Range(最小値,最大値)が使われているが、他にもUnityで乱数を生成する時によく使われるものにRandom.valueがある。
Random.valueはシンプルで範囲が0fから1.0fまでのランダムな数値(0.11111など)を返す。
float value = Random.value;
小数が使われるためfloat型。
整数を取得したい場合には
int value = Random.Range(X, Y + 1)
などとする。この場合Y+1は生成する値に入らない。X<=value<Y+1となる。
floatにした場合はX<=value<=Y+1となり、Y+1も含まれる。
これらの乱数も規則性があるので、その規則性を崩すために現在日時などを乱数の起点のシード値となるように設定し、Random.InitState(数値)を限りなく予測しづらい乱数に強化して多くの場合使われている。