最近、趣味でしょぼしょぼゲームを作った。めっちゃ楽しかったけど、嘔吐しそうなほどつまづいたとこを備忘録。
こういう自動で敵の位置に向かって攻撃が飛んでくやつ。
参考文献
たのしい2Dゲームの作り方 Unityではじめるゲーム開発入門
本誌のおまけpdfで三角関数の解説がある。当時おまけpdfまで読み込んでいなくて、後から気がついて喪失感に襲われた。嘘だと言ってよバーニー。。。
環境
Windows 10 Pro 21H1
Unity 2020.3.18f1
Microsoft Visual Studio Community 2019 Version 16.11.15
準備するもの
・プレイヤーキャラ。紹介するコードは全部プレイヤーキャラにアタッチしたスクリプトに記述すること。
・攻撃エフェクト(複数画像のアニメーションにRigidbodyとColliderをつけたりしたPrefabファイルここでは変数nowPrefab)
・敵(全ての敵で共通のTagをつけている前提)
・算数するぞ! っていう気持ち
※敵キャラにつけたTagを利用する。ここでは「Tag Enemy がついているオブジェクト=敵」という考え方で実装する。
概要
流れ
攻撃ボタンが押される
↓
自分から一番近い敵を探す
↓
一番近い敵に攻撃を飛ばす。
↓
連射を防ぐため攻撃中フラグを立てる
まずボタンを押すと攻撃。ここではデフォルトの Fire1 を使う。
Update()でフレーム毎に「Fire1」が押されたか確認。押されたならAttack()メソッドへ。
//オートエイム用角度変数。後で使う。クラス内メソッド外に置く。
float degree = 0.0f;
float rad = 0.0f;
public GameObject nowPrefab; //発射したいプレハブ。
public float shootSpeed; //攻撃の速度力。
bool inAttack = false; //攻撃中フラグ
void Update()
{
if ((Input.GetButton("Fire1")))
{
Attack();
}
}
肝心かなめの攻撃処理本体。
public void Attack()
{
if (inAttack == false)
{
inAttack = true; //攻撃フラグ立てる。連続で攻撃が発生しないようにするため。
//↓++++++++++++一番近い敵探し++++++++++++↓
// タグEnemyのオブジェクトをすべて取得し、10f以内の最も近いエネミーを取得する。
GameObject nearestEnemy = null; //前回の攻撃で一番近かった敵をリセット
float minDis = 10f; //オートエイム範囲。お好みで。
GameObject[] enemys = GameObject.FindGameObjectsWithTag("Enemy");//Enemyタグがついたオブジェクトをすべて配列に格納。
foreach (GameObject enemy in enemys) //全Enemyオブジェクト入り配列をひとつづつループ。
{
float dis = Vector3.Distance(transform.position, enemy.transform.position); //プレイヤーキャラとループ中の敵オブジェクトの距離を引き算して差を出す。
if (dis < minDis) //オートエイム範囲(10f)以内か確認
{
minDis = dis; //今んとこ一番近い敵との距離更新。次のループ用。
nearestEnemy = enemy; //今んとこ一番近い敵オブジェクト更新。
}
}
// foreach が終わった時、nearestEnemyにプレイヤーキャラから一番近い敵が入ってる。
//↑++++++++++++一番近い敵探し++++++++++++↑
if (nearestEnemy != null) //オートエイム有効nullチェック。10f以内にタグEnemy存在。
{
//↓++++++++++++オートエイム++++++++++++↓
Vector2 dt = nearestEnemy.transform.position - transform.position; //nearestEnemyとプレイヤーキャラの距離を引き算。
rad = Mathf.Atan2(dt.y, dt.x); //距離をラジアンへ。
degree = rad * Mathf.Rad2Deg; //ラジアンを角度へ。
//回転
Quaternion r = Quaternion.Euler(0, 0, degree); //プレイヤーキャラからみたnearestEnemyへの角度でQuaternionを用意。
//発射するPrefabを生成。発射したいnowPrefabをプレイヤーキャラの位置に、rの角度で生成する。
GameObject SlashObj = Instantiate(nowPrefab, transform.position, r);
//↑++++++++++++オートエイム++++++++++++↑
//発射するパワーを用意。
float x = Mathf.Cos(degree * Mathf.Deg2Rad); //角度をラジアンに。Horizontal。
float y = Mathf.Sin(degree * Mathf.Deg2Rad); //角度をラジアンに。Vertical。
Vector3 v = new Vector3(x, y) * shootSpeed; //Vector3生成。 変数shootSpeedを大きくすると力が大きくなる。お好みで。
Rigidbody2D body = SlashObj.GetComponent<Rigidbody2D>(); //SlashObjの当たり判定取得。
body.AddForce(v, ForceMode2D.Impulse); //SlashObjの当たり判定に力を加える。飛んでく。やったぜ。
Invoke("StopAttack", 0.4f); //連射を防ぐためのフラグ操作。
Destroy(SlashObj, 0.3f); //攻撃オブジェクトを0.3秒後に削除。射程にも影響する。
}
}
}
//攻撃ディレイ中の再攻撃禁止。Attack内でInvokeで呼ぶことでディレイをしている。
public void StopAttack()
{
inAttack = false; //攻撃中フラグ下ろす
}
まあまあ複雑。改造して使う際、一気にコピペしないで、少しづつ実装してDebug.Log出しながらの方がわかりやすいと思う。
自作ゲームからかいつまんだコードなので、変数の宣言ぬけとか変なとこあったらごめん。
ミスがあったらご報告いただければ嬉しいです。