거의 알고리즘 일기장

10. 유니티 _ 간단 2D 플랫포머 게임 본문

유니티

10. 유니티 _ 간단 2D 플랫포머 게임

건우권 2020. 5. 7. 01:27

게임 설명

 


Scripts

 

GameManager Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class Manager : MonoBehaviour
{
    public int totalPoint;
    public int stagePoint;
    public int stageIndex;
    public int health;
    public Player player;
    public GameObject[] stages;

    public Image[] UIhealth;
    public Text UIPoint;
    public Text UIStage;
    public Button UIRestartBtn;

    private void Update()
    {
        UIPoint.text = (totalPoint + stagePoint).ToString();
    }

    public void NextStage()
    {
        //changeStage
        if (stageIndex < stages.Length-1)
        {
            stages[stageIndex].SetActive(false);
            stageIndex++;
            stages[stageIndex].SetActive(true);
            //player reposition
            player.RePosition();

            UIStage.text = (stageIndex + 1).ToString();
        }
        //game clear
        else
        {
            Debug.Log("게임 클리어!");
            //Player control lock
            Time.timeScale = 0;
            //result UI
            Text btnText = UIRestartBtn.GetComponentInChildren<Text>();
            btnText.text = "Clear!";
            UIRestartBtn.gameObject.SetActive(true);
        }

        //calculate Point
        totalPoint += stagePoint;
        stagePoint = 0;
    }

    public void HealthDown()
    {
        if (health > 1)
        {
            health--;
            UIhealth[health].color = new Color(1, 0, 1, 0.4f);
        }
        else
        {
            UIhealth[0].color = new Color(1, 0, 1, 0.4f);
            //player die
            player.OnDie();

            //result ui
            Debug.Log("죽었습니다.");

            //retry ui
            UIRestartBtn.gameObject.SetActive(true);
        }
    }

    public void Restart()
    {
        SceneManager.LoadScene(0);
        Time.timeScale = 1;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Player")
        {
            if (health > 1)
            {
                //player reposition
                player.RePosition();
            }
            //health down
            HealthDown();
        }
    }
}

 

Enemy Script

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

public class Enermy : MonoBehaviour
{
    Rigidbody2D rigid;
    //-1 0 1
    Animator anim;
    public int nextMove;
    SpriteRenderer spRender;
    CapsuleCollider2D capsuleCollider;

    private void Awake()
    {
        capsuleCollider = GetComponent<CapsuleCollider2D>();
        spRender = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
        rigid = GetComponent<Rigidbody2D>();
        Think();
    }

    private void FixedUpdate()
    {
        //move
        rigid.velocity = new Vector2(nextMove, rigid.velocity.y);

        //platform check
        Vector2 frontVec = new Vector2(rigid.position.x + nextMove*0.3f, 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)
        {
            nextMove *= (-1);
            Motion();
        }
    }
    
    void Turn()
    {
        //방향전환
        if (nextMove == 1)
            spRender.flipX = true;
        else if (nextMove == -1)
            spRender.flipX = false;
    }

    void Motion()
    {
        //emermy motion
        if (nextMove == 0)
            anim.SetBool("isWalking", false);
        else
            anim.SetBool("isWalking", true);
        Turn();
    }

    void Think()
    {
        //랜덤 방법
        nextMove = Random.Range(-1, 2);
        float nextMoveTime = Random.Range(2.0f, 4.0f);     
        Motion();
        Invoke("Think", nextMoveTime);
    }

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

    public void OnDamaged()
    {
        //sprite alpha
        spRender.color = new Color(1, 1, 1, 0.4f);
        //sprite Flip Y
        spRender.flipY = true;
        //collider false
        capsuleCollider.enabled = false;
        //die effect jump
        rigid.AddForce(Vector2.up * 3.0f, ForceMode2D.Impulse);
        //destroy
        Invoke("DeActive", 3);
    }
}

 

Player Script

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

public class Player : MonoBehaviour
{
    public Manager gameManager;
    public AudioClip audioJump;
    public AudioClip audioAttack;
    public AudioClip audioDamaged;
    public AudioClip audioItem;
    public AudioClip audioDie;
    public AudioClip audioFinish;
    public float maxSpeed;
    public float jumpPower;
    bool isJump;

    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;    
    CapsuleCollider2D capsuleCollider;
    AudioSource audioSource;

    private void Awake()
    {
        isJump = false;
        audioSource = GetComponent<AudioSource>();
        capsuleCollider = GetComponent<CapsuleCollider2D>();
        anim = GetComponent<Animator>();
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    void PlaySound(string action)
    {
        switch (action)
        {
            case "JUMP":
                audioSource.clip = audioJump;
                break;
            case "ATTACK":
                audioSource.clip = audioAttack;
                break;
            case "DAMAGED":
                audioSource.clip = audioDamaged;
                break;
            case "ITEM":
                audioSource.clip = audioItem;
                break;
            case "DIE":
                audioSource.clip = audioDie;
                break;
            case "FINISH":
                audioSource.clip = audioFinish;
                break;
        }
        audioSource.Play();
    }

    //단발적인 입력은 update에
    void Update()
    {
        //stop speed
        if(Input.GetButtonUp("Horizontal"))
        {
            //normalized -> 벡터 크기를 1로 만든 상태
            rigid.velocity = new Vector2(rigid.velocity.normalized.x *0.5f, rigid.velocity.y);
        }

        //jump
        if (Input.GetButtonDown("Jump") && isJump == false)
        {
            isJump = true;
            rigid.AddForce(new Vector2(rigid.velocity.x, jumpPower), ForceMode2D.Impulse);
            PlaySound("JUMP");
        }

        //방향전환
        if (Input.GetButton("Horizontal"))
        {
            bool v = (Input.GetAxisRaw("Horizontal") == -1.0f);
            spriteRenderer.flipX = v;
        }

        //walking motion
        if (Mathf.Abs(rigid.velocity.x) <= 0.3f)
            anim.SetBool("isWalking", false);
        else
            anim.SetBool("isWalking", true);

        //jump motion
        if(isJump == true)
            anim.SetBool("isJumping", true);
        else
            anim.SetBool("isJumping", false);
    }

    private void FixedUpdate()
    {
        //move by key control
        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)
        {
            //landing platform, 레이저로 쏴서 맞춘 첫번째 물체를 식별
            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.5)
                    isJump = false;
        }
    }

    void OnDamaged(Vector2 targetPos)
    {
        //Health down
        gameManager.HealthDown();

        //player  damaged
        gameObject.layer = 11;

        spriteRenderer.color = new Color(1, 1, 1, 0.4f);

        //reaction forc
        int dirc = transform.position.x - targetPos.x > 0 ? 1 : -1;
        rigid.AddForce(new Vector2(dirc, 1)*10.0f, ForceMode2D.Impulse);

        //animation
        anim.SetTrigger("doDamaged");

        //sound
        PlaySound("DAMAGED");    
        
        Invoke("OffDamaged", 2);
    }

    void OffDamaged()
    {
        gameObject.layer = 10;
        spriteRenderer.color = new Color(1, 1, 1, 1);
    }

    void OnAttack(Transform enemy)
    {
        //Point
        gameManager.stagePoint += 100;
        //reation force
        rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
        //Enermy Die
        Enermy enemyMove = enemy.GetComponent<Enermy>();
        enemyMove.OnDamaged();
        //SOUND
        PlaySound("ATTACK");
    }


    public void OnDie()
    {
        //sprite alpha
        spriteRenderer.color = new Color(1, 1, 1, 0.4f);
        //sprite Flip Y
        spriteRenderer.flipY = true;
        //collider false
        capsuleCollider.enabled = false;
        //die effect jump
        rigid.AddForce(Vector2.up * 3.0f, ForceMode2D.Impulse);
        //SOUND
        PlaySound("DIE");
    }

    public void RePosition()
    {
        rigid.velocity = Vector2.zero;
        gameObject.transform.position = new Vector3(-5, 1, 0);
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        //적에게 닿았을때
        if (collision.gameObject.tag == "Enermy")
        {
            //attack
            if (rigid.velocity.y < 0 && transform.position.y > collision.transform.position.y)
            {
                OnAttack(collision.transform);
            }
            //Damaged
            else
                OnDamaged(collision.transform.position);
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Item")
        {
            bool isBronze = collision.gameObject.name.Contains("Bronze");
            bool isSliver = collision.gameObject.name.Contains("Sliver");
            bool isGold = collision.gameObject.name.Contains("Gold");

            //Point
            if(isBronze)
                gameManager.stagePoint += 50;
            else if(isSliver)
                gameManager.stagePoint += 100;
            else if(isGold)
                gameManager.stagePoint += 150;

            //SOUND
            PlaySound("ITEM");

            //deactive item
            collision.gameObject.SetActive(false);
        }
        else if(collision.gameObject.tag == "Finish")
        {
            //next stage
            gameManager.NextStage();
            //sound
            PlaySound("FINISH");
        }
    }
}

게임동작

게임 동작gif


참고

https://www.youtube.com/channel/UCw_N-Q_eYJo-IJFbNkhiYDA

 

골드메탈

게임 개발 & 그림 그리기 & 게임 플레이 각종 컨텐츠를 방송하는 스트리머 골드메탈 채널입니다. 주 컨텐츠는 게임 개발이며 유니티 엔진을 기반으로 컨텐츠를 진행합니다. - 2019.03.15 구독자 5천명 돌파! 감사합니다. - 2019.12.02 구독자 1만명 돌파! 감사합니다.

www.youtube.com


후기

그 전 강의까지는 내맘대로 바꾸고 함수도 다르게 바꾸고 이렇게 만들었었는데, 이건 끝마무리라 그런지 구현량이 많아서 따라 치기도 벅찼다.ㅎㅎㅎ

 

반응형

'유니티' 카테고리의 다른 글

12. 유니티 _ 타워디펜스 _ 진행중  (2) 2020.05.19
11. 유니티 _ 3D 닷지  (0) 2020.05.12
9.유니티 _ 피격 이벤트 구현  (0) 2020.05.06
8. 유니티 _ 몬스터 움직임 구현  (0) 2020.05.05
7. 유니티 _ 타일맵  (0) 2020.05.05
Comments