캐릭터 점프
캐릭터의 점프 기능을 추가해 보자.
우선, Space를 입력하여 동작할 수 있도록 입력 Action을 추가하자.
private InputAction Jump_Input;
void Start()
{
...
Jump_Input = Input.actions["Jump"];
...
}
이를, Update함수에서 입력을 감지해 점프가 실행되도록 하면 된다.
추가로 Animation까지 적용해 보자.
private bool IsGround = true;
public bool Ground
{
get => IsGround;
set => IsGround = value;
}
void Update()
{
Vector2 moveValue = Move_Input.ReadValue<Vector2>();
if (moveValue.x != 0) _spriteRenderer.flipX = moveValue.x < 0;
_animator.SetFloat(SpeedId, Mathf.Abs(moveValue.x));
_rigidbody.velocity = new Vector2(moveValue.x * Speed, _rigidbody.velocity.y);
if (Jump_Input.triggered && IsGround)
{
_rigidbody.AddForce(Vector2.up * JumpSpeed, ForceMode2D.Impulse);
_animator.Play("Alchemist_Jump");
}
}
public void OnGround()
{
IsGround = true;
GetComponent<Animator>().Play("Alchemist_Idle");
}
Update에서 Space키가 눌렸을 때, 위쪽으로 힘을 주어 점프가 되도록 한 뒤 점프에 해당하는 Animation을 실행한다.
점프가 실행되고 땅에 착지했는지를 확인해야 하기 때문에, 이를 확인하는 Componenet를 추가하자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GroundChecker : MonoBehaviour
{
CharacterController controller;
void Start()
{
controller = GetComponentInParent<CharacterController>();
}
void OnTriggerEnter2D(Collider2D other)
{
controller.OnGround();
}
void OnTriggerExit2D(Collider2D other)
{
controller.Ground = false;
}
}
해당 컴포넌트는 Collider2D와 위의 스크립트를 가지고 있어, 지면과 Trigger가 일어났을 때 controller에게 동작을 요구한다.
아이템 획득
캐릭터가 이동하여 아이템을 획득하여 인벤토리에 저장할 수 있도록 만들어 보자.
우선, 획득할 아이템 오브젝트를 만들어 보자.
해당 오브젝트는 충돌 감지를 위한 Collider와 이미지를 보여줄 Sprite Renderer, 그리고 충돌 처리를 위한 스크립트를 하나씩 갖는다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnedItem : MonoBehaviour
{
//Do Something
}
해당 스크립트에서는 충돌시 애니메이션을 주며 사라지게 할 수도 있고 다양한 처리를 할 수 있지만, 지금은 구현하지 않는다.
이제, 아이템을 획득하여 인벤토리에 저장할 컴포넌트를 추가하자.
해당 컴포넌트는 충돌을 감지할 Collider와 이를 처리할 스크립트를 갖는다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ItemGetter : MonoBehaviour
{
public RectTransform itemRectTransform;
public Canvas canvas;
public GettedObject itemPrefab;
public Camera uiCamera;
private void OnTriggerEnter2D(Collider2D other)
{
var newObject = Instantiate(itemPrefab, other.transform.position, Quaternion.identity, canvas.transform);
newObject.GetComponent<Image>().sprite = other.GetComponent<SpriteRenderer>().sprite;
newObject.transform.position = other.transform.position;
if (Camera.main == null) return;
var screenPos = Camera.main.WorldToScreenPoint(newObject.transform.position);
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.GetComponent<RectTransform>(), screenPos, uiCamera, out localPoint);
newObject.transform.localPosition = localPoint;
newObject.TargetPos = itemRectTransform;
Destroy(other.gameObject);
}
}
SpawnedItem과 ItemGetter사이의 충돌을 설정하기 위해 Layer를 다음과 같이 변경해야 한다.
Physics2D인 점을 유의하자.
캐릭터와 아이템이 충돌을 일으키면 아이템의 이미지가 UI로 생성되어 인벤토리 UI 쪽으로 이동하도록 해보자.
우선, 아이템 이미지를 나타내는 UI용 오브젝트를 만들어 보자.
해당 오브젝트는 Image와 스크립트를 갖는다.
스크립트에서는 전달받은 위치로 이동하는 코루틴을 실행한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GettedObject : MonoBehaviour
{
public GameObject reachFX;
public RectTransform TargetPos
{
set => StartCoroutine(MoveToTarget(value));
}
private float EaseInOut(float t)
{
return t < 0.5f ? 2f * t * t : -1f + (4f - 2f * t) * t;
}
private IEnumerator MoveToTarget(RectTransform boxTransform)
{
float duration = 1.0f;
float t = 0.0f;
Vector3 itemBeginPOS = transform.position;
while (t <= duration)
{
Vector3 newPosition = Vector3.Lerp(itemBeginPOS, boxTransform.position, EaseInOut(t / duration));
transform.position = newPosition;
t += Time.deltaTime;
yield return null;
}
var particle = Instantiate(reachFX, boxTransform.position, reachFX.transform.rotation);
var vector3 = particle.transform.position;
vector3.z = 1f;
particle.transform.position = vector3;
Destroy(particle, 3.0f);
var inventoryButton = boxTransform.gameObject.GetComponent<InventoryButton>();
inventoryButton.Shake();
transform.position = boxTransform.position;
Destroy(gameObject);
}
}
EaseInOut은 이동할 때 애니메이션을 주기위한 함수이다.
상자에 도달하면 fx를 생성하여 보여주고 삭제된다.
인벤토리 버튼이 흔들리는 효과도 추가하였다.
상자가 흔들리는 효과는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryButton : MonoBehaviour
{
[SerializeField] private float ShakeSpeed = 10f;
[SerializeField] private float ShakeAngle = 30f;
public void Shake()
{
StartCoroutine(ShakeChest());
}
private float Sine(float end, float value)
{
return Mathf.Sin(value/end * ShakeSpeed);
}
private IEnumerator ShakeChest()
{
float duration = 2.0f;
float t = 0.0f;
while (t <= duration)
{
var currenQuat = transform.rotation;
var newQuat = Quaternion.Euler(new Vector3(0f, 0f, Sine(duration, t) * ShakeAngle));
transform.rotation = Quaternion.Lerp(currenQuat, newQuat, t / duration);
t += Time.deltaTime;
yield return null;
}
transform.rotation = Quaternion.identity;
}
}