NPCの移動と武器【UnityでRTSを作る 3】
今日はNPCの移動及び武器を実装しました。
NPCの移動処理
これは前回の記事で紹介したCubeKunクラスを継承させてMoveTo(移動のための汎用関数)にターゲットの位置を渡してあげるだけなので簡単でした。
NPC.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class NPC : CubeKun { private new void Update () { if (target) MoveTo(target.position); } } }
武器
弾の処理
武器から発射する弾のコードです。
弾のステータスと単純な移動処理だけです。
Bullet.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { [RequireComponent(typeof(BoxCollider))] public class Bullet : MonoBehaviour { public Transform Tr { get { return _Tr ? _Tr : (_Tr = transform); } } private Transform _Tr; public int power = 20; public float speed = 10; private void Update () { Tr.Translate(Tr.forward * speed * Time.deltaTime,Space.World); } } }
武器による弾の発射
武器には弾の発射と、その処理を一定間隔でループさせるためのコルーチンを実装します。
Weapon.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class Weapon : MonoBehaviour { public Transform[] firingPoints; public float interval = 0.5f; [Header("Bullet Settings")] public Bullet bullet; public int power = 20; public float speed = 5; public float time = 5; private Coroutine shootCoroutine = null; private void Start () { ShootStart(); } public void ShootStart () { if (shootCoroutine == null) shootCoroutine = StartCoroutine(ShootCoroutine()); } public void ShootStop () { if (shootCoroutine == null) return; shootCoroutine = null; StopCoroutine(shootCoroutine); } public void Shoot () { for (int i = 0;firingPoints.Length > i;i++) { var ins = Instantiate(bullet); ins.Tr.position = firingPoints[i].position; ins.Tr.rotation = firingPoints[i].rotation; ins.power = power; ins.speed = speed; Destroy(ins.gameObject,time); } } private IEnumerator ShootCoroutine () { while (true) { Shoot(); yield return new WaitForSeconds(interval); } } } }
体力
武器があっても減る体力が無いと意味がないので、体力を実装するHealthクラスを用意します。
Health.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace MackySoft.CubeKunWars { [Serializable] public class OnValueChangedEvent : UnityEvent<int> { } public class Health : MonoBehaviour { [SerializeField] private int _Value = 100; [Header("Events")] public OnValueChangedEvent onValueChanged; public UnityEvent onDie; public int Value { get { return _Value; } set { _Value = value > 0 ? value : 0; onValueChanged.Invoke(Value); if (IsDead) onDie.Invoke(); } } public bool IsDead { get { return Value == 0; } } private void OnValidate () { Value = _Value; } } }
それに従ってCubeKunクラスに「弾に当たった時にダメージを受ける」処理を追加しました。
CubeKun.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Pathfinding; namespace MackySoft.CubeKunWars { [RequireComponent(typeof(Health))] [RequireComponent(typeof(Rigidbody))] public abstract class CubeKun : AIPath { public float sleepVelocity = 0.4F; public Transform Tr { get; private set; } public Rigidbody Rigid { get; private set; } public Health Health { get; private set; } protected override void Awake () { base.Awake(); Tr = transform; Rigid = GetComponent<Rigidbody>(); Rigid.constraints = RigidbodyConstraints.FreezeAll; Health = GetComponent<Health>(); Health.onDie.AddListener(() => Destroy(gameObject)); } protected virtual void OnCollisionEnter (Collision collision) { var bullet = collision.gameObject.GetComponent<Bullet>(); if (bullet) { Health.Value -= bullet.power; Destroy(bullet.gameObject); } } public void MoveTo (Vector3 position) { if (canMove) { var dir = CalculateVelocity(GetFeetPosition()); RotateTowards(targetDirection); dir.y = 0; if (dir.sqrMagnitude > sleepVelocity * sleepVelocity) { } else { dir = Vector3.zero; } Tr.Translate(dir * Time.deltaTime,Space.World); } } public override Vector3 GetFeetPosition () { return Tr.position; } } }
プレイヤーの移動【UnityでRTSを作る 2】
前回の記事ではざっくりと開発計画をしましたが、
ついに今回ゲーム制作が始まります。
今回はプレイヤーの移動です。
モデル
まずはプレイヤーのモデルの紹介です。
キューブ君(CubeKun)と呼びます。
ゲーム制作を始めた当初に作ったキャラクターです。
このキューブ君がプレイヤーとなります。
そしてこのプロジェクトの名前は「CubeKun Wars」となりました。
(変更の可能性もあります)
カメラ
まず最初にカメラを制御するためのコードを書きます。
トップダウン型のゲームなのでカメラが下に向いている前提のコードです。
CameraController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class CameraController : MonoBehaviour { public Transform target; public float height = 10; private Transform tr; void Start () { tr = transform; } void Update () { if (!target) return; tr.position = target.position + Vector3.up * height; } } }
移動処理
経路探索にはA* Pathfinding Projectを使用します。
CubeKun.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Pathfinding; namespace MackySoft.CubeKunWars { public abstract class CubeKun : AIPath { public float sleepVelocity = 0.4F; public Transform Tr { get ; private set; } protected override void Awake () { base.Awake(); Tr = transform; } public void MoveTo (Vector3 position) { if (canMove) { var dir = CalculateVelocity(GetFeetPosition()); RotateTowards(targetDirection); dir.y = 0; if (dir.sqrMagnitude > sleepVelocity * sleepVelocity) { } else { dir = Vector3.zero; } Tr.Translate(dir * Time.deltaTime,Space.World); } } public override Vector3 GetFeetPosition () { return Tr.position; } } }
Player.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MackySoft.CubeKunWars { public class Player : CubeKun { public Transform Pointer { get; private set; } protected override void Awake () { base.Awake(); canMove = false; Pointer = new GameObject("pointer").transform; target = Pointer; Camera.main.orthographic = true; } private new void Update () { canMove = Input.GetMouseButton(0); canSearch = canMove; if (canMove) { Pointer.position = Camera.main.ScreenToWorldPoint(Input.mousePosition); MoveToPointerPosition(); } } public void MoveToPointerPosition () { MoveTo(Pointer.position); } } }
動画
クリックし続けるとキューブ君がカーソルのある方向へ向かいます。
Make RTS with Unity Part.1[Player Mover]
どんなゲームを作るか【UnityでRTSを作る 1】
これから作り始めるRTSっぽいゲームの話をします
開発日記を始めるわけ
「誰にも見せずやってても続かなかった」からです。
2年間ゲームを作ってて一番開発が続いたのが、
YouTubeに進歩を投稿していたプロジェクトです。(今はありませんがブログも同時進行でした)
そんなわけで今一度、開発日記を初めようと思います。
ゲームの内容
タイトル通り、RTSのような群衆同士をを戦わせるゲームを作ります。
ただし通常のRTSと違って、プレイヤーは神様ではなく、
NPCと同じようにユニットとして存在し、戦うことができます。
ルール
- お互いにマップに配置された拠点を取り合いながら戦います
- 拠点はユニットのスポーン、弾薬の補充など、戦略的に重要な意味を持ちます
- 先に相手を全滅させたら勝ちです
開発手順
メインシーンから作る
タイトル画面などのUIが主体となるシーンは後回しです。
めんどくさいうえに大した達成感がないからです。
小さく作る
最初から立派なものを作らず、モデルは少なく、UIもてきとーに作ります。
まずは最低限のゲームサイクルを作ります。
使用するアセット
現在使用予定のアセットです。
A* Pathfinding Project
ユニットの移動に使用します。
Chronos
ポーズ、倍速処理に使用します。
Dynamic CullingGroup
製作中の自作アセットです。
ランダムマップになる予定なので、動的なカリングをするために使用します。