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.

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