Created
April 6, 2017 08:24
-
-
Save Xanewok/b6fabc72ad5d1cecb396fd1a90ec132a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class Monster : MonoBehaviour { | |
/* Enum of states for FSM. Few more states should be add ie. for animation :HURTED */ | |
public enum MONSTER_STATE {PATROL = 0, CHASE = 1, ATTACK = 2}; | |
/* Current state of monster */ | |
public MONSTER_STATE ActiveState = MONSTER_STATE.PATROL; | |
/* Current health of monster. It's independ with enemy protection, only show % of health, wchih should be | |
printed above enemy head, or could be overwrite in child class */ | |
public int Health = 100; | |
/* Reference to active Player */ | |
protected GameObject Player = null; | |
/* Monster cached transform */ | |
protected Transform ThisTransform = null; | |
/* Reference to Player Transform */ | |
protected Transform PlayerTransform = null; | |
/* Reference to NavMesh Agent component */ | |
protected UnityEngine.AI.NavMeshAgent Agent = null; | |
/* Area of monster sight */ | |
/* DISCLAIMER::: Here and below random values: to elaborate*/ | |
protected float Sight_distance = 10f; | |
protected float Sight_Angle = 10f; | |
/* Area of monster hearing */ | |
protected float Hearing_distance = 10f; | |
/* Area of monster patrol */ | |
protected float Patrol_distance = 10f; | |
/* Area of head twist */ | |
protected float Twist_angle = 10f; | |
protected float Twist_speed = 10f; | |
/* Area of monster attack */ | |
/* DISCLAMIER::: Should be overwrite in child class depending on weapon, */ | |
/* now its mock value refering to min distance between monster and player.*/ | |
protected float Attack_distance = 0.5f; | |
void Start () { | |
Player = GameObject.FindWithTag("Player"); | |
PlayerTransform = Player.transform; | |
ThisTransform = transform; | |
Agent = GetComponent<UnityEngine.AI.NavMeshAgent>(); | |
} | |
protected bool canISeePlayer() { | |
UnityEngine.AI.NavMeshHit hit; | |
bool blocked = UnityEngine.AI.NavMesh.Raycast(ThisTransform.position, PlayerTransform.position, out hit, 1); | |
if(!blocked && hit.distance <= Sight_distance && | |
Vector3.Angle(ThisTransform.forward, PlayerTransform.position - ThisTransform.position) <= Sight_Angle)/* right Angle */ | |
return true; | |
return false; | |
} | |
protected bool canIHerePlayer() { | |
UnityEngine.AI.NavMeshHit hit; | |
UnityEngine.AI.NavMesh.Raycast(ThisTransform.position, PlayerTransform.position, out hit, 1); | |
if(hit.distance <= Hearing_distance) | |
return true; | |
return false; | |
} | |
/* Now its just mock function. Its should be return true, if monster is hit by player.*/ | |
protected bool canIFeelPlayer() { | |
return false; | |
} | |
/* Later could be add more circumstances like shell or something...*/ | |
protected bool canIAttackPlayer() { | |
return Vector3.Distance(ThisTransform.position, PlayerTransform.position) <= Attack_distance; | |
} | |
protected void chase() { | |
Agent.SetDestination(PlayerTransform.position); | |
Agent.updateRotation = true; | |
} | |
/* Err = feature. Last solution lay on assumption, that we extend states set to "idle", becouse we want that monster could take few-baby step */ | |
/* in some direction. Idle states would-be called when monster isnt in chase state and have no destination. Now before we establish new patrol point */ | |
/* , we just check if monster is walking--> thats mean if monster lost sight of player its go to last destination, when player been seen. Last solution */ | |
/* donst support that behaviour.*/ | |
protected void patrol() { | |
/* Nothing to go afrter - idle. Establish new random patrol point */ | |
if(!Agent.hasPath) { | |
/* Get random destination on map */ | |
Vector3 randomPoint = Random.insideUnitSphere * Patrol_distance; | |
/* Add as offset from current position */ | |
randomPoint += ThisTransform.position; | |
/* Get nearest valid position */ | |
UnityEngine.AI.NavMeshHit hit; | |
UnityEngine.AI.NavMesh.SamplePosition(randomPoint, out hit, Patrol_distance, 1); | |
/* Set destination */ | |
Agent.SetDestination(hit.position); | |
} | |
/*DISCLAIMER::: I'm not sure if rotation of all monster body to "symulate look around" is good idea- maybe just head should dance */ | |
/* Make sure thats flag is set in any other state */ | |
/* Btw it can product some undefined bevahiour*/ | |
Agent.updateRotation = false; | |
/* Fuck this shit... work-around: sinus is periodic and in some point symmetrical, so can be used to symulate any periodic movement */ | |
float currentOffsetAngle = Twist_angle * (2 * Mathf.Sin(Time.time * Twist_speed) - 1); | |
/* Obtain vector which make currentOffSetAngle with verocity vector*/ | |
Vector3 lookAtPosition = Quaternion.Euler(0, currentOffsetAngle, 0) * Agent.velocity; | |
/* What happen when velocity == 0 ? */ | |
ThisTransform.LookAt(lookAtPosition); | |
} | |
protected void attack() { | |
/* Bite */ | |
} | |
/* Dealing monster state */ | |
void Update() { | |
/* Elaborate states */ | |
if(canISeePlayer() || canIHerePlayer() || canIFeelPlayer()) | |
ActiveState = MONSTER_STATE.CHASE; | |
if(ActiveState == MONSTER_STATE.CHASE && canIAttackPlayer()) | |
ActiveState = MONSTER_STATE.ATTACK; | |
/* Call state function and animation launch */ | |
switch (ActiveState){ | |
case MONSTER_STATE.CHASE: | |
chase(); | |
break; | |
case MONSTER_STATE.PATROL: | |
patrol(); | |
break; | |
case MONSTER_STATE.ATTACK: | |
attack(); | |
break; | |
default: | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment