Skip to content

Commit

Permalink
tsunami rendering improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
gtanczyk committed Aug 22, 2024
1 parent 5c73c00 commit ef10b35
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 64 deletions.
1 change: 1 addition & 0 deletions js13k2024/game/src/game-states/gameplay/game-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ const handleTsunamiEffect = (gameState: GameState): void => {
startGameOverAnimation(gameState);
}
gameState.monsters = [];
gameState.tsunamiLevel = 0;
}
};

Expand Down
12 changes: 7 additions & 5 deletions js13k2024/game/src/game-states/gameplay/game-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { calculateShakeOffset, interpolatePosition } from './render/animation-ut
import { drawTooltip } from './render/tooltip-render';
import { drawElectricalDischarges } from './render/discharges-render';
import { drawPlatform } from './render/grid-render';
import { drawBlasterShot, drawSlideTrail, drawTsunamiEffect } from './render/bonus-effect-render';
import { drawBlasterShot, drawSlideTrail, drawTsunamiWave, generateTsunamiWaves } from './render/bonus-effect-render';

export const PLATFORM_HEIGHT = 20;

Expand Down Expand Up @@ -42,10 +42,8 @@ export const drawGameState = (
// Draw the grid
drawGrid(ctx, gridSize, gameState);

// Draw tsunami effect
if (gameState.tsunamiLevel > 0) {
drawTsunamiEffect(ctx, gameState, gridSize, cellSize);
}
// Generate tsunami effect
const tsunamiWaves = gameState.tsunamiLevel > 0 ? generateTsunamiWaves(gameState, gridSize, cellSize) : [];

// Draw electrical discharges
drawElectricalDischarges(ctx, gridSize, gameState.monsterSpawnSteps, gameState.player.moveTimestamp, cellSize);
Expand All @@ -57,6 +55,7 @@ export const drawGameState = (

// Prepare all game objects for sorting
const allObjects = [
...tsunamiWaves.map((obj) => ({ position: obj.grid, type: 'wave', obj }) as const),
...gameState.obstacles.map((obj) => ({ position: obj.position, type: 'obstacle', obj }) as const),
...gameState.bonuses.map((obj) => ({ position: obj.position, type: 'bonus', obj }) as const),
...gameState.landMines.map((obj) => ({ position: obj, type: 'landMine' }) as const),
Expand All @@ -82,6 +81,9 @@ export const drawGameState = (
for (const sortedObject of sortedObjects) {
const { type, position } = sortedObject;
switch (type) {
case 'wave':
drawTsunamiWave(ctx, sortedObject.obj);
break;
case 'obstacle':
drawObstacles(ctx, [sortedObject.obj], cellSize);
break;
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.Sokoban)];
state.bonuses = [createBonus(1, 3, BonusType.Tsunami)];

return [state, config, config.levelStory];
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,58 @@ import { interpolatePosition } from './animation-utils';
import { BlasterShot, Direction, GameState, Position } from '../gameplay-types';
import { toIsometric } from './isometric-utils';

export const drawTsunamiEffect = (
ctx: CanvasRenderingContext2D,
gameState: GameState,
gridSize: number,
cellSize: number,
) => {
type TsunamiWave = {
tsunamiLevel: number;
grid: Position;
iso: [Position, Position, Position, Position];
};

export const generateTsunamiWaves = (gameState: GameState, gridSize: number, cellSize: number): TsunamiWave[] => {
const { tsunamiLevel } = gameState;
const maxWaterHeight = cellSize * 0.8; // Maximum water height when tsunamiLevel reaches 13

ctx.save();
ctx.globalAlpha = 0.6; // Make the water slightly transparent
const waves: TsunamiWave[] = [];

for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
const { x: isoX, y: isoY } = toIsometric(x, y);
const topL = toIsometric(x, y);
const topR = toIsometric(x + 1, y);
const bottomL = toIsometric(x, y + 1);
const bottomR = toIsometric(x + 1, y + 1);
const waterHeight = (tsunamiLevel / 13) * maxWaterHeight;

ctx.fillStyle = `rgba(0, 100, 255, ${tsunamiLevel / 13})`; // Blue color with increasing opacity
ctx.beginPath();
ctx.moveTo(isoX, isoY);
ctx.lineTo(isoX + cellSize / 2, isoY + cellSize / 4);
ctx.lineTo(isoX, isoY + cellSize / 2);
ctx.lineTo(isoX - cellSize / 2, isoY + cellSize / 4);
ctx.closePath();
ctx.fill();

// Add wave effect
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(isoX - cellSize / 2, isoY + cellSize / 4 - waterHeight + Math.sin(Date.now() / 200 + x * 0.5) * 5);
ctx.lineTo(
isoX + cellSize / 2,
isoY + cellSize / 4 - waterHeight + Math.sin(Date.now() / 200 + (x + 1) * 0.5) * 5,
);
ctx.stroke();
const wave1 = waterHeight + Math.sin(Date.now() / 200 + x * 0.5) * 5;
const wave2 = waterHeight + Math.sin(Date.now() / 200 + (x + 1) * 0.5) * 5;

waves.push({
tsunamiLevel,
grid: { x, y },
iso: [
{ x: topL.x, y: topL.y - wave1 },
{ x: bottomL.x, y: bottomL.y - wave2 },
{ x: bottomR.x, y: bottomR.y - wave2 },
{ x: topR.x, y: topR.y - wave1 },
],
});
}
}

return waves;
};

export const drawTsunamiWave = (ctx: CanvasRenderingContext2D, wave: TsunamiWave) => {
ctx.save();
ctx.globalAlpha = 0.6; // Make the water slightly transparent

ctx.fillStyle = `rgba(0, 100, 255, ${wave.tsunamiLevel / 13})`; // Blue color with increasing opacity
ctx.beginPath();
ctx.moveTo(wave.iso[0].x, wave.iso[0].y);
for (let i = 1; i < wave.iso.length; i++) {
ctx.lineTo(wave.iso[i].x, wave.iso[i].y);
}
ctx.closePath();
ctx.fill();

ctx.restore();
};

Expand Down
30 changes: 0 additions & 30 deletions js13k2024/game/src/game-states/gameplay/render/grid-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ export const drawGrid = (ctx: CanvasRenderingContext2D, gridSize: number, gameSt
ctx.stroke();
}

// Draw Tsunami effect
if (gameState.tsunamiLevel > 0) {
drawTsunamiTile(ctx, x, y, gameState.tsunamiLevel);
}

// Draw Slide effect if active
if (gameState.isSliding) {
drawSlideTile(ctx, x, y);
Expand All @@ -76,31 +71,6 @@ export const drawGrid = (ctx: CanvasRenderingContext2D, gridSize: number, gameSt
}
};

const drawTsunamiTile = (ctx: CanvasRenderingContext2D, x: number, y: number, tsunamiLevel: number) => {
const { x: isoX, y: isoY } = toIsometric(x, y);
const waterHeight = (tsunamiLevel / 13) * TILE_HEIGHT * 0.5; // Max water height is half of tile height

ctx.fillStyle = `rgba(0, 100, 255, ${tsunamiLevel / 26})`; // Increasing opacity as tsunami level increases
ctx.beginPath();
ctx.moveTo(isoX, isoY - waterHeight);
ctx.lineTo(isoX + TILE_WIDTH / 2, isoY + TILE_HEIGHT / 2 - waterHeight);
ctx.lineTo(isoX, isoY + TILE_HEIGHT - waterHeight);
ctx.lineTo(isoX - TILE_WIDTH / 2, isoY + TILE_HEIGHT / 2 - waterHeight);
ctx.closePath();
ctx.fill();

// Add wave effect
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(isoX - TILE_WIDTH / 2, isoY + TILE_HEIGHT / 2 - waterHeight + Math.sin(Date.now() / 200 + x * 0.5) * 3);
ctx.lineTo(
isoX + TILE_WIDTH / 2,
isoY + TILE_HEIGHT / 2 - waterHeight + Math.sin(Date.now() / 200 + (x + 1) * 0.5) * 3,
);
ctx.stroke();
};

const drawSlideTile = (ctx: CanvasRenderingContext2D, x: number, y: number) => {
const { x: isoX, y: isoY } = toIsometric(x, y);

Expand Down

0 comments on commit ef10b35

Please sign in to comment.