Creo que una solución sólida sería ir orientado a objetos.
Dependiendo del tipo de logro que desee apoyar, necesita una forma de consultar el estado actual de su juego y / o el historial de acciones / eventos que han realizado los objetos del juego (como el jugador).
Digamos que tiene una clase de Logro base como:
class AbstractAchievement
{
GameState& gameState;
virtual bool IsEarned() = 0;
virtual string GetName() = 0;
};
AbstractAchievement
tiene una referencia al estado del juego. Se utiliza para consultar las cosas que están sucediendo.
Luego haces implementaciones concretas. Usemos sus ejemplos:
class MasterSlicerAchievement : public AbstractAchievement
{
string GetName() { return "Master Slicer"; }
bool IsEarned()
{
Action lastAction = gameState.GetPlayerActionHistory().GetAction(0);
Action previousAction = gameState.GetPlayerActionHistory().GetAction(1);
if (lastAction.GetType() == ActionType::Slice &&
previousAction.GetType() == ActionType::Slice &&
lastAction.GetObjectType() == ObjectType::Watermelon &&
previousAction.GetObjectType() == ObjectType::Strawberry)
return true;
return false;
}
};
class InvinciblePipeRiderAchievement : public AbstractAchievement
{
string GetName() { return "Invincible Pipe Rider"; }
bool IsEarned()
{
if (gameState.GetLocationType(gameState.GetPlayerPosition()) == LocationType::OVER_PIPE &&
gameState.GetPlayerState() == EntityState::INVINCIBLE)
return true;
return false;
}
};
Entonces depende de usted decidir cuándo verificar utilizando el IsEarned()
método. Puedes consultar cada actualización del juego.
Una forma más eficiente sería, por ejemplo, tener algún tipo de administrador de eventos. Y luego registre eventos (como PlayerHasSlicedSomethingEvent
o PlayerGotInvicibleEvent
simplemente PlayerStateChanged
) en un método que tome el logro en parámetro. Ejemplo:
class Game
{
void Initialize()
{
eventManager.RegisterAchievementCheckByActionType(ActionType::Slice, masterSlicerAchievement);
// Each time an action of type Slice happens,
// the CheckAchievement() method is invoked with masterSlicerAchievement as parameter.
eventManager.RegisterAchievementCheckByPlayerState(EntityState::INVINCIBLE, invinciblePiperAchievement);
// Each time the player gets the INVINCIBLE state,
// the CheckAchievement() method is invoked with invinciblePipeRiderAchievement as parameter.
}
void CheckAchievement(const AbstractAchievement& achievement)
{
if (!HasAchievement(player, achievement) && achievement.IsEarned())
{
AddAchievement(player, achievement);
}
}
};
if(...) return true; else return false;
es lo mismo quereturn (...)
Bueno, en resumen, los logros se desbloquean cuando se cumple una determinada condición. Por lo tanto, debe poder generar sentencias if para verificar la condición que desea.
Por ejemplo, si desea saber que un nivel se completó o un jefe fue derrotado, necesitaría que la bandera booleana se volviera verdadera cuando ocurrieran estos eventos.
Entonces:
Puede hacer esto tan complejo o simplista como sea necesario para que coincida con la condición que desea.
Puede encontrar información sobre los logros de Xbox 360 aquí .
fuente
¿Qué pasa si cada acción que el jugador realiza publica un mensaje en el
AchievementManager
? Luego, el gerente puede verificar internamente si se han cumplido ciertas condiciones. Los primeros objetos publican mensajes:Y luego
AchievementManager
comprueba si necesita hacer algo:Sin embargo, es probable que desee hacer esto con enumeraciones en lugar de cadenas. ;)
fuente
AchievementManager
en cada clase (que es lo que OP preguntaba cómo evitar en primer lugar). Y use una enumeración o clases separadas para sus mensajes, no literales de cadena; usar literales de cadena para pasar el estado siempre es una mala idea.El último diseño que utilicé se basó en tener un conjunto de contadores persistentes por usuario y luego hacer que los logros eliminen cierto contador que alcanza un cierto valor. La mayoría eran un solo par de logro / contador donde el contador solo sería 0 o 1 (y el logro se activaba en> = 1), pero también puedes usar esto para "tipos X muertos" o "cofres X encontrados". También significa que puede configurar contadores para algo que no tiene logros, y aún se rastreará para su uso futuro.
fuente
Cuando implementé los logros en mi último juego, lo hice todo basado en estadísticas. Los logros se desbloquean cuando nuestras estadísticas alcanzan cierto valor. Considera Modern Warfare 2: ¡el juego rastrea toneladas de estadísticas! ¿Cuántas tomas has tomado con el SCAR-H? ¿Cuántas millas has corrido mientras usas el beneficio Lightweight?
Entonces, en mi implementación, simplemente creé un motor de estadísticas, luego creé un administrador de logros que ejecuta consultas realmente simples para verificar el estado de los logros durante el juego.
Si bien mi implementación es bastante simplista, hace el trabajo. Escribí sobre eso y compartí mis consultas aquí .
fuente
Usar cálculo de eventos . Luego, haga algunas condiciones previas y acciones que se aplican después de que se cumplan las condiciones previas:
Úselo como (¡no optimizado para la velocidad!):
Si quieres hacerlo rápido:
Nota
Es difícil dar el mejor consejo ya que todas las cosas tienen pros y contras.
fuente
¿Qué tiene de malo una verificación IF después de que ocurra el evento de logro?
fuente