2D PlatForm게임

재이리 ㅣ 2023. 4. 21. 22:06

https://www.youtube.com/watch?v=GHUJMXtHKL0&list=PLO-mt5Iu5TeZGR_y6mHmTWyo0RyGgO0N_&index=8 

유튜버 골드메탈님의 프로젝트 영상을 보며 제작

 

깃허브 링크 https://github.com/jaeil777/study_unity/tree/main/Unity%202D%20Learn

 

Player

기본적으로 좌우로 이동과 점프를  가능하게 구현함 

        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); //왼쪽 최대속도
        }

InputManager의 Horizontal 값을 받아와 

Rigidbody의 Addforce를 통해 좌우로 이동 

if 문을 사용해 maxSpeed이상일경우 속도에 제한을 걸어 최대속도를 제한함

 

   if (Input.GetButtonUp("Jump")&& !anim.GetBool("isJumping"))
        {
            rigid.AddForce(Vector2.up*jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping", true);
            
        }

 점프의 경우에도 마찬가지로 InputManager의 Jump를 받아와 점프를 구현 하였고 

if(rigid.velocity.y < 0)
        {
            Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0));

            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("PlatForm"));

            if (rayHit.collider != null)
            {
                if (rayHit.distance < 0.7f)
                {
                   // Debug.Log(rayHit.collider.name);
                    anim.SetBool("isJumping", false);
        
                }

            }

 

해당하는 코드를 통해 아래로 레이를 쏴서  PlatForm 이라는 레이어를 받아왔을때(땅을 밟았을때) 

isJump를 비활성화하여 무한하게 점프를 하는것을 방지함 

 

        if(collision.gameObject.tag =="Trap" || collision.gameObject.tag == "Monster")
        {
            if(rigid.velocity.y<0 && transform.position.y> collision.transform.position.y+0.3 && collision.gameObject.tag == "Monster")
            {
                Onattack(collision.gameObject);
            }
            else
            {
                OnDamaged(collision.transform.position);

            }
        }

해당하는 코드를 통해 OnCollisionEnter2D이벤트에서 

충돌된 오브젝트의 태그가 Trap 또는 Monster 일때 

그리고 위에서 아래로 충돌하면서 Monster 태그를 가졌을때는 

Onattack 메소드를 호출해 공격을 하고 

아닐경우에는 OnDamaged 메소드를 호출해 타격을 받게끔 설계함 

 void OnDamaged(Vector2 targetPos)
    {
        gameObject.layer = 10;
        gameManager.HealthDown();
        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)*15, ForceMode2D.Impulse);

        Invoke("OffDamaged", 1);

        //피격 애니메이션
        anim.SetTrigger("Damaged");
    }
void Onattack(GameObject monster)
    {

        //내 캐릭터에 가해질 반발력
        rigid.AddForce(Vector2.up*5,ForceMode2D.Impulse);

        //몬스터한테 가할 행동 
        EnemyMove enemyMove =  monster.GetComponent<EnemyMove>();
        enemyMove.OnDamaged();
    }

 

 

또한 OnTriggerEnter2D 이벤트를 이용해 

코인을 먹었을때와 종료 지점에 다가갔을경우 다음스테이지로 넘어가게끔 해주었다 

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.tag == "Coin")
        {
            bool isBronze = collision.gameObject.name.Contains("Bronze");
            bool isSilver = collision.gameObject.name.Contains("Silver");
            bool isGold = collision.gameObject.name.Contains("Gold");
            Debug.Log(isBronze.ToString() + isSilver.ToString()+ isGold.ToString());
            if (isBronze)
                gameManager.stagescore += 50;
            else if (isSilver)
                gameManager.stagescore += 100;
            else if (isGold)
                gameManager.stagescore += 300;
            collision.gameObject.SetActive(false);



        }
        else if (collision.tag == "Finish")
        {
            gameManager.NextStage();
        }
    }

 

 

MONSTER

몬스터의 경우에는 좌우로 기본적인 이동을 하며 이동방향의 한픽셀 앞으로 레이를 쏴 지형물이 없을경우 

반대로 돌수 있도록 짜주었다

        //몬스터 기본이동
        rigid.velocity = new Vector2(nextMove, rigid.velocity.y);

        //바닥 확인
        Vector2 frontVec = new Vector2(rigid.position.x + nextMove*0.2f, rigid.position.y);
        Debug.DrawRay(frontVec, Vector3.down, new Color(0, 1, 0));
        RaycastHit2D rayHit = Physics2D.Raycast(frontVec, Vector3.down, 1, LayerMask.GetMask("PlatForm"));
        if (rayHit.collider == null)
        {
            Turn();
        }

그리고 좀더 기계적이지 않은 움직임을 구현하기 위해 랜덤 함수를 이용해서 일정시간마다 움직임을 변환할수 있도록 해주었다

    void ChooseNextMove()
    {
        //다음 움직임 랜덤
        nextMove = Random.Range(-1,2);
        nextMoveTime = Random.Range(2f,5f);
      
        //방향전환 애니메이션
        anim.SetInteger("WalkSpeed",nextMove);
        //방향전환 (반전)
        if (nextMove != 0)
        {
            spriteRenderer.flipX = (nextMove == 1);
        }

        Invoke("ChooseNextMove", nextMoveTime);
    }

그리고 플레이어에게 공격당하였을경우 

  public void OnDamaged()
    {
        spriteRenderer.color = new Color(1, 1, 1, 0.4f);
        spriteRenderer.flipY = true;
        boxcolider.enabled = false;
        rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
        Invoke("DeAttack", 3);

    }

OnDamaged 함수를 이용해 

투명도를 변경 y축 반전 콜라이더 오프를 하고 피격효과를 주고 3초뒤 DeAttack 함수를 실행하도록 해주어 

    void DeAttack()
    {
        gameObject.SetActive(false);
    }

오브젝트가 사라지도록 구현하였다.

 

GameManager

게임매니저를 통해 

캐릭터의 체력을 관리하는 메소드를 하나 생성하여 

    public void HealthDown()
    {
        if(health > 1)
        {
            health--;
            UIHealth[health].color = new Color(1, 1, 1, 0f);
        }
        else
        {
            UIClear.text = "STAGE FAIELD";
            UIClear.gameObject.SetActive(true);
            UIRetryButton.gameObject.SetActive(true);
            UIRestartButton.gameObject.SetActive(true);
            player.OnDie();

        }
    }

캐릭터가 충돌하였을시 HealthDown 함수를 호출해 체력을 감소해줄수 있도록 하였으며 

체력이 0이 되었을경우

 

 

 

콜라이더를 맵 아래에 배치하여 플레이어가 추락하여 콜라이더에 닿았을시 OnTriggerEnter2D이벤트를 통해 

재위치 시킬수 있도록 하였다.

 

    void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Player")
        {
            HealthDown();
            PlayerReposition();
        }
    }
    void PlayerReposition()
    {
        player.transform.position = new Vector3(-6, 2.5f, 0);
        player.VelocityZero();
    }

 

 

그리고 플레이어가 죽었을경우 

UI버튼들을 호출해 

처음부터 시작하기와 다시하기를 구현해 다시 할수 있도록 코드를 짜주었다 .

 

 public void OnClickUIRestartButton()
    {
        stages[stageIndex].SetActive(false);
        stageIndex = 0;
        health = 3;
        for (int i = 0; i < UIHealth.Length; i++)
        {
            UIHealth[i].color = new Color(1, 1, 1);
        }
        stages[stageIndex].SetActive(true);
        UIStage.text = "STAGE" + (stageIndex + 1);
        UIRetryButton.gameObject.SetActive(false);
        UIRestartButton.gameObject.SetActive(false);
        UIClear.gameObject.SetActive(false);
        if(Time.timeScale == 0)
            Time.timeScale = 1f;
        player.OnRvive();
        PlayerReposition();

    }

    public void OnClickUIRetryButton()
    {

        health = 3;
        for (int i = 0; i < UIHealth.Length; i++)
        {
            UIHealth[i].color = new Color(1, 1, 1);
        }
        UIRetryButton.gameObject.SetActive(false);
        UIRestartButton.gameObject.SetActive(false);
        UIClear.gameObject.SetActive(false);
        if (Time.timeScale == 0)
            Time.timeScale = 1f;
        player.OnRvive();
        PlayerReposition();

    }