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();
}