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.
 
 
 
 
 
 

428 lines
14 KiB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using Networking.Server;
using TMPro;
public class Character : MonoBehaviour
{
public enum Animation { Walk, Run, Jump, Sit, Attack, Hit }
public blockSpawn spawn;
public int runOrder = 0;
public string nextScene;
Animator characterAnimator;
public bool isTuteLevel = false;
public bool inWater = false; //Am I in the water?
public bool respawnNeeded = false; //Am I waiting on a respawn?
public bool onCrystal = false;
public bool underRock = false;
public bool stuck = false; //Am I still stuck?
public bool justMoved = false; //Was the logic block I just executed a move command?
public bool inPit = false;
Vector3 death = new Vector3(-50, 0, 0);
#region Inspector Fields
[SerializeField]
[Tooltip("Will move to this block at start, else will try and find a block below")]
private Block _currentBlock;
[SerializeField]
[Tooltip("Layers to ignore when checking for blocks")]
public LayerMask Ignore;
[Tooltip("Current Inventory of the player")]
public Inventory Inventory;
public bool CloneInventoryOnStart = false;
[Tooltip("How many lives to start out with")]
public int lives = 3;
[SerializeField]
[Tooltip("Character to display")]
private string CharacterModel = "Bear";
[SerializeField]
public ClientData ClientLink;
[SerializeField]
private TMPro.TextMeshPro BlockTitlePrefab;
#endregion Inspector Fields
#region Read Only
public Block CurrentBlock { get { return _currentBlock; } }
public float lastRotation;
#endregion Read Only
#region Unity Functions
private void Start()
{
spawn = GameObject.Find("GameManager").GetComponent<blockSpawn>();
if (Inventory != null && CloneInventoryOnStart)
Inventory = Inventory.Clone(Inventory);
//If no starting block find one below it
if (_currentBlock == null)
Block.isBlockAtPosition(transform.position + Vector3.down / 2, 1, ~Ignore, out _currentBlock);
//move to starting block
transform.position = _currentBlock.VisualPosition;
//get character string from player replace from "Bear"
GameObject prefab = Resources.Load(CharacterModel) as GameObject;
GameObject animal = Instantiate(prefab, this.gameObject.transform);
characterAnimator = GetComponentInChildren<Animator>();
}
private void Update()
{
if(lives < 1)
{
this.transform.position = death;
//this.enabled = false;
//gameObject.SetActive(false);
}
GetComponentInChildren<TextMeshPro>().text = runOrder.ToString();
}
#endregion Unity Functions
#region Class Implementation
public void Initialise(Block startingBlock, Inventory inventory, string Character)
{
_currentBlock = startingBlock;
Inventory = inventory;
CharacterModel = Character;
}
public void DisplayBlock(LogicBlock block)
{
if (isTuteLevel == false)
{
if (BlockTitlePrefab == null)
return;
TMPro.TextMeshPro temp = Instantiate(BlockTitlePrefab.gameObject).GetComponent<TMPro.TextMeshPro>();
temp.text = block.DisplayName;
temp.color = ClientLink.Color;
temp.transform.position = transform.position + (Vector3.one * 0.25f);
temp.transform.rotation = Quaternion.LookRotation(temp.transform.position - Camera.main.transform.position);
}
}
public IEnumerator MoveToBlock(Block target, Animation animation, float time)
{
float startTime = Time.time;
Vector3 moveDirection = Vector3.ProjectOnPlane(target.position - _currentBlock.position, Vector3.up).normalized;
_currentBlock.OnLeftByPlayer(this);
System.Func<float, float> yFunction = null;
if (animation == Animation.Jump)
yFunction = (t) => Mathf.Sin((Mathf.PI * t));
StartAnimation(animation, time);
yield return StartCoroutine(LerpToBlock(target.VisualPosition, time * 0.8f, yFunction));
_currentBlock= target;
yield return StartCoroutine (_currentBlock.OnWalkedOnByPlayer(this,moveDirection));
yield return new WaitForSeconds(time - (Time.time - startTime));
StopAnimation(animation);
}
public IEnumerator RotateInDirection(Direction direction,float angles, Animation animation, float time)
{
System.Func<float, float> yFunction = null;
if (animation == Animation.Jump)
yFunction = (t) => Mathf.Sin((Mathf.PI * t));
StartAnimation(animation, time);
//Debug.Log("Rotating by: " + angles);
yield return StartCoroutine(Rotate(direction,angles, time * 0.8f, yFunction));
StopAnimation(animation);
}
public IEnumerator AnimateToPosition(Vector3 position, Animation animation, float time)
{
System.Func<float, float> yFunction = null;
if (animation == Animation.Jump)
yFunction = (t) => Mathf.Sin((Mathf.PI * t));
StartAnimation(animation, time);
yield return StartCoroutine(LerpToBlock(position, time * 0.8f, yFunction));
StopAnimation(animation);
}
public void StartAnimation(Animation animation,float speed = 1)
{
characterAnimator.SetFloat("AnimationSpeed", (1 / speed));
switch (animation)
{
case Animation.Walk:
characterAnimator.SetBool("isWalking", true);
break;
case Animation.Run:
characterAnimator.SetBool("isRunning", true);
break;
case Animation.Sit:
characterAnimator.SetBool("isSitting", true);
break;
case Animation.Jump:
characterAnimator.SetTrigger("Jump");
break;
case Animation.Attack:
characterAnimator.SetTrigger("Attack");
break;
case Animation.Hit:
characterAnimator.SetTrigger("Hit");
break;
default:
break;
}
}
public void StopAnimation(Animation animation)
{
characterAnimator.SetFloat("AnimationSpeed", 1f);
switch (animation)
{
case Animation.Walk:
characterAnimator.SetBool("isWalking", false);
break;
case Animation.Run:
characterAnimator.SetBool("isRunning", false);
break;
case Animation.Sit:
characterAnimator.SetBool("isSitting", false);
break;
}
}
public void respawnCharacter()
{
respawnCharacter(CurrentBlock.position);
}
public void respawnCharacter(Vector3 respawnPosition)
{
/* Will introduce more complex criteria for choosing where to respawn the player in future
* For now: if the square one back (x =- 1) from the pit is walkable and unoccupied, then put them there
* Otherwise, try the next square back, etc, until we find an available one
*/
Block currentBlock = null;
//We start from the position of our pit, at ground level
Vector3 currentPos = respawnPosition;
Debug.Log("Commencing respawn");
//Hardcoding the number of iterations for now for simplicity, should change this later
for (int i = 0; i < 100; i++)
{
//First we check one back
currentPos.x -= 1;
Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
{
Debug.Log("Block exists");
if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
{
Debug.Log("Block is walkable");
//Don't yet have a check for whether it's occupied
break; //If it is, we stop here
}
}
//If the block one back isn't an option, we check to the left and right
currentPos.z += 1;
Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
{
Debug.Log("Block exists");
if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
{
Debug.Log("Block is walkable");
//Don't yet have a check for whether it's occupied
break; //If it is, we stop here
}
}
currentPos.z -= 2;
Debug.Log("currentPos = " + currentPos.x + ", " + currentPos.y + ", " + currentPos.z);
if (Block.isBlockAtPosition(currentPos, 1, ~Ignore, out currentBlock)) //Does a block exist here?
{
Debug.Log("Block exists");
if (currentBlock.isWalkable(~Ignore)) //If so, can we walk on it?
{
Debug.Log("Block is walkable");
//Don't yet have a check for whether it's occupied
break; //If it is, we stop here
}
}
//If we've gotten this far and haven't found an available spot, we move back a row and try again
currentPos.z += 1;
}
//Having found our target block, we move the character there
if (currentBlock != null)
{
this.transform.position = currentBlock.VisualPosition;
this.respawnNeeded = false;
this._currentBlock = currentBlock;
Debug.Log("Moved " + this.name + " to "
+ this.transform.position.x + ", "
+ this.transform.position.y + ", "
+ this.transform.position.z + ", "
+ " respawnNeeded = " + respawnNeeded);
}
else
{
Debug.Log("Failed to find anywhere to put " + this.name);
}
}
/// <summary>
/// Upon collision with a floating block, collect its
/// Upon collision with the end portal, end of level
/// </summary>
/// <param name="other">name of collided object</param>
void OnTriggerEnter(Collider other)
{
Collectable collectable = other.GetComponentInChildren<Collectable>();
if (collectable != null)
{
//get position from average;
ClientList list = spawn.clientDataList;
float average = 0;
int livePlayerCount = 0;
foreach (ClientData data in list.ConnectedClients)
{
if (data.Lives > 0)
{
average += data.playerCharacter.transform.position.x;
livePlayerCount++;
}
}
average /= livePlayerCount;
float tosend = lives + (transform.position.x - average);
//Debug.Log(transform.position.x + " - " + average + " =" + (transform.position.x - average));
//Debug.Log("Value to send: " + tosend);
spawn.assignLogicBlock(collectable.gameObject, tosend);
collectable.OnCollect(this);
}
}
#endregion Class Implementation
#region Private Functions
private IEnumerator LerpToBlock(Vector3 target, float time, System.Func<float, float> heightOffset = null)
{
Vector3 _startPos = transform.position;
Vector3 _endPos = target;
Vector3 _newPos;
float elapsedTime = 0;
while (elapsedTime / time < 1)
{
_newPos = Vector3.Lerp(_startPos, _endPos, (elapsedTime / time));
if (heightOffset != null)
_newPos.y += heightOffset(elapsedTime / time);
transform.position = _newPos;
yield return new WaitForEndOfFrame();
elapsedTime += Time.deltaTime;
}
_newPos = _endPos;
if (heightOffset != null)
_newPos.y += heightOffset(1);
transform.position = _newPos;
}
private IEnumerator Rotate(Direction direction, float angles, float time, System.Func<float, float> heightOffset = null)
{
int RotationDir = 0;
switch (direction)
{
case Direction.Forward:
RotationDir = 0;
break;
case Direction.Left:
RotationDir = -1;
break;
case Direction.Right:
RotationDir = 1;
break;
case Direction.Back:
RotationDir = 2;
break;
}
lastRotation = angles * RotationDir;
float elapsedTime = 0;
float anglePerSecond = (angles * RotationDir) / time;
Vector3 _startPos = transform.position;
Vector3 startDirection = transform.forward;
while (elapsedTime < time)
{
transform.Rotate(Vector3.up, anglePerSecond * Time.deltaTime);
if (heightOffset != null)
transform.position = _startPos + Vector3.up * heightOffset(elapsedTime / time);
yield return new WaitForEndOfFrame();
elapsedTime += Time.deltaTime;
}
transform.forward = Quaternion.AngleAxis(angles * RotationDir, Vector3.up) * startDirection;
if (heightOffset != null)
transform.position = _startPos + Vector3.up * heightOffset(1);
}
#endregion Private Functions
}