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
Wanderqui permet aux ennemis de se promener sans but prédéterminéIdlequi permet aux ennemis de rester immobiles pour une durée limiteChasequi permet aux ennemis de pourchasser le joueur

Étapes à suivre
Modifiez la classe
Enemyen ajoutant les états définis ci-dessus
- ajoutez une la classe
StateUtilsqui défini les états de l'ennemi- ajoutez les constantes permettant de configurer les états de l'ennemi
- ajoutez une méthode
setStatepermettant l'initialisation d'un état
- Pour chaque état, l'initialisation permet d'immobiliser l'ennemi afin de partir à zéro.
- Pour l'état
Wanderl'initialisation permet de choisir une destination aléatoirement- ajoutez une méthode
updateStatepermettant 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);
// ...
}
}