게임 메니저 스크립트
게임 메니저의 역할
- 게임의 점수를 관리한다.
- 게임의 도착지에 도달 시 스테이지를 관리한다.
- 스테이지의 인덱스를 관리한다.
using UnityEngine;
public class GameManager : MonoBehaviour
{
public int totalPoint;
public int stagePoint;
public int stageIndex;
void Start()
{
}
void Update()
{
}
}
게임 메니저를 위 사진과 같이 생성한 후 플레이어에서 매니저 변수를 만들어 점수 변수에 접근한다.
PlayerMove 스크립트에 다음과 같이 게임 메니저 스크립트를 추가한다.
public GameManager gameManager;
게임 포인트
동전에 접촉 시 사용하는 메서드를 수정하여 게임 포인트를 증가하도록 한다.
이때 동전 게임 오브젝트를 금,은,동을 각각 태그를 달아준다.
금 | tag | Gold |
은 | Silver | |
동 | Bronze |
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "Enemy") {
//Attack - 3.22
Debug.Log("Enemy Connect!");
if(rigid.velocity.y<0 && transform.position.y > collision.transform.position.y){
OnAttack(collision.transform);
Debug.Log("Attack to Enemy!");
}
else {
OnDamaged(collision.transform.position); //Damaged - 3.22
Debug.Log("Too Sad...");
}
}
//Coin Manager
else if (collision.gameObject.tag == "Bronze")gameManager.stagePoint += 50;
else if (collision.gameObject.tag == "Silver")gameManager.stagePoint += 150;
else if (collision.gameObject.tag == "Gold")gameManager.stagePoint += 300;
//Finish
else if (collision.gameObject.tag == "Finish"){
Destroy(collision.gameObject);
}
}
이제 플레이어가 데미지를 입으면 체력을 감소시킬 HealthDown 함수를 만든다.
이때 게임 메니저를 참조하여 스테이지 포인트를 관리한다. 이 과정에서 오류가 나면 다음 블로그 포스팅을 참조한다.
https://udangtangtang-cording-oldcast1e.tistory.com/125
public void HealthDown(){
if(healthPoint > 1) healthPoint --;
else{
//player Die Effect
player.OnDie();
//Result UI
Debug.Log("죽었습니다!");
//Retry Button UI
}
}
해당 함수를 만드면 Healthpoint를 감소시키는 코드인 Healthpoint--;를 가진 코드를 모두 HealthDown();로 변경한다.
게임 스테이지
스테이지가 올라가면 totalPoint에 누적한다. 이때 NextStage 함수는 Finish 오브젝트를 접촉할 때 사용한다.
Finish 오브젝트를 접촉은 스테이지 클리어의 의미를 가진다.
[GameManager]
이때 NextStage의 범위를 public으로 정의하는 것을 주의한다!
using UnityEngine;
public class GameManager : MonoBehaviour
{
public int totalPoint;
public int stagePoint;
public int stageIndex;
public void NextStage()
{
stageIndex ++;
totalPoint += stagePoint;
stagePoint = 0;
}
void Update()
{
}
}
[PlayerMove]
private void OnCollisionEnter2D(Collision2D collision)
...이후 생략
else if (collision.gameObject.tag == "Finish"){
//NextStage
gameManager.NextStage();
}
플레이어의 체력 관리
게임 메니저 스크립트에 플레이어의 체력을 관리할 healthPoint 변수를 public으로 선언한다.
public int healthPoint;
public int totalPoint;
public int stagePoint;
public int stageIndex;
public int healthPoint;
void OnTriggerEnter2D(Collision2D collision){
if (collision.gameObject.tag == "Player"){
//HealthDown
healthPoint --;
collision.attachedRigdbody.velocity = Vector2.zero;
collision.transform.position = new Vector3(0,0,-1);
}
}
이때 collision.transform.position = new Vector3(0,0,-1); 는 캐릭터의 시작점이 (0,0)일 때만 가능하다.
따라서 캐릭터의 재시작 로직의 Vector3는 각 스테이지의 캐릭터 시작점으로 설정한다.
[PlayerMove]
PlayerMove의 스크립트의 Ongamaged 함수를 변경한다.
public void OnDamaged(Vector2 TargetPos){//-3.22
//Health Down
gameManager.healthPoint --;
...이하 중략
}
플레이어의 낙사/사망 시 원위치
게임 메니저에 BoxCollider2D 컴포넌트를 추가하고, isTrigger를 체크한다.
void OnTriggerEnter2D(Collider2D collision){
if (collision.gameObject.tag == "Player"){
//HealthDown
healthPoint --;
Debug.Log("Player Die!");
collision.attachedRigidbody.velocity = Vector2.zero;
collision.transform.position = new Vector3(0,0,-1);
}
}
}
PlayerMove 스크립트 변경
플레이어가 Die 판정을 받을 때의 함수를 생성한다.
- 플레이어의 컬러를 변경한다.
- 플레이어의 y 축 Flip를 true로 변경한다.
- 플레이어의 콜라이더를 비활성화 한다.
- 플레이어의 리지드 바디에 힘을 부여한다.
- DeActive를 5초 후에 실행한다.
void OnDie(){
//Sprite Alpha
spriteRenderer.color = new Color(1,1,1,0.4f);
//Sprite Flip Y
spriteRenderer.flipY = true;
//Collider Disable
PlayerColider.enabled = false;
//Die Effect Jump
rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
// //Destroy
Invoke("DeActive",5);
}
PlayerMove 스크립트 전체 코드
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
public GameManager gameManager;
public float maxSpeed; //최대 속력 변수
public float jumpPower;
private Rigidbody2D rigid; //물리이동을 위한 변수 선언
private SpriteRenderer spriteRenderer; //방향전환을 위한 변수
private Animator animator; //애니메이터 조작을 위한 변수
private CircleCollider2D PlayerColider;
private AudioSource playerAudio; // 사용할 오디오 소스 컴포넌트
private bool isDead = false; // 사망 상태
private void Awake() {
rigid = GetComponent<Rigidbody2D>(); //변수 초기화
spriteRenderer = GetComponent<SpriteRenderer>(); // 초기화
animator = GetComponent<Animator>();
PlayerColider = GetComponent<CircleCollider2D>();
// gameManager = GetComponent<GameManager>();
}
void Update(){
// 버튼에서 손을 떄는 등의 단발적인 키보드 입력은 FixedUpdate보다 Update에 쓰는게 키보드 입력이 누락될 확률이 낮아짐
//Jump
if(Input.GetButtonDown("Jump") && !animator.GetBool("isJumping")){
rigid.AddForce(Vector2.up* jumpPower , ForceMode2D.Impulse);
animator.SetBool("isJumping",true);
}
//Stop speed
if(Input.GetButtonUp("Horizontal")){ // 버튼에서 손을 때는 경우
// normalized : 벡터 크기를 1로 만든 상태 (단위벡터 : 크기가 1인 벡터)
// 벡터는 방향과 크기를 동시에 가지는데 크기(- : 왼 , + : 오)를 구별하기 위하여 단위벡터(1,-1)로 방향을 알수 있도록 단위벡터를 곱함
rigid.velocity = new Vector2( 0.5f * rigid.velocity.normalized.x , rigid.velocity.y);
}
//Direction Sprite
if(Input.GetButtonDown("Horizontal"))
spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
//Animation
if( Mathf.Abs(rigid.velocity.x) < 0.2) //속도가 0 == 멈춤
animator.SetBool("isWalking",false); //isWalking 변수 : false
else// 이동중
animator.SetBool("isWalking",true);
}
// Update is called once per frame
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); //해당 오브젝트의 속력은 maxSpeed
else if(rigid.velocity.x < maxSpeed*(-1)) // 왼쪽으로 이동 (-)
rigid.velocity = new Vector2(maxSpeed*(-1), rigid.velocity.y); //y값은 점프의 영향이므로 0으로 제한을 두면 안됨
//Landing Paltform
Debug.DrawRay(rigid.position, Vector3.down, new Color(0,1,0)); //빔을 쏨(디버그는 게임상에서보이지 않음 ) 시작위치, 어디로 쏠지, 빔의 색
RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform"));
//빔의 시작위치, 빔의 방향 , 1:distance , ( 빔에 맞은 오브젝트를 특정 레이어로 한정 지어야할 때 사용 ) // RaycastHit2D : Ray에 닿은 오브젝트 클래스
//rayHit는 여러개 맞더라도 처음 맞은 오브젝트의 정보만을 저장(?)
if(rigid.velocity.y < 0){ // 뛰어올랐다가 아래로 떨어질 때만 빔을 쏨
// Debug.Log("Drop!");
if(rayHit.collider != null){ //빔을 맞은 오브젝트가 있을때 -> 맞지않으면 collider도 생성되지않음
// Debug.Log("Down!");
if(rayHit.distance < 0.5f)
animator.SetBool("isJumping",false); //거리가 0.5보다 작아지면 변경
}
}
}
private void OnTriggerEnter2D(Collider2D other) {
if (other.tag == "Dead" && !isDead) Die();
Debug.Log("Player Dead");
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "Enemy") {
//Attack - 3.22
Debug.Log("Enemy Connect!");
if(rigid.velocity.y<0 && transform.position.y > collision.transform.position.y){
OnAttack(collision.transform);
Debug.Log("Attack to Enemy!");
}
else {
OnDamaged(collision.transform.position); //Damaged - 3.22
Debug.Log("Too Sad...");
}
}//Coin Manager
else if (collision.gameObject.tag == "Bronze") {
gameManager.stagePoint += 50;
collision.gameObject.SetActive(false);
}
else if (collision.gameObject.tag == "Silver") {
gameManager.stagePoint += 150;
collision.gameObject.SetActive(false);
}
else if (collision.gameObject.tag == "Gold") {
gameManager.stagePoint += 300;
collision.gameObject.SetActive(false);
}
else if (collision.gameObject.tag == "Finish"){//Finish
// Destroy(collision.gameObject);
//NextStage
Debug.Log("스테이지 클리어!");
gameManager.NextStage();
}
}
void OnAttack(Transform enemy){
//Point
//Enemy Die
EnemyMove enemyMove = enemy.GetComponent<EnemyMove>();
enemyMove.OnDamaged();
}
private void Die() {
animator.SetTrigger("Die");
// // playerAudio.clip = deathClip;
// // playerAudio.Play();
rigid.velocity = Vector2.zero;
isDead = true;
}
public void OnDamaged(Vector2 TargetPos){//-3.22
//Health Down
// gameManager.healthPoint --;
gameManager.HealthDown();
//Change Layer
gameObject.layer = 11;
//Sprite Alpha
spriteRenderer.color = new Color(1,1,1,0.4f);
//Readctio Force 3.22
int dirc = transform.position.x - TargetPos.x > 0 ?1:-1;
rigid.AddForce(new Vector2(dirc,1)*5,ForceMode2D.Impulse);
animator.SetTrigger("Die"); //- 3.25
Invoke("OffDamaged",3);
}
void DeActive(){
gameObject.SetActive(false);
}
void OffDamaged(){
gameObject.layer = 10;
spriteRenderer.color = new Color(1,1,1,1);
}
public void OnDie(){
//Sprite Alpha
spriteRenderer.color = new Color(1,1,1,0.4f);
//Sprite Flip Y
spriteRenderer.flipY = true;
//Collider Disable
PlayerColider.enabled = false;
//Die Effect Jump
rigid.AddForce(Vector2.up * 5, ForceMode2D.Impulse);
// //Destroy
Invoke("DeActive",5);
}
public void VelocityZero(){
rigid.velocity = Vector2.zero;
}
}
GameManager 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public int totalPoint;
public int stagePoint;
public int stageIndex;
public GameObject[] Stages;
public PlayerMove player;
public int healthPoint;
public void NextStage()
{
Debug.Log("다음 스테이지 개방!");
if(stageIndex < Stages.Length -1){
Stages[stageIndex].SetActive(false);
Debug.Log("stageIndex:"+stageIndex);
stageIndex ++;
PlayerReposition();
Stages[stageIndex].SetActive(true);
// SceneManager.LoadScene(stageLevel, LoadSceneMode.Single);
}
else{
Time.timeScale = 0;
Debug.Log("게임 클리어!");
}
totalPoint += stagePoint;
stagePoint = 0;
}
void OnTriggerEnter2D(Collider2D collision){
if (collision.gameObject.tag == "Player"){
//HealthDown
// healthPoint --;
if(healthPoint> 1) PlayerReposition();
HealthDown();
}
}
public void HealthDown(){
if(healthPoint > 1) healthPoint --;
else{
//player Die Effect
player.OnDie();
//Result UI
Debug.Log("죽었습니다!");
//Retry Button UI
}
}
void PlayerReposition(){
player.transform.position = new Vector3(0,0,-1);
player.VelocityZero();
}
}
'Development > [Game] Basic Game' 카테고리의 다른 글
[Game] #7. 게임 UI 생성 및 완성 (0) | 2022.03.29 |
---|---|
[Game] #4. 충돌 및 사냥 구현 (0) | 2022.03.28 |
[Game] #3. AI 구현 (0) | 2022.03.20 |
[Game] #2. 게임 UI 및 팔레트 (0) | 2022.03.20 |
[Game] #1. 새로운 프로젝트 (0) | 2022.03.20 |