[Unity3D] 武器の実装

1, Playerプレハブの手の部分にEquippedSwordを作成する
![953BA4C6-8D1E-48D6-9318-7026A0CD5A48.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/48af850a-3c88-f747-0655-10b63dd76835.jpeg)

2, EquippedSwordに武器を子オブジェクト化し、再生した状態でScaleや位置を調整してコピーしておく
![CCF6A698-8908-4034-8FEC-A044B886FA5C.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/cad5ca24-de3b-a3fd-686d-c47d980061e1.jpeg)
![D2B6756D-7A0E-4258-898B-3081095E0514_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/c8bcdeec-2cd3-2f91-1d5b-bfc85474ba58.jpeg)

3, コピーした位置をPlayerのTransformにPasteする
![92AD8B33-2689-4267-907D-DAEF02C77560.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/17c5c4c0-9c7e-3a96-0e6b-8a0db8a19c23.jpeg)

4, Waeponsフォルダを作成し、プレハブ化する。（プレハブ済のものは削除しておく）
![810B8AEE-BB9B-43AF-81F0-97813A12D7EF.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/5fab8ce6-fd09-2a36-589c-e26a79858bfa.jpeg)
![06EF6F8E-5F93-4CA0-973C-D65FB9EFDAC7.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a662bb7d-fc92-67cd-0291-fbc6f3f4f94a.jpeg)

5, Fighterに下記コードを追加する

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float weaponRange = 2f;
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] GameObject weaponPrefab = null; //追加
        [SerializeField] Transform handTransform = null; //追加

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;

        //追加
        private void Start()
        {
            SpawnWeapon();
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        //追加
        private void SpawnWeapon()
        {
            Instantiate(weaponPrefab, handTransform);
        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(weaponDamage);
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < weaponRange;
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```
6, コンポーネントに位置と武器を設定する
![0A94B483-F26F-49E5-947C-8E273581303E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/b92f50fb-0049-aadc-aebb-d9f2ed299801.jpeg)

アニメーションの実装
---
1, Swordフォルダを作成し、EquippedSwordを入れる
![A2E0BE18-0241-47F5-88DB-3F3AE14804B3_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0907d05d-4dd2-669d-de73-ac5111b523c6.jpeg)

2, SwordフォルダにAnimatorOverrideControllerを作成する
![913BB3F2-C216-4294-B8C5-0CEDF111A8CC_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/ebe0a13b-a3b7-fb4d-a0f1-e43e555a7289.jpeg)

3, SwordOverrideControllerに名前を変更し、CharactorControllerを設定する
![34C31F37-7965-4F0D-B740-26E4F48D9CF1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/7e9f597f-6a63-bd27-05eb-c2671f53008e.jpeg)

4, SwordOverrideControllerのUnarmed-Attakに任意のアニメーションを設定する
![50E55896-6730-4A28-A68C-9D82A8B994B5_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/8d40da2e-5a38-6867-64ad-86e86da9775e.jpeg)

5, Fighterに下記スクリプトを書く

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float weaponRange = 2f;
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] GameObject weaponPrefab = null;
        [SerializeField] Transform handTransform = null;
        [SerializeField] AnimatorOverrideController weaponOverride = null; //追加

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;

        private void Start()
        {
            SpawnWeapon();
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        private void SpawnWeapon()
        {
            Instantiate(weaponPrefab, handTransform);
            Animator animator = GetComponent<Animator>(); //追加
            animator.runtimeAnimatorController = weaponOverride; //追加

        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(weaponDamage);
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < weaponRange;
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```
6,PlayerプレハブのWeaponOverrideにSwordOverrideControllerをアタッチする
![2CA40A2C-2417-42D0-ABCA-B296B63D85D1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/cb641d23-bcf0-8723-4cea-ff56284b74d6.jpeg)

スクリプト化可能なオブジェクトの作成
---
1, Wwaponスクリプトを作成し、各スクリプトに下記コードを書く
![83962986-D6BB-4A76-A1F1-C61A6A462EC0_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0fd04710-1b0c-f772-c9fc-e2420ae86b02.jpeg)

```C#:Weapon
using UnityEngine;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class Weapon : ScriptableObject
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] GameObject weaponPrefab = null;

        public void Spawn(Transform handTransform, Animator animator)
        {
            Instantiate(weaponPrefab, handTransform);
            animator.runtimeAnimatorController = animatorOverride;
        }
    }
}
```

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float weaponRange = 2f;
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] Transform handTransform = null;
        [SerializeField] Weapon weapon = null; //追加

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;

        private void Start()
        {
            SpawnWeapon();
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        private void SpawnWeapon()
        {
            if (weapon == null) return; //追加
            Animator animator = GetComponent<Animator>();
            weapon.Spawn(handTransform, animator); //追加

        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(weaponDamage);
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < weaponRange;
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```
2, Swordフォルダ内にCreate→Weapons→MakeNewWeaponsを押してSwordを作成する
![45CFF818-24C8-4B9C-8B12-354B4D28C379.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a72e4bcf-8ca7-af20-672e-755adaf0379d.jpeg)
![57843597-903B-4C35-AF88-2FBA27EF8AA0_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/642d98e6-5d59-e86f-c3ed-bbb9c02850d1.jpeg)

3, SwordにSwordOverrideControllerとEquippedSwordを設定する
![DA3FE0A1-BEAF-4636-A6C4-FE261C98DACB_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/6a1b5ebc-6c32-cda0-46e0-4c24d9256dfb.jpeg)

4, PlayerプレハブのWeaponにSwordをアタッチする
![42AA4536-B0B8-411A-877F-60199DFB9929.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/6aa4cd31-5755-d271-bc5e-73522d61af96.jpeg)

武器無し攻撃の実装
---
1, Weaponsフォルダ内にUnarmedフォルダを作成し、Create→Weapons→MakeNewWeaponでUnarmedを作成。
![822E6AC4-1508-4157-AE64-384DB753A84A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/62b389f3-9c03-2e14-7e02-220eb9c94e00.jpeg)
![CEED2AFC-60C7-4459-8E8F-4317CF892897_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/c330619b-3242-296e-3eb5-3f9a29416f1a.jpeg)

2, 各スクリプトに下記コードを書く

```C#:Weapon
using UnityEngine;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class Weapon : ScriptableObject
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] GameObject equippedPrefab = null;
        [SerializeField] float weaponDamage = 5f; //Fighter.csから移動
        [SerializeField] float weaponRange = 2f; //Fighter.csから移動

        public void Spawn(Transform handTransform, Animator animator)
        {
            if (equippedPrefab != null)
            {
                Instantiate(equippedPrefab, handTransform);
            }
            if (animatorOverride != null)
            {
                animator.runtimeAnimatorController = animatorOverride;
            }
        }

        public float GetDamage()
        {
            return weaponDamage;
        }

        public float GetRange()
        {
            return weaponRange;
        }
    }
}
```

```C#:Fighter
void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(weapon.GetDamage()); //GetDamageに変更
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < weapon.GetRange(); //GetRangeに変更
        }
```
3, EnemyのWeaponにUnarmedを設定する
![90344D3C-579C-4DCA-AA96-FB258486C3BF_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a715c1c2-726d-67fc-ab9d-f886d54881ed.jpeg)

4, SWordのEquippedPrefabにEquippedSwordオブジェクトを設定する
![B8D4372F-F02B-41B7-BBD0-7938C6729B58.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/7671206d-a371-bea5-224f-33c1263b32fd.jpeg)

武器を拾う
---
1, プロジェクトにPickupsフォルダを作成。ヒエラルキーにPickupsとSwordPickupのげーむオブジェクトを作成し、SwordPickupをプレハブ化する。
![9F5502DD-E866-46AE-8156-806D07F92805.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/25e999e9-d130-c456-6249-b612bc931e5b.jpeg)

2, SwordPickupに武器を入れ、サイズを調整する
![3D1EF594-330D-4753-9BFA-0855F95BD767_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/6686eea9-3ab9-6e3f-61d0-4ea84838061d.jpeg)

3, SwordPickupにSphereColliderを付け、Colliderのサイズを調整する
![D9D28624-7638-40B5-B326-6027CC5FD6E7.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/3bf06064-ff34-8a8e-2753-75a1d6be5e47.jpeg)

4, WeaponPickupスクリプトを作成し、SwordPickupに付ける
![3269E4AE-464A-44E3-8650-EA37E925B9BC.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/36831150-05af-3063-4e01-1585dd07bb22.jpeg)

5, 下記スクリプトを記述する

```C#:WeaponPickup
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Combat
{
    public class WeaponPickup : MonoBehaviour
    {
        [SerializeField] Weapon weapon = null;

        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.tag == "Player")
            {
                other.GetComponent<Fighter>().EquipWeapon(weapon);
                Destroy(gameObject);
            }
        }
    }
}
```

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] Transform handTransform = null;
        [SerializeField] Weapon defaultWeapon = null; //変更

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;
        Weapon currentWeapon = null; //追加

        private void Start()
        {
            EquipWeapon(defaultWeapon); //追加
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        public void EquipWeapon(Weapon weapon) //EquipWeaponに変更
        {
            currentWeapon = weapon; //追加
            Animator animator = GetComponent<Animator>();
            weapon.Spawn(handTransform, animator);

        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(currentWeapon.GetDamage()); //currentWeaponに変更
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < currentWeapon.GetRange(); //currentWeaponに変更
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```

6, SwordPickupのWeaponにSwordをアタッチし、IsTriggerにチェックを入れる
![E403B5C2-7AB9-46B8-B8B6-F623B98D4907.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/eff05bc4-05da-8875-62db-cec7d52d4c5b.jpeg)

7, PlayerプレハブのFighterスクリプト→DefaultWeaponにUnarmedをアタッチする
![1A35607D-BE22-49BB-91EA-65FD7A549F63.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/32bebf64-641c-f03d-3e4f-b0fcb7975d96.jpeg)

8, CharactorにRigidbodyを付ける
![A40129D6-6761-4486-9A23-CF3EF7B54FEB.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/c547f127-1d49-4c4b-2952-114b23c82d59.jpeg)

上記で再生したところplayerがプルプルしていたので追加でIsKinematicにチェックを入れました。
![E9D97FFB-8FDA-41A8-A849-6C8B41AF225C_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/01e5331e-d524-bc27-1e8f-fd82bbce1532.jpeg)

左手に持つ武器を実装
---
1, 武器のアセットをインポートする
![536D1B0F-8A26-43C3-B268-1B42DAA4526A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/089e56c4-bca3-75eb-d528-ea671d7ad9be.jpeg)

2, 各スクリプトに下記コードを記述する

```C#:Weapon
using UnityEngine;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class Weapon : ScriptableObject
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] GameObject equippedPrefab = null;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] float weaponRange = 2f;
        [SerializeField] bool isRightHanded = true; //追加


        public void Spawn(Transform rightHand, Transform leftHand, Animator animator) //追加
        {
            if (equippedPrefab != null)
            {
                Transform handTransform; //追加
                if (isRightHanded) handTransform = rightHand; //追加
                else handTransform = leftHand; //追加
                Instantiate(equippedPrefab, handTransform);
            }
            if (animatorOverride != null)
            {
                animator.runtimeAnimatorController = animatorOverride;
            }
        }

        public float GetDamage()
        {
            return weaponDamage;
        }

        public float GetRange()
        {
            return weaponRange;
        }
    }
}
```

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] Transform rightHandTransform = null; //変更
        [SerializeField] Transform leftHandTransform = null; //追加
        [SerializeField] Weapon defaultWeapon = null;

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;
        Weapon currentWeapon = null;

        private void Start()
        {
            EquipWeapon(defaultWeapon);
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        public void EquipWeapon(Weapon weapon)
        {
            currentWeapon = weapon;
            Animator animator = GetComponent<Animator>();
            weapon.Spawn(rightHandTransform, leftHandTransform, animator); //追加

        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }
            target.TakeDamage(currentWeapon.GetDamage());
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < currentWeapon.GetRange();
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```
3, PlayerのHandLとHandRをFighterコンポーネントにアタッチする
![11BF02EC-3CF7-46B9-B1DC-712E277390C6.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/8b7130b0-1039-cae2-539e-e82c41a014b1.jpeg)

4, SwordのIsRightHandedのチェックを外す
![6D59AFD6-068F-426F-A708-856DF55E8490.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/10fac8e8-0aa6-18cd-bc0d-2366e46e209b.jpeg)

5, Bowフォルダを作成する
![AE79B4B2-C834-451D-ABFF-1BD931736241_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/1f738f47-a7e7-b4af-327f-2929480ec8ab.jpeg)

6, BowフォルダにMakeNewWeaponとAnimatorOverrideControllerを作成する
![3EB0CD4B-F5CD-49DD-82C5-8544D97B03FB.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/ebeab635-ca16-7c1a-dbd3-2f7d15cdc7ef.jpeg)
![77DFC5C6-B94D-42C3-A769-EA4F2807AD30_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/8e771934-5373-e303-e79f-ff3d9228b342.jpeg)
![F734E82E-B6EE-4928-A500-763C45F9159E_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/304955fd-3f62-8d63-2a88-ab533767cfed.jpeg)

7,BowAnimatorOverrideにCharactorとアニメーションをアタッチする
![0FB55E9B-EC5E-43B4-8C57-BC716A6F0584.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/4fddb7d9-4599-9d57-318c-b4462833cc95.jpeg)

8, BowのAnimatorOverrideとdamage値など設定する
![CAE7DD5A-586C-4C41-AC11-37FF0822F429.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/6f2402e8-1546-5bf7-07c2-88a490c1ae62.jpeg)

9, PlayerのHandLにBowオブジェクトを作成し、武器を子オブジェクト化しておく。それをプレハブ化する
![BA2D43D3-9F10-4845-832A-60F7F0081AD1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a33f8e67-903b-848f-0ef3-3c866de6e98e.jpeg)

10,再生しながら武器の位置を合わせてTransformをコピーする
![7CF9420D-8115-4E5F-BC9E-2DDB90FE60AE.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a2616cba-f42c-8ff2-65fc-b243398ae47e.jpeg)

11, 位置をPasteする
![8ECFA1F9-60BC-4A74-B5C1-AA8F0BC8AD4F_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/8f40fe73-39d6-f99d-771f-a4f1d595e012.jpeg)

12, PlayerのdefaltWeaponをBowにする
![89ADF208-F6F3-45CF-9B8B-A8D0AC1A2942.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/bc2ebde7-4dec-6c78-87bc-0442b24dbd3e.jpeg)

13, BowのEquippedPrefabを設定する
![E9212927-1EE9-4932-9567-BC72C1AD9EC4.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/02b53203-5fc7-33f0-1b98-6f2a39b04631.jpeg)

矢をplayerに当てる
---
1, 矢のアセットをインポートする
![35BA28DF-BD6F-44D6-9B66-F6F58460350C_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/f248092e-76cd-f1ed-d3a3-070a44f80168.jpeg)

2, ProjectにProjectileフォルダを作成。ヒエラルキーにArrowProjectileオブジェクトを作成し、プレハブ化する
![218CBB19-FA4F-461F-8341-A93D4A6F4BE7.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/1717d7a3-ed4a-721c-f39d-6767903cb337.jpeg)

3, ArrowProjectileに矢のプレハブを子オブジェクト化する
![22D94C3E-E623-4D0A-9063-D29553CF8A67_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a051bc97-47db-85b1-3392-57cff807e8fd.jpeg)

4, SimpleArrowのサイズや向きを調整する
![1584B30A-E612-4431-8F7D-54BE5C8EDDE8_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/e1567f42-0c8e-79ef-9d7c-fb42166f32db.jpeg)

5, Projectile.csを作成する
![11EF0310-9EEA-4E13-BB8C-2361DB6D509C_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/b6cb6103-21ca-2d53-aa08-f2555364638d.jpeg)

6, 下記のコードを記述する

```C#:Projectile
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    [SerializeField] Transform target = null;
    [SerializeField] float speed = 1;

    void Update()
    {
        if (target == null) return;

        transform.LookAt(GetAimLocation());
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }

    private Vector3 GetAimLocation()
    {
        CapsuleCollider targetCapsule = target.GetComponent<CapsuleCollider>();
        if (targetCapsule == null)
        {
            return target.position;
        }
        return target.position + Vector3.up * targetCapsule.height / 2;
    }
}
```
7, ArrowProjectileのTargetにplayerをアタッチする
![E5684329-CB83-4613-9DD8-1199B720E30A.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/d469f69b-edd8-d23f-fed4-2d7136e821bc.jpeg)

矢を敵に飛ばす
---
1, アタックアニメーションを確認し、Hitなどのイベントがついているか確認する
![70BCFB93-B7FF-473B-8DB7-96580A6B080E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/84610106-5375-fa86-6067-0a167033c6a9.jpeg)

2, 各スクリプトに下記コードを追加する

```C#:Fighter
using UnityEngine;
using RPG.Movement;
using RPG.Core;
using System;

namespace RPG.Combat
{
    public class Fighter : MonoBehaviour, IAction
    {
        [SerializeField] float timeBetweenAttacks = 1f;
        [SerializeField] Transform rightHandTransform = null; //変更
        [SerializeField] Transform leftHandTransform = null; //追加
        [SerializeField] Weapon defaultWeapon = null;

        Health target;
        float timeSinceLastAttack = Mathf.Infinity;
        Weapon currentWeapon = null;

        private void Start()
        {
            EquipWeapon(defaultWeapon);
        }

        private void Update()
        {
            timeSinceLastAttack += Time.deltaTime;

            if (target == null) return;
            if (target.IsDead()) return;

            if (!GetIsInRange())
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                AttackBehaviour();
            }
        }

        public void EquipWeapon(Weapon weapon)
        {
            currentWeapon = weapon;
            Animator animator = GetComponent<Animator>();
            weapon.Spawn(rightHandTransform, leftHandTransform, animator); //追加

        }

        private void AttackBehaviour()
        {
            transform.LookAt(target.transform);
            if (timeSinceLastAttack > timeBetweenAttacks)
            {
                TriggerAttack();
                timeSinceLastAttack = 0;
            }
        }

        private void TriggerAttack()
        {
            GetComponent<Animator>().ResetTrigger("stopAttack");
            GetComponent<Animator>().SetTrigger("attack");
        }

        void Hit()
        {
            if(target == null) { return; }

            if (currentWeapon.HasProjectile())
            {
                currentWeapon.LaunchProjectile(rightHandTransform, leftHandTransform, target);
            }
            else
            {
                target.TakeDamage(currentWeapon.GetDamage());
            }
        }

        void Shoot()
        {
            Hit();
        }

        private bool GetIsInRange()
        {
            return Vector3.Distance(transform.position, target.transform.position) < currentWeapon.GetRange();
        }

        public bool CanAttack(GameObject combatTarget)
        {
            if (combatTarget == null) { return false; }
            Health targetToTest = combatTarget.GetComponent<Health>();
            return targetToTest != null && !targetToTest.IsDead();
        }

        public void Attack(GameObject combatTarget)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = combatTarget.GetComponent<Health>();
        }

        public void Cancel()
        {
            StopAttack();
            target = null;
            GetComponent<Mover>().Cancel();
        }

        private void StopAttack()
        {
            GetComponent<Animator>().ResetTrigger("attack");
            GetComponent<Animator>().SetTrigger("stopAttack");
        }
    }
}
```

```C#:Weapon
using RPG.Core;
using UnityEngine;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class Weapon : ScriptableObject
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] GameObject equippedPrefab = null;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] float weaponRange = 2f;
        [SerializeField] bool isRightHanded = true;
        [SerializeField] Projectile projectile = null;


        public void Spawn(Transform rightHand, Transform leftHand, Animator animator)
        {
            if (equippedPrefab != null)
            {
                Transform handTransform = GetTransform(rightHand, leftHand);
                Instantiate(equippedPrefab, handTransform);
            }
            if (animatorOverride != null)
            {
                animator.runtimeAnimatorController = animatorOverride;
            }
        }

        private Transform GetTransform(Transform rightHand, Transform leftHand)
        {
            Transform handTransform;
            if (isRightHanded) handTransform = rightHand;
            else handTransform = leftHand;
            return handTransform;
        }

        public bool HasProjectile()
        {
            return projectile != null;
        }

        public void LaunchProjectile(Transform rightHand, Transform leftHand, Health target)
        {
            Projectile projectileInstance = Instantiate(projectile, GetTransform(rightHand, leftHand).position, Quaternion.identity);
            projectileInstance.SetTarget(target);
        }

        public float GetDamage()
        {
            return weaponDamage;
        }

        public float GetRange()
        {
            return weaponRange;
        }
    }
}
```

```C#:Projectile
using System.Collections;
using System.Collections.Generic;
using RPG.Core;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    [SerializeField] float speed = 1;

    Health target = null;

    void Update()
    {
        if (target == null) return;

        transform.LookAt(GetAimLocation());
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }

    public void SetTarget(Health target)
    {
        this.target = target;
    }

    private Vector3 GetAimLocation()
    {
        CapsuleCollider targetCapsule = target.GetComponent<CapsuleCollider>();
        if (targetCapsule == null)
        {
            return target.transform.position;
        }
        return target.transform.position + Vector3.up * targetCapsule.height / 2;
    }
}
```

3, AxeのProjectileにArrowProjectileをアタッチする
![55E99FD5-EC77-4FCF-82A8-840169611749.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/60df20f4-8750-0ce8-22ff-8ac9c58b3b42.jpeg)

ダメージの実装
---
1, 各スクリプトに下記のコードを書く

```C#:Projectile
using System.Collections;
using System.Collections.Generic;
using RPG.Core;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    [SerializeField] float speed = 1;
    Health target = null;
    float damage = 0; //追加

    void Update()
    {
        if (target == null) return;

        transform.LookAt(GetAimLocation());
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }

    public void SetTarget(Health target, float damage) //danageを追加
    {
        this.target = target;
        this.damage = damage; //追加
    }

    private Vector3 GetAimLocation()
    {
        CapsuleCollider targetCapsule = target.GetComponent<CapsuleCollider>();
        if (targetCapsule == null)
        {
            return target.transform.position;
        }
        return target.transform.position + Vector3.up * targetCapsule.height / 2;
    }

    //追加
    private void OnTriggerEnter(Collider other)
    {
        if (other.GetComponent<Health>() != target) return;
        target.TakeDamage(damage);
        Destroy(gameObject);
    }
}
```

```C#:Weapon
using RPG.Core;
using UnityEngine;

namespace RPG.Combat
{
    [CreateAssetMenu(fileName = "Weapon", menuName = "Weapons/Make New Weapon", order = 0)]
    public class Weapon : ScriptableObject
    {
        [SerializeField] AnimatorOverrideController animatorOverride = null;
        [SerializeField] GameObject equippedPrefab = null;
        [SerializeField] float weaponDamage = 5f;
        [SerializeField] float weaponRange = 2f;
        [SerializeField] bool isRightHanded = true;
        [SerializeField] Projectile projectile = null;


        public void Spawn(Transform rightHand, Transform leftHand, Animator animator)
        {
            if (equippedPrefab != null)
            {
                Transform handTransform = GetTransform(rightHand, leftHand);
                Instantiate(equippedPrefab, handTransform);
            }
            if (animatorOverride != null)
            {
                animator.runtimeAnimatorController = animatorOverride;
            }
        }

        private Transform GetTransform(Transform rightHand, Transform leftHand)
        {
            Transform handTransform;
            if (isRightHanded) handTransform = rightHand;
            else handTransform = leftHand;
            return handTransform;
        }

        public bool HasProjectile()
        {
            return projectile != null;
        }

        public void LaunchProjectile(Transform rightHand, Transform leftHand, Health target)
        {
            Projectile projectileInstance = Instantiate(projectile, GetTransform(rightHand, leftHand).position, Quaternion.identity);
            projectileInstance.SetTarget(target, weaponDamage); //weaponDamageを追加
        }

        public float GetDamage()
        {
            return weaponDamage;
        }

        public float GetRange()
        {
            return weaponRange;
        }
    }
}
```
2, ArrowProjectileにBoxColliderをつけ、サイズ調整、IsTriggerを付ける
![A776E65B-C782-428C-AB1E-3D95E48B0941.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/ffd7ad36-6288-ef9e-a57b-a84fa62f4f43.jpeg)

矢にエフェクトを実装
---
1, ArrowProjecttileにTrailを作成する
![B1BB165C-BCC2-4C47-A2E7-B748D0ABB343.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0223d07c-8107-7ad1-eaf2-2e09652bb97b.jpeg)

2, TrailのTime、Widthの数値を決める
![BBC38AAC-A383-43C8-83FB-F8EBBEDCB2BD.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/a8a491be-77a2-2f34-6580-737d85487d5e.jpeg)

3, ReceiveShadowのチェックを外す
![2DA1C22F-AE92-46F0-BE6B-845EA28C8EB6_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/14cc7e08-29f2-c80b-deda-842f01de410f.jpeg)

4, EnemyをPrefabVariantしてArcherを作成する
![06D40913-9DB2-4AD4-B7F3-B9E9840554E3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/d0b40bdf-bf73-da61-9661-b879ff078f2b.jpeg)

5, ArcherにWeaponを設定する
![9AA99BE2-16EF-4226-983C-97026FD71BE6_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/eed441c4-79eb-bad9-5ea8-2d85c1664f39.jpeg)

6, ArrowProjectileをPrefabVariantしてRedとBlueを作成
![B355D041-3181-47D0-A39A-111B4C7B9790.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/34a4407f-00c5-754d-9654-bcbc23c4bd05.jpeg)
![305818F0-4325-4DC9-826A-DF972367E537_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0dd8f531-e181-492a-c2e5-609e69b9ff5f.jpeg)

7, 各Trailのカラーを設定する
![9177D8A3-AD0C-49F2-8C35-C6F7F768BB1D.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/d88ec4d6-5de8-1580-61d5-04dd57b1ad29.jpeg)

8, Axeを複製し、AxeBlueProjectileとAxeRedProjectileを作成
![9B71E5BF-642B-4A23-998B-BB489432AB7A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/5a274840-6574-93cd-c0b5-2aa882119df5.jpeg)

9, 各AxeRedProjectile、Blueにオブジェクトをアタッチする
![DA860277-76C1-4D5C-81B5-EC1F3935AA9B.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/d00207f8-7306-d921-cdcf-884fd2c78548.jpeg)

10, Archer,PlayerそれぞれにWeaponを設定する
![CABFACE0-1F94-490F-AA10-318DC4E03EE2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/34feb894-e146-15c1-5c67-d4d0cfd55508.jpeg)