[Unity] Roll-a-Ball
๐ Roll-a-Ball ์ด๋?
โถ Roll-a-Ball - Unity Learn ํํ ๋ฆฌ์ผ ๋งํฌ
Unity์์ ๊ณต์์ ์ผ๋ก ์ ๊ณตํ๋ ๊ฒ์ ํํ ๋ฆฌ์ผ โRoll-a-Ballโ์ ์ ์ํ์๋ค. Unity ์ค์ ๋ถํฐ, Asset, C# Script ๋ฑ ์ ๋ฐ์ ์ธ ๊ฒ์ ์ ์ ๋ฐฉ๋ฒ์ ์ตํ ์ ์๋ค.
๐ค ์ฃผ์ C# Script
๐งก CameraController
๊ฒ์ ์คํ์, ํ์๋๋ ํ๋ฉด์ Camera๊ฐ ๋น์ถ์ด์ค๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค. ์ฌ๊ธฐ์๋ Player ์ญํ ์ ํ๋ ๊ณต(ball)์ 3์ธ์นญ์ผ๋ก ๋ฐ๋ผ๋ค๋๋ Camera ์ค์ ์ ์ง์ ํด์ฃผ์๋ค.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
// Start๋ ์ฒซ ํ๋ ์ ์
๋ฐ์ดํธ ์ด์ ์ ํธ์ถ๋ฉ๋๋ค.
void Start()
{
offset = transform.position - player.transform.position;
}
// Update๋ ํ๋ ์๋ง๋ค ํ ๋ฒ์ฉ ํธ์ถ๋ฉ๋๋ค.
void LateUpdate()
{
transform.position = player.transform.position + offset;
}
}
๐งก PlayerController
Player๋ฅผ ๋ฐฉํฅํค๋ก ์์ง์ด๊ณ , ์์ง์ด๋ speed๋ฅผ ์ง์ ํด์ฃผ๋ ์ญํ ์ด๋ค. ๋ํ ๋ ธ๋์ ์ค๋ธ์ ํธ์ ๋ถ๋ชํ๋ฉด ๋์ ํ๋ ๋ก์ง์ ๊ตฌํํ๊ธฐ ์ํ ์ฝ๋, ์ ์๋ฅผ ์นด์ดํธํ๋ ์ฝ๋๋ ํฌํจ๋์ด ์๋ค.
using UnityEngine;
// Unity UI ๋ฐ Input System์ ์ฌ์ฉํ๋ ๋ฐ ํ์ํ ๋ค์์คํ์ด์ค๋ฅผ ํฌํจํฉ๋๋ค.
using UnityEngine.InputSystem;
using TMPro;
public class PlayerController : MonoBehaviour
{
// ํ๋ ์ด์ด ์๋ ๋ฐ ํ
์คํธ UI ๊ฒ์ ์ค๋ธ์ ํธ์ ๋ํ public ๋ณ์๋ฅผ ๋ง๋ญ๋๋ค.
public float speed;
public TextMeshProUGUI countText;
public GameObject winTextObject;
private float movementX;
private float movementY;
private Rigidbody rb;
private int count;
// ๊ฒ์์ ์์ํ ๋
void Start()
{
// ๋ฆฌ์ง๋๋ฐ๋ ์ปดํฌ๋ํธ๋ฅผ private rb ๋ณ์์ ํ ๋นํฉ๋๋ค.
rb = GetComponent<Rigidbody>();
// count๋ฅผ 0์ผ๋ก ์ค์ ํฉ๋๋ค.
count = 0;
SetCountText();
// Win Text UI์ ํ
์คํธ ํ๋กํผํฐ๋ฅผ ๋น ๋ฌธ์์ด๋ก ์ค์ ํ์ฌ 'You Win'(๊ฒ์ ์ค๋ฒ ๋ฉ์์ง)์ ๊ณต๋ฐฑ์ผ๋ก ๋ง๋ญ๋๋ค.
winTextObject.SetActive(false);
}
void FixedUpdate()
{
// Vector3 ๋ณ์๋ฅผ ๋ง๋ค๊ณ X์ Z๋ฅผ ํ ๋นํ์ฌ ์์ horizontal ๋ฐ vertical ํ๋กํธ ๋ณ์๋ฅผ ๊ตฌํํฉ๋๋ค.
Vector3 movement = new Vector3(movementX, 0.0f, movementY);
rb.AddForce(movement * speed);
}
void OnTriggerEnter(Collider other)
{
// ๊ต์ฐจํ๋ ๊ฒ์ ์ค๋ธ์ ํธ์ 'Pick Up' ํ๊ทธ๊ฐ ํ ๋น๋์ด ์๋ ๊ฒฝ์ฐ
if (other.gameObject.CompareTag("PickUp"))
{
other.gameObject.SetActive(false);
// ์ ์ ๋ณ์ 'count'์ 1์ ์ถ๊ฐํฉ๋๋ค.
count = count + 1;
// 'SetCountText()' ํจ์๋ฅผ ์คํํฉ๋๋ค(์๋ ์ฐธ์กฐ).
SetCountText();
}
}
void OnMove(InputValue value)
{
Vector2 v = value.Get<Vector2>();
movementX = v.x;
movementY = v.y;
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 12)
{
// 'winText'์ ํ
์คํธ ๊ฐ์ ์ค์ ํฉ๋๋ค.
winTextObject.SetActive(true);
}
}
}
๐งก Rotator
์ ์ ์ญํ ์ ํ๋ ๋
ธ๋์ ์ค๋ธ์ ํธ์ ์ ๋๋ฉ์ด์
์ ์ฃผ๋ ์ญํ ์ด๋ค. ์ด๋ Prefab
์ด๋ผ๋ ๋ณต์ (์ปจํธ๋กค ํ์) ๊ธฐ๋ฅ์ ์ด์ฉํด ์ฌ๋ฌ๊ฐ์ ์ค๋ธ์ ํธ๋ฅผ ํ๋ฒ์ ์กฐ์ ํ ์ ์๋ค.
using UnityEngine;
using System.Collections;
public class Rotator : MonoBehaviour
{
// ๊ฐ ํ๋ ์์ ๋ ๋๋งํ๊ธฐ ์ ์
void Update()
{
// ์ด ์คํฌ๋ฆฝํธ๊ฐ ์ฐ๊ฒฐ๋ ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ X์ถ์ผ๋ก 15๋,
// Y์ถ์ผ๋ก 30๋, Z์ถ์ผ๋ก 45๋ ํ์ ํ๊ณ deltaTime ๊ฐ์ ๊ณฑํ๋ฉด
// ํ๋ ์์ด ์๋ ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์ ํฉ๋๋ค.
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
}
๐ค ๊ฐ์ธ์ ์๊ฐ
- ์ ์๋ฅผ ์นด์ดํธํ์ฌ UI TEXT๋ฅผ ์กฐ์ํ๋ ๋ถ๋ถ์ ์๋ก์ด Script์ Asset์๊ฒ ํ ๋นํด์ฃผ๋ ๊ฒ์ด ๊น๋ํ๋ค. Asset์ invisibleํ๊ฒ ๋ง๋ค ์ ์์ผ๋ฏ๋ก, ์ ๊ทน์ ์ผ๋ก ์ฌ์ฉํ์ฌ ์ญํ ์ ๋ถ๋ด์ํค๋ ๊ฒ์ด ํจ์จ์ ์ด๋ค.
- ์ด๋ฒ์ ๊ตฌํํ CameraController์ ๊ธฐ๋ฅ(3์ธ์นญ์ผ๋ก Player ๋ฐ๋ผ๋ค๋๊ธฐ)์ ์ ๋ง ๋ง์ด ์ฐ์ด๋ฏ๋ก ๊ธฐ์ตํด๋๋ฉด ์ ์ฉํ ๋ฏ ํ๋ค.
โค ์คํ ํ๋ฉด ๋ฐ ๊นํ๋ธ ๋งํฌ