引越しが落ち着いたので久々にゲームを開発していきたいと思います。
かなりのブランクがあるので簡単なエンドレスランナーのゲームを作っていきます。
できるだけコードも忘れないように記入していきたいので、もしこうした方がいいなどありましたら指摘していただけると幸いです!
今期は下記を目標に作っていきます。
簡単に遊べるエンドレスランナーの基礎の基礎を作っていきます。
まずやったこと:
- Unityの更新 2022.3.8f1(かなり古かったので久々に更新)
- プロジェクトの作成(モバイル用にリリース目標なので3Dモバイルで作成)
- キャラクターの作成(PlayerController.cs)
- 地面の作成(PlaneFollow.cs)
- 障害物の作成(Obstacle.cs)
- 障害物の自動生成(ObstacleSpawner.cs)
- カメラの設定(CameraFollow.cs)
- 障害物に直撃した場合はゲームをリセット(GameManager.cs)
次に各コードを載せていきます。まだシンプルなので細かい調整はないです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.SceneManagement; | |
public class GameManager : MonoBehaviour | |
{ | |
public bool isGameOver = false; | |
void Update() | |
{ | |
if (isGameOver) | |
{ | |
RestartGame(); | |
} | |
} | |
public void GameOver() | |
{ | |
isGameOver = true; | |
} | |
void RestartGame() | |
{ | |
SceneManager.LoadScene(SceneManager.GetActiveScene().name); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class CameraFollow : MonoBehaviour | |
{ | |
public Transform target; // カメラが追従する対象(プレイヤー) | |
public Vector3 offset; // カメラとプレイヤーの相対位置 | |
void Update() { | |
// プレイヤーの位置にオフセットを加えてカメラの位置を更新 | |
transform.position = new Vector3(transform.position.x, offset.y + offset.y, target.position.z + offset.z); | |
transform.LookAt(target); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class Obstacle : MonoBehaviour | |
{ | |
private GameObject player; // プレイヤーオブジェクト | |
public float threshold = -5.0f; // このZ座標を過ぎたら障害物を削除 | |
void Start() | |
{ | |
player = GameObject.Find("Player"); | |
} | |
void Update() | |
{ | |
// プレイヤーのZ座標よりも後ろにある(小さい)場合、障害物を削除 | |
if (transform.position.z < player.transform.position.z + threshold) | |
{ | |
Destroy(gameObject); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class ObstacleSpawner : MonoBehaviour | |
{ | |
public GameObject obstaclePrefab; | |
public float spawnRate = 2.0f; | |
private float spawnInterval; | |
void Start() | |
{ | |
Invoke("SpawnObstacle", 2.0f); | |
} | |
void SpawnObstacle() | |
{ | |
spawnInterval = Random.Range(0.5f, spawnRate); | |
Instantiate(obstaclePrefab, new Vector3(Random.Range(-1, 2) * 2, Random.Range(0, 2) + 0.6f, transform.position.z), Quaternion.identity); | |
Invoke("SpawnObstacle", spawnInterval); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class PlaneFollow : MonoBehaviour | |
{ | |
public Transform target; | |
void Update() { | |
transform.position = new Vector3(transform.position.x, transform.position.y, target.position.z); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class PlayerController : MonoBehaviour | |
{ | |
public float speed = 10.0f; | |
public float jumpForce = 5.0f; | |
public float laneSwitchSpeed = 0.5f; // レーン切り替えの速度 | |
private Rigidbody rb; | |
private int lane = 1; // 0: 左, 1: 中央, 2: 右 | |
private Vector3[] lanePositions = { new Vector3(-2, 1, 0), new Vector3(0, 1, 0), new Vector3(2, 1, 0) }; | |
private Vector3 targetPosition; // プレイヤーが移動する目的地 | |
private bool isGrounded = true; // プレイヤーが地面にいるかどうか | |
void Start() | |
{ | |
rb = GetComponent<Rigidbody>(); | |
targetPosition = transform.position; // 初期位置を設定 | |
} | |
void Update() | |
{ | |
// レーン切り替え | |
if ((Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A)) && lane > 0) | |
{ | |
lane--; | |
SwitchLane(); | |
} | |
else if ((Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D)) && lane < 2) | |
{ | |
lane++; | |
SwitchLane(); | |
} | |
// ジャンプ(地面にいる場合のみ) | |
if (Input.GetButtonDown("Jump") && isGrounded) | |
{ | |
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); | |
isGrounded = false; // ジャンプ後は地面から離れる | |
} | |
// スムーズなレーン切り替え(X座標のみ) | |
Vector3 newPosition = transform.position; | |
newPosition.x = Mathf.Lerp(newPosition.x, targetPosition.x, laneSwitchSpeed * Time.deltaTime); | |
transform.position = newPosition; | |
// 前進(Z座標) | |
transform.Translate(Vector3.forward * speed * Time.deltaTime, Space.World); | |
} | |
void SwitchLane() | |
{ | |
targetPosition = lanePositions[lane]; | |
targetPosition.z = transform.position.z; // Z座標は変更しない | |
} | |
private void OnTriggerEnter(Collider other) | |
{ | |
// ゲームオーバー | |
if (other.gameObject.tag == "Obstacle") | |
{ | |
FindObjectOfType<GameManager>().GameOver(); | |
} | |
} | |
void OnCollisionEnter(Collision collision) | |
{ | |
// 地面に触れたらisGroundedをtrueにする | |
if (collision.gameObject.CompareTag("Ground")) | |
{ | |
isGrounded = true; | |
} | |
} | |
} |
ここからやってみたことを細かく説明していきます。
- キャラクターの作成ではキャラクターが3方向のみ(左、中央、右)に移動できるように制御、またスムーズに動くようにLerpを使って移動できるようにしています。キャラクターが障害物に当たっ時の処理も一緒に含めています。
- 地面の作成はキャラクターと一緒に移動するようにしています。エンドレスなので地面を固定のフィールドを作るのは大変なのでシンプルに地面もキャラクターと一緒に移動するようにしてエンドレスっぽく見せています。
- 障害物の作成では障害物用のタグを作成してプレイヤーが避けてプレイヤーの後ろをある程度離れたら削除するように処理を入れています。
- 障害物の自動生成はランダムのDelayタイムを設定して障害物を延々と生成するように作りました。本当にシンプルです笑
- 障害物に直撃した場合はゲームをリセットはシンプルにゲーム全体の処理をここに入れていきます。今のところはプレイヤーが障害物に当たった場合にリセットする処理が含まれています。
上記だけで一応は遊べるぐらいのシンプルなエンドレスランナーっぽいゲームになります。ここから細かくオリジナリティを加えていければと思います。
日記のバージョン毎にWebGLで遊べるようにしていきたいのでぜひ触ってみてください!
Version 0.1
次はちょっと雰囲気でも変えていこうかな。。
最後まで読んでいただきありがとうございます!
これからもギルガメを応援していただけるよ嬉しいです!
0 件のコメント:
コメントを投稿