본문 바로가기
Development/멋쟁이사자처럼 게임개발 부트캠프

[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 21일차 - Katana ZERO (2)

by jjeondeuk1008 2025. 4. 3.
반응형

 

[ 목차 ]


     

    지난 포스팅에서 Katana ZERO (1)에 이어서 2번째 포스팅이다.

     

    이번 포스팅은 캐릭터 애니메이션에 추가적으로 이어서 하는 것과

    디테일과 이펙트를 위주로 진행한다.

     

    전의 포스팅을 보고 싶다면 아래 링크로 들어가길 바란다!

     

     

    Katana ZERO (1)

     

    [멋쟁이사자처럼 Unity 게임 부트캠프 4기] 20일차 - Katana ZERO (1)

    [ 목차 ]  1945에 이어서 다른 게임을 실습해 보는 가진다.  횡스크롤 종류의 KATANA ZERO 게임을 구현해 볼 것이다.2D 횡스크롤은 엄청나게 많은 종류이면서 게임의 기본 중 기본이라고도 볼 수 있

    gang-design.com

     

     

     

    그럼 Katana ZERO 2번째 실습 시작!

     

     

     

     


     

     

     

    1. 공격 이펙트

     

     

     

    지난 블로그 글에 이어서 이펙트 추가 설정을 하도록 한다.

     

    새로운 스크립트를 만들 것이다.

    Slash 이름의 스크립트를 만들고, 플레이어의 위치를 따라다니면서 마우스 방향을 바라보도록 설정한다.

     

    Player 태그로 플레이어 게임 오브젝트를 찾는다.

    MousePos로 마우스 위치를 가져온다.

     

    그리고 공격이펙트가 끝나면 오브젝트가 삭제된다.

    using UnityEngine;
    
    public class Slash : MonoBehaviour
    {
        private GameObject p;
        Vector2 MousePos;
        Vector3 dir;
    
        float angle;
        Vector3 dirNo;
    
        public Vector3 direction = Vector3.right;
    
        
        void Start()
        {
            p = GameObject.FindGameObjectWithTag("Player");
    
            Transform tr = p.GetComponent<Transform>();
            MousePos = Input.mousePosition;
            MousePos = Camera.main.ScreenToWorldPoint(MousePos);
            Vector3 Pos = new Vector3(MousePos.x, MousePos.y, 0);
            dir = Pos - tr.position;
    
    
            //바라보는 각도 구하기
            angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        }
    
        
        void Update()
        {
            //회전적용
            transform.rotation = Quaternion.Euler(0f, 0f, angle);
            transform.position = p.transform.position;
        }
    
        public void Des()
        {
            Destroy(gameObject);
        }
    
    }

     

     

     

     

    이제 Slash 오브젝트의 Animation으로 가서 끝 프레임에 Add Event로 추가한다.

     

     

     

    Event를 추가하면 Inspector에 스스로를 삭제하는 메서드 Des()를 추가한다.

     

     

     

     

    이제 플레이어의 방향을 확인해서 Slash 오브젝트가 생성되는 것을 설정해 보겠다.

    Player 스크립트에서 새로운 메서드를 추가한다.

    public void AttSlash()
    {
        // 플레이어가 오른쪽을 바라보고 있을 때
        if (sp.flipX == false)
        {
            // 새로운 슬래시 오브젝트 생성 (오른쪽 방향)
            GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
            go.GetComponent<SpriteRenderer>().flipX = sp.flipX; // 플레이어의 방향에 맞춰 스프라이트 플립 설정
        }
        else
        {
            // 새로운 슬래시 오브젝트 생성 (왼쪽 방향)
            GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
            go.GetComponent<SpriteRenderer>().flipX = sp.flipX; // 왼쪽 방향으로 스프라이트 플립 설정
        }
    }

     

     

     

    여기에서 추가 Tip!

    필드 상단에 이 코드를 작성하면

    [Header("플레이어 속성")]
    

     

     

    이렇게 구분 지을 수 있는 플레이어 속성 텍스트가 나타나게 된다.

     

     

     

    그렇게 Player 전체 스크립트이다.

    using UnityEngine;
    
    public class Player : MonoBehaviour
    {
        [Header("플레이어 속성")]
        public float speed = 5;
        public float jumpUp = 1;
        public float power = 5;
        public Vector3 direction;
        public GameObject slash;
    
        bool bJump = false;
        Animator pAnimator;
        Rigidbody2D pRig2D;
        SpriteRenderer sp;
    
        void Start()
        {
            pAnimator = GetComponent<Animator>();
            pRig2D = GetComponent<Rigidbody2D>();
            direction = Vector2.zero;
            sp = GetComponent<SpriteRenderer>();
    
        }
    
    
        void KeyInput()
        {
            direction.x = Input.GetAxisRaw("Horizontal"); //왼쪽은 -1   0   1
    
            if(direction.x <0)
            {
                //left
                sp.flipX = true;
                pAnimator.SetBool("Run", true);
            }
            else if(direction.x >0)
            {
                //right
                sp.flipX = false;
                pAnimator.SetBool("Run", true);
            }
            else if(direction.x == 0)
            {
                pAnimator.SetBool("Run", false);
            }
    
    
            if(Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
            {
                pAnimator.SetTrigger("Attack");
            }
    
    
    
    
        }
    
        
        void Update()
        {
            KeyInput();
            Move();
    
            if(Input.GetKeyDown(KeyCode.W))
            {
                if(pAnimator.GetBool("Jump")==false)
                {
                    Jump();
                    pAnimator.SetBool("Jump", true);
                }
              
            }
    
        }
    
        private void FixedUpdate()
        {
            Debug.DrawRay(pRig2D.position, Vector3.down, new Color(0, 1, 0));
    
            //레이캐스트로 땅체크 
            RaycastHit2D rayHit = Physics2D.Raycast(pRig2D.position, Vector3.down, 1, LayerMask.GetMask("Ground"));
    
            if(pRig2D.linearVelocityY < 0)
            {
                if(rayHit.collider != null)
                {
                    if(rayHit.distance <0.7f)
                    {
                        pAnimator.SetBool("Jump", false);
                    }
                }
            }
    
    
        }
    
    
    
    
    
    
    
    
        public void Jump()
        {
            pRig2D.linearVelocity = Vector2.zero;
    
            pRig2D.AddForce(new Vector2(0, jumpUp), ForceMode2D.Impulse);
        }
    
    
    
    
    
        public void Move()
        {
            transform.position += direction * speed * Time.deltaTime;
        }
    
    
    
        public void AttSlash()
        {
            //플레이어 오른쪽
            if(sp.flipX == false)
            {
                pRig2D.AddForce(Vector2.right * power, ForceMode2D.Impulse);
                //플레이어 오른쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
            else
            {
    
                pRig2D.AddForce(Vector2.left * power, ForceMode2D.Impulse);
                //왼쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }   
    
        }
    
    }

     

     


     

     

     

    2. 이동 시에 그림자 추가

     

     

    플레이어가 이동할 때 디테일 추가를 위한 그림자를 표현해 보도록 하겠다.

    플레이어 모션 그림자 이미지를 자르고 pixels per unit을 기존 player와 동일하게 맞추어준다.

     

     

     

    저 이미지의 Animation ClipAnimator Controller를 생성해 준다.

     

     

     

     

    이제 스크립트를 새로 생성한다.

    Shadow 스크립트이다.

     

    Player 태그를 가져오고 선형 보간을 사용해 부드러운 이동에 도움이 되도록 한다.

    using UnityEngine;
    
    public class Shadow : MonoBehaviour
    {
        private GameObject player;
        public float TwSpeed = 10;
    
        void Start()
        {
            
        }
    
        void Update()
        {
            //Player 태그 가져오기
            player = GameObject.FindGameObjectWithTag("Player");
    
            //Vector3.Lerp : 위치가 가까워지면 천천히 느려진다.
            //선형 보간이라고도 칭한다. -> 부드러운 이동에 적합
            transform.position = Vector3.Lerp(transform.position, player.transform.position, TwSpeed * Time.deltaTime);
        }
    }
    
    

     

     

     

     

    스크립트를 해당 이미지에 넣어주고 프리팹화 한다.

     

     

     

     

    Player 스크립트로 이동해 코드를 추가한다.

    using System.Collections.Generic;
    

     

     

    그림자 오브젝트를 저장하는 변수를 지니고,

    생성된 그림자 오브젝트를 저장하는 리스트를 작성한다.

    //그림자
    public GameObject Shadow1;
    List<GameObject> sh = new List<GameObject>();
    

     

     

     

    최대 그림자는 6개로 유지되도록 제한한다.

    그림자 개수가 많을수록 속도가 느려진다.

    //그림자
    public void RunShadow()
    {
        if(sh.Count < 6)
        {
            GameObject go = Instantiate(Shadow1, transform.position, Quaternion.identity);
            go.GetComponent<Shadow>().TwSpeed = 10 - sh.Count;
        }
    }
    

     

     

     

    그렇게 Player의 전체 스크립트이다.

    using System.Collections.Generic;
    using UnityEngine;
    
    public class Player : MonoBehaviour
    {
        [Header("플레이어 속성")]
        public float speed = 5;
        public float jumpUp = 1;
        public float power = 5;
    
        //그림자
        public GameObject Shadow1;
        List<GameObject> sh = new List<GameObject>();
    
        public Vector3 direction;
        public GameObject slash;
    
        bool bJump = false;
        Animator pAnimator;
        Rigidbody2D pRig2D;
        SpriteRenderer sp;
    
        void Start()
        {
            pAnimator = GetComponent<Animator>();
            pRig2D = GetComponent<Rigidbody2D>();
            direction = Vector2.zero;
            sp = GetComponent<SpriteRenderer>();
    
        }
    
        void KeyInput()
        {
            direction.x = Input.GetAxisRaw("Horizontal"); //왼쪽은 -1   0   1
    
            if(direction.x <0)
            {
                //left
                sp.flipX = true;
                pAnimator.SetBool("Run", true);
            }
            else if(direction.x >0)
            {
                //right
                sp.flipX = false;
                pAnimator.SetBool("Run", true);
            }
            else if(direction.x == 0)
            {
                pAnimator.SetBool("Run", false);
            }
    
            if(Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
            {
                pAnimator.SetTrigger("Attack");
            }
    
        }
    
        
        void Update()
        {
            KeyInput();
            Move();
    
            if(Input.GetKeyDown(KeyCode.W))
            {
                if(pAnimator.GetBool("Jump")==false)
                {
                    Jump();
                    pAnimator.SetBool("Jump", true);
                }
              
            }
    
        }
    
        private void FixedUpdate()
        {
            Debug.DrawRay(pRig2D.position, Vector3.down, new Color(0, 1, 0));
    
            //레이캐스트로 땅체크 
            RaycastHit2D rayHit = Physics2D.Raycast(pRig2D.position, Vector3.down, 1, LayerMask.GetMask("Ground"));
    
            if(pRig2D.linearVelocityY < 0)
            {
                if(rayHit.collider != null)
                {
                    if(rayHit.distance <0.7f)
                    {
                        pAnimator.SetBool("Jump", false);
                    }
                }
            }
    
        }
    
        public void Jump()
        {
            pRig2D.linearVelocity = Vector2.zero;
    
            pRig2D.AddForce(new Vector2(0, jumpUp), ForceMode2D.Impulse);
        }
    
        public void Move()
        {
            transform.position += direction * speed * Time.deltaTime;
        }
    
        public void AttSlash()
        {
            if(sp.flipX == false)
            {
                pRig2D.AddForce(Vector2.right * power, ForceMode2D.Impulse);
    
                //플레이어 오른쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
            else
            {
                pRig2D.AddForce(Vector2.left * power, ForceMode2D.Impulse);
    
                //플레이어 왼쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
        }
    
        //그림자
        public void RunShadow()
        {
            if(sh.Count < 6)
            {
                GameObject go = Instantiate(Shadow1, transform.position, Quaternion.identity);
                go.GetComponent<Shadow>().TwSpeed = 10 - sh.Count;
                sh.Add(go);
            }
        }
    
    }
    
    

     

     

     

     

     

    이제 플레이어가 뛰고 있을 때의 타이밍에 넣어보도록 한다.

    Player Anmation의 player_run의 Inspector를 본다.

    Motion을 더블 클릭하면 Animation 창이 열릴 것이다.

     

     

     

    이렇게 window 외에도 열어줄 방법이 생겼다.

     

     

     

     

    Animation이 현재 player_idle로 선택되어 있는 것을 player_run으로 바꾸어준다.

     

     

     

     

    달리기를 시작할 때 넣어주도록 하겠다.

    0 프레임에 책갈피 아이콘을 클릭해 넣어준다.

     

     

     

    책갈피 아이콘을 클릭해

    Inspector에서 Function - Player - Methods - RunShadow()를 선택한다.

     

     

     

     

    이제 player_run2로 간다.

     

     

     

    player_run과 동일한 방법으로 수행한다.

     

     

     

     

    프리팹으로 만든 그림자를 Shadow1에 넣어준다.

     

     

     

     

    이제 그림자의 방향을 바꾸어보겠다.

    기존에 있는 Player 스크립트에서

    KeyInput() 메서드로 간다.

     

    이미지도 Flip 효과와 동일하게 그림자도 같이 방향 전환이 되도록 한다.

    void KeyInput()
    {
        direction.x = Input.GetAxisRaw("Horizontal"); //왼쪽은 -1   0   1
    
        if (direction.x < 0)
        {
            //left
            sp.flipX = true;
            pAnimator.SetBool("Run", true);
    
            //Shadowflip
            for (int i = 0; i < sh.Count; i++)
            {
                sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
    
        }
        
        else if (direction.x > 0)
        {
            //right
            sp.flipX = false;
            pAnimator.SetBool("Run", true);
    
            //Shadowflip
            for (int i = 0; i < sh.Count; i++)
            {
                sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
        }
        
        else if (direction.x == 0)
        {
            pAnimator.SetBool("Run", false);
    
            for (int i = 0; i < sh.Count; i++)
            {
                Destroy(sh[i]); //게임오브젝트지우기
                sh.RemoveAt(i); //게임오브젝트 관리하는 리스트지우기
            }
        }
    
        if (Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
        {
            pAnimator.SetTrigger("Attack");
        }
    
    }
    

     

     

     

     


     

     

    3. 지형지물 인식

     

     

    이제 계단 같은 지형지물로 이동할 때의 인식하는 것을 해주겠다.

    LineStep 게임 오브젝트를 생성하고,

    Edge Collider 2D를 추가한다.

     

     

     

     

    계단 이미지에 맞게 라인을 설정해 준다.

     

     

     

    계단 위에도 Box Collider 2D를 생성해 지형에 맞게 설정한다.

     

     

     

    반대편 계단 라인도 추가한다.

     

     

     

    이제 새로운 스크립트를 추가한다. 

    Staris의 이름으로 생성한다.

     

    플레이어가 계단 위에 있을 때 중력을 0으로 설정하여

    계단을 올라갈 수 있게 하는 스크립트이다.

    using UnityEngine;
    
    public class Stairs : MonoBehaviour
    {
        //충돌처리
        //trigger 충돌이 일어났을 때 통과
        //Collision 충돌이 일어났을 때 통과 X
    
        public GameObject player;
    
        private void OnCollisionEnter2D(Collision2D collision)
        {
            if(collision.gameObject.CompareTag("Player"))
            {
                //충돌될 때 0으로 중력 만들기
                player.GetComponent<Rigidbody2D>().gravityScale = 0;
            }
        }
    
        private void OnCollisionExit2D(Collision2D collision)
        {
            if (collision.gameObject.tag == "Player")
            {
                //충돌되지 않을 때 중력 1로 만들기
                player.GetComponent<Rigidbody2D>().gravityScale = 1;
            }
    
        }
    }
    
    

     

     

     

    Player 빈 곳에 Player 오브젝트를 넣어준다.

     

     

     

     


     

     

    4. 공격 레이저 이펙트

     

     

     

    이펙트 이미지를 Hierarchy에 추가한다.

    이 이펙트는 마우스의 방향으로 레이저가 나가는 것을 해보겠다.

     

     

     

     

    새로운 스크립트 Hit_Lazer를 생성한다.

     

    스피드를 설정하고, 생성되고 4초 뒤에 없어지는 것으로 한다.

    using UnityEngine;
    
    public class Hit_Lazer : MonoBehaviour
    {
        float Speed = 50f;
    
        void Start()
        {
            Destroy(gameObject, 4f); //4초 뒤에 없어지기
        }
    
        void Update()
        {
            //이동
            transform.position += Vector3.right * Speed * Time.deltaTime;
            
        }
    }
    
    

     

     

     

    그 레이저를 프리팹으로 만든다.

     

     

     

     

    이제 Player 스크립트에서 이 이펙트 레이저를 추가해 볼 것이다.

    이펙트의 게임오브젝트를 불러오는 변수를 선언한다.

    //히트 이펙트
    public GameObject hit_lazer;
    

     

     

    왼쪽 마우스를 클릭하면 공격이 나가는 KeyInput() 메서드 안에

    공격애니메이션이 수행되면서, 공격 오브젝트 레이저를 생성한다.

    if (Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
    {
        pAnimator.SetTrigger("Attack");
    
        Instantiate(hit_lazer, transform.position, Quaternion.identity);
    }
    

     

     

     

    그렇게 Player의 전체 코드이다.

    using System.Collections.Generic;
    using UnityEngine;
    
    public class Player : MonoBehaviour
    {
        [Header("플레이어 속성")]
        public float speed = 5;
        public float jumpUp = 1;
        public float power = 5;
        public Vector3 direction;
        public GameObject slash;
    
        //그림자
        public GameObject Shadow1;
        List<GameObject> sh = new List<GameObject>();
    
        //히트 이펙트
        public GameObject hit_lazer;
    
        bool bJump = false;
        Animator pAnimator;
        Rigidbody2D pRig2D;
        SpriteRenderer sp;
    
        void Start()
        {
            pAnimator = GetComponent<Animator>();
            pRig2D = GetComponent<Rigidbody2D>();
            direction = Vector2.zero;
            sp = GetComponent<SpriteRenderer>();
    
        }
    
        void KeyInput()
        {
            direction.x = Input.GetAxisRaw("Horizontal"); //왼쪽은 -1   0   1
    
            if (direction.x < 0)
            {
                //left
                sp.flipX = true;
                pAnimator.SetBool("Run", true);
    
                //Shadowflip
                for (int i = 0; i < sh.Count; i++)
                {
                    sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
                }
    
            }
            else if (direction.x > 0)
            {
                //right
                sp.flipX = false;
                pAnimator.SetBool("Run", true);
    
                //Shadowflip
                for (int i = 0; i < sh.Count; i++)
                {
                    sh[i].GetComponent<SpriteRenderer>().flipX = sp.flipX;
                }
    
            }
            else if (direction.x == 0)
            {
                pAnimator.SetBool("Run", false);
    
                for (int i = 0; i < sh.Count; i++)
                {
                    Destroy(sh[i]); //게임오브젝트지우기
                    sh.RemoveAt(i); //게임오브젝트 관리하는 리스트지우기
                }
    
            }
    
            if (Input.GetMouseButtonDown(0)) //0번 왼쪽마우스
            {
                pAnimator.SetTrigger("Attack");
    
                Instantiate(hit_lazer, transform.position, Quaternion.identity);
            }
    
        }
    
        void Update()
        {
            KeyInput();
            Move();
    
            if (Input.GetKeyDown(KeyCode.W))
            {
                if (pAnimator.GetBool("Jump") == false)
                {
                    Jump();
                    pAnimator.SetBool("Jump", true);
                }
    
            }
    
        }
    
        private void FixedUpdate()
        {
            Debug.DrawRay(pRig2D.position, Vector3.down, new Color(0, 1, 0));
    
            //레이캐스트로 땅체크 
            RaycastHit2D rayHit = Physics2D.Raycast(pRig2D.position, Vector3.down, 1, LayerMask.GetMask("Ground"));
    
            if (pRig2D.linearVelocityY < 0)
            {
                if (rayHit.collider != null)
                {
                    if (rayHit.distance < 0.7f)
                    {
                        pAnimator.SetBool("Jump", false);
                    }
                }
            }
    
        }
    
        public void Jump()
        {
            pRig2D.linearVelocity = Vector2.zero;
    
            pRig2D.AddForce(new Vector2(0, jumpUp), ForceMode2D.Impulse);
        }
    
        public void Move()
        {
            transform.position += direction * speed * Time.deltaTime;
        }
    
        public void AttSlash()
        {
            //플레이어 오른쪽
            if (sp.flipX == false)
            {
                pRig2D.AddForce(Vector2.right * power, ForceMode2D.Impulse);
                //플레이어 오른쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
            else
            {
    
                pRig2D.AddForce(Vector2.left * power, ForceMode2D.Impulse);
                //왼쪽
                GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
                go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
            }
    
        }
    
        //그림자
        public void RunShadow()
        {
            if (sh.Count < 6)
            {
                GameObject go = Instantiate(Shadow1, transform.position, Quaternion.identity);
                go.GetComponent<Shadow>().TwSpeed = 10 - sh.Count;
                sh.Add(go);
            }
        }
    
    }
    
    

     

     

     

    Player의 Inspector에서 이펙트 레이저 프리팹을 넣어준다.

     

     

     

     

     


     

     

    5. 마우스 방향 공격

     

     

    이 공격 이펙트가 마우스 방향에 따라서 공격되는 것을 표현하겠다.

     

    Hit_Lizer 스크립트를 수정한다.

    방향벡터를 계산하여 마우스 방향으로 이동한다.

    using UnityEngine;
    
    public class Hit_Lazer : MonoBehaviour
    {
        float Speed = 50f;
    
        Vector2 MousePos;
        Transform tr;
        Vector3 dir;
    
        float angle;
        Vector3 dirNo;
    
        void Start()
        {
            tr = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
            MousePos = Input.mousePosition;
            MousePos = Camera.main.ScreenToWorldPoint(MousePos);
            Vector3 Pos = new Vector3(MousePos.x, MousePos.y, 0); //0은 z좌표
            dir = Pos - tr.position; //마우스 - 플레이어 포지션 빼면 마우스를 바라보는 벡터
    
            //normalized 단위 벡터
            dirNo = new Vector3(dir.x, dir.y, 0).normalized;
    
            Destroy(gameObject, 4f); //4초 뒤에 없어지기
        }
    
        void Update()
        {
            //이동
            transform.position += dirNo * Speed * Time.deltaTime;
            
        }
    }
    
    

     

     

     

     

    하지만 마우스에 따라 레이저 이미지가 호출되는 건 되는데,

    이미지의 각도가 변경이 되지 않는 점이다.

     

    여기에서 바라보는 각도를 구하는 함수를 추가한다.

    void Start()
    {
        tr = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
        MousePos = Input.mousePosition;
        MousePos = Camera.main.ScreenToWorldPoint(MousePos);
        Vector3 Pos = new Vector3(MousePos.x, MousePos.y, 0); //0은 z좌표
        dir = Pos - tr.position; //마우스 - 플레이어 포지션 빼면 마우스를 바라보는 벡터
    
        //바라보는 각도 구하기
        angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
    
        //normalized 단위 벡터
        dirNo = new Vector3(dir.x, dir.y, 0).normalized;
    
        Destroy(gameObject, 4f); //4초 뒤에 없어지기
    }
    

     

     

     

    그리고 회전 적용을 해준다.

    여기서는 4차원 벡터 사원수를 사용한다. z 축을 기준으로 회전하는 방향을 만들어준다.

    void Update()
    {
        //회전적용
        //회전을 위해서는 3차원 x,y,z가 부족할 정도이다. 그래서 4차원 벡터 사원수를 사용하는 것이다.
        transform.rotation = Quaternion.Euler(0f, 0f, angle);
        //z축이 angle인 이유? z축을 기준으로 회전하기 때문
    
        //이동
        transform.position += dirNo * Speed * Time.deltaTime;
        
    }
    

     

     

     

     

    그렇게 최종으로 전체코드이다.

    using UnityEngine;
    
    public class Hit_Lazer : MonoBehaviour
    {
        float Speed = 50f;
    
        Vector2 MousePos;
        Transform tr;
        Vector3 dir;
    
        float angle;
        Vector3 dirNo;
    
        void Start()
        {
            tr = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
            MousePos = Input.mousePosition;
            MousePos = Camera.main.ScreenToWorldPoint(MousePos);
            Vector3 Pos = new Vector3(MousePos.x, MousePos.y, 0); //0은 z좌표
            dir = Pos - tr.position; //마우스 - 플레이어 포지션 빼면 마우스를 바라보는 벡터
    
            //바라보는 각도 구하기
            angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
    
            //normalized 단위 벡터
            dirNo = new Vector3(dir.x, dir.y, 0).normalized;
    
            Destroy(gameObject, 4f); //4초 뒤에 없어지기
        }
    
        void Update()
        {
            //회전적용
            //회전을 위해서는 3차원 x,y,z가 부족할 정도이다. 그래서 4차원 벡터 사원수를 사용하는 것이다.
            transform.rotation = Quaternion.Euler(0f, 0f, angle);
            //z축이 angle인 이유? z축을 기준으로 회전하기 때문
    
            //이동
            transform.position += dirNo * Speed * Time.deltaTime;
            
        }
    }
    
    

     

     

     

     

     

    이제 방금 진행한 레이저 회전 적용과 비슷하게

    이펙트도 회전 적용을 하려고 한다.

     

    Slash 스크립트를 수정한다.

    using UnityEngine;
    using UnityEngine.UIElements;
    
    public class Slash : MonoBehaviour
    {
        private GameObject p;
    
        Vector2 MousePos;
        Transform tr;
        Vector3 dir;
    
        float angle;
        Vector3 dirNo;
    
        //방향
        public Vector3 direction = Vector3.right;
        void Start()
        {
            //플레이어 태그 가져오기
            p = GameObject.FindGameObjectWithTag("Player");
    
            Transform tr = p.GetComponent<Transform>();
            MousePos = Input.mousePosition;
            MousePos = Camera.main.ScreenToWorldPoint(MousePos);
            Vector3 Pos = new Vector3(MousePos.x, MousePos.y, 0);
            dir = Pos - tr.position;
    
            //바라보는 각도 구하기
            //Atan보다 Atan2가 더 계산이 정확하다.
            angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        }
    
        void Update()
        {
            //회전적용
            //Quaternion = 사원수
            transform.rotation = Quaternion.Euler(0f, 0f, angle);
    
            transform.position = p.transform.position;
        }
    
        public void Des()
        {
            //삭제
            Destroy(gameObject);
        }
    }
    
    

     

     

     

     

    Player 스크립트도 수정할 것이다.

     

    Player의 이펙트 flip을 적용했던 코드가 있는데,

    회전 적용을 하면서 자동으로 flip을 해주기 때문에

    이 코드는 없어도 된다. 그래서 주석 처리로 변경한다.

    public void AttSlash()
    {
        //플레이어 오른쪽
        if (sp.flipX == false)
        {
            pRig2D.AddForce(Vector2.right * power, ForceMode2D.Impulse);
            //플레이어 오른쪽
            GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
            //go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
        }
        else
        {
    
            pRig2D.AddForce(Vector2.left * power, ForceMode2D.Impulse);
            //왼쪽
            GameObject go = Instantiate(slash, transform.position, Quaternion.identity);
            //go.GetComponent<SpriteRenderer>().flipX = sp.flipX;
        }
    
    }
    

     

     

     

     


     

     

    6. 커서 만들기

     

     

     

    유니티에서는 가볍게 커서 이미지를 추가할 수 있다.

     

    해당 원하는 커서 이미지를 가져온다.

    이미지의 Inspector - Texture Type - Cursor로 변경한다.

    화질을 높이고 싶다면 Filter Mode - Point (no filter)를 하면 된다.

     

     

     

     

     

    Edit - Project Settings - Player - Defalut Cursor를 해당 이미지로 변경한다.

     

     

     

     


     

     

    오늘은 Katana ZERO 2번째가 끝났다.

     

    평소에 수포자였어서 그런가.. 함수에 확실히 약한 것 같다.

    뭔가 코드를 작성하고 보면 신기한데!

     

    왜 그렇게 함수가 쓰이는지 솔직히 이해하기 조금 어렵다..

     

    이래서 코딩에는 수학이 필요한 것인가.. 계속 느껴지고 있다.

     

     

    그래도 수학이 엄청난 비율을 차지하는 것은 아니니,

    반복적으로 계속하다 보면 익숙해지지 않을까 싶다!

     

     

    오늘도 고생했고, 다음에도 파이팅 하자!


    목차