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.

597 lines
23 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 = 3;
  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. private void Update()
  55. {
  56. if(lives < 1)
  57. {
  58. this.enabled = false;
  59. gameObject.SetActive(false);
  60. }
  61. }
  62. #endregion Unity Functions
  63. #region Class Implementation
  64. public void Initialise(Block startingBlock, Inventory inventory, string Character)
  65. {
  66. _currentBlock = startingBlock;
  67. Inventory = inventory;
  68. CharacterModel = Character;
  69. }
  70. public void DisplayBlock(LogicBlock block)
  71. {
  72. if(isTuteLevel == false){
  73. if (BlockTitlePrefab == null)
  74. return;
  75. TMPro.TextMeshPro temp = Instantiate(BlockTitlePrefab.gameObject).GetComponent<TMPro.TextMeshPro>();
  76. temp.text = block.DisplayName;
  77. temp.color = ClientLink.Color;
  78. temp.transform.position = transform.position + (Vector3.one * 0.25f);
  79. temp.transform.rotation = Quaternion.LookRotation(temp.transform.position - Camera.main.transform.position);
  80. }
  81. }
  82. public Vector3 yValue(float time, float heightMultiplier)
  83. {
  84. float y = Mathf.Sin((Mathf.PI * time)) * heightMultiplier;
  85. return new Vector3(0, y, 0);
  86. }
  87. IEnumerator JumpCoroutine(Block Target, Transform Current, float time, float heightMax)
  88. {
  89. float elapsedTime = 0;
  90. Vector3 startPosition = Current.position;
  91. time *= 0.8f;
  92. characterAnimator.Play("Jump Inplace");
  93. yield return new WaitForSeconds(0.15f);
  94. while (elapsedTime < time)
  95. {
  96. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  97. transform.position += yValue((elapsedTime / time), heightMax);
  98. yield return new WaitForEndOfFrame();
  99. elapsedTime += Time.deltaTime;
  100. }
  101. transform.position = Target.VisualPosition;
  102. }
  103. IEnumerator MoveCoroutine(Block Target, Transform Current, float time, float heightMax)
  104. {
  105. float elapsedTime = 0;
  106. Vector3 startPosition = Current.position;
  107. time *= 0.8f;
  108. characterAnimator.Play("Walk");
  109. yield return new WaitForSeconds(0.05f);
  110. while (elapsedTime < time)
  111. {
  112. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  113. yield return new WaitForEndOfFrame();
  114. elapsedTime += Time.deltaTime;
  115. }
  116. transform.position = Target.VisualPosition;
  117. }
  118. IEnumerator MoveConveyorForwardCoroutine(Block Target, Transform Current, float time, float heightMax)
  119. {
  120. float elapsedTime = 0;
  121. Vector3 startPosition = Current.position;
  122. Vector3 charEndPosition = new Vector3(Current.position.x + 1.0f, Current.position.y, Current.position.z);
  123. time *= 0.8f;
  124. yield return new WaitForSeconds(0.05f);
  125. while (elapsedTime < time)
  126. {
  127. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  128. yield return new WaitForEndOfFrame();
  129. elapsedTime += Time.deltaTime;
  130. }
  131. Current.position = charEndPosition;
  132. }
  133. IEnumerator MoveConveyorBackwardCoroutine(Block Target, Transform Current, float time, float heightMax)
  134. {
  135. float elapsedTime = 0;
  136. Vector3 startPosition = Current.position;
  137. Vector3 charEndPosition = new Vector3(Current.position.x - 1.0f, Current.position.y, Current.position.z);
  138. time *= 0.8f;
  139. yield return new WaitForSeconds(0.05f);
  140. while (elapsedTime < time)
  141. {
  142. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  143. yield return new WaitForEndOfFrame();
  144. elapsedTime += Time.deltaTime;
  145. }
  146. Current.position = charEndPosition;
  147. }
  148. IEnumerator MoveConveyorLeftCoroutine(Block Target, Transform Current, float time, float heightMax)
  149. {
  150. float elapsedTime = 0;
  151. Vector3 startPosition = Current.position;
  152. Vector3 charEndPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z + 1.0f);
  153. time *= 0.8f;
  154. yield return new WaitForSeconds(0.05f);
  155. while (elapsedTime < time)
  156. {
  157. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  158. yield return new WaitForEndOfFrame();
  159. elapsedTime += Time.deltaTime;
  160. }
  161. Current.position = charEndPosition;
  162. }
  163. IEnumerator MoveConveyorRightCoroutine(Block Target, Transform Current, float time, float heightMax)
  164. {
  165. float elapsedTime = 0;
  166. Vector3 startPosition = Current.position;
  167. Vector3 charEndPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z - 1.0f);
  168. time *= 0.8f;
  169. yield return new WaitForSeconds(0.05f);
  170. while (elapsedTime < time)
  171. {
  172. Current.position = Vector3.Lerp(startPosition, charEndPosition, (elapsedTime / time));
  173. yield return new WaitForEndOfFrame();
  174. elapsedTime += Time.deltaTime;
  175. }
  176. Current.position = charEndPosition;
  177. }
  178. IEnumerator PushLeftCoroutine(Transform Current, float time)
  179. {
  180. float elapsedTime = 0;
  181. Vector3 startPosition = Current.transform.position;
  182. Vector3 endPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z + 1.0f);
  183. time *= 0.8f;
  184. yield return new WaitForSeconds(0.05f);
  185. while (elapsedTime < time)
  186. {
  187. Current.position = Vector3.Lerp(startPosition, endPosition, (elapsedTime / time));
  188. yield return new WaitForEndOfFrame();
  189. elapsedTime += Time.deltaTime;
  190. }
  191. Current.position = endPosition;
  192. }
  193. IEnumerator PushRightCoroutine(Transform Current, float time)
  194. {
  195. float elapsedTime = 0;
  196. Vector3 startPosition = Current.transform.position;
  197. Vector3 endPosition = new Vector3(Current.position.x, Current.position.y, Current.position.z - 1.0f);
  198. time *= 0.8f;
  199. yield return new WaitForSeconds(0.05f);
  200. while (elapsedTime < time)
  201. {
  202. Current.position = Vector3.Lerp(startPosition, endPosition, (elapsedTime / time));
  203. yield return new WaitForEndOfFrame();
  204. elapsedTime += Time.deltaTime;
  205. }
  206. Current.position = endPosition;
  207. }
  208. IEnumerator MoveDownCoroutine(Block Target, Transform Current, float time, float heightMax)
  209. {
  210. float elapsedTime = 0;
  211. Vector3 startPosition = Current.position;
  212. time *= 0.8f;
  213. characterAnimator.Play("Walk");
  214. while (elapsedTime < time)
  215. {
  216. transform.position = Vector3.Lerp(startPosition, Target.VisualPosition, (elapsedTime / time));
  217. transform.position += yValue((elapsedTime / time), heightMax);
  218. yield return new WaitForEndOfFrame();
  219. elapsedTime += Time.deltaTime;
  220. }
  221. transform.position = Target.VisualPosition;
  222. }
  223. IEnumerator rotateCoroutine(Direction direction, Transform Current, float time, float heightMax)
  224. {
  225. float elapsedTime = 0;
  226. time *= 0.8f;
  227. Vector3 endDirection = direction.ToVector(Current);
  228. Vector3 startDirection = Current.forward;
  229. while (elapsedTime < time)
  230. {
  231. characterAnimator.Play("Jump");
  232. transform.forward = Vector3.Slerp(startDirection, endDirection, (elapsedTime / time));
  233. yield return new WaitForEndOfFrame();
  234. elapsedTime += Time.deltaTime;
  235. }
  236. transform.forward = endDirection;
  237. }
  238. IEnumerator rotateHalfCoroutine(Direction direction, Transform Current, float time, float heightMax)
  239. {
  240. float elapsedTime = 0;
  241. time *= 0.8f;
  242. Vector3 endDirection = (direction.ToVector(Current) + Current.forward).normalized;
  243. Vector3 startDirection = Current.forward;
  244. while (elapsedTime < time)
  245. {
  246. characterAnimator.Play("Jump");
  247. transform.forward = Vector3.Slerp(startDirection, endDirection, (elapsedTime / time));
  248. yield return new WaitForEndOfFrame();
  249. elapsedTime += Time.deltaTime;
  250. }
  251. transform.forward = endDirection;
  252. }
  253. /// <summary>
  254. /// Moves one block in specefied direction, Can walk off obstacles
  255. /// </summary>
  256. /// <param name="direction">direction to walk</param>
  257. /// <remarks>Technically is same as JumpLong(1) but kept seperate to avoid confusion</remarks>
  258. public void Move(Direction direction, float speed)
  259. {
  260. //setting up variables
  261. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  262. Block hit; //output of block detection
  263. Block moveTo = _currentBlock; //block we'll actually move to
  264. //if move is obstucted no where to move
  265. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  266. return;
  267. //If block at Position is walkable set it to moveTo
  268. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  269. {
  270. moveTo = hit;
  271. _currentBlock = moveTo;
  272. StartCoroutine(MoveCoroutine(_currentBlock, transform, speed, 0.3f));
  273. }
  274. //else if block down one is walkable
  275. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  276. {
  277. moveTo = hit;
  278. _currentBlock = moveTo;
  279. StartCoroutine(MoveDownCoroutine(_currentBlock, transform, speed, 0.3f));
  280. }
  281. }
  282. public void conveyorMoveForward(Direction direction, float speed)
  283. {
  284. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  285. Block hit; //output of block detection
  286. Block moveTo = _currentBlock; //block we'll actually move to
  287. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  288. {
  289. moveTo = hit;
  290. _currentBlock = moveTo;
  291. StartCoroutine(MoveConveyorForwardCoroutine(_currentBlock, transform, speed, 0.3f));
  292. }
  293. }
  294. public void conveyorMoveBackward(Direction direction, float speed)
  295. {
  296. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  297. Block hit; //output of block detection
  298. Block moveTo = _currentBlock; //block we'll actually move to
  299. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  300. {
  301. moveTo = hit;
  302. _currentBlock = moveTo;
  303. StartCoroutine(MoveConveyorBackwardCoroutine(_currentBlock, transform, speed, 0.3f));
  304. }
  305. }
  306. public void conveyorMoveLeft(Direction direction, float speed)
  307. {
  308. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  309. Block hit; //output of block detection
  310. Block moveTo = _currentBlock; //block we'll actually move to
  311. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  312. {
  313. moveTo = hit;
  314. _currentBlock = moveTo;
  315. StartCoroutine(MoveConveyorLeftCoroutine(_currentBlock, transform, speed, 0.3f));
  316. }
  317. }
  318. public void conveyorMoveRight(Direction direction, float speed)
  319. {
  320. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  321. Block hit; //output of block detection
  322. Block moveTo = _currentBlock; //block we'll actually move to
  323. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  324. {
  325. moveTo = hit;
  326. _currentBlock = moveTo;
  327. StartCoroutine(MoveConveyorRightCoroutine(_currentBlock, transform, speed, 0.3f));
  328. }
  329. }
  330. public void CannonRMove(float speed)
  331. {
  332. Direction direction = Direction.Right;
  333. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  334. Block hit; //output of block detection
  335. Block moveTo = _currentBlock; //block we'll actually move to
  336. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  337. {
  338. moveTo = hit;
  339. _currentBlock = moveTo;
  340. StartCoroutine(PushRightCoroutine(transform, speed));
  341. }
  342. }
  343. public void CannonLMove(float speed)
  344. {
  345. Direction direction = Direction.Left;
  346. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  347. Block hit; //output of block detection
  348. Block moveTo = _currentBlock; //block we'll actually move to
  349. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  350. {
  351. moveTo = hit;
  352. _currentBlock = moveTo;
  353. StartCoroutine(PushLeftCoroutine(transform, speed));
  354. }
  355. }
  356. public void respawnCharacter()
  357. {
  358. /* Will introduce more complex criteria for choosing where to respawn the player in future
  359. * For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
  360. * Otherwise, try the next square back, etc, until we find an available one
  361. */
  362. Block currentBlock = null;
  363. //We start from the position of our pit, at ground level
  364. Vector3 currentPos = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z);
  365. Debug.Log("Commencing respawn");
  366. //Hardcoding the number of iterations for now for simplicity, should change this later
  367. for (int i = 0; i < 100; i++)
  368. {
  369. //First we check one back
  370. currentPos.x -= 1;
  371. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  372. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  373. {
  374. Debug.Log("Block exists");
  375. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  376. {
  377. Debug.Log("Block is walkable");
  378. //Don't yet have a check for whether it's occupied
  379. break; //If it is, we stop here
  380. }
  381. }
  382. //If the block one back isn't an option, we check to the left and right
  383. currentPos.z += 1;
  384. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  385. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  386. {
  387. Debug.Log("Block exists");
  388. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  389. {
  390. Debug.Log("Block is walkable");
  391. //Don't yet have a check for whether it's occupied
  392. break; //If it is, we stop here
  393. }
  394. }
  395. currentPos.z -= 2;
  396. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  397. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  398. {
  399. Debug.Log("Block exists");
  400. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  401. {
  402. Debug.Log("Block is walkable");
  403. //Don't yet have a check for whether it's occupied
  404. break; //If it is, we stop here
  405. }
  406. }
  407. //If we've gotten this far and haven't found an available spot, we move back a row and try again
  408. currentPos.z += 1;
  409. }
  410. //Having found our target block, we move the character there
  411. if (currentBlock != null)
  412. {
  413. this.transform.position = currentBlock.VisualPosition;
  414. this.inPit = false;
  415. this._currentBlock = currentBlock;
  416. Debug.Log("Moved " + this.name + " to "
  417. + this.transform.position.x + ", "
  418. + this.transform.position.y + ", "
  419. + this.transform.position.z + ", "
  420. + " inPit = " + inPit);
  421. }
  422. else
  423. {
  424. Debug.Log("Failed to find anywhere to put " + this.name);
  425. }
  426. }
  427. /// <summary>
  428. /// Upon collision with a floating block, collect its
  429. /// Upon collision with the end portal, end of level
  430. /// </summary>
  431. /// <param name="other">name of collided object</param>
  432. void OnTriggerEnter(Collider other)
  433. {
  434. Collectable collectable = other.GetComponentInChildren<Collectable>();
  435. if (collectable != null)
  436. {
  437. collectable.OnCollect(this);
  438. }
  439. if (other.gameObject.name == "collect_sphere")
  440. {
  441. other.gameObject.SetActive(false);
  442. //player.collected +=1;
  443. }
  444. if (other.gameObject.name == "End Portal")
  445. {
  446. other.GetComponent<Collider>().enabled = false;
  447. SceneManager.LoadScene(nextScene);
  448. }
  449. }
  450. /// <summary>
  451. /// Rotates to point in specific direction based on current direction
  452. /// </summary>
  453. /// <param name="direction">Local direction to point</param>
  454. public void Rotate(Direction direction, float speed)
  455. {
  456. StartCoroutine(rotateCoroutine(direction, transform, speed, 0.15f));
  457. //transform.forward = direction.ToVector(transform);
  458. }
  459. public void RotateHalf(Direction direction, float speed)
  460. {
  461. StartCoroutine(rotateHalfCoroutine(direction, transform, speed, 0.15f));
  462. //transform.forward = direction.ToVector(transform);
  463. }
  464. /// <summary>
  465. /// Jumps in specefied direction, picks between Long Jump and Jumping up
  466. /// </summary>
  467. /// <param name="direction">Direction to Jump</param>
  468. public void Jump(Direction direction, float speed)
  469. {
  470. //if there is a block infront JumpUp else LongJump
  471. if (Block.isBlockAtPosition(_currentBlock.position + direction.ToVector(transform) + Vector3.up, 1, ~Ignore))
  472. JumpUp(direction, speed);
  473. else
  474. JumpLong(direction, speed);
  475. }
  476. #endregion Class Implementation
  477. #region Private Functions
  478. /// <summary>
  479. /// Jumps up obstacle of specific height. Jumps as high as possible
  480. /// </summary>
  481. /// <param name="direction">Direction of obstacle</param>
  482. /// <param name="height">max height</param>
  483. private void JumpUp(Direction direction, float speed, int height = 1)
  484. {
  485. //setting up variables
  486. Vector3 position; // position wanted
  487. Block hit; //output of block detection
  488. Block moveTo = _currentBlock; //block we'll actually move to
  489. //Check blocks in going up then move to the heighest walkable one
  490. for (int i = 0; i <= height; i++)
  491. {
  492. //next position up the tower
  493. position = _currentBlock.position + direction.ToVector(transform) + (Vector3.up * i);
  494. //if block is walkable set it to last known position
  495. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  496. moveTo = hit;
  497. }
  498. //set current block && move
  499. _currentBlock = moveTo;
  500. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  501. //transform.position = CurrentBlock.VisualPosition;
  502. }
  503. /// <summary>
  504. /// Long jumps forward a specified distance. Can Jump gaps. Stops at obstruction
  505. /// </summary>
  506. /// <param name="direction">Direction to Jump</param>
  507. /// <param name="Distance">Max distance</param>
  508. private void JumpLong(Direction direction, float speed, int Distance = 2)
  509. {
  510. //setting up variables
  511. Vector3 position; // position wanted
  512. Block hit; //output of block detection
  513. Block moveTo = _currentBlock; //block we'll actually move to
  514. //Check blocks in front until we hit an obstruction or went the distance
  515. for (int i = 1; i <= Distance; i++)
  516. {
  517. //Next position to MoveTo
  518. position = _currentBlock.position + (direction.ToVector(transform) * i);
  519. //if jump is obstructed, stop and go to last known block
  520. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  521. break;
  522. //If block at Position is walkable set it to last known position
  523. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  524. moveTo = hit;
  525. //else if block down one is walkable
  526. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  527. moveTo = hit;
  528. }//end for
  529. //Set Current Block and move
  530. _currentBlock = moveTo;
  531. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  532. //transform.position = CurrentBlock.VisualPosition;
  533. }
  534. #endregion Private Functions
  535. }