유니티 공부로 선택한 첫번쨰 강의. 2D이지만 유니티 기초적인 내용 파악하기 너무 좋은 강의.
쉬우면서도 중요한 기능을 2D 플랫포머 게임을 만들면서 배울 수 있다.
기본적인 기능들은 3D에서도 활용할 수 있기 때문에 처음한다면 이 강의로 시작하는 것을 추천!
마지막 강의, 1번 강의부터 순서대로 보는 것을 추천.
https://www.youtube.com/watch?v=GHUJMXtHKL0&list=PLO-mt5Iu5TeZGR_y6mHmTWyo0RyGgO0N_&index=8
🚀 첫 강의부터 : https://youtu.be/v_Y5FH_tCpc
📖 챕터 : 01 00:00
플레이어 이동 로직 수정 02 01:49
몬스터 밟아서 잡기 03 08:53
아이템 04 11:34
결승점 05 13:50
게임 매니저 추가 06 26:55
스테이지 추가 07 34:10
유저 인터페이스 08 41:34
사운드
*전체 코드
PlayerMove.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
public GameManager 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;
Rigidbody2D rigid;
SpriteRenderer spriteRenderer;
Animator animator;
BoxCollider2D boxCollider;
AudioSource audioSource;
private void Awake()
{
rigid = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
boxCollider = GetComponent<BoxCollider2D>();
audioSource = GetComponent<AudioSource>();
}
private void FixedUpdate()
{
//Move Speed
float h = Input.GetAxisRaw("Horizontal");
rigid.AddForce(Vector2.right * h * 3, ForceMode2D.Impulse);
//Max Speed
if (rigid.velocity.x > maxSpeed)//Right
{
rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
}
else if (rigid.velocity.x < maxSpeed * (-1)) //Left
{
rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);
}
//Ray Collider Check
if (rigid.velocity.y < 0)
{
//Debugging ray
Debug.DrawRay(rigid.position, Vector3.down, new Color(0, 1, 0));
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platforms"));
if (rayHit.collider != null)
{
if (rayHit.distance < 0.5f)
{
Debug.Log(rayHit.collider.name);
animator.SetBool("isJump", false);
}
}
}
}
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();
}
void Update()
{
//Jump
if (Input.GetButtonDown("Jump") && !animator.GetBool("isJump"))
{
rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
animator.SetBool("isJump", true);
PlaySound("JUMP");
}
//Stop Speed
if (Input.GetButtonUp("Horizontal"))
{
rigid.velocity = new Vector2(rigid.velocity.normalized.x * 0.5f, rigid.velocity.y);
}
//Direction Sprite
if (Input.GetButton("Horizontal"))
{
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
}
//Animation
if (Mathf.Abs(rigid.velocity.x) < 0.4)
{
animator.SetBool("isWalk", false);
}
else
{
animator.SetBool("isWalk", true);
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
//Attack
if(rigid.velocity.y < 0 && transform.position.y > collision.transform.position.y)
{
OnAttack(collision.transform);
}
else
{
OnDamaged(collision.transform.position);
}
}
}
void OnAttack(Transform enemy)
{
PlaySound("ATTACK");
gameManager.stagePoint += 100;
// Reaction Force
rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
// Enemy Die
EnemyMove enemyMove = enemy.GetComponent<EnemyMove>();
enemyMove.OnDamaged();
}
void OnDamaged(Vector2 vec)
{
PlaySound("DAMAGED");
//Health Down
gameManager.HealthDown();
//Change Layer
gameObject.layer = 9;
Debug.Log("맞음");
spriteRenderer.color = new Color(1, 1, 1, 0.4f);
int dirc = transform.position.x - vec.x > 0 ? 1 : -1;
rigid.AddForce(new Vector2(dirc, 1)*7, ForceMode2D.Impulse);
//Animation
animator.SetTrigger("doDamaged");
Invoke("OffDamaged", 3);
}
void OffDamaged()
{
gameObject.layer = 10;
spriteRenderer.color = new Color(1, 1, 1, 1);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Item")
{
PlaySound("ITEM");
// Point
bool isBronze = collision.gameObject.name.Contains("Bronze");
bool isSilver = collision.gameObject.name.Contains("Silver");
bool isGold = collision.gameObject.name.Contains("Gold");
if (isBronze)
gameManager.stagePoint += 50;
else if(isSilver)
gameManager.stagePoint += 100;
else if (isGold)
gameManager.stagePoint += 300;
gameManager.stagePoint += 100;
//Deactive Item
collision.gameObject.SetActive(false);
}
else if(collision.gameObject.tag == "Finish")
{
PlaySound("FINISH");
gameManager.NextStage();
}
}
public void OnDie()
{
PlaySound("DIE");
//Sprite Alpha
spriteRenderer.color = new Color(1, 1, 1, 0.3f);
//Sprite Flip Y
spriteRenderer.flipY = true;
//Collider Disalbe
boxCollider.enabled = false;
//Die Effect Jump
rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
}
public void VelocityZero()
{
rigid.velocity = Vector2.zero;
}
}
EnemyMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour
{
Rigidbody2D rigid;
Animator animator;
SpriteRenderer spriteRenderer;
CapsuleCollider2D capsuleCollider;
public int nextMove;
private void Awake()
{
rigid = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
spriteRenderer = GetComponent<SpriteRenderer>();
capsuleCollider = GetComponent<CapsuleCollider2D>();
Invoke("Think", 5);
}
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("Platforms"));
if (rayHit.collider == null)
{
Debug.Log("경고! 이 앞 낭떠러지다");
Turn();
}
}
void Think()
{
//Set Next Active
nextMove = Random.Range(-1, 2);
//Sprite Animation
animator.SetInteger("WalkSpeed", nextMove);
//Flip Sprite
if(nextMove != 0)
{
spriteRenderer.flipX = nextMove == 1;
}
//Set Next Active
float nextThinkTime = Random.Range(2f, 5f);
Invoke("Think", nextThinkTime);
}
void Turn()
{
nextMove *= -1;
spriteRenderer.flipX = nextMove == 1;
CancelInvoke();
Invoke("Think", 5);
}
public void OnDamaged()
{
//Sprite Alpha
spriteRenderer.color = new Color(1, 1, 1, 0.3f);
//Sprite Flip Y
spriteRenderer.flipY = true;
//Collider Disalbe
capsuleCollider.enabled = false;
//Die Effect Jump
rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
//Destroy.
Invoke("Deactive", 5);
}
void DeActive()
{
gameObject.SetActive(false);
}
}
GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public int totalPoint;
public int stagePoint;
public int stageIndex;
public int health;
public PlayerMove player;
public GameObject[] Stages;
public Image[] UIHealth;
public Text UIPoint;
public Text UIStage;
public GameObject RestartBtn;
private void Update()
{
UIPoint.text = (totalPoint + stagePoint).ToString();
}
public void NextStage()
{
//Change Stage
if(stageIndex < Stages.Length - 1)
{
Stages[stageIndex].SetActive(false);
stageIndex++;
Stages[stageIndex].SetActive(true);
PlayerReposition();
UIStage.text = "STAGE " + stageIndex + 1;
}
else
{
//Game Clear
Time.timeScale = 0;
//Player Control Lock
//Result UI
Debug.Log("Game Clear");
//Restart Button UI
Text btnText = RestartBtn.GetComponentInChildren<Text>();
btnText.text = "Game Clear";
RestartBtn.SetActive(true);
}
//Calcuate Point
totalPoint += stagePoint;
stagePoint = 0;
}
public void HealthDown()
{
if(health > 1)
{
health--;
UIHealth[health].color = new Color(1, 0, 0, 0.4f);
}
else
{
UIHealth[0].color = new Color(1, 0, 0, 0.4f);
//PlayerMove Die Effect
player.OnDie();
//Result UI
Debug.Log("죽었습니다.");
//Retry Button UI
RestartBtn.SetActive(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player")
{
//Player Reposition
if(health > 1)
{
PlayerReposition();
}
//Health Down
HealthDown();
}
}
void PlayerReposition()
{
player.transform.position = new Vector3(0, 0, 0);
player.VelocityZero();
}
public void Restart()
{
Time.timeScale = 1;
SceneManager.LoadScene(0);
}
}
완성된 모습. 자잘하게 수정해주면 좋을게 있지만, 2D는 여기서 마무리.
2D 튜토리얼 강좌를 듣다보니 대학생때 유니티로 만든 첫 프로젝트가 기억난다. 팀 프로젝트로 만들었던 게임인데, 이런식의 스테이지별로 진행하는 2D 게임이었다.ㅎㅎ 그게 벌써 10년 전 일...
728x90
'Software Development > Unity' 카테고리의 다른 글
유니티 3D 간보기 - 골드메탈 3D강좌:아이템 먹기/장착 (0) | 2022.02.06 |
---|---|
유니티 3D 간보기 - 골드메탈 3D강좌:플레이어 컨트롤 (0) | 2022.02.05 |
유니티 간보기 - 골드메탈 2D 따라하기_피격이벤트 (0) | 2022.02.05 |
유니티 간보기 - 골드메탈 2D 따라하기_몬스터기초 AI (0) | 2022.02.04 |
유니티 간보기 - 골드메탈 2D 따라하기_타일맵 (0) | 2022.02.04 |