본문 바로가기
3D 콘텐츠 제작/[위저드 히어로] 제작 일지

[위저드 히어로05] 근거리 원거리 무기 및 플레이 영상

by 잰쟁 2023. 10. 10.
728x90

▶ 근거리 및 원거리 무기 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.TextCore.Text;
using UnityEngine.XR;

public class Weapon : MonoBehaviour
{
    //무기id, 프리팹id, damage, 갯수, 속도
    public int id;
    public int prefabId;
    public float damage;
    public int count;
    public float size;
    public float speed;

    private ParticleScaler particle;

    private float timer;

    private void Awake()
    {
        //부모 오브젝트에 있는 컴포넌트 가져오기
        //this.player = GameManager.instance.player;
        //this.transform.localPosition = GameManager.instance.player.transform.position;
    }

    void Update()
    {
        if (!GameManager.instance.isLive)
        {
            return;
        }

        //id 별로 관리
        switch (id)
        {
            case 0:
                this.transform.localPosition = Camera.main.WorldToScreenPoint(GameManager.instance.player.transform.position);
                //bullet(얼음 오브) 회전시키기
                this.transform.Rotate(Vector3.back * this.speed * Time.deltaTime);
                break;
            case 1:
                this.transform.localPosition = Camera.main.WorldToScreenPoint(GameManager.instance.player.transform.position);
                break;
            case 2:
                this.transform.localPosition = Camera.main.WorldToScreenPoint(GameManager.instance.player.stickPoint.transform.position);
                this.timer += Time.deltaTime;

                if (this.timer > this.speed)
                {
                    //timer 초기화
                    this.timer = 0f;
                    //총알 발사   
                    this.Fire();
                }
                break;
        }
    }

    //id별로 초기화
    public void Init(ItemData data)
    {
        //...Basic Set
        this.name = "Weapon" + data.itemId;
        //부모 transform 설정
        //this.transform.parent = player.transform;

        //..Property Set
        this.id = data.itemId;
        this.damage = data.baseDamage;
        this.count = data.baseCount;
        this.size = data.baseSize;

        for (int i = 0; i < GameManager.instance.pool.prefabs.Length; i++)
        {
            //무기 프리팹과 오브젝트 풀의 프리팹 연동
            if (data.projectile == GameManager.instance.pool.prefabs[i])
            {
                this.prefabId = i;
                Debug.LogFormat("<color=red>prefabId : {0}</color>", this.prefabId);
                break;
            }
        }

        switch (id)
        {
            case 0:
                this.speed = 180;
                this.Batch();
                break;
            case 2:
                //총알 발사 속도
                speed = 0.3f;
                break;
        }


        //player가 가지고 있는 모든 장비에 ApplyGear 적용
        //...특정 함수 호출을 모든 자식에게 방송하는 함수
        //2번째 인자값으로 'DontRequireReceiver' 추가 (꼭 receiver가 필요하지 않다)
        //this.player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
    }

    //...레벨업 메서드
    //레벨업 시 damage와 count 조절하기
    public void LevelUp(float damage, int count, float speed, float size)
    {
        this.damage = damage;
        this.count += count;
        this.speed = speed;
        this.size = size;

        //레벨 = 0 , 근접무기일 경우
        if (id == 0)
        {
            //배치해아함
            this.Batch();
        }
        else if(id == 1)
        {
            //아우라 사이즈 업
            this.particle.SizeUp(size);
        }
        else if(id == 2)
        {
            this.RateUp();
        }
        //...BroadcastMessage 초기화
        //this.player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
    }


    //...근거리 bullet(삽) 배치하기
    void Batch()
    {
        for (int i = 0; i < this.count; i++)
        {
            //...bullet 게임오브젝트 생성 후
            //Weapon의 자식으로 넣기 위해 transform가져와 지역변수에 넣기
            Transform bullet;

            //...i가 childCount 범위 내라면
            if (i < this.transform.childCount)
            {
                //현재 child를 사용
                bullet = this.transform.GetChild(i);
            }
            else
            {
                //...i가 범위를 넘어서면
                //'모자란 수 만큼' 풀링으로 가져옴
                bullet = GameManager.instance.pool.Get(prefabId).transform;
                //현재 transform을 부모로 설정
                //bullet.parent = this.transform;
            }

            //...bullet위치 player의 위치로 초기화
            //levelup 했을때 위치 오류 방지
            bullet.localPosition = GameManager.instance.player.transform.position;
            bullet.localRotation = Quaternion.identity;

            //...회전 각도(z축) 설정
            //count(갯수)만큼 회전각 나누어서 배치
            Vector3 rot = Vector3.forward * 360 * i / count;
            bullet.Rotate(rot);
            //Player로 부터 1.5f 거리만큼 떨어져서 위치
            bullet.Translate(bullet.right * 2f, Space.World);

            //bullet 초기화
            bullet.GetComponent<Bullet>().Init(this.damage, -1, Vector3.zero);  // -1 == 무한, 무한 관통
        }
    }

    //...원거리 Bullet(총알) 발사
    void Fire()
    {
        if (!GameManager.instance.player.scanner.nearestTarget)
        {
            return;
        }

        //가장 가까운 몬스터 위치
        Vector3 targetPos = GameManager.instance.player.scanner.nearestTarget.position;
        //...총알 방향 설정
        Vector3 dir = targetPos - transform.position;
        //현재 Vector의 방향은 유지, 크기는 1로 변환
        dir = dir.normalized;

        Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
        bullet.position = this.transform.position;
        bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);

        //bullet 초기화
        bullet.GetComponent<Bullet>().Init(this.damage, count, dir);  // -1 == 무한, 무한 관통

    }

    void RateUp()
    {
        switch (id)
        {
            //id =2 -> 얼음 발사
            case 2:
                float speed = 180;
                this.speed = speed + (speed * this.speed);
                break;
        }    
    }
}
using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using UnityEngine;
using UnityEngine.UI;


public class Item : MonoBehaviour
{
    public ItemData data;
    public int level;
    public Weapon weapon;
    public Gear gear;

    private Text txtName;
    private Text txtDesc;
    private Text txtLevel;
    private Image icon;
    private Image bg;

    void Awake()
    {
        //GetComponentsInchildren에서 2번째 값으로 가져오기(1번째 : 자기자신)
        this.bg = this.GetComponentsInChildren<Image>()[1];
        this.icon = this.GetComponentsInChildren<Image>()[2];

        //아이콘 넣어주기
        this.icon.sprite = data.itemIcon;
        this.bg.sprite = data.bgIcon;

        Text[] texts = GetComponentsInChildren<Text>();
        this.txtLevel = texts[0];
        this.txtName = texts[1];
        this.txtDesc = texts[2];

        //이름 넣어주기
        this.txtName.text = data.itemName;
    }

    //활성화시 동작
    void OnEnable()
    {
        //레벨 1부터 시작
        txtLevel.text = string.Format("Lv.{0}", (level + 1).ToString());
        switch (data.itemType) 
        {
            case ItemData.eItemType.Orb:
                txtDesc.text = string.Format(data.descs[level], data.damages[level] * 100, data.counts[level],data.speeds[level] * 100);
                break;
            case ItemData.eItemType.Aura:
                txtDesc.text = string.Format(data.descs[level], data.damages[level] * 100, data.sizes[level] * 100);
                break;
            case ItemData.eItemType.Ice_Bolt:
                //..count 뺀 나머지 --> 백분율
                txtDesc.text = string.Format(data.descs[level], data.damages[level] * 100, data.counts[level]);
                break;
            case ItemData.eItemType.Heal:
            case ItemData.eItemType.Shoe:
            case ItemData.eItemType.Shield:
                //모두 --> 백분율
                txtDesc.text = string.Format(data.descs[level],data.damages[level]*100);
                break;
        }

    }

    public void OnClick()
    {
        switch (data.itemType) 
        {
            case ItemData.eItemType.Orb:
                if (level == 0)
                {
                    GameObject newWeapon = new GameObject();
                    this.weapon = newWeapon.AddComponent<Weapon>();
                    //Weapon 초기화
                    this.weapon.Init(data);
                    this.weapon.transform.Rotate(new Vector3(90, 0, 0));
                }
                else
                {
                    //...처음 이후의 레벨업은 데미지와 횟수를 계산
                    //새로운 무기이면 damage 올려줘야함
                    float nextDamage = data.baseDamage;
                    int nextCount = 0;
                    float nextSpeed = data.baseSpeed;

                    //damages가 백분률 값이므로 곱해준 다음 더해줌
                    nextDamage += data.baseDamage * data.damages[level];
                    nextCount += data.counts[level];
                    nextSpeed += data.baseSpeed * data.speeds[level];

                    //Weapon 레벨업
                    weapon.LevelUp(nextDamage, nextCount,nextSpeed,0);
                }
                //level 증가
                level++;
                break;
            case ItemData.eItemType.Ice_Bolt:
                if (level == 0)
                {
                    GameObject newWeapon = new GameObject();
                    this.weapon = newWeapon.AddComponent<Weapon>();
                    //Weapon 초기화
                    this.weapon.Init(data);
                }
                else
                {
                    //...처음 이후의 레벨업은 데미지와 횟수를 계산
                    //새로운 무기이면 damage 올려줘야함
                    float nextDamage = data.baseDamage;
                    int nextCount = 0;

                    //damages가 백분률 값이므로 곱해준 다음 더해줌
                    nextDamage += data.baseDamage * data.damages[level];
                    nextCount += data.counts[level];

                    //Weapon 레벨업
                    weapon.LevelUp(nextDamage, nextCount,0,0);
                }
                //level 증가
                level++;
                break;
            case ItemData.eItemType.Aura:
                if (level == 0)
                {
                    GameObject newWeapon = new GameObject();
                    this.weapon = newWeapon.AddComponent<Weapon>();
                    //Weapon 초기화
                    this.weapon.Init(data);
                }
                else
                {
                    //...처음 이후의 레벨업은 데미지와 횟수를 계산
                    //새로운 무기이면 damage 올려줘야함
                    float nextDamage = data.baseDamage;
                    float nextSize = data.baseSize;

                    //damages가 백분률 값이므로 곱해준 다음 더해줌
                    nextDamage += data.baseDamage * data.damages[level];
                    nextSize += data.baseSize * data.sizes[level];

                    //Weapon 레벨업
                    weapon.LevelUp(nextDamage, 0, 0, nextSize);
                }
                //level 증가
                level++;
                break;
            case ItemData.eItemType.Shoe:
            case ItemData.eItemType.Shield:
            case ItemData.eItemType.Heal:
                if (level == 0)
                {
                    GameObject newGear = new GameObject();
                    this.gear = newGear.AddComponent<Gear>();
                    //Gear 초기화
                    this.gear.Init(data);
                }
                else
                {
                    float nextRate = data.damages[level];
                    gear.LevelUp(nextRate);
                }
                break;
           
        }

        //...레벨 개수 넘기지 않게 로직 추가
        //Damages의 배열길이:5 를 넘어가면 Button의 interactable 비활성화(투명하게)
        if (level == data.descs.Length)
        {
            GetComponent<Button>().interactable = false;
        }
    }
}

 

 

부모 - 자식 관계 수정

https://m.blog.naver.com/yoohee2018/221187229189

 

오브젝트간 움직임을 연결하는 4가지 방법.

Unity 2017.3 ver. 예를 들어 player가 박스를 들고 움직이는 동작을 처리해야 할 때, 여러가지 방법이 있...

blog.naver.com

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.TextCore.Text;
using UnityEngine.XR;

public class Weapon : MonoBehaviour
{
    //무기id, 프리팹id, damage, 갯수, 속도
    public int id;
    public int prefabId;
    public float damage;
    public int count;
    public float size;
    public float speed;

    private ParticleScaler particle;

    private Player player;
    private float timer;

    private void Awake()
    {
        //부모 오브젝트에 있는 컴포넌트 가져오기
        this.player = GameManager.instance.player;
    }

    void Update()
    {
        if (!GameManager.instance.isLive)
        {
            return;
        }

        //id 별로 관리
        switch (id)
        {
            case 0:
                //bullet(얼음 오브) 회전시키기
                this.transform.Rotate(Vector3.back * this.speed * Time.deltaTime);
                break;
            case 1:

                break;
            case 2:
                if (this.timer > this.speed)
                {
                    //timer 초기화
                    this.timer = 0f;
                    //총알 발사   
                    this.Fire();
                }
                break;
        }
    }

    //id별로 초기화
    public void Init(ItemData data)
    {
        //...Basic Set
        this.name = "Weapon" + data.itemId;
        //부모 transform 설정
        this.transform.parent = this.player.transform;
        this.transform.localPosition = Vector3.zero;

        //..Property Set
        this.id = data.itemId;
        this.damage = data.baseDamage;
        this.count = data.baseCount;
        this.size = data.baseSize;

        for (int i = 0; i < GameManager.instance.pool.prefabs.Length; i++)
        {
            //무기 프리팹과 오브젝트 풀의 프리팹 연동
            if (data.projectile == GameManager.instance.pool.prefabs[i])
            {
                this.prefabId = i;
                Debug.LogFormat("<color=red>prefabId : {0}</color>", this.prefabId);
                break;
            }
        }

        switch (id)
        {
            case 0:
                this.speed = 180;
                this.Batch();
                break;
            case 2:
                //총알 발사 속도
                speed = 0.3f;
                break;
        }


        //player가 가지고 있는 모든 장비에 ApplyGear 적용
        //...특정 함수 호출을 모든 자식에게 방송하는 함수
        //2번째 인자값으로 'DontRequireReceiver' 추가 (꼭 receiver가 필요하지 않다)
        //this.player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
    }

    //...레벨업 메서드
    //레벨업 시 damage와 count 조절하기
    public void LevelUp(float damage, int count, float speed, float size)
    {
        this.damage = damage;
        this.count += count;
        this.speed = speed;
        this.size = size;

        //레벨 = 0 , 근접무기일 경우
        if (id == 0)
        {
            //배치해아함
            this.Batch();
        }
        else if(id == 1)
        {
            //아우라 사이즈 업
            this.particle.SizeUp(size);
        }
        else if(id == 2)
        {
            this.RateUp();
        }
        //...BroadcastMessage 초기화
        //this.player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
    }


    //...근거리 bullet(삽) 배치하기
    void Batch()
    {
        for (int i = 0; i < this.count; i++)
        {
            //...bullet 게임오브젝트 생성 후
            //Weapon의 자식으로 넣기 위해 transform가져와 지역변수에 넣기
            Transform bullet;

            //...i가 childCount 범위 내라면
            if (i < this.transform.childCount)
            {
                //현재 child를 사용
                bullet = this.transform.GetChild(i);
            }
            else
            {
                //...i가 범위를 넘어서면
                //'모자란 수 만큼' 풀링으로 가져옴
                bullet = GameManager.instance.pool.Get(prefabId).transform;
                //현재 transform을 부모로 설정
                bullet.parent = this.transform;
            }

            //...bullet위치 player의 위치로 초기화
            //levelup 했을때 위치 오류 방지
            bullet.localPosition = Vector3.zero;
            bullet.localRotation = Quaternion.identity;

            //...회전 각도(z축) 설정
            //count(갯수)만큼 회전각 나누어서 배치
            Vector3 rot = Vector3.forward * 360 * i / count;
            bullet.Rotate(rot);
            //Player로 부터 1.5f 거리만큼 떨어져서 위치
            bullet.Translate(bullet.up * 2f, Space.World);

            //bullet 초기화
            bullet.GetComponent<Bullet>().Init(this.damage, -1, Vector3.zero);  // -1 == 무한, 무한 관통
        }
    }

    //...원거리 Bullet(총알) 발사
    void Fire()
    {
        if (!this.player.scanner.nearestTarget)
        {
            return;
        }

        //가장 가까운 몬스터 위치
        Vector3 targetPos = this.player.scanner.nearestTarget.position;
        //...총알 방향 설정
        Vector3 dir = targetPos - transform.position;
        //현재 Vector의 방향은 유지, 크기는 1로 변환
        dir = dir.normalized;

        Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
        bullet.position = this.transform.position;
        bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);

        //bullet 초기화
        bullet.GetComponent<Bullet>().Init(this.damage, count, dir);  // -1 == 무한, 무한 관통

    }

    void RateUp()
    {
        switch (id)
        {
            //id =2 -> 얼음 발사
            case 2:
                float speed = 180;
                this.speed = speed + (speed * this.speed);
                break;
        }    
    }
}

 

**문제 해결

Player와 동등한 관계인 빈 오브젝트를 만들고 Player position과 동등하게 해주는 스크립트를 생성하여 넣어준다.

별거 아니지만 그래도 해결해서 다행이다ㅜㅜ

 

PlayerPos 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPos : MonoBehaviour
{
    void Update()
    {
        this.transform.position = new Vector3(GameManager.instance.player.transform.position.x, 0, GameManager.instance.player.transform.position.z);
    }
}

 


 

🎥게임 플레이 영상 및 소감

 

: 요새 개인적인 일이 좀 생겨서 솔직히 이 프로젝트에 온전히 집중하지 못했다..

그래서 제작 과정을 꼼꼼히 적지 못하여 많이 아쉽고 반성도 많이 했다. 그래도 마무리는 지어서 다행이라고 생각한다.

 

 

플레이 영상