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.

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