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.

590 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. #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. while (elapsedTime < time)
  222. {
  223. characterAnimator.Play("Jump");
  224. transform.forward = Vector3.Slerp(startDirection, endDirection, (elapsedTime / time));
  225. yield return new WaitForEndOfFrame();
  226. elapsedTime += Time.deltaTime;
  227. }
  228. transform.forward = endDirection;
  229. }
  230. IEnumerator rotateHalfCoroutine(Direction direction, Transform Current, float time, float heightMax)
  231. {
  232. float elapsedTime = 0;
  233. time *= 0.8f;
  234. Vector3 endDirection = (direction.ToVector(Current) + Current.forward).normalized;
  235. Vector3 startDirection = Current.forward;
  236. while (elapsedTime < time)
  237. {
  238. characterAnimator.Play("Jump");
  239. transform.forward = Vector3.Slerp(startDirection, endDirection, (elapsedTime / time));
  240. yield return new WaitForEndOfFrame();
  241. elapsedTime += Time.deltaTime;
  242. }
  243. transform.forward = endDirection;
  244. }
  245. /// <summary>
  246. /// Moves one block in specefied direction, Can walk off obstacles
  247. /// </summary>
  248. /// <param name="direction">direction to walk</param>
  249. /// <remarks>Technically is same as JumpLong(1) but kept seperate to avoid confusion</remarks>
  250. public void Move(Direction direction, float speed)
  251. {
  252. //setting up variables
  253. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  254. Block hit; //output of block detection
  255. Block moveTo = _currentBlock; //block we'll actually move to
  256. //if move is obstucted no where to move
  257. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  258. return;
  259. //If block at Position is walkable set it to moveTo
  260. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  261. {
  262. moveTo = hit;
  263. _currentBlock = moveTo;
  264. StartCoroutine(MoveCoroutine(_currentBlock, transform, speed, 0.3f));
  265. }
  266. //else if block down one is walkable
  267. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  268. {
  269. moveTo = hit;
  270. _currentBlock = moveTo;
  271. StartCoroutine(MoveDownCoroutine(_currentBlock, transform, speed, 0.3f));
  272. }
  273. }
  274. public void conveyorMoveForward(Direction direction, float speed)
  275. {
  276. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  277. Block hit; //output of block detection
  278. Block moveTo = _currentBlock; //block we'll actually move to
  279. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  280. {
  281. moveTo = hit;
  282. _currentBlock = moveTo;
  283. StartCoroutine(MoveConveyorForwardCoroutine(_currentBlock, transform, speed, 0.3f));
  284. }
  285. }
  286. public void conveyorMoveBackward(Direction direction, float speed)
  287. {
  288. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  289. Block hit; //output of block detection
  290. Block moveTo = _currentBlock; //block we'll actually move to
  291. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  292. {
  293. moveTo = hit;
  294. _currentBlock = moveTo;
  295. StartCoroutine(MoveConveyorBackwardCoroutine(_currentBlock, transform, speed, 0.3f));
  296. }
  297. }
  298. public void conveyorMoveLeft(Direction direction, float speed)
  299. {
  300. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  301. Block hit; //output of block detection
  302. Block moveTo = _currentBlock; //block we'll actually move to
  303. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  304. {
  305. moveTo = hit;
  306. _currentBlock = moveTo;
  307. StartCoroutine(MoveConveyorLeftCoroutine(_currentBlock, transform, speed, 0.3f));
  308. }
  309. }
  310. public void conveyorMoveRight(Direction direction, float speed)
  311. {
  312. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  313. Block hit; //output of block detection
  314. Block moveTo = _currentBlock; //block we'll actually move to
  315. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  316. {
  317. moveTo = hit;
  318. _currentBlock = moveTo;
  319. StartCoroutine(MoveConveyorRightCoroutine(_currentBlock, transform, speed, 0.3f));
  320. }
  321. }
  322. public void CannonRMove(float speed)
  323. {
  324. Direction direction = Direction.Right;
  325. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  326. Block hit; //output of block detection
  327. Block moveTo = _currentBlock; //block we'll actually move to
  328. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  329. {
  330. moveTo = hit;
  331. _currentBlock = moveTo;
  332. StartCoroutine(PushRightCoroutine(transform, speed));
  333. }
  334. }
  335. public void CannonLMove(float speed)
  336. {
  337. Direction direction = Direction.Left;
  338. Vector3 position = _currentBlock.position + direction.ToVector(transform); // position wanted
  339. Block hit; //output of block detection
  340. Block moveTo = _currentBlock; //block we'll actually move to
  341. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  342. {
  343. moveTo = hit;
  344. _currentBlock = moveTo;
  345. StartCoroutine(PushLeftCoroutine(transform, speed));
  346. }
  347. }
  348. public void respawnCharacter()
  349. {
  350. /* Will introduce more complex criteria for choosing where to respawn the player in future
  351. * For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
  352. * Otherwise, try the next square back, etc, until we find an available one
  353. */
  354. Block currentBlock = null;
  355. //We start from the position of our pit, at ground level
  356. Vector3 currentPos = new Vector3(this.transform.position.x, this.transform.position.y, this.transform.position.z);
  357. Debug.Log("Commencing respawn");
  358. //Hardcoding the number of iterations for now for simplicity, should change this later
  359. for (int i = 0; i < 100; i++)
  360. {
  361. //First we check one back
  362. currentPos.x -= 1;
  363. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  364. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  365. {
  366. Debug.Log("Block exists");
  367. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  368. {
  369. Debug.Log("Block is walkable");
  370. //Don't yet have a check for whether it's occupied
  371. break; //If it is, we stop here
  372. }
  373. }
  374. //If the block one back isn't an option, we check to the left and right
  375. currentPos.z += 1;
  376. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  377. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  378. {
  379. Debug.Log("Block exists");
  380. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  381. {
  382. Debug.Log("Block is walkable");
  383. //Don't yet have a check for whether it's occupied
  384. break; //If it is, we stop here
  385. }
  386. }
  387. currentPos.z -= 2;
  388. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  389. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  390. {
  391. Debug.Log("Block exists");
  392. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  393. {
  394. Debug.Log("Block is walkable");
  395. //Don't yet have a check for whether it's occupied
  396. break; //If it is, we stop here
  397. }
  398. }
  399. //If we've gotten this far and haven't found an available spot, we move back a row and try again
  400. currentPos.z += 1;
  401. }
  402. //Having found our target block, we move the character there
  403. if (currentBlock != null)
  404. {
  405. this.transform.position = currentBlock.VisualPosition;
  406. this.inPit = false;
  407. this._currentBlock = currentBlock;
  408. Debug.Log("Moved " + this.name + " to "
  409. + this.transform.position.x + ", "
  410. + this.transform.position.y + ", "
  411. + this.transform.position.z + ", "
  412. + " inPit = " + inPit);
  413. }
  414. else
  415. {
  416. Debug.Log("Failed to find anywhere to put " + this.name);
  417. }
  418. }
  419. /// <summary>
  420. /// Upon collision with a floating block, collect its
  421. /// Upon collision with the end portal, end of level
  422. /// </summary>
  423. /// <param name="other">name of collided object</param>
  424. void OnTriggerEnter(Collider other)
  425. {
  426. Collectable collectable = other.GetComponentInChildren<Collectable>();
  427. if (collectable != null)
  428. {
  429. collectable.OnCollect(this);
  430. }
  431. if (other.gameObject.name == "collect_sphere")
  432. {
  433. other.gameObject.SetActive(false);
  434. //player.collected +=1;
  435. }
  436. if (other.gameObject.name == "End Portal")
  437. {
  438. other.GetComponent<Collider>().enabled = false;
  439. SceneManager.LoadScene(nextScene);
  440. }
  441. }
  442. /// <summary>
  443. /// Rotates to point in specific direction based on current direction
  444. /// </summary>
  445. /// <param name="direction">Local direction to point</param>
  446. public void Rotate(Direction direction, float speed)
  447. {
  448. StartCoroutine(rotateCoroutine(direction, transform, speed, 0.15f));
  449. //transform.forward = direction.ToVector(transform);
  450. }
  451. public void RotateHalf(Direction direction, float speed)
  452. {
  453. StartCoroutine(rotateHalfCoroutine(direction, transform, speed, 0.15f));
  454. //transform.forward = direction.ToVector(transform);
  455. }
  456. /// <summary>
  457. /// Jumps in specefied direction, picks between Long Jump and Jumping up
  458. /// </summary>
  459. /// <param name="direction">Direction to Jump</param>
  460. public void Jump(Direction direction, float speed)
  461. {
  462. //if there is a block infront JumpUp else LongJump
  463. if (Block.isBlockAtPosition(_currentBlock.position + direction.ToVector(transform) + Vector3.up, 1, ~Ignore))
  464. JumpUp(direction, speed);
  465. else
  466. JumpLong(direction, speed);
  467. }
  468. #endregion Class Implementation
  469. #region Private Functions
  470. /// <summary>
  471. /// Jumps up obstacle of specific height. Jumps as high as possible
  472. /// </summary>
  473. /// <param name="direction">Direction of obstacle</param>
  474. /// <param name="height">max height</param>
  475. private void JumpUp(Direction direction, float speed, int height = 1)
  476. {
  477. //setting up variables
  478. Vector3 position; // position wanted
  479. Block hit; //output of block detection
  480. Block moveTo = _currentBlock; //block we'll actually move to
  481. //Check blocks in going up then move to the heighest walkable one
  482. for (int i = 0; i <= height; i++)
  483. {
  484. //next position up the tower
  485. position = _currentBlock.position + direction.ToVector(transform) + (Vector3.up * i);
  486. //if block is walkable set it to last known position
  487. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  488. moveTo = hit;
  489. }
  490. //set current block && move
  491. _currentBlock = moveTo;
  492. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  493. //transform.position = CurrentBlock.VisualPosition;
  494. }
  495. /// <summary>
  496. /// Long jumps forward a specified distance. Can Jump gaps. Stops at obstruction
  497. /// </summary>
  498. /// <param name="direction">Direction to Jump</param>
  499. /// <param name="Distance">Max distance</param>
  500. private void JumpLong(Direction direction, float speed, int Distance = 2)
  501. {
  502. //setting up variables
  503. Vector3 position; // position wanted
  504. Block hit; //output of block detection
  505. Block moveTo = _currentBlock; //block we'll actually move to
  506. //Check blocks in front until we hit an obstruction or went the distance
  507. for (int i = 1; i <= Distance; i++)
  508. {
  509. //Next position to MoveTo
  510. position = _currentBlock.position + (direction.ToVector(transform) * i);
  511. //if jump is obstructed, stop and go to last known block
  512. if (Block.isBlockAtPosition(position + Vector3.up, 1, ~Ignore))
  513. break;
  514. //If block at Position is walkable set it to last known position
  515. if (Block.isBlockAtPosition(position, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  516. moveTo = hit;
  517. //else if block down one is walkable
  518. else if (Block.isBlockAtPosition(position + Vector3.down, 1, ~Ignore, out hit) && hit.isWalkable(~Ignore))
  519. moveTo = hit;
  520. }//end for
  521. //Set Current Block and move
  522. _currentBlock = moveTo;
  523. StartCoroutine(JumpCoroutine(_currentBlock, transform, speed, 0.5f));
  524. //transform.position = CurrentBlock.VisualPosition;
  525. }
  526. #endregion Private Functions
  527. }