From 88cf60e096efc34462883df70903738e05e69470 Mon Sep 17 00:00:00 2001 From: Bluwww Date: Sat, 13 Dec 2025 11:50:04 +0700 Subject: [PATCH] hitbox fix --- Script.js | 104 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/Script.js b/Script.js index c8e5acb..9581b00 100644 --- a/Script.js +++ b/Script.js @@ -1,5 +1,7 @@ "use strict"; +const DEBUG_HITBOX = true; + // ================== BGM SYSTEM ================== const bgmList = [ { normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" }, @@ -114,7 +116,6 @@ window.onload = function () { init(); }; - // Init function init() { c = document.getElementById("canvas"); @@ -135,7 +136,6 @@ function init() { requestAnimationFrame(gameLoop); } - function gameLoop(timestamp) { if (!gameStarted) return; @@ -269,7 +269,17 @@ function drawGame() { t.draw(); 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++; abilityTokens.splice(i, 1); createParticles(t.x, t.y, 15, "#00ffea"); @@ -286,6 +296,8 @@ function drawGame() { // Player if (!player1.dead) { player1.draw(); + // DEBUG: Lihat Hitbox Player + if (DEBUG_HITBOX) drawDebugHitbox(player1.getHitbox(), "lime"); } // Enemies @@ -294,6 +306,8 @@ function drawGame() { s.draw(); s.update(); + if (DEBUG_HITBOX) drawDebugHitbox(s.getHitbox(), "red"); + if (s.x < -200) { enemyShipArray.splice(i, 1); i--; @@ -311,15 +325,8 @@ function drawGame() { // Collision with player (hitbox vs hitbox) if (!player1.dead && Tabrakan(player1.getHitbox(), s.getHitbox())) { - explosions.push( - 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" - ); + explosions.push(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"); enemyShipArray.splice(i, 1); i--; handlePlayerHit(); @@ -333,11 +340,14 @@ function drawGame() { m.draw(); m.update(); + if (DEBUG_HITBOX) drawDebugHitbox(m.getHitbox(), "cyan"); + let hit = false; for (let j = 0; j < enemyShipArray.length; 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; explosion_enemy.currentTime = 0; explosion_enemy.play(); @@ -374,7 +384,10 @@ function drawGame() { b.draw(); 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( new Explosion( player1.x + player1.width / 2, @@ -421,6 +434,14 @@ function drawGame() { 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() { drawNewText(" " + player1.score, 1400, 760, "white"); @@ -467,16 +488,18 @@ class PlayerObject { }; } + getHitbox() { - const w = this.width * 0.45; - const h = this.height * 0.55; + const h = this.height * 0.05; + + const w = this.width * 0.8; + const x = this.x + (this.width - w) / 2; const y = this.y + (this.height - h) / 2; + return { x, y, width: w, height: h }; } - draw() { - // Invi frames if (this.invincible > 0 && game.frames % 10 < 5) { return; } @@ -646,7 +669,7 @@ function updateCamera() { cameraY += (clamped - cameraY) * 0.1; } -// +// class LaserBullet { constructor(x, y) { this.x = x; @@ -656,6 +679,10 @@ class LaserBullet { this.speed = 16; } + getHitbox() { + return { x: this.x, y: this.y, width: this.width, height: this.height }; + } + draw() { let g = ctx.createLinearGradient( this.x, @@ -678,7 +705,7 @@ class LaserBullet { } } -// +// class EnemyObj { constructor(x, y, speed, img, pattern = "straight") { this.x = x; @@ -693,9 +720,10 @@ class EnemyObj { this.angle = 0; } + getHitbox() { - const w = this.width * 0.65; - const h = this.height * 0.65; + const w = this.width * 0.55; + const h = this.height * 0.55; const x = this.x + (this.width - w) / 2; const y = this.y + (this.height - h) / 2; return { x, y, width: w, height: h }; @@ -732,6 +760,17 @@ class EnemyBullet { 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() { let g = ctx.createLinearGradient( this.x + this.width, @@ -910,12 +949,7 @@ function useAbility() { // Explosions for all enemies enemyShipArray.forEach((e) => { explosions.push(new Explosion(e.x + e.width / 2, e.y + e.height / 2)); - createParticles( - e.x + e.width / 2, - e.y + e.height / 2, - 20, - "#ff9900" - ); + createParticles(e.x + e.width / 2, e.y + e.height / 2, 20, "#ff9900"); }); enemyShipArray = []; @@ -1035,7 +1069,7 @@ class Explosion { } } -// GAME OVER / PAUSE +// GAME OVER / PAUSE function drawGameOver() { ctx.fillStyle = "rgba(53, 0, 0, 0.7)"; ctx.fillRect(0, 0, canvasWidth, canvasHeight); @@ -1052,11 +1086,7 @@ function drawGameOver() { canvasWidth / 2, canvasHeight / 2 + 20 ); - ctx.fillText( - "Refresh to Restart", - canvasWidth / 2, - canvasHeight / 2 + 70 - ); + ctx.fillText("Refresh to Restart", canvasWidth / 2, canvasHeight / 2 + 70); ctx.textAlign = "left"; } @@ -1070,11 +1100,7 @@ function drawPauseOverlay() { ctx.textAlign = "center"; ctx.fillText("PAUSED", canvasWidth / 2, canvasHeight / 2); ctx.font = "24px Arial"; - ctx.fillText( - "Press P to Resume", - canvasWidth / 2, - canvasHeight / 2 + 50 - ); + ctx.fillText("Press P to Resume", canvasWidth / 2, canvasHeight / 2 + 50); ctx.textAlign = "left"; }