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.

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