Unity ์‹ฌํ™” - 2

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

๐Ÿ“Œ Unity ๊ฒŒ์ž„ ๊ฐœ๋ฐœ ์‹ฌํ™”



๐Ÿ“Œ ๊ฒŒ์ž„ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ดํ•ด

โž” ๐Ÿ”ฅ ํ•ต์‹ฌ ๋‚ด์šฉ

Unity๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์ž„์„ ๊ฐœ๋ฐœํ•œ ํ›„ ์‹ค์ œ๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ, ์ฆ‰ "๋นŒ๋“œ"๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํ•™์Šต






โž” Windows์šฉ ๋นŒ๋“œ

๋นŒ๋“œ ๊ณผ์ •

  • 'File' > 'Build Setting'๋กœ ์ด๋™

  • 'Platform' ๋ชฉ๋ก์—์„œ 'Windows'๋ฅผ ์„ ํƒํ•˜๊ณ , 'Switch Platform'์„ ํด๋ฆญ

  • ์›ํ•˜๋Š” ์”ฌ์„ 'Scenes in Build' ๋ชฉ๋ก์— ์ถ”๊ฐ€

  • 'Player Settings'์—์„œ ๊ฒŒ์ž„์˜ ์„ค์ •์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. (์˜ˆ : ํšŒ์‚ฌ ์ด๋ฆ„, ๊ฒŒ์ž„ ์•„์ด์ฝ˜ ๋“ฑ)

  • 'Build' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋นŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

์œ ์˜ ์‚ฌํ•ญ

  • Windows๋นŒ๋“œ๋Š” Windows ์šด์˜์ฒด์ œ์—์„œ๋งŒ ์‹คํ–‰๋œ๋‹ค.

  • ๋นŒ๋“œ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋“ค, ์˜ˆ๋ฅผ ๋“ค๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ ํ˜ธํ™˜์„ฑ ์ด์Šˆ ๋“ฑ์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.






โž” Android์šฉ ๋นŒ๋“œ

๋นŒ๋“œ ๊ณผ์ •

  • 'File' > 'Build Settings'๋กœ ์ด๋™

  • 'Platform'๋ชฉ๋ก์—์„œ 'Android'๋ฅผ ์„ ํƒํ•˜๊ณ , 'Switch Platform'์„ ํด๋ฆญ

  • ์›ํ•˜๋Š” ์”ฌ์„ 'Scenes in Build'๋ชฉ๋ก์— ์ถ”๊ฐ€

  • 'Player Settings'์—์„œ ๊ฒŒ์ž„์˜ ์„ค์ •์„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ (์˜ˆ : ํšŒ์‚ฌ ์ด๋ฆ„, ๊ฒŒ์ž„ ์•„์ด์ฝ˜, ๋ฒˆ๋“ค ์‹๋ณ„์ž ๋“ฑ)

  • 'Minimum API Level'๊ณผ 'Target API Level'์„ ์ ์ ˆํ•˜๊ฒŒ ์„ค์ •ํ•œ๋‹ค.

  • 'Build'๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋นŒ๋“œ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

์œ ์˜ ์‚ฌํ•ญ

  • Android ๋นŒ๋“œ๋ฅผ ์œ„ํ•ด์„œ๋Š” JDK์™€ Android SDK๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • ๋นŒ๋“œ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋“ค, ์˜ˆ๋ฅผ ๋“ค๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ ํ˜ธํ™˜์„ฑ ์ด์Šˆ, API๋ ˆ๋ฒจ ๋ฌธ์ œ ๋“ฑ์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

  • Android๋Š” ๋‹ค์–‘ํ•œ ํ•ด์ƒ๋„์™€ ๊ธฐ๊ธฐ๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๊ณ ๋ คํ•œ UI / UX ๋””์ž์ธ์ด ํ•„์š”ํ•˜๋‹ค.

  • ์•ˆ๋“œ๋กœ์ด๋“œ์˜ ๋‹ค์–‘ํ•œ OS๋ฒ„์ „๊ณผ ํ˜ธํ™˜์„ฑ์„ ํ™•๋ณดํ•ด์•ผ ํ•œ๋‹ค.






โž” ์ฃผ์š” Player Settings ์˜ต์…˜

Windows์šฉ Player Settings

General

  • Company Name : ํšŒ์‚ฌ ์ด๋ฆ„์„ ์ž…๋ ฅ. ์ด ์ •๋ณด๋Š” ๊ฒŒ์ž„์˜ ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ์— ์ €์žฅ๋œ๋‹ค.

  • Product Name : ๊ฒŒ์ž„์˜ ์ด๋ฆ„์„ ์ž…๋ ฅ

  • Version : ๊ฒŒ์ž„์˜ ๋ฒ„์ „์„ ์ž…๋ ฅ

  • Default Icon : ๊ฒŒ์ž„์˜ ์•„์ด์ฝ˜์„ ์„ค์ •. ํ•ด๋‹น ์•„์ด์ฝ˜์€ ๊ฒŒ์ž„ ์‹คํ–‰ ํŒŒ์ผ์— ์‚ฌ์šฉ๋œ๋‹ค.

Resolution and Presentation

  • Default Screen Width, Default Screen Height : ๊ฒŒ์ž„์ด ์ฒ˜์Œ ์‹คํ–‰๋  ๋•Œ์˜ ๊ธฐ๋ณธ ํ™”๋ฉด ๋„ˆ๋น„์™€ ๋†’์ด๋ฅผ ์„ค์ •

  • FullScreen Mode : ๊ฒŒ์ž„์ด ์ „์ฒดํ™”๋ฉด์œผ๋กœ ์‹คํ–‰๋ ์ง€, ์ฐฝ๋ชจ๋“œ๋กœ ์‹คํ–‰๋ ์ง€๋ฅผ ๊ฒฐ์ •

  • Visible in Background : ์ด ์˜ต์…˜์€ ์ฐฝ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ, ๊ฒŒ์ž„์ด ๋ณด์ผ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •.

Icon

  • ์—ฌ๊ธฐ์„œ ๊ฒŒ์ž„์˜ ์•„์ด์ฝ˜์„ ๋”์šฑ ์ž์„ธํžˆ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Android์šฉ Player Settings

General

  • Company Name, Product Name, Version : ์œ„์˜ Windows ์„ค์ •๊ณผ ๋™์ผํ•˜๋‹ค.

  • Bundle Identifier : ์•ฑ์˜ ๊ณ ์œ  ์‹๋ณ„์ž์ด๋‹ค. ๋ณดํ†ต "com.CompanyName.GameName" ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ๋œ๋‹ค.

Icon

  • Default Icon : ๊ฒŒ์ž„์˜ ์•„์ด์ฝ˜์„ ์„ค์ •ํ•œ๋‹ค. ํ•ด๋‹น ์•„์ด์ฝ˜์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ์•„์ด์ฝ˜์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

  • Adaptive Icons : Android 8.0 ์ด์ƒ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ ์‘ํ˜• ์•„์ด์ฝ˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Resolution and Presentation

  • Default Orientaion : ๊ฒŒ์ž„์ด ์‹œ์ž‘๋  ๋•Œ์˜ ํ™”๋ฉด ๋ฐฉํ–ฅ์„ ์„ค์ •ํ•œ๋‹ค.

  • Auto Rotation : ํ™”๋ฉด์ด ์ž๋™์œผ๋กœ ํšŒ์ „ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค.

Other Settings

  • Minimum API Level : ์•ฑ์ด ์ง€์›ํ•˜๋Š” ์ตœ์†Œ ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์„ ์„ค์ •ํ•œ๋‹ค.

  • Target API Level : ์•ฑ์ด ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ๋ฒ„์ „์„ ์„ค์ •ํ•œ๋‹ค. ์ตœ์‹  ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.






โž” ์ฐธ๊ณ ์‚ฌํ•ญ

์œˆ๋„์šฐ ๋นŒ๋“œ์‹œ ํ™”๋ฉด ํฌ๊ธฐ ์„ค์ •

  • [๋ ˆ์ง€์ŠคํŠธ๋ฆฌํŽธ์ง‘๊ธฐ] ๊ฒ€์ƒ‰ ํ›„

  • HKCU\Software\[ํšŒ์‚ฌ๋ช…]\[์ œํ’ˆ๋ช…]

  • ์„ค์ •๋œ ํ•ด์ƒ๋„ ๊ฐ’ ์ˆ˜์ • ๋˜๋Š” ์‚ญ์ œ












๐Ÿ“Œ ํฌํ†ค์ด๋ž€

โž” ๐Ÿ”ฅ ํฌํ†ค์ด๋ž€?

ํฌํ†ค(Photon)์€ Exit Games์—์„œ ๊ฐœ๋ฐœํ•œ ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๋„คํŠธ์›Œํฌ ์—”์ง„์ด๋‹ค. Unity์™€ ๊ฐ™์€ ๊ฒŒ์ž„ ์—”์ง„๊ณผ ์‚ฌ์šฉ๋˜์–ด ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ๊ธฐ๋Šฅ์„ ๊ฒŒ์ž„์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.






โž” ํฌํ†ค์˜ ์ฃผ์š” ํŠน์ง•

  • Cross-Platform : ํฌํ†ค์€ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ ๊ฐ„์— ํ†ต์‹ ์„ ์ง€์›ํ•œ๋‹ค. ์ด๋Š” PC, ๋ชจ๋ฐ”์ผ, ์ฝ˜์†” ๊ฒŒ์ž„์—์„œ ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด๋ฅผ ์ง€์›ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค.

  • Real-Time, Multiplayer : ํฌํ†ค์€ ์‹ค์‹œ๊ฐ„ ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์žˆ๋‹ค.

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

  • Reliability : ํฌํ†ค์€ ๋ฐ์ดํ„ฐ ์ „์†ก์— ๋Œ€ํ•œ ๋†’์€ ์‹ ๋ขฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.






โž” ํฌํ†ค์˜ ์ฃผ์š” ๋ฉ”์„œ๋“œ ๋ฐ ๊ธฐ๋Šฅ

ํฌํ†ค์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๋ฉ”์„œ๋“œ์™€ ํด๋ž˜์Šค

PhotonNetwork ํด๋ž˜์Šค

PhotonNetworkํด๋ž˜์Šค๋Š” ํฌํ†ค ๋„คํŠธ์›Œํฌ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์— ์—‘๊ฒŒ์Šค ํ•˜๋Š” ์ค‘์‹ฌ์ ์ธ ํด๋ž˜์Šค์ด๋‹ค.



  • ConnectUsingSettings ๋ฉ”์„œ๋“œ
PhotonNetwork.ConnectUsingSettings();

์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์•ฑ์ด ํฌํ†ค ํด๋ผ์šฐ๋“œ์— ์—ฐ๊ฒฐ๋œ๋‹ค. ์—ฐ๊ฒฐ์ƒํƒœ๋Š” PhtonNetwork.IsConnected๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • CreateRoom ๋ฐ JoinRoom ๋ฉ”์„œ๋“œ
PhotonNetwork.CreateRoom("RoomName");
PhotonNetwork.JoinRoom("RoomName");

CreateRoom ๋ฉ”์„œ๋“œ๋Š” ์ƒˆ๋กœ์šด ๋ฐฉ์„ ๋งŒ๋“ค๊ณ , Join ๋ฉ”์„œ๋“œ๋Š” ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ฐฉ์— ์ฐธ๊ฐ€ํ•œ๋‹ค.

  • Instantiate ๋ฉ”์„œ๋“œ
PhotonNetwork.Instantiate("PrefabName", position, rotation);

ํฌํ†ค ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” Unity์˜ Instantiate ๋ฉ”์„œ๋“œ์™€ ์œ ์‚ฌํ•˜๋‚˜, ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋™๊ธฐํ™”๋œ๋‹ค.

MonoBehaviourPunCallbacks ํด๋ž˜์Šค

MonoBehaviourPunCallbacksํด๋ž˜์Šค๋Š” ํฌํ†ค์˜ ์ฃผ์š” ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.



  • OnConnectedToMaster ๋ฉ”์„œ๋“œ
public override void OnConnectedToMaster() { ... }

๊ฒŒ์ž„์ด ํฌํ†ค ๋งˆ์Šคํ„ฐ ์„œ๋ฒ„์— ์„ฑ๊ณต์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค.

  • OnJoinedRoom ๋ฉ”์„œ๋“œ
public override void OnJoinedRoom() { ... }

๋กœ์ปฌ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋ฐฉ์— ์ž…์žฅํ•˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค.

  • OnPlayerEnteredRoom ๋ฉ”์„œ๋“œ
public override void OnPlayerEnteredRoom(Player newPlayer) { ... }

๋‹ค๋ฅธ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋ฐฉ์— ์ž…์žฅํ•˜๋ฉด ํ˜ธ์ถœ๋œ๋‹ค.






โž” ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ ๋ฐ ๊ธฐ๋Šฅ

์ปดํฌ๋„ŒํŠธ ์†Œ๊ฐœ

ํฌํ†ค์—์„œ ์ฃผ์š”ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ ๋ช‡ ๊ฐ€์ง€

  • PhotinView


    PhotonView๋Š” ํฌํ†ค ๋„คํŠธ์›Œํฌ์—์„œ ๋„คํŠธ์›Œํฌ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ
    ๋ฅผ ํ†ตํ•ด PhotonNetwork.Instantiate๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด๊ฐ€ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋™๊ธฐํšŒ๋œ๋‹ค.
    PhotonView๋Š” ์ฃผ๋กœ Transform์ปดํฌ๋„ŒํŠธ๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐ™์ด ๋™๊ธฐํ™”ํ•˜๊ณ ์ž ํ•˜๋Š”
    ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

  • PhotonTransformView


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

  • PhotonAnimatorView


    PhotonAnimatorView๋Š” Animator์ปดํฌ๋„ŒํŠธ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋Š”
    PhotonView์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋ฉฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒํƒœ์™€ ๋ณ€์ˆ˜๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

  • PhotonRigidbodyView


    PhotonRigidbodyView๋Š” Rigidbody ๋˜๋Š” Rigidbody2D ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
    ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์›€์ง์ž„๊ณผ ํšŒ์ „์„ ๋™๊ธฐํ™”ํ•˜์—ฌ ๋ฌผ๋ฆฌ์  ํšจ๊ณผ๋ฅผ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.






โž” ๊ธฐ์ดˆ์ ์ธ ๋„คํŠธ์›Œํฌ ์ง€์‹

IP ์ฃผ์†Œ์™€ ํฌํŠธ

  • IP Adress : ์ธํ„ฐ๋„ท์— ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์žฅ์น˜๋Š” IP ์ฃผ์†Œ๋ผ๋Š” ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง„๋‹ค.
  • Port : IP ์ฃผ์†Œ ๋‚ด์—์„œ ํŠน์ • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

TCP vs UDP

  • TCP (Transmission Control Protocol) : ์‹ ๋ขฐ์„ฑ์ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์— ์‚ฌ์šฉ๋œ๋‹ค. ๋ฐ์ดํ„ฐ ์ „์†ก ํ™•์ธ์„ ์œ„ํ•œ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์น˜์ง€ ๋•Œ๋ฌธ์— UDP๋ณด๋‹ค ๋Š๋ฆด ์ˆ˜ ์žˆ๋‹ค.

  • UDP (User Datagram Protocol) : ์†๋„๊ฐ€ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์— ์‚ฌ์šฉ๋œ๋‹ค. ๋ฐ์ž‰ํ„ฐ์˜ ๋„์ฐฉ์„ ํ™•์ธํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋น ๋ฅด์ง€๋งŒ, ์‹ ๋ขฐ์„ฑ์€ TCP๋ณด๋‹ค ๋‚ฎ๋‹ค.

ํŒจํ‚ท

  • Packet : ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ „์†ก๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ž‘์€ ๋ธ”๋ก์ด๋‹ค. ๋ฐ์ดํ„ฐ๋Š” ํŒจํ‚ท์œผ๋กœ ๋ถ„ํ• ๋˜์–ด ์ „์†ก๋˜๋ฉฐ, ๋ชฉ์ ์ง€์—์„œ ๋‹ค์‹œ ์กฐ๋ฆฝ๋œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ๋ชจ๋ธ

  • Client-Server Model : ์„œ๋ฒ„๋Š” ๋„คํŠธ์›Œํฌ์— ์—ฐ๊ฒฐ๋œ ์ปดํ“จํ„ฐ๋กœ์„œ, ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ตํ•œ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ์‚ฌ์šฉ์ž์˜ ์žฅ์น˜๋กœ์„œ, ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค.

ํ”ผ์–ด ํˆฌ ํ”ผ์–ด(P2P) ๋ชจ๋ธ

  • Peer-to-Peer Model : ๋ชจ๋“  ์ฐธ์—ฌ์ž(ํ”ผ์–ด)๊ฐ€ ๋™๋“ฑํ•œ ํœ˜์น˜์— ์žˆ์œผ๋ฉฐ, ์ง์ ‘ ํ†ต์‹ ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ค‘์•™ ์„œ๋ฒ„์˜ ์—ญํ• ์ด ์ค„์–ด๋“ค๊ฑฐ๋‚˜ ์—†์–ด์ง„๋‹ค.











๐Ÿ“Œ Net - Pong ๋งŒ๋“ค๊ธฐ

โž” ํ”„๋กœ์ ํŠธ ์ค€๋น„ํ•˜๊ธฐ

๊ธฐ์กด์˜ Pong ํ”„๋กœ์ ํŠธ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ์ค€๋น„

ํฌํ†ค ์—์…‹ ๋‹ค์šด๋กœ๋“œ

์—์…‹ ์Šคํ† ์–ด ๋งํฌ

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์ด๋”” ๊ฐ€์ ธ์˜ค๊ธฐ

  • ํฌํ†ค ์‚ฌ์ดํŠธ ๊ฐ€์ž…

  • PUN ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ

  • ๋Œ€์‰ฌ๋ณด๋“œ - ์–ดํ”Œ๋ฆฌ์ด์…˜ ID ๋ณต์‚ฌ

  • Pun Wizard ์„ค์ •

๋กœ๋น„์‹  ๋ณต์ œ

  • ํŒจํ‚ค์ง€ ํ•˜์œ„ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ๋กœ๋น„์‹ ์„ ๋ณต์ œํ•˜์—ฌ ๊ฐ€์ ธ์˜ค๊ธฐ






โž” ๊ฒŒ์ž„์‹  ์—ฐ๊ฒฐํ•˜๊ธฐ

LobbyMainPanel ์ˆ˜์ •

''' ์ƒ๋žต
public void OnStartGameButtonClicked()
{
    PhotonNetwork.CurrentRoom.IsOpen = false;
    PhotonNetwork.CurrentRoom.IsVisible = false;
	
    // ์œ ๋‹ˆํ‹ฐ ๊ธฐ๋Šฅ์ธ ์”ฌ๋งค๋‹ˆ์ง€๋จผํŠธ๋กœ ์”ฌ์„ ๋กœ๋“œํ•˜๊ฒŒ ๋˜๋ฉด "๋‚˜๋งŒ" ๋„˜์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.
    // ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„  ์šฐ๋ฆฌ ๋ฐฉ์—์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋„˜์–ด๊ฐ€์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—, PhotonNetwork.LoadLevel();
    // ๋ฅผ ํ†ตํ•ด์„œ ์ง„ํ–‰ํ•ด์•ผํ•œ๋‹ค.
    PhotonNetwork.LoadLevel("SampleScene");
}

Build Setting์— ์‹  ์ถ”๊ฐ€






โž” ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์˜ค๋ธŒ์ ํŠธ ๋งŒ๋“ค๊ธฐ

Ball ์ˆ˜์ •

  • Photon View ์ถ”๊ฐ€

Player1 ์ˆ˜์ •

  • Paddle๋กœ ์ด๋ฆ„๋ณ€๊ฒฝ

  • Player ์ปดํฌ๋„ŒํŠธ ์‚ญ์ œ

  • Net Paddle ์Šคํฌ๋ฆฝํŠธ ์ƒ์„ฑํ›„ ์—ฐ๊ฒฐ

  • Photon View ์ถ”๊ฐ€

  • Photon Transform View, Position ์ถ”๊ฐ€ ํ›„ ์ฒดํฌ

Resources

  • ์œ„์—์„œ ์ˆ˜์ •๋œ ๋‘ ์˜ค๋ธŒ์ ํŠธ Resources ํด๋”๋กœ ์ด๋™ ํ”„๋ฆฌํŒนํ™”

  • ์‹ ์— ์กด์žฌํ•˜๋Š” ํ”Œ๋ ˆ์ด์–ด์™€ ๋ณผ ์‚ญ์ œ






โž” ์˜จ๋ผ์ธ ๋ฉ€ํ‹ฐ๋กœ ์ˆ˜์ •ํ•˜๊ธฐ

NetPaddle.cs ๋งŒ๋“ค๊ธฐ

public class NetPaddle : MonoBehaviourPun // photonView๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ€์ ธ์˜จ๋‹ค.
{
    public float speed = 10f;

    void Update()
    {
    	// ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋‚ด๊ฒƒ์ด๋ƒ? ์—ฌ๊ธฐ์„œ ๋‚ด๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์€ ๋‚ด๊ฐ€๋งŒ๋“  ์˜ค๋ธŒ์ ํŠธ๋ƒ? ๋ผ๋Š” ๊ฒƒ
        // ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ์žˆ๊ณ  ์ด๊ฒƒ์ด ํ˜ธ์ŠคํŠธ ๊ฒƒ์ธ์ง€? ์•„๋‹ˆ๋ฉด ๋‚ด๊ฐ€ ์ด ํ”Œ๋ ˆ์ด๋ฅผ
        // ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋‚ด ๊ฒƒ์„ ์œ„ํ•ด ๋‚ด๊ฐ€ ๋งŒ๋“ ๊ฒƒ์ธ์ง€.
        if(photonView.IsMine)
        {
            float move = Input.GetAxis("Vertical") * speed * Time.deltaTime;
            transform.Translate(0, move, 0);
        }
    }
}

Ball.cs ์ˆ˜์ •

public class Ball : MonoBehaviourPun, IPunObservable
{
    public float speed;
    public Rigidbody2D rigidbody;

    private void Awake()
    {
        rigidbody = GetComponent<Rigidbody2D>();
    }

    void Start()
    {
		// ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ์‚ฌ๋žŒ๋“ค์€ ํ˜ธ์ŠคํŠธ๊ฐ€ ์›€์ง์ด๋Š” ๊ณต์˜ ์œ„์น˜๋ฅผ ๋™๊ธฐํ™”๋งŒ ํ•˜๋ฉด ๋˜๊ธฐ๋•Œ๋ฌธ์—,
        // ๋ฐ‘์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ํ•„์š”๊ฐ€ ์—†๋‹ค.
        if(!photonView.AmOwner) // ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ๊ฒฝ์šฐ.
        {
            return;
        }

        Launch();
    }

    private void Launch()
    {
        if (!photonView.AmOwner)
        {
            return;
        }

        float x = Random.Range(0, 2) == 0 ? -1 : 1;
        float y = Random.Range(0, 2) == 0 ? -1 : 1;

        rigidbody.velocity = new Vector2(x* speed, y* speed);
    }

    public void Reset()
    {
        rigidbody.velocity = Vector2.zero;
        transform.position = Vector2.zero;
        Invoke("Launch", 1);
        // Launch();
    }
	
    // IPunObservable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ.
    // ์šฐ๋ฆฌ๋งŒ์˜ ๋™๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
    	// ํ˜ธ์ŠคํŠธ์—ฌ์„œ ์ •๋ณด๋ฅผ ์“ฐ๋Š”(Write) ๊ฒฝ์šฐ๋Š” ๊ณ„์† ์ •๋ณด๋ฅผ ์ฃผ๊ธฐ๋งŒ ํ•œ๋‹ค.
        if (stream.IsWriting)
        {
            stream.SendNext(rigidbody.position);
            stream.SendNext(rigidbody.velocity);
        }
        else // ๋ฐ›๋Š”๊ฒฝ์šฐ, ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ์ •๋ณด๋ฅผ ๋ฐ›๊ธฐ๋งŒ ํ•œ๋‹ค.
        {
        	// ์œ„์—์„œ ์ฃผ๋Š” ์ˆœ์„œ๋Œ€๋กœ ๋ฐ›์•„์•ผํ•œ๋‹ค.
            // ReceiveNext() ๋Š” objectํ˜•์‹, ๋ชจ๋“  ์• ๋“ค์˜ ์ตœ์ƒ์œ„ ํด๋ž˜์Šค์ด๊ธฐ์—
            // Vector2๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.
            rigidbody.position = (Vector2)stream.ReceiveNext();
            rigidbody.velocity = (Vector2)stream.ReceiveNext();
        }
    }
}

Goal.cs ์ˆ˜์ •

private void OnTriggerEnter2D(Collider2D collision)
{
    if(collision.name.Contains("Ball"))
    {
        if(isPlayer1Goal)
'''์ƒ๋žต

GameManager.cs ์ˆ˜์ •

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviourPunCallbacks
{
    [Header("Ball")]
    public Ball ball;

    [Header("Player 1")]
    public Paddle player1Paddle;
    public Goal player1Goal;

    [Header("Player 2")]
    public Paddle player2Paddle;
    public Goal player2Goal;

    [Header("UI")]
    public TextMeshProUGUI player1Text;
    public TextMeshProUGUI player2Text;

    private int player1Score;
    private int player2Score;

    private void Start()
    {
        SpawnPaddle(); // ๋ชจ๋‘ ํŒจ๋“ค ์ƒ์„ฑ
        if(photonView.AmOwner) // ์˜ค๋„ˆ์ธ(๋ฐฉ์ฃผ์ธ) ๊ฒฝ์šฐ๋งŒ ๋ณผ ์ƒ์„ฑ
            SpawnBall();
    }

    private void SpawnPaddle()
    {
        int idx = PhotonNetwork.LocalPlayer.ActorNumber; // ActorNumber : ๋ฒˆํ˜ธ
        GameObject prefab = Resources.Load<GameObject>("Paddle");

        if(idx == 1)
        {
        	// Instantiate์•ž์— PhotonNetwork๋ฅผ ๋ถ™์—ฌ์ค˜์•ผ ๋‚˜๋งŒ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ.
            // ๊ฒŒ์ž„ ์ž์ฒด์— ์ƒ์„ฑํ•˜์—ฌ ๋‹ค๋ฅธ ์œ ์ €๋“ค๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅ.
            PhotonNetwork.Instantiate(prefab.name, new Vector3(-12, 0, 0), Quaternion.identity);
        }
        else
        {
            PhotonNetwork.Instantiate(prefab.name, new Vector3(12, 0, 0), Quaternion.identity);
        }
    }

    private void SpawnBall()
    {
        GameObject prefab = Resources.Load<GameObject>("Ball");
        GameObject go = PhotonNetwork.Instantiate(prefab.name, Vector3.zero, Quaternion.identity);
        ball = go.GetComponent<Ball>();

    }


    public void Player1Scored()
    {
        if (photonView.AmOwner)
        {
            player1Score++;
            ResetPosition();
            // (๋ฉ”์„œ๋“œ ์ด๋ฆ„, ๋ˆ„๊ตฌ ์—๊ฒŒ?, ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณด๋‚ผ ๋งค๊ฐœ๋ณ€์ˆ˜)
            photonView.RPC("UpdateScore", RpcTarget.All, player1Score, player2Score);
        }
    }

    public void Player2Scored()
    {
        if (photonView.AmOwner)
        {
            player2Score++;
            ResetPosition();
            photonView.RPC("UpdateScore", RpcTarget.All, player1Score, player2Score);
        }
    }
    

    [PunRPC] // ์ฃผ๊ธฐ๊ฐ€ ๊ธด, ์ž์ฃผ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”
    public void UpdateScore(int score1, int score2)
    {
        player1Text.text = score1.ToString();
        player2Text.text = score2.ToString();

        if (score1 > 5 || score2 > 5)
            PhotonNetwork.LeaveRoom();
    }

    private void ResetPosition()
    {
        ball.Reset();
    }

    public override void OnLeftRoom()
    {
    	// ๋‚˜๊ฐ€๋Š” ๊ฒฝ์šฐ๋Š” ๊ฐ์ž ์•Œ์•„์„œ ๋‚˜๊ฐ€๋Š” ๊ฒƒ์ด๊ฐ€ ๋•Œ๋ฌธ์—,
        // PhotonNetwork ์ด ์•„๋‹Œ SceneManager์‚ฌ์šฉ.
        SceneManager.LoadScene("LobbyScene");
    }


}

LobbyMainPanel.cs ์ˆ˜์ •

''' ์ƒ๋žต
private void Start()
{
    if (PhotonNetwork.NetworkClientState == ClientState.Joined) // ์ด๋ฏธ ์ ‘์†ํ•œ ์ƒํƒœ๋ผ๋ฉด
        this.SetActivePanel(SelectionPanel.name);
}

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