K-digital traning/유니티 심화

[주말과제] 궁수의 전설

내꺼블로그 2023. 8. 21. 00:02

1.현재 구현

 

- 플레이어 이동(조이스틱 or 키보드 둘 중 하나로 가능)

- 플레이어 공격(몬스터가 살아있는 상태에서 조이스틱을 놓을 경우(or 키보드를 건드리지 않을 경우) 플레이어는 몬스터를 공격)

- 플레이어 Idle(몬스터가 죽은 상태에서는 이동하지 않는 한 기본 상태)

- 몬스터는 아직 한 마리 구현

  ->generator를 구현하였으나 아직 게임을 관리해줄 game main을 못 만든 상태,,

- 몬스터 hp가 다 닳으면 소멸되도록 구현

 

 

 

2.구현 코드

 

(1) Player

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

public class Player : MonoBehaviour
{
    public enum eControlType
    {
        Keyboard, Joystick
    }

    public enum eState
    {
        Idle, Run, Shoot
    }

    [SerializeField]
    private float moveSpeed=2f;

    [SerializeField]
    private VariableJoystick joystick;

    private Transform tr;
    [SerializeField]
    private eControlType control;

    private Monster monster;

    [SerializeField]
    private BulletGenerator bulletGenerator;

    private Animator anim;
    private bool isShoot = true;
    private eState state;
    private Coroutine shootCoroutine;

    // Start is called before the first frame update
    void Start()
    {
        tr = this.gameObject.transform;
        this.anim=this.GetComponent<Animator>();
        
        GameObject go = GameObject.FindGameObjectWithTag("Monster");
        Debug.Log(go);
        monster = go.GetComponent<Monster>();
        monster.onDie = () =>
        {
            isShoot = false;
        };
    }

    // Update is called once per frame
    void Update()
    {
        float h, v;
        if(control == eControlType.Keyboard)
        {
            h = Input.GetAxisRaw("Horizontal");
            v = Input.GetAxisRaw("Vertical");
        }
        else
        {
            h = this.joystick.Direction.x;
            v = this.joystick.Direction.y;
        }

        Vector3 dir = Vector3.forward * v + Vector3.right * h;
        Debug.LogFormat("dir: {0}", dir);    

        if (dir != Vector3.zero)
        {
            float angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg;
            this.tr.localRotation = Quaternion.AngleAxis(angle, Vector3.up);
            this.tr.Translate(dir.normalized * this.moveSpeed * Time.deltaTime, Space.World);
            PlayAnimation(eState.Run);
        }
        else
        {
            if (isShoot)
                this.Shoot();
            else
                PlayAnimation(eState.Idle);
        }

    }

    private void Shoot()
    {
        Debug.LogFormat("monster: {0}", monster.transform.position);
        this.tr.LookAt(monster.transform.position);
        Debug.LogFormat("<color=yellow>rotation: {0}</color>", tr.rotation);
        PlayAnimation(eState.Shoot);
        if(shootCoroutine==null)
            this.shootCoroutine = StartCoroutine(CoShoot());
    }

    private IEnumerator CoShoot()
    {
        anim.Play("Shoot", -1, 0f);
        yield return new WaitForSeconds(0.015f);
        bulletGenerator.Generate();
        yield return new WaitForSeconds(0.485f);
        this.shootCoroutine = null;
    }

    private void PlayAnimation(eState state)
    {
        this.state = state;
        anim.SetInteger("State", (int)this.state); 
    }
}

 

 

 

(2) BulletGenerator

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

public class BulletGenerator : MonoBehaviour
{
    [SerializeField]
    private Transform trans;
    [SerializeField]
    private GameObject bulletPrefab;

    public void Generate()
    {
        GameObject go = Instantiate(bulletPrefab, trans);
        go.transform.Translate(Vector3.forward*0.2f);
        go.transform.parent = null;
    }
}

 

 

 

(3) Bullet

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

public class Bullet : MonoBehaviour
{
    private int damage = 1;
    [SerializeField]
    private float moveSpeed = 5f;
    
    void Update()
    {
        this.transform.Translate(Vector3.forward*moveSpeed*Time.deltaTime);
        if (this.transform.position.x >= 4 || this.transform.position.x <= -4 || this.transform.position.y >= 17 || this.transform.position.y <= -3)
            Destroy(this.gameObject);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Monster"))
        {
            Monster monster = other.GetComponent<Monster>();
            monster.HitDamage(this.damage);
            Destroy(this.gameObject);
        }
    }
}

 

 

 

 

 

(4) MonsterGenerator

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

public class MonsterGenerator : MonoBehaviour
{
    [SerializeField]
    private GameObject monsterPrefab;

    // Start is called before the first frame update
    void Start()
    {
        GameObject go = Instantiate(monsterPrefab);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

 

 

(5) Monster

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

public class Monster : MonoBehaviour
{
    private Transform tr;
    private int hp;
    public System.Action onDie;
    // Start is called before the first frame update
    void Start()
    {
        this.tr = this.gameObject.transform;
        this.tr.position = new Vector3(2, 0, 8);
        this.hp = 5;
    }

    // Update is called once per frame
    /*void Update()
    {
        
    }*/

    public void HitDamage(int damage)
    {
        this.hp -= damage;
        if (this.hp <= 0)
            this.Die();
    }

    void Die()
    {
        Destroy(this.gameObject);
        this.onDie();
    }
}

 

 

 

 

3. 결과

녹화를 프로그램 돌리기 전에 시작하지 못해서 나타난 움짤 모양(start 부분이 살짝 엉망,,)

지금 보니 콜라이더 모양도 다시 잡아야 될 것 같,,,

 

 

 

+추가로 구현해야되는 부분

- 몬스터 여러 마리 생성

- Game Main으로 게임 관리

  ->몬스터 리스트, 플레이어 프리팹 두고 game main에서 돌리기

- 몬스터 애니메이션 구현

- 그 밖 : 몬스터 플레이어 공격, 몬스터 아이템 드롭, 아이템에 따른 플레이어 성능 추가, 종스크롤 등등,,,

 

 

+구현하면서 포기한(?) 부분

플레이어도 프리팹으로 두고 등장시키고 싶었는데 조이스틱을 플레이어 스크립트 속성값에 넣으려니 Type mismatch가 떠버렸다. 검색을 해보니 Asset으로 저장해야 된다고 하는데 방법을 보다가 머리 터져서 pass (나중에 찬찬히 보기로,,,)