Ships Animation

This commit is contained in:
Bluwww 2025-12-08 14:33:36 +07:00
parent 38b82a1cb1
commit 9cb03ccf95
6 changed files with 232 additions and 176 deletions

408
Script.js
View File

@ -1,11 +1,9 @@
"use strict"; "use strict";
// BGM system
const bgmList = [ const bgmList = [
{ normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" }, { normal: "music/Scary.mp3", gameover: "music/ScaryGO.mp3" },
{ normal: "music/Fear.mp3", gameover: "music/FearGO.mp3" }, { normal: "music/Fear.mp3", gameover: "music/FearGO.mp3" },
{ normal: "music/Chill.mp3", gameover: "music/ChillGO.mp3" } { normal: "music/Chill.mp3", gameover: "music/ChillGO.mp3" },
]; ];
let currentBGM = new Audio(); let currentBGM = new Audio();
@ -14,9 +12,9 @@ currentBGM.loop = true;
gameOverBGM.loop = true; gameOverBGM.loop = true;
function pickRandomBGM() { function pickRandomBGM() {
const bgm = bgmList[Math.floor(Math.random() * bgmList.length)]; const bgm = bgmList[Math.floor(Math.random() * bgmList.length)];
currentBGM.src = bgm.normal; currentBGM.src = bgm.normal;
gameOverBGM.src = bgm.gameover; gameOverBGM.src = bgm.gameover;
} }
var canvasWidth = 1280; var canvasWidth = 1280;
@ -25,11 +23,9 @@ var c = undefined;
var ctx = undefined; var ctx = undefined;
var gameStarted = false; var gameStarted = false;
var musicMuted = false; var musicMuted = false;
/// 90 FPS (Cause I got motion sickness while playing our game fr)
let lastFrameTime = 0; let lastFrameTime = 0;
const frameInterval = 1000 / 80; // 90 FPS limit right now it's capped at 80 const frameInterval = 1000 / 80;
// 90 FPS mark (change the const x/x to what fps you want)
// Changing FPS actually makes the game slower ya or faster, tergantung(?)
var game = { var game = {
level: 1, level: 1,
@ -48,7 +44,7 @@ var keys = {
}; };
var playerShipImg = new Image(); var playerShipImg = new Image();
playerShipImg.src = "img/ships2.png"; playerShipImg.src = "img/Player/pesawat22.png";
var bg0 = new Image(); var bg0 = new Image();
bg0.src = "img/bg_0.png"; bg0.src = "img/bg_0.png";
@ -65,22 +61,18 @@ enemy1.src = "img/alien_0.png";
var enemyImgArray = []; var enemyImgArray = [];
enemyImgArray.length = 4; enemyImgArray.length = 4;
///Key listen
let audioStarted = false; let audioStarted = false;
window.addEventListener("keydown", () => { window.addEventListener("keydown", () => {
if (!audioStarted) { if (!audioStarted) {
currentBGM.play(); currentBGM.play();
audioStarted = true; audioStarted = true;
} }
}); });
//Stanley
for (var i = 0; i < enemyImgArray.length; i++) { for (var i = 0; i < enemyImgArray.length; i++) {
enemyImgArray[i] = new Image(); enemyImgArray[i] = new Image();
enemyImgArray[i].src = 'img/alien_' + [i] + '.png'; enemyImgArray[i].src = "img/alien_" + [i] + ".png";
} }
var missilesArray = []; var missilesArray = [];
@ -90,9 +82,9 @@ var laser = document.createElement("audio");
laser.src = "music/laser2.mp3"; laser.src = "music/laser2.mp3";
var explosion_enemy = document.createElement("audio"); var explosion_enemy = document.createElement("audio");
explosion_enemy.src = "music/explosion-small.mp3" explosion_enemy.src = "music/explosion-small.mp3";
var planetImages = []; var planetImages = [];
for (let i = 1; i <= 4; i++) { for (let i = 1; i <= 4; i++) {
let img = new Image(); let img = new Image();
img.src = `img/SpritesPlanet/planet_${i}.png`; img.src = `img/SpritesPlanet/planet_${i}.png`;
@ -110,54 +102,53 @@ function init() {
document.addEventListener("keydown", keyDownPressed, false); document.addEventListener("keydown", keyDownPressed, false);
document.addEventListener("keyup", keyUpPressed, false); document.addEventListener("keyup", keyUpPressed, false);
gameStarted = true; gameStarted = true;
//randomb bgm yg kita punya we have 3 songs///
pickRandomBGM(); pickRandomBGM();
currentBGM.volume = 1; currentBGM.volume = 1;
currentBGM.play(); currentBGM.play();
requestAnimationFrame(gameLoop); requestAnimationFrame(gameLoop);
} }
//Aku ganti function game loop that follows the 90FPS Cap rule
function gameLoop(timestamp) { function gameLoop(timestamp) {
if (!gameStarted) return; if (!gameStarted) return;
if (game.gameOver) { if (game.gameOver) {
drawGameOver(); drawGameOver();
return; return;
} }
if (timestamp - lastFrameTime >= frameInterval) { if (timestamp - lastFrameTime >= frameInterval) {
lastFrameTime = timestamp; lastFrameTime = timestamp;
clearGame(); clearGame();
updateGame(); updateGame();
drawGame(); drawGame();
} }
requestAnimationFrame(gameLoop); requestAnimationFrame(gameLoop);
} }
// End of 90fps mark
function keyDownPressed(e) { function keyDownPressed(e) {
if (e.keyCode == 87) { if (e.keyCode == 87 || e.keyCode == 38) {
keys.up = true; keys.up = true;
} else if (e.keyCode == 83) { } else if (e.keyCode == 83 || e.keyCode == 40) {
keys.down = true; keys.down = true;
} }
if (e.keyCode == 65) { if (e.keyCode == 65 || e.keyCode == 37) {
keys.left = true; keys.left = true;
} }
if (e.keyCode == 68) { if (e.keyCode == 68 || e.keyCode == 39) {
keys.right = true; keys.right = true;
} }
if (e.keyCode == 32) { if (e.keyCode == 32) {
keys.fire = true; keys.fire = true;
missilesArray.push(new LaserBullet(player1.x + 150, player1.y + 50)); missilesArray.push(
new LaserBullet(player1.x + player1.width, player1.y + player1.height / 2)
);
laser.currentTime = 0; laser.currentTime = 0;
laser.play(); laser.play();
@ -166,17 +157,17 @@ function keyDownPressed(e) {
} }
function keyUpPressed(e) { function keyUpPressed(e) {
if (e.keyCode == 87) { if (e.keyCode == 87 || e.keyCode == 38) {
keys.up = false; keys.up = false;
} else if (e.keyCode == 83) { } else if (e.keyCode == 83 || e.keyCode == 40) {
keys.down = false; keys.down = false;
} }
if (e.keyCode == 65) { if (e.keyCode == 65 || e.keyCode == 37) {
keys.left = false; keys.left = false;
} }
if (e.keyCode == 68) { if (e.keyCode == 68 || e.keyCode == 39) {
keys.right = false; keys.right = false;
} }
@ -203,125 +194,191 @@ function updateGame() {
} }
function drawGame() { function drawGame() {
if (currentPlanet) currentPlanet.draw(); if (currentPlanet) currentPlanet.draw();
player1.draw(); player1.draw();
for (var i = 0; i < enemyShipArray.length; i++) { for (var i = 0; i < enemyShipArray.length; i++) {
var s = enemyShipArray[i]; var s = enemyShipArray[i];
s.draw(); s.draw();
s.update(); s.update();
if (s.x < -200) { if (s.x < -200) {
enemyShipArray.splice(i, 1); enemyShipArray.splice(i, 1);
i--; i--;
continue; continue;
}
if (Tabrakan(player1, s)) {
if (player1.invincible <= 0) {
player1.lives--;
player1.invincible = 60;
//self note: change this later
explosion_enemy.play();
player1.x = 15;
player1.y = 300;
game.frames = 0;
enemyShipArray.splice(i, 1);
i--;
if (player1.lives <= 0) {
game.gameOver = true;
crossfadeToGameOver();
}
continue;
}
}
} }
for (var i = 0; i < missilesArray.length; i++) { if (Tabrakan(player1, s)) {
var m = missilesArray[i]; if (player1.invincible <= 0) {
m.draw(); player1.lives--;
m.update(); player1.invincible = 60;
explosion_enemy.play();
// --- POSISI RESPAWN TENGAH ---
// Menggunakan tinggi player yang sudah dihitung agar pas tengah
player1.x = 100;
player1.y = canvasHeight / 2 - player1.height / 2;
player1.vx = 0;
player1.vy = 0;
game.frames = 0;
enemyShipArray.splice(i, 1);
i--;
if (player1.lives <= 0) {
// Hit detecttion game.gameOver = true;
for (var j = 0; j < enemyShipArray.length; j++) { crossfadeToGameOver();
var en = enemyShipArray[j];
if (Tabrakan(m, en)) {
player1.score += 100;
explosion_enemy.play();
missilesArray.splice(i, 1);
enemyShipArray.splice(j, 1);
}
}
//Hits end
if (m.x > canvasWidth) {
missilesArray.splice(i, 1);
i--;
} }
continue;
}
}
}
for (var i = 0; i < missilesArray.length; i++) {
var m = missilesArray[i];
m.draw();
m.update();
for (var j = 0; j < enemyShipArray.length; j++) {
var en = enemyShipArray[j];
if (Tabrakan(m, en)) {
player1.score += 100;
explosion_enemy.play();
missilesArray.splice(i, 1);
enemyShipArray.splice(j, 1);
}
} }
drawNewText("Score: " + player1.score, 30, 610, "white"); if (m.x > canvasWidth) {
drawNewText("Player Lives: " + player1.lives, 1100, 610, "white"); missilesArray.splice(i, 1);
i--;
}
}
drawNewText("Score: " + player1.score, 30, 610, "white");
drawNewText("Player Lives: " + player1.lives, 1100, 610, "white");
} }
class PlayerObject { class PlayerObject {
constructor(x, y) { constructor(x, y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.width = 170; this.width = 100;
this.height = 105; this.height = 64;
this.image = playerShipImg; this.image = playerShipImg;
this.speed = 8;
this.vx = 0;
this.vy = 0;
this.acceleration = 0.8;
this.friction = 0.92;
this.maxSpeed = 10;
this.lives = 3; this.lives = 3;
this.score = 0; this.score = 0;
this.health = 100; this.health = 100;
this.invincible = 0; this.invincible = 0;
this.totalFrames = 5;
this.frameIndex = 2;
this.spriteWidth = 0;
this.sourceHeight = 0;
this.scale = 1.3;
this.image.onload = () => {
this.spriteWidth = this.image.width / this.totalFrames;
this.sourceHeight = this.image.height;
this.width = this.spriteWidth * this.scale;
this.height = this.sourceHeight * this.scale;
this.y = canvasHeight / 2 - this.height / 2;
};
} }
draw() { draw() {
ctx.save(); ctx.save();
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
if (this.invincible > 0 && this.invincible % 4 < 2) {
ctx.globalAlpha = 0.5;
}
if (this.spriteWidth > 0) {
ctx.drawImage(
this.image,
this.frameIndex * this.spriteWidth,
0,
this.spriteWidth,
this.sourceHeight,
this.x,
this.y,
this.width,
this.height
);
} else {
ctx.fillStyle = "red";
ctx.fillRect(this.x, this.y, 50, 50);
}
ctx.restore(); ctx.restore();
} }
update() { update() {
if (keys.up) { if (keys.up) {
if (this.y > 0) { this.vy -= this.acceleration;
this.y -= this.speed;
}
} else if (keys.down) {
if (this.x < canvasWidth - this.width) {
this.y += this.speed;
}
} }
if (keys.down) {
if (keys.right) { this.vy += this.acceleration;
if (this.x < canvasWidth - this.width) {
this.x += this.speed;
}
} }
if (keys.left) { if (keys.left) {
if (this.x > 10) { this.vx -= this.acceleration;
this.x -= this.speed; }
} if (keys.right) {
this.vx += this.acceleration;
}
this.vx *= this.friction;
this.vy *= this.friction;
this.x += this.vx;
this.y += this.vy;
const bleedY = this.height * 0.4;
const bleedX = this.width * 0.4;
if (this.y < -bleedY) {
this.y = -bleedY;
if (this.vy < 0) this.vy = 0;
}
if (this.y > canvasHeight - this.height + bleedY) {
this.y = canvasHeight - this.height + bleedY;
if (this.vy > 0) this.vy = 0;
}
if (this.x < -bleedX) {
this.x = -bleedX;
if (this.vx < 0) this.vx = 0;
}
if (this.x > canvasWidth - this.width + bleedX) {
this.x = canvasWidth - this.width + bleedX;
if (this.vx > 0) this.vx = 0;
}
if (this.vy < -2.5) {
this.frameIndex = 4;
} else if (this.vy < -0.5) {
this.frameIndex = 3;
} else if (this.vy > 2.5) {
this.frameIndex = 0;
} else if (this.vy > 0.5) {
this.frameIndex = 1;
} else {
this.frameIndex = 2;
} }
} }
} }
let player1 = new PlayerObject(100, 100); // Inisialisasi awal (Posisi Y akan di-override otomatis saat gambar load)
let player1 = new PlayerObject(100, 300);
function drawNewText(txt, x, y, color) { function drawNewText(txt, x, y, color) {
ctx.font = "20px Arial"; ctx.font = "20px Arial";
@ -447,7 +504,7 @@ class Planet {
draw() { draw() {
ctx.drawImage(this.image, this.x, this.y, this.width, this.height); ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
} }
update() { update() {
this.x -= this.speed; this.x -= this.speed;
@ -468,61 +525,60 @@ function spawnPlanet() {
} }
function addShips() { function addShips() {
if (game.frames > 200) { if (game.frames > 200) {
if (game.frames % 150 == 0) {
if (game.frames % 150 == 0) { var randomY = Math.floor(Math.random() * 500) + 20;
var randomY = Math.floor(Math.random() * 500) + 20; var randomSpeed = Math.floor(Math.random() * 10) + 1;
var randomSpeed = Math.floor(Math.random() * 10) + 1; var randomShip = Math.floor(Math.random() * enemyImgArray.length);
var randomShip = Math.floor(Math.random() * enemyImgArray.length); enemyShipArray.push(
enemyShipArray.push(new EnemyObj(1300, randomY, randomSpeed, enemyImgArray[randomShip])); new EnemyObj(1300, randomY, randomSpeed, enemyImgArray[randomShip])
} );
} }
}
} }
function Tabrakan(o, p){ function Tabrakan(o, p) {
if (o.x + o.width > p.x && if (
o.x < p.x + p.width && o.x + o.width > p.x &&
o.y + o.height > p.y && o.x < p.x + p.width &&
o.y < p.y + p.height) { o.y + o.height > p.y &&
return true; o.y < p.y + p.height
} ) {
return false; return true;
}
return false;
} }
function drawGameOver() { function drawGameOver() {
ctx.fillStyle = "rgba(0,0,0,0.7)"; ctx.fillStyle = "rgba(0,0,0,0.7)";
ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.font = "80px Arial"; ctx.font = "80px Arial";
ctx.fillStyle = "red"; ctx.fillStyle = "red";
ctx.textAlign = "center"; ctx.textAlign = "center";
ctx.fillText("GAME OVER", canvasWidth / 2, canvasHeight / 2 - 50); ctx.fillText("GAME OVER", canvasWidth / 2, canvasHeight / 2 - 50);
ctx.font = "40px Arial"; ctx.font = "40px Arial";
ctx.fillStyle = "white"; ctx.fillStyle = "white";
ctx.fillText("Refresh to Restart", canvasWidth / 2, canvasHeight / 2 + 30); ctx.fillText("Refresh to Restart", canvasWidth / 2, canvasHeight / 2 + 30);
} }
function crossfadeToGameOver() { function crossfadeToGameOver() {
let fadeSpeed = 0.02; let fadeSpeed = 0.02;
gameOverBGM.volume = 0; gameOverBGM.volume = 0;
gameOverBGM.play(); gameOverBGM.play();
let fadeInterval = setInterval(() => { let fadeInterval = setInterval(() => {
currentBGM.volume -= fadeSpeed;
if (currentBGM.volume < 0) currentBGM.volume = 0;
currentBGM.volume -= fadeSpeed; gameOverBGM.volume += fadeSpeed;
if (currentBGM.volume < 0) currentBGM.volume = 0; if (gameOverBGM.volume > 1) gameOverBGM.volume = 1;
gameOverBGM.volume += fadeSpeed; if (currentBGM.volume === 0) {
if (gameOverBGM.volume > 1) gameOverBGM.volume = 1; currentBGM.pause();
clearInterval(fadeInterval);
if (currentBGM.volume === 0) { }
currentBGM.pause(); }, 1000 / 30);
clearInterval(fadeInterval);
}
}, 1000 / 30);
} }

BIN
img/Player/pesawat2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
img/Player/pesawat22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

BIN
img/ships3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB