deepsite-arkanoid / index.html
Xie's picture
Add 3 files
c917b9c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Castlevania Arkanoid</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&family=MedievalSharp&display=swap');
body {
font-family: 'Cinzel Decorative', cursive;
background-color: #000;
overflow: hidden;
touch-action: none;
user-select: none;
}
#gameCanvas {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400"><rect width="400" height="400" fill="%23000"/><path d="M0,0 L400,400 M400,0 L0,400" stroke="%231a0a0a" stroke-width="1"/></svg>');
box-shadow: 0 0 30px rgba(186, 0, 0, 0.5);
border: 8px solid #3a1a1a;
border-image: linear-gradient(45deg, #3a1a1a, #5a2a2a, #3a1a1a) 1;
}
.gothic-text {
font-family: 'MedievalSharp', cursive;
text-shadow: 0 0 10px rgba(255, 0, 0, 0.7);
}
.blood-red {
background: linear-gradient(135deg, #5a0000, #3a0000);
}
.vampire-button {
background: linear-gradient(135deg, #5a0000, #3a0000);
border: 2px solid #8a0000;
box-shadow: 0 0 15px rgba(186, 0, 0, 0.7);
transition: all 0.3s;
}
.vampire-button:hover {
background: linear-gradient(135deg, #7a0000, #5a0000);
box-shadow: 0 0 25px rgba(255, 0, 0, 0.9);
transform: translateY(-2px);
}
.candle-flicker {
animation: flicker 3s infinite alternate;
}
@keyframes flicker {
0%, 100% { opacity: 0.8; }
25% { opacity: 1; }
50% { opacity: 0.7; }
75% { opacity: 0.9; }
}
.gothic-border {
border: 4px solid transparent;
border-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><path d="M0,0 L12,0 L12,12 L0,12 Z" fill="none" stroke="%238a0000" stroke-width="2" stroke-dasharray="4,2"/></svg>') 1;
}
.skull-icon {
filter: drop-shadow(0 0 5px rgba(255, 0, 0, 0.7));
}
</style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen bg-black text-red-600">
<div class="absolute top-0 left-0 w-full h-full opacity-20 pointer-events-none" style="background: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\" viewBox=\"0 0 100 100\"><path d=\"M20,20 L80,20 L80,80 L20,80 Z M30,30 L70,30 L70,70 L30,70 Z\" fill=\"none\" stroke=\"%238a0000\" stroke-width=\"1\"/></svg>');"></div>
<h1 class="text-5xl md:text-6xl font-bold mb-4 gothic-text candle-flicker">
<i class="fas fa-skull skull-icon mr-2"></i> CASTLEVANIA ARKANOID
</h1>
<div class="relative mb-8">
<canvas id="gameCanvas" width="800" height="600" class="rounded-lg"></canvas>
<div id="startScreen" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-80 rounded-lg">
<div class="text-center p-8 gothic-border bg-black bg-opacity-90 max-w-md">
<h2 class="text-3xl font-bold mb-6 gothic-text candle-flicker">THE NIGHT WALKER'S CHALLENGE</h2>
<p class="mb-6 text-gray-300">Break the cursed bricks before the night creatures overwhelm you!</p>
<button id="startButton" class="px-8 py-3 rounded-lg text-xl font-bold gothic-text vampire-button">
<i class="fas fa-play mr-2"></i> BEGIN THE HUNT
</button>
</div>
</div>
<div id="gameOverScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80 rounded-lg">
<div class="text-center p-8 gothic-border bg-black bg-opacity-90 max-w-md">
<h2 class="text-4xl font-bold mb-6 gothic-text text-red-500">YOU HAVE DIED</h2>
<p id="finalScore" class="text-2xl mb-6">Score: 0</p>
<button id="restartButton" class="px-8 py-3 rounded-lg text-xl font-bold gothic-text vampire-button">
<i class="fas fa-redo mr-2"></i> TRY AGAIN
</button>
</div>
</div>
</div>
<div class="flex justify-between w-full max-w-2xl px-4 mb-8">
<div class="bg-black bg-opacity-70 px-6 py-3 rounded-lg gothic-border">
<h3 class="text-xl gothic-text mb-1">SCORE</h3>
<p id="scoreDisplay" class="text-3xl font-bold">0</p>
</div>
<div class="bg-black bg-opacity-70 px-6 py-3 rounded-lg gothic-border">
<h3 class="text-xl gothic-text mb-1">LIVES</h3>
<p id="livesDisplay" class="text-3xl font-bold">3</p>
</div>
<div class="bg-black bg-opacity-70 px-6 py-3 rounded-lg gothic-border">
<h3 class="text-xl gothic-text mb-1">LEVEL</h3>
<p id="levelDisplay" class="text-3xl font-bold">1</p>
</div>
</div>
<div class="absolute bottom-4 right-4 text-xs text-gray-600">
<p>Beware the creatures of the night...</p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const startButton = document.getElementById('startButton');
const restartButton = document.getElementById('restartButton');
const scoreDisplay = document.getElementById('scoreDisplay');
const livesDisplay = document.getElementById('livesDisplay');
const levelDisplay = document.getElementById('levelDisplay');
const finalScore = document.getElementById('finalScore');
// Game variables
let gameRunning = false;
let score = 0;
let lives = 3;
let level = 1;
let bricks = [];
let brickRowCount = 5;
let brickColumnCount = 10;
let brickWidth = 75;
let brickHeight = 20;
let brickPadding = 10;
let brickOffsetTop = 60;
let brickOffsetLeft = 30;
// Ball variables
let ballRadius = 10;
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 4;
let dy = -4;
// Paddle variables
let paddleHeight = 15;
let paddleWidth = 100;
let paddleX = (canvas.width - paddleWidth) / 2;
let rightPressed = false;
let leftPressed = false;
// Special effects
let particles = [];
let lastTime = 0;
// Initialize bricks
function initBricks() {
bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (let r = 0; r < brickRowCount; r++) {
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
const brickHealth = Math.floor(Math.random() * 3) + 1; // 1-3 hits to break
// Different colors based on health
let brickColor;
if (brickHealth === 1) brickColor = '#5a0000'; // Dark red
else if (brickHealth === 2) brickColor = '#8a0000'; // Medium red
else brickColor = '#ba0000'; // Bright red
bricks[c][r] = { x: brickX, y: brickY, health: brickHealth, color: brickColor, visible: true };
}
}
}
// Draw bricks
function drawBricks() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
if (bricks[c][r].visible) {
const brick = bricks[c][r];
// Draw brick with gothic style
ctx.beginPath();
ctx.rect(brick.x, brick.y, brickWidth, brickHeight);
ctx.fillStyle = brick.color;
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = '#3a0000';
ctx.stroke();
// Add gothic cross pattern
ctx.beginPath();
ctx.moveTo(brick.x + 5, brick.y + 5);
ctx.lineTo(brick.x + brickWidth - 5, brick.y + brickHeight - 5);
ctx.moveTo(brick.x + brickWidth - 5, brick.y + 5);
ctx.lineTo(brick.x + 5, brick.y + brickHeight - 5);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.stroke();
// Add health indicator (skull icons)
if (brick.health > 1) {
const skulls = brick.health;
const spacing = brickWidth / (skulls + 1);
for (let i = 1; i <= skulls; i++) {
const skullX = brick.x + (spacing * i) - 4;
const skullY = brick.y + brickHeight / 2 - 4;
ctx.beginPath();
ctx.arc(skullX + 4, skullY + 4, 3, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fill();
ctx.beginPath();
ctx.arc(skullX + 4, skullY + 4, 5, 0, Math.PI, false);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.stroke();
}
}
}
}
}
}
// Draw ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
// Create a glowing red ball effect
const gradient = ctx.createRadialGradient(
x, y, ballRadius / 2,
x, y, ballRadius
);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(1, '#8a0000');
ctx.fillStyle = gradient;
ctx.fill();
// Add inner glow
ctx.beginPath();
ctx.arc(x, y, ballRadius / 2, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 150, 150, 0.5)';
ctx.fill();
// Add outer glow
ctx.beginPath();
ctx.arc(x, y, ballRadius + 3, 0, Math.PI * 2);
const glowGradient = ctx.createRadialGradient(
x, y, ballRadius,
x, y, ballRadius + 3
);
glowGradient.addColorStop(0, 'rgba(255, 0, 0, 0.7)');
glowGradient.addColorStop(1, 'rgba(255, 0, 0, 0)');
ctx.fillStyle = glowGradient;
ctx.fill();
}
// Draw paddle
function drawPaddle() {
// Main paddle
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
// Gradient for paddle
const gradient = ctx.createLinearGradient(
paddleX, canvas.height - paddleHeight,
paddleX, canvas.height
);
gradient.addColorStop(0, '#3a1a1a');
gradient.addColorStop(1, '#5a2a2a');
ctx.fillStyle = gradient;
ctx.fill();
ctx.strokeStyle = '#8a0000';
ctx.lineWidth = 2;
ctx.stroke();
// Add gothic details
const segmentWidth = paddleWidth / 5;
for (let i = 1; i < 5; i++) {
ctx.beginPath();
ctx.moveTo(paddleX + (segmentWidth * i), canvas.height - paddleHeight);
ctx.lineTo(paddleX + (segmentWidth * i), canvas.height);
ctx.strokeStyle = 'rgba(186, 0, 0, 0.5)';
ctx.stroke();
}
// Add spikes at the ends
ctx.beginPath();
ctx.moveTo(paddleX, canvas.height - paddleHeight);
ctx.lineTo(paddleX - 5, canvas.height - paddleHeight - 10);
ctx.lineTo(paddleX + 5, canvas.height - paddleHeight - 10);
ctx.closePath();
ctx.fillStyle = '#8a0000';
ctx.fill();
ctx.beginPath();
ctx.moveTo(paddleX + paddleWidth, canvas.height - paddleHeight);
ctx.lineTo(paddleX + paddleWidth + 5, canvas.height - paddleHeight - 10);
ctx.lineTo(paddleX + paddleWidth - 5, canvas.height - paddleHeight - 10);
ctx.closePath();
ctx.fillStyle = '#8a0000';
ctx.fill();
}
// Draw particles
function drawParticles() {
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
const alpha = p.lifetime / 100;
ctx.fillStyle = `rgba(255, ${Math.floor(100 + Math.random() * 155)}, 0, ${alpha})`;
ctx.fill();
p.x += p.vx;
p.y += p.vy;
p.lifetime--;
if (p.lifetime <= 0) {
particles.splice(i, 1);
i--;
}
}
}
// Create particles
function createParticles(x, y, count) {
for (let i = 0; i < count; i++) {
particles.push({
x: x,
y: y,
radius: Math.random() * 3 + 1,
vx: (Math.random() - 0.5) * 5,
vy: (Math.random() - 0.5) * 5,
lifetime: Math.floor(Math.random() * 30) + 20
});
}
}
// Collision detection
function collisionDetection() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
const brick = bricks[c][r];
if (brick.visible) {
if (
x > brick.x &&
x < brick.x + brickWidth &&
y > brick.y &&
y < brick.y + brickHeight
) {
dy = -dy;
brick.health--;
// Create particles on hit
createParticles(
brick.x + brickWidth / 2,
brick.y + brickHeight / 2,
10
);
if (brick.health <= 0) {
brick.visible = false;
score += 10 * level;
scoreDisplay.textContent = score;
// Check if all bricks are cleared
if (checkLevelComplete()) {
levelUp();
}
}
}
}
}
}
}
// Check if level is complete
function checkLevelComplete() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
if (bricks[c][r].visible) {
return false;
}
}
}
return true;
}
// Level up
function levelUp() {
level++;
levelDisplay.textContent = level;
// Increase difficulty
brickRowCount = Math.min(8, brickRowCount + 1);
dx *= 1.1;
dy *= 1.1;
// Reset ball position
x = canvas.width / 2;
y = canvas.height - 30;
// Create new bricks
initBricks();
// Show level up message
const levelUpDiv = document.createElement('div');
levelUpDiv.className = 'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-4xl font-bold gothic-text text-red-500 bg-black bg-opacity-80 px-8 py-4 rounded-lg';
levelUpDiv.textContent = `LEVEL ${level}`;
document.body.appendChild(levelUpDiv);
setTimeout(() => {
levelUpDiv.style.opacity = '0';
setTimeout(() => {
document.body.removeChild(levelUpDiv);
}, 500);
}, 1500);
}
// Game over
function gameOver() {
gameRunning = false;
finalScore.textContent = `Score: ${score}`;
gameOverScreen.classList.remove('hidden');
gameOverScreen.classList.add('flex');
}
// Reset game
function resetGame() {
score = 0;
lives = 3;
level = 1;
scoreDisplay.textContent = score;
livesDisplay.textContent = lives;
levelDisplay.textContent = level;
x = canvas.width / 2;
y = canvas.height - 30;
dx = 4;
dy = -4;
paddleX = (canvas.width - paddleWidth) / 2;
brickRowCount = 5;
initBricks();
gameOverScreen.classList.add('hidden');
gameOverScreen.classList.remove('flex');
}
// Main draw function
function draw() {
if (!gameRunning) return;
// Clear canvas with dark translucent overlay for motion blur effect
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw game elements
drawBricks();
drawBall();
drawPaddle();
drawParticles();
// Collision detection
collisionDetection();
// Wall collision
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
createParticles(x, y, 5);
}
if (y + dy < ballRadius) {
dy = -dy;
createParticles(x, y, 5);
} else if (y + dy > canvas.height - ballRadius) {
// Paddle collision
if (x > paddleX && x < paddleX + paddleWidth) {
// Calculate angle based on where ball hits paddle
const hitPosition = (x - paddleX) / paddleWidth;
const angle = (hitPosition - 0.5) * Math.PI / 3; // -30 to 30 degrees
// Calculate new direction
const speed = Math.sqrt(dx * dx + dy * dy) * 1.05; // Slightly increase speed
dy = -Math.abs(Math.cos(angle) * speed);
dx = Math.sin(angle) * speed;
createParticles(x, y, 10);
} else {
// Ball missed paddle
lives--;
livesDisplay.textContent = lives;
if (lives <= 0) {
gameOver();
} else {
// Reset ball position
x = canvas.width / 2;
y = canvas.height - 30;
dx = 4;
dy = -4;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
// Paddle movement
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
// Move ball
x += dx;
y += dy;
requestAnimationFrame(draw);
}
// Event listeners
document.addEventListener('keydown', keyDownHandler);
document.addEventListener('keyup', keyUpHandler);
canvas.addEventListener('mousemove', mouseMoveHandler);
canvas.addEventListener('touchmove', touchMoveHandler, { passive: false });
function keyDownHandler(e) {
if (e.key === 'Right' || e.key === 'ArrowRight') {
rightPressed = true;
} else if (e.key === 'Left' || e.key === 'ArrowLeft') {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key === 'Right' || e.key === 'ArrowRight') {
rightPressed = false;
} else if (e.key === 'Left' || e.key === 'ArrowLeft') {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
const relativeX = e.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
function touchMoveHandler(e) {
e.preventDefault();
const touch = e.touches[0];
const relativeX = touch.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
// Button event listeners
startButton.addEventListener('click', () => {
startScreen.classList.add('hidden');
gameRunning = true;
resetGame();
draw();
});
restartButton.addEventListener('click', () => {
resetGame();
gameRunning = true;
draw();
});
// Initialize game
initBricks();
// Add ambient candle flicker effect
setInterval(() => {
const flickerElements = document.querySelectorAll('.candle-flicker');
flickerElements.forEach(el => {
el.style.opacity = 0.7 + Math.random() * 0.3;
});
}, 100);
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Xie/deepsite-arkanoid" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>