본문 바로가기

Unity 공부/Unity_2D

[Day 10] 무기 장착 표현

[ 무기 장착 표현 ] --> 플레이어블 캐릭터가 능력을 흭득 했을 때, 무기 장착을 UI로 표현

  • Player 자식 오브젝트로 2D Object --> Sprites --> Triangle(아무거나 상관 없음) 생성
        - 이름을 Hand Left로 변경 
        - Sprite를 Props의 Weapon 0으로 변경(드래그&드랍)
        - Order in Layer를 6으로 설정
        - Rotation의 Z축을 -35로 설정
        - Position의 X = -0.17, Y = -0.38로 설정
  • Ctrl + D하여 Hand Left 복사 후 이름 Hand Right로 변경
        - Sprite를 Props의 Weapon 3으로 변경(드래그&드랍)
        - Rotation의 Z축을 0으로 설정
        - Position의 X = 0.35, Y = -0.15로 설정
        - Order in Layer를 4로 설정
  • C# 스크립트 생성(Hand)
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Hand : MonoBehaviour
{
    public bool isLeft; // 왼손, 오른손 구분 변수
    public SpriteRenderer spriter; // SpriterRenderer 변수

    SpriteRenderer player; // 플레이어의 SpriterRenderer 변수 선언

    Vector3 rightPos = new Vector3(0.35f, -0.15f, 0); // 오른손 각 위치
    Vector3 rightposReverse = new Vector3(-0.15f, -0.15f, 0); // 오른손 반전 위치
    Quaternion leftRot = Quaternion.Euler(0, 0, -35); // 왼손 위치
    Quaternion leftRotReverse = Quaternion.Euler(0, 0, -135); // 왼손 반전 위치

    private void Awake()
    {
        player = GetComponentsInParent<SpriteRenderer>()[1]; // 플레이어의 SpriterRenderer 변수 초기화
    }

    private void LateUpdate()
    {
        bool isReverse = player.flipX; // 플레이어의 반전 상태

        if (isLeft) // 근접무기
        {
            transform.localRotation = isReverse ? leftRotReverse : leftRot;
            spriter.flipY = isReverse; // 왼손 스프라이트 Y축 반전
            spriter.sortingOrder = isReverse ? 4 : 6;
        }
        else // 원거리 무기
        {
            transform.localPosition = isReverse ? rightposReverse : rightPos;
            spriter.flipX = isReverse; // 오른손 스프라이트 X축 반전
            spriter.sortingOrder = isReverse ? 6 : 4;
        }
    }
}
  • Hand Left/Right 오브젝트에 Add Component
        - Hand(Script)
  • Hand Left/Right 각각 Sprite Renderer를 Spriter에 넣어주기(드래그&드랍)
  • Hand Left의 IsLeft 체크
  • Hand Left/Right에 연결되어 있는 Sprite 삭제
  • Hand Left/Right 오브젝트 비활성화
  • 기존의 Item Data 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "Item", menuName = "Scriptble Object/ItemData")]
public class ItemData : ScriptableObject
{
    public enum ItemType { Melee, Range, Glove, Shoe, Heal }
    [Header("# Main Info")]
    public ItemType itemType;
    public int itemId;
    public string itemName;
    public string itemDesc;
    public Sprite itemIcon;

    [Header("# Level Data")]
    public float baseDamage;
    public int baseCount;
    public float[] damages;
    public int[] counts;

    [Header("# Weapon")]
    public GameObject projectile;
    public Sprite hand; // hand 스프라이트 속성
}
  • Data 폴더의 Item 0,1의 Hand에 각각 Weapon 0, 3 넣어주기
  • 기존의 Player 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    public Vector2 inputVec;
    public float speed;
    public Scanner scanner;
    public Hand[] hands; // 손 스크립트를 담을 배열변수 선언

    Rigidbody2D rigid;
    SpriteRenderer spriter;
    Animator anim;
    
    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriter = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
        scanner = GetComponent<Scanner>();
        hands = GetComponentsInChildren<Hand>(true); // 배열변수 초기화(비활성화 된 오브젝트 활성화)
    }

    void Update()
    {
        inputVec.x = Input.GetAxisRaw("Horizontal");
        inputVec.y = Input.GetAxisRaw("Vertical");
    }

    private void FixedUpdate()
    {
        Vector2 nextVec = inputVec.normalized*speed* Time.fixedDeltaTime;
        rigid.MovePosition(rigid.position + nextVec);
    }

    private void LateUpdate()
    {
        anim.SetFloat("Speed", inputVec.magnitude); 

        if (inputVec.x != 0) 
        {
            spriter.flipX = inputVec.x < 0;
        }
    }
}
  • 기존의 Weapon 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
using UnityEngine;

public class Weapon : MonoBehaviour
{
    public int id;
    public int prefabId;
    public float damage;
    public int count;
    public float speed;

    float timer;
    Player player;

    void Awake(){
        player = GameManager.instance.player;
    }

    void Update(){
        switch (id){
            case 0:
                transform.Rotate(Vector3.back * speed * Time.deltaTime);
                break;

            default:
                timer += Time.deltaTime;

                if(timer > speed){
                    timer = 0f;
                    Fire();
                }
                break;

        }

        // .. Test Code ..
        if (Input.GetButtonDown("Jump")){
            LevelUp(10, 1);
        }
    }

    public void LevelUp(float damage, int count)
    {
        this.damage += damage;
        this.count += count;

        if(id == 0){
            Batch();
        }

        player.BroadcastMessage("ApplyGear",SendMessageOptions.DontRequireReceiver);
    }

    public void Init(ItemData data)
    {
        // Basic Set
        name = "Weapon " + data.itemId;
        transform.parent = player.transform;
        transform.localPosition = Vector3.zero;

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

        for(int index=0; index<GameManager.instance.pool.prefabs.Length; index++){
            if (data.projectile == GameManager.instance.pool.prefabs[index]){
                prefabId = index;
                break;
            }    
        }

        switch(id){
            case 0:
                speed = 150; // (+) --> 반시계방향
                Batch();
                break;

            default:
                speed = 0.3f;
                break;
        }

        // Hand Set
        Hand hand = player.hands[(int)data.itemType]; // Hand 오브젝트 가져오기
        hand.spriter.sprite = data.hand; // 스크립트블 오브젝트의 데이터로 스프라이트 적용
        hand.gameObject.SetActive(true); // 활성화

        player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
    }

    void Batch(){
        for(int index=0; index < count; index++) {
            Transform bullet;
           
            if(index < transform.childCount){
                bullet = transform.GetChild(index);
            }
            else{
                bullet = GameManager.instance.pool.Get(prefabId).transform;
                bullet.parent = transform;

            }

            bullet.localPosition = Vector3.zero;
            bullet.localRotation = Quaternion.identity;

            Vector3 rotVec = Vector3.forward * 350 * index / count;
            bullet.Rotate(rotVec);
            bullet.Translate(bullet.up * 1.5f, Space.World);
            bullet.GetComponent<Bullet>().Init(damage, -1, Vector3.zero); // -1 is Infinity Per.

        }
    }

    void Fire()
    {
        if (!player.scanner.nearestTarget){
            return;
        }

        Vector3 targetPos = player.scanner.nearestTarget.position;
        Vector3 dir = targetPos - transform.position;
        dir = dir.normalized;

        Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
        bullet.position = transform.position;
        bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);
        bullet.GetComponent<Bullet>().Init(damage, count, dir);

    }
}

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

★Slow and Steady★

'Unity 공부 > Unity_2D' 카테고리의 다른 글

[Day 12] 게임 시작과 종료 구현  (0) 2023.07.18
[Day 11] 레벨업 시스템  (0) 2023.07.17
[Day 9] 능력 업그레이드 구현  (0) 2023.07.15
[Day 8] HUD 제작  (0) 2023.07.14
[Day 7] 타격감 있는 몬스터 처치 구현  (0) 2023.07.13