Skip to content

Instantly share code, notes, and snippets.

@Xanewok
Created April 6, 2017 08:24
Show Gist options
  • Save Xanewok/b6fabc72ad5d1cecb396fd1a90ec132a to your computer and use it in GitHub Desktop.
Save Xanewok/b6fabc72ad5d1cecb396fd1a90ec132a to your computer and use it in GitHub Desktop.
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