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