16. Ennemis plus intelligents
Téléchargement fichiers référence desktop.zip core.src.zip core.assets.zip
De retour à l'intérieur du donjon, nous voulons maintenant améliorer le comportement des ennemis afin qu'ils semblent plus intelligents. En particulier, à la place de continuellement pourchasser le joueur nous voulons incorporer un nombre d'états différents dans le comportement des ennemis.
Dans le cadre de ce projet, nous définirons les états
Wander
qui permet aux ennemis de se promener sans but prédéterminéIdle
qui permet aux ennemis de rester immobiles pour une durée limiteChase
qui permet aux ennemis de pourchasser le joueur
Étapes à suivre
Modifiez la classe
Enemy
en ajoutant les états définis ci-dessus
- ajoutez une la classe
StateUtils
qui défini les états de l'ennemi- ajoutez les constantes permettant de configurer les états de l'ennemi
- ajoutez une méthode
setState
permettant l'initialisation d'un état
- Pour chaque état, l'initialisation permet d'immobiliser l'ennemi afin de partir à zéro.
- Pour l'état
Wander
l'initialisation permet de choisir une destination aléatoirement- ajoutez une méthode
updateState
permettant la mise à jour de l'état
- Imposez une limite de temps à chaque état à l'aide de la variable
stateTime
- Déterminez les transitions nécessaires entre les états lorsque le joueur passe suffisamment proche de l'ennemi ou lorsque la limite de temps est écoulée.
/* Enemy.java */
package com.tutorialquest.entities;
// import ..
public class Enemy extends Character {
// AJOUT:
public class StateUtils
{
public static final int IDLE = 0;
public static final int CHASE = 1;
public static final int WANDER = 2;
}
// AJOUT:
// Constantes pour configurer les états de l'ennemi
public static final float IDLE_TIME_LIMIT = 2f;
public static final float WANDER_DISTANCE_RANGE = 96f;
public static final float WANDER_TIME_LIMIT = 5f;
public static final float CHASE_DETECTION_RANGE = 64f;
public static final float DESTINATION_DISTANCE_EPSILON = 0.1f;
// AJOUT:
private PhysicalObject chaseTarget = null;
private Vector2 wanderTarget = new Vector2();
public int state = StateUtils.IDLE;
// Variable qui sert à imposer une limite de temps à un état
private float stateTime = 0;
// AJOUT:
// Initialisation de l'état
public void setState(int state)
{
stateTime = 0;
switch (state)
{
case StateUtils.CHASE:
controlAxes.setZero();
locomotionVelocity.setZero();
break;
case StateUtils.IDLE:
controlAxes.setZero();
locomotionVelocity.setZero();
break;
case StateUtils.WANDER:
controlAxes.setZero();
locomotionVelocity.setZero();
// Choix de la destination de promenade aléatoire
wanderTarget
.set(position)
.add(new Vector2()
.setToRandomDirection()
.scl(WANDER_DISTANCE_RANGE));
break;
}
this.state = state;
}
// AJOUT:
public void updateState(float deltaTime)
{
stateTime += deltaTime;
switch (state)
{
// Mouvement en direction du joueur
case StateUtils.CHASE:
if(
chaseTarget == null ||
position.dst(chaseTarget.position) > CHASE_DETECTION_RANGE)
{
setState(StateUtils.IDLE);
return;
}
controlAxes
.set(chaseTarget.position)
.sub(position)
.nor();
locomotionVelocity
.set(controlAxes)
.scl(speed);
break;
// Imobilisation
case StateUtils.IDLE:
if(
chaseTarget != null &&
position.dst(chaseTarget.position) < CHASE_DETECTION_RANGE)
{
setState(StateUtils.CHASE);
return;
}
if(stateTime >= IDLE_TIME_LIMIT)
{
setState(StateUtils.WANDER);
return;
}
break;
// Déplacement en direction de la destination de promenade
case StateUtils.WANDER:
if(
chaseTarget != null &&
position.dst(chaseTarget.position) < CHASE_DETECTION_RANGE)
{
setState(StateUtils.CHASE);
return;
}
if(
stateTime >= WANDER_TIME_LIMIT ||
position.epsilonEquals(wanderTarget, DESTINATION_DISTANCE_EPSILON))
{
setState(StateUtils.IDLE);
return;
}
controlAxes
.set(wanderTarget)
.sub(position)
.nor();
locomotionVelocity
.set(controlAxes)
.scl(speed);
break;
}
}
public Enemy(Vector2 position) {
// ...
// AJOUT:
// État initial
setState(StateUtils.IDLE);
}
@Override
public void update(float deltaTime) {
super.update(deltaTime);
// AJOUT:
updateState(deltaTime);
// ...
}
}