Skip to content

Commit aba7d63

Browse files
authored
enhanced: gameplay and UI
1 parent b027006 commit aba7d63

2 files changed

Lines changed: 171 additions & 14 deletions

File tree

data/game.js

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,41 @@ let reconnecting = false;
88
let ws = null;
99
let lastGameStart = 0;
1010

11+
const enemyFireDelays = {
12+
vi: 3000,
13+
vim: 2000,
14+
neovim: 1000
15+
};
16+
17+
18+
19+
let quoteText = "";
20+
let quoteAuthor = "";
21+
22+
const fallbackQuotes = [
23+
{ text: "Keep calm and code on.", author: "Anonymous" },
24+
{ text: "There is no place like 127.0.0.1.", author: "Unknown" },
25+
{ text: "First, solve the problem. Then, write the code.", author: "John Johnson" },
26+
{ text: "Code is like humor. When you have to explain it, it’s bad.", author: "Cory House" },
27+
{ text: "The best way to get a project done faster is to start sooner.", author: "Jim Highsmith" }
28+
];
29+
30+
async function getMotivationalQuote() {
31+
try {
32+
const res = await fetch("https://api.quotable.io/random?maxLength=120&tags=technology|motivational|famous-quotes");
33+
const data = await res.json();
34+
quoteText = data.content || fallbackQuotes[0].text;
35+
quoteAuthor = data.author || fallbackQuotes[0].author;
36+
} catch (err) {
37+
const fallback = fallbackQuotes[Math.floor(Math.random() * fallbackQuotes.length)];
38+
quoteText = fallback.text;
39+
quoteAuthor = fallback.author;
40+
}
41+
}
42+
43+
44+
45+
1146
function resizeCanvas() {
1247
const ratio = 4 / 3;
1348
const w = window.innerWidth;
@@ -48,23 +83,23 @@ document.addEventListener("visibilitychange", () => {
4883
requestWakeLock();
4984

5085
const pauseBtn = document.createElement("button");
51-
pauseBtn.innerText = "⏸️ Pauza";
86+
pauseBtn.innerText = "⏸️ Pause";
5287
pauseBtn.className = "game-button";
5388
pauseBtn.style.right = "120px";
5489
pauseBtn.style.top = "10px";
5590
pauseBtn.onclick = () => paused = !paused;
5691
document.body.appendChild(pauseBtn);
5792

5893
const restartBtn = document.createElement("button");
59-
restartBtn.innerText = "🔄 Restart";
94+
restartBtn.innerText = "🔄 Reset";
6095
restartBtn.className = "game-button";
6196
restartBtn.style.right = "10px";
6297
restartBtn.style.top = "10px";
6398
restartBtn.onclick = () => newGame();
6499
document.body.appendChild(restartBtn);
65100

66101
// resizeCanvas();
67-
102+
getMotivationalQuote();
68103

69104

70105
const playerColors = ["white", "lime", "cyan", "orange", "violet"];
@@ -174,6 +209,7 @@ class Enemy {
174209
this.y = y;
175210
this.dx = 1;
176211
this.type = type;
212+
this.nextFireTime = Date.now() + Math.random() * enemyFireDelays[type];
177213
}
178214

179215
draw() {
@@ -194,6 +230,15 @@ class Enemy {
194230
this.y += 10;
195231
}
196232
}
233+
234+
canFire() {
235+
return Date.now() >= this.nextFireTime;
236+
}
237+
238+
resetFireCooldown() {
239+
this.nextFireTime = Date.now() + enemyFireDelays[this.type];
240+
}
241+
197242
}
198243

199244

@@ -236,11 +281,16 @@ function randomColor() {
236281
}
237282

238283
function enemyFire() {
239-
if (enemies.length === 0 || gameOver) return;
240-
const shooter = enemies[Math.floor(Math.random() * enemies.length)];
241-
enemyBullets.push({ x: shooter.x + 10, y: shooter.y + 10 });
284+
if (gameOver || enemies.length === 0) return;
285+
enemies.forEach(enemy => {
286+
if (enemy.canFire()) {
287+
enemyBullets.push({ x: enemy.x + 10, y: enemy.y + 10 });
288+
enemy.resetFireCooldown();
289+
}
290+
});
242291
}
243292

293+
244294
function drawHUD() {
245295
ctx.fillStyle = "white";
246296
ctx.font = "16px monospace";
@@ -262,9 +312,17 @@ function draw() {
262312
ctx.fillStyle = "white";
263313
ctx.font = "28px sans-serif";
264314
ctx.fillText("Tap, press, or move to start", canvas.width / 2 - 180, canvas.height / 2);
315+
316+
ctx.font = "18px sans-serif";
317+
ctx.fillText(`"${quoteText}"`, canvas.width / 2 - 180, canvas.height / 2 + 40);
318+
319+
ctx.font = "16px sans-serif";
320+
ctx.fillText(`— ${quoteAuthor}`, canvas.width / 2 - 180, canvas.height / 2 + 65);
321+
265322
requestAnimationFrame(draw);
266323
return;
267-
}
324+
}
325+
268326

269327
if (paused) {
270328
ctx.fillStyle = "white";
@@ -313,6 +371,17 @@ function draw() {
313371
level++;
314372
createEnemies();
315373
updateFireRate();
374+
375+
[player1, player2].forEach(p => {
376+
if (p.lives < 3) {
377+
p.lives++;
378+
if (!p.alive) {
379+
p.alive = false;
380+
p.respawnTimer = Date.now();
381+
}
382+
}
383+
});
384+
316385
}
317386

318387
if (!player1.alive && player1.lives === 0 && !player2.alive && player2.lives === 0) {

data/game.js.bak

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,41 @@ let reconnecting = false;
88
let ws = null;
99
let lastGameStart = 0;
1010

11+
const enemyFireDelays = {
12+
vi: 3000,
13+
vim: 2000,
14+
neovim: 1000
15+
};
16+
17+
18+
19+
let quoteText = "";
20+
let quoteAuthor = "";
21+
22+
const fallbackQuotes = [
23+
{ text: "Keep calm and code on.", author: "Anonymous" },
24+
{ text: "There is no place like 127.0.0.1.", author: "Unknown" },
25+
{ text: "First, solve the problem. Then, write the code.", author: "John Johnson" },
26+
{ text: "Code is like humor. When you have to explain it, it’s bad.", author: "Cory House" },
27+
{ text: "The best way to get a project done faster is to start sooner.", author: "Jim Highsmith" }
28+
];
29+
30+
async function getMotivationalQuote() {
31+
try {
32+
const res = await fetch("https://api.quotable.io/random?maxLength=120&tags=technology|motivational|famous-quotes");
33+
const data = await res.json();
34+
quoteText = data.content || fallbackQuotes[0].text;
35+
quoteAuthor = data.author || fallbackQuotes[0].author;
36+
} catch (err) {
37+
const fallback = fallbackQuotes[Math.floor(Math.random() * fallbackQuotes.length)];
38+
quoteText = fallback.text;
39+
quoteAuthor = fallback.author;
40+
}
41+
}
42+
43+
44+
45+
1146
function resizeCanvas() {
1247
const ratio = 4 / 3;
1348
const w = window.innerWidth;
@@ -48,23 +83,23 @@ document.addEventListener("visibilitychange", () => {
4883
requestWakeLock();
4984

5085
const pauseBtn = document.createElement("button");
51-
pauseBtn.innerText = "⏸️ Pauza";
86+
pauseBtn.innerText = "⏸️ Pause";
5287
pauseBtn.className = "game-button";
5388
pauseBtn.style.right = "120px";
5489
pauseBtn.style.top = "10px";
5590
pauseBtn.onclick = () => paused = !paused;
5691
document.body.appendChild(pauseBtn);
5792

5893
const restartBtn = document.createElement("button");
59-
restartBtn.innerText = "🔄 Restart";
94+
restartBtn.innerText = "🔄 Reset";
6095
restartBtn.className = "game-button";
6196
restartBtn.style.right = "10px";
6297
restartBtn.style.top = "10px";
6398
restartBtn.onclick = () => newGame();
6499
document.body.appendChild(restartBtn);
65100

66101
// resizeCanvas();
67-
102+
getMotivationalQuote();
68103

69104

70105
const playerColors = ["white", "lime", "cyan", "orange", "violet"];
@@ -139,14 +174,42 @@ class Player {
139174
if (now - this.lastShot > 1000 && this.active && this.alive) {
140175
this.bullets.push({ x: this.x, y: this.y });
141176
this.lastShot = now;
142-
} else if (gameOver
177+
} else if (gameOver) {
178+
newGame();
179+
}
180+
}
181+
182+
updateBullets() {
183+
this.bullets = this.bullets.filter(b => b.y > 0);
184+
this.bullets.forEach(b => b.y -= 7);
185+
ctx.fillStyle = this.color;
186+
this.bullets.forEach(b => ctx.fillRect(b.x - 2, b.y, 4, 10));
187+
}
188+
189+
takeHit() {
190+
if (!this.alive || this.lives <= 0) return;
191+
this.lives -= 1;
192+
this.alive = false;
193+
this.respawnTimer = Date.now();
194+
}
195+
196+
updateRespawn() {
197+
if (!this.alive && this.lives > 0) {
198+
const now = Date.now();
199+
if (now - this.respawnTimer >= 5000) {
200+
this.alive = true;
201+
}
202+
}
203+
}
204+
}
143205

144206
class Enemy {
145207
constructor(x, y, type) {
146208
this.x = x;
147209
this.y = y;
148210
this.dx = 1;
149211
this.type = type;
212+
this.nextFireTime = Date.now() + Math.random() * enemyFireDelays[type];
150213
}
151214

152215
draw() {
@@ -167,6 +230,15 @@ class Enemy {
167230
this.y += 10;
168231
}
169232
}
233+
234+
canFire() {
235+
return Date.now() >= this.nextFireTime;
236+
}
237+
238+
resetFireCooldown() {
239+
this.nextFireTime = Date.now() + enemyFireDelays[this.type];
240+
}
241+
170242
}
171243

172244

@@ -209,11 +281,16 @@ function randomColor() {
209281
}
210282

211283
function enemyFire() {
212-
if (enemies.length === 0 || gameOver) return;
213-
const shooter = enemies[Math.floor(Math.random() * enemies.length)];
214-
enemyBullets.push({ x: shooter.x + 10, y: shooter.y + 10 });
284+
if (gameOver || enemies.length === 0) return;
285+
enemies.forEach(enemy => {
286+
if (enemy.canFire()) {
287+
enemyBullets.push({ x: enemy.x + 10, y: enemy.y + 10 });
288+
enemy.resetFireCooldown();
289+
}
290+
});
215291
}
216292

293+
217294
function drawHUD() {
218295
ctx.fillStyle = "white";
219296
ctx.font = "16px monospace";
@@ -286,6 +363,17 @@ function draw() {
286363
level++;
287364
createEnemies();
288365
updateFireRate();
366+
367+
[player1, player2].forEach(p => {
368+
if (p.lives < 3) {
369+
p.lives++;
370+
if (!p.alive) {
371+
p.alive = false;
372+
p.respawnTimer = Date.now();
373+
}
374+
}
375+
});
376+
289377
}
290378

291379
if (!player1.alive && player1.lives === 0 && !player2.alive && player2.lives === 0) {

0 commit comments

Comments
 (0)