Skip to content

Commit

Permalink
isActiveBonus function instead of bonus state on player/game state props
Browse files Browse the repository at this point in the history
  • Loading branch information
gtanczyk committed Aug 22, 2024
1 parent 15466bd commit 2e0e551
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 56 deletions.
42 changes: 18 additions & 24 deletions js13k2024/game/src/game-states/gameplay/game-logic.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { GameState, Position, LevelConfig, Direction, BonusType, ActiveBonus, BlasterShot } from './gameplay-types';
import {
GameState,
Position,
LevelConfig,
Direction,
BonusType,
ActiveBonus,
BlasterShot,
isActiveBonus,
} from './gameplay-types';
import {
moveMonsters,
checkCollision,
Expand Down Expand Up @@ -62,7 +71,7 @@ export const doGameUpdate = (direction: Direction, gameState: GameState, levelCo
);

if (
gameState.crusherActive &&
isActiveBonus(newGameState, BonusType.Crusher) &&
gameState.obstacles.find((obstacle) => isPositionEqual(newPosition, obstacle.position))
) {
newGameState.obstacles = gameState.obstacles.map((obstacle) =>
Expand Down Expand Up @@ -122,12 +131,13 @@ export const doGameUpdate = (direction: Direction, gameState: GameState, levelCo
newGameState.player.position,
levelConfig.gridSize,
newGameState.obstacles,
newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.CapOfInvisibility),
newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.ConfusedMonsters),
isActiveBonus(newGameState, BonusType.CapOfInvisibility),
isActiveBonus(newGameState, BonusType.ConfusedMonsters),
isActiveBonus(newGameState, BonusType.Monster),
);

// Handle Monster bonus
if (newGameState.player.isMonster) {
if (isActiveBonus(newGameState, BonusType.Monster)) {
handleMonsterBonus(newGameState);
} else {
// Check for collisions with monsters
Expand All @@ -139,7 +149,7 @@ export const doGameUpdate = (direction: Direction, gameState: GameState, levelCo
}

// Handle Blaster bonus
if (newGameState.player.hasBlaster) {
if (isActiveBonus(newGameState, BonusType.Blaster)) {
handleBlasterShot(newGameState, direction, levelConfig);
}
newGameState.blasterShots = newGameState.blasterShots.filter(
Expand Down Expand Up @@ -191,13 +201,8 @@ export const doGameUpdate = (direction: Direction, gameState: GameState, levelCo
.map((bonus) => ({ ...bonus, duration: bonus.duration - 1 }))
.filter((bonus) => bonus.duration > 0);

newGameState.builderActive = newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.Builder);
newGameState.crusherActive = newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.Crusher);
newGameState.player.isClimbing = newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.Climber);
newGameState.isSliding = newGameState.activeBonuses.some((bonus) => bonus.type === BonusType.Slide);

// Handle builder bonus
if (gameState.builderActive) {
if (isActiveBonus(newGameState, BonusType.Builder)) {
const newObstacle = { position: oldPosition, creationTime: Date.now(), isRaising: true, isDestroying: false };
if (
!isPositionOccupied(
Expand Down Expand Up @@ -236,13 +241,10 @@ export const applyBonus = (gameState: GameState, bonusType: BonusType) => {
});
break;
case BonusType.Crusher:
gameState.crusherActive = true;
break;
case BonusType.Builder:
gameState.builderActive = true;
break;
case BonusType.Climber:
gameState.player.isClimbing = true;
break;
case BonusType.Teleport:
// Teleport is handled immediately when collected
Expand All @@ -251,17 +253,13 @@ export const applyBonus = (gameState: GameState, bonusType: BonusType) => {
gameState.tsunamiLevel = 1;
break;
case BonusType.Monster:
gameState.player.isMonster = true;
break;
case BonusType.Slide:
gameState.isSliding = true;
break;
case BonusType.Sokoban:
// Sokoban logic is handled in movement
break;
case BonusType.Blaster:
gameState.player.hasBlaster = true;
gameState.player.blasterSteps = 13;
break;
}
};
Expand Down Expand Up @@ -330,7 +328,7 @@ const performTeleportation = (gameState: GameState, teleportPoint: Position): vo
const handleTsunamiEffect = (gameState: GameState): void => {
gameState.tsunamiLevel++;
if (gameState.tsunamiLevel >= 13) {
if (!gameState.player.isClimbing) {
if (!isActiveBonus(gameState, BonusType.Climber)) {
gameState.gameEndingState = 'gameOver';
startGameOverAnimation(gameState);
}
Expand Down Expand Up @@ -408,10 +406,6 @@ const handleBlasterShot = (gameState: GameState, direction: Direction, levelConf
const isHit = isMonsterOnBlasterPath(monster.position, start, end, direction);
return !isHit;
});

if (gameState.player.hasBlaster && gameState.player.blasterSteps!-- <= 0) {
gameState.player.hasBlaster = false;
}
};

const isMonsterOnBlasterPath = (
Expand Down
9 changes: 5 additions & 4 deletions js13k2024/game/src/game-states/gameplay/game-render.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BonusType, GameState, LevelConfig } from './gameplay-types';
import { BonusType, GameState, isActiveBonus, LevelConfig } from './gameplay-types';
import { drawObstacles, drawGoal } from './render/grid-objects-render';
import { drawGrid } from './render/grid-render';
import { drawPlayer } from './render/player-render';
Expand Down Expand Up @@ -97,7 +97,7 @@ export const drawGameState = (
drawTimeBombs(ctx, [sortedObject.obj], cellSize);
break;
case 'monster':
drawMonsters(ctx, [sortedObject.obj], cellSize, gameState.player.isMonster);
drawMonsters(ctx, [sortedObject.obj], cellSize, isActiveBonus(gameState, BonusType.Monster));
break;
case 'player':
drawPlayer(
Expand All @@ -106,8 +106,9 @@ export const drawGameState = (
cellSize,
gameState.activeBonuses.some((bonus) => bonus.type === BonusType.CapOfInvisibility),
gameState.obstacles,
gameState.player.isMonster,
gameState.player.hasBlaster,
isActiveBonus(gameState, BonusType.Monster),
isActiveBonus(gameState, BonusType.Blaster),
isActiveBonus(gameState, BonusType.Climber),
);
break;
case 'goal':
Expand Down
11 changes: 4 additions & 7 deletions js13k2024/game/src/game-states/gameplay/gameplay-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,8 @@ export interface Player {
previousPosition: Position;
moveTimestamp: number;
teleportTimestamp?: number;
isInvisible: boolean;
isVictorious: boolean;
isVanishing: boolean;
isClimbing: boolean;
isMonster: boolean;
hasBlaster: boolean;
blasterSteps: number | undefined;
}

export interface Obstacle {
Expand All @@ -68,8 +63,6 @@ export interface GameState {
explosions: Explosion[];
timeBombs: TimeBomb[];
landMines: Position[];
crusherActive: boolean;
builderActive: boolean;
score: number;
gameEndingState: GameEndingState;
tsunamiLevel: number;
Expand Down Expand Up @@ -217,3 +210,7 @@ export interface EntityAnimationState {
bounceOffset: number;
tentacleAnimationFactor: number;
}

export function isActiveBonus(gameState: GameState, bonusType: BonusType) {
return gameState.activeBonuses.some((bonus) => bonus.type === bonusType);
}
7 changes: 0 additions & 7 deletions js13k2024/game/src/game-states/gameplay/level-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,8 @@ const createPlayer = (x: number, y: number): Player => ({
position: createPosition(x, y),
previousPosition: createPosition(x, y),
moveTimestamp: Date.now(),
isInvisible: false,
isVictorious: false,
isVanishing: false,
isClimbing: false,
isMonster: false,
hasBlaster: false,
blasterSteps: undefined,
});

const createObstacle = (x: number, y: number): Obstacle => ({
Expand All @@ -62,8 +57,6 @@ const generateBaseState = (): GameState => ({
explosions: [],
timeBombs: [],
landMines: [],
crusherActive: false,
builderActive: false,
score: 0,
gameEndingState: 'none',
tsunamiLevel: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const generateLevel = (): [GameState, LevelConfig, string] => {
state.goal = createPosition(6, 3);
state.monsters = [createMonster(3, 0)];
state.obstacles = [createObstacle(2, 3), createObstacle(5, 2), createObstacle(5, 3)];
state.bonuses = [createBonus(1, 3, BonusType.Tsunami)];
state.bonuses = [createBonus(1, 3, BonusType.Builder)];

return [state, config, config.levelStory];
};
5 changes: 3 additions & 2 deletions js13k2024/game/src/game-states/gameplay/monster-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const moveMonsters = (
obstacles: Obstacle[],
isPlayerInvisible: boolean,
isConfused: boolean,
isPlayerMonster: boolean,
): Monster[] => {
const newPositions: Position[] = [];
return monsters.map((monster) => {
Expand All @@ -21,8 +22,8 @@ export const moveMonsters = (
}

let newPosition: Position;
if (isConfused) {
// If monsters are confused, move in the opposite direction
if (isConfused || isPlayerMonster) {
// If monsters are confused, or player is the monster, move in the opposite direction
newPosition = getConfusedPosition(monster.position, path[1] || monster.position, gridSize, obstacles, monsters);
} else {
newPosition = path.length > 1 ? path[1] : monster.position;
Expand Down
8 changes: 6 additions & 2 deletions js13k2024/game/src/game-states/gameplay/move-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BonusType, Direction, GameState, LevelConfig, Position } from './gameplay-types';
import { BonusType, Direction, GameState, isActiveBonus, LevelConfig, Position } from './gameplay-types';
import { getArrowShape } from './render/move-arrows-render';

export const isPositionEqual = (pos1: Position, pos2: Position): boolean => pos1.x === pos2.x && pos1.y === pos2.y;
Expand Down Expand Up @@ -95,7 +95,11 @@ export const isValidMove = (
);

// Allow movement onto obstacles if the player has the Climber bonus active
if (isObstaclePresent && !gameState.player.isClimbing && !gameState.crusherActive) {
if (
isObstaclePresent &&
!isActiveBonus(gameState, BonusType.Climber) &&
!isActiveBonus(gameState, BonusType.Crusher)
) {
// Check if Sokoban bonus is active
if (gameState.activeBonuses.some((bonus) => bonus.type === BonusType.Sokoban)) {
const pushDirection = getDirectionFromPositions(gameState.player.position, newPosition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export const drawPlayer = (
obstacles: Obstacle[] = [],
isMonster: boolean = false,
hasBlaster: boolean = false,
isClimbing: boolean = false,
) => {
const { position, previousPosition, moveTimestamp, teleportTimestamp, isVanishing, isVictorious, isClimbing } =
player;
const { position, previousPosition, moveTimestamp, teleportTimestamp, isVanishing, isVictorious } = player;
const isTeleporting = teleportTimestamp && Date.now() - teleportTimestamp < TELEPORT_ANIMATION_DURATION;

const interpolatedPosition = isTeleporting
Expand Down
7 changes: 0 additions & 7 deletions js13k2024/game/src/game-states/intro/game-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@ const createPreviewGameState = (): GameState => ({
position: { x: 2, y: 2 },
previousPosition: { x: 2, y: 2 },
moveTimestamp: Date.now(),
isInvisible: false,
isVictorious: false,
isVanishing: false,
isClimbing: false,
isMonster: false,
hasBlaster: false,
blasterSteps: undefined,
},
goal: { x: 4, y: 4 },
obstacles: [
Expand Down Expand Up @@ -54,8 +49,6 @@ const createPreviewGameState = (): GameState => ({
explosions: [],
timeBombs: [],
landMines: [],
crusherActive: false,
builderActive: false,
score: 0,
gameEndingState: 'none',
tsunamiLevel: 0,
Expand Down

0 comments on commit 2e0e551

Please sign in to comment.