こんにちは。【2Dシューティング】Unity公式チュートリアルをやってみるシリーズの9回目です。前回はHPの実装とアニメーションの実装を行いました。アニメーションに関してはUnity公式チュートリアルがくそすぎてなかなか作業が進みませんでした、動画つきになっていますので参考にしてください。
【2Dシューティング】Unity公式チュートリアル9回目。HPの実装とアニメーション
今回はScoreを実装していきます。
Scoreを実装しよう
ここでやること
- 新しいCanvasを作成しにScoreテキストとHighScoreテキストを子要素として作成
- Score用のスクリプトを作成
- EnemyScriptにコード追加
- Managerにアタッチ
とりあえずテキストを作ろう
2DシューティングUnity公式チュートリアルのGUIテキストは使えなくなっている。情報が古いくせに更新されていない。怒りがわいてきた。もはやここからは公式とはまったく違う手順になっているので参考までにしておいてください。
新しいCanvasを作成してScoreテキストとHIghScoreテキストを子要素として作成します。Canvasがすでにあるのになぜまた新しいCanvasを作るのか?→Xを押すとゲームがはじまりテキストが消えるためです。作成した状態が以下。Canvasは名前を変えてScore UIとしました。
テキストのパラメーター調整は適当でもいいのだが場合によっては表示されないこともあるので、OverFlowの設定は行っておいたほうがよいだろう
ScoreScriptを作成しよう
敵を倒したらScoreを加算していくためのScoreScriptを作成する。スコアが大きくなればHighScoreも更新する。(公式とScriptが全然違うので真似するなら注意。)公式ではHighScoreの保存をするコードもあるが、今回はだるいので省略した。
using UnityEngine;
using UnityEngine.UI;
public class ScoreScript : MonoBehaviour {
private int score;// スコア
private int highScore;// ハイスコア
public Text scoreText;// スコアテキスト
public Text highScoreText;// ハイスコアテキスト
void Start () {
score = 0;// スコアの初期化
highScore = 0;// ハイスコアの初期化
scoreText.text = "SCORE:\n" + score;// スコアの表示
UpdateHighScore();
}
void Update () {
//scoreの方が大きかったら
if(score > highScore){
UpdateHighScore();
}
}
public void AddScore(int scoreToAdd){
score += scoreToAdd;
scoreText.text = "SCORE:\n" + score;// スコアの表示
}
void UpdateHighScore(){
//ハイスコアの表示と更新
highScoreText.text = "HIGHSCORE:\n" + score;
}
}
EnemyScriptにコードを追加しよう
敵にはスコアを表示させるためにpublicな変数を追加する。publicにしておくと後で敵のスコアを変えられる。ScoreScriptのAddScroe()関数をつかうためにオブジェクトを取得している。敵が死ぬときにAddScoreを呼び出している。今回はわかりにくいかもしれないがEnemyScriptを全部のせておく
using UnityEngine;
using System.Collections;
public class EnemyScript : MonoBehaviour
{
//HP
public int hp = 1;
public int point;
// Spaceshipコンポーネント
SpaceShipScript spaceship;
// ScoreScirptコンポーネント
ScoreScript scoreScript;
IEnumerator Start ()
{
// Spaceshipコンポーネントを取得
spaceship = GetComponent<SpaceShipScript> ();
scoreScript = GameObject
.FindWithTag("GameController")
.GetComponent<ScoreScript>();
// ローカル座標のY軸のマイナス方向に移動する
Move (transform.up * -1);
// canShotがfalseの場合、ここでコルーチンを終了させる
if (spaceship.canShot == false) {
yield break;
}
while (true) {
// 子要素を全て取得する
for (int i = 0; i < transform.childCount; i++) {
Transform shotPosition = transform.GetChild(i);
// ShotPositionの位置/角度で弾を撃つ
spaceship.Shot (shotPosition);
}
// shotDelay秒待つ
yield return new WaitForSeconds (spaceship.shotDelay);
}
}
// 機体の移動
public void Move (Vector2 direction)
{
GetComponent<Rigidbody2D>().velocity = direction * spaceship.speed;
}
void OnTriggerEnter2D (Collider2D c){
//レイヤー名を取得
string layerName = LayerMask.LayerToName(c.gameObject.layer);
//レイヤー名がBullet(Player)以外のときは何も行わない
if(layerName != "Bullet (Player)") return;
//PlayerBulletのTransformを取得
Transform playerBulletTransform = c.transform.parent;
//Bulletコンポーネントを取得
BulletScript bullet = playerBulletTransform.GetComponent<BulletScript>();
if(c.gameObject.CompareTag("PlayerBullet")){
Destroy(c.gameObject);//弾の削除
hp = hp - bullet.power;
if(hp <= 0){
spaceship.Explosion();//爆発する
Destroy(gameObject);//敵の削除
scoreScript.AddScore(point);//敵倒したらスコア加算
}else{
spaceship.GetAnimator().SetTrigger("Damage");
}
}
}
}
なぜFindWithTag()が必要なのか
なぜ普通にGetComponentで取得できないか疑問に思った方もいるかもしれない。GetComponentは呼び出し元にEnemyScriptにはScoreScriptがアタッチされていないので、GetComponentだけでは取得できない。(上ではEnemyScirptが呼び出し元になる)そのためFindWithTag()を使う必要があるのだ。
今回はScoreScriptをManagerにアタッチした。
ManagerのTagに注目してほしい。名前がGameControllerになっているはずだ。このタグ名をFindWithTag()で指定できるということだ。
GetComponentのおさらい
- 呼び出し元に指定のコンポーネントがアタッチされているか確認。
- コンポーネントがないが他クラスのメンバーを呼び出したい場合は、タグで指定してコンポーネントを取得する方法がある
とりあえずゲーム完成
Enemyに適当にpointを設定したらとりあえずスコアは増える。いろいろいじって、変になってしまったけど、まあとりあえずこれで完成とする。・・・〇ガネブログの全方位シューティング作ったときもそうだったけど、今回も何も学びがなかった。Unityの操作だけは少し慣れた気がする。
次は弾幕シューティング作りたい。

コメント