You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
20 KiB

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using UnityEngine.SceneManagement;
  6. using Networking.Server;
  7. public class Character : MonoBehaviour
  8. {
  9. public string nextScene;
  10. Animator characterAnimator;
  11. public bool isTuteLevel = false;
  12. public bool inWater = false; //Am I in the water?
  13. public bool inPit = false; //Did I fall into a pit?
  14. public bool stuck = false; //Am I still stuck?
  15. public bool justMoved = false; //Was the logic block I just executed a move command?
  16. #region Inspector Fields
  17. [SerializeField]
  18. [Tooltip("Will move to this block at start, else will try and find a block below")]
  19. private Block _currentBlock;
  20. [SerializeField]
  21. [Tooltip("Layers to ignore when checking for blocks")]
  22. private LayerMask Ignore;
  23. [Tooltip("Current Inventory of the player")]
  24. public Inventory Inventory;
  25. public bool CloneInventoryOnStart = false;
  26. [Tooltip("How many lives to start out with")]
  27. public int lives = 5;
  28. [SerializeField]
  29. [Tooltip("Character to display")]
  30. private string CharacterModel = "Bear";
  31. [SerializeField]
  32. public ClientData ClientLink;
  33. [SerializeField]
  34. private TMPro.TextMeshPro BlockTitlePrefab;
  35. #endregion Inspector Fields
  36. #region Read Only
  37. public Block CurrentBlock { get { return _currentBlock; } }
  38. #endregion Read Only
  39. #region Unity Functions
  40. private void Start()
  41. {
  42. if (Inventory != null && CloneInventoryOnStart)
  43. Inventory = Inventory.Clone(Inventory);
  44. //If no starting block find one below it
  45. if (_currentBlock == null)
  46. Block.isBlockAtPosition(transform.position + Vector3.down / 2, 1, ~Ignore, out _currentBlock);
  47. //move to starting block
  48. transform.position = _currentBlock.VisualPosition;
  49. //get character string from player replace from "Bear"
  50. GameObject prefab = Resources.Load(CharacterModel) as GameObject;
  51. GameObject animal = Instantiate(prefab, this.gameObject.transform);
  52. characterAnimator = GetComponentInChildren<Animator>();
  53. }
  54. #endregion Unity Functions
  55. #region Class Implementation
  56. public void Initialise(Block startingBlock, Inventory inventory, string Character)
  57. {
  58. _currentBlock = startingBlock;
  59. Inventory = inventory;
  60. CharacterModel = Character;
  61. }
  62. public void DisplayBlock(LogicBlock block)
  63. {
  64. if(isTuteLevel == false){
  65. if (BlockTitlePrefab == null)
  66. return;
  67. TMPro.TextMeshPro temp = Instantiate(BlockTitlePrefab.gameObject).GetComponent<TMPro.TextMeshPro>();
  68. temp.text = block.DisplayName;
  69. temp.color = ClientLink.Color;
  70. temp.transform.position = transform.position + (Vector3.one * 0.25f);
  71. temp.transform.rotation = Quaternion.LookRotation(temp.transform.position - Camera.main.transform.position);
  72. }
  73. }
  74. public Vector3 yValue(float time, float heightMultiplier)
  75. {
  76. float y = Mathf.Sin((Mathf.PI * time)) * heightMultiplier;
  77. return new Vector3(0, y, 0);
  78. }
  79. IEnumerator JumpCoroutine(Block Target, Transform Current, float time, float heightMax)
  80. {
  81. float elapsedTime = 0;
  82. Vector3 startPosition = Current.position;
  83. time *= 0.8f;
  84. characterAnimator.Play("Jump Inplace");
  85. yield return new WaitForSeconds(0.15f);
  86. while (elapsedTime < time)
  87. {
  88. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  89. transform.position += yValue((elapsedTime / time), heightMax);
  90. yield return new WaitForEndOfFrame();
  91. elapsedTime += Time.deltaTime;
  92. }
  93. transform.position = Target.VisualPosition;
  94. }
  95. IEnumerator MoveCoroutine(Block Target, Transform Current, float time, float heightMax)
  96. {
  97. float elapsedTime = 0;
  98. Vector3 startPosition = Current.position;
  99. time *= 0.8f;
  100. characterAnimator.Play("Walk");
  101. yield return new WaitForSeconds(0.05f);
  102. while (elapsedTime < time)
  103. {
  104. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  105. yield return new WaitForEndOfFrame();
  106. elapsedTime += Time.deltaTime;
  107. }
  108. transform.position = Target.VisualPosition;
  109. }
  110. IEnumerator MoveConveyorForwardCoroutine(Block Target, Transform Current, float time, float heightMax)
  111. {
  112. float elapsedTime = 0;
  113. Vector3 startPosition = Current.position;
  114. Vector3 charEndPosition = new Vector3(Current.position.x + 1.0f, Current.position.y, Current.position.z);
  115. time *= 0.8f;
  116. yield return new WaitForSeconds(0.05f);
  117. while (elapsedTime < time)
  118. {
  119. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  120. yield return new WaitForEndOfFrame();
  121. elapsedTime += Time.deltaTime;
  122. }
  123. Current.position = charEndPosition;
  124. }
  125. IEnumerator MoveConveyorBackwardCoroutine(Block Target, Transform Current, float time, float heightMax)
  126. {
  127. float elapsedTime = 0;
  128. Vector3 startPosition = Current.position;
  129. Vector3 charEndPosition = new Vector3(Current.position.x - 1.0f, Current.position.y, Current.position.z);
  130. time *= 0.8f;
  131. yield return new WaitForSeconds(0.05f);
  132. while (elapsedTime < time)
  133. {
  134. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  135. yield return new WaitForEndOfFrame();
  136. elapsedTime += Time.deltaTime;
  137. }
  138. Current.position = charEndPosition;
  139. }
  140. IEnumerator MoveConveyorLeftCoroutine(Block Target, Transform Current, float time, float heightMax)
  141. {
  142. float elapsedTime = 0;
  143. Vector3 startPosition = Current.position;
  144. Vector3 charEndPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z + 1.0f);
  145. time *= 0.8f;
  146. yield return new WaitForSeconds(0.05f);
  147. while (elapsedTime < time)
  148. {
  149. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  150. yield return new WaitForEndOfFrame();
  151. elapsedTime += Time.deltaTime;
  152. }
  153. Current.position = charEndPosition;
  154. }
  155. IEnumerator MoveConveyorRightCoroutine(Block Target, Transform Current, float time, float heightMax)
  156. {
  157. float elapsedTime = 0;
  158. Vector3 startPosition = Current.position;
  159. Vector3 charEndPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z - 1.0f);
  160. time *= 0.8f;
  161. yield return new WaitForSeconds(0.05f);
  162. while (elapsedTime < time)
  163. {
  164. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  165. yield return new WaitForEndOfFrame();
  166. elapsedTime += Time.deltaTime;
  167. }
  168. Current.position = charEndPosition;
  169. }
  170. IEnumerator PushLeftCoroutine(Transform Current, float time)
  171. {
  172. float elapsedTime = 0;
  173. Vector3 startPosition = Current.transform.position;
  174. Vector3 endPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z - 1.0f);
  175. time *= 0.8f;
  176. yield return new WaitForSeconds(0.05f);
  177. while (elapsedTime < time)
  178. {
  179. Current.position = Vector3.Lerp(startPosition, endPosition, (elapsedTime / time));
  180. yield return new WaitForEndOfFrame();
  181. elapsedTime += Time.deltaTime;
  182. }
  183. Current.position = endPosition;
  184. }
  185. IEnumerator PushRightCoroutine(Transform Current, float time)
  186. {
  187. float elapsedTime = 0;
  188. Vector3 startPosition = Current.transform.position;
  189. Vector3 endPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z + 1.0f);
  190. time *= 0.8f;
  191. yield return new WaitForSeconds(0.05f);
  192. while (elapsedTime < time)
  193. {
  194. Current.position = Vector3.Lerp(startPosition, endPosition, (elapsedTime / time));
  195. yield return new WaitForEndOfFrame();
  196. elapsedTime += Time.deltaTime;
  197. }
  198. Current.position = endPosition;
  199. }
  200. IEnumerator MoveDownCoroutine(Block Target, Transform Current, float time, float heightMax)
  201. {
  202. float elapsedTime = 0;
  203. Vector3 startPosition = Current.position;
  204. time *= 0.8f;
  205. characterAnimator.Play("Walk");
  206. while (elapsedTime < time)
  207. {
  208. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  209. transform.position += yValue((elapsedTime / time), heightMax);
  210. yield return new WaitForEndOfFrame();
  211. elapsedTime += Time.deltaTime;
  212. }
  213. transform.position = Target.VisualPosition;
  214. }
  215. IEnumerator rotateCoroutine(Direction direction, Transform Current, float time, float heightMax)
  216. {
  217. float elapsedTime = 0;
  218. time *= 0.8f;
  219. Vector3 endDirection = direction.ToVector(Current);
  220. Vector3 startDirection = Current.forward;
  221. Vector3 startPosition = transform.position;
  222. while (elapsedTime < time)
  223. {
  224. characterAnimator.Play("Jump");
  225. transform.forward = Vector3.Slerp(startDirection, endDirection, (elapsedTime / time));
  226. yield return new WaitForEndOfFrame();
  227. elapsedTime += Time.deltaTime;
  228. }
  229. transform.forward = endDirection;
  230. }
  231. /// <summary>
  232. /// Moves one block in specefied direction, Can walk off obstacles
  233. /// </summary>
  234. /// <param name="direction">direction to walk</param>
  235. /// <remarks>Technically is same as JumpLong(1) but kept seperate to avoid confusion</remarks>
  236. public void Move(Direction direction, float speed)
  237. {
  238. //setting up variables
  239. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  240. Block hit; //output of block detection
  241. Block moveTo = _currentBlock; //block we'll actually move to
  242. //if move is obstucted no where to move
  243. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  244. return;
  245. //If block at Position is walkable set it to moveTo
  246. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  247. {
  248. moveTo = hit;
  249. _currentBlock = moveTo;
  250. StartCoroutine(MoveCoroutine(_currentBlock, transform, speed, 0.3f));
  251. }
  252. //else if block down one is walkable
  253. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  254. {
  255. moveTo = hit;
  256. _currentBlock = moveTo;
  257. StartCoroutine(MoveDownCoroutine(_currentBlock, transform, speed, 0.3f));
  258. }
  259. //set current block && move
  260. //CurrentBlock = moveTo;
  261. //StartCoroutine(MoveCoroutine(CurrentBlock, transform, speed, 0.3f));
  262. //transform.position = CurrentBlock.VisualPosition;
  263. }
  264. public void conveyorMoveForward(Direction direction, float speed)
  265. {
  266. StartCoroutine(MoveConveyorForwardCoroutine(_currentBlock, transform, speed, 0.3f));
  267. }
  268. public void conveyorMoveBackward(Direction direction, float speed)
  269. {
  270. StartCoroutine(MoveConveyorBackwardCoroutine(_currentBlock, transform, speed, 0.3f));
  271. }
  272. public void conveyorMoveLeft(Direction direction, float speed)
  273. {
  274. StartCoroutine(MoveConveyorLeftCoroutine(_currentBlock, transform, speed, 0.3f));
  275. }
  276. public void conveyorMoveRight(Direction direction, float speed)
  277. {
  278. StartCoroutine(MoveConveyorRightCoroutine(_currentBlock, transform, speed, 0.3f));
  279. }
  280. public void CannonRMove(float speed)
  281. {
  282. StartCoroutine(PushRightCoroutine(transform, speed));
  283. }
  284. public void CannonLMove(float speed)
  285. {
  286. StartCoroutine(PushLeftCoroutine(transform, speed));
  287. }
  288. public void respawnCharacter()
  289. {
  290. /* Will introduce more complex criteria for choosing where to respawn the player in future
  291. * For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
  292. * Otherwise, try the next square back, etc, until we find an available one
  293. */
  294. Block currentBlock = null;
  295. //We start from the position of our pit, at ground level
  296. Vector3 currentPos = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z);
  297. Debug.Log("Commencing respawn");
  298. //Hardcoding the number of iterations for now for simplicity, should change this later
  299. for (int i = 0; i < 100; i++)
  300. {
  301. //First we check one back
  302. currentPos.x -= 1;
  303. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  304. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  305. {
  306. Debug.Log("Block exists");
  307. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  308. {
  309. Debug.Log("Block is walkable");
  310. //Don't yet have a check for whether it's occupied
  311. break; //If it is, we stop here
  312. }
  313. }
  314. //If the block one back isn't an option, we check to the left and right
  315. currentPos.z += 1;
  316. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  317. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  318. {
  319. Debug.Log("Block exists");
  320. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  321. {
  322. Debug.Log("Block is walkable");
  323. //Don't yet have a check for whether it's occupied
  324. break; //If it is, we stop here
  325. }
  326. }
  327. currentPos.z -= 2;
  328. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  329. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  330. {
  331. Debug.Log("Block exists");
  332. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  333. {
  334. Debug.Log("Block is walkable");
  335. //Don't yet have a check for whether it's occupied
  336. break; //If it is, we stop here
  337. }
  338. }
  339. //If we've gotten this far and haven't found an available spot, we move back a row and try again
  340. currentPos.z += 1;
  341. }
  342. //Having found our target block, we move the character there
  343. if (currentBlock != null)
  344. {
  345. this.transform.position = currentBlock.VisualPosition;
  346. this.inPit = false;
  347. this._currentBlock = currentBlock;
  348. Debug.Log("Moved " + this.name + " to "
  349. + this.transform.position.x + ", "
  350. + this.transform.position.y + ", "
  351. + this.transform.position.z + ", "
  352. + " inPit = " + inPit);
  353. }
  354. else
  355. {
  356. Debug.Log("Failed to find anywhere to put " + this.name);
  357. }
  358. }
  359. /// <summary>
  360. /// Upon collision with a floating block, collect its
  361. /// Upon collision with the end portal, end of level
  362. /// </summary>
  363. /// <param name="other">name of collided object</param>
  364. void OnTriggerEnter(Collider other)
  365. {
  366. Collectable collectable = other.GetComponentInChildren<Collectable>();
  367. if (collectable != null)
  368. {
  369. collectable.OnCollect(this);
  370. }
  371. if (other.gameObject.name == "collect_sphere")
  372. {
  373. other.gameObject.SetActive(false);
  374. //player.collected +=1;
  375. }
  376. if (other.gameObject.name == "End Portal")
  377. {
  378. other.GetComponent<Collider>().enabled = false;
  379. SceneManager.LoadScene(nextScene);
  380. }
  381. }
  382. /// <summary>
  383. /// Rotates to point in specific direction based on current direction
  384. /// </summary>
  385. /// <param name="direction">Local direction to point</param>
  386. public void Rotate(Direction direction, float speed)
  387. {
  388. StartCoroutine(rotateCoroutine(direction, transform, speed, 0.15f));
  389. //transform.forward = direction.ToVector(transform);
  390. }
  391. /// <summary>
  392. /// Jumps in specefied direction, picks between Long Jump and Jumping up
  393. /// </summary>
  394. /// <param name="direction">Direction to Jump</param>
  395. public void Jump(Direction direction, float speed)
  396. {
  397. //if there is a block infront JumpUp else LongJump
  398. if (Block.isBlockAtPosition(_currentBlock.position + direction.ToVector(transform) + Vector3.up, 1, ~Ignore))
  399. JumpUp(direction, speed);
  400. else
  401. JumpLong(direction, speed);
  402. }
  403. #endregion Class Implementation
  404. #region Private Functions
  405. /// <summary>
  406. /// Jumps up obstacle of specific height. Jumps as high as possible
  407. /// </summary>
  408. /// <param name="direction">Direction of obstacle</param>
  409. /// <param name="height">max height</param>
  410. private void JumpUp(Direction direction, float speed, int height = 1)
  411. {
  412. //setting up variables
  413. Vector3 position; // position wanted
  414. Block hit; //output of block detection
  415. Block moveTo = _currentBlock; //block we'll actually move to
  416. //Check blocks in going up then move to the heighest walkable one
  417. for (int i = 0; i <= height; i++)
  418. {
  419. //next position up the tower
  420. position = _currentBlock.position + direction.ToVector(transform) + (Vector3.up * i);
  421. //if block is walkable set it to last known position
  422. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  423. moveTo = hit;
  424. }
  425. //set current block && move
  426. _currentBlock = moveTo;
  427. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  428. //transform.position = CurrentBlock.VisualPosition;
  429. }
  430. /// <summary>
  431. /// Long jumps forward a specified distance. Can Jump gaps. Stops at obstruction
  432. /// </summary>
  433. /// <param name="direction">Direction to Jump</param>
  434. /// <param name="Distance">Max distance</param>
  435. private void JumpLong(Direction direction, float speed, int Distance = 2)
  436. {
  437. //setting up variables
  438. Vector3 position; // position wanted
  439. Block hit; //output of block detection
  440. Block moveTo = _currentBlock; //block we'll actually move to
  441. //Check blocks in front until we hit an obstruction or went the distance
  442. for (int i = 1; i <= Distance; i++)
  443. {
  444. //Next position to MoveTo
  445. position = _currentBlock.position + (direction.ToVector(transform) * i);
  446. //if jump is obstructed, stop and go to last known block
  447. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  448. break;
  449. //If block at Position is walkable set it to last known position
  450. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  451. moveTo = hit;
  452. //else if block down one is walkable
  453. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  454. moveTo = hit;
  455. }//end for
  456. //Set Current Block and move
  457. _currentBlock = moveTo;
  458. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  459. //transform.position = CurrentBlock.VisualPosition;
  460. }
  461. #endregion Private Functions
  462. }