3 분 소요

몬스터밟기

이번 포스팅에서는 캐릭터의 공격을 만들어보겠습니다.

이동로직 변경

지금 캐릭터 이동을 하다보면 어색하고, 잘 안먹히는 부분이 있습니다.

GetButtonDown을 써서 이동로직을 짰기 때문에 버튼을 누른상태로 다른 버튼을 누르게되면 겹치게되어서 그렇습니다.

PlayerControl.cs 의 Update 함수에서 플레이어 방향전환 부분 GetButtonDown을 GetButton으로 바꿔줍니다.

//플레이어 방향 전환
        if (Input.GetButton("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

공격만들기

슈퍼마리오에서는 원래 몬스터를 밟으면 몬스터가 죽게됩니다.

PlayerControl.cs

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

public class PlayerControl : MonoBehaviour
{
    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;

    public float maxSpeed;
    public float jumpPower;

    private void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }
    // Start is called before the first frame update
    void Start()
    {

    }

    void Update()
    {
        //키보드 뗏을때 속도감소(멈춤)
        if (Input.GetButtonUp("Horizontal"))
        {
            //normalized : 단위벡터화
            rigid.velocity = new Vector2(0.5f * rigid.velocity.normalized.x, rigid.velocity.y);

        }

        //플레이어 방향 전환
        if (Input.GetButton("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

        //Walking Animation 설정
        if (Mathf.Abs(rigid.velocity.x) < 0.3f)
            anim.SetBool("isWalking", false);
        else
            anim.SetBool("isWalking", true);

        //점프(1단점프만 가능)
        if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping", true);        
        }
    }

    void FixedUpdate()
    {
        //키보드 방향키 입력으로 움직임
        float h = Input.GetAxisRaw("Horizontal");

        rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);

        if (rigid.velocity.x > maxSpeed) //오른쪽 속도
            rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
        else if (rigid.velocity.x < maxSpeed * (-1))  //왼쪽 속도
            rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);

        //착지(캐릭터가 떨어지고있을 때)
        if (rigid.velocity.y < 0)
        {
            Debug.DrawRay(rigid.position, Vector3.down, new Color(1, 0, 0));
            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Floor"));
            if (rayHit.collider != null)
            {
                if (rayHit.distance <= 0.45f)
                    anim.SetBool("isJumping", false);
            }
        }
    }

    // 충돌 이벤트
    void OnCollisionEnter2D(Collision2D collision)
    {
        if(collision.gameObject.tag == "Monster")
        {
            //공격
            if(rigid.velocity.y < 0 && transform.position.y > collision.transform.position.y)
            {
                Attack(collision.transform);
            }
            else
                OnDamaged(collision.transform.position);
        }
    }

    //몬스터 밟기
    void Attack(Transform monster)
    {
        //캐릭터 반동효과 
        rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

        //몬스터의 스크립트를 참조
        MonsterController monsterMove = monster.GetComponent<MonsterController>();
        monsterMove.OnDamaged();
    }

    // 피격됐을 때 호출되는 함수 [무적만들기] (피격된 대상의 위치를 받음)
    void OnDamaged(Vector2 targetPos)
    {
        // PlayerDamaged 레이어로 변경
        gameObject.layer = 8;

        // 반투명도 설정(맞았다는것을 표현)
        spriteRenderer.color = new Color(1, 1, 1, 0.4f);

        //맞았을 때 팅겨남
        int dirc = transform.position.x - targetPos.x > 0 ? 1 : -1;
        rigid.AddForce(new Vector2(dirc, 1) * 7, ForceMode2D.Impulse);

        //피격 애니메이션
        anim.SetTrigger("Damaged");

        //무적풀림
        Invoke("OffDamaged", 2);
    }

    // 무적판정 풀기
    void OffDamaged()
    {
        gameObject.layer = 7;
        spriteRenderer.color = new Color(1, 1, 1, 1.0f);

    }
}

  • 몬스터를 공격하는것은 충돌 이벤트이므로 OnCollisionEnter2D 함수에서 만들어줍니다.

  • 공격을 하려면 캐릭터가 공중에서 내려올 때 + 몬스터의 y높이보다 높을 때 공격이 성립하게됩니다.

  • Attack 이라는 함수를 만들어 공격 함수를 만들어주었습니다.

  • 몬스터를 밟아 죽였을 때 캐릭터에 반동을 주어 공격에 성공했음을 표시합니다.

MonsterController.cs

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

public class MonsterController : MonoBehaviour
{

    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;
    CapsuleCollider2D Mon_collider;

    public int nextMovement;

    private void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
        Mon_collider = GetComponent<CapsuleCollider2D>();

        Invoke("NextMove", 3);
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    private void FixedUpdate()
    {
        //Monster Move
        rigid.velocity = new Vector2(nextMovement * 2.0f, rigid.velocity.y);

        //낭떠러지 체크
        Vector2 vec_Front = new Vector2(rigid.position.x + nextMovement * 0.5f, rigid.position.y);
        Debug.DrawRay(vec_Front, Vector3.down, new Color(1, 0, 0));
        RaycastHit2D rayHit = Physics2D.Raycast(vec_Front, Vector3.down, 1, LayerMask.GetMask("Floor"));
        if (rayHit.collider == null)
        {
            //낭떠러지가 있을 때 방향전환
            TurnBack();
        }
    }

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

    }

    //Monster 다음 움직임 결정
    void NextMove()
    {
        //Monster의 움직임은 왼쪽(-1),오른쪽(1),가만히(0)
        nextMovement = Random.Range(-1, 2);

        anim.SetInteger("isWalking", nextMovement);

        //Set Flip
        if(nextMovement != 0)
        {
            spriteRenderer.flipX = nextMovement == 1;

        }

        //재귀함수 호출시간
        float nextMoveTime = Random.Range(2f, 4f);
        Invoke("NextMove", nextMoveTime);
    }

    void TurnBack()
    {
        nextMovement *= -1;
        spriteRenderer.flipX = nextMovement == 1;

        CancelInvoke();
        Invoke("NextMove", 3);
    }

    // 몬스터가 공격 당했을 때
    public void OnDamaged()
    {
        //투명도 설정
        spriteRenderer.color = new Color(1, 1, 1, 0.4f);
        //몬스터가 죽었음을 표현하기위해 거꾸로 뒤집음
        spriteRenderer.flipY = true;
        rigid.AddForce(Vector2.up * 5.0f, ForceMode2D.Impulse);

        //몬스터 콜라이더설정
        Mon_collider.enabled = false;
        
        //몬스터가 죽고 잠시 뒤 없애버림
        Invoke("Destroy", 5);
    }

    //몬스터 오브젝트 삭제
    void Destroy()
    {
        gameObject.SetActive(false);
    }
}

  • 플레이어 스크립트에서 OnDamaged 함수를 호출하여 사용합니다.

  • OnDamaged 함수에서 몬스터 죽음을 만들어줍니다.

  • 몬스터가 죽을 때 반투명해지며, 거꾸로 뒤집혀 잠깐 튀어올랐다가 떨어지고 잠시뒤 사라집니다.

image

댓글남기기