void
Update()
{
// 현재 활성화된 상태를 기반으로 코드는 실행 된다.
switch
(currentState)
{
case
EnemyStates.sleeping:
// 적은 sleeping 상태이다.
//Check the current time against the time for the next Zzzzz to appear
if
(timeOfNextZZZZ < Time.time)
{
//If its time then create the sleeping prefab above the enemies
//head
var newPrefab = Instantiate(sleepingPrefab, _transform.position + Vector3.up * 3f, Quaternion.identity)
as
Transform;
newPrefab.forward = Camera.main.transform.forward;
//Calculate a time between 2 and 8 seconds for the next
//Zzzzz
timeOfNextZZZZ = Time.time + 2 + (6 * Random.value);
}
//Now check if the player has appraoched, using sqrMagnitude to avoid
//a performance expensive square root
if
((_transform.position - _player.position).sqrMagnitude < _attackDistanceSquared)
{
//Move the enemy into the following state
currentState = EnemyStates.following;
//Make the enemy target the player
target = _player;
//Where this enemy wants to stand to attack
_attackRotation = Random.Range(60,310);
}
break
;
case
EnemyStates.following:
// enemy는 target을 따라가고 있다.
//If the target has been destroyed then we go back to sleep
//(Destroyed objects return null and false)
if
(!target)
{
currentState = EnemyStates.sleeping;
return
;
}
//Calculate the vector to the target
var difference = (target.position - _transform.position);
//Ignore a big part of the height difference by dividing it
//by 6
difference.y /= 6;
//Calculate the square of the distance (avoid expensive square root)
var distanceSquared = difference.sqrMagnitude;
//Too far away to care?
if
( distanceSquared > _sleepDistanceSquared)
{
//If we've got too far away then go to sleep
currentState = EnemyStates.sleeping;
return
;
}
//Close enough to attack
if
( distanceSquared < _maximumAttackEffectRangeSquared && _angleToTarget < 60f)
{
//Move the enemy into the attacking state
currentState = EnemyStates.attacking;
//Enable the attack animation
_attack.enabled =
true
;
//Reset the animation to the start
_attack.time = 0;
//Make the animation just play once and hold
//this is so .normalizedTime will become =1
_attack.wrapMode = WrapMode.ClampForever;
//Make the attack animation full power
_attack.weight = 1;
//Indicate that we have yet to strike the target
hasStruckTarget =
false
;
return
;
}
//Move towards the target
//First decide target position based on the angle of attack we decided on waking up
var targetPosition = target.position + (Quaternion.AngleAxis(_attackRotation, Vector3.up) * target.forward * maximumAttackEffectRange * 0.8f);
//Calculate the basic movement toward the target
var basicMovement = (targetPosition - _transform.position).normalized * speed * Time.deltaTime;
//Zero out the y movement so we can get a bearing angle
//we will apply gravity later
basicMovement.y = 0;
//Only move when facing the target - so calculate
//the angle between the heading of the enemy and the target
_angleToTarget = Vector3.Angle(basicMovement, _transform.forward);
//Only move the enemy if it is within 70 degrees
if
( _angleToTarget < 70f)
{
//Provide some gravity
basicMovement.y = -20 * Time.deltaTime;
_controller.Move(basicMovement);
}
break
;
case
EnemyStates.attacking:
// enemy는 공격하고 있다.
//Work out if we are half way through the animation and haven't
//yet added any damage to the target
if
(!hasStruckTarget && _attack.normalizedTime > 0.5f)
{
//Ready to hit, so flag that it is done so we
//only come in here once
hasStruckTarget =
true
;
//Check if still in range
if
(target && (target.position - _transform.position).sqrMagnitude < _maximumAttackEffectRangeSquared)
{
//Apply the damage
target.SendMessage(
"TakeDamage"
, 1 + Random.value * 5, SendMessageOptions.DontRequireReceiver);
}
}
//See if the animation is complete yet (normalizedTime will be 1)
if
(_attack.normalizedTime >= 1 -
float
.Epsilon)
{
//Set the state of the enemy based on whether the target is
//dead or not
currentState = target ? EnemyStates.following : EnemyStates.sleeping;
//Make sure the animation has no effect
_attack.weight = 0;
}
break
;
case
EnemyStates.beingHit:
//
enemy는 현재 맞고 있다.
//Check whether the animation is complete
if
(_hit.normalizedTime >= 1 -
float
.Epsilon)
{
//Animation is complete so set the state based on whether
//the enemy is still alive (in which case chase it).
currentState = target ? EnemyStates.following : EnemyStates.sleeping;
}
break
;
case
EnemyStates.dying:
//Wait for the end of the death animation
if
(_die.normalizedTime >= 1 -
float
.Epsilon)
{
//Animation is complete, destroy the enemy
Destroy(gameObject);
}
break
;
}
}