Unityでフリック入力を使ってフリスビーを投げるゲームを作っていて、以下のような処理が必要だったので、まとめてみました。
Invokeで実装しようとしましたが、Invokeは第一引数で指定されたメソッドを、第二引数で指定された秒数後に実行するものなので、Invoke以降に書かれたコードはどんどん実行されてしまい、今回ほしい機能は作れませんでした。
(注:投げる と 攻撃 は以降同じことを指します。投げた瞬間に攻撃は終了します)
こんなのが作りたい!
- フリック入力でフリスビーを投げて攻撃する。三(卍^o^)卍ドゥルルルルルルルルル
- 攻撃すると、クールタイム(5秒間)に入って、攻撃できなくなる。
- 5秒間経ったら、フリスビーが出現して、また投げられるようになる。
- 任意のタイミングで投げる。三(卍^o^)卍ドゥルルルルルルルルル
- 2に戻る。
それでは順番に作っていきます。
タップやフリックを受け取る
これは、本題ではないので、簡単に書いておきます。AssetStoreのTouchScriptを使って、タップやフリックを受け取れるようにしました。フリック入力でフリスビーのようなものを、相手に投げたかったので、フリックしたら呼ばれるイベントハンドラーを使って、RigidbodyのAddForce()の引数に、プレイヤーが入力したフリックに関する情報を指定して、フリスビーが飛んでいくようにしました。
攻撃可能かを表す変数を用意して、プレイヤーが攻撃したら、攻撃不能にする
攻撃可能かを表す変数はisAttackableとでもしておきます。これをfalseになる)。
フリスビーくんの変数名はdiscにしました。
フリック入力の調整用変数としてspeedを用意しました。
デバッグ時に、UnityのInspectorから見えると便利なのでpublicを使っています。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Collections;
using TouchScript.Gestures;
public class DiscController : MonoBehaviour
{
public GameObject disc;
public bool isAttackable;
public float speed;
// Use this for initialization
void Start()
{
//isAttackableをtrueにしておく
isAttackable = true;
speed = 10.0f;
}
// Update is called once per frame
void Update()
{
}
//=====フリック入力を有効・無効にする部分=====
private void OnEnable()
{
GetComponent<FlickGesture>().StateChanged += HandleFlick;
}
private void OnDisable()
{
// UnsubscribeEvent();
GetComponent<FlickGesture>().Flicked += HandleFlick;
GetComponent<FlickGesture>().MinDistance = 0.5f;
GetComponent<FlickGesture>().FlickTime = 0.01f;
}
//=====ここまで=====
//=====フリック操作に関する部分=====
void HandleFlick(object sender, System.EventArgs e)
{
var gesture = sender as FlickGesture;
//AddForceに渡すVector3の数値を仮置きしている
//例えば、gesture.ScreenFlickVector.xを引数に指定することで、
//画面横方向に大きくフリックすれば、遠くまで飛んでいき
//小さくフリックすれば、あまり飛ばないといったことができる
Vector3 movement = new Vector3(1.0f,2.0f,0.0f);
disc.GetComponent<Rigidbody>().AddForce(movement * speed);
//フリックして、フリスビーが飛んでいったら(AddForceされたら)、isAttackableをfalseにします
isAttackable = false;
}
//=====ここまで=====
}
クールタイム後に、再度攻撃可能にする
このままでは、1回攻撃したら、一生攻撃できなくなってしまうので、isAttackableをtrueに戻す処理をUpdate()の中に追記します。
Update()より前に、攻撃してからの経過時間を表す変数lapseTimeを用意しておきます。
public float lapseTime;
void Start() {
//isAttackableをtrueにしておく
isAttackable = true;
speed = 10.0f;
//lapseTimeを初期化
lapseTime = 0.0f;
}
void Update() {
//isAttackableがfalseなら、直前のフレームからの経過時間を足す
if(isAttackable == false) {
lapseTime += Time.deltaTime;
//lapsetimeが5秒を越えたら、isAttackableをtrueに戻して
//次に備えて、lapseTimeを0で初期化
if(lapseTime >= 5) {
isAttackable = true;
lapseTime = 0.0f;
}
}
}
ここまでできたら、Unityに戻って、対象のゲームオブジェクトにこのスクリプトをつけて、Inspectorのこのスクリプトに関する情報がまとめられている箇所を見つけて、Disc None(Game Object)というところに、フリックで飛ばしたいゲームオブジェクトをHierarchyの中から選んでドラッグ&ドロップします。
攻撃可能になっても、投げるゲームオブジェクトがないので、自動生成する
これは本題ではないので、簡単に書いておきます(近いうちに追記する予定ですが)。プレハブ化して、isAttackableがtrueになった時点で、Instantiateします。
以上のスクリプトで実装できました。Unityで動くことは確認しています。ただ、Instantiateのところはエラーが出るので要研究ですね…(´・ω・`)