hitbox fix

This commit is contained in:
Bluwww 2025-12-13 11:50:04 +07:00
parent d3640e0a32
commit 88cf60e096

104
Script.js
View File

@ -1,5 +1,7 @@
"use strict"; "use strict";
const DEBUG_HITBOX = true;
// ================== BGM SYSTEM ================== // ================== BGM SYSTEM ==================
const bgmList = [ const bgmList = [
{ normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" }, { normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" },
@ -114,7 +116,6 @@ window.onload = function () {
init(); init();
}; };
// Init // Init
function init() { function init() {
c = document.getElementById("canvas"); c = document.getElementById("canvas");
@ -135,7 +136,6 @@ function init() {
requestAnimationFrame(gameLoop); requestAnimationFrame(gameLoop);
} }
function gameLoop(timestamp) { function gameLoop(timestamp) {
if (!gameStarted) return; if (!gameStarted) return;
@ -269,7 +269,17 @@ function drawGame() {
t.draw(); t.draw();
t.update(); t.update();
if (!player1.dead && Tabrakan(player1.getHitbox(), t)) { // Hitbox token sederhana (tidak perlu .getHitbox karena bentuknya simple)
// Tapi kita pakai logika bounding box manual di sini
if (
!player1.dead &&
Tabrakan(player1.getHitbox(), {
x: t.x,
y: t.y,
width: t.width,
height: t.height,
})
) {
abilityCharges++; abilityCharges++;
abilityTokens.splice(i, 1); abilityTokens.splice(i, 1);
createParticles(t.x, t.y, 15, "#00ffea"); createParticles(t.x, t.y, 15, "#00ffea");
@ -286,6 +296,8 @@ function drawGame() {
// Player // Player
if (!player1.dead) { if (!player1.dead) {
player1.draw(); player1.draw();
// DEBUG: Lihat Hitbox Player
if (DEBUG_HITBOX) drawDebugHitbox(player1.getHitbox(), "lime");
} }
// Enemies // Enemies
@ -294,6 +306,8 @@ function drawGame() {
s.draw(); s.draw();
s.update(); s.update();
if (DEBUG_HITBOX) drawDebugHitbox(s.getHitbox(), "red");
if (s.x < -200) { if (s.x < -200) {
enemyShipArray.splice(i, 1); enemyShipArray.splice(i, 1);
i--; i--;
@ -311,15 +325,8 @@ function drawGame() {
// Collision with player (hitbox vs hitbox) // Collision with player (hitbox vs hitbox)
if (!player1.dead && Tabrakan(player1.getHitbox(), s.getHitbox())) { if (!player1.dead && Tabrakan(player1.getHitbox(), s.getHitbox())) {
explosions.push( explosions.push(new Explosion(s.x + s.width / 2, s.y + s.height / 2));
new Explosion(s.x + s.width / 2, s.y + s.height / 2) createParticles(s.x + s.width / 2, s.y + s.height / 2, 20, "#ff6600");
);
createParticles(
s.x + s.width / 2,
s.y + s.height / 2,
20,
"#ff6600"
);
enemyShipArray.splice(i, 1); enemyShipArray.splice(i, 1);
i--; i--;
handlePlayerHit(); handlePlayerHit();
@ -333,11 +340,14 @@ function drawGame() {
m.draw(); m.draw();
m.update(); m.update();
if (DEBUG_HITBOX) drawDebugHitbox(m.getHitbox(), "cyan");
let hit = false; let hit = false;
for (let j = 0; j < enemyShipArray.length; j++) { for (let j = 0; j < enemyShipArray.length; j++) {
let en = enemyShipArray[j]; let en = enemyShipArray[j];
if (Tabrakan(m, en.getHitbox())) { // PERBAIKAN: Gunakan .getHitbox() untuk kedua objek
if (Tabrakan(m.getHitbox(), en.getHitbox())) {
player1.score += 100; player1.score += 100;
explosion_enemy.currentTime = 0; explosion_enemy.currentTime = 0;
explosion_enemy.play(); explosion_enemy.play();
@ -374,7 +384,10 @@ function drawGame() {
b.draw(); b.draw();
b.update(); b.update();
if (!player1.dead && Tabrakan(b, player1.getHitbox())) { if (DEBUG_HITBOX) drawDebugHitbox(b.getHitbox(), "orange");
// PERBAIKAN: Gunakan b.getHitbox() agar collision lebih akurat (tidak kena glow)
if (!player1.dead && Tabrakan(b.getHitbox(), player1.getHitbox())) {
explosions.push( explosions.push(
new Explosion( new Explosion(
player1.x + player1.width / 2, player1.x + player1.width / 2,
@ -421,6 +434,14 @@ function drawGame() {
drawUI(); drawUI();
} }
function drawDebugHitbox(rect, color) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
ctx.restore();
}
function drawUI() { function drawUI() {
drawNewText(" " + player1.score, 1400, 760, "white"); drawNewText(" " + player1.score, 1400, 760, "white");
@ -467,16 +488,18 @@ class PlayerObject {
}; };
} }
getHitbox() { getHitbox() {
const w = this.width * 0.45; const h = this.height * 0.05;
const h = this.height * 0.55;
const w = this.width * 0.8;
const x = this.x + (this.width - w) / 2; const x = this.x + (this.width - w) / 2;
const y = this.y + (this.height - h) / 2; const y = this.y + (this.height - h) / 2;
return { x, y, width: w, height: h }; return { x, y, width: w, height: h };
} }
draw() { draw() {
// Invi frames
if (this.invincible > 0 && game.frames % 10 < 5) { if (this.invincible > 0 && game.frames % 10 < 5) {
return; return;
} }
@ -646,7 +669,7 @@ function updateCamera() {
cameraY += (clamped - cameraY) * 0.1; cameraY += (clamped - cameraY) * 0.1;
} }
// //
class LaserBullet { class LaserBullet {
constructor(x, y) { constructor(x, y) {
this.x = x; this.x = x;
@ -656,6 +679,10 @@ class LaserBullet {
this.speed = 16; this.speed = 16;
} }
getHitbox() {
return { x: this.x, y: this.y, width: this.width, height: this.height };
}
draw() { draw() {
let g = ctx.createLinearGradient( let g = ctx.createLinearGradient(
this.x, this.x,
@ -678,7 +705,7 @@ class LaserBullet {
} }
} }
// //
class EnemyObj { class EnemyObj {
constructor(x, y, speed, img, pattern = "straight") { constructor(x, y, speed, img, pattern = "straight") {
this.x = x; this.x = x;
@ -693,9 +720,10 @@ class EnemyObj {
this.angle = 0; this.angle = 0;
} }
getHitbox() { getHitbox() {
const w = this.width * 0.65; const w = this.width * 0.55;
const h = this.height * 0.65; const h = this.height * 0.55;
const x = this.x + (this.width - w) / 2; const x = this.x + (this.width - w) / 2;
const y = this.y + (this.height - h) / 2; const y = this.y + (this.height - h) / 2;
return { x, y, width: w, height: h }; return { x, y, width: w, height: h };
@ -732,6 +760,17 @@ class EnemyBullet {
this.vy = (dy / len) * speed; this.vy = (dy / len) * speed;
} }
getHitbox() {
const padding = 1;
return {
x: this.x + padding,
y: this.y + padding,
width: this.width - padding * 2,
height: this.height - padding * 2,
};
}
draw() { draw() {
let g = ctx.createLinearGradient( let g = ctx.createLinearGradient(
this.x + this.width, this.x + this.width,
@ -910,12 +949,7 @@ function useAbility() {
// Explosions for all enemies // Explosions for all enemies
enemyShipArray.forEach((e) => { enemyShipArray.forEach((e) => {
explosions.push(new Explosion(e.x + e.width / 2, e.y + e.height / 2)); explosions.push(new Explosion(e.x + e.width / 2, e.y + e.height / 2));
createParticles( createParticles(e.x + e.width / 2, e.y + e.height / 2, 20, "#ff9900");
e.x + e.width / 2,
e.y + e.height / 2,
20,
"#ff9900"
);
}); });
enemyShipArray = []; enemyShipArray = [];
@ -1035,7 +1069,7 @@ class Explosion {
} }
} }
// GAME OVER / PAUSE // GAME OVER / PAUSE
function drawGameOver() { function drawGameOver() {
ctx.fillStyle = "rgba(53, 0, 0, 0.7)"; ctx.fillStyle = "rgba(53, 0, 0, 0.7)";
ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.fillRect(0, 0, canvasWidth, canvasHeight);
@ -1052,11 +1086,7 @@ function drawGameOver() {
canvasWidth / 2, canvasWidth / 2,
canvasHeight / 2 + 20 canvasHeight / 2 + 20
); );
ctx.fillText( ctx.fillText("Refresh to Restart", canvasWidth / 2, canvasHeight / 2 + 70);
"Refresh to Restart",
canvasWidth / 2,
canvasHeight / 2 + 70
);
ctx.textAlign = "left"; ctx.textAlign = "left";
} }
@ -1070,11 +1100,7 @@ function drawPauseOverlay() {
ctx.textAlign = "center"; ctx.textAlign = "center";
ctx.fillText("PAUSED", canvasWidth / 2, canvasHeight / 2); ctx.fillText("PAUSED", canvasWidth / 2, canvasHeight / 2);
ctx.font = "24px Arial"; ctx.font = "24px Arial";
ctx.fillText( ctx.fillText("Press P to Resume", canvasWidth / 2, canvasHeight / 2 + 50);
"Press P to Resume",
canvasWidth / 2,
canvasHeight / 2 + 50
);
ctx.textAlign = "left"; ctx.textAlign = "left";
} }