ํ˜ผ์ž ๊ฐœ๋ฐœํ•˜๋Š”๋ฐ ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๊ณ  ์–ด๋”” ๊ธ€์“ธ๋ฐ๋„ ์—†๊ณ  ํ•ด์„œ ์ƒˆ๋ฒฝ์— ํ•œ๋ฒˆ ๋˜ฅํ•œ๋ฒˆ ์‹ธ๊ณ ๊ฐ.


3Dย 3์ธ์นญ๊ฒœ ๋งŒ๋“œ๋Š”๋ฐ,ย ํ”Œ๋ ˆ์ด์–ด ์ปจํŠธ๋กค๋Ÿฌ ์ž˜ ๋งŒ๋“ค๊ธฐย ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค.

์ง€๋‚œ 2๋…„๊ฐ„ 3๋ฒˆ์ •๋„์˜ ๋Œ€๊ฒฉ๋ณ€๊ณผ ์•ฝ 10์ฐจ๋ก€์˜ ๋ฆฌํŒฉํ† ๋ง์„ ๊ฑฐ์ณ๋„ ์•„์ง๋„ ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค.ย 


๊ณ ์ž‘ 2000์ค„์ด ๋‹ค๋ฅธ์ด๋“ค์—๊ฒŒ๋„ ๊ฑฐ๋Œ€ํ•œ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ

๋ˆ„๋”๊ธฐ์ฒ˜๋Ÿผ ๋งŒ๋“ค๋‹ค๋ณด๋‹ˆ ์–ด๋А์ƒˆ 2000์ค„์ด ๋˜์—ˆ๊ณ ,ย 

๋‚ด ๋จธ๋ฆฌ๋กœ๋Š”ย ์ด์ œ ๋”์ด์ƒ ๊ธฐ๋Šฅ์ถ”๊ฐ€๋‚˜ ์ˆ˜์ •์ดย ๋ถˆ๊ฐ€๋Šฅํ•ด์ง.

๋”๋ถˆ์–ด ๊ฐ€๋…์„ฑ๋„ ๋‚˜๋ฝ๊ฐ„์ง€ ์˜ค๋ž˜.ย 


unirx์™€ unitask๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ ๋‚œ ์งํ›„์— ์ƒˆ๋กœ ๋งŒ๋“  ์ฝ”๋“œ์—ฌ์„œ ๊ทธ๋Ÿฐ์ง€ย 

๋ฌด๋ถ„๋ณ„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ ์‹ ๊ธฐ์ˆ (?)๋“ค๋กœ ์ธํ•ด ๋”์šฑ๋” ์ข†๊ฐ™์€ย ์ฝ”๋“œ๊ฐ€ ๋˜์—ˆ๋‹ค.


์•„๋ฌดํŠผ ํ•„์š”์— ์˜ํ•œย ๋ฆฌํŒฉํ† ๋ง์„ ์‹œ์ž‘ํ•œ์ง€ ์–ด์–ธ ์ผ์ฃผ์ผ...

์‚ฌ์‹ค ์ด์ „์—๋„ ๋ฆฌํŒฉํ† ๋ง์„ ์‹œ๋„ํ•ด๋ณด์•˜์œผ๋‚˜ ์—„๋‘๊ฐ€ ์•ˆ๋‚˜์„œ ํฌ๊ธฐํ–ˆ๋Š”๋ฐ, ์ฐจ๋ผ๋ฆฌ ๊ทธ ๋•Œ ํ•ด๊ฒฐํ• ๊ฑธ ๊ทธ๋žฌ๋‹ค.



์•„๋ฌดํŠผ ์ง€๋‚œ ์ผ์ฃผ์ผ๋™์•ˆ์—๋„ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‹œํ–‰์ฐฉ์˜ค๊ฐ€ ์žˆ์—ˆ๋‹ค.


1. ์—ฌ๋Ÿฌ๊ฐœ์˜ ํด๋ž˜์Šค๋กœ ์—ญํ• ์„ ๋ถ„๋‹ดํ•ด์„œ ์ชผ๊ฐœ๊ธฐ.

์ด๋ฐฉ๋ฒ•์˜ ๋‹จ์ ์€ ํ•œ์ค„์š”์•ฝํ•˜์ž๋ฉด ์ฝ”๋“œ์˜ ์–‘์ด ์˜คํžˆ๋ ค ๋„ˆ๋ฌด ๋งŽ์ด ๋Š˜์–ด๋‚˜, ์ผ์ด ๋งŽ์•„์ง€๊ณ  ์‹ค์ˆ˜์˜ ์—ฌ์ง€๊ฐ€ ๋งŽ์•„์ง„๋‹ค.


๊ธฐ์กด ํด๋ž˜์Šค๊ฐ€ ์ฐธ์กฐ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๊ณ , ๋Œ€๋ถ€๋ถ„์˜ ์ฝ”๋“œ์—์„œ ๊ทธ ์ฐธ์กฐ๋ณ€์ˆ˜๋“ค์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด

void HandleAttack(), void HandleBackstep(), void HandleDie() ๋“ฑ ์ „๋ถ€ ํ”Œ๋ ˆ์ด์–ด ์บ๋ฆญํ„ฐ์˜ ๋™์ž‘์„ ์œ„ํ•œ ํ•จ์ˆ˜์ด๊ณ 

๋Œ€๋ถ€๋ถ„ animator, characterController์™€ ๊ธฐํƒ€๋“ฑ๋“ฑ ์ปค์Šคํ…€ ํด๋ž˜์Šค, ํŒŒ๋ผ๋ฏธํ„ฐ์Šคํฌ๋ฆฝํ„ฐ๋ธ”์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ฐธ์กฐ์‹œ์ผœ์•ผ ํ•˜๊ณ ,ย 

์ฐธ์กฐ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ์ž๋ผ๋˜์ง€, ์•„๋‹ˆ๋ฉด ์ฐธ์กฐ๋ณ€์ˆ˜๋“ค๋งŒ ๋ฌถ์–ด๋†“์€ ์ถ”๊ฐ€ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค๋˜์ง€ ํ•ด์•ผํ–ˆ๋Š”๋ฐ, ๋‹ค๋ฅธ๋ฐฉ๋ฒ•์€ ์•„์ง ์•Œ์ง€ ๋ชปํ•˜๊ฒ ๋‹ค.


์œ„์˜ ๋ฌธ์ œ๋Š” ์‚ฌ์‹ค ์ข€๋งŒ ๋ถ€์ง€๋Ÿฐํ•˜๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ ๋”์šฑ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.

์›๋ž˜ ํด๋ž˜์Šค๊ฐ€ IPlayerController๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†์ค‘์ด๊ณ , ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•ด์„œ ์œ ์ €์ธํ’‹์„ ํ”Œ๋ ˆ์ด์–ด์ปจํŠธ๋กค๋Ÿฌ์— ์ „๋‹ฌ์ค‘์ธ๋ฐ

๊ทธ๋ ‡๋‹ค๋ฉด IPlayerController๋ฅผ ์ƒ์†๋ฐ›์€ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ณ  ๊ทธ๋ฆฌ๊ณ  ์ƒˆ๋กœ๋งŒ๋“ค ํด๋ž˜์Šค๋“ค์„ ์—ฐ๊ฒฐํ•ด์ค„ ์ƒ๊ฐ์„ ํ•˜๋‹ˆ

์ด๊ฒŒ ์ตœ์„ ์ธ๊ฐ€ ์‹ถ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•˜๋ฃจ์ •๋„ ์ฝ”๋”ฉํ•˜๊ณ  ํ•˜๋ฃจ์ •๋„ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ๊ฒฐ๊ตญ ๊ธฐ๊ฐ.


2. ๊ทธ๋ƒฅ ๊ธฐ์กด ๊ฑฐ๋Œ€ํด๋ž˜์Šค ๋‹ค์‹œ ์ž˜ ์จ๋ณด๊ธฐ.

1๋ฒˆ์˜ ์‚ฝ์งˆ์„ ํ•˜๋‹ค๊ฐ€ ๋‹ค์‹œ ์ž˜ ์ƒ๊ฐํ•ด๋ณด๋‹ˆย 

ํ˜„์žฌ ์ฝ”๋“œ์—์„œ unirx๋ฅผ ์ด์ƒํ•˜๊ฒŒ ์‚ฌ์šฉํ•œ ๋ถ€๋ถ„๋งŒ ๊ฑท์–ด๋‚ด๋ฉด ์“ธ๋งŒํ•  ๊ฒƒ ๊ฐ™์•˜๋‹ค.


unirx์˜ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๊ตฌ๋…๋ฐฉ์‹์˜ ํŒจํ„ด์€ ๋งค์šฐ ๋งค๋ ฅ์ ์ด์—ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜. ๋‚˜์ฒ˜๋Ÿผ ์ž˜๋ชป์“ฐ๋ฉด ๋…์ด๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด. ์บ๋ฆญํ„ฐ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ง€๋ฉดํŒ์ • ์ด๋ฒคํŠธ๋ฅผ

ย subject๊ฐ€ ์žˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ์กด ์บ๋ฆญํ„ฐ์ปจํŠธ๋กค๋Ÿฌ์˜ isGroundedํŒ์ •์˜ ๋‹จ์ ์„ ๊ฐœ์„ ํ•œ ๊ฒƒ์ด๋‹ค.

GroundObserver.OnFeetOff, GroundObserver.OnLand ๋‘๊ฐœ์˜ subject๋ฅผ ๊ตฌ๋…ํ•ด์„œ ์บ๋ฆญํ„ฐ๊ฐ€ ์ง€๋ฉด์—์„œ ๋–จ์–ด์ก‹์„ ๋•Œ,ย 

์ง€๋ฉด์— ๋‹ฟ์•˜์„ ๋•Œ ์›ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.ย 


private void Awake(){

_groundObserver.OnFeetOff.Subscribe(_ => { ...ย });

_groundObserver.OnLand.Subscribe(_ => { ...ย });

}


์Œ ๊ฝค ๊น”๋”ํ•˜๊ณ  ์ข‹์€๊ฒƒ๊ฐ™์ง€๋งŒ, ์ž˜ ์“ฐ๋ฉด ์ข‹๊ฒ ์ง€๋งŒ ๋‚˜๋Š” ์ด๊ฒƒ์˜ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์ ์€

๋‹ค๋ฅธ ๋กœ์ง๋“ค๊ณผ ๊ฒน์ณ์กŒ์„ ๋•Œ, ์ด๊ฒŒ ๋‹จ๋…์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ง€๊ณ ,

์ฝ”๋“œ๊ฐ€ 2000์ค„์ด ๋  ๋•Œ, ์‹คํ–‰ ๋กœ์ง์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์ฝํžˆ์ง€ ์•Š๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.


๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ unirx๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ์–ด๋–จ๊นŒ๋กœ ์ ‘๊ทผํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” ์–ด๋””์„œ๋ถ€ํ„ฐ ์ œ๊ฑฐํ• ์ง€ ์ฐธ ๋‚œ๊ฐํ–ˆ๋‹ค.

๊ธฐ์กด ์ฝ”๋“œ์—์„œ ์ œ๊ฑฐ๊ฐ€ ์•„๋‹ˆ๊ณ , ๊ธฐ์กด ์ฝ”๋“œ์—์„œ ํ•ต์‹ฌ์ ์ธ ๋ถ€๋ถ„๋งŒ ์‚ด์‚ด ๋“ค์–ด๋‚ด์„œย 

์ƒˆ๋กœ์šด ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์„ธ์›Œ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.


3. partial ํด๋ž˜์Šค ๋„์ž…

ํ•˜์ง€๋งŒ ์•„๋ฌด๋ฆฌ ์ƒˆ๋กœ ์“ด๋‹ค๊ณ  ํ•ด๋„ ๊ฒฐ๊ตญ์€ ๋ช‡์ฒœ์ค„์งœ๋ฆฌ ์ฝ”๋“œ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆด๊ฒƒ์ด ๋ถ„๋ช…ํ•˜๋‹ค.

๊ทธ๋ž˜์„œ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๋‹ˆ partial ํด๋ž˜์Šค๋กœ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŒŒ์ผ๋กœ ๋ถ„ํ• ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋ฅผ ์ฃผ์ œ์— ๋งž๊ฒŒ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํŒŒ์ผ๋กœ ๋ถ„ํ• ํ–ˆ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด,ย 

PlayerController.cs ย - ๋‹จ์ˆœํžˆ ํด๋ž˜์Šค๋งŒ ์„ ์–ธ, monobehaviour์™€ ๊ฐ์ข… ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ƒ์†

PlayerController.SerializedFields.cs - ์ธ์ŠคํŽ™ํ„ฐ์—์„œ ๋ณด์ด๊ณ  ์‹ถ์€ ๋ณ€์ˆ˜๋“ค๋งŒ ์ •์˜

PlayerController.Commands.cs - IPlayerController์— ์ •์˜๋œ ํ•จ์ˆ˜๋“ค๋งŒ ์ •์˜

PlayerController.HandleAttacks.cs - ๊ณต๊ฒฉ๊ด€๋ จ ๋™์ž‘๋“ค

PlayerController.HandleJump.cs - ์ ํ”„๊ด€๋ จ ๋™์ž‘๋“ค..

..๋“ฑ

๊ทธ๋ฆฌ๊ณ  unirx๋กœ ๊ตฌํ˜„ํ–‡๋˜ ๊ธฐ๋Šฅ๋“ค์ค‘ ๋Œ€๋‹ค์ˆ˜๋Š” ๋น„๋™๊ธฐ unitask ํ•จ์ˆ˜๋“ค๋กœ ๊ต์ฒดํ–ˆ๋‹ค.


์•„๊นŒ ์˜ˆ์‹œ๋กœ ๋“ค์—ˆ๋˜ ์ง€๋ฉด ํŒ์ •๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋Œ€๋ถ€๋ถ„ ๋กœ์ง ์ค‘๊ฐ„์—ย 

await UniTask.WaitUntil(() => _groundObserver.IsGrounded);

๊ฐ™์ด ์œ ๋‹ˆํƒœ์Šคํฌ๋กœ ํ•จ์ˆ˜๋กœ ์ง€๋ฉดํŒ์ •์„ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•˜์—ฌ

ํ•จ์ˆ˜๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ฝ์œผ๋ฉด ์™„์„ฑ๋œ ๋กœ์ง์„ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

์ด ๊ณผ์ •์—๋Š”ย 

https://qiita.com/toRisouP/items/af7d32846ab99f493d92

์ด ๊ธ€์„ ๋งŽ์ด ์ฐธ์กฐํ–ˆ๋‹ค. ๊ตญ๋‚ด ๋ฒˆ์—ญ๊ธ€๋„ ์žˆ์—ˆ๋˜๊ฑฐ ๊ฐ™์€๋ฐย ์š”์ฆ˜ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฒˆ์—ญ ๋‹ค ์ž˜๋˜๋‹ˆ ์›๊ธ€์„ ์ฒจ๋ถ€ํ•จ.


์ฝ”๋ฃจํ‹ด์“ฐ๋‹ค๊ฐ€ ์œ ๋‹ˆํƒœ์Šคํฌ ์“ฐ๋‹ˆ๊นŒ ๋„ˆ๋ฌด ์ข‹๋‹ค.ย 

์ฐธ๊ณ ๋กœ dotween๋„ ์œ ๋‹ˆํƒœ์Šคํฌ ์ง€์›์ด ๋˜๋‹ˆ ์•„์ง ์•ˆ์จ๋ณธ ์ธ๋ถ•์ด๋“ค์€ ์จ๋ณด๋„๋ก ํ•˜์ž.


์•„๋ฌดํŠผ ์ด์ œ ๋ฆฌํŒฉํ† ๋ง์˜ 70ํ”„๋กœ์ •๋„ ์ง„ํ–‰๋œ ๊ฒƒ ๊ฐ™๋‹ค.

๊ทผ๋ฐ ๊ฒŒ์ž„์€ ๋„๋Œ€์ฒด ์–ธ์ œ ์™„์„ฑํ•  ์ˆ˜ ์žˆ๋Š”๊ฑธ๊นŒ.