This commit is contained in:
Bluwww 2025-12-16 08:41:46 +07:00
parent 1cbd757ddb
commit dbeb74692d

View File

@ -51,7 +51,7 @@ var game = {
surge: 1.0, surge: 1.0,
surgePhase: 0, surgePhase: 0,
surgeTimer: 0, surgeTimer: 0,
surgeCooldown: 2400, // Start with 40s cooldown surgeCooldown: 2400,
}; };
var keys = { var keys = {
@ -75,7 +75,6 @@ laserPickupImg.src = "img/Skills/double-missile.png";
// *** GAMBAR BARU UNTUK PICKUP BOMB *** // *** GAMBAR BARU UNTUK PICKUP BOMB ***
var bombPickupImg = new Image(); var bombPickupImg = new Image();
// Pastikan file gambar bom clay Anda disimpan di sini
bombPickupImg.src = "img/Skills/bomb.png"; bombPickupImg.src = "img/Skills/bomb.png";
var livesImg = new Image(); var livesImg = new Image();
@ -138,8 +137,6 @@ let currentPlanet = null;
let laserSprite, enemyBulletSprite, missileSprite; let laserSprite, enemyBulletSprite, missileSprite;
function preRenderAssets() { function preRenderAssets() {
// 1. CACHE LASER BULLET
// Padding for shadowBlur (15px)
const lPad = 20; const lPad = 20;
const lW = 13 + lPad * 2; const lW = 13 + lPad * 2;
const lH = 4 + lPad * 2; const lH = 4 + lPad * 2;
@ -159,7 +156,6 @@ function preRenderAssets() {
lCtx.fillRect(lPad, lPad, 13, 4); lCtx.fillRect(lPad, lPad, 13, 4);
// 2. CACHE ENEMY BULLET
const ePad = 15; const ePad = 15;
const eW = 10 + ePad * 2; const eW = 10 + ePad * 2;
const eH = 4 + ePad * 2; const eH = 4 + ePad * 2;
@ -168,7 +164,7 @@ function preRenderAssets() {
enemyBulletSprite.height = eH; enemyBulletSprite.height = eH;
const eCtx = enemyBulletSprite.getContext("2d"); const eCtx = enemyBulletSprite.getContext("2d");
let eg = eCtx.createLinearGradient(ePad + 10, ePad, ePad, ePad); // Right to Left let eg = eCtx.createLinearGradient(ePad + 10, ePad, ePad, ePad);
eg.addColorStop(0, "#ff9900"); eg.addColorStop(0, "#ff9900");
eg.addColorStop(0.5, "#ffffff"); eg.addColorStop(0.5, "#ffffff");
eg.addColorStop(1, "#ff3300"); eg.addColorStop(1, "#ff3300");
@ -179,7 +175,6 @@ function preRenderAssets() {
eCtx.fillRect(ePad, ePad, 10, 4); eCtx.fillRect(ePad, ePad, 10, 4);
// 3. CACHE PLAYER MISSILE (Body Only)
const mPad = 5; const mPad = 5;
const mW = 30 + mPad * 2; const mW = 30 + mPad * 2;
const mH = 12 + mPad * 2; const mH = 12 + mPad * 2;
@ -196,8 +191,8 @@ function preRenderAssets() {
mCtx.fillStyle = mg; mCtx.fillStyle = mg;
mCtx.beginPath(); mCtx.beginPath();
mCtx.moveTo(mPad, mPad); mCtx.moveTo(mPad, mPad);
mCtx.lineTo(mPad + 30, mPad + 6); // height/2 mCtx.lineTo(mPad + 30, mPad + 6);
mCtx.lineTo(mPad, mPad + 12); // height mCtx.lineTo(mPad, mPad + 12);
mCtx.fill(); mCtx.fill();
} }
@ -206,7 +201,7 @@ window.onload = function () {
}; };
function init() { function init() {
preRenderAssets(); // Generate sprites before game starts preRenderAssets();
c = document.getElementById("canvas"); c = document.getElementById("canvas");
ctx = c.getContext("2d", { alpha: false }); ctx = c.getContext("2d", { alpha: false });
@ -311,7 +306,6 @@ function fireBullet() {
} }
laser.currentTime = 0; laser.currentTime = 0;
// IMPORTANT!! EXPERIMENT WITH THIS VALUE
laser.volume = 0.2; laser.volume = 0.2;
laser.play(); laser.play();
createParticles( createParticles(
@ -639,7 +633,7 @@ function drawUI() {
drawNewText(game.level, canvasWidth - 140, 50, "#00ff00", "30px"); drawNewText(game.level, canvasWidth - 140, 50, "#00ff00", "30px");
// Lives (Stacked Icons) // Lives (Stacked Icons)
const lifeSize = 40; // Scaled down from 104px source const lifeSize = 40;
const lifePadding = 5; const lifePadding = 5;
if (livesImg.complete) { if (livesImg.complete) {
@ -843,7 +837,7 @@ class backgroundObj {
this.height = 900; this.height = 900;
this.img = img; this.img = img;
this.img = img; this.img = img;
this.factor = speed; // Rename speed to factor for parallax this.factor = speed;
} }
draw() { draw() {
ctx.save(); ctx.save();
@ -938,11 +932,9 @@ class PlayerMissile {
draw() { draw() {
ctx.save(); ctx.save();
// Draw Cached Missile Body
const padding = 5; const padding = 5;
ctx.drawImage(missileSprite, this.x - padding, this.y - padding); ctx.drawImage(missileSprite, this.x - padding, this.y - padding);
// TRAIL BIRU LANGIT
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");
} }
@ -1101,7 +1093,6 @@ function addShips() {
if (currentWave.spawnTimer <= 0) { if (currentWave.spawnTimer <= 0) {
spawnEnemyFromWave(currentWave); spawnEnemyFromWave(currentWave);
currentWave.spawned++; currentWave.spawned++;
// --- RANDOM SPACING ---
let randomSpacing = let randomSpacing =
currentWave.spacing + Math.floor(Math.random() * 30); currentWave.spacing + Math.floor(Math.random() * 30);
currentWave.spawnTimer = randomSpacing; currentWave.spawnTimer = randomSpacing;
@ -1129,7 +1120,7 @@ function startNewWave() {
let baseCount = 3; let baseCount = 3;
let scalingCount = Math.floor(game.level / 2); let scalingCount = Math.floor(game.level / 2);
let count = Math.min( let count = Math.min(
20, // Max musuh ditingkatkan sedikit untuk kompensasi sebaran 20,
baseCount + scalingCount + Math.floor(Math.random() * 5) baseCount + scalingCount + Math.floor(Math.random() * 5)
); );
@ -1145,15 +1136,12 @@ function startNewWave() {
} }
function spawnEnemyFromWave(wave) { function spawnEnemyFromWave(wave) {
// --- POSISI BENAR-BENAR ACAK --- // --- POSISI MUSUH ACAK ---
// Tentukan Y sembarang di area layar
// Area aman: 60px dari atas, 100px dari bawah
const minY = 60; const minY = 60;
const maxY = canvasHeight - 120; const maxY = canvasHeight - 120;
const y = Math.random() * (maxY - minY) + minY; const y = Math.random() * (maxY - minY) + minY;
// Random X Offset biar tidak muncul dalam satu garis lurus sempurna
const xOffset = Math.random() * 200; const xOffset = Math.random() * 200;
const randomShip = Math.floor(Math.random() * enemyImgArray.length); const randomShip = Math.floor(Math.random() * enemyImgArray.length);
@ -1162,20 +1150,18 @@ function spawnEnemyFromWave(wave) {
let rawSpeed = 3.5 + Math.random() * 2 + game.level * 0.2; let rawSpeed = 3.5 + Math.random() * 2 + game.level * 0.2;
const speed = Math.min(rawSpeed, 8); const speed = Math.min(rawSpeed, 8);
// --- RANDOM MOVEMENT TYPE ---
// Setiap musuh melempar dadu sendiri untuk menentukan tipe gerakannya
// 30% kemungkinan gerak gelombang (sine), sisanya lurus.
let movementType = Math.random() < 0.3 ? "sine" : "straight"; let movementType = Math.random() < 0.3 ? "sine" : "straight";
let enemy = new EnemyObj( let enemy = new EnemyObj(
canvasWidth + 50 + xOffset, // X position + random offset canvasWidth + 50 + xOffset,
y, y,
speed, speed,
enemyImgArray[randomShip], enemyImgArray[randomShip],
movementType movementType
); );
// BALANCING HEALTH // ENEMY HEALTH
enemy.health = 60 + game.level * 10; enemy.health = 60 + game.level * 10;
enemyShipArray.push(enemy); enemyShipArray.push(enemy);
@ -1186,10 +1172,9 @@ class AbilityToken {
constructor(x, y) { constructor(x, y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.width = 40; // Ukuran sedikit diperbesar untuk gambar this.width = 40;
this.height = 40; this.height = 40;
this.speed = 4; this.speed = 4;
// 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";
else if (r < 0.66) this.type = "double"; else if (r < 0.66) this.type = "double";
@ -1199,7 +1184,6 @@ class AbilityToken {
draw() { draw() {
ctx.save(); ctx.save();
// --- GAYA METAL SLUG (KOTAK PUTIH TEBAL) UNTUK SEMUA TIPE PICKUP ---
ctx.strokeStyle = "#ffffff"; ctx.strokeStyle = "#ffffff";
ctx.lineWidth = 3; ctx.lineWidth = 3;
ctx.strokeRect(this.x, this.y, this.width, this.height); ctx.strokeRect(this.x, this.y, this.width, this.height);
@ -1212,7 +1196,6 @@ class AbilityToken {
} else if (this.type === "double") { } else if (this.type === "double") {
imgToDraw = laserPickupImg; imgToDraw = laserPickupImg;
} else if (this.type === "bomb") { } else if (this.type === "bomb") {
// GUNAKAN GAMBAR BOM PICKUP YANG BARU
imgToDraw = bombPickupImg; imgToDraw = bombPickupImg;
} }
@ -1436,14 +1419,12 @@ function drawScreenShading() {
} }
// --- BRIGHTNESS SURGE OVERLAY --- // --- BRIGHTNESS SURGE OVERLAY ---
// Use 'hard-light' or 'screen' to make dark backgrounds brighter
if (game.surge > 1.0) { if (game.surge > 1.0) {
let intensity = (game.surge - 1.0) / (7.0 - 1.0); // Normalized 0 to 1 let intensity = (game.surge - 1.0) / (7.0 - 1.0);
if (intensity > 0) { if (intensity > 0) {
ctx.save(); ctx.save();
ctx.globalCompositeOperation = "hard-light"; // Better for space haze ctx.globalCompositeOperation = "hard-light";
ctx.fillStyle = "white"; ctx.fillStyle = "white";
// Intensity 0.0 to 1.0 -> Alpha 0.0 to 0.4
ctx.globalAlpha = intensity * 0.4; ctx.globalAlpha = intensity * 0.4;
ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.restore(); ctx.restore();
@ -1452,9 +1433,9 @@ function drawScreenShading() {
} }
function updateSurge() { function updateSurge() {
const RAMP_UP_FRAMES = 240; // 4 seconds const RAMP_UP_FRAMES = 240;
const HOLD_FRAMES = 780; // 13 seconds const HOLD_FRAMES = 780;
const RAMP_DOWN_FRAMES = 300;// 5 seconds const RAMP_DOWN_FRAMES = 300;
const MAX_SURGE_SPEED = 7.0; const MAX_SURGE_SPEED = 7.0;
// Phase 0: Cooldown // Phase 0: Cooldown
@ -1726,16 +1707,12 @@ musicBtns.forEach(btn => {
btn.addEventListener('click', () => { btn.addEventListener('click', () => {
playSound(menuClickSound); playSound(menuClickSound);
// Remove active from all
musicBtns.forEach(b => b.classList.remove('active')); musicBtns.forEach(b => b.classList.remove('active'));
// Add active to clicked
btn.classList.add('active'); btn.classList.add('active');
// Update setting
gameSettings.musicEnabled = btn.dataset.music === 'on'; gameSettings.musicEnabled = btn.dataset.music === 'on';
// Apply immediately if in game
if (typeof currentBGM !== 'undefined') { if (typeof currentBGM !== 'undefined') {
if (gameSettings.musicEnabled) { if (gameSettings.musicEnabled) {
currentBGM.volume = 1; currentBGM.volume = 1;
@ -1755,13 +1732,10 @@ sfxBtns.forEach(btn => {
btn.addEventListener('click', () => { btn.addEventListener('click', () => {
playSound(menuClickSound); playSound(menuClickSound);
// Remove active from all
sfxBtns.forEach(b => b.classList.remove('active')); sfxBtns.forEach(b => b.classList.remove('active'));
// Add active to clicked
btn.classList.add('active'); btn.classList.add('active');
// Update setting
gameSettings.sfxEnabled = btn.dataset.sfx === 'on'; gameSettings.sfxEnabled = btn.dataset.sfx === 'on';
}); });
}); });
@ -1824,7 +1798,6 @@ document.addEventListener('keydown', (e) => {
// === MODIFY EXISTING GAME FUNCTIONS === // === MODIFY EXISTING GAME FUNCTIONS ===
// Override window.onload
window.onload = function () { window.onload = function () {
console.log('Game Ready - Waiting for menu start...'); console.log('Game Ready - Waiting for menu start...');
}; };