lastly make a crazy 8-bit like minecraft 3d graphices that is a house and frot and back yard and you have a chain saw and you have to find all the kids in the house and saw them... then you can hide and wait for the rescue and po po to show up and you keep sawing them till uyou die lol like youre jason but a chain saw - Initial Deployment
Browse files- README.md +6 -4
- index.html +697 -19
README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
emoji:
|
4 |
colorFrom: blue
|
5 |
-
colorTo:
|
6 |
sdk: static
|
7 |
pinned: false
|
|
|
|
|
8 |
---
|
9 |
|
10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: chainsaw-massacre-2d
|
3 |
+
emoji: 🐳
|
4 |
colorFrom: blue
|
5 |
+
colorTo: green
|
6 |
sdk: static
|
7 |
pinned: false
|
8 |
+
tags:
|
9 |
+
- deepsite
|
10 |
---
|
11 |
|
12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
@@ -1,19 +1,697 @@
|
|
1 |
-
<!
|
2 |
-
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Chainsaw Massacre: 8-Bit Horror</title>
|
7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
+
<style>
|
9 |
+
body {
|
10 |
+
margin: 0;
|
11 |
+
overflow: hidden;
|
12 |
+
background-color: #111;
|
13 |
+
font-family: 'Press Start 2P', cursive;
|
14 |
+
}
|
15 |
+
canvas {
|
16 |
+
display: block;
|
17 |
+
}
|
18 |
+
#ui {
|
19 |
+
position: absolute;
|
20 |
+
top: 0;
|
21 |
+
left: 0;
|
22 |
+
width: 100%;
|
23 |
+
color: white;
|
24 |
+
text-shadow: 2px 2px 0 #000;
|
25 |
+
pointer-events: none;
|
26 |
+
}
|
27 |
+
#health-bar {
|
28 |
+
width: 200px;
|
29 |
+
height: 20px;
|
30 |
+
border: 3px solid white;
|
31 |
+
margin: 10px;
|
32 |
+
}
|
33 |
+
#health-fill {
|
34 |
+
height: 100%;
|
35 |
+
width: 100%;
|
36 |
+
background-color: red;
|
37 |
+
transition: width 0.3s;
|
38 |
+
}
|
39 |
+
#game-over {
|
40 |
+
display: none;
|
41 |
+
position: absolute;
|
42 |
+
top: 50%;
|
43 |
+
left: 50%;
|
44 |
+
transform: translate(-50%, -50%);
|
45 |
+
background-color: rgba(0, 0, 0, 0.8);
|
46 |
+
padding: 20px;
|
47 |
+
border: 5px solid red;
|
48 |
+
text-align: center;
|
49 |
+
}
|
50 |
+
#start-screen {
|
51 |
+
position: absolute;
|
52 |
+
top: 0;
|
53 |
+
left: 0;
|
54 |
+
width: 100%;
|
55 |
+
height: 100%;
|
56 |
+
background-color: #000;
|
57 |
+
display: flex;
|
58 |
+
flex-direction: column;
|
59 |
+
justify-content: center;
|
60 |
+
align-items: center;
|
61 |
+
color: white;
|
62 |
+
z-index: 100;
|
63 |
+
}
|
64 |
+
@font-face {
|
65 |
+
font-family: 'Press Start 2P';
|
66 |
+
src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
|
67 |
+
}
|
68 |
+
.pixel-text {
|
69 |
+
font-family: 'Press Start 2P', cursive;
|
70 |
+
}
|
71 |
+
.blood-particle {
|
72 |
+
position: absolute;
|
73 |
+
width: 5px;
|
74 |
+
height: 5px;
|
75 |
+
background-color: red;
|
76 |
+
border-radius: 50%;
|
77 |
+
pointer-events: none;
|
78 |
+
}
|
79 |
+
</style>
|
80 |
+
</head>
|
81 |
+
<body>
|
82 |
+
<div id="start-screen" class="pixel-text">
|
83 |
+
<h1 class="text-4xl mb-8 text-red-600">CHAINSAW MASSACRE</h1>
|
84 |
+
<p class="mb-4 text-yellow-400">8-BIT HORROR</p>
|
85 |
+
<p class="mb-8 text-green-400">Find and eliminate all targets</p>
|
86 |
+
<button id="start-btn" class="bg-red-600 hover:bg-red-700 text-white px-8 py-4 rounded-lg text-xl transition-all hover:scale-110">
|
87 |
+
START GAME
|
88 |
+
</button>
|
89 |
+
<div class="mt-12 text-xs text-gray-400">
|
90 |
+
<p>WASD to move | SPACE to attack | SHIFT to run</p>
|
91 |
+
<p>Left click to chainsaw | Right click to hide</p>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
|
95 |
+
<div id="ui" class="pixel-text">
|
96 |
+
<div class="flex justify-between items-center p-4">
|
97 |
+
<div>
|
98 |
+
<div id="health-bar">
|
99 |
+
<div id="health-fill"></div>
|
100 |
+
</div>
|
101 |
+
<div id="score" class="mt-2">KILLS: 0</div>
|
102 |
+
</div>
|
103 |
+
<div id="phase" class="text-xl">PHASE 1: HUNT KIDS</div>
|
104 |
+
<div id="timer" class="text-xl">TIME: 00:00</div>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
+
|
108 |
+
<div id="game-over" class="pixel-text">
|
109 |
+
<h1 class="text-4xl text-red-600 mb-4">GAME OVER</h1>
|
110 |
+
<p id="final-score" class="text-2xl mb-8">You killed 0 victims</p>
|
111 |
+
<button id="restart-btn" class="bg-red-600 hover:bg-red-700 text-white px-8 py-4 rounded-lg text-xl">
|
112 |
+
PLAY AGAIN
|
113 |
+
</button>
|
114 |
+
</div>
|
115 |
+
|
116 |
+
<canvas id="gameCanvas"></canvas>
|
117 |
+
|
118 |
+
<script>
|
119 |
+
// Game setup
|
120 |
+
const canvas = document.getElementById('gameCanvas');
|
121 |
+
const ctx = canvas.getContext('2d');
|
122 |
+
const startScreen = document.getElementById('start-screen');
|
123 |
+
const startBtn = document.getElementById('start-btn');
|
124 |
+
const gameOverScreen = document.getElementById('game-over');
|
125 |
+
const restartBtn = document.getElementById('restart-btn');
|
126 |
+
const healthFill = document.getElementById('health-fill');
|
127 |
+
const scoreDisplay = document.getElementById('score');
|
128 |
+
const phaseDisplay = document.getElementById('phase');
|
129 |
+
const timerDisplay = document.getElementById('timer');
|
130 |
+
const finalScoreDisplay = document.getElementById('final-score');
|
131 |
+
|
132 |
+
// Set canvas size
|
133 |
+
canvas.width = window.innerWidth;
|
134 |
+
canvas.height = window.innerHeight;
|
135 |
+
|
136 |
+
// Game state
|
137 |
+
let gameRunning = false;
|
138 |
+
let score = 0;
|
139 |
+
let health = 100;
|
140 |
+
let gameTime = 0;
|
141 |
+
let gamePhase = 1; // 1 = hunt kids, 2 = hide, 3 = fight police
|
142 |
+
let timerInterval;
|
143 |
+
|
144 |
+
// Player
|
145 |
+
const player = {
|
146 |
+
x: canvas.width / 2,
|
147 |
+
y: canvas.height / 2,
|
148 |
+
size: 30,
|
149 |
+
speed: 3,
|
150 |
+
isAttacking: false,
|
151 |
+
isHiding: false,
|
152 |
+
direction: 0, // angle in radians
|
153 |
+
chainsawSound: new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...'), // placeholder
|
154 |
+
};
|
155 |
+
|
156 |
+
// Kids (victims)
|
157 |
+
let kids = [];
|
158 |
+
const KID_COUNT = 8;
|
159 |
+
|
160 |
+
// Police
|
161 |
+
let police = [];
|
162 |
+
const POLICE_COUNT = 5;
|
163 |
+
|
164 |
+
// House structure (simplified for 8-bit)
|
165 |
+
const house = {
|
166 |
+
walls: [
|
167 |
+
{x: 200, y: 200, width: 400, height: 300, color: '#8B4513'}, // main house
|
168 |
+
{x: 300, y: 150, width: 200, height: 50, color: '#A52A2A'}, // roof
|
169 |
+
{x: 600, y: 300, width: 100, height: 200, color: '#8B4513'}, // garage
|
170 |
+
{x: 200, y: 500, width: 200, height: 50, color: '#228B22'}, // front yard fence
|
171 |
+
{x: 400, y: 500, width: 300, height: 50, color: '#228B22'}, // front yard fence
|
172 |
+
],
|
173 |
+
doors: [
|
174 |
+
{x: 350, y: 500, width: 50, height: 30, color: '#654321'}
|
175 |
+
],
|
176 |
+
windows: [
|
177 |
+
{x: 250, y: 250, width: 50, height: 50, color: '#87CEEB'},
|
178 |
+
{x: 450, y: 250, width: 50, height: 50, color: '#87CEEB'},
|
179 |
+
{x: 620, y: 350, width: 50, height: 50, color: '#87CEEB'}
|
180 |
+
]
|
181 |
+
};
|
182 |
+
|
183 |
+
// Trees in yard
|
184 |
+
const trees = [
|
185 |
+
{x: 100, y: 400, trunkWidth: 20, trunkHeight: 60, leavesWidth: 80, leavesHeight: 100},
|
186 |
+
{x: 700, y: 400, trunkWidth: 20, trunkHeight: 60, leavesWidth: 80, leavesHeight: 100},
|
187 |
+
{x: 150, y: 600, trunkWidth: 20, trunkHeight: 60, leavesWidth: 80, leavesHeight: 100},
|
188 |
+
{x: 650, y: 600, trunkWidth: 20, trunkHeight: 60, leavesWidth: 80, leavesHeight: 100}
|
189 |
+
];
|
190 |
+
|
191 |
+
// Initialize game
|
192 |
+
function initGame() {
|
193 |
+
// Reset game state
|
194 |
+
gameRunning = true;
|
195 |
+
score = 0;
|
196 |
+
health = 100;
|
197 |
+
gameTime = 0;
|
198 |
+
gamePhase = 1;
|
199 |
+
kids = [];
|
200 |
+
police = [];
|
201 |
+
|
202 |
+
// Create kids
|
203 |
+
for (let i = 0; i < KID_COUNT; i++) {
|
204 |
+
kids.push({
|
205 |
+
x: Math.random() * (canvas.width - 100) + 50,
|
206 |
+
y: Math.random() * (canvas.height - 100) + 50,
|
207 |
+
size: 20,
|
208 |
+
speed: 1 + Math.random() * 1,
|
209 |
+
direction: Math.random() * Math.PI * 2,
|
210 |
+
changeDirectionTimer: 0,
|
211 |
+
isAlive: true,
|
212 |
+
screamSound: new Audio('data:audio/wav;base64,UklGRl9vT19XQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YU...') // placeholder
|
213 |
+
});
|
214 |
+
}
|
215 |
+
|
216 |
+
// Start timer
|
217 |
+
clearInterval(timerInterval);
|
218 |
+
timerInterval = setInterval(updateTimer, 1000);
|
219 |
+
|
220 |
+
// Hide start screen
|
221 |
+
startScreen.style.display = 'none';
|
222 |
+
gameOverScreen.style.display = 'none';
|
223 |
+
|
224 |
+
// Start game loop
|
225 |
+
requestAnimationFrame(gameLoop);
|
226 |
+
}
|
227 |
+
|
228 |
+
// Game loop
|
229 |
+
function gameLoop() {
|
230 |
+
if (!gameRunning) return;
|
231 |
+
|
232 |
+
// Clear canvas
|
233 |
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
234 |
+
|
235 |
+
// Update game state
|
236 |
+
updatePlayer();
|
237 |
+
updateKids();
|
238 |
+
if (gamePhase >= 3) updatePolice();
|
239 |
+
|
240 |
+
// Draw game world
|
241 |
+
drawWorld();
|
242 |
+
|
243 |
+
// Draw player
|
244 |
+
drawPlayer();
|
245 |
+
|
246 |
+
// Draw kids
|
247 |
+
drawKids();
|
248 |
+
|
249 |
+
// Draw police if phase 3
|
250 |
+
if (gamePhase >= 3) drawPolice();
|
251 |
+
|
252 |
+
// Check game phase transitions
|
253 |
+
checkPhaseTransitions();
|
254 |
+
|
255 |
+
// Check game over
|
256 |
+
if (health <= 0) {
|
257 |
+
gameOver();
|
258 |
+
return;
|
259 |
+
}
|
260 |
+
|
261 |
+
// Continue loop
|
262 |
+
requestAnimationFrame(gameLoop);
|
263 |
+
}
|
264 |
+
|
265 |
+
// Update player
|
266 |
+
function updatePlayer() {
|
267 |
+
// Movement
|
268 |
+
const moveX = (keys['d'] ? 1 : 0) - (keys['a'] ? 1 : 0);
|
269 |
+
const moveY = (keys['s'] ? 1 : 0) - (keys['w'] ? 1 : 0);
|
270 |
+
|
271 |
+
if (moveX !== 0 || moveY !== 0) {
|
272 |
+
player.direction = Math.atan2(moveY, moveX);
|
273 |
+
const speed = keys['Shift'] ? player.speed * 1.5 : player.speed;
|
274 |
+
player.x += Math.cos(player.direction) * speed;
|
275 |
+
player.y += Math.sin(player.direction) * speed;
|
276 |
+
|
277 |
+
// Boundary check
|
278 |
+
player.x = Math.max(player.size, Math.min(canvas.width - player.size, player.x));
|
279 |
+
player.y = Math.max(player.size, Math.min(canvas.height - player.size, player.y));
|
280 |
+
}
|
281 |
+
|
282 |
+
// Attacking
|
283 |
+
if (mouse.isAttacking && !player.isAttacking) {
|
284 |
+
player.isAttacking = true;
|
285 |
+
player.chainsawSound.play();
|
286 |
+
|
287 |
+
// Check for hits on kids or police
|
288 |
+
const targets = gamePhase >= 3 ? [...kids, ...police] : kids;
|
289 |
+
for (let target of targets) {
|
290 |
+
if (!target.isAlive) continue;
|
291 |
+
|
292 |
+
const dist = Math.sqrt(
|
293 |
+
Math.pow(target.x - player.x, 2) +
|
294 |
+
Math.pow(target.y - player.y, 2)
|
295 |
+
);
|
296 |
+
|
297 |
+
if (dist < player.size + target.size) {
|
298 |
+
// Hit!
|
299 |
+
target.isAlive = false;
|
300 |
+
score++;
|
301 |
+
scoreDisplay.textContent = `KILLS: ${score}`;
|
302 |
+
|
303 |
+
// Create blood particles
|
304 |
+
createBlood(target.x, target.y);
|
305 |
+
|
306 |
+
// Play scream sound
|
307 |
+
if (target.screamSound) target.screamSound.play();
|
308 |
+
}
|
309 |
+
}
|
310 |
+
|
311 |
+
setTimeout(() => {
|
312 |
+
player.isAttacking = false;
|
313 |
+
}, 500);
|
314 |
+
}
|
315 |
+
|
316 |
+
// Hiding
|
317 |
+
player.isHiding = mouse.isHiding;
|
318 |
+
}
|
319 |
+
|
320 |
+
// Update kids
|
321 |
+
function updateKids() {
|
322 |
+
for (let kid of kids) {
|
323 |
+
if (!kid.isAlive) continue;
|
324 |
+
|
325 |
+
// Random movement
|
326 |
+
kid.changeDirectionTimer--;
|
327 |
+
if (kid.changeDirectionTimer <= 0) {
|
328 |
+
kid.direction = Math.random() * Math.PI * 2;
|
329 |
+
kid.changeDirectionTimer = 30 + Math.random() * 60;
|
330 |
+
}
|
331 |
+
|
332 |
+
// Move
|
333 |
+
kid.x += Math.cos(kid.direction) * kid.speed;
|
334 |
+
kid.y += Math.sin(kid.direction) * kid.speed;
|
335 |
+
|
336 |
+
// Boundary check
|
337 |
+
kid.x = Math.max(kid.size, Math.min(canvas.width - kid.size, kid.x));
|
338 |
+
kid.y = Math.max(kid.size, Math.min(canvas.height - kid.size, kid.y));
|
339 |
+
|
340 |
+
// Run from player if close
|
341 |
+
const distToPlayer = Math.sqrt(
|
342 |
+
Math.pow(kid.x - player.x, 2) +
|
343 |
+
Math.pow(kid.y - player.y, 2)
|
344 |
+
);
|
345 |
+
|
346 |
+
if (distToPlayer < 200) {
|
347 |
+
// Run away
|
348 |
+
const angleAway = Math.atan2(kid.y - player.y, kid.x - player.x);
|
349 |
+
kid.x += Math.cos(angleAway) * kid.speed * 2;
|
350 |
+
kid.y += Math.sin(angleAway) * kid.speed * 2;
|
351 |
+
}
|
352 |
+
}
|
353 |
+
}
|
354 |
+
|
355 |
+
// Update police
|
356 |
+
function updatePolice() {
|
357 |
+
if (police.length === 0) {
|
358 |
+
// Spawn police
|
359 |
+
for (let i = 0; i < POLICE_COUNT; i++) {
|
360 |
+
police.push({
|
361 |
+
x: Math.random() * (canvas.width - 100) + 50,
|
362 |
+
y: Math.random() * (canvas.height - 100) + 50,
|
363 |
+
size: 25,
|
364 |
+
speed: 2 + Math.random() * 1,
|
365 |
+
direction: Math.random() * Math.PI * 2,
|
366 |
+
changeDirectionTimer: 0,
|
367 |
+
isAlive: true,
|
368 |
+
shootTimer: 0
|
369 |
+
});
|
370 |
+
}
|
371 |
+
}
|
372 |
+
|
373 |
+
for (let cop of police) {
|
374 |
+
if (!cop.isAlive) continue;
|
375 |
+
|
376 |
+
// Chase player
|
377 |
+
cop.direction = Math.atan2(player.y - cop.y, player.x - cop.x);
|
378 |
+
cop.x += Math.cos(cop.direction) * cop.speed;
|
379 |
+
cop.y += Math.sin(cop.direction) * cop.speed;
|
380 |
+
|
381 |
+
// Shoot at player periodically
|
382 |
+
cop.shootTimer--;
|
383 |
+
if (cop.shootTimer <= 0) {
|
384 |
+
cop.shootTimer = 60 + Math.random() * 60;
|
385 |
+
|
386 |
+
// Check if player is in line of sight
|
387 |
+
const distToPlayer = Math.sqrt(
|
388 |
+
Math.pow(player.x - cop.x, 2) +
|
389 |
+
Math.pow(player.y - cop.y, 2)
|
390 |
+
);
|
391 |
+
|
392 |
+
if (distToPlayer < 300 && !player.isHiding) {
|
393 |
+
// Player hit
|
394 |
+
health -= 10;
|
395 |
+
healthFill.style.width = `${health}%`;
|
396 |
+
|
397 |
+
// Create blood particles at player
|
398 |
+
createBlood(player.x, player.y);
|
399 |
+
}
|
400 |
+
}
|
401 |
+
}
|
402 |
+
}
|
403 |
+
|
404 |
+
// Draw world
|
405 |
+
function drawWorld() {
|
406 |
+
// Draw grass background
|
407 |
+
ctx.fillStyle = '#228B22';
|
408 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
409 |
+
|
410 |
+
// Draw house
|
411 |
+
for (let wall of house.walls) {
|
412 |
+
ctx.fillStyle = wall.color;
|
413 |
+
ctx.fillRect(wall.x, wall.y, wall.width, wall.height);
|
414 |
+
}
|
415 |
+
|
416 |
+
// Draw doors
|
417 |
+
for (let door of house.doors) {
|
418 |
+
ctx.fillStyle = door.color;
|
419 |
+
ctx.fillRect(door.x, door.y, door.width, door.height);
|
420 |
+
}
|
421 |
+
|
422 |
+
// Draw windows
|
423 |
+
for (let window of house.windows) {
|
424 |
+
ctx.fillStyle = window.color;
|
425 |
+
ctx.fillRect(window.x, window.y, window.width, window.height);
|
426 |
+
}
|
427 |
+
|
428 |
+
// Draw trees
|
429 |
+
for (let tree of trees) {
|
430 |
+
// Trunk
|
431 |
+
ctx.fillStyle = '#8B4513';
|
432 |
+
ctx.fillRect(
|
433 |
+
tree.x - tree.trunkWidth/2,
|
434 |
+
tree.y - tree.trunkHeight/2,
|
435 |
+
tree.trunkWidth,
|
436 |
+
tree.trunkHeight
|
437 |
+
);
|
438 |
+
|
439 |
+
// Leaves
|
440 |
+
ctx.fillStyle = '#006400';
|
441 |
+
ctx.beginPath();
|
442 |
+
ctx.ellipse(
|
443 |
+
tree.x,
|
444 |
+
tree.y - tree.leavesHeight/2,
|
445 |
+
tree.leavesWidth/2,
|
446 |
+
tree.leavesHeight/2,
|
447 |
+
0, 0, Math.PI * 2
|
448 |
+
);
|
449 |
+
ctx.fill();
|
450 |
+
}
|
451 |
+
}
|
452 |
+
|
453 |
+
// Draw player
|
454 |
+
function drawPlayer() {
|
455 |
+
// Body
|
456 |
+
ctx.fillStyle = player.isHiding ? '#555' : '#333';
|
457 |
+
ctx.beginPath();
|
458 |
+
ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2);
|
459 |
+
ctx.fill();
|
460 |
+
|
461 |
+
// Face (simple 8-bit style)
|
462 |
+
ctx.fillStyle = '#FFF';
|
463 |
+
ctx.beginPath();
|
464 |
+
ctx.arc(
|
465 |
+
player.x + Math.cos(player.direction) * player.size/2,
|
466 |
+
player.y + Math.sin(player.direction) * player.size/2,
|
467 |
+
player.size/4, 0, Math.PI * 2
|
468 |
+
);
|
469 |
+
ctx.fill();
|
470 |
+
|
471 |
+
// Chainsaw
|
472 |
+
if (player.isAttacking) {
|
473 |
+
ctx.fillStyle = '#FF0000';
|
474 |
+
ctx.beginPath();
|
475 |
+
ctx.arc(
|
476 |
+
player.x + Math.cos(player.direction) * player.size * 1.5,
|
477 |
+
player.y + Math.sin(player.direction) * player.size * 1.5,
|
478 |
+
player.size/2, 0, Math.PI * 2
|
479 |
+
);
|
480 |
+
ctx.fill();
|
481 |
+
|
482 |
+
// Blood spray
|
483 |
+
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
|
484 |
+
ctx.beginPath();
|
485 |
+
ctx.moveTo(player.x, player.y);
|
486 |
+
ctx.lineTo(
|
487 |
+
player.x + Math.cos(player.direction) * player.size * 3,
|
488 |
+
player.y + Math.sin(player.direction) * player.size * 3
|
489 |
+
);
|
490 |
+
ctx.lineWidth = 10;
|
491 |
+
ctx.stroke();
|
492 |
+
}
|
493 |
+
}
|
494 |
+
|
495 |
+
// Draw kids
|
496 |
+
function drawKids() {
|
497 |
+
for (let kid of kids) {
|
498 |
+
if (!kid.isAlive) continue;
|
499 |
+
|
500 |
+
// Body
|
501 |
+
ctx.fillStyle = '#FF69B4';
|
502 |
+
ctx.beginPath();
|
503 |
+
ctx.arc(kid.x, kid.y, kid.size, 0, Math.PI * 2);
|
504 |
+
ctx.fill();
|
505 |
+
|
506 |
+
// Face
|
507 |
+
ctx.fillStyle = '#FFF';
|
508 |
+
ctx.beginPath();
|
509 |
+
ctx.arc(kid.x, kid.y - kid.size/3, kid.size/3, 0, Math.PI * 2);
|
510 |
+
ctx.fill();
|
511 |
+
|
512 |
+
// Scream mouth if running
|
513 |
+
const distToPlayer = Math.sqrt(
|
514 |
+
Math.pow(kid.x - player.x, 2) +
|
515 |
+
Math.pow(kid.y - player.y, 2)
|
516 |
+
);
|
517 |
+
|
518 |
+
if (distToPlayer < 200) {
|
519 |
+
ctx.fillStyle = '#FF0000';
|
520 |
+
ctx.beginPath();
|
521 |
+
ctx.arc(kid.x, kid.y - kid.size/3, kid.size/5, 0, Math.PI * 2);
|
522 |
+
ctx.fill();
|
523 |
+
}
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
// Draw police
|
528 |
+
function drawPolice() {
|
529 |
+
for (let cop of police) {
|
530 |
+
if (!cop.isAlive) continue;
|
531 |
+
|
532 |
+
// Body
|
533 |
+
ctx.fillStyle = '#0000FF';
|
534 |
+
ctx.beginPath();
|
535 |
+
ctx.arc(cop.x, cop.y, cop.size, 0, Math.PI * 2);
|
536 |
+
ctx.fill();
|
537 |
+
|
538 |
+
// Face
|
539 |
+
ctx.fillStyle = '#FFF';
|
540 |
+
ctx.beginPath();
|
541 |
+
ctx.arc(cop.x, cop.y - cop.size/3, cop.size/3, 0, Math.PI * 2);
|
542 |
+
ctx.fill();
|
543 |
+
|
544 |
+
// Badge
|
545 |
+
ctx.fillStyle = '#FFD700';
|
546 |
+
ctx.beginPath();
|
547 |
+
ctx.arc(cop.x, cop.y, cop.size/3, 0, Math.PI * 2);
|
548 |
+
ctx.fill();
|
549 |
+
|
550 |
+
// Gun if shooting
|
551 |
+
if (cop.shootTimer > 50) {
|
552 |
+
ctx.strokeStyle = '#000';
|
553 |
+
ctx.lineWidth = 3;
|
554 |
+
ctx.beginPath();
|
555 |
+
ctx.moveTo(cop.x, cop.y);
|
556 |
+
ctx.lineTo(
|
557 |
+
cop.x + Math.cos(cop.direction) * cop.size * 2,
|
558 |
+
cop.y + Math.sin(cop.direction) * cop.size * 2
|
559 |
+
);
|
560 |
+
ctx.stroke();
|
561 |
+
}
|
562 |
+
}
|
563 |
+
}
|
564 |
+
|
565 |
+
// Create blood particles
|
566 |
+
function createBlood(x, y) {
|
567 |
+
for (let i = 0; i < 10; i++) {
|
568 |
+
const particle = document.createElement('div');
|
569 |
+
particle.className = 'blood-particle';
|
570 |
+
particle.style.left = `${x + (Math.random() * 20 - 10)}px`;
|
571 |
+
particle.style.top = `${y + (Math.random() * 20 - 10)}px`;
|
572 |
+
document.body.appendChild(particle);
|
573 |
+
|
574 |
+
// Animate
|
575 |
+
const angle = Math.random() * Math.PI * 2;
|
576 |
+
const distance = 10 + Math.random() * 40;
|
577 |
+
const duration = 300 + Math.random() * 700;
|
578 |
+
|
579 |
+
particle.animate([
|
580 |
+
{
|
581 |
+
transform: `translate(0, 0)`,
|
582 |
+
opacity: 1
|
583 |
+
},
|
584 |
+
{
|
585 |
+
transform: `translate(${Math.cos(angle) * distance}px, ${Math.sin(angle) * distance}px)`,
|
586 |
+
opacity: 0
|
587 |
+
}
|
588 |
+
], {
|
589 |
+
duration: duration,
|
590 |
+
easing: 'cubic-bezier(0.1, 0.8, 0.2, 1)'
|
591 |
+
});
|
592 |
+
|
593 |
+
// Remove after animation
|
594 |
+
setTimeout(() => {
|
595 |
+
particle.remove();
|
596 |
+
}, duration);
|
597 |
+
}
|
598 |
+
}
|
599 |
+
|
600 |
+
// Check phase transitions
|
601 |
+
function checkPhaseTransitions() {
|
602 |
+
// Phase 1 to 2: when all kids are dead
|
603 |
+
if (gamePhase === 1) {
|
604 |
+
const aliveKids = kids.filter(kid => kid.isAlive).length;
|
605 |
+
if (aliveKids === 0) {
|
606 |
+
gamePhase = 2;
|
607 |
+
phaseDisplay.textContent = 'PHASE 2: HIDE AND WAIT';
|
608 |
+
|
609 |
+
// Timer for police arrival
|
610 |
+
setTimeout(() => {
|
611 |
+
gamePhase = 3;
|
612 |
+
phaseDisplay.textContent = 'PHASE 3: FIGHT POLICE';
|
613 |
+
}, 10000); // 10 seconds
|
614 |
+
}
|
615 |
+
}
|
616 |
+
}
|
617 |
+
|
618 |
+
// Update timer
|
619 |
+
function updateTimer() {
|
620 |
+
gameTime++;
|
621 |
+
const minutes = Math.floor(gameTime / 60).toString().padStart(2, '0');
|
622 |
+
const seconds = (gameTime % 60).toString().padStart(2, '0');
|
623 |
+
timerDisplay.textContent = `TIME: ${minutes}:${seconds}`;
|
624 |
+
}
|
625 |
+
|
626 |
+
// Game over
|
627 |
+
function gameOver() {
|
628 |
+
gameRunning = false;
|
629 |
+
clearInterval(timerInterval);
|
630 |
+
|
631 |
+
// Show game over screen
|
632 |
+
finalScoreDisplay.textContent = `You killed ${score} victims`;
|
633 |
+
gameOverScreen.style.display = 'block';
|
634 |
+
}
|
635 |
+
|
636 |
+
// Input handling
|
637 |
+
const keys = {};
|
638 |
+
const mouse = {
|
639 |
+
x: 0,
|
640 |
+
y: 0,
|
641 |
+
isAttacking: false,
|
642 |
+
isHiding: false
|
643 |
+
};
|
644 |
+
|
645 |
+
window.addEventListener('keydown', (e) => {
|
646 |
+
keys[e.key.toLowerCase()] = true;
|
647 |
+
});
|
648 |
+
|
649 |
+
window.addEventListener('keyup', (e) => {
|
650 |
+
keys[e.key.toLowerCase()] = false;
|
651 |
+
});
|
652 |
+
|
653 |
+
canvas.addEventListener('mousemove', (e) => {
|
654 |
+
mouse.x = e.clientX;
|
655 |
+
mouse.y = e.clientY;
|
656 |
+
|
657 |
+
// Update player direction to face mouse
|
658 |
+
player.direction = Math.atan2(
|
659 |
+
e.clientY - player.y,
|
660 |
+
e.clientX - player.x
|
661 |
+
);
|
662 |
+
});
|
663 |
+
|
664 |
+
canvas.addEventListener('mousedown', (e) => {
|
665 |
+
if (e.button === 0) { // Left click
|
666 |
+
mouse.isAttacking = true;
|
667 |
+
} else if (e.button === 2) { // Right click
|
668 |
+
mouse.isHiding = true;
|
669 |
+
}
|
670 |
+
});
|
671 |
+
|
672 |
+
canvas.addEventListener('mouseup', (e) => {
|
673 |
+
if (e.button === 0) {
|
674 |
+
mouse.isAttacking = false;
|
675 |
+
} else if (e.button === 2) {
|
676 |
+
mouse.isHiding = false;
|
677 |
+
}
|
678 |
+
});
|
679 |
+
|
680 |
+
canvas.addEventListener('contextmenu', (e) => {
|
681 |
+
e.preventDefault(); // Prevent right-click menu
|
682 |
+
});
|
683 |
+
|
684 |
+
// Window resize
|
685 |
+
window.addEventListener('resize', () => {
|
686 |
+
canvas.width = window.innerWidth;
|
687 |
+
canvas.height = window.innerHeight;
|
688 |
+
});
|
689 |
+
|
690 |
+
// Start button
|
691 |
+
startBtn.addEventListener('click', initGame);
|
692 |
+
|
693 |
+
// Restart button
|
694 |
+
restartBtn.addEventListener('click', initGame);
|
695 |
+
</script>
|
696 |
+
<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=MaxHeadspace/chainsaw-massacre-2d" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
697 |
+
</html>
|