Ejemplo n.º 1
0
void Boids::MakeMoves( const GameState currentState, size_t teamIndex, std::vector<Move>& outMoves ) {
	const Team& team						= currentState.Teams[teamIndex];
	const glm::vec2 teamAvaragePosition		= CalculateAvaragePosition( currentState, teamIndex );
	
	// Choose a new apple for the team as its goal if the previous goal-apple was taken.
	if ( !currentState.IsTileWalkable( m_GoalTile ) || currentState.Board[m_GoalTile.y][m_GoalTile.x] != Tile::Apple ) {
		m_GoalTile		= currentState.FindClosestApple( teamAvaragePosition );		// TODO: Figure out another goal if there are no apples.
	}

	// Decide for each snake which direction it should move.
	for ( size_t snakeIndex = 0; snakeIndex < team.Snakes.size(); ++snakeIndex ) {
		const Snake& snake						= team.Snakes[snakeIndex];
		const glm::ivec2& snakeTile				= snake.Segments[0];
		const glm::vec2 snakePosition			= glm::vec2( snakeTile );

		// Calculate which moves the snake can make without dying this turn.		// TODO: Take into account that tails move.
		std::vector<Move> safeMoves;
		if ( currentState.IsTileWalkable( snakeTile + glm::ivec2( 0, -1 ) ) ) {
			safeMoves.push_back( Move::Up );
		}
		if ( currentState.IsTileWalkable( snakeTile + glm::ivec2( 0, 1 ) ) ) {
			safeMoves.push_back( Move::Down );
		}
		if ( currentState.IsTileWalkable( snakeTile + glm::ivec2( -1, 0 ) ) ) {
			safeMoves.push_back( Move::Left );
		}
		if ( currentState.IsTileWalkable( snakeTile + glm::ivec2( 1, 0 ) ) ) {
			safeMoves.push_back( Move::Right );
		}

		// If there is only one safe move it is chosen, and we continue to the next snake instead.
		if ( safeMoves.size() == 1 ) {
			outMoves[snakeIndex]		= safeMoves.front();
			continue;
		}

		// Calculate and accumulate the effect of each rule that makes up boids (plus some extra ones specialized for the application snake/nibbles).
		glm::vec2 newSnakeDirection		= glm::vec2( 0.0f );
		newSnakeDirection				+= RULE_FACTOR_GOAL					* GoalDirection( currentState, teamIndex, snakeIndex );
		newSnakeDirection				+= RULE_FACTOR_LOCAL_GOAL			* LocalGoalDirection( currentState, teamIndex, snakeIndex );
		newSnakeDirection				+= RULE_FACTOR_SEPERATION			* SeperationDirection( currentState, teamIndex, snakeIndex );
		if ( team.Snakes.size() > 1 ) {		// Only apply team-rules if the snake is not alone in the team.
			newSnakeDirection				+= RULE_FACTOR_COHESION				* CohesionDirection( currentState, teamIndex, snakeIndex );
			newSnakeDirection				+= RULE_FACTOR_ALIGNMENT			* AlignmentDirection( currentState, teamIndex, snakeIndex );
			newSnakeDirection				+= RULE_FACTOR_TEAM_SEPERATION		* TeamSeperationDirection( currentState, teamIndex, snakeIndex );
		}

		outMoves[snakeIndex]		= ChooseSafeMove( newSnakeDirection, outMoves[snakeIndex], safeMoves );
	}
}
Ejemplo n.º 2
0
glm::vec2 Boids::SeperationDirection( const GameState& gameState, const size_t teamIndex, const size_t snakeIndex ) const {
	const Team& team				= gameState.Teams[teamIndex];
	const Snake& snake				= team.Snakes[snakeIndex];
	const glm::ivec2& snakeTile		= snake.Segments[0];

	// Accumulate repelling forces that keeps the snake away from blocked tiles within the avoidance distance.
	glm::vec2 avoidDirection		= glm::vec2( 0.0f );
	for ( int dy = -AVOIDANCE_DISTANCE; dy <= AVOIDANCE_DISTANCE; ++dy ) {
		for ( int dx = -AVOIDANCE_DISTANCE; dx <= AVOIDANCE_DISTANCE; ++dx ) {
			const glm::ivec2 tile		= glm::ivec2( snakeTile.x + dx, snakeTile.y + dy );

			// Tiles that are walkable are skipped, since they are safe for the snake to traverse.
			if ( gameState.IsTileWalkable( tile ) ) {		// TODO: Take into account that tails move.
				continue;
			}

			// Skip tile if it is one of the 4 first segments in the snake, since the head cannot collide with any of those segments.
			bool skipTile = false;
			for ( size_t segmentIndex = 0; segmentIndex < 4 && segmentIndex < snake.Segments.size(); ++segmentIndex ) {
				if ( tile == snake.Segments[segmentIndex] ) {
					skipTile = true;
					break;
				}
			}
			if ( skipTile ) {
				continue;
			}

			// Add repelling force that keeps the snake away from the tile
			const glm::vec2 vectorFromTile		= glm::vec2( snakeTile - tile );
			const float distanceFromTile		= glm::length( vectorFromTile );
			avoidDirection 						+= vectorFromTile / ( glm::pow( distanceFromTile, 3 ) );		// Force diminishes with distance.
		}
	}
	return avoidDirection;
}