Best Laid Schemes
Contributions
Gameplay Programmer
Creation of a Map with a Navmesh
Player interactions
AI movement
Animations
Project Overview
Project Duration - 6 Weeks
Genre - Stealth
Engine - TenGine (In-house)
Team Size - 11
Platfroms - PC & Playstation 5
Personal Notes
It was a unique opportunity to work in the in-house engine, building the game from the ground up in addition to a lack of documentation. I also have a soft spot for both turn based and stealth games.
I had to make our pathfinding, input, navmesh, AI, and our own animation system for all the characters, and I am grateful for the experience.
Development Process
Turn Manager
As we knew we didn't have a lot of time, I made the turn manager while the characters and enemies were being worked on since we knew this was a vital part of the game, meaning that we would have to go through a lot of iterations before we had a viable product. We had a hard time getting the initial "turn based" portion of the gameplay to stick. After deliberating with the other programmers, our solution for it was to make a turn manager that took care of all the characters in one go. The idea was to make something that generalized it as much as possible.
Through a lot of playtesting and the iterative process, we made different states depending on if the character was a player or an AI. Having differing functionality, yet using the same overarching system from the turn manager.
switch ( _state )
{
case iTurnState::PLANNING:
{
m_map->m_chosen_coords.clear();
for ( cPlayer* player : m_players )
{
m_map->m_chosen_coords.emplace_back( player->getPos() / m_map->m_spacing );
}
for ( cEnemy* enemy : m_enemies )
{
enemy->setState( cCharacter::IDLE );
}
checkInput( m_current_character_turn );
}
break;
case iTurnState::WALKING:
{
for ( cEnemy* enemy : m_enemies )
{
enemy->setState( cCharacter::WALKING );
}
for ( cPlayer* player : m_players )
{
if( player->getState() != cCharacter::CAUGHT && player->getState() != cCharacter::INTERACTING )
{
player->setState( cCharacter::WALKING );
player->m_finished_moves = false;
player->m_is_selected = false;
}
}
}
break;
default:
break;
}
The animations were also done as part of the turn manager
In retrospect, another approach using a base class for both players and enemies would be prefferable for both the verbostiy and cleanliness of states with the turn manager.
Naive A* Implementation
Acknowledging the time constraints, I made a naive implementation of the A* pathfinding algorithm, making it as generalized as possible so we could implement it for both the AI and the player characters. I find the closest tile you could move to from the mouse position using a raycast.
I also made a custom Obstacle Generator for the map, making the map generation itself modular. You could make the navmesh work on any model. I made it using raycasts, checking if it hits any kind of obstacle, and removing it from the navmesh if it did.