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.

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