bug fix
This commit is contained in:
parent
71389ebb08
commit
2b55cdc7a4
123
Script.js
123
Script.js
@ -41,7 +41,7 @@ let currentWave = null;
|
||||
let waveCooldown = 0;
|
||||
|
||||
let abilityCharges = 0;
|
||||
let missileAmmo = 0; // Missile Ammo
|
||||
let missileAmmo = 0;
|
||||
|
||||
var game = {
|
||||
level: 1,
|
||||
@ -59,9 +59,15 @@ var keys = {
|
||||
fire: false,
|
||||
};
|
||||
|
||||
// --- LOAD IMAGES ---
|
||||
var playerShipImg = new Image();
|
||||
playerShipImg.src = "img/Player/pesawat22.png";
|
||||
|
||||
// *** GAMBAR BARU UNTUK PICKUP MISSILE ***
|
||||
// Pastikan file gambar "missile_pickup.png" ada di folder img Anda
|
||||
var missilePickupImg = new Image();
|
||||
missilePickupImg.src = "img/Skills/missile.png";
|
||||
|
||||
var bg0 = new Image();
|
||||
bg0.src = "img/bg_0.png";
|
||||
var bg1 = new Image();
|
||||
@ -93,8 +99,8 @@ for (var i = 0; i < enemyImgArray.length; i++) {
|
||||
enemyImgArray[i].src = "img/alien_" + [i] + ".png";
|
||||
}
|
||||
|
||||
var missilesArray = []; // Laser Biasa
|
||||
var playerMissilesArray = []; // Homing Missile
|
||||
var missilesArray = [];
|
||||
var playerMissilesArray = [];
|
||||
var enemyShipArray = [];
|
||||
var enemyBulletsArray = [];
|
||||
var explosions = [];
|
||||
@ -131,6 +137,8 @@ function init() {
|
||||
document.addEventListener("keydown", keyDownPressed, false);
|
||||
document.addEventListener("keyup", keyUpPressed, false);
|
||||
|
||||
document.addEventListener("contextmenu", (event) => event.preventDefault());
|
||||
|
||||
gameStarted = true;
|
||||
pickRandomBGM();
|
||||
currentBGM.volume = 1;
|
||||
@ -165,30 +173,27 @@ function gameLoop(timestamp) {
|
||||
let gamePaused = false;
|
||||
|
||||
function keyDownPressed(e) {
|
||||
if (e.keyCode === 87 || e.keyCode === 38) keys.up = true; // W / UP
|
||||
else if (e.keyCode === 83 || e.keyCode === 40) keys.down = true; // S / DOWN
|
||||
if (e.keyCode === 65 || e.keyCode === 37) keys.left = true; // A / LEFT
|
||||
if (e.keyCode === 68 || e.keyCode === 39) keys.right = true; // D / RIGHT
|
||||
if (e.keyCode === 87 || e.keyCode === 38) keys.up = true;
|
||||
else if (e.keyCode === 83 || e.keyCode === 40) keys.down = true;
|
||||
if (e.keyCode === 65 || e.keyCode === 37) keys.left = true;
|
||||
if (e.keyCode === 68 || e.keyCode === 39) keys.right = true;
|
||||
|
||||
if (e.keyCode === 32) {
|
||||
// SPACE
|
||||
keys.fire = true;
|
||||
if (!player1.dead) {
|
||||
fireBullet();
|
||||
}
|
||||
}
|
||||
|
||||
if (e.keyCode === 80) togglePause(); // P
|
||||
if (e.keyCode === 80) togglePause();
|
||||
|
||||
if (e.keyCode === 16) {
|
||||
// SHIFT (Bomb)
|
||||
if (abilityCharges > 0 && !game.gameOver && !gamePaused && !player1.dead) {
|
||||
useAbility();
|
||||
abilityCharges--;
|
||||
}
|
||||
}
|
||||
|
||||
// --- TOMBOL Q UNTUK MISSILE ---
|
||||
if (e.keyCode === 81) {
|
||||
// Q
|
||||
if (!game.gameOver && !gamePaused && !player1.dead) {
|
||||
@ -205,7 +210,6 @@ function keyUpPressed(e) {
|
||||
if (e.keyCode === 32) keys.fire = false;
|
||||
}
|
||||
|
||||
// --- NORMAL LASER ---
|
||||
function fireBullet() {
|
||||
if (player1.doubleLaserTimer > 0) {
|
||||
missilesArray.push(
|
||||
@ -237,7 +241,6 @@ function fireBullet() {
|
||||
);
|
||||
}
|
||||
|
||||
// --- FIRE HOMING MISSILE (Q) ---
|
||||
function firePlayerMissile() {
|
||||
if (missileAmmo > 0) {
|
||||
missileAmmo--;
|
||||
@ -248,7 +251,6 @@ function firePlayerMissile() {
|
||||
)
|
||||
);
|
||||
|
||||
// Sound effect
|
||||
let sfx = explosion_enemy.cloneNode();
|
||||
sfx.volume = 0.5;
|
||||
sfx.playbackRate = 2.0;
|
||||
@ -289,7 +291,6 @@ function updateGame() {
|
||||
player1.y = canvasHeight / 2 - player1.height / 2;
|
||||
player1.vx = 0;
|
||||
player1.vy = 0;
|
||||
// Reset skill jika mati
|
||||
player1.doubleLaserTimer = 0;
|
||||
}
|
||||
}
|
||||
@ -311,7 +312,6 @@ function drawGame() {
|
||||
|
||||
drawParticles();
|
||||
|
||||
// --- LOGIKA PICKUP ORB ---
|
||||
for (let i = 0; i < abilityTokens.length; i++) {
|
||||
const t = abilityTokens[i];
|
||||
t.draw();
|
||||
@ -327,15 +327,12 @@ function drawGame() {
|
||||
})
|
||||
) {
|
||||
if (t.type === "bomb") {
|
||||
// KUNING = BOMB
|
||||
abilityCharges++;
|
||||
createParticles(t.x, t.y, 15, "#ffff00");
|
||||
} else if (t.type === "double") {
|
||||
// MERAH = DOUBLE LASER
|
||||
player1.doubleLaserTimer = 600;
|
||||
createParticles(t.x, t.y, 15, "#ff0000");
|
||||
} else if (t.type === "missile") {
|
||||
// BIRU TUA = MISSILE (+3 Ammo)
|
||||
missileAmmo += 3;
|
||||
createParticles(t.x, t.y, 15, "#0000ff");
|
||||
}
|
||||
@ -390,7 +387,6 @@ function drawGame() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- UPDATE LASER BIASA ---
|
||||
for (let i = 0; i < missilesArray.length; i++) {
|
||||
let m = missilesArray[i];
|
||||
m.draw();
|
||||
@ -439,7 +435,6 @@ function drawGame() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- UPDATE PLAYER MISSILES (AUTO LOCK) ---
|
||||
for (let i = 0; i < playerMissilesArray.length; i++) {
|
||||
let pm = playerMissilesArray[i];
|
||||
pm.draw();
|
||||
@ -450,11 +445,9 @@ function drawGame() {
|
||||
let en = enemyShipArray[j];
|
||||
|
||||
if (Tabrakan(pm.getHitbox(), en.getHitbox())) {
|
||||
// DAMAGE MISSILE: 400 + (Level * 20)
|
||||
let missileDmg = 400 + game.level * 20;
|
||||
en.health -= missileDmg;
|
||||
|
||||
// Efek ledakan besar biru
|
||||
createParticles(pm.x + pm.width, pm.y, 20, "#0000ff");
|
||||
explosions.push(new Explosion(pm.x + pm.width, pm.y, 0.5));
|
||||
|
||||
@ -479,7 +472,6 @@ function drawGame() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hapus jika keluar layar jauh
|
||||
if (pm.x > canvasWidth + 200 || pm.y < -200 || pm.y > canvasHeight + 200) {
|
||||
playerMissilesArray.splice(i, 1);
|
||||
i--;
|
||||
@ -562,9 +554,8 @@ function drawUI() {
|
||||
}
|
||||
drawNewText(livesText, 30, canvasHeight - 50, "#ff3366");
|
||||
|
||||
// UI SKILL
|
||||
drawNewText("Bombs (Shift): " + abilityCharges, 30, 50, "#ffff00");
|
||||
drawNewText("Missiles (Q): " + missileAmmo, 30, 85, "#00ccff"); // Updated Text
|
||||
drawNewText("Missiles (Q): " + missileAmmo, 30, 85, "#00ccff");
|
||||
}
|
||||
|
||||
class PlayerObject {
|
||||
@ -821,18 +812,17 @@ class LaserBullet {
|
||||
}
|
||||
}
|
||||
|
||||
// --- NEW CLASS: HOMING PLAYER MISSILE ---
|
||||
class PlayerMissile {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = 30;
|
||||
this.height = 12;
|
||||
this.speed = 2; // Kecepatan Awal
|
||||
this.speed = 2;
|
||||
this.maxSpeed = 18;
|
||||
this.vx = 2;
|
||||
this.vy = 0;
|
||||
this.target = null; // Target yang akan dikejar
|
||||
this.target = null;
|
||||
}
|
||||
|
||||
getHitbox() {
|
||||
@ -841,7 +831,6 @@ class PlayerMissile {
|
||||
|
||||
draw() {
|
||||
ctx.save();
|
||||
// Gambar body missile (Biru)
|
||||
let g = ctx.createLinearGradient(
|
||||
this.x,
|
||||
this.y,
|
||||
@ -859,7 +848,6 @@ class PlayerMissile {
|
||||
ctx.lineTo(this.x, this.y + this.height);
|
||||
ctx.fill();
|
||||
|
||||
// Trail Effect
|
||||
if (Math.random() < 0.5) {
|
||||
createParticles(this.x, this.y + this.height / 2, 2, "#00bfff");
|
||||
}
|
||||
@ -867,11 +855,9 @@ class PlayerMissile {
|
||||
}
|
||||
|
||||
update() {
|
||||
// 1. Akselerasi (makin lama makin cepat)
|
||||
this.speed *= 1.08;
|
||||
if (this.speed > this.maxSpeed) this.speed = this.maxSpeed;
|
||||
|
||||
// 2. Logic Cari Musuh Terdekat (Auto Lock)
|
||||
if (!this.target || !enemyShipArray.includes(this.target)) {
|
||||
let minDist = 100000;
|
||||
let closest = null;
|
||||
@ -887,7 +873,6 @@ class PlayerMissile {
|
||||
this.target = closest;
|
||||
}
|
||||
|
||||
// 3. Gerak Mengejar Target
|
||||
if (this.target) {
|
||||
let tx = this.target.x + this.target.width / 2;
|
||||
let ty = this.target.y + this.target.height / 2;
|
||||
@ -895,11 +880,9 @@ class PlayerMissile {
|
||||
let dy = ty - this.y;
|
||||
let angle = Math.atan2(dy, dx);
|
||||
|
||||
// Update velocity ke arah musuh
|
||||
this.vx = Math.cos(angle) * this.speed;
|
||||
this.vy = Math.sin(angle) * this.speed;
|
||||
} else {
|
||||
// Jika tidak ada target, terbang lurus
|
||||
this.vx = this.speed;
|
||||
this.vy = 0;
|
||||
}
|
||||
@ -1058,8 +1041,6 @@ function addShips() {
|
||||
|
||||
function startNewWave() {
|
||||
// --- CHAOS WAVE MODE ---
|
||||
// Tidak ada pattern 'line', 'v', 'zigzag'.
|
||||
// Kita hanya menentukan jumlah musuh yang akan muncul di wave ini.
|
||||
|
||||
let baseCount = 3;
|
||||
let scalingCount = Math.floor(game.level / 2);
|
||||
@ -1116,17 +1097,14 @@ function spawnEnemyFromWave(wave) {
|
||||
enemyShipArray.push(enemy);
|
||||
}
|
||||
|
||||
// --- CLASS ORB UPDATE: Support Type ---
|
||||
// --- CLASS ORB UPDATE: SUPPORT IMAGE & OUTLINE ---
|
||||
class AbilityToken {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = 32;
|
||||
this.height = 32;
|
||||
this.width = 40; // Ukuran sedikit diperbesar untuk gambar
|
||||
this.height = 40;
|
||||
this.speed = 4;
|
||||
// Random Type saat spawn: "bomb" atau "double"
|
||||
this.type = Math.random() < 0.5 ? "bomb" : "double";
|
||||
|
||||
// RAND: 0-0.33=Bomb, 0.33-0.66=Double, 0.66-1.0=Missile
|
||||
let r = Math.random();
|
||||
if (r < 0.33) this.type = "bomb";
|
||||
@ -1136,31 +1114,44 @@ class AbilityToken {
|
||||
|
||||
draw() {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
const cx = this.x + this.width / 2;
|
||||
const cy = this.y + this.height / 2;
|
||||
ctx.arc(cx, cy, 12, 0, Math.PI * 2);
|
||||
|
||||
// --- WARNA ORB BERDASARKAN TIPE ---
|
||||
const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, 12);
|
||||
g.addColorStop(0, "#ffffff");
|
||||
if (this.type === "missile") {
|
||||
// --- METAL SLUG STYLE OUTLINE (KOTAK PUTIH TEBAL) ---
|
||||
ctx.strokeStyle = "#ffffff";
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeRect(this.x, this.y, this.width, this.height);
|
||||
|
||||
if (this.type === "bomb") {
|
||||
// Kuning (Bomb)
|
||||
g.addColorStop(0.5, "#ffff00");
|
||||
g.addColorStop(1, "#ff9900");
|
||||
} else if (this.type === "double") {
|
||||
// Merah (Double Laser)
|
||||
g.addColorStop(0.5, "#ff3333");
|
||||
g.addColorStop(1, "#990000");
|
||||
// Gambar Roket Piksel di dalamnya dengan sedikit padding
|
||||
const padding = 4;
|
||||
ctx.drawImage(
|
||||
missilePickupImg,
|
||||
this.x + padding,
|
||||
this.y + padding,
|
||||
this.width - padding * 2,
|
||||
this.height - padding * 2
|
||||
);
|
||||
} else {
|
||||
// Biru Tua (Missile)
|
||||
g.addColorStop(0.5, "#0000ff");
|
||||
g.addColorStop(1, "#00008b");
|
||||
// --- GAYA LAMA (ORB LINGKARAN) UNTUK BOMB & DOUBLE ---
|
||||
ctx.beginPath();
|
||||
const cx = this.x + this.width / 2;
|
||||
const cy = this.y + this.height / 2;
|
||||
ctx.arc(cx, cy, 16, 0, Math.PI * 2); // Radius disesuaikan dengan ukuran baru
|
||||
|
||||
const g = ctx.createRadialGradient(cx, cy, 0, cx, cy, 16);
|
||||
g.addColorStop(0, "#ffffff");
|
||||
|
||||
if (this.type === "bomb") {
|
||||
g.addColorStop(0.5, "#ffff00"); // Kuning
|
||||
g.addColorStop(1, "#ff9900");
|
||||
} else if (this.type === "double") {
|
||||
g.addColorStop(0.5, "#ff3333"); // Merah
|
||||
g.addColorStop(1, "#990000");
|
||||
}
|
||||
|
||||
ctx.fillStyle = g;
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
ctx.fillStyle = g;
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
@ -1170,8 +1161,8 @@ class AbilityToken {
|
||||
}
|
||||
|
||||
function maybeSpawnAbilityToken() {
|
||||
// --- KEMBALI KE 0.2% (0.002) ---
|
||||
if (Math.random() < 0.003 && abilityTokens.length < 3) {
|
||||
// --- 0.2% (0.002) ---
|
||||
if (Math.random() < 0.002 && abilityTokens.length < 3) {
|
||||
const y = Math.random() * (canvasHeight - 120) + 60;
|
||||
abilityTokens.push(new AbilityToken(canvasWidth + 40, y));
|
||||
}
|
||||
|
||||
BIN
img/Skills/missile.png
Normal file
BIN
img/Skills/missile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
Loading…
x
Reference in New Issue
Block a user