์คํฌ๋ฆฝํธ ํ์ผ์๋ ๊ฒ์์ ๋ก์ง, ์ค๋ธ์ ํธ์ ๋์, ์ ๋ ฅ ์ฒ๋ฆฌ ๋ฑ์ ์ ์ํ๋ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
MonoBehaviour๋ฅผ ์์๋ฐ์ ํด๋์ค๋ฅผ ์์ฑํ๋ค. ์ด ํด๋์ค๋ ์ ๋ํฐ์ ๊ฒ์ ์ค๋ธ์ ํธ์ ์ฐ๊ฒฐ๋ ์คํฌ๋ฆฝํธ๋ก ๋์ํ๋ค.
ํ์ํ ๋ณ์, ํจ์, ์ด๋ฒคํธ ๋ฑ์ ์ ์ํ๊ณ ๊ตฌํํ๋ค. ๊ฒ์์ ๋์์ ์ํ ๋ก์ง์ ์์ฑํ๋ค.
ํ์ํ Unityํจ์๋ค์ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ ์ํ๋ ๋์์ ๊ตฌํํ ์ ์๋ค. ์๋ฅผ ๋ค์ด, Start()
, Update()
, FixedUpdate()
๋ฑ์ ํ์ฉํ ์ ์๋ค.
ํ์์ ๋ฐ๋ผ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ Unity์ ์ปดํฌ๋ํธ์ ์ํธ์์ฉํ๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค.
๊ฒ์ ์ค๋ธ์ ํธ์ ์๋ช ์ฃผ๊ธฐ ๋์ ํธ์ถ๋๋ ํน์ ํ ๋ฉ์๋๋ค์ ์์์ ํ์ด๋ฐ
๊ฒ์ ์ค๋ธ์ ํธ์ ์์ฑ, ์ด๊ธฐํ, ์ ๋ฐ์ดํธ, ํ๊ดด ๋ฑ๊ณผ ๊ด๋ จ๋ ์์ ์ ์ํ
Awake : ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ์์ฑ๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋. ์ฃผ๋ก ์ด๊ธฐํ ์์ ์ด ์ํ๋๋ค.
Start : ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ํ์ฑํ๋์ด ๊ฒ์ ๋ฃจํ๊ฐ ์์๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋. ์ด๊ธฐ ์ค์ ๋ฐ ์์ ์์ ์ ์ํํ๋ค.
Update : ๋งค ํ๋ ์๋ง๋ค ํธ์ถ๋๋ ๋ฉ์๋. ๊ฒ์ ๋ก์ง์ ์ฃผ์ ์ ๋ฐ์ดํธ๊ฐ ์ด๋ฃจ์ด์ง๋ค.
FixedUpdate : ๋ฌผ๋ฆฌ ์์ง ์ ๋ฐ์ดํธ ์ ํธ์ถ๋๋ ๋ฉ์๋. ๋ฌผ๋ฆฌ์ ์ธ ์๋ฎฌ๋ ์ด์ ์ ๊ด๋ จ๋ ์์ ์ ์ฒ๋ฆฌํ ๋ ์ฌ์ฉ๋๋ค.
LateUpdate : Update๋ฉ์๋ ํธ์ถ ์ดํ์ ํธ์ถ๋๋ ๋ฉ์๋. ๋ค๋ฅธ ์ค๋ธ์ ํธ์ ์ ๋ฐ์ดํธ๊ฐ ์๋ฃ๋ ํ์ ์์ ์ ์ํํ๋ ๋ฐ ์ ์ฉํ๋ค.
OnEnable : ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ํ์ฑํ๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋.
OnDisable : ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ๋นํ์ฑํ๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋
OnDestory : ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ํ๊ดด๋ ๋ ํธ์ถ๋๋ ๋ฉ์๋. ์์ ์ ๋ฆฌ ๋ฐ ํด์ ์์
์ด ์ํ๋๋ค.
์ด๋ฒคํธ ํจ์์ ์คํ ์์ ๋งํฌ
๊ฒ์ ์ค๋ธ์ ํธ์ ๋ถ์ฐฉ๋๋ ๋ ๋ฆฝ์ ์ธ ๊ธฐ๋ฅ ๋ชจ๋
๊ฐ ์ปดํฌ๋ํธ๋ ํน์ ํ ์์ ์ ์ํํ๊ฑฐ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ญํ
์ปดํฌ๋ํธ๋ค์ ๊ฒ์ ์ค๋ธ์ ํธ์ ์ถ๊ฐํ๊ณ ๊ตฌ์ฑํจ์ผ๋ก์จ ๊ฒ์์ ๋์๊ณผ ํน์ง์ ๊ฒฐ์
Transform :
๊ฒ์ ์ค๋ธ์ ํธ์ ์์น, ํ์ , ํฌ๊ธฐ ๋ฑ์ ์กฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
Rigidbody :
๋ฌผ๋ฆฌ์ ์ธ ํจ๊ณผ๋ฅผ ๊ฒ์ ์ค๋ธ์ ํธ์ ์ ์ฉํ ์ ์๊ฒ ํด์ค๋ค.
Collider :
์ถฉ๋ ๊ฐ์ง๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ
SpriteRenderer :
2D๊ทธ๋ํฝ์ ํ์ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
AudioSource :
์ฌ์ด๋๋ฅผ ์ฌ์ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ
์ฌ์ฉ์๊ฐ ํ์์ ๋ฐ๋ผ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ์์ฑํ๊ณ ์ถ๊ฐํ ์๋ ์๋ค. ์ด๋ฅผ ํตํด ๊ฒ์์ ํน์ ํ ๋์์ด๋ ๊ธฐ๋ฅ์ ๊ฐ๋ฐ์๊ฐ ์ํ๋ ๋๋ก ์ปค์คํฐ๋ง์ด์ฆ
Pixels Per Unit (PPU) :
์คํ๋ผ์ดํธ์ ํฝ์
์์ ํด๋น ์คํ๋ผ์ดํธ๊ฐ ๊ฒ์ ์ธ๊ณ์์ ์ฐจ์งํ๋ ๊ณต๊ฐ์ ๊ด๊ณ๋ฅผ ์ค๋ช
ํ๋ค. ์๋ฅผ ๋ค์ด, PPU๊ฐ 100์ด๋ผ๋ฉด ์คํ๋ผ์ดํธ์ 100ํฝ์
์ ๊ฒ์ ์ธ๊ณ์์ 1์ ๋ํฐ ๋จ์๋ฅผ ๋ํ๋ธ๋ค.
์คํ๋ผ์ดํธ์ ํฌ๊ธฐ :
PPU๊ฐ์ด ํด์๋ก ์คํ๋ผ์ดํธ๋ ์์์ง๋ค. ์ด๋ ๋ ๋ง์ ํฝ์
์ด ๋์ผํ ๊ฒ์ ์ธ๊ณ์ ๊ณต๊ฐ์ ๋งคํ๋๊ธฐ ๋๋ฌธ์ด๋ค.
1๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ :1 PPU๊ฐ์ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์ ์ํฅ์ ๋ฏธ์น๋ค. ๋์ PPU๊ฐ์ ๋ ์์ ์คํ๋ผ์ดํธ๋ฅผ ์์ฑํ๋ฏ๋ก, ์ด๋ ๋ ๋์ ํด์๋์ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
ํผํฌ๋จผ์ค :
๋์ PPU๊ฐ์ ๋ ๋ง์ ์ฐ์ฐ์ ํ์๋ก ํ๋ค. ์ด๋ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์๋ค. ๋ฐ๋ผ์, ํ์ํ ๋งํผ์ PPU๊ฐ์ ์ค์ ํ๋ ๊ฒ์ด ์ค์ํ๋ค.
์ผ๊ด์ฑ :
๋ชจ๋ ์คํ๋ผ์ดํธ์ ๋ํด ์ผ๊ด๋ PPU๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. ์ด๋ ์คํ๋ผ์ดํธ๊ฐ์ ํฌ๊ธฐ ๋น์จ์ ์ผ์ ํ๊ฒ ์ ์งํ๊ณ , ๋ฌผ๋ฆฌ์ ํ๋์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋๋ค.
๊ฐ ๊ฒ์ ์ค๋ธ์ ํธ๋ Transform์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ง๋ค.
Transform์ปดํฌ๋ํธ๋ ๊ฒ์ ์ค๋ธ์ ํธ์ ์์น, ํ์ , ๋ฐ ํฌ๊ธฐ(Scale)๋ฅผ ์ ์ํ๋ค.
๊ฒ์ ์ค๋ธ์ ํธ๋ ๋ค๋ฅธ ๊ฒ์ ์ค๋ธ์ ํธ์ '์์'์ด ๋ ์ ์๋ค.
๋ถ๋ชจ ๊ฒ์ ์ค๋ธ์ ํธ์ Transform์ด ๋ณ๊ฒฝ๋๋ฉด(์ : ์ด๋, ํ์ , ํฌ๊ธฐ ๋ณ๊ฒฝ), ๊ทธ ์์ ์ค๋ธ์ ํธ ๋ค์ Transform๋ ๋์ผํ๊ฒ ์ ์ฉ๋๋ค.
์ด๋ ๊ฒ, ๊ฒ์ ์ค๋ธ์ ํธ๋ค ์ฌ์ด์ ๊ณ์ธต์ ์ธ ๊ด๊ณ๊ฐ ํ์ฑ๋๊ณ ์ด๋ฅผ 'ํธ๋ฆฌ ๊ตฌ์กฐ' ๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.
์ด ๊ตฌ์กฐ๋ ๋ณต์กํ ์ฌ์ ๊ตฌ์ฑํ๊ณ ๊ด๋ฆฌํ๋๋ฐ ์ ์ฉํ๋ค. ์๋ฅผ ๋ค์ด, ์ฐจ๋ ๊ฒ์ ์ค๋ธ์ ํธ ๋ด๋ถ์ ๊ฐ๊ฐ์ ๋ถํ(๋ฐํด, ํธ๋ค ๋ฑ)์ ์์ ๊ฒ์ ์ค๋ธ์ ํธ๋ก ๋๋ฉด, ์ฐจ๋์ Transform์ด ๋ณ๊ฒฝ๋ ๋ ๊ฐ ๋ถํ๋ค๋ ํจ๊ป ์์ง์ธ๋ค.
์๋ ์ขํ๊ณ(World Coordinate System) :
์๋ ์ขํ๊ณ๋ ๊ฒ์ ์ธ๊ณ์ ์ ์ฒด์ ์ธ ์ฐธ์กฐ ํ๋ ์์ ์ ๊ณตํ๋ค. ์ด๋ ๋ชจ๋ ๊ฒ์ ์ค๋ธ์ ํธ๊ฐ ๊ณต์ ํ๋ฉฐ, ์๋ ์ขํ๊ณ์์์ ์์น๋ ๊ฒ์ ํ๊ฒฝ ๋ด์์ ์ค๋ธ์ ํธ์ ์ ๋์ ์ธ ์์น๋ฅผ ๋ํ๋ธ๋ค. ์๋ ์ขํ๊ณ๋ ๋ณํ์ง ์๊ณ ์ผ์ ํ๊ฒ ์ ์ง๋๋ค.
๋ก์ปฌ ์ขํ๊ณ(Local Coordinate System) :
๋ก์ปฌ ์ขํ๊ณ๋ ๊ฐ๋ณ ๊ฒ์ ์ค๋ธ์ ํธ์ ๋ํ ์ฐธ์กฐ ํ๋ ์์ ์ ๊ณตํ๋ค. ์ค๋ธ์ ํธ์ ๋ก์ปฌ ์ขํ๊ณ๋ ํด๋น ์ค๋ธ์ ํธ์ ์์น, ํ์ , ํฌ๊ธฐ(scale)์ ๋ฐ๋ผ ๋ณํํ๋ค. ์ด ์ขํ๊ณ๋ ํนํ ๋ถ๋ชจ-์์ ๊ด๊ณ์ ์๋ ์ค๋ธ์ ํธ๋ค ์ฌ์ด์์ ์ค์ํ๋ค. ์์ ์ค๋ธ์ ํธ์ ๋ก์ปฌ ์ขํ๋ ๋ถ๋ชจ ์ค๋ธ์ ํธ์ ๋ํ ์๋์ ์ธ ์์น๋ฅผ ๋ํ๋ด๋ฉฐ, ๋ถ๋ชจ ์ค๋ธ์ ํธ๊ฐ ์์ง์ด๋ฉด ๊ทธ์ ๋ฐ๋ผ ์์ ์ค๋ธ์ ํธ์ ์๋ ์ขํ๋ ๋ณํํ๊ฒ ๋๋ค.
input.GetAxis๋ ์ ๋ํฐ์ ์ ๋ ฅ ์์คํ ์์ ์ฌ์ฉ๋๋ ๋ฉ์๋์ด๋ค.
์ด ๋ฉ์๋๋ ์ ๋ ฅ ์ถ์ ๊ฐ์ ๋ฐํํ๋ค.
์ ๋ ฅ ์ถ์ ์ฃผ๋ก ํค๋ณด๋๋ ์กฐ์ด์คํฑ๊ณผ ๊ฐ์ ์ ๋ ฅ ์ฅ์น์ ์ ๋ ฅ์ ๋ํ๋ธ๋ค.
GetAxis ๋ฉ์๋๋ -1๋ถํฐ 1 ์ฌ์ด์ ๊ฐ์ ๋ฐํํ๋๋ฐ, ์ ๋ ฅ ์ฅ์น์ ์์ง์์ ๋ฐ๋ผ ํด๋น ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค.
๊ฐ์ด 0์ ๊ฐ๊น์ธ์๋ก ์ ๋ ฅ์ด ์๊ฑฐ๋ ์ค๋ฆฝ ์ํ๋ฅผ ๋ํ๋ด๋ฉฐ, ์์ ๊ฐ์ ์ ๋ฐฉํฅ ์ ๋ ฅ์, ์์ ๊ฐ์ ์ ๋ฐฉํฅ ์ ๋ ฅ์ ๋ํ๋ธ๋ค.
GetAxis ๋ฉ์๋๋ ์ฃผ๋ก ํ๋ ์ด์ด์ ์์ง์, ํ์ , ์ ํ ๋ฑ์ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์ํ ์ด๋์ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ, ์ข์ฐ ํ์ดํค์ ์ ๋ ฅ์ ๋ฐ๋ผ Input.GetAxis("Horizontal")์ ์ฌ์ฉํ์ฌ ์ข์ฐ ๋ฐฉํฅ์ ๊ฐ์ ์ป์ ์ ์๋ค.
์ด ๊ฐ์ ํ๋ ์ด์ด์ ์ด๋ ์๋๋ ํ์ ์๋์ ๊ฐ์ ๋ณ์์ ์ ์ฉํ์ฌ ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ ์ ์ดํ ์ ์๋ค.
์ด์ ํ๋ ์๋ถํฐ ํ์ฌ ํ๋ ์๊น์ง์ ๊ฒฝ๊ณผ ์๊ฐ์ ๋ํ๋ธ๋ค.
deltaTime์ ๊ฒ์์ ํ๋ ์ ์๋์ ์๊ด์์ด ์ผ์ ํ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ๋์ํ๋ ๊ฒ์์ ๋ง๋ค ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋๋ค.
์ฃผ๋ก ์์ง์, ์ ๋๋ฉ์ด์ , ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ๋ฑ์์ ์๊ฐ์ ๋ฐ๋ฅธ ๋ณํ๋ฅผ ์กฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
์๋ฅผ ๋ค์ด, transform.Translate(Vector3.forward speed Time.deltaTime)๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ํ๋ ์ ์๋์ ๊ด๊ณ์์ด speed๋งํผ์ ์ผ์ ํ ์ด๋ ์๋๋ฅผ ๋ณด์ฅํ ์ ์๋ค.
Time.deltaTime์ ์ด ๋จ์์ ๊ฐ์ ๋ฐํํ๋ฉฐ, 1์ด์ 1์ ๊ฐ๊น์ด ๊ฐ์ ๊ฐ์ง๋ค.
๊ฒ์์ ๋ก์ง์ด ๋งค ํ๋ ์๋ง๋ค ์ผ์ ํ ์๋๋ก ์คํ๋์ด์ผ ํ ๋, deltaTime์ ์ด์ฉํ์ฌ ์ด๋, ํ์ , ์ ๋๋ฉ์ด์ ๋ฑ์ ์ฐ์ฐ์ ์ผ์ ํ ์๊ฐ ๊ฐ๊ฒฉ์ ์ ์ฉํ ์ ์๋ค.
์ด๋ฅผ ํตํด ๊ฒ์์ด ์ผ์ ํ ์๋๋ก ๋์ํ๊ณ , ๋ค์ํ ๊ธฐ๊ธฐ๋ ํ๊ฒฝ์์๋ ์ผ๊ด๋ ๊ฒฝํ์ ์ ๊ณตํ ์ ์๋ค.
public
private
SerializeField
private
๋ก ์ ์ธ๋ ๋ณ์๋ฅผ ์ธ์คํํฐ์์ ์ง์ ์ ๊ทผprivate
๋ณ์๋ ์ธ์คํํฐ์ ํ์๋์ง ์์ง๋ง, SerializeField
๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ๋ณ์๊ฐ ์ธ์คํํฐ์์ ์์ ๊ฐ๋ฅํ ํ๋๋ก ํ์public class ExampleClass : MonoBehaviour
{
public int publicVariable;
private int privateVariable;
[SerializeField]
private int serializedFieldVariable;
private void Start()
{
publicVariable = 10; // ์ธ๋ถ์์ ์ ๊ทผ ๊ฐ๋ฅ
privateVariable = 20; // ํด๋์ค ๋ด๋ถ์์๋ง ์ ๊ทผ ๊ฐ๋ฅ
serializedFieldVariable = 30; // ์ธ์คํํฐ์์ ์ ๊ทผ ๊ฐ๋ฅ
}
}
New Input System์ ํต์ฌ ๊ฐ๋ ๋ค
- Input Action : ์ ๋ ฅ ํ๋์ ์ ์ํ๋ค. ์๋ฅผ ๋ค์ด "์ ํ", "๊ณต๊ฒฉ" ๋ฑ์ ํ๋์ ์ ์ํ๊ณ , ์ด๋ฌํ ํ๋์ ํธ๋ฆฌ๊ฑฐํ๋ ํค ๋ํ ๋ฒํผ์ ์ง์ ํ ์ ์๋ค.
- Input Action Asset : ์ฌ๋ฌ ๊ฐ์ ์ ๋ ฅ ํ๋์ ๊ทธ๋ฃนํํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์ด๋ฅผ ํตํด ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ ๋ ฅ ์ค์ ์ ๋ง๋ค์ด ๊ฒ์ ๋ด์ ๋ค๋ฅธ ์บ๋ฆญํฐ๋ ๋ฉ๋ด์ ์ ์ฉํ ์ ์๋ค.
- Player Input Component : Unity์ New Input System์ ์ถ๊ฐ๋ ์๋ก์ด ์ปดํฌ๋ํธ๋ก, ์๋์ผ๋ก ์ ๋ ฅ ํ๋์ ์ฒ๋ฆฌํ๊ณ ํด๋น ๊ฒ์ ์ค๋ธ์ ํธ์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ธ๋ค.
New Input System์ ์ฅ์
- Cross-Platform Compatibillity : New Input System์ ๋ค์ํ ํ๋ซํผ ์ ๋ ฅ ์ฅ์น์ ๋ํด ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก ์๋ํ๋ค.
- Rebinding : ํ๋ ์ด์ด๊ฐ ๊ฒ์ ๋ด์์ ์์ ์ ์ ๋ ฅ ์ค์ ์ ๋ณ๊ฒฝํ ์ ์๋๋ก ์ง์ํ๋ค.
- Multiplayer Support : ์ฌ๋ฌ ํ๋ ์ด์ด๊ฐ ๋์ผํ ์ฅ์น์์ ๊ฒ์์ ํ๋ ์ดํ๊ฑฐ๋, ๊ฐ๊ฐ์ ์ฅ์น์์ ๊ฒ์์ ํ๋ ์ดํ ๋ ์ ๋ ฅ์ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TopDownCharacterController : MonoBehaviour
{
// evnet : ์ธ๋ถ์์ ํธ์ถํ์ง ๋ชปํ๊ฒ ๋ง์
public event Action<Vector2> OnMoveEvent;
public event Action<Vector2> OnLookEvent;
public void CallMoveEvent(Vector2 direction)
{
// OnMoveEvent๊ฐ Null์ด ์๋๋ผ๋ฉด?. ์คํ(Invoke)
OnMoveEvent?.Invoke(direction);
}
public void CallLookEvent(Vector2 direction)
{
OnLookEvent?.Invoke(direction);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerInputController : TopDownCharacterController
{
private Camera _camera;
private void Awake()
{
// ์นด๋ฉ๋ผ์ ํด๋์ค์์ ๋ฉ์ธ์ด๋? ์ง๊ธ ์ด ์ฌ์ ์กด์ฌํ๋ ํ๊ทธ๊ฐ ๋ฉ์ธ์นด๋ฉ๋ผ์ธ ์๋ฅผ ์ฐพ์์จ๋ค.
_camera = Camera.main;
}
// SendMessage๋ฐฉ์ Move, Look, Fire ๋ผ๋ 3๊ฐ์ง Action์ ๋ง๋ค์ด๋จ๋๋ฐ ๊ทธ ์์๋ค On์ ๋ถ์ด๋ฉด ๊ทธ ์ ๋ค์ด ์คํ๋์ ๋ ๋๋ ค๋ฐ๋ ํจ์๋ฅผ ๋ง๋ค์ด ์ฃผ๋ ๊ฒ ์ด๋ค.
public void OnMove(InputValue value)
{
// Debug.Log("OnMove" + value.ToString());
Vector2 moveInput = value.Get<Vector2>().normalized;
CallMoveEvent(moveInput);
}
public void OnLook(InputValue value)
{
// Mouse์ ์ขํ ( Screen์์ ์ขํ )
Vector2 newAim = value.Get<Vector2>();
// Screen์ ์ขํ(newAim) -> World์ขํ๋ก ๋ณํ
Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
// ๋ฒกํฐ์์ ๋ฒกํฐ๋ฅผ ๋นผ๋ฉด ๊ทธ ๋ฒกํฐ๋ฅผ ํฅํ๋ ๋ฐฉํฅ,๊ฐ์ด ๋์จ๋ค.
newAim = (worldPos - (Vector2)transform.position).normalized;
// .magnitude๋ ๊ทธ ํ์ ์๋ฏธ ์์์ normalized๋ฅผ ํ๊ธฐ์ 1์ด ๋์ฌ๊ฑฐ๋ค.
if (newAim.magnitude >= .9f)
{
CallLookEvent(newAim);
}
}
public void OnFire(InputValue value)
{
Debug.Log("OnFire" + value.ToString());
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TopDownMovement : MonoBehaviour
{
private TopDownCharacterController _controller;
private Vector2 _movementDirection = Vector2.zero;
private Rigidbody2D _rigidbody;
private void Awake()
{
// Player์๊ฒ ๋ฌ๋ ค์๋ PlayerInputController.cs Component์ ์์ ๋ถ๋ชจ๊ฐ TopDownCharacterController
_controller = GetComponent<TopDownCharacterController>();
_rigidbody = GetComponent<Rigidbody2D>();
}
private void Start()
{
_controller.OnMoveEvent += Move;
}
private void FixedUpdate()
{
ApplyMovment(_movementDirection);
}
private void Move(Vector2 direction)
{
_movementDirection = direction;
}
private void ApplyMovment(Vector2 direction)
{
direction = direction * 5;
_rigidbody.velocity = direction;
}
}
์ด ๋ ์ปดํฌ๋ํธ๋ Unity์์ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ๊ณผ ์ถฉ๋ ๊ฐ์ง๋ฅผ ์ฒ๋ฆฌํ๋๋ฐ ํ์์ ์ด๋ค.
Collider
Rigidbody
Unity๋ OnCollisionEnter, OnCollisionStay, OnCollisionExit ๋ฑ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ๋ค.
์ด ์ด๋ฒคํธ๋ ์คํฌ๋ฆฝํธ์์ ์ฒ๋ฆฌํ์ฌ ์ํ๋ ๊ธฐ๋ฅ์ ์คํํ ์ ์๋ค.
์๋ฅผ ๋ค์ด, ์ค๋ธ์ ํธ๊ฐ ๋ ์ ๋ฟ์ผ๋ฉด ์ ํ ๊ฐ๋ฅ ์ํ๋ก ๋ณ๊ฒฝํ๊ฑฐ๋, ์ค๋ธ์ ํธ๊ฐ ํ๋ ์ด์ด์ ์ถฉ๋ํ๋ฉด ๋ฐ๋ฏธ์ง๋ฅผ ์ ํ๋ ๋ฑ์ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๋ค.
Unity์ Tilemap ์์คํ ์ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ํ์ผ ๊ธฐ๋ฐ์ ๊ฒ์ ํ๊ฒฝ์ ์ฝ๊ฒ ๋ง๋ค ์ ์๋ค. ์ด ์์คํ ์ ์ฌ์ฉํ๋ฉด ์์ ์คํ๋ผ์ดํธ๋ฅผ ํตํด ๊ด๋ํ ๊ฒ์ ํ๊ฒฝ์ ๊ตฌ์ฑํ ์ ์์ผ๋ฉฐ, ๋ณต์กํ ๊ฒ์ ๋ ๋ฒจ์ ์ฝ๊ฒ ๋์์ธํ๊ณ , ํธ์งํ๊ณ , ์กฐ์ํ ์ ์๋ค.
Tilemap GameObject
: Unity์ ํ์ผ๋งต ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. Tilemap Grid์ ์์์ผ๋ก ์์นํ๊ณ , ํน์ ํ์ผ์ ๋ฐฐ์น๋ฅผ ๊ด๋ฆฌํ๋ค.
Grid GameObject
: ๋ชจ๋ ํ์ผ๋งต์ด ์์นํ๋ ๊ธฐ๋ณธ ๊ฒฉ์๋ฅผ ๋ํ๋ธ๋ค.
Tilemap Renderer
: Tilemap์ ๋ชจ์์ ์ค์ ๋ก ๊ทธ๋ฆฌ๋ ์ญํ ์ ํ๋ค.
Tilemap Collider 2D
: ํ์ํ ๊ฒฝ์ฐ, Tilemap์ ๋ฌผ๋ฆฌ์ ์ธ ๊ฒฝ๊ณ๋ฅผ ์ถ๊ฐํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฒ์ ์บ๋ฆญํฐ๊ฐ ํ์ผ๋งต ํ๊ฒฝ๊ณผ ์ํธ์์ฉํ ์ ์๊ฒ ๋๋ค.
Tile Assets
: ๊ฐ๋ณ ํ์ผ์ ๋ชจ์๊ณผ ๋์์ ์ ์ํ๋ค. ์ฌ๋ฌ ๊ฐ์ ํ์ผ์ ๋ฌถ์ด์ Tileset์ด๋ผ๊ณ ๋ถ๋ฅด๊ธฐ๋ ํ๋ค.
4์ฐจ์ ๋ณต์์๋ฅผ ์ด์ฉํ ํ์ ํํ ๋ฐฉ๋ฒ. (x, y, z, w) ํํ๋ก ํํ๋๋ฉฐ, Unity์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค.
์ค์ผ๋ฌ ๊ฐ๋(Euler angles)๋ฅผ ์ฌ์ฉํ์ฌ ํ์ ์ ํํํ ๊ฒฝ์ฐ ๋ฐ์ํ๋ ์ง๋ฒ ๋ฝ(Gimbal Lock) ๋ฌธ์ ๋ฅผ ํผํ ์ ์๋ค.
์ง๊ด์ ์ด์ง ์๊ณ ๋ณต์กํด ๋ณด์ผ ์ ์์ง๋ง, Unity์์๋ ์ฟผํฐ๋์ธ์ ์ฌ์ฉํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด์ก๋ค.
์ง์ ๊ฐ์ ๋ณ๊ฒฝํ๊ฑฐ๋ ๊ณ์ฐํ๋ ๋์ , Unity์ ๋ด์ฅ ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. (์ : Quaternion.Euler, Quaternion.LookRotation, Quaternion.Slerp ๋ฑ).
์ฟผํฐ๋์ธ์ ์ผ๋ฐ์ ์ผ๋ก "์ ๊ทํ(nomalized)"๋์ด์ผ ํ๋๋ฐ, Unity์์๋ ์ด๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ค. ํ์ง๋ง ์ง์ ๊ณ์ฐ์ ํ ๋๋ ์ ๊ทํ์ ์ฃผ์ํด์ผ ํ๋ค.
์ํฌํ์ ํธ ํจ์๋ ์ผ๊ฐํจ์์ ์ญํจ์์ด๋ค. ํน์ ๋น์จ์ ๋ํ ๊ฐ๋๋ฅผ ๊ณ์ฐํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
2์ฐจ์ ๊ณต๊ฐ์์ ์ ๋๋ ๋ฒกํฐ์ ๋ํ ๊ฐ๋๋ฅผ ์ฐพ๋ ๋ฐ ์ํฌํ์ ํธ ํจ์๊ฐ ์ข ์ข ์ฌ์ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ฒกํฐ(x,y)์ ๊ฒฝ์ฐ, Math.Atan2(y,x) ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒกํฐ๊ฐ x์ถ๊ณผ ์ด๋ฃจ๋ ๊ฐ๋๋ฅผ ๋ผ๋์์ผ๋ก ์ป์ ์ ์๋ค.
์ํฌํ์ ํธ ํจ์๋ ์ฌ์ธ(sine)๊ณผ ์ฝ์ฌ์ธ(cosine)ํจ์๋ฅผ ์ด์ฉํ์ฌ ์ง๊ฐ ์ผ๊ฐํ์์ ๋น๋ณ์ ๊ฐ๋๋ฅผ ๊ณ์ฐํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์๋ค.
์ด ๊ธฐ๋ฅ์ ๊ฒ์ ๊ฐ๋ฐ์์ ๋ง์ด ์ฌ์ฉ๋๋ฉฐ, ํนํ ๊ฐ์ฒด๊ฐ ํน์ ๋ฐฉํฅ์ ํฅํ๋๋ก ๋ง๋ค๊ฑฐ๋ ๋ ์ ์ฌ์ด์ ๊ฐ๋๋ฅผ ๊ณ์ฐํ ๋ ์ ์ฉํ๋ค.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TopDownAimRotation : MonoBehaviour
{
[SerializeField] private SpriteRenderer armRenderer;
[SerializeField] private Transform armPivot;
[SerializeField] private SpriteRenderer characterRenderer;
private TopDownCharacterController _controller;
private void Awake()
{
_controller = GetComponent<TopDownCharacterController>();
}
void Start()
{
_controller.OnLookEvent += OnAim;
}
public void OnAim(Vector2 newAimDirection)
{
RotateArm(newAimDirection);
}
private void RotateArm(Vector2 direction)
{
// Mathf.Atan2 (์ํฌํ์ ํธ๋ฅผ ๊ตฌํ๋ ๋ฉ์๋) : ์ด๋ค ๋ฒกํฐ์ y, x๋ฅผ ๊ฐ์ง๊ณ ์ํฌํ์ ํธ๋ฅด ํ๋ฉด ๊ทธ ์ฌ์ด์ ์ธํ๊ฐ์ด ๋์จ๋ค. ( ๋ฒกํฐ์ ๊ฐ๋๋ฅผ ๊ตฌ๋ ๊ฒ )
// Mathf.Atan2(direction.y, direction.x) ๋ฅผ ํ์ฌ "์ธํ"๊ฐ์ด ๋์ค๋ฉด "ํ์ด๊ฐ. ๋ผ๋์ ๊ฐ์ด ๋์จ๋ค.(0 ~ 3.14)"
// ๊ทธ ๋ผ๋์๊ฐ์ ๋๊ทธ๋ฆฌ๊ฐ(0 ~ 180๋) ์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ ๊ฐ(Mathf.Rad2Deg)์ ๊ณฑํด์ค๋ค.
float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
// flipY : SpriteRendererํด๋์ค๊ฐ ์ ๊ณตํ๋ Y์ถ์ ๊ธฐ์ค์ผ๋ก ๋ค์ง๋ ์ฝ๋
// (X์ถ์ด ๊ธฐ์ค) ์ ๋๊ฐ 90๋๋ฅผ ๊ธฐ์ค์ผ๋ก ๋์ด๊ฐ๋ฉด ๋ฌด๊ธฐ๋ ์์๋ ์ ํ(flip.Y), ์บ๋ฆญํฐ๋ ์ค๋ฅธ์ชฝ์ผ์ชฝ ์ ํ(flip.X)
armRenderer.flipY = Mathf.Abs(rotZ) > 90f;
characterRenderer.flipX = armRenderer.flipY;
// Rotation์ด๋ผ๋ ํ์ ๊ฐ์ Quaternion์ด๋ผ๋ 4์์ ๊ฐ์ ์ด๋ค. ๊ทธ๋์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ์๋ ์ด๋ ต๋ค.
// ๊ทธ๋์ ์ฐ๊ธฐ์ฌ์ด ๋๊ทธ๋ฆฌ๊ณ๋(0 ~ 360๋) ๋ผ๋์๊ฐ์ด ์๋ ๋๊ทธ๋ฆฌ๋๋ฅผ ์ฌ์ฉํ๋ ์๋ก ๋ง๋ค์ด์ค
// rotZ๋ Euler๊ฐ๋์ด๋ค.
armPivot.rotation = Quaternion.Euler(0, 0, rotZ);
}
}
ํ๋ฆฌํน์ Unity ๊ฒ์ ์์ง์์ ์ฌ์ฉ๋๋ ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค๊ธฐ ์ํ ํ ํ๋ฆฟ์ด๋ค.
ํ๋ฆฌํน์ ์ฌ์ฉํ๋ฉด ๊ฒ์ ์ค๋ธ์ ํธ์ ๊ทธ์ ๊ด๋ จ๋ ์ปดํฌ๋ํธ ๋ฐ ์ค์ ์ ๋ฏธ๋ฆฌ ์ ์ํ๊ณ , ์ฌ๋ฌ ์ฅ๋ฉด์ด๋ ๊ฒ์์์ ์ฌ์ฌ์ฉํ ์ ์๋ค.
ํ๋ฆฌํน์ ์ธ์คํด์คํ๋ฅผ ํตํด ์ค์ ๊ฒ์ ์ค๋ธ์ ํธ๋ก ๋ณํ๋ ์ ์์ผ๋ฉฐ, ์ด ๋ ๋ชจ๋ ํ๋กํผํฐ์ ์ปดํฌ๋ํธ ์ค์ ์ด ๋ณต์ฌ๋๋ค.
ํ๋ฆฌํน์ ๋ณ๊ฒฝ์ฌํญ์ ๋ชจ๋ ์ธ์คํด์ค์ ์ฆ์ ๋ฐ์๋๋ฏ๋ก, ์ผ๊ด์ฑ์ ์ ์งํ๊ณ ์ผ๊ด์ ์ธ ์ ๋ฐ์ดํธ๋ฅผ ์ฝ๊ฒ ํ ์ ์๋ค.
ํ๋ฆฌํน์ ๋ ๋ฒจ ๋์์ธ, ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒ์ ์์(์บ๋ฆญํฐ, ์์ดํ , ์ฅ์ ๋ฌผ ๋ฑ)์ ์์ฑ, ํ๋กํ ํ์ดํ ๋ฑ์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค.
Instantiateํจ์๋ Unity์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ก, ์ฃผ์ด์ง ์๋ณธ ๊ฐ์ฒด์ ๋ณต์ฌ๋ณธ์ ์๋ก ์์ฑํ๊ณ ์ด๋ฅผ ๋ฐํํ๋ค.
์ด ํจ์๋ ์ฃผ๋ก ๊ฒ์ ์ค๋ธ์ ํธ, ์ฆ ์บ๋ฆญํฐ, ์์ดํ , ํ๋ก์ ํ์ผ ๋ฑ์ ๋์ ์ผ๋ก ๊ฒ์ ์ธ๊ณ์ ์ถ๊ฐํ ๋ ์ฌ์ฉ๋๋ค.
Instantiateํจ์๋ ์๋ณธ ๊ฐ์ฒด์ ๋ชจ๋ ์ปดํฌ๋ํธ์ ๊ทธ ํ๋กํผํฐ๋ฅผ ๋ณต์ฌํ์ฌ ์ ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ ์์ฑํ๋ค.
์ด ํจ์๋ฅผ ํตํด ์์ฑ๋ ๊ฒ์ ์ค๋ธ์ ํธ๋ ๋ ๋ฆฝ์ ์ด๋ฉฐ, ์๋ณธ ๊ฐ์ฒด์ ๋ํ ๋ณํ๋ ์ด์ ์ํฅ์ ์ฃผ์ง ์๋๋ค.
Instantiateํจ์๋ ์๋ณธ ๊ฒ์ ์ค๋ธ์ ํธ, ์์น ๋ฐ ํ์ ์ ๋ณด๋ฅผ ์ธ์๋ก ๋ฐ์ ์ ์๋ค.
public void OnFire(InputValue value)
{
//Debug.Log("OnFire" + value.ToString());
IsAttacking = value.isPressed;
}
---------- ์๋ต ----------
public event Action OnAttackEvent;
private float _timeSinceLastAttack = float.MaxValue;
protected bool IsAttacking { get; set; }
protected virtual void Update()
{
HandleAttackDelay();
}
private void HandleAttackDelay()
{
if(_timeSinceLastAttack <= 0.2f) // TODO
{
_timeSinceLastAttack += Time.deltaTime;
}
if(IsAttacking && _timeSinceLastAttack > 0.2f)
{
_timeSinceLastAttack = 0;
CallAttackEvent();
}
}
---------- ์๋ต ----------
public void CallAttackEvent()
{
OnAttackEvent?.Invoke();
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TopDownShooting : MonoBehaviour
{
private TopDownCharacterController _contoller;
[SerializeField] private Transform projectileSpawnPosition;
private Vector2 _aimDirection = Vector2.right;
public GameObject testPrefab;
private void Awake()
{
_contoller = GetComponent<TopDownCharacterController>();
}
// Start is called before the first frame update
void Start()
{
_contoller.OnAttackEvent += OnShoot;
_contoller.OnLookEvent += OnAim;
}
private void OnAim(Vector2 newAimDirection)
{
_aimDirection = newAimDirection;
}
private void OnShoot()
{
CreateProjectile();
}
private void CreateProjectile()
{
// IInstantiate(testPrefab, projectileSpawnPosition) = ์ง๊ธ ์ฌ์ฉํ๊ณ ์๋ ์ค๋ฒ๋ก๋๊ฐ ์ฒ์์๋ ์ค๋ฆฌ์ง๋ ๋๋ฒ์งธ๋ ๋ถ๋ชจ, ๋ด๊ฐ ์ง์ ํด์ค ํธ๋์คํผ ํ์ ์๋ค๊ฐ ์์ฑ์ ํ๊ฒ ๋ค๋ ๊ฒ์ด๋ค.
// ์ฆ, ํ์ด๋ผํค์ฐฝ์ ๊ฐ๋ณ๋ก ์์ฑ๋๋๊ฒ ์๋๋ผ ์ง์ ํด์ค ์ค๋ธ์ ํธ(projectileSpawnPosition)์ ํ์๋ก ์์ฑ์ด ๋๋ค.
// ๊ทธ๋์ ๋ฐ์์ฒ๋ผ position์ผ๋ก ์ง์ . ์ค๋ฆฌ์ง๋๊ณผ position๋ง ์ฌ์ฉํ ์๋ ์๊ธฐ์ Quaternion๋ ์ง์ ํด์ค์ผ ํ๋ค.
Instantiate(testPrefab, projectileSpawnPosition.position, Quaternion.identity); // Quaternion.identity = Vector.zero
}
}