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.

427 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. characterAnimator.SetFloat("AnimationSpeed", (1 / speed));
  132. switch (animation)
  133. {
  134. case Animation.Walk:
  135. characterAnimator.SetBool("isWalking", true);
  136. break;
  137. case Animation.Run:
  138. characterAnimator.SetBool("isRunning", true);
  139. break;
  140. case Animation.Sit:
  141. characterAnimator.SetBool("isSitting", true);
  142. break;
  143. case Animation.Jump:
  144. characterAnimator.SetTrigger("Jump");
  145. break;
  146. case Animation.Attack:
  147. characterAnimator.SetTrigger("Attack");
  148. break;
  149. case Animation.Hit:
  150. characterAnimator.SetTrigger("Hit");
  151. break;
  152. default:
  153. break;
  154. }
  155. }
  156. public void StopAnimation(Animation animation)
  157. {
  158. characterAnimator.SetFloat("AnimationSpeed", 1f);
  159. switch (animation)
  160. {
  161. case Animation.Walk:
  162. characterAnimator.SetBool("isWalking", false);
  163. break;
  164. case Animation.Run:
  165. characterAnimator.SetBool("isRunning", false);
  166. break;
  167. case Animation.Sit:
  168. characterAnimator.SetBool("isSitting", false);
  169. break;
  170. }
  171. }
  172. public void respawnCharacter()
  173. {
  174. respawnCharacter(CurrentBlock.position);
  175. }
  176. public void respawnCharacter(Vector3 respawnPosition)
  177. {
  178. /* Will introduce more complex criteria for choosing where to respawn the player in future
  179. * For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
  180. * Otherwise, try the next square back, etc, until we find an available one
  181. */
  182. Block currentBlock = null;
  183. //We start from the position of our pit, at ground level
  184. Vector3 currentPos = respawnPosition;
  185. Debug.Log("Commencing respawn");
  186. //Hardcoding the number of iterations for now for simplicity, should change this later
  187. for (int i = 0; i < 100; i++)
  188. {
  189. //First we check one back
  190. currentPos.x -= 1;
  191. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  192. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  193. {
  194. Debug.Log("Block exists");
  195. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  196. {
  197. Debug.Log("Block is walkable");
  198. //Don't yet have a check for whether it's occupied
  199. break; //If it is, we stop here
  200. }
  201. }
  202. //If the block one back isn't an option, we check to the left and right
  203. currentPos.z += 1;
  204. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  205. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  206. {
  207. Debug.Log("Block exists");
  208. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  209. {
  210. Debug.Log("Block is walkable");
  211. //Don't yet have a check for whether it's occupied
  212. break; //If it is, we stop here
  213. }
  214. }
  215. currentPos.z -= 2;
  216. Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
  217. if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
  218. {
  219. Debug.Log("Block exists");
  220. if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
  221. {
  222. Debug.Log("Block is walkable");
  223. //Don't yet have a check for whether it's occupied
  224. break; //If it is, we stop here
  225. }
  226. }
  227. //If we've gotten this far and haven't found an available spot, we move back a row and try again
  228. currentPos.z += 1;
  229. }
  230. //Having found our target block, we move the character there
  231. if (currentBlock != null)
  232. {
  233. this.transform.position = currentBlock.VisualPosition;
  234. this.respawnNeeded = false;
  235. this._currentBlock = currentBlock;
  236. Debug.Log("Moved " + this.name + " to "
  237. + this.transform.position.x + ", "
  238. + this.transform.position.y + ", "
  239. + this.transform.position.z + ", "
  240. + " respawnNeeded = " + respawnNeeded);
  241. }
  242. else
  243. {
  244. Debug.Log("Failed to find anywhere to put " + this.name);
  245. }
  246. }
  247. /// <summary>
  248. /// Upon collision with a floating block, collect its
  249. /// Upon collision with the end portal, end of level
  250. /// </summary>
  251. /// <param name="other">name of collided object</param>
  252. void OnTriggerEnter(Collider other)
  253. {
  254. Collectable collectable = other.GetComponentInChildren<Collectable>();
  255. if (collectable != null)
  256. {
  257. //get position from average;
  258. ClientList list = spawn.clientDataList;
  259. float average = 0;
  260. int livePlayerCount = 0;
  261. foreach (ClientData data in list.ConnectedClients)
  262. {
  263. if (data.Lives > 0)
  264. {
  265. average += data.playerCharacter.transform.position.x;
  266. livePlayerCount++;
  267. }
  268. }
  269. average /= livePlayerCount;
  270. float tosend = lives + (transform.position.x - average);
  271. //Debug.Log(transform.position.x + " - " + average + " =" + (transform.position.x - average));
  272. //Debug.Log("Value to send: " + tosend);
  273. spawn.assignLogicBlock(collectable.gameObject, tosend);
  274. collectable.OnCollect(this);
  275. }
  276. }
  277. #endregion Class Implementation
  278. #region Private Functions
  279. private IEnumerator LerpToBlock(Vector3 target, float time, System.Func<float, float> heightOffset = null)
  280. {
  281. Vector3 _startPos = transform.position;
  282. Vector3 _endPos = target;
  283. Vector3 _newPos;
  284. float elapsedTime = 0;
  285. while (elapsedTime / time < 1)
  286. {
  287. _newPos = Vector3.Lerp(_startPos, _endPos, (elapsedTime / time));
  288. if (heightOffset != null)
  289. _newPos.y += heightOffset(elapsedTime / time);
  290. transform.position = _newPos;
  291. yield return new WaitForEndOfFrame();
  292. elapsedTime += Time.deltaTime;
  293. }
  294. _newPos = _endPos;
  295. if (heightOffset != null)
  296. _newPos.y += heightOffset(1);
  297. transform.position = _newPos;
  298. }
  299. private IEnumerator Rotate(Direction direction, float angles, float time, System.Func<float, float> heightOffset = null)
  300. {
  301. int RotationDir = 0;
  302. switch (direction)
  303. {
  304. case Direction.Forward:
  305. RotationDir = 0;
  306. break;
  307. case Direction.Left:
  308. RotationDir = -1;
  309. break;
  310. case Direction.Right:
  311. RotationDir = 1;
  312. break;
  313. case Direction.Back:
  314. RotationDir = 2;
  315. break;
  316. }
  317. lastRotation = angles * RotationDir;
  318. float elapsedTime = 0;
  319. float anglePerSecond = (angles * RotationDir) / time;
  320. Vector3 _startPos = transform.position;
  321. Vector3 startDirection = transform.forward;
  322. while (elapsedTime < time)
  323. {
  324. transform.Rotate(Vector3.up, anglePerSecond * Time.deltaTime);
  325. if (heightOffset != null)
  326. transform.position = _startPos + Vector3.up * heightOffset(elapsedTime / time);
  327. yield return new WaitForEndOfFrame();
  328. elapsedTime += Time.deltaTime;
  329. }
  330. transform.forward = Quaternion.AngleAxis(angles * RotationDir, Vector3.up) * startDirection;
  331. if (heightOffset != null)
  332. transform.position = _startPos + Vector3.up * heightOffset(1);
  333. }
  334. #endregion Private Functions
  335. }