일단 배경 생성
사용한 에셋
1. 조이스틱 움직이면 움직이게 설정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField]
private float moveSpeed = 2f;
[SerializeField]
private VariableJoystick joystick;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//조이스틱 x, y좌표
Vector2 moveDir = (Vector2.right * joystick.Direction.x) + (Vector2.up * joystick.Direction.y);
this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);
Debug.Log(moveDir);
if (moveDir == Vector2.zero)
{
//공격
}
else if (moveDir.x > 0)
{
//오른쪽
}
else if (moveDir.x < 0)
{
//왼쪽
}
else if (moveDir.y > 0)
{
//위
}
else if (moveDir.y < 0)
{
//아래
}
}
}
벽돌을 통과안하게 tag로 벽을 Wall로 설정해서 하고싶었는데
왜 그런건지
Trigger로 해도 , Collision으로 해도 태그를 알아보지못한다.
그래서 어떻게 해야할지 잘 모르겠다.
-----------------> 알았다. 지금 나는 2D Unity를 사용중인데 OnTrigger나 Collision이나 2D용으로 쓰지 않고 3D? 용으로 사용해서 반응이 없었던 것이었다.
이건 무슨 오류 때문에 발생한건지 잘 모르겠다.
----------> 3D로 보니까 화살이 LookAt으로 쥐를 보면서 가는건데 화살 자체가 3D로 LookAt되서 2D로는 보이지 않았던 것 같다.
찾아보니까 transform.Lookat 함수는 회전값도 변경시켜서 2D에서는 사용할 수 없는 것 같다.
ArrowController
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using System;
public class ArrowController : MonoBehaviour
{
[SerializeField]
private float attackSpeed = 1f;
private GameObject monsterGo;
private GameObject playerGo;
// Start is called before the first frame update
void Start()
{
this.monsterGo = GameObject.Find("Rat");
this.playerGo = GameObject.Find("Player");
//화살 생성 위치
this.transform.position = this.playerGo.transform.position + this.playerGo.transform.up * 0.5f;
}
// Update is called once per frame
void Update()
{
//바라보기
this.transform.LookAt(this.monsterGo.transform.position);
//이동
this.transform.position = Vector2.Lerp(this.transform.position, this.monsterGo.transform.position, Time.deltaTime * 1f);
}
public void Fire()
{
//Instantiate(this.gameObject);
}
}
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class PlayerController : MonoBehaviour
{
private enum eAnimState
{
Idle, Run, Attack
}
[SerializeField]
private float moveSpeed = 2f;
[SerializeField]
private VariableJoystick joystick;
[SerializeField]
private ArrowController arrowController;
private Animator anim;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//바깥으로 안나가는 x, y좌표
float clampX = Mathf.Clamp(this.transform.position.x, -2.35f, 2.70f);
float clampY = Mathf.Clamp(this.transform.position.y, -4.00f, 4.50f);
this.transform.position = new Vector2(clampX, clampY);
//몬스터와 플레이어 사이의 방향벡터 계산
//조이스틱 x, y좌표
Vector2 moveDir = (Vector2.right * joystick.Direction.x) + (Vector2.up * joystick.Direction.y);
this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);
if (moveDir == Vector2.zero)
{
//공격
this.PlayAnimation(eAnimState.Attack);
this.arrowController.Fire();
}
else if (moveDir.x > 0)
{
//오른쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.x < 0)
{
//왼쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y > 0)
{
//위
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y < 0)
{
//아래
this.PlayAnimation(eAnimState.Run);
}
}
private void PlayAnimation(eAnimState state)
{
this.anim.SetInteger("State", (int)state);
}
}
[Unity] 2D LookAt Lerp
Transform에는 특정 target을 바라보도록 하는 함수인 LookAt이 기본적으로 내장되어 있습니다. 그런데 이 함수는 한 프레임 만에 회전값을 변경시킵니다. 2D에서는 다음과 같이 간단하게 수식 하나로,
saens.tistory.com
2D는 LookAt이 없나.. 찾아보다가 찾게되었다.
ArrowController
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using System;
public class ArrowController : MonoBehaviour
{
[SerializeField]
private float attackSpeed = 1f;
private GameObject monsterGo;
private GameObject playerGo;
private float elapsedTime = 0f;
// Start is called before the first frame update
void Start()
{
this.monsterGo = GameObject.Find("Rat");
this.playerGo = GameObject.Find("Player");
//화살 생성 위치
this.transform.position = this.playerGo.transform.position + this.playerGo.transform.right * 1f;
}
// Update is called once per frame
void Update()
{
//바라보기
this.transform.LookAt2DLerp(this.monsterGo.transform.position);
//이동
this.transform.position = Vector2.Lerp(this.transform.position, this.monsterGo.transform.position, Time.deltaTime * 1f);
if (Input.GetMouseButtonDown(0))
{
this.elapsedTime = 0f;
}
}
public void Fire()
{
this.elapsedTime += Time.deltaTime;
if (this.elapsedTime >= 0.95f)
{
Instantiate(this.gameObject);
this.elapsedTime = 0f;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Monster")
{
Destroy(this.gameObject);
}
}
}
public static class LookAtExtension
{
public static void LookAt2DLerp(this Transform transform, Vector2 dir, float lerpPercent = 0.05f)
{
float rotationZ = Mathf.Acos(dir.x / dir.magnitude)
* 180 / Mathf.PI
* Mathf.Sign(dir.y);
transform.rotation = Quaternion.Lerp(
transform.rotation,
Quaternion.Euler(0, 0, rotationZ),
lerpPercent
);
}
}
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class PlayerController : MonoBehaviour
{
private enum eAnimState
{
Idle, Run, Attack
}
[SerializeField]
private float moveSpeed = 2f;
[SerializeField]
private VariableJoystick joystick;
[SerializeField]
private ArrowController arrowController;
private Animator anim;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//바깥으로 안나가는 x, y좌표
float clampX = Mathf.Clamp(this.transform.position.x, -2.35f, 2.70f);
float clampY = Mathf.Clamp(this.transform.position.y, -4.00f, 4.50f);
this.transform.position = new Vector2(clampX, clampY);
//몬스터와 플레이어 사이의 방향벡터 계산
//조이스틱 x, y좌표
Vector2 moveDir = (Vector2.right * joystick.Direction.x) + (Vector2.up * joystick.Direction.y);
this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);
if (moveDir == Vector2.zero)
{
//공격
this.PlayAnimation(eAnimState.Attack);
this.arrowController.Fire();
}
else if (moveDir.x > 0)
{
//오른쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.x < 0)
{
//왼쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y > 0)
{
//위
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y < 0)
{
//아래
this.PlayAnimation(eAnimState.Run);
}
}
private void PlayAnimation(eAnimState state)
{
this.anim.SetInteger("State", (int)state);
}
}
뭔가.. 벽에 붙으면 멈추게 하거나 벽으로 못가게 하는걸 어떻게 해야할지 몰라서 기존 위치로 초기화 시키는 방식으로 택했다.
거의 완성된 거 같다..?
구현내용
조이스틱[움직이기]
몬스터가 있으면 공격하기
몬스터가 없으면 공격 안하기
벽에 닿으면 원래 위치로 초기화[벽에 부딪히면 멈추는걸 어떻게 해야할지 모르겠음]
몬스터가 죽으면 포탈 소환하기
PortalController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PortalController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
public void CreatePortal()
{
this.gameObject.SetActive(true);
}
}
MonsterController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterController : MonoBehaviour
{
[SerializeField]
private PortalController portalController;
private int hp = 3;
public int Hp
{
get
{
return this.hp;
}
set
{
if(value == 0)
{
Debug.Log("몬스터 사망!");
this.Die();
}
else
{
this.hp = value;
Debug.LogFormat("남은 체력: ({0}/{1})", this.hp, this.maxHp);
}
}
}
private int maxHp;
// Start is called before the first frame update
void Start()
{
this.maxHp = this.hp;
}
private void Die()
{
Destroy(this.gameObject);
portalController.CreatePortal();
}
}
ArrowController
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using System;
public class ArrowController : MonoBehaviour
{
[SerializeField]
private float attackSpeed = 1f;
private int arrowDamage = 1;
private GameObject monsterGo;
private GameObject playerGo;
private MonsterController monsterController;
private float elapsedTime = 0f;
// Start is called before the first frame update
void Start()
{
this.monsterGo = GameObject.Find("Rat");
this.playerGo = GameObject.Find("Player");
this.monsterController = this.monsterGo.GetComponent<MonsterController>();
//화살 생성 위치
this.transform.position = this.playerGo.transform.position + this.playerGo.transform.right * 1f;
}
// Update is called once per frame
void Update()
{
//바라보기
this.transform.LookAt2DLerp(this.monsterGo.transform.position);
//이동
this.transform.position = Vector2.Lerp(this.transform.position, this.monsterGo.transform.position, Time.deltaTime * this.attackSpeed);
if (Input.GetMouseButtonDown(0))
{
this.elapsedTime = 0f;
}
}
public void Fire()
{
this.elapsedTime += Time.deltaTime;
if (this.elapsedTime >= 0.95f)
{
Instantiate(this.gameObject);
this.elapsedTime = 0f;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Monster")
{
Destroy(this.gameObject);
this.monsterController.Hp -= this.arrowDamage;
}
else if(collision.tag == "Wall")
{
this.attackSpeed = 0f;
Destroy(this.gameObject, 3f);
}
}
}
public static class LookAtExtension
{
public static void LookAt2DLerp(this Transform transform, Vector2 dir, float lerpPercent = 0.05f)
{
float rotationZ = Mathf.Acos(dir.x / dir.magnitude)
* 180 / Mathf.PI
* Mathf.Sign(dir.y);
transform.rotation = Quaternion.Lerp(
transform.rotation,
Quaternion.Euler(0, 0, rotationZ),
lerpPercent
);
}
}
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class PlayerController : MonoBehaviour
{
private enum eAnimState
{
Idle, Run, Attack
}
[SerializeField]
private float moveSpeed = 2f;
[SerializeField]
private VariableJoystick joystick;
[SerializeField]
private ArrowController arrowController;
[SerializeField]
private GameObject monsterGo;
private Animator anim;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
this.monsterGo = GameObject.Find("Rat");
}
// Update is called once per frame
void Update()
{
//바깥으로 안나가는 x, y좌표
float clampX = Mathf.Clamp(this.transform.position.x, -2.35f, 2.70f);
float clampY = Mathf.Clamp(this.transform.position.y, -4.00f, 4.50f);
this.transform.position = new Vector2(clampX, clampY);
//몬스터와 플레이어 사이의 방향벡터 계산
//조이스틱 x, y좌표
Vector2 moveDir = (Vector2.right * joystick.Direction.x) + (Vector2.up * joystick.Direction.y);
this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);
if (moveDir == Vector2.zero)
{
//공격
if (this.monsterGo != null)
{
this.PlayAnimation(eAnimState.Attack);
this.arrowController.Fire();
}
else
this.PlayAnimation(eAnimState.Idle);
}
else if (moveDir.x > 0)
{
//오른쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.x < 0)
{
//왼쪽
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y > 0)
{
//위
this.PlayAnimation(eAnimState.Run);
}
else if (moveDir.y < 0)
{
//아래
this.PlayAnimation(eAnimState.Run);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Wall")
{
Debug.Log("벽을 통과할 수 없습니다.");
this.transform.position = new Vector2(-2.02f, -3.73f);
}
}
private void PlayAnimation(eAnimState state)
{
this.anim.SetInteger("State", (int)state);
}
}
'유니티 심화' 카테고리의 다른 글
절대강좌 유니티 - Quaternion.LookRotation (0) | 2023.08.21 |
---|---|
절대강좌 유니티 - 총알 이펙트효과 (0) | 2023.08.21 |
SpaceShooter2D - 스페이스바 눌러서 총쏘고 제거하기 [완] (0) | 2023.08.18 |
챕터5 - 총알 (0) | 2023.08.18 |
Ref (0) | 2023.08.18 |