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.

424 lines
14 KiB

5 years ago
5 years ago
5 years ago
  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. using TMPro;
  8. public class Character : MonoBehaviour
  9. {
  10. public enum Animation { Walk, Run, Jump, Sit, Attack, Hit }
  11. public blockSpawn spawn;
  12. public int runOrder = 0;
  13. public string nextScene;
  14. Animator characterAnimator;
  15. public bool isTuteLevel = false;
  16. public bool inWater = false; //Am I in the water?
  17. public bool respawnNeeded = false; //Am I waiting on a respawn?
  18. public bool onCrystal = false;
  19. public bool underRock = false;
  20. public bool stuck = false; //Am I still stuck?
  21. public bool justMoved = false; //Was the logic block I just executed a move command?
  22. public bool inPit = false;
  23. Vector3 death = new Vector3(-50, 0, 0);
  24. #region Inspector Fields
  25. [SerializeField]
  26. [Tooltip("Will move to this block at start, else will try and find a block below")]
  27. private Block _currentBlock;
  28. [SerializeField]
  29. [Tooltip("Layers to ignore when checking for blocks")]
  30. public LayerMask Ignore;
  31. [Tooltip("Current Inventory of the player")]
  32. public Inventory Inventory;
  33. public bool CloneInventoryOnStart = false;
  34. [Tooltip("How many lives to start out with")]
  35. public int lives = 3;
  36. [SerializeField]
  37. [Tooltip("Character to display")]
  38. private string CharacterModel = "Bear";
  39. [SerializeField]
  40. public ClientData ClientLink;
  41. [SerializeField]
  42. private TMPro.TextMeshPro BlockTitlePrefab;
  43. #endregion Inspector Fields
  44. #region Read Only
  45. public Block CurrentBlock { get { return _currentBlock; } }
  46. public float lastRotation;
  47. #endregion Read Only
  48. #region Unity Functions
  49. private void Start()
  50. {
  51. spawn = GameObject.Find("GameManager").GetComponent<blockSpawn>();
  52. if (Inventory != null && CloneInventoryOnStart)
  53. Inventory = Inventory.Clone(Inventory);
  54. //If no starting block find one below it
  55. if (_currentBlock == null)
  56. Block.isBlockAtPosition(transform.position + Vector3.down / 2, 1, ~Ignore, out _currentBlock);
  57. //move to starting block
  58. transform.position = _currentBlock.VisualPosition;
  59. //get character string from player replace from "Bear"
  60. GameObject prefab = Resources.Load(CharacterModel) as GameObject;
  61. GameObject animal = Instantiate(prefab, this.gameObject.transform);
  62. characterAnimator = GetComponentInChildren<Animator>();
  63. }
  64. private void Update()
  65. {
  66. if(lives < 1)
  67. {
  68. this.transform.position = death;
  69. //this.enabled = false;
  70. //gameObject.SetActive(false);
  71. }
  72. GetComponentInChildren<TextMeshPro>().text = runOrder.ToString();
  73. }
  74. #endregion Unity Functions
  75. #region Class Implementation
  76. public void Initialise(Block startingBlock, Inventory inventory, string Character)
  77. {
  78. _currentBlock = startingBlock;
  79. Inventory = inventory;
  80. CharacterModel = Character;
  81. }
  82. public void DisplayBlock(LogicBlock block)
  83. {
  84. if (isTuteLevel == false)
  85. {
  86. if (BlockTitlePrefab == null)
  87. return;
  88. TMPro.TextMeshPro temp = Instantiate(BlockTitlePrefab.gameObject).GetComponent<TMPro.TextMeshPro>();
  89. temp.text = block.DisplayName;
  90. temp.color = ClientLink.Color;
  91. temp.transform.position = transform.position + (Vector3.one * 0.25f);
  92. temp.transform.rotation = Quaternion.LookRotation(temp.transform.position - Camera.main.transform.position);
  93. }
  94. }
  95. public IEnumerator MoveToBlock(Block target, Animation animation, float time)
  96. {
  97. float startTime = Time.time;
  98. Vector3 moveDirection = Vector3.ProjectOnPlane(target.position - _currentBlock.position, Vector3.up).normalized;
  99. _currentBlock.OnLeftByPlayer(this);
  100. System.Func<float, float> yFunction = null;
  101. if (animation == Animation.Jump)
  102. yFunction = (t) => Mathf.Sin((Mathf.PI * t));
  103. StartAnimation(animation, time);
  104. yield return StartCoroutine(LerpToBlock(target.VisualPosition, time * 0.8f, yFunction));
  105. _currentBlock= target;
  106. yield return StartCoroutine (_currentBlock.OnWalkedOnByPlayer(this,moveDirection));
  107. yield return new WaitForSeconds(time - (Time.time - startTime));
  108. StopAnimation(animation);
  109. }
  110. public IEnumerator RotateInDirection(Direction direction,float angles, Animation animation, float time)
  111. {
  112. System.Func<float, float> yFunction = null;
  113. if (animation == Animation.Jump)
  114. yFunction = (t) => Mathf.Sin((Mathf.PI * t));
  115. StartAnimation(animation, time);
  116. //Debug.Log("Rotating by: " + angles);
  117. yield return StartCoroutine(Rotate(direction,angles, time * 0.8f, yFunction));
  118. StopAnimation(animation);
  119. }
  120. public IEnumerator AnimateToPosition(Vector3 position, Animation animation, float time)
  121. {
  122. System.Func<float, float> yFunction = null;
  123. if (animation == Animation.Jump)
  124. yFunction = (t) => Mathf.Sin((Mathf.PI * t));
  125. StartAnimation(animation, time);
  126. yield return StartCoroutine(LerpToBlock(position, time * 0.8f, yFunction));
  127. StopAnimation(animation);
  128. }
  129. public void StartAnimation(Animation animation,float speed = 1)
  130. {
  131. switch (animation)
  132. {
  133. case Animation.Walk:
  134. characterAnimator.SetBool("isWalking", true);
  135. break;
  136. case Animation.Run:
  137. characterAnimator.SetBool("isRunning", true);
  138. break;
  139. case Animation.Sit:
  140. characterAnimator.SetBool("isSitting", true);
  141. break;
  142. case Animation.Jump:
  143. characterAnimator.SetTrigger("Jump");
  144. break;
  145. case Animation.Attack:
  146. characterAnimator.SetTrigger("Attack");
  147. break;
  148. case Animation.Hit:
  149. characterAnimator.SetTrigger("Hit");
  150. break;
  151. default:
  152. break;
  153. }
  154. }
  155. public void StopAnimation(Animation animation)
  156. {
  157. switch (animation)
  158. {
  159. case Animation.Walk:
  160. characterAnimator.SetBool("isWalking", false);
  161. break;
  162. case Animation.Run:
  163. characterAnimator.SetBool("isRunning", false);
  164. break;
  165. case Animation.Sit:
  166. characterAnimator.SetBool("isSitting", false);
  167. break;
  168. }
  169. }
  170. public void respawnCharacter()
  171. {
  172. respawnCharacter(CurrentBlock.position);
  173. }
  174. public void respawnCharacter(Vector3 respawnPosition)
  175. {
  176. /* Will introduce more complex criteria for choosing where to respawn the player in future
  177. * For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
  178. * Otherwise, try the next square back, etc, until we find an available one
  179. */
  180. Block currentBlock = null;
  181. //We start from the position of our pit, at ground level
  182. Vector3 currentPos = respawnPosition;
  183. //Debug.Log("Commencing respawn");
  184. //Hardcoding the number of iterations for now for simplicity, should change this later
  185. for (int i = 0; i < 100; i++)
  186. {
  187. //First we check one back
  188. currentPos.x -= 1;
  189. //Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  190. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  191. {
  192. //Debug.Log("Block exists");
  193. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  194. {
  195. //Debug.Log("Block is walkable");
  196. //Don't yet have a check for whether it's occupied
  197. break; //If it is, we stop here
  198. }
  199. }
  200. //If the block one back isn't an option, we check to the left and right
  201. currentPos.z += 1;
  202. //Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  203. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  204. {
  205. //Debug.Log("Block exists");
  206. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  207. {
  208. //Debug.Log("Block is walkable");
  209. //Don't yet have a check for whether it's occupied
  210. break; //If it is, we stop here
  211. }
  212. }
  213. currentPos.z -= 2;
  214. //Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  215. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  216. {
  217. //Debug.Log("Block exists");
  218. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  219. {
  220. //Debug.Log("Block is walkable");
  221. //Don't yet have a check for whether it's occupied
  222. break; //If it is, we stop here
  223. }
  224. }
  225. //If we've gotten this far and haven't found an available spot, we move back a row and try again
  226. currentPos.z += 1;
  227. }
  228. //Having found our target block, we move the character there
  229. if (currentBlock != null)
  230. {
  231. this.transform.position = currentBlock.VisualPosition;
  232. this.respawnNeeded = false;
  233. this._currentBlock = currentBlock;
  234. Debug.Log("Moved " + this.name + " to "
  235. + this.transform.position.x + ", "
  236. + this.transform.position.y + ", "
  237. + this.transform.position.z + ", "
  238. + " respawnNeeded = " + respawnNeeded);
  239. }
  240. else
  241. {
  242. Debug.Log("Failed to find anywhere to put " + this.name);
  243. }
  244. }
  245. /// <summary>
  246. /// Upon collision with a floating block, collect its
  247. /// Upon collision with the end portal, end of level
  248. /// </summary>
  249. /// <param name="other">name of collided object</param>
  250. void OnTriggerEnter(Collider other)
  251. {
  252. Collectable collectable = other.GetComponentInChildren<Collectable>();
  253. if (collectable != null)
  254. {
  255. //get position from average;
  256. ClientList list = spawn.clientDataList;
  257. float average = 0;
  258. int livePlayerCount = 0;
  259. foreach (ClientData data in list.ConnectedClients)
  260. {
  261. if (data.Lives > 0)
  262. {
  263. average += data.playerCharacter.transform.position.x;
  264. livePlayerCount++;
  265. }
  266. }
  267. average /= livePlayerCount;
  268. float tosend = lives + (transform.position.x - average);
  269. //Debug.Log(transform.position.x + " - " + average + " =" + (transform.position.x - average));
  270. //Debug.Log("Value to send: " + tosend);
  271. spawn.assignLogicBlock(collectable.gameObject, tosend);
  272. collectable.OnCollect(this);
  273. }
  274. }
  275. #endregion Class Implementation
  276. #region Private Functions
  277. private IEnumerator LerpToBlock(Vector3 target, float time, System.Func<float, float> heightOffset = null)
  278. {
  279. Vector3 _startPos = transform.position;
  280. Vector3 _endPos = target;
  281. Vector3 _newPos;
  282. float elapsedTime = 0;
  283. while (elapsedTime / time < 1)
  284. {
  285. _newPos = Vector3.Lerp(_startPos, _endPos, (elapsedTime / time));
  286. if (heightOffset != null)
  287. _newPos.y += heightOffset(elapsedTime / time);
  288. transform.position = _newPos;
  289. yield return new WaitForEndOfFrame();
  290. elapsedTime += Time.deltaTime;
  291. }
  292. _newPos = _endPos;
  293. if (heightOffset != null)
  294. _newPos.y += heightOffset(1);
  295. transform.position = _newPos;
  296. }
  297. private IEnumerator Rotate(Direction direction, float angles, float time, System.Func<float, float> heightOffset = null)
  298. {
  299. int RotationDir = 0;
  300. switch (direction)
  301. {
  302. case Direction.Forward:
  303. RotationDir = 0;
  304. break;
  305. case Direction.Left:
  306. RotationDir = -1;
  307. break;
  308. case Direction.Right:
  309. RotationDir = 1;
  310. break;
  311. case Direction.Back:
  312. RotationDir = 2;
  313. break;
  314. }
  315. lastRotation = angles * RotationDir;
  316. float elapsedTime = 0;
  317. float anglePerSecond = (angles * RotationDir) / time;
  318. Vector3 _startPos = transform.position;
  319. Vector3 startDirection = transform.forward;
  320. while (elapsedTime < time)
  321. {
  322. transform.Rotate(Vector3.up, anglePerSecond * Time.deltaTime);
  323. if (heightOffset != null)
  324. transform.position = _startPos + Vector3.up * heightOffset(elapsedTime / time);
  325. yield return new WaitForEndOfFrame();
  326. elapsedTime += Time.deltaTime;
  327. }
  328. transform.forward = Quaternion.AngleAxis(angles * RotationDir, Vector3.up) * startDirection;
  329. if (heightOffset != null)
  330. transform.position = _startPos + Vector3.up * heightOffset(1);
  331. }
  332. #endregion Private Functions
  333. }