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.

421 lines
13 KiB

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