Unity ์ž…๋ฌธ - 2

์ด์ค€ํ˜ธยท2023๋…„ 11์›” 27์ผ
0

๐Ÿ“Œ Unity ๊ฒŒ์ž„ ๊ฐœ๋ฐœ ์ž…๋ฌธ



๐Ÿ“Œ 1. ์ž…๋ ฅ๊ณผ ์บ๋ฆญํ„ฐ ์ด๋™

1) ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ•

์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์—๋Š” ๊ฒŒ์ž„์˜ ๋กœ์ง, ์˜ค๋ธŒ์ ํŠธ์˜ ๋™์ž‘, ์ž…๋ ฅ ์ฒ˜๋ฆฌ ๋“ฑ์„ ์ •์˜ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

โž” ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ•

  • MonoBehaviour๋ฅผ ์ƒ์†๋ฐ›์€ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์œ ๋‹ˆํ‹ฐ์˜ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์™€ ์—ฐ๊ฒฐ๋œ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋™์ž‘ํ•œ๋‹ค.

  • ํ•„์š”ํ•œ ๋ณ€์ˆ˜, ํ•จ์ˆ˜, ์ด๋ฒคํŠธ ๋“ฑ์„ ์ •์˜ํ•˜๊ณ  ๊ตฌํ˜„ํ•œ๋‹ค. ๊ฒŒ์ž„์˜ ๋™์ž‘์„ ์œ„ํ•œ ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค.

  • ํ•„์š”ํ•œ Unityํ•จ์ˆ˜๋“ค์€ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ์›ํ•˜๋Š” ๋™์ž‘์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Start(), Update(), FixedUpdate() ๋“ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํ•„์š”์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋‚˜ Unity์˜ ์ปดํฌ๋„ŒํŠธ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

โž” ์Šคํฌ๋ฆฝํŠธ ๋ผ์ดํ”„ ์‚ฌ์ดํด

  • ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์ƒ๋ช… ์ฃผ๊ธฐ ๋™์•ˆ ํ˜ธ์ถœ๋˜๋Š” ํŠน์ •ํ•œ ๋ฉ”์„œ๋“œ๋“ค์˜ ์ˆœ์„œ์™€ ํƒ€์ด๋ฐ

  • ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์ƒ์„ฑ, ์ดˆ๊ธฐํ™”, ์—…๋ฐ์ดํŠธ, ํŒŒ๊ดด ๋“ฑ๊ณผ ๊ด€๋ จ๋œ ์ž‘์—…์„ ์ˆ˜ํ–‰

  1. Awake : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ์ฃผ๋กœ ์ดˆ๊ธฐํ™” ์ž‘์—…์ด ์ˆ˜ํ–‰๋œ๋‹ค.

  2. Start : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ๊ฒŒ์ž„ ๋ฃจํ”„๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์‹œ์ž‘ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  3. Update : ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ๊ฒŒ์ž„ ๋กœ์ง์˜ ์ฃผ์š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค.

  4. FixedUpdate : ๋ฌผ๋ฆฌ ์—”์ง„ ์—…๋ฐ์ดํŠธ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ๋ฌผ๋ฆฌ์ ์ธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์— ๊ด€๋ จ๋œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

  5. LateUpdate : Update๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ดํ›„์— ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์˜ ์—…๋ฐ์ดํŠธ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„์— ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

  6. OnEnable : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ํ™œ์„ฑํ™”๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ.

  7. OnDisable : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ

  8. OnDestory : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ํŒŒ๊ดด๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ. ์ž์› ์ •๋ฆฌ ๋ฐ ํ•ด์ œ ์ž‘์—…์ด ์ˆ˜ํ–‰๋œ๋‹ค.

์ด๋ฒคํŠธ ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ˆœ์„œ ๋งํฌ

2) ์ปดํฌ๋„ŒํŠธ ์ดํ•ด

โž” ์œ ๋‹ˆํ‹ฐ์˜ ์ปดํฌ๋„ŒํŠธ ๋ฐฉ์‹

  • ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ๋ถ€์ฐฉ๋˜๋Š” ๋…๋ฆฝ์ ์ธ ๊ธฐ๋Šฅ ๋ชจ๋“ˆ

  • ๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ํŠน์ •ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ญํ• 

  • ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๊ณ  ๊ตฌ์„ฑํ•จ์œผ๋กœ์จ ๊ฒŒ์ž„์˜ ๋™์ž‘๊ณผ ํŠน์ง•์„ ๊ฒฐ์ •

โž” ๊ธฐ๋ณธ ์ปดํฌ๋„ŒํŠธ ์˜ˆ์‹œ

  • Transform : ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์œ„์น˜, ํšŒ์ „, ํฌ๊ธฐ ๋“ฑ์„ ์กฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

  • Rigidbody : ๋ฌผ๋ฆฌ์ ์ธ ํšจ๊ณผ๋ฅผ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

  • Collider : ์ถฉ๋Œ ๊ฐ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ

  • SpriteRenderer : 2D๊ทธ๋ž˜ํ”ฝ์„ ํ‘œ์‹œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

  • AudioSource : ์‚ฌ์šด๋“œ๋ฅผ ์žฌ์ƒํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ

  • ์‚ฌ์šฉ์ž๊ฐ€ ํ•„์š”์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ณ  ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฒŒ์ž„์˜ ํŠน์ •ํ•œ ๋™์ž‘์ด๋‚˜ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆ

3) ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์†Œ๊ฐœ

โž” Pixels Per Unit (PPU)

  • Pixels Per Unit (PPU) : ์Šคํ”„๋ผ์ดํŠธ์˜ ํ”ฝ์…€ ์ˆ˜์™€ ํ•ด๋‹น ์Šคํ”„๋ผ์ดํŠธ๊ฐ€ ๊ฒŒ์ž„ ์„ธ๊ณ„์—์„œ ์ฐจ์ง€ํ•˜๋Š” ๊ณต๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์„ค๋ช…ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, PPU๊ฐ€ 100์ด๋ผ๋ฉด ์Šคํ”„๋ผ์ดํŠธ์˜ 100ํ”ฝ์…€์€ ๊ฒŒ์ž„ ์„ธ๊ณ„์—์„œ 1์œ ๋‹ˆํ‹ฐ ๋‹จ์œ„๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • ์Šคํ”„๋ผ์ดํŠธ์˜ ํฌ๊ธฐ : PPU๊ฐ’์ด ํด์ˆ˜๋ก ์Šคํ”„๋ผ์ดํŠธ๋Š” ์ž‘์•„์ง„๋‹ค. ์ด๋Š” ๋” ๋งŽ์€ ํ”ฝ์…€์ด ๋™์ผํ•œ ๊ฒŒ์ž„ ์„ธ๊ณ„์˜ ๊ณต๊ฐ„์— ๋งคํ•‘๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • 1๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ :1 PPU๊ฐ’์€ ๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. ๋†’์€ PPU๊ฐ’์€ ๋” ์ž‘์€ ์Šคํ”„๋ผ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, ์ด๋Š” ๋” ๋†’์€ ํ•ด์ƒ๋„์˜ ๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

  • ํผํฌ๋จผ์Šค : ๋†’์€ PPU๊ฐ’์€ ๋” ๋งŽ์€ ์—ฐ์‚ฐ์„ ํ•„์š”๋กœ ํ•œ๋‹ค. ์ด๋Š” ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ, ํ•„์š”ํ•œ ๋งŒํผ์˜ PPU๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

  • ์ผ๊ด€์„ฑ : ๋ชจ๋“  ์Šคํ”„๋ผ์ดํŠธ์— ๋Œ€ํ•ด ์ผ๊ด€๋œ PPU๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋Š” ์Šคํ”„๋ผ์ดํŠธ๊ฐ„์˜ ํฌ๊ธฐ ๋น„์œจ์„ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ , ๋ฌผ๋ฆฌ์  ํ–‰๋™์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

โž” ๊ณ„์ธต ๊ตฌ์กฐ (Transform ๊ตฌ์กฐ)

  • ๊ฐ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” Transform์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ง„๋‹ค.

  • Transform์ปดํฌ๋„ŒํŠธ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์œ„์น˜, ํšŒ์ „, ๋ฐ ํฌ๊ธฐ(Scale)๋ฅผ ์ •์˜ํ•œ๋‹ค.

  • ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” ๋‹ค๋ฅธ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ '์ž์‹'์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

  • ๋ถ€๋ชจ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ Transform์ด ๋ณ€๊ฒฝ๋˜๋ฉด(์˜ˆ : ์ด๋™, ํšŒ์ „, ํฌ๊ธฐ ๋ณ€๊ฒฝ), ๊ทธ ์ž์‹ ์˜ค๋ธŒ์ ํŠธ ๋“ค์˜ Transform๋„ ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋œ๋‹ค.

  • ์ด๋ ‡๊ฒŒ, ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋“ค ์‚ฌ์ด์— ๊ณ„์ธต์ ์ธ ๊ด€๊ณ„๊ฐ€ ํ˜•์„ฑ๋˜๊ณ  ์ด๋ฅผ 'ํŠธ๋ฆฌ ๊ตฌ์กฐ' ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

  • ์ด ๊ตฌ์กฐ๋Š” ๋ณต์žกํ•œ ์”ฌ์„ ๊ตฌ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ์œ ์šฉํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ฐจ๋Ÿ‰ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ๋‚ด๋ถ€์— ๊ฐ๊ฐ์˜ ๋ถ€ํ’ˆ(๋ฐ”ํ€ด, ํ•ธ๋“ค ๋“ฑ)์„ ์ž์‹ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋กœ ๋‘๋ฉด, ์ฐจ๋Ÿ‰์˜ Transform์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๊ฐ ๋ถ€ํ’ˆ๋“ค๋„ ํ•จ๊ป˜ ์›€์ง์ธ๋‹ค.

โž” ๋กœ์ปฌ ์ขŒํ‘œ๊ณ„(Local Coordinate System)์™€ ์›”๋“œ ์ขŒํ‘œ๊ณ„(World Coordinate System)

  • ์›”๋“œ ์ขŒํ‘œ๊ณ„(World Coordinate System) : ์›”๋“œ ์ขŒํ‘œ๊ณ„๋Š” ๊ฒŒ์ž„ ์„ธ๊ณ„์˜ ์ „์ฒด์ ์ธ ์ฐธ์กฐ ํ”„๋ ˆ์ž„์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ๋ชจ๋“  ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๊ณต์œ ํ•˜๋ฉฐ, ์›”๋“œ ์ขŒํ‘œ๊ณ„์—์„œ์˜ ์œ„์น˜๋Š” ๊ฒŒ์ž„ ํ™˜๊ฒฝ ๋‚ด์—์„œ ์˜ค๋ธŒ์ ํŠธ์˜ ์ ˆ๋Œ€์ ์ธ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์›”๋“œ ์ขŒํ‘œ๊ณ„๋Š” ๋ณ€ํ•˜์ง€ ์•Š๊ณ  ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€๋œ๋‹ค.

  • ๋กœ์ปฌ ์ขŒํ‘œ๊ณ„(Local Coordinate System) : ๋กœ์ปฌ ์ขŒํ‘œ๊ณ„๋Š” ๊ฐœ๋ณ„ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ๋Œ€ํ•œ ์ฐธ์กฐ ํ”„๋ ˆ์ž„์„ ์ œ๊ณตํ•œ๋‹ค. ์˜ค๋ธŒ์ ํŠธ์˜ ๋กœ์ปฌ ์ขŒํ‘œ๊ณ„๋Š” ํ•ด๋‹น ์˜ค๋ธŒ์ ํŠธ์˜ ์œ„์น˜, ํšŒ์ „, ํฌ๊ธฐ(scale)์— ๋”ฐ๋ผ ๋ณ€ํ™”ํ•œ๋‹ค. ์ด ์ขŒํ‘œ๊ณ„๋Š” ํŠนํžˆ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„์— ์ž‡๋Š” ์˜ค๋ธŒ์ ํŠธ๋“ค ์‚ฌ์ด์—์„œ ์ค‘์š”ํ•˜๋‹ค. ์ž์‹ ์˜ค๋ธŒ์ ํŠธ์˜ ๋กœ์ปฌ ์ขŒํ‘œ๋Š” ๋ถ€๋ชจ ์˜ค๋ธŒ์ ํŠธ์— ๋Œ€ํ•œ ์ƒ๋Œ€์ ์ธ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋ถ€๋ชจ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์›€์ง์ด๋ฉด ๊ทธ์— ๋”ฐ๋ผ ์ž์‹ ์˜ค๋ธŒ์ ํŠธ์˜ ์›”๋“œ ์ขŒํ‘œ๋„ ๋ณ€ํ™”ํ•˜๊ฒŒ ๋œ๋‹ค.

โž” Input.GetAxis

  • input.GetAxis๋Š” ์œ ๋‹ˆํ‹ฐ์˜ ์ž…๋ ฅ ์‹œ์Šคํ…œ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

  • ์ด ๋ฉ”์„œ๋“œ๋Š” ์ž…๋ ฅ ์ถ•์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • ์ž…๋ ฅ ์ถ•์€ ์ฃผ๋กœ ํ‚ค๋ณด๋“œ๋‚˜ ์กฐ์ด์Šคํ‹ฑ๊ณผ ๊ฐ™์€ ์ž…๋ ฅ ์žฅ์น˜์˜ ์ž…๋ ฅ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • GetAxis ๋ฉ”์„œ๋“œ๋Š” -1๋ถ€ํ„ฐ 1 ์‚ฌ์ด์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ์ž…๋ ฅ ์žฅ์น˜์˜ ์›€์ง์ž„์— ๋”ฐ๋ผ ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ๋‹ค.

  • ๊ฐ’์ด 0์— ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ์ž…๋ ฅ์ด ์—†๊ฑฐ๋‚˜ ์ค‘๋ฆฝ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์–‘์ˆ˜ ๊ฐ’์€ ์–‘ ๋ฐฉํ–ฅ ์ž…๋ ฅ์„, ์Œ์ˆ˜ ๊ฐ’์€ ์Œ ๋ฐฉํ–ฅ ์ž…๋ ฅ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • GetAxis ๋ฉ”์„œ๋“œ๋Š” ์ฃผ๋กœ ํ”Œ๋ ˆ์ด์–ด์˜ ์›€์ง์ž„, ํšŒ์ „, ์ ํ”„ ๋“ฑ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

  • ์˜ˆ๋ฅผ ๋“ค์–ด, ์ˆ˜ํ‰ ์ด๋™์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ, ์ขŒ์šฐ ํ™”์‚ดํ‚ค์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ Input.GetAxis("Horizontal")์„ ์‚ฌ์šฉํ•˜์—ฌ ์ขŒ์šฐ ๋ฐฉํ–ฅ์˜ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • ์ด ๊ฐ’์€ ํ”Œ๋ ˆ์ด์–ด์˜ ์ด๋™ ์†๋„๋‚˜ ํšŒ์ „ ์†๋„์™€ ๊ฐ™์€ ๋ณ€์ˆ˜์— ์ ์šฉํ•˜์—ฌ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

โž” Time.deltaTime

  • ์ด์ „ ํ”„๋ ˆ์ž„๋ถ€ํ„ฐ ํ˜„์žฌ ํ”„๋ ˆ์ž„๊นŒ์ง€์˜ ๊ฒฝ๊ณผ ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • 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

4) ์ž…๋ ฅ ๋ฐ›์„ ์ค€๋น„ (New Input System)

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 : ์—ฌ๋Ÿฌ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋™์ผํ•œ ์žฅ์น˜์—์„œ ๊ฒŒ์ž„์„ ํ”Œ๋ ˆ์ดํ•˜๊ฑฐ๋‚˜, ๊ฐ๊ฐ์˜ ์žฅ์น˜์—์„œ ๊ฒŒ์ž„์„ ํ”Œ๋ ˆ์ดํ•  ๋•Œ ์ž…๋ ฅ์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โž” Package ์ถ”๊ฐ€

  • Window โ†’ Package Manager โ†’ Unity Register โ†’ Input System โ†’ Install

โž” New Input System ์ค€๋น„

  • Create โ†’ Input Action ํด๋ฆญ โ†’ Top Down Controller 2D๋กœ ์ˆ˜์ •

โž” Input Action ์ˆ˜์ •

  • InputAction ๋”๋ธ”ํด๋ฆญ
  • No Control Schemes โ†’ Add Control Scheme
  • ์ด๋ฆ„ ์ˆ˜์ • โ†’ + ๋ฒ„ํŠผ โ†’ Keyboard ์™€ Mouse ์ถ”๊ฐ€
  • Action Maps โ†’ + โ†’ Player
  • Move Action ์ˆ˜์ • โ†’ Add Up Down Left Right Composite ์ถ”๊ฐ€ โ†’ WASD ์„ค์ •
  • Look Action ์ˆ˜์ •
  • Fire Action ์ˆ˜์ •

5) ํ”Œ๋ ˆ์ด์–ด ๋งŒ๋“ค๊ธฐ

โž” TopDownChacterController

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);
    }

}

โž” PlayerInputController

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());
    }
}

โž” TopDownMovement

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;
    }
}

โž” ํ”Œ๋ ˆ์ด์–ด ์˜ค๋ธŒ์ ํŠธ ๋งŒ๋“ค๊ธฐ






๐Ÿ“Œ 2. ์ถฉ๋Œ ์ฒ˜๋ฆฌ์™€ ๋งต ๊ตฌ์„ฑ

1) ์ถฉ๋Œ๊ณผ ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์ดํ•ด

โž” Unity์—์„œ ์ถฉ๋Œ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ค‘์š”ํ•œ ๊ฐœ๋…์€ Collider์™€ Rigidbody ์ปดํฌ๋„ŒํŠธ

์ด ๋‘ ์ปดํฌ๋„ŒํŠธ๋Š” Unity์—์„œ ๋ฌผ๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜๊ณผ ์ถฉ๋Œ ๊ฐ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ํ•„์ˆ˜์ ์ด๋‹ค.

  • Collider

    • Collider ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ๋ฌผ๋ฆฌ์ ์ธ ํ˜•ํƒœ๋ฅผ ๋ถ€์—ฌํ•œ๋‹ค. ์ด๋Š” ์ถฉ๋Œ ๊ฐ์ง€๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ Collider๊ฐ€ ์žˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด BoxCollider๋Š” ์‚ฌ๊ฐํ˜•, SphereCollider๋Š” ์›ํ˜•, MeshCollider๋Š” ๋ณต์žกํ•œ ๋ฉ”์‹œ ํ˜•ํƒœ์˜ Collider๋ฅผ ์ œ๊ณตํ•œ๋‹ค. Collider๋Š” ์ž์ฒด์ ์œผ๋กœ ๋ฌผ๋ฆฌ์ ์ธ ์›€์ง์ž„์„ ์ œ์–ดํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Rigidbody
    • Rigidbody์ปดํฌ๋„ŒํŠธ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ๋ฌผ๋ฆฌ ๋ฒ•์น™์„ ์ ์šฉํ•œ๋‹ค. Rigidbody๊ฐ€ ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ๋Š” ์ค‘๋ ฅ์— ์˜ํ–ฅ์„ ๋ฐ›๊ณ , ํž˜๊ณผ ํ† ํฌ๋ฅผ ํ†ตํ•ด ์›€์ง์ผ ์ˆ˜ ์žˆ๋‹ค.
    • ๋˜ํ•œ Rigidbody๊ฐ€ ๋ถ€์ฐฉ๋œ ์˜ค๋ธŒ์ ํŠธ๋Š” ๋‹ค๋ฅธ Rigidbody๋‚˜ Collider์™€ ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ๋‹ค.

โž” ์ถฉ๋Œ ๋ฐœ์ƒ ์‹œ

  • Unity๋Š” OnCollisionEnter, OnCollisionStay, OnCollisionExit ๋“ฑ์˜ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

  • ์ด ์ด๋ฒคํŠธ๋Š” ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ฒ˜๋ฆฌํ•˜์—ฌ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์˜ˆ๋ฅผ ๋“ค์–ด, ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋•…์— ๋‹ฟ์œผ๋ฉด ์ ํ”„ ๊ฐ€๋Šฅ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ํ”Œ๋ ˆ์ด์–ด์™€ ์ถฉ๋Œํ•˜๋ฉด ๋ฐ๋ฏธ์ง€๋ฅผ ์ž…ํžˆ๋Š” ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

2) ํƒ€์ผ๋งต

Unity์˜ Tilemap ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ํƒ€์ผ ๊ธฐ๋ฐ˜์˜ ๊ฒŒ์ž„ ํ™˜๊ฒฝ์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘์€ ์Šคํ”„๋ผ์ดํŠธ๋ฅผ ํ†ตํ•ด ๊ด‘๋Œ€ํ•œ ๊ฒŒ์ž„ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ณต์žกํ•œ ๊ฒŒ์ž„ ๋ ˆ๋ฒจ์„ ์‰ฝ๊ฒŒ ๋””์ž์ธํ•˜๊ณ , ํŽธ์ง‘ํ•˜๊ณ , ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

โž” TileMap ์‹œ์Šคํ…œ ๊ตฌ์„ฑ ์š”์†Œ

  • Tilemap GameObject: Unity์˜ ํƒ€์ผ๋งต ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. Tilemap Grid์˜ ์ž์‹์œผ๋กœ ์œ„์น˜ํ•˜๊ณ , ํŠน์ • ํƒ€์ผ์˜ ๋ฐฐ์น˜๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

  • Grid GameObject: ๋ชจ๋“  ํƒ€์ผ๋งต์ด ์œ„์น˜ํ•˜๋Š” ๊ธฐ๋ณธ ๊ฒฉ์ž๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • Tilemap Renderer: Tilemap์˜ ๋ชจ์–‘์„ ์‹ค์ œ๋กœ ๊ทธ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

  • Tilemap Collider 2D: ํ•„์š”ํ•œ ๊ฒฝ์šฐ, Tilemap์— ๋ฌผ๋ฆฌ์ ์ธ ๊ฒฝ๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ๊ฐ€ ํƒ€์ผ๋งต ํ™˜๊ฒฝ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

  • Tile Assets: ๊ฐœ๋ณ„ ํƒ€์ผ์˜ ๋ชจ์–‘๊ณผ ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํƒ€์ผ์„ ๋ฌถ์–ด์„œ Tileset์ด๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค.

โž” TileMap ์ค€๋น„

  • Create โ†’ 2D Object โ†’ Tilemap โ†’ Rectangular

  • ์ด๋ฆ„ ์ˆ˜์ • Floor

  • Window โ†’ 2D โ†’ Tile Palette

  • Create New Palette โ†’ ์ด๋ฆ„ ์ˆ˜์ • Dungeon โ†’ Artwork\Level ํด๋”์— ์ €์žฅ

  • Floor1 ~ 8 ๋“œ๋ž˜๊ทธ ํ•˜์—ฌ ์ถ”๊ฐ€ โ†’ Artwork\Level ํด๋”์— ์ €์žฅ

  • ๋ชจ๋“  wall_* ์ถ”๊ฐ€

โž” TileMap ๊ทธ๋ฆฌ๊ธฐ

  • Floor ํ•˜๋‚˜ ์„ ํƒ ํ›„ ๊ทธ๋ฆฌ๊ธฐ

  • Create โ†’ 2D Object โ†’ Tilemap โ†’ Rectangular โ†’ ์ด๋ฆ„๋ณ€๊ฒฝ BackDesign
  • Tilemap Renderer โ†’ Order in Layer 2
  • ๊ทธ๋ฆฌ๊ธฐ

  • Create โ†’ 2D Object โ†’ Tilemap โ†’ Rectangular โ†’ ์ด๋ฆ„๋ณ€๊ฒฝ ForeDesign
  • Tilemap Renderer โ†’ Order in Layer 20
  • ๊ทธ๋ฆฌ๊ธฐ

  • Create โ†’ 2D Object โ†’ Tilemap โ†’ Rectangular โ†’ ์ด๋ฆ„๋ณ€๊ฒฝ Collision
  • Tilemap Collider 2D ์ถ”๊ฐ€
  • Tilemap โ†’ Color โ†’ a 0

  • ๊ทธ๋ฆฌ๊ธฐ






๐Ÿ“Œ 3. ์กฐ์ค€(Aim) ์‹œ์Šคํ…œ (Quaternion)

1) ํ•ต์‹ฌ ๋‚ด์šฉ

โž” ์ฟผํ„ฐ๋‹ˆ์–ธ(Quaternion)

  • 4์ฐจ์› ๋ณต์†Œ์ˆ˜๋ฅผ ์ด์šฉํ•œ ํšŒ์ „ ํ‘œํ˜„ ๋ฐฉ๋ฒ•. (x, y, z, w) ํ˜•ํƒœ๋กœ ํ‘œํ˜„๋˜๋ฉฐ, Unity์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

  • ์˜ค์ผ๋Ÿฌ ๊ฐ๋„(Euler angles)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํšŒ์ „์„ ํ‘œํ˜„ํ•  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ์ง๋ฒŒ ๋ฝ(Gimbal Lock) ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ง๊ด€์ ์ด์ง€ ์•Š๊ณ  ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, Unity์—์„œ๋Š” ์ฟผํ„ฐ๋‹ˆ์–ธ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์กŒ๋‹ค.

  • ์ง์ ‘ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๊ณ„์‚ฐํ•˜๋Š” ๋Œ€์‹ , Unity์˜ ๋‚ด์žฅ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. (์˜ˆ : Quaternion.Euler, Quaternion.LookRotation, Quaternion.Slerp ๋“ฑ).

  • ์ฟผํ„ฐ๋‹ˆ์–ธ์€ ์ผ๋ฐ˜์ ์œผ๋กœ "์ •๊ทœํ™”(nomalized)"๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, Unity์—์„œ๋Š” ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ง์ ‘ ๊ณ„์‚ฐ์„ ํ•  ๋•Œ๋Š” ์ •๊ทœํ™”์— ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค.

โž” ์•„ํฌํƒ„์  ํŠธ(ArcTangent)

  • ์•„ํฌํƒ„์  ํŠธ ํ•จ์ˆ˜๋Š” ์‚ผ๊ฐํ•จ์ˆ˜์˜ ์—ญํ•จ์ˆ˜์ด๋‹ค. ํŠน์ • ๋น„์œจ์— ๋Œ€ํ•œ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

  • 2์ฐจ์› ๊ณต๊ฐ„์—์„œ ์  ๋˜๋Š” ๋ฒกํ„ฐ์— ๋Œ€ํ•œ ๊ฐ๋„๋ฅผ ์ฐพ๋Š” ๋ฐ ์•„ํฌํƒ„์  ํŠธ ํ•จ์ˆ˜๊ฐ€ ์ข…์ข… ์‚ฌ์šฉ๋œ๋‹ค.

  • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฒกํ„ฐ(x,y)์˜ ๊ฒฝ์šฐ, Math.Atan2(y,x) ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฒกํ„ฐ๊ฐ€ x์ถ•๊ณผ ์ด๋ฃจ๋Š” ๊ฐ๋„๋ฅผ ๋ผ๋””์•ˆ์œผ๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

  • ์•„ํฌํƒ„์  ํŠธ ํ•จ์ˆ˜๋Š” ์‚ฌ์ธ(sine)๊ณผ ์ฝ”์‚ฌ์ธ(cosine)ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ง๊ฐ ์‚ผ๊ฐํ˜•์—์„œ ๋น—๋ณ€์˜ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

  • ์ด ๊ธฐ๋Šฅ์€ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋ฉฐ, ํŠนํžˆ ๊ฐ์ฒด๊ฐ€ ํŠน์ • ๋ฐฉํ–ฅ์„ ํ–ฅํ•˜๋„๋ก ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋‘ ์  ์‚ฌ์ด์˜ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

2) ๋งˆ์šฐ์Šค๋ฅผ ๋”ฐ๋ผ ํšŒ์ „ํ•˜๋Š” ๋ฌด๊ธฐ ๋งŒ๋“ค๊ธฐ

โž” ์˜ค๋ธŒ์ ํŠธ ์ค€๋น„

โž” TopDownAimRotation

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);
    }
}





๐Ÿ“Œ 4. ๊ณต๊ฒฉ ์‹œ์Šคํ…œ ๊ตฌํ˜„

1) ํ•ต์‹ฌ ๋‚ด์šฉ

โž” ํ”„๋ฆฌํŒน(Prefab)

  • ํ”„๋ฆฌํŒน์€ Unity ๊ฒŒ์ž„ ์—”์ง„์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ์ด๋‹ค.

  • ํ”„๋ฆฌํŒน์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์™€ ๊ทธ์— ๊ด€๋ จ๋œ ์ปดํฌ๋„ŒํŠธ ๋ฐ ์„ค์ •์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•˜๊ณ , ์—ฌ๋Ÿฌ ์žฅ๋ฉด์ด๋‚˜ ๊ฒŒ์ž„์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํ”„๋ฆฌํŒน์€ ์ธ์Šคํ„ด์Šคํ™”๋ฅผ ํ†ตํ•ด ์‹ค์ œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋กœ ๋ณ€ํ™˜๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๋•Œ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์™€ ์ปดํฌ๋„ŒํŠธ ์„ค์ •์ด ๋ณต์‚ฌ๋œ๋‹ค.

  • ํ”„๋ฆฌํŒน์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค์— ์ฆ‰์‹œ ๋ฐ˜์˜๋˜๋ฏ€๋กœ, ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ์ผ๊ด„์ ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํ”„๋ฆฌํŒน์€ ๋ ˆ๋ฒจ ๋””์ž์ธ, ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฒŒ์ž„ ์š”์†Œ(์บ๋ฆญํ„ฐ, ์•„์ดํ…œ, ์žฅ์• ๋ฌผ ๋“ฑ)์˜ ์ƒ์„ฑ, ํ”„๋กœํ† ํƒ€์ดํ•‘ ๋“ฑ์— ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

โž” Instantiate ํ•จ์ˆ˜ (Unity)

  • Instantiateํ•จ์ˆ˜๋Š” Unity์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ, ์ฃผ์–ด์ง„ ์›๋ณธ ๊ฐœ์ฒด์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • ์ด ํ•จ์ˆ˜๋Š” ์ฃผ๋กœ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ, ์ฆ‰ ์บ๋ฆญํ„ฐ, ์•„์ดํ…œ, ํ”„๋กœ์ ํƒ€์ผ ๋“ฑ์„ ๋™์ ์œผ๋กœ ๊ฒŒ์ž„ ์„ธ๊ณ„์— ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

  • Instantiateํ•จ์ˆ˜๋Š” ์›๋ณธ ๊ฐœ์ฒด์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์™€ ๊ทธ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ƒˆ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

  • ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” ๋…๋ฆฝ์ ์ด๋ฉฐ, ์›๋ณธ ๊ฐœ์ฒด์— ๋Œ€ํ•œ ๋ณ€ํ™”๋Š” ์ด์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

  • Instantiateํ•จ์ˆ˜๋Š” ์›๋ณธ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ, ์œ„์น˜ ๋ฐ ํšŒ์ „ ์ •๋ณด๋ฅผ ์ธ์ž๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

2) ๊ณต๊ฒฉ ์‹œ์Šคํ…œ & ์ด์•Œ ๋งŒ๋“ค๊ธฐ

โž” PlayerInputController.cs

public void OnFire(InputValue value)
{
    //Debug.Log("OnFire" + value.ToString());
    IsAttacking = value.isPressed;
}

โž” TopDownCharacterController.cs

---------- ์ƒ๋žต ----------
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();
}

โž” TopDownShooting.cs

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
    }
}
  • Player์— ์ถ”๊ฐ€

โž” Arrow ๋งŒ๋“ค๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€