Git
https://github.com/mjmj1/InD_GameJam_2
InputSystem.cs
public class InputSystem : MonoBehaviour
{
public static InputSystem Instance;
private bool isDragging;
private void Awake()
{
if (!Instance)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else if (Instance != this)
{
Destroy(gameObject);
}
}
private void Update()
{
var mousePos = Input.mousePosition;
switch (isDragging)
{
case false when Input.GetMouseButtonDown(0):
isDragging = true;
OnMouseButtonDown?.Invoke(mousePos);
break;
case true when Input.GetMouseButton(0):
OnMouseButtonHold?.Invoke(mousePos);
break;
case true when Input.GetMouseButtonUp(0):
isDragging = false;
OnMouseButtonUp?.Invoke(mousePos);
break;
}
}
public event Action<Vector2> OnMouseButtonDown;
public event Action<Vector2> OnMouseButtonHold;
public event Action<Vector2> OnMouseButtonUp;
}- new Input System을 사용하기엔 단순 마우스 조작만 있었기에 과하다고 판단했기에 간단하게 InputSystem을 구현
Thrower.cs
public class Thrower : MonoBehaviour
{
// 생략
protected Vector2 ThrowDirection;
protected float ThrowForce;
protected bool IsThrown = false;
private Vector2 _startPosition;
public event Action OnThrow;
protected virtual void Start()
{
InputSystem.Instance.OnMouseButtonDown += OnMouseButtonDown;
InputSystem.Instance.OnMouseButtonHold += OnMouseButtonHold;
InputSystem.Instance.OnMouseButtonUp += OnMouseButtonUp;
}
protected virtual void OnDestroy()
{
InputSystem.Instance.OnMouseButtonDown -= OnMouseButtonDown;
InputSystem.Instance.OnMouseButtonHold -= OnMouseButtonHold;
InputSystem.Instance.OnMouseButtonUp -= OnMouseButtonUp;
}
protected virtual void OnMouseButtonDown(Vector2 mousePosition)
{
if (IsThrown) return;
_startPosition = mousePosition;
}
protected virtual void OnMouseButtonHold(Vector2 mousePosition)
{
if (IsThrown) return;
var offset = _startPosition - mousePosition;
ThrowDirection = offset.normalized;
ThrowForce = Mathf.InverseLerp(0, 1000, offset.magnitude) * maxThrowForce;
}
protected virtual void OnMouseButtonUp(Vector2 mousePosition)
{
IsThrown = true;
OnThrow?.Invoke();
}
}- 던질 수 있는 것들에 코드 중복을 피하기 위해 Thrower 라는 부모 클래스를 생성하고 이를 상속받는 클래스를 구현
- OnMouseButtonUp 도 if (IsThrown) return; 처리를 했어야 했음
public class MultiThrower : Thrower
{
// 생략
[SerializeField] private float throwDelay = 0.1f;
private WaitForSeconds _wait;
protected override void OnMouseButtonUp(Vector2 mousePosition)
{
if (IsThrown) return;
base.OnMouseButtonUp(mousePosition);
StartCoroutine(ShootRoutine());
}
private IEnumerator ShootRoutine()
{
for (var i = 0; i < throwableCount; i++)
{
Spawn();
var throwable = currentThrowable.GetComponent<Throwable>();
throwable.Throw(ThrowDirection, ThrowForce, 40f);
yield return _wait;
}
}
// 생략
}- 던질 때 여러 개를 던질 수 있도록 상속 후 오버라이딩
Throwable.cs
public class Throwable : MonoBehaviour
{
[Range(0f, 1f)]
[SerializeField] protected float restitution = 1f;
protected virtual void OnCollisionEnter2D(Collision2D collision)
{
if (!collision.collider.CompareTag("Failed")) return;
// 실패 처리
if (!collision.collider.CompareTag("Target")) return;
var interactable = collision.collider.GetComponent<Interactable>();
interactable.Interact(collision);
Interact();
}
protected virtual void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Target")) return;
var interactable = other.GetComponent<Interactable>();
interactable.Interact(null);
Interact();
}
public void Throw(Vector2 throwDirection, float throwForce, float spreadAngle = 0f)
{
if (IsThrown) return;
IsThrown = true;
var direction = Spread(throwDirection, spreadAngle);
Rb.AddForce(direction * throwForce, ForceMode2D.Impulse);
}
private Vector2 Spread(Vector2 throwDirection, float spreadAngle)
{
if (spreadAngle == 0f) return throwDirection;
var halfAngle = spreadAngle * 0.5f;
var randomAngle = Random.Range(-halfAngle, halfAngle);
return Quaternion.Euler(0, 0, randomAngle) * throwDirection;
}
public void Torque(float torque)
{
Rb.AddTorque(torque);
}
protected virtual void Interact()
{
StopToCollision();
}
public void StopToCollision()
{
Rb.velocity = Vector2.zero;
Rb.angularVelocity = 0f;
Rb.constraints = RigidbodyConstraints2D.FreezePosition;
}
public void Bound(Vector2 normal)
{
var incomingVel = Rb.velocity;
var reflectedVel = Vector2.Reflect(incomingVel, normal);
Rb.velocity = reflectedVel * restitution;
}
}- 다양한 효과들을 미리 정의하고 파생 클래스마다 다른 효과를 선택해서 사용하도록 구현
- Interact() 부분에서 함수를 완전히 비워서 만들었어야 팀원들이 덜 헷갈려했을 듯함 → 코드가 너무 과했음
Interactable.cs
public class Interactable : MonoBehaviour
{
protected SpriteRenderer Sprite;
protected Collider2D Col;
protected Rigidbody2D Rb;
protected virtual void Awake()
{
Sprite = GetComponent<SpriteRenderer>();
Col = GetComponent<Collider2D>();
Rb = GetComponent<Rigidbody2D>();
}
public virtual void Interact(Collision2D collision)
{
}
}- Throwable 이 날라가서 상호작용 하는 물체에 들어가는 스크립트
- 아래의 두 코드를 봤을 때, 성공 판정에 대한 코드도 넣어뒀어야 했음
public class MakeBurger : Interactable
{
// 생략
private void FixedUpdate()
{
if (_hasEntered && !_isClear)
{
_elapsed += Time.fixedDeltaTime;
if (!(_elapsed >= targetTime)) return;
StageManager.Instance.StageClear();
_isClear = true;
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Failed")) StageManager.Instance.StageRestart();
if (!other.CompareTag("Throwable")) return;
_elapsed = 0f;
_hasEntered = true;
}
private void OnTriggerExit2D(Collider2D other)
{
if (!_hasEntered) return;
_elapsed = 0f;
_hasEntered = false;
}
// 생략
}using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Interactables
{
public class MoveTruck : Interactable
{
// 생략
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Throwable")) return;
_elapsed = 0f;
_hasEntered = true;
}
private void OnTriggerExit2D(Collider2D other)
{
if (!other.CompareTag("Throwable")) return;
if (!_hasEntered) return;
_elapsed = 0f;
_hasEntered = false;
}
private void OnTriggerStay2D(Collider2D other)
{
if (!_hasEntered) return;
if (!other.CompareTag("Throwable")) return;
if (other.GetComponent<Rigidbody2D>().velocity.magnitude > 3f)
{
_elapsed = 0f;
return;
}
_elapsed += Time.fixedDeltaTime;
if (!(_elapsed >= targetTime)) return;
StageManager.Instance.StageClear();
_hasEntered = false;
}
// 생략
}
}