i am making a platformer and need help making the editor here is my current code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tower Tim</title>
<style>
body {
margin: 0;
background-color: #f0f8ff;
overflow: hidden;
font-family: Arial, sans-serif;
text-align: center;
}
canvas {
display: block;
background-color: #000;
}
h1 {
color: white;
font-size: 48px;
text-shadow: 2px 2px 4px #000000;
}
p {
color: white;
font-size: 15px;
text-shadow: 2px 2px 4px #000000;
}
button {
padding: 15px 30px;
font-size: 24px;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #ff4500;
color: white;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
transition: background-color 0.3s;
}
button:hover {
background-color: #e03c00;
}
</style>
</head>
<body>
<div id="homeMenu" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1;">
<h1>Tower Tim</h1>
<button id="startButton">Start Game</button>
<p></p>
<button id="startButton">Level Editor Coming Soon</button>
<p>MADE BY plasma studios</p>
<p>Version-Alfa 1.02</p>
<audio autoplay loop>
<source src="your_audio_file.mp3" type="audio/mpeg">
<source src="your_audio_file.ogg" type="audio/ogg">
Your browser does not support the audio element.
</audio>
</div>
<canvas id="gameCanvas"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const homeMenu = document.getElementById('homeMenu');
const startButton = document.getElementById('startButton');
// Game states
const GAME_STATE = {
MENU: 'menu',
PLAYING: 'playing'
};
let currentState = GAME_STATE.MENU;
// Game constants
const GRAVITY = 0.5;
const JUMP_POWER = -12;
const PLAYER_SPEED = 9;
const TILE_SIZE = 40;
const DASH_SPEED = 25;
const DASH_DURATION = 15; // frames
const DASH_COOLDOWN = 15; // frames
const MAX_JUMPS = 3; // For double jump
// Map constants
const mapWidthInTiles = 500;
const mapHeightInTiles = 100;
// Game map data (50 wide x 100 high)
// 0 = empty space
// 1 = platform
// 2 = spikes (top)
// 3 = finish line
// 4 = lava (animated)
// 5 = spikes (down)
// 6 = spikes (left)
// 7 = spikes (right)
const gameMap = new Array(mapHeightInTiles).fill(null).map(() => new Array(mapWidthInTiles).fill(0));
// Player object
const player = {
x: TILE_SIZE * 2,
y: TILE_SIZE * 90,
width: TILE_SIZE * 0.75,
height: TILE_SIZE * 0.75,
dx: 0,
dy: 0,
onGround: false,
jumpCount: 0,
canDash: true,
isDashing: false,
dashTimer: 0,
dashCooldown: 0,
facingDirection: 1, // 1 for right, -1 for left
onWall: false,
spawnX: TILE_SIZE * 2,
spawnY: TILE_SIZE * 90
};
// --- EDITED MAP FOR A DIFFICULT LEVEL ---
function createMap() {
// Start area
for (let x = 0; x < 5; x++) { gameMap[95][x] = 1; }
for (let y = 96; y < mapHeightInTiles; y++) { gameMap[y][0] = 1; gameMap[y][4] = 1; }
gameMap[90][5] = 1; gameMap[90][6] = 4;
gameMap[90][7] = 4; gameMap[90][8] = 4;
gameMap[90][5] = 1; gameMap[91][6] = 1;
gameMap[91][7] = 1; gameMap[91][8] = 1;
gameMap[91][7] = 1; gameMap[91][9] = 1;
gameMap[91][7] = 1; gameMap[91][10] = 1;
gameMap[91][7] = 1; gameMap[91][5] = 1;
gameMap[90][9] = 1; gameMap[90][10] = 1;
// Long jump with spikes
gameMap[85][15] = 1;
for (let x = 16; x < 20; x++) { gameMap[85][x] = 4; }
gameMap[85][20] = 1;
// Vertical climbing section
gameMap[80][25] = 1; gameMap[80][26] = 1; gameMap[79][26] = 2;
gameMap[75][30] = 1; gameMap[75][31] = 1; gameMap[74][30] = 2;
gameMap[70][25] = 1; gameMap[70][26] = 1; gameMap[69][26] = 2;
gameMap[65][30] = 1; gameMap[65][31] = 1; gameMap[64][30] = 2;
// Wall jump challenge
for (let y = 60; y < 65; y++) { gameMap[y][10] = 1; gameMap[y][15] = 1; }
for (let x = 11; x < 15; x++) { gameMap[65][x] = 2; }
gameMap[60][12] = 1; gameMap[60][13] = 1;
gameMap[55][12] = 1; gameMap[55][13] = 1;
// Dash tunnel with low ceiling
for (let x = 18; x < 30; x++) { gameMap[50][x] = 1; gameMap[47][x] = 1; }
for (let x = 20; x < 28; x++) { gameMap[49][x] = 2; }
for (let x = 21; x < 27; x++) { gameMap[48][x] = 5; }
// Lava pit with tight platforms
for (let x = 0; x < 50; x++) { gameMap[45][x] = 1; }
gameMap[44][5] = 1; gameMap[44][10] = 1; gameMap[44][15] = 1;
gameMap[44][20] = 1; gameMap[44][25] = 1; gameMap[44][30] = 1;
// Final wall climb
for (let y = 35; y < 44; y++) { gameMap[y][40] = 1; }
for (let y = 35; y < 44; y++) { gameMap[y][44] = 1; }
for (let y = 30; y < 50; y++) { gameMap[y][47] = 1; }
for (let y = 30; y < 52; y++) { gameMap[y][49] = 4; }
gameMap[30][40] = 1;
gameMap[29][40] = 1;
gameMap[28][40] = 1;
gameMap[27][40] = 1;
gameMap[26][40] = 1;
gameMap[25][40] = 1;
gameMap[24][40] = 1;
gameMap[23][40] = 1;
gameMap[22][40] = 1;
gameMap[21][40] = 1;
gameMap[20][40] = 1;
gameMap[19][40] = 1;
gameMap[18][40] = 1;
gameMap[17][40] = 1;
gameMap[16][40] = 1;
gameMap[15][42] = 2;
gameMap[16][41] = 1;
gameMap[16][42] = 1;
gameMap[31][40] = 1;
gameMap[32][40] = 1;
gameMap[33][40] = 1;
gameMap[34][40] = 1;
gameMap[35][40] = 1;
gameMap[36][40] = 1;
gameMap[34][39] = 1;
gameMap[34][38] = 1;
gameMap[43][40] = 1;
// The Finish Line
gameMap[35][42] = 3;
gameMap[44][42] = 2;
gameMap[44][43] = 2;
gameMap[44][41] = 2;
gameMap[44][40] = 1;
gameMap[44][39] = 6;
gameMap[43][39] = 6;
gameMap[42][39] = 6;
gameMap[41][39] = 6;
gameMap[32][39] = 6;
gameMap[31][39] = 6;
gameMap[33][39] = 6;
gameMap[90][4] = 6;
for (let x = 0; x < 90; x++) { gameMap[99][x] = 4; }
}
createMap();
// --- END OF MAP EDITING AREA ---
let cameraX = 0;
let cameraY = 0;
const mapWidth = mapWidthInTiles * TILE_SIZE;
const mapHeight = mapHeightInTiles * TILE_SIZE;
let lavaAnimationFrame = 0;
// Key states
const keys = {
right: false,
left: false,
up: false,
dash: false
};
// Event listeners for key presses
window.addEventListener('keydown', (e) => {
if (currentState === GAME_STATE.PLAYING) {
if (e.key === 'ArrowRight') keys.right = true;
if (e.key === 'ArrowLeft') keys.left = true;
if (e.key === 'ArrowUp') {
if (player.onGround || player.jumpCount < MAX_JUMPS -1) {
player.dy = JUMP_POWER;
player.onGround = false;
player.jumpCount++;
} else if (player.onWall) {
// Wall jump
player.dy = JUMP_POWER;
player.dx = -player.facingDirection * PLAYER_SPEED * 1.5; // Push away from the wall
player.jumpCount = 1; // Reset jump count for double jump
player.onWall = false;
}
}
if (e.key === 'z' && player.canDash) {
keys.dash = true;
}
}
});
window.addEventListener('keyup', (e) => {
if (currentState === GAME_STATE.PLAYING) {
if (e.key === 'ArrowRight') keys.right = false;
if (e.key === 'ArrowLeft') keys.left = false;
if (e.key === 'z') keys.dash = false;
}
});
// Start button handler
startButton.addEventListener('click', () => {
currentState = GAME_STATE.PLAYING;
homeMenu.style.display = 'none';
});
// Main game loop
function gameLoop() {
if (currentState === GAME_STATE.PLAYING) {
update();
draw();
} else {
drawMenu();
}
requestAnimationFrame(gameLoop);
}
// Draw menu
function drawMenu() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
// Update game state
function update() {
// Player horizontal movement
if (!player.isDashing) {
player.dx = 0;
if (keys.right) {
player.dx = PLAYER_SPEED;
player.facingDirection = 1;
}
if (keys.left) {
player.dx = -PLAYER_SPEED;
player.facingDirection = -1;
}
}
// Dash logic
if (keys.dash && player.canDash) {
player.isDashing = true;
player.canDash = false;
player.dashTimer = DASH_DURATION;
player.dx = DASH_SPEED * player.facingDirection;
}
if (player.isDashing) {
player.dashTimer--;
if (player.dashTimer <= 0) {
player.isDashing = false;
player.dx = 0;
}
}
if (!player.canDash) {
player.dashCooldown++;
if (player.dashCooldown >= DASH_COOLDOWN) {
player.canDash = true;
player.dashCooldown = 0;
}
}
// Apply gravity if not dashing
if (!player.isDashing) {
player.dy += GRAVITY;
}
// Update player position
player.x += player.dx;
player.y += player.dy;
// Increment lava animation frame
lavaAnimationFrame = (lavaAnimationFrame + 1) % 60; // 60 frames per second
// Handle collision with map tiles
player.onGround = false;
player.onWall = false;
const tileX = Math.floor(player.x / TILE_SIZE);
const tileY = Math.floor(player.y / TILE_SIZE);
for (let y = Math.max(0, tileY - 2); y < Math.min(gameMap.length, tileY + 3); y++) {
for (let x = Math.max(0, tileX - 2); x < Math.min(gameMap[y].length, tileX + 3); x++) {
if (y >= 0 && y < mapHeightInTiles && x >= 0 && x < mapWidthInTiles) {
const tile = gameMap[y][x];
if (tile !== 0) {
const tileRect = {
x: x * TILE_SIZE,
y: y * TILE_SIZE,
width: TILE_SIZE,
height: TILE_SIZE
};
// Check for collision with deadly tiles first
if (tile === 2 || tile === 4 || tile === 5 || tile === 6 || tile === 7) {
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
resetGame();
}
}
// Check for platform or finish line collision
if (tile === 1 || tile === 3) {
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y + player.height > tileRect.y &&
player.y + player.height <= tileRect.y + tileRect.height &&
player.dy >= 0
) {
player.y = tileRect.y - player.height;
player.dy = 0;
player.onGround = true;
player.jumpCount = 0; // Reset jumps on landing
}
// Wall collision
if (
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
// Left wall
if (player.x + player.width > tileRect.x && player.x < tileRect.x && player.dx >= 0) {
player.x = tileRect.x - player.width;
if (player.onGround === false) player.onWall = true;
}
// Right wall
if (player.x < tileRect.x + tileRect.width && player.x + player.width > tileRect.x + tileRect.width && player.dx <= 0) {
player.x = tileRect.x + tileRect.width;
if (player.onGround === false) player.onWall = true;
}
}
}
if (tile === 3) { // Finish line
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
alert("You Win!");
resetGame();
}
}
}
}
}
}
// Keep player within map bounds
if (player.x < 0) player.x = 0;
if (player.x + player.width > mapWidth) player.x = mapWidth - player.width;
// Handle falling off the map
if (player.y > mapHeight) {
resetGame();
}
// Update camera position to follow the player
cameraX = player.x - canvas.width / 2;
cameraY = player.y - canvas.height / 2;
// Clamp camera to map bounds
if (cameraX < 0) cameraX = 0;
if (cameraX + canvas.width > mapWidth) cameraX = mapWidth - canvas.width;
if (cameraY < 0) cameraY = 0;
if (cameraY + canvas.height > mapHeight) cameraY = mapHeight - canvas.height;
}
// Draw game objects
function draw() {
// Adjust canvas size based on window size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw game map with camera offset
for (let y = 0; y < mapHeightInTiles; y++) {
for (let x = 0; x < mapWidthInTiles; x++) {
const tile = gameMap[y][x];
const screenX = x * TILE_SIZE - cameraX;
const screenY = y * TILE_SIZE - cameraY;
// Only draw tiles visible on screen
if (
screenX + TILE_SIZE > 0 && screenX < canvas.width &&
screenY + TILE_SIZE > 0 && screenY < canvas.height
) {
ctx.save();
if (tile === 1) {
ctx.fillStyle = '#804000'; // Platform
ctx.fillRect(screenX, screenY, TILE_SIZE, TILE_SIZE);
} else if (tile === 2) {
ctx.fillStyle = '#ff0000'; // Spikes (top)
drawSpikes(screenX, screenY, 'top');
} else if (tile === 3) {
ctx.fillStyle = '#00ff00'; // Finish line
ctx.fillRect(screenX, screenY, TILE_SIZE, TILE_SIZE);
} else if (tile === 4) {
drawLava(screenX, screenY); // Animated lava
} else if (tile === 5) {
ctx.fillStyle = '#ff0000'; // Spikes (down)
drawSpikes(screenX, screenY, 'down');
} else if (tile === 6) {
ctx.fillStyle = '#ff0000'; // Spikes (left)
drawSpikes(screenX, screenY, 'left');
} else if (tile === 7) {
ctx.fillStyle = '#ff0000'; // Spikes (right)
drawSpikes(screenX, screenY, 'right');
}
ctx.restore();
}
}
}
// Draw player
ctx.fillStyle = '#ff4500';
ctx.fillRect(player.x - cameraX, player.y - cameraY, player.width, player.height);
}
// Helper function to draw spikes
function drawSpikes(x, y, direction) {
ctx.beginPath();
if (direction === 'top') {
ctx.moveTo(x, y + TILE_SIZE);
ctx.lineTo(x + TILE_SIZE / 2, y);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE);
} else if (direction === 'down') {
ctx.moveTo(x, y);
ctx.lineTo(x + TILE_SIZE / 2, y + TILE_SIZE);
ctx.lineTo(x + TILE_SIZE, y);
} else if (direction === 'left') {
ctx.moveTo(x + TILE_SIZE, y);
ctx.lineTo(x, y + TILE_SIZE / 2);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE);
} else if (direction === 'right') {
ctx.moveTo(x, y);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE / 2);
ctx.lineTo(x, y + TILE_SIZE);
}
ctx.closePath();
ctx.fill();
}
// Helper function to draw animated lava
function drawLava(x, y) {
const waveHeight = 5 + Math.sin(lavaAnimationFrame * 0.1) * 3;
ctx.fillStyle = '#ff6600'; // Orange lava
ctx.fillRect(x, y + waveHeight, TILE_SIZE, TILE_SIZE - waveHeight);
ctx.fillStyle = '#ff4500'; // Red lava highlight
ctx.fillRect(x, y + TILE_SIZE - 5, TILE_SIZE, 5);
ctx.beginPath();
ctx.fillStyle = '#ff9900'; // Yellow lava wave
ctx.moveTo(x, y + waveHeight);
for (let i = 0; i <= TILE_SIZE; i++) {
ctx.lineTo(x + i, y + waveHeight + Math.sin((i + lavaAnimationFrame) * 0.3) * 3);
}
ctx.lineTo(x + TILE_SIZE, y + waveHeight);
ctx.fill();
}
// Reset game function
function resetGame() {
player.x = player.spawnX;
player.y = player.spawnY;
player.dx = 0;
player.dy = 0;
player.jumpCount = 0;
player.canDash = true;
player.isDashing = false;
player.dashTimer = 0;
player.dashCooldown = 0;
}
// Start the game loop
gameLoop();
</script>
<style>
/* Apply the 'crosshair' cursor to the entire body of the webpage */
body {
cursor: crosshair;
}
/*
Optional: If you want to change the cursor only for a specific
element, you could use a class or ID like this:
.specific-element {
cursor: crosshair;
}
*/
</style>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tower Tim</title>
<style>
body {
margin: 0;
background-color: #f0f8ff;
overflow: hidden;
font-family: Arial, sans-serif;
text-align: center;
}
canvas {
display: block;
background-color: #000;
}
h1 {
color: white;
font-size: 48px;
text-shadow: 2px 2px 4px #000000;
}
p {
color: white;
font-size: 15px;
text-shadow: 2px 2px 4px #000000;
}
button {
padding: 15px 30px;
font-size: 24px;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #ff4500;
color: white;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
transition: background-color 0.3s;
}
button:hover {
background-color: #e03c00;
}
</style>
</head>
<body>
<div id="homeMenu" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1;">
<h1>Tower Tim</h1>
<button id="startButton">Start Game</button>
<p></p>
<button id="startButton">Level Editor Coming Soon</button>
<p>MADE BY plasma studios</p>
<p>Version-Alfa 1.02</p>
<audio autoplay loop>
<source src="your_audio_file.mp3" type="audio/mpeg">
<source src="your_audio_file.ogg" type="audio/ogg">
Your browser does not support the audio element.
</audio>
</div>
<canvas id="gameCanvas"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const homeMenu = document.getElementById('homeMenu');
const startButton = document.getElementById('startButton');
// Game states
const GAME_STATE = {
MENU: 'menu',
PLAYING: 'playing'
};
let currentState = GAME_STATE.MENU;
// Game constants
const GRAVITY = 0.5;
const JUMP_POWER = -12;
const PLAYER_SPEED = 9;
const TILE_SIZE = 40;
const DASH_SPEED = 25;
const DASH_DURATION = 15; // frames
const DASH_COOLDOWN = 15; // frames
const MAX_JUMPS = 3; // For double jump
// Map constants
const mapWidthInTiles = 500;
const mapHeightInTiles = 100;
// Game map data (50 wide x 100 high)
// 0 = empty space
// 1 = platform
// 2 = spikes (top)
// 3 = finish line
// 4 = lava (animated)
// 5 = spikes (down)
// 6 = spikes (left)
// 7 = spikes (right)
const gameMap = new Array(mapHeightInTiles).fill(null).map(() => new Array(mapWidthInTiles).fill(0));
// Player object
const player = {
x: TILE_SIZE * 2,
y: TILE_SIZE * 90,
width: TILE_SIZE * 0.75,
height: TILE_SIZE * 0.75,
dx: 0,
dy: 0,
onGround: false,
jumpCount: 0,
canDash: true,
isDashing: false,
dashTimer: 0,
dashCooldown: 0,
facingDirection: 1, // 1 for right, -1 for left
onWall: false,
spawnX: TILE_SIZE * 2,
spawnY: TILE_SIZE * 90
};
// --- EDITED MAP FOR A DIFFICULT LEVEL ---
function createMap() {
// Start area
for (let x = 0; x < 5; x++) { gameMap[95][x] = 1; }
for (let y = 96; y < mapHeightInTiles; y++) { gameMap[y][0] = 1; gameMap[y][4] = 1; }
gameMap[90][5] = 1; gameMap[90][6] = 4;
gameMap[90][7] = 4; gameMap[90][8] = 4;
gameMap[90][5] = 1; gameMap[91][6] = 1;
gameMap[91][7] = 1; gameMap[91][8] = 1;
gameMap[91][7] = 1; gameMap[91][9] = 1;
gameMap[91][7] = 1; gameMap[91][10] = 1;
gameMap[91][7] = 1; gameMap[91][5] = 1;
gameMap[90][9] = 1; gameMap[90][10] = 1;
// Long jump with spikes
gameMap[85][15] = 1;
for (let x = 16; x < 20; x++) { gameMap[85][x] = 4; }
gameMap[85][20] = 1;
// Vertical climbing section
gameMap[80][25] = 1; gameMap[80][26] = 1; gameMap[79][26] = 2;
gameMap[75][30] = 1; gameMap[75][31] = 1; gameMap[74][30] = 2;
gameMap[70][25] = 1; gameMap[70][26] = 1; gameMap[69][26] = 2;
gameMap[65][30] = 1; gameMap[65][31] = 1; gameMap[64][30] = 2;
// Wall jump challenge
for (let y = 60; y < 65; y++) { gameMap[y][10] = 1; gameMap[y][15] = 1; }
for (let x = 11; x < 15; x++) { gameMap[65][x] = 2; }
gameMap[60][12] = 1; gameMap[60][13] = 1;
gameMap[55][12] = 1; gameMap[55][13] = 1;
// Dash tunnel with low ceiling
for (let x = 18; x < 30; x++) { gameMap[50][x] = 1; gameMap[47][x] = 1; }
for (let x = 20; x < 28; x++) { gameMap[49][x] = 2; }
for (let x = 21; x < 27; x++) { gameMap[48][x] = 5; }
// Lava pit with tight platforms
for (let x = 0; x < 50; x++) { gameMap[45][x] = 1; }
gameMap[44][5] = 1; gameMap[44][10] = 1; gameMap[44][15] = 1;
gameMap[44][20] = 1; gameMap[44][25] = 1; gameMap[44][30] = 1;
// Final wall climb
for (let y = 35; y < 44; y++) { gameMap[y][40] = 1; }
for (let y = 35; y < 44; y++) { gameMap[y][44] = 1; }
for (let y = 30; y < 50; y++) { gameMap[y][47] = 1; }
for (let y = 30; y < 52; y++) { gameMap[y][49] = 4; }
gameMap[30][40] = 1;
gameMap[29][40] = 1;
gameMap[28][40] = 1;
gameMap[27][40] = 1;
gameMap[26][40] = 1;
gameMap[25][40] = 1;
gameMap[24][40] = 1;
gameMap[23][40] = 1;
gameMap[22][40] = 1;
gameMap[21][40] = 1;
gameMap[20][40] = 1;
gameMap[19][40] = 1;
gameMap[18][40] = 1;
gameMap[17][40] = 1;
gameMap[16][40] = 1;
gameMap[15][42] = 2;
gameMap[16][41] = 1;
gameMap[16][42] = 1;
gameMap[31][40] = 1;
gameMap[32][40] = 1;
gameMap[33][40] = 1;
gameMap[34][40] = 1;
gameMap[35][40] = 1;
gameMap[36][40] = 1;
gameMap[34][39] = 1;
gameMap[34][38] = 1;
gameMap[43][40] = 1;
// The Finish Line
gameMap[35][42] = 3;
gameMap[44][42] = 2;
gameMap[44][43] = 2;
gameMap[44][41] = 2;
gameMap[44][40] = 1;
gameMap[44][39] = 6;
gameMap[43][39] = 6;
gameMap[42][39] = 6;
gameMap[41][39] = 6;
gameMap[32][39] = 6;
gameMap[31][39] = 6;
gameMap[33][39] = 6;
gameMap[90][4] = 6;
for (let x = 0; x < 90; x++) { gameMap[99][x] = 4; }
}
createMap();
// --- END OF MAP EDITING AREA ---
let cameraX = 0;
let cameraY = 0;
const mapWidth = mapWidthInTiles * TILE_SIZE;
const mapHeight = mapHeightInTiles * TILE_SIZE;
let lavaAnimationFrame = 0;
// Key states
const keys = {
right: false,
left: false,
up: false,
dash: false
};
// Event listeners for key presses
window.addEventListener('keydown', (e) => {
if (currentState === GAME_STATE.PLAYING) {
if (e.key === 'ArrowRight') keys.right = true;
if (e.key === 'ArrowLeft') keys.left = true;
if (e.key === 'ArrowUp') {
if (player.onGround || player.jumpCount < MAX_JUMPS -1) {
player.dy = JUMP_POWER;
player.onGround = false;
player.jumpCount++;
} else if (player.onWall) {
// Wall jump
player.dy = JUMP_POWER;
player.dx = -player.facingDirection * PLAYER_SPEED * 1.5; // Push away from the wall
player.jumpCount = 1; // Reset jump count for double jump
player.onWall = false;
}
}
if (e.key === 'z' && player.canDash) {
keys.dash = true;
}
}
});
window.addEventListener('keyup', (e) => {
if (currentState === GAME_STATE.PLAYING) {
if (e.key === 'ArrowRight') keys.right = false;
if (e.key === 'ArrowLeft') keys.left = false;
if (e.key === 'z') keys.dash = false;
}
});
// Start button handler
startButton.addEventListener('click', () => {
currentState = GAME_STATE.PLAYING;
homeMenu.style.display = 'none';
});
// Main game loop
function gameLoop() {
if (currentState === GAME_STATE.PLAYING) {
update();
draw();
} else {
drawMenu();
}
requestAnimationFrame(gameLoop);
}
// Draw menu
function drawMenu() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
// Update game state
function update() {
// Player horizontal movement
if (!player.isDashing) {
player.dx = 0;
if (keys.right) {
player.dx = PLAYER_SPEED;
player.facingDirection = 1;
}
if (keys.left) {
player.dx = -PLAYER_SPEED;
player.facingDirection = -1;
}
}
// Dash logic
if (keys.dash && player.canDash) {
player.isDashing = true;
player.canDash = false;
player.dashTimer = DASH_DURATION;
player.dx = DASH_SPEED * player.facingDirection;
}
if (player.isDashing) {
player.dashTimer--;
if (player.dashTimer <= 0) {
player.isDashing = false;
player.dx = 0;
}
}
if (!player.canDash) {
player.dashCooldown++;
if (player.dashCooldown >= DASH_COOLDOWN) {
player.canDash = true;
player.dashCooldown = 0;
}
}
// Apply gravity if not dashing
if (!player.isDashing) {
player.dy += GRAVITY;
}
// Update player position
player.x += player.dx;
player.y += player.dy;
// Increment lava animation frame
lavaAnimationFrame = (lavaAnimationFrame + 1) % 60; // 60 frames per second
// Handle collision with map tiles
player.onGround = false;
player.onWall = false;
const tileX = Math.floor(player.x / TILE_SIZE);
const tileY = Math.floor(player.y / TILE_SIZE);
for (let y = Math.max(0, tileY - 2); y < Math.min(gameMap.length, tileY + 3); y++) {
for (let x = Math.max(0, tileX - 2); x < Math.min(gameMap[y].length, tileX + 3); x++) {
if (y >= 0 && y < mapHeightInTiles && x >= 0 && x < mapWidthInTiles) {
const tile = gameMap[y][x];
if (tile !== 0) {
const tileRect = {
x: x * TILE_SIZE,
y: y * TILE_SIZE,
width: TILE_SIZE,
height: TILE_SIZE
};
// Check for collision with deadly tiles first
if (tile === 2 || tile === 4 || tile === 5 || tile === 6 || tile === 7) {
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
resetGame();
}
}
// Check for platform or finish line collision
if (tile === 1 || tile === 3) {
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y + player.height > tileRect.y &&
player.y + player.height <= tileRect.y + tileRect.height &&
player.dy >= 0
) {
player.y = tileRect.y - player.height;
player.dy = 0;
player.onGround = true;
player.jumpCount = 0; // Reset jumps on landing
}
// Wall collision
if (
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
// Left wall
if (player.x + player.width > tileRect.x && player.x < tileRect.x && player.dx >= 0) {
player.x = tileRect.x - player.width;
if (player.onGround === false) player.onWall = true;
}
// Right wall
if (player.x < tileRect.x + tileRect.width && player.x + player.width > tileRect.x + tileRect.width && player.dx <= 0) {
player.x = tileRect.x + tileRect.width;
if (player.onGround === false) player.onWall = true;
}
}
}
if (tile === 3) { // Finish line
if (
player.x < tileRect.x + tileRect.width &&
player.x + player.width > tileRect.x &&
player.y < tileRect.y + tileRect.height &&
player.y + player.height > tileRect.y
) {
alert("You Win!");
resetGame();
}
}
}
}
}
}
// Keep player within map bounds
if (player.x < 0) player.x = 0;
if (player.x + player.width > mapWidth) player.x = mapWidth - player.width;
// Handle falling off the map
if (player.y > mapHeight) {
resetGame();
}
// Update camera position to follow the player
cameraX = player.x - canvas.width / 2;
cameraY = player.y - canvas.height / 2;
// Clamp camera to map bounds
if (cameraX < 0) cameraX = 0;
if (cameraX + canvas.width > mapWidth) cameraX = mapWidth - canvas.width;
if (cameraY < 0) cameraY = 0;
if (cameraY + canvas.height > mapHeight) cameraY = mapHeight - canvas.height;
}
// Draw game objects
function draw() {
// Adjust canvas size based on window size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw game map with camera offset
for (let y = 0; y < mapHeightInTiles; y++) {
for (let x = 0; x < mapWidthInTiles; x++) {
const tile = gameMap[y][x];
const screenX = x * TILE_SIZE - cameraX;
const screenY = y * TILE_SIZE - cameraY;
// Only draw tiles visible on screen
if (
screenX + TILE_SIZE > 0 && screenX < canvas.width &&
screenY + TILE_SIZE > 0 && screenY < canvas.height
) {
ctx.save();
if (tile === 1) {
ctx.fillStyle = '#804000'; // Platform
ctx.fillRect(screenX, screenY, TILE_SIZE, TILE_SIZE);
} else if (tile === 2) {
ctx.fillStyle = '#ff0000'; // Spikes (top)
drawSpikes(screenX, screenY, 'top');
} else if (tile === 3) {
ctx.fillStyle = '#00ff00'; // Finish line
ctx.fillRect(screenX, screenY, TILE_SIZE, TILE_SIZE);
} else if (tile === 4) {
drawLava(screenX, screenY); // Animated lava
} else if (tile === 5) {
ctx.fillStyle = '#ff0000'; // Spikes (down)
drawSpikes(screenX, screenY, 'down');
} else if (tile === 6) {
ctx.fillStyle = '#ff0000'; // Spikes (left)
drawSpikes(screenX, screenY, 'left');
} else if (tile === 7) {
ctx.fillStyle = '#ff0000'; // Spikes (right)
drawSpikes(screenX, screenY, 'right');
}
ctx.restore();
}
}
}
// Draw player
ctx.fillStyle = '#ff4500';
ctx.fillRect(player.x - cameraX, player.y - cameraY, player.width, player.height);
}
// Helper function to draw spikes
function drawSpikes(x, y, direction) {
ctx.beginPath();
if (direction === 'top') {
ctx.moveTo(x, y + TILE_SIZE);
ctx.lineTo(x + TILE_SIZE / 2, y);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE);
} else if (direction === 'down') {
ctx.moveTo(x, y);
ctx.lineTo(x + TILE_SIZE / 2, y + TILE_SIZE);
ctx.lineTo(x + TILE_SIZE, y);
} else if (direction === 'left') {
ctx.moveTo(x + TILE_SIZE, y);
ctx.lineTo(x, y + TILE_SIZE / 2);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE);
} else if (direction === 'right') {
ctx.moveTo(x, y);
ctx.lineTo(x + TILE_SIZE, y + TILE_SIZE / 2);
ctx.lineTo(x, y + TILE_SIZE);
}
ctx.closePath();
ctx.fill();
}
// Helper function to draw animated lava
function drawLava(x, y) {
const waveHeight = 5 + Math.sin(lavaAnimationFrame * 0.1) * 3;
ctx.fillStyle = '#ff6600'; // Orange lava
ctx.fillRect(x, y + waveHeight, TILE_SIZE, TILE_SIZE - waveHeight);
ctx.fillStyle = '#ff4500'; // Red lava highlight
ctx.fillRect(x, y + TILE_SIZE - 5, TILE_SIZE, 5);
ctx.beginPath();
ctx.fillStyle = '#ff9900'; // Yellow lava wave
ctx.moveTo(x, y + waveHeight);
for (let i = 0; i <= TILE_SIZE; i++) {
ctx.lineTo(x + i, y + waveHeight + Math.sin((i + lavaAnimationFrame) * 0.3) * 3);
}
ctx.lineTo(x + TILE_SIZE, y + waveHeight);
ctx.fill();
}
// Reset game function
function resetGame() {
player.x = player.spawnX;
player.y = player.spawnY;
player.dx = 0;
player.dy = 0;
player.jumpCount = 0;
player.canDash = true;
player.isDashing = false;
player.dashTimer = 0;
player.dashCooldown = 0;
}
// Start the game loop
gameLoop();
</script>
<style>
/* Apply the 'crosshair' cursor to the entire body of the webpage */
body {
cursor: crosshair;
}
/*
Optional: If you want to change the cursor only for a specific
element, you could use a class or ID like this:
.specific-element {
cursor: crosshair;
}
*/
</style>
</body>
</html>