GameController.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. namespace Oculus.Platform.Samples.VrBoardGame
  2. {
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. // This is the primary class that implements the game logic.
  6. public class GameController : MonoBehaviour
  7. {
  8. // instance of the object interfacing with the matchmaking service
  9. [SerializeField] private MatchmakingManager m_matchmaking = null;
  10. [SerializeField] private GameBoard m_board = null;
  11. [SerializeField] private GamePiece m_pieceA = null;
  12. [SerializeField] private GamePiece m_pieceB = null;
  13. [SerializeField] private GamePiece m_powerPiece = null;
  14. // colors for the various states of the selectable games pieces
  15. [SerializeField] private Color m_unusableColor = Color.white;
  16. [SerializeField] private Color m_unselectedColor = Color.white;
  17. [SerializeField] private Color m_selectedColor = Color.white;
  18. [SerializeField] private Color m_highlightedColor = Color.white;
  19. [SerializeField] private Text m_ballCountText = null;
  20. [SerializeField] private Text m_player0Text = null;
  21. [SerializeField] private Text m_player1Text = null;
  22. private enum GameState {
  23. None,
  24. PracticingMyTurn, PracticingAiTurn,
  25. OnlineMatchMyTurn, OnlineMatchRemoteTurn
  26. }
  27. private GameState m_state;
  28. // the game piece the player is currently looking at
  29. private GamePiece m_interestedPiece;
  30. // the piece the player selected with the Fire button
  31. private GamePiece m_selectedPiece;
  32. // the piece that would be placed if the player pressed the Fire button
  33. private GamePiece m_proposedPiece;
  34. // how many IAP power-balls the user has
  35. private uint m_powerBallcount;
  36. // the name of the current opponent
  37. private string m_opponentName;
  38. void Start()
  39. {
  40. TransitionToState(GameState.None);
  41. UpdateScores();
  42. }
  43. void Update()
  44. {
  45. PerFrameStateUpdate();
  46. }
  47. #region Game State
  48. private void TransitionToState(GameState state)
  49. {
  50. m_state = state;
  51. UpdateGamePieceColors();
  52. }
  53. private void TransitionToNextState()
  54. {
  55. if (!m_board.IsFull())
  56. {
  57. switch (m_state)
  58. {
  59. case GameState.PracticingAiTurn:
  60. TransitionToState(GameState.PracticingMyTurn);
  61. break;
  62. case GameState.PracticingMyTurn:
  63. TransitionToState(GameState.PracticingAiTurn);
  64. break;
  65. case GameState.OnlineMatchRemoteTurn:
  66. TransitionToState(GameState.OnlineMatchMyTurn);
  67. break;
  68. case GameState.OnlineMatchMyTurn:
  69. TransitionToState(GameState.OnlineMatchRemoteTurn);
  70. break;
  71. }
  72. }
  73. else
  74. {
  75. switch (m_state)
  76. {
  77. case GameState.OnlineMatchRemoteTurn:
  78. case GameState.OnlineMatchMyTurn:
  79. m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
  80. break;
  81. }
  82. TransitionToState(GameState.None);
  83. }
  84. }
  85. private void PerFrameStateUpdate()
  86. {
  87. switch (m_state)
  88. {
  89. case GameState.PracticingAiTurn:
  90. // don't move immediately to give the AI time to 'think'
  91. if (Random.Range(1, 100) < 3)
  92. {
  93. MakeAIMove(1);
  94. }
  95. break;
  96. case GameState.PracticingMyTurn:
  97. case GameState.OnlineMatchMyTurn:
  98. if (Input.GetButton("Fire1"))
  99. {
  100. TrySelectPiece();
  101. TryPlacePiece();
  102. }
  103. break;
  104. }
  105. }
  106. #endregion
  107. #region Practicing with an AI Player
  108. public void PracticeButtonPressed()
  109. {
  110. m_opponentName = "* AI *";
  111. switch (m_state)
  112. {
  113. case GameState.OnlineMatchMyTurn:
  114. case GameState.OnlineMatchRemoteTurn:
  115. m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
  116. break;
  117. }
  118. m_board.Reset();
  119. // randomly decised whether the player or AI goes first
  120. if (Random.Range(0, 2) == 1)
  121. {
  122. TransitionToState(GameState.PracticingMyTurn);
  123. }
  124. else
  125. {
  126. TransitionToState(GameState.PracticingAiTurn);
  127. }
  128. UpdateScores();
  129. }
  130. private void MakeAIMove(int player)
  131. {
  132. bool moved = false;
  133. // pick a random search start position
  134. int rx = Random.Range(0, GameBoard.LENGTH_X - 1);
  135. int ry = Random.Range(0, GameBoard.LENGTH_Y - 1);
  136. // from (rx,ry) search of an available move
  137. for (int i = 0; i < GameBoard.LENGTH_X && !moved; i++)
  138. {
  139. for (int j = 0; j < GameBoard.LENGTH_Y && !moved; j++)
  140. {
  141. int x = (rx + i) % GameBoard.LENGTH_X;
  142. int y = (ry + j) % GameBoard.LENGTH_Y;
  143. // first try to place a piece on the current position
  144. if (m_board.CanPlayerMoveToPostion(x, y))
  145. {
  146. GamePiece p = Random.Range(0, 2) == 0 ? m_pieceA : m_pieceB;
  147. m_board.AddPiece(player, p.Prefab, x, y);
  148. moved = true;
  149. }
  150. // a random percentage of the time, try to powerup this position
  151. else if (m_board.CanPlayerPowerUpPosition(x, y) && Random.Range(0, 8) < 2)
  152. {
  153. m_board.AddPowerPiece(player, m_powerPiece.Prefab, x, y);
  154. moved = true;
  155. }
  156. }
  157. }
  158. if (moved)
  159. {
  160. UpdateScores();
  161. TransitionToNextState();
  162. }
  163. }
  164. #endregion
  165. #region Playing Online Match
  166. // called from the MatchmakingManager was a successly online match is made
  167. public void StartOnlineMatch (string opponentName, bool localUserGoesFirst)
  168. {
  169. m_board.Reset();
  170. m_opponentName = opponentName;
  171. if (localUserGoesFirst)
  172. {
  173. TransitionToState(GameState.OnlineMatchMyTurn);
  174. }
  175. else
  176. {
  177. TransitionToState(GameState.OnlineMatchRemoteTurn);
  178. }
  179. UpdateScores();
  180. }
  181. // called from the Matchmaking Manager when the remote users their next move
  182. public void MakeRemoteMove(GamePiece.Piece piece, int x, int y)
  183. {
  184. GameObject prefab = m_pieceA.PrefabFor(piece);
  185. if (piece == GamePiece.Piece.PowerBall)
  186. {
  187. m_board.AddPowerPiece(1, prefab, x, y);
  188. }
  189. else
  190. {
  191. m_board.AddPiece(1, prefab, x, y);
  192. }
  193. UpdateScores();
  194. }
  195. // called from the MatchmakingManager when the local user becomes the room
  196. // owner and thus it's safe for the local user to make their move
  197. public void MarkRemoteTurnComplete()
  198. {
  199. if (m_state == GameState.OnlineMatchRemoteTurn)
  200. {
  201. TransitionToNextState();
  202. }
  203. }
  204. // the match ended from a player leaving before the board was complete
  205. public void RemoteMatchEnded()
  206. {
  207. m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
  208. }
  209. #endregion
  210. #region Selecting and Placing a Game Place
  211. public void StartedLookingAtPiece(GamePiece piece)
  212. {
  213. m_interestedPiece = piece;
  214. UpdateGamePieceColors();
  215. }
  216. public void StoppedLookingAtPiece()
  217. {
  218. m_interestedPiece = null;
  219. UpdateGamePieceColors();
  220. }
  221. // This method is used to display an example piece where the player is looking
  222. // so they know what to expect when they press the Fire button.
  223. public void StartedLookingAtPosition(BoardPosition position)
  224. {
  225. if (m_state != GameState.OnlineMatchMyTurn && m_state != GameState.PracticingMyTurn)
  226. return;
  227. GamePiece newPiece = null;
  228. if ((m_selectedPiece == m_pieceA || m_selectedPiece == m_pieceB) &&
  229. m_board.CanPlayerMoveToPostion(position.x, position.y))
  230. {
  231. newPiece = m_board.AddProposedPiece(m_selectedPiece.Prefab, position);
  232. }
  233. else if (m_selectedPiece == m_powerPiece &&
  234. m_board.CanPlayerPowerUpPosition(position.x, position.y))
  235. {
  236. newPiece = m_board.AddProposedPowerPiece(m_selectedPiece.Prefab, position);
  237. }
  238. if (newPiece != null)
  239. {
  240. if (m_proposedPiece != null)
  241. {
  242. Destroy(m_proposedPiece.gameObject);
  243. }
  244. m_proposedPiece = newPiece;
  245. }
  246. }
  247. public void ClearProposedMove()
  248. {
  249. if (m_proposedPiece != null)
  250. {
  251. Destroy(m_proposedPiece.gameObject);
  252. }
  253. }
  254. public void TrySelectPiece()
  255. {
  256. if (m_interestedPiece == m_pieceA || m_interestedPiece == m_pieceB)
  257. {
  258. m_selectedPiece = m_interestedPiece;
  259. }
  260. else if (m_interestedPiece == m_powerPiece &&
  261. (m_powerBallcount > 0 || m_state == GameState.PracticingMyTurn))
  262. {
  263. m_selectedPiece = m_interestedPiece;
  264. }
  265. UpdateGamePieceColors();
  266. }
  267. public void TryPlacePiece()
  268. {
  269. if (m_proposedPiece == null)
  270. return;
  271. var position = m_proposedPiece.Position;
  272. switch(m_proposedPiece.Type)
  273. {
  274. case GamePiece.Piece.A:
  275. case GamePiece.Piece.B:
  276. m_board.AddPiece(0, m_proposedPiece.Prefab, position.x, position.y);
  277. break;
  278. case GamePiece.Piece.PowerBall:
  279. m_board.AddPowerPiece(0, m_proposedPiece.Prefab, position.x, position.y);
  280. break;
  281. }
  282. Destroy(m_proposedPiece.gameObject);
  283. if (m_state == GameState.OnlineMatchMyTurn)
  284. {
  285. m_matchmaking.SendLocalMove(m_proposedPiece.Type, position.x, position.y);
  286. }
  287. UpdateScores();
  288. TransitionToNextState();
  289. }
  290. #endregion
  291. #region UI
  292. public void QuitButtonPressed()
  293. {
  294. UnityEngine.Application.Quit();
  295. }
  296. public void AddPowerballs(uint count)
  297. {
  298. m_powerBallcount += count;
  299. m_ballCountText.text = "x" + m_powerBallcount.ToString();
  300. }
  301. private void UpdateScores()
  302. {
  303. m_player0Text.text = string.Format("{0}\n\n{1}",
  304. PlatformManager.MyOculusID, m_board.GetPlayerScore(0));
  305. m_player1Text.text = string.Format("{0}\n\n{1}",
  306. m_opponentName, m_board.GetPlayerScore(1));
  307. }
  308. private void UpdateGamePieceColors()
  309. {
  310. switch (m_state)
  311. {
  312. case GameState.None:
  313. case GameState.PracticingAiTurn:
  314. case GameState.OnlineMatchRemoteTurn:
  315. m_pieceA.GetComponent<Renderer>().material.color = m_unusableColor;
  316. m_pieceB.GetComponent<Renderer>().material.color = m_unusableColor;
  317. m_powerPiece.GetComponent<Renderer>().material.color = m_unusableColor;
  318. if (m_proposedPiece != null)
  319. {
  320. Destroy(m_proposedPiece.gameObject);
  321. }
  322. break;
  323. case GameState.PracticingMyTurn:
  324. case GameState.OnlineMatchMyTurn:
  325. m_pieceA.GetComponent<Renderer>().material.color = m_unselectedColor;
  326. m_pieceB.GetComponent<Renderer>().material.color = m_unselectedColor;
  327. m_powerPiece.GetComponent<Renderer>().material.color = m_unselectedColor;
  328. if (m_interestedPiece == m_pieceA || m_interestedPiece == m_pieceB ||
  329. m_interestedPiece == m_powerPiece)
  330. {
  331. m_interestedPiece.GetComponent<Renderer>().material.color = m_highlightedColor;
  332. }
  333. if (m_selectedPiece != null)
  334. {
  335. m_selectedPiece.GetComponent<Renderer>().material.color = m_selectedColor;
  336. }
  337. break;
  338. }
  339. }
  340. #endregion
  341. }
  342. }