/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { playerDeaths: 0, monsterDeaths: 0 }); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemy2_horn', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.update = function () { self.x -= self.speed; if (self.speed < 0) { self.rotation += 0.1; // Add spinning effect // Check collision with enemies for (var i = 0; i < enemyContainer.children.length; i++) { var enemy = enemyContainer.children[i]; if (self.intersects(enemy.bodyCollider)) { enemy.sendEvent(GameEvents.BULLET_HIT, self); } } } if (self.x < 0) { self.destroy(); } else if (self.x > 2048 + 200) { self.destroy(); } }; }); var Enemy = Container.expand(function () { var self = Container.call(this); self.images = { "dead": LK.getAsset('enemy1_dead', { anchorX: 0.5, anchorY: 0.5 }), "walk1": LK.getAsset('enemy1_walk1', { anchorX: 0.5, anchorY: 0.5 }), "walk2": LK.getAsset('enemy1_walk2', { anchorX: 0.5, anchorY: 0.5 }), "horns": LK.getAsset('enemy1_horns', { anchorX: 0.5, anchorY: 0.5 }) }; //replacing the asset ref with the image added. for (var img_name in self.images) { var img = self.addChild(self.images[img_name]); img.visible = false; self.images[img_name] = img; } //configure the animation frames. self.anims = { 'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300), 'dead': new FrameAnimation([self.images.dead], 100) }; var enemyGraphics = { height: 300, width: 300 }; // Add a red rectangle to the enemy's head self.headCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 100 }); self.headCollider.y = -enemyGraphics.height / 4; // Position the rectangle on the enemy's head self.headCollider.alpha = 0; // Add a bodyCollider rectangle to the bottom part of the enemy self.bodyCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, color: 0xffff00 }); self.bodyCollider.y = enemyGraphics.height / 4; // Position the rectangle on the enemy's body self.bodyCollider.alpha = 0; self.speed = 5; self.state; self.removeFromArray = false; self.states = { moving: { onEnter: function onEnter() { console.log('Enemy starts moving'); self.anims['walk'].play(); }, onUpdate: function onUpdate() { self.x -= self.speed; }, onExit: function onExit() { console.log('Enemy stops moving'); self.anims['walk'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in moving state: ', event, data); if (event === GameEvents.COLLISION_ENEMY_HEAD) { if (self.hasHorns() == false) { self.setState('dead'); } } else if (event === GameEvents.BULLET_HIT) { self.setState('dead'); } } }, dead: { onEnter: function onEnter() { console.log('Enemy has died'); LK.getSound('bounce').play(); monsterDeaths++; tween(monsterDeathsText.scale, { x: 1.5, y: 1.5 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(monsterDeathsText.scale, { x: 1, y: 1 }, { duration: 100, easing: tween.easeIn }); } }); storage.monsterDeaths = monsterDeaths; onEnemyDeath(self); self.anims['dead'].play(); self.speed = 0; var y_val = self.y - Math.random() * 150; var x_val = self.x + 100 + Math.random() * 200; tween(self, { x: x_val, y: y_val, rotation: Math.PI / 6 // 30 degrees in radians }, { duration: 250, easing: tween.expoOut, onFinish: function onFinish() { tween(self, { y: 2732 + 300 }, { duration: 500, easing: tween.expoIn, onFinish: function onFinish() { self.removeFromArray = true; } }); } }); }, onUpdate: function onUpdate() {}, onExit: function onExit() { console.log('Exiting dead state'); }, onEvent: function onEvent(event, data) { console.log('Event received in dead state: ', event, data); } } }; self.setState = function (state) { if (self.state) { self.states[self.state].onExit(); } self.state = state; self.states[self.state].onEnter(); }; self.sendEvent = function (event, data) { if (self.state) { self.states[self.state].onEvent(event, data); } }; self.update = function () { self.states[self.state].onUpdate(); }; self.setState('moving'); // Function to check if the enemy has visible horns self.hasHorns = function () { return self.images['horns'] && self.images['horns'].visible; }; }); var Enemy2 = Container.expand(function () { var self = Container.call(this); self.images = { "dead": LK.getAsset('enemy2_dead', { anchorX: 0.5, anchorY: 0.5 }), "walk1": LK.getAsset('enemy2_walk1', { anchorX: 0.5, anchorY: 0.5 }), "walk2": LK.getAsset('enemy2_walk2', { anchorX: 0.5, anchorY: 0.5 }), "attack1": LK.getAsset('enemy2_attack1', { anchorX: 0.5, anchorY: 0.5 }), "attack2": LK.getAsset('enemy2_attack2', { anchorX: 0.5, anchorY: 0.5 }), "horn": LK.getAsset('enemy2_horn', { anchorX: 0.5, anchorY: 0.5 }), "idle1": LK.getAsset('enemy2_idle1', { anchorX: 0.5, anchorY: 0.5 }), "idle2": LK.getAsset('enemy2_idle2', { anchorX: 0.5, anchorY: 0.5 }) }; for (var img_name in self.images) { var img = self.addChild(self.images[img_name]); img.visible = false; self.images[img_name] = img; } self.anims = { 'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300), 'dead': new FrameAnimation([self.images.dead], 100), 'idle': new FrameAnimation([self.images.idle1, self.images.idle2], 300), // New idle animation 'attack': new FrameAnimation([self.images.attack1, self.images.attack2], 300) // New attack animation }; var enemyGraphics = { height: 300, width: 300 }; self.headCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 100 }); self.headCollider.y = -enemyGraphics.height / 4; self.headCollider.alpha = 0; self.bodyCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, color: 0xffff00 }); self.bodyCollider.y = enemyGraphics.height / 4; self.bodyCollider.alpha = 0; self.speed = 5; self.state; self.removeFromArray = false; self.states = { moving: { onEnter: function onEnter() { console.log('Enemy2 starts moving'); self.anims['walk'].play(); }, onUpdate: function onUpdate() { self.x -= self.speed; // Transition to attack state when reaching 2/3rd of the screen if (self.lastX > 2048 * (2 / 3) && self.x <= 2048 * (2 / 3)) { self.setState('attack'); } self.lastX = self.x; }, onExit: function onExit() { console.log('Enemy2 stops moving'); self.anims['walk'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in moving state: ', event, data); if (event === GameEvents.COLLISION_ENEMY_HEAD) { self.setState('dead'); } } }, attack: { // New attack state onEnter: function onEnter() { console.log('Enemy2 starts attacking'); self.anims['idle'].play(); // Play idle animation self.attackTimer = 500; // Set attack timer }, onUpdate: function onUpdate() { if (self.attackTimer > 0) { self.attackTimer--; // Decrease attack timer } else { self.anims['idle'].stop(); // Stop idle animation self.anims['attack'].play(); // Play attack animation LK.getSound('roar').play(); self.attackTimer = 1000; } }, onExit: function onExit() { console.log('Enemy2 stops attacking'); self.anims['idle'].stop(); self.anims['attack'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in attack state: ', event, data); if (event === GameEvents.ANIM_FINISHED && data == self.anims['attack']) { // Shoot a bullet at the player using enemy_horn image var bullet = new Bullet(self.images.horn); bullet.x = self.x; bullet.y = self.y; bulletContainer.addChild(bullet); self.anims['attack'].stop(); self.anims['idle'].play(); self.attackTimer = 500; } else if (event === GameEvents.COLLISION_ENEMY_HEAD) { self.setState('dead'); } else if (event === GameEvents.BULLET_HIT) { self.setState('dead'); } } }, // End of new attack state dead: { onEnter: function onEnter() { console.log('Enemy2 has died'); LK.getSound('bounce').play(); monsterDeaths++; storage.monsterDeaths = monsterDeaths; onEnemyDeath(self); self.anims['dead'].play(); self.speed = 0; var y_val = self.y - Math.random() * 150; var x_val = self.x + 100 + Math.random() * 200; tween(self, { x: x_val, y: y_val, rotation: Math.PI / 6 }, { duration: 250, easing: tween.expoOut, onFinish: function onFinish() { tween(self, { y: 2732 + 300 }, { duration: 500, easing: tween.expoIn, onFinish: function onFinish() { self.removeFromArray = true; } }); } }); }, onUpdate: function onUpdate() {}, onExit: function onExit() { console.log('Exiting dead state'); }, onEvent: function onEvent(event, data) { console.log('Event received in dead state: ', event, data); } } }; self.setState = function (state) { if (self.state) { self.states[self.state].onExit(); } self.state = state; self.states[self.state].onEnter(); }; self.sendEvent = function (event, data) { if (self.state) { self.states[self.state].onEvent(event, data); } }; self.update = function () { self.states[self.state].onUpdate(); }; self.setState('moving'); // Function to check if the enemy has visible horns self.hasHorns = function () { return self.images['horn'] && self.images['horn'].visible; }; }); var Enemy4 = Container.expand(function () { var self = Container.call(this); self.images = { "dead": LK.getAsset('enemy4_dead', { anchorX: 0.5, anchorY: 0.5 }), "idle1": LK.getAsset('enemy4_idle1', { anchorX: 0.5, anchorY: 0.5 }), "idle2": LK.getAsset('enemy4_idle2', { anchorX: 0.5, anchorY: 0.5 }), "horns": LK.getAsset('enemy1_horns', { anchorX: 0.5, anchorY: 0.5 }) }; for (var img_name in self.images) { var img = self.addChild(self.images[img_name]); img.visible = false; self.images[img_name] = img; } self.anims = { 'walk': new FrameAnimation([self.images.idle1, self.images.idle2], 300), 'dead': new FrameAnimation([self.images.dead], 100) }; var enemyGraphics = { height: 300, width: 300 }; self.headCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 120, height: 100, x: -200, y: 150 - 50 }); self.headCollider.alpha = 0; self.bodyCollider = self.attachAsset('enemyRectangle', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 200, x: 0 }); self.bodyCollider.y = enemyGraphics.height / 4; self.bodyCollider.alpha = 0; self.speed = 8; self.state; self.removeFromArray = false; self.states = { moving: { onEnter: function onEnter() { console.log('Enemy4 starts moving'); self.anims['walk'].play(); }, onUpdate: function onUpdate() { self.x -= self.speed; if (self.x < -500) { self.setState('dead'); } }, onExit: function onExit() { console.log('Enemy4 stops moving'); self.anims['walk'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in moving state: ', event, data); if (event === GameEvents.COLLISION_ENEMY_HEAD) { data.setState('dead'); } else if (event === GameEvents.BULLET_HIT) { // Do nothing for Enemy4 when hit by a bullet } else if (event == GameEvents.COLLISION_PLAYER_BODY) { self.setState('dead'); } } }, dead: { onEnter: function onEnter() { console.log('Enemy4 has died'); LK.getSound('bounce').play(); monsterDeaths++; storage.monsterDeaths = monsterDeaths; onEnemyDeath(self); self.anims['dead'].play(); self.speed = 0; var y_val = self.y - Math.random() * 150; var x_val = self.x + 100 + Math.random() * 200; tween(self, { x: x_val, y: y_val, rotation: Math.PI / 6 }, { duration: 250, easing: tween.expoOut, onFinish: function onFinish() { tween(self, { y: 2732 + 300 }, { duration: 500, easing: tween.expoIn, onFinish: function onFinish() { self.removeFromArray = true; } }); } }); }, onUpdate: function onUpdate() {}, onExit: function onExit() { console.log('Exiting dead state'); }, onEvent: function onEvent(event, data) { console.log('Event received in dead state: ', event, data); } } }; self.setState = function (state) { if (self.state) { self.states[self.state].onExit(); } self.state = state; self.states[self.state].onEnter(); }; self.sendEvent = function (event, data) { if (self.state) { self.states[self.state].onEvent(event, data); } }; self.update = function () { self.states[self.state].onUpdate(); }; self.setState('moving'); self.hasHorns = function () { return true; }; }); //<Assets used in the game will automatically appear here> // Define a class for the player character var Player = Container.expand(function () { var self = Container.call(this); self.images = { "idle": LK.getAsset('player', { anchorX: 0.5, anchorY: 0.5 }), "jump": LK.getAsset('player_jump', { anchorX: 0.5, anchorY: 0.5 }), "walk1": LK.getAsset('walk_1', { anchorX: 0.5, anchorY: 0.5 }), "walk2": LK.getAsset('walk_2', { anchorX: 0.5, anchorY: 0.5 }), 'dead': LK.getAsset('player_dead', { anchorX: 0.5, anchorY: 0.5 }), 'attack1': LK.getAsset('player_attack1', { anchorX: 0.5, anchorY: 0.5 }), 'attack2': LK.getAsset('player_attack2', { anchorX: 0.5, anchorY: 0.5 }) }; self.speed = 5; self.jumpHeight = 40; self.isJumping = false; self.velocityY = 0; self.state; //replacing the asset ref with the image added. for (var img_name in self.images) { var img = self.addChild(self.images[img_name]); img.visible = false; self.images[img_name] = img; } // Add a bodyCollider rectangle to the player character self.bodyCollider = self.attachAsset('collider', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, color: 0xffff00, // Yellow color alpha: 0 }); self.bodyCollider.y = self.images.idle.height / 4; // Position the rectangle on the player's body //configure the animation frames. self.anims = { 'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300), 'jump': new FrameAnimation([self.images.jump], 100), 'idle': [self.images.idle], 'dead': new FrameAnimation([self.images.dead], 100), 'attack': new FrameAnimation([self.images.jump, self.images.attack1, self.images.attack2, self.images.idle], 200) }; self.states = { idle: { onEnter: function onEnter() { console.log('Entering idle state'); self.anims['walk'].play(); }, onUpdate: function onUpdate() {}, onExit: function onExit() { console.log('Exiting idle state'); self.anims['walk'].stop(); }, onEvent: function onEvent(event, data) { if (event === GameEvents.COLLISION_ENEMY_BODY) { if (data instanceof Enemy4) { //do nothing. } else { self.setState('dead'); } } else if (event === GameEvents.BULLET_HIT) { self.setState('dead'); } } }, dead: { onEnter: function onEnter() { console.log('Player has died'); LK.getSound('player_hit').play(); playerDeaths++; storage.playerDeaths = playerDeaths; playerDeathsText.setText('' + playerDeaths); tween(playerDeathsText.scale, { x: 1.5, y: 1.5 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playerDeathsText.scale, { x: 1, y: 1 }, { duration: 100, easing: tween.easeIn }); } }); tween(self, { y: self.y - 400, rotation: -Math.PI / 6 // 30 degrees in radians }, { duration: 250, easing: tween.expoOut, onFinish: function onFinish() { tween(self, { y: 2732 + 300 }, { duration: 1000, easing: tween.expoIn, onFinish: function onFinish() { LK.showGameOver(); } }); } }); // Stop all enemies from moving for (var j = 0; j < enemies.length; j++) { enemies[j].speed = 0; } self.anims['dead'].play(); // Additional logic for death state can be added here }, onUpdate: function onUpdate() {}, onExit: function onExit() { console.log('Exiting death state'); }, onEvent: function onEvent(event, data) { console.log('Event received in death state: ', event, data); } }, attack: { onEnter: function onEnter() { console.log('Player is attacking'); LK.getSound('punch_swing').play(); self.anims['attack'].play(); }, onUpdate: function onUpdate() { // Attack logic can be added here }, onExit: function onExit() { console.log('Exiting attack state'); self.anims['attack'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in attack state: ', event, data); if (event === GameEvents.ANIM_FINISHED) { self.setState('idle'); } else if (event === GameEvents.COLLISION_ENEMY_HEAD) { if (data.hasHorns()) { self.setState('dead'); } else { data.setState('dead'); } } else if (event === GameEvents.COLLISION_ENEMY_BODY) { LK.getSound('punch').play(); data.setState('dead'); } else if (event === GameEvents.BULLET_HIT) { if (data.speed > 0) { data.speed = -data.speed; LK.getSound('punch').play(); } // Reverse bullet direction } } }, jumping: { onEnter: function onEnter() { if (!self.isJumping) { LK.getSound('jump').play(); self.isJumping = true; self.velocityY = -self.jumpHeight; self.anims['jump'].play(); console.log("jump Started"); } }, onUpdate: function onUpdate() { if (self.isJumping) { self.y += self.velocityY; self.velocityY += 1.4; // Increase gravity effect to make descent twice as fast if (self.y >= 2732 / 2) { // Ground level self.y = 2732 / 2; self.isJumping = false; self.velocityY = 0; self.setState('idle'); } } }, onExit: function onExit() { console.log('Exiting jumping state'); self.anims['jump'].stop(); }, onEvent: function onEvent(event, data) { console.log('Event received in jumping state: ', event, data); if (event === GameEvents.COLLISION_ENEMY_HEAD) { if (data.hasHorns()) { self.setState('dead'); } else { // Add upward velocity to player player.velocityY = -player.jumpHeight / 2; player.isJumping = true; LK.getSound('bounce').play(); } } else if (event === GameEvents.COLLISION_ENEMY_BODY) { if (data instanceof Enemy4) { // Add upward velocity to player player.velocityY = -player.jumpHeight / 2; player.isJumping = true; LK.getSound('bounce').play(); } else { self.setState('dead'); } } else if (event === GameEvents.BULLET_HIT) { self.setState('dead'); } } } }; self.setState = function (state) { if (self.state) { self.states[self.state].onExit(); } self.state = state; self.states[self.state].onEnter(); }; self.sendEvent = function (event, data) { if (self.state) { self.states[self.state].onEvent(event, data); } }; self.update = function () { self.states[self.state].onUpdate(); }; self.attack = function () { if (self.state !== 'jumping' && self.state !== 'dead') { self.setState('attack'); } }; self.jump = function () { if (self.state !== 'jumping' && self.state !== 'dead') { self.setState('jumping'); } }; //call the initial state. self.setState('idle'); }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ function onEnemyDeath(enemy) { LK.setScore(LK.getScore() + 1); scoreText.setText(LK.getScore()); // Increment the count of enemies killed by the player enemiesKilledByPlayer++; monsterDeathsText.setText('' + monsterDeaths); // Check if the score is 8 or above and 5 enemies have been killed if (LK.getScore() >= 8 && enemiesKilledByPlayer % 5 === 0) { // Spawn Enemy4 var enemy4 = new Enemy4(); enemy4.x = 2048; enemy4.y = 2732 / 2; enemies.push(enemy4); enemyContainer.addChild(enemy4); } } LK.playMusic('platformer_music'); // Start playing background music var GameEvents = { COLLISION_ENEMY_HEAD: 0, COLLISION_ENEMY_BODY: 1, COLLISION_PLAYER_BODY: 2, ANIM_FINISHED: 3, BULLET_HIT: 4 // New event for when player is hit by enemy bullet }; // Initialize death counters from storage var playerDeaths = storage.playerDeaths; var monsterDeaths = storage.monsterDeaths; // Track the number of enemies killed by the player var enemiesKilledByPlayer = 0; // Define a class for frame animations var FrameAnimation = function FrameAnimation(assets, frameRate) { var self = this; self.assets = assets; self.frameRate = frameRate; self.currentFrame = 0; self.isPlaying = false; self.interval = null; // Function to show the current frame self.showFrame = function () { for (var i = 0; i < self.assets.length; i++) { self.assets[i].visible = false; } self.assets[self.currentFrame].visible = true; }; // Play the animation self.play = function () { if (!self.isPlaying) { self.isPlaying = true; self.showFrame(); if (self.assets.length > 1) { self.interval = LK.setInterval(function () { self.currentFrame = (self.currentFrame + 1) % self.assets.length; self.showFrame(); if (self.currentFrame === 0) { // Send ANIM_FINISHED event when animation completes a cycle self.assets[0].parent.sendEvent(GameEvents.ANIM_FINISHED, self); } }, self.frameRate); } } }; // Pause the animation self.pause = function () { if (self.isPlaying) { clearInterval(self.interval); self.isPlaying = false; } }; // Resume the animation self.resume = function () { if (!self.isPlaying) { self.play(); } }; // Stop the animation self.stop = function () { LK.clearInterval(self.interval); self.isPlaying = false; self.currentFrame = 0; for (var i = 0; i < self.assets.length; i++) { self.assets[i].visible = false; } }; }; var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 })); background.x = 2048 / 2; background.y = 2732 / 2 - 550; // Initialize player var player = game.addChild(new Player()); player.x = 150; // Position player on the left side of the screen player.y = 2732 / 2; // Initialize enemy container var enemyContainer = new Container(); game.addChild(enemyContainer); // Initialize enemies array var enemies = []; // Initialize bullet container var bulletContainer = new Container(); game.addChild(bulletContainer); var enemySpawnInterval = 100; var enemySpawnCounter = 0; // Create a new Text2 object to display the score var scoreText = new Text2('0', { size: 100, fill: 0xFFFFFF }); // Create a GUI container var guiContainer = new Container(); game.addChild(guiContainer); // Add the score text to the GUI container at the top center of the screen guiContainer.addChild(scoreText); scoreText.x = 2048 / 2; scoreText.y = 20; // Adjusted to align with other top elements scoreText.anchor.set(0.5, 0); // Center the score text horizontally // Add a jump button to the bottom of the screen in the GUI container var jumpButton = LK.getAsset('jump_button', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 400 }); jumpButton.x = 2048 / 4; jumpButton.y = 2732 - jumpButton.height / 2 - 300; guiContainer.addChild(jumpButton); // Add an attack button to the bottom of the screen in the GUI container var attackButton = LK.getAsset('attack_button', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 400 }); attackButton.x = 3 * 2048 / 4; attackButton.y = 2732 - attackButton.height / 2 - 300; guiContainer.addChild(attackButton); // Add event listeners to flash buttons black on mouse or touch down jumpButton.down = function (x, y, obj) { LK.effects.flashObject(jumpButton, 0x000000, 500); player.jump(); }; attackButton.down = function (x, y, obj) { LK.effects.flashObject(attackButton, 0x000000, 500); player.attack(); }; // Add a music button to the top right corner of the screen var musicButton = LK.getAsset('music_on', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 200 }); musicButton.x = 2048 - musicButton.width / 2 - 50; // Position it at the top right corner musicButton.y = musicButton.height / 2 + 50; guiContainer.addChild(musicButton); music_off = LK.getAsset('music_off', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 200, x: musicButton.x, y: musicButton.y, visible: false }); guiContainer.addChild(music_off); // Add event listener to toggle music on button press var isMusicPlaying = true; // Initialize music state musicButton.down = function (x, y, obj) { LK.effects.flashObject(musicButton, 0x000000, 500); LK.effects.flashObject(music_off, 0x000000, 500); if (isMusicPlaying) { LK.stopMusic(); // Stop playing background music music_off.visible = true; } else { LK.playMusic('platformer_music'); // Start playing background music music_off.visible = false; } isMusicPlaying = !isMusicPlaying; // Toggle music state }; // Add the score_display image to the GUI container at the top center of the screen var scoreDisplayImage = LK.getAsset('score_display', { anchorX: 0.5, anchorY: 0.0 }); scoreDisplayImage.x = 2048 / 2; scoreDisplayImage.y = 0; // Align to the top of the screen guiContainer.addChild(scoreDisplayImage); // Create Text2 objects to display player and monster deaths var playerDeathsText = new Text2('' + playerDeaths, { size: 72, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0.5, font: "VAG Rounded" // More rounded and thick font }); var monsterDeathsText = new Text2('' + monsterDeaths, { size: 72, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0.5, font: "VAG Rounded" // More rounded and thick font }); // Position the death counters at the top of the screen playerDeathsText.x = scoreDisplayImage.x + 150; playerDeathsText.y = 190; monsterDeathsText.x = scoreDisplayImage.x - 280; monsterDeathsText.y = 190; // Add the death counters to the GUI container guiContainer.addChild(playerDeathsText); guiContainer.addChild(monsterDeathsText); function addEnemy2(game, enemies) { enemy = new Enemy2(); enemy.x = 2048; enemy.y = 2732 / 2; enemies.push(enemy); enemyContainer.addChild(enemy); } // Handle game updates game.update = function () { player.update(); // Spawn enemies if (player.state !== 'dead') { enemySpawnCounter++; if (enemySpawnCounter >= enemySpawnInterval) { //get if enemy2 is on the map. var enemy2Exists = enemies.some(function (e) { return e instanceof Enemy2; }); var enemy; var playerScore = LK.getScore(); if (!enemy2Exists && playerScore > 10 && Math.random() < 0.4) { enemy = new Enemy4(); enemy.x = 2048; enemy.y = 2732 / 2; enemies.push(enemy); enemyContainer.addChild(enemy); } else { enemy = new Enemy(); enemy.x = 2048; enemy.y = 2732 / 2; enemies.push(enemy); enemyContainer.addChild(enemy); if (playerScore > 3 && Math.random() < 0.4) { enemy.images['horns'].visible = true; } } if (!enemy2Exists && playerScore >= 5) { addEnemy2(game, enemies); } // Randomize the spawn interval for the next enemy enemySpawnInterval = Math.floor(Math.random() * 150) + 50; enemySpawnCounter = 0; } } // Check collision between player bodyCollider and bullets for (var k = bulletContainer.children.length - 1; k >= 0; k--) { var bullet = bulletContainer.children[k]; if (bullet.intersects(player.bodyCollider)) { // Send BULLET_HIT event to player player.sendEvent(GameEvents.BULLET_HIT, bullet); // bullet.destroy(); // bulletContainer.removeChild(bullet); } } // Update enemies for (var j = enemies.length - 1; j >= 0; j--) { enemies[j].update(); // Skip collision checks if player is in the dead state if (player.state === 'dead') { continue; } //remove the enemies marked for removal. if (enemies[j].removeFromArray == true) { enemies[j].destroy(); enemies.splice(j, 1); continue; } //skip collisions if enemy is dead. if (enemies[j].state === 'dead') { continue; } // Check collision between player bodyCollider and enemy headCollider if (player.bodyCollider.intersects(enemies[j].headCollider)) { onEnemyDeath(enemies[j]); // Call onEnemyDeath function // Send COLLISION_ENEMY_HEAD event to player player.sendEvent(GameEvents.COLLISION_ENEMY_HEAD, enemies[j]); enemies[j].sendEvent(GameEvents.COLLISION_ENEMY_HEAD, player); continue; } // Check collision between enemy bodyCollider and player bodyCollider if (enemies[j].bodyCollider.intersects(player.bodyCollider)) { // Send COLLISION_ENEMY_BODY event to player player.sendEvent(GameEvents.COLLISION_ENEMY_BODY, enemies[j]); enemies[j].sendEvent(GameEvents.COLLISION_PLAYER_BODY, player); return; } } }; // Handle player jump game.down = function (x, y, obj) { if (y > 2732 / 2 && x < 2048 / 2) { // Check if click is on the left half player.jump(); } else if (y > 2732 / 2) { // Otherwise, it's on the right half player.attack(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
playerDeaths: 0,
monsterDeaths: 0
});
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemy2_horn', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.update = function () {
self.x -= self.speed;
if (self.speed < 0) {
self.rotation += 0.1; // Add spinning effect
// Check collision with enemies
for (var i = 0; i < enemyContainer.children.length; i++) {
var enemy = enemyContainer.children[i];
if (self.intersects(enemy.bodyCollider)) {
enemy.sendEvent(GameEvents.BULLET_HIT, self);
}
}
}
if (self.x < 0) {
self.destroy();
} else if (self.x > 2048 + 200) {
self.destroy();
}
};
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.images = {
"dead": LK.getAsset('enemy1_dead', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk1": LK.getAsset('enemy1_walk1', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk2": LK.getAsset('enemy1_walk2', {
anchorX: 0.5,
anchorY: 0.5
}),
"horns": LK.getAsset('enemy1_horns', {
anchorX: 0.5,
anchorY: 0.5
})
};
//replacing the asset ref with the image added.
for (var img_name in self.images) {
var img = self.addChild(self.images[img_name]);
img.visible = false;
self.images[img_name] = img;
}
//configure the animation frames.
self.anims = {
'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300),
'dead': new FrameAnimation([self.images.dead], 100)
};
var enemyGraphics = {
height: 300,
width: 300
};
// Add a red rectangle to the enemy's head
self.headCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 100
});
self.headCollider.y = -enemyGraphics.height / 4; // Position the rectangle on the enemy's head
self.headCollider.alpha = 0;
// Add a bodyCollider rectangle to the bottom part of the enemy
self.bodyCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
color: 0xffff00
});
self.bodyCollider.y = enemyGraphics.height / 4; // Position the rectangle on the enemy's body
self.bodyCollider.alpha = 0;
self.speed = 5;
self.state;
self.removeFromArray = false;
self.states = {
moving: {
onEnter: function onEnter() {
console.log('Enemy starts moving');
self.anims['walk'].play();
},
onUpdate: function onUpdate() {
self.x -= self.speed;
},
onExit: function onExit() {
console.log('Enemy stops moving');
self.anims['walk'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in moving state: ', event, data);
if (event === GameEvents.COLLISION_ENEMY_HEAD) {
if (self.hasHorns() == false) {
self.setState('dead');
}
} else if (event === GameEvents.BULLET_HIT) {
self.setState('dead');
}
}
},
dead: {
onEnter: function onEnter() {
console.log('Enemy has died');
LK.getSound('bounce').play();
monsterDeaths++;
tween(monsterDeathsText.scale, {
x: 1.5,
y: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(monsterDeathsText.scale, {
x: 1,
y: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
storage.monsterDeaths = monsterDeaths;
onEnemyDeath(self);
self.anims['dead'].play();
self.speed = 0;
var y_val = self.y - Math.random() * 150;
var x_val = self.x + 100 + Math.random() * 200;
tween(self, {
x: x_val,
y: y_val,
rotation: Math.PI / 6 // 30 degrees in radians
}, {
duration: 250,
easing: tween.expoOut,
onFinish: function onFinish() {
tween(self, {
y: 2732 + 300
}, {
duration: 500,
easing: tween.expoIn,
onFinish: function onFinish() {
self.removeFromArray = true;
}
});
}
});
},
onUpdate: function onUpdate() {},
onExit: function onExit() {
console.log('Exiting dead state');
},
onEvent: function onEvent(event, data) {
console.log('Event received in dead state: ', event, data);
}
}
};
self.setState = function (state) {
if (self.state) {
self.states[self.state].onExit();
}
self.state = state;
self.states[self.state].onEnter();
};
self.sendEvent = function (event, data) {
if (self.state) {
self.states[self.state].onEvent(event, data);
}
};
self.update = function () {
self.states[self.state].onUpdate();
};
self.setState('moving');
// Function to check if the enemy has visible horns
self.hasHorns = function () {
return self.images['horns'] && self.images['horns'].visible;
};
});
var Enemy2 = Container.expand(function () {
var self = Container.call(this);
self.images = {
"dead": LK.getAsset('enemy2_dead', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk1": LK.getAsset('enemy2_walk1', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk2": LK.getAsset('enemy2_walk2', {
anchorX: 0.5,
anchorY: 0.5
}),
"attack1": LK.getAsset('enemy2_attack1', {
anchorX: 0.5,
anchorY: 0.5
}),
"attack2": LK.getAsset('enemy2_attack2', {
anchorX: 0.5,
anchorY: 0.5
}),
"horn": LK.getAsset('enemy2_horn', {
anchorX: 0.5,
anchorY: 0.5
}),
"idle1": LK.getAsset('enemy2_idle1', {
anchorX: 0.5,
anchorY: 0.5
}),
"idle2": LK.getAsset('enemy2_idle2', {
anchorX: 0.5,
anchorY: 0.5
})
};
for (var img_name in self.images) {
var img = self.addChild(self.images[img_name]);
img.visible = false;
self.images[img_name] = img;
}
self.anims = {
'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300),
'dead': new FrameAnimation([self.images.dead], 100),
'idle': new FrameAnimation([self.images.idle1, self.images.idle2], 300),
// New idle animation
'attack': new FrameAnimation([self.images.attack1, self.images.attack2], 300) // New attack animation
};
var enemyGraphics = {
height: 300,
width: 300
};
self.headCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 100
});
self.headCollider.y = -enemyGraphics.height / 4;
self.headCollider.alpha = 0;
self.bodyCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
color: 0xffff00
});
self.bodyCollider.y = enemyGraphics.height / 4;
self.bodyCollider.alpha = 0;
self.speed = 5;
self.state;
self.removeFromArray = false;
self.states = {
moving: {
onEnter: function onEnter() {
console.log('Enemy2 starts moving');
self.anims['walk'].play();
},
onUpdate: function onUpdate() {
self.x -= self.speed;
// Transition to attack state when reaching 2/3rd of the screen
if (self.lastX > 2048 * (2 / 3) && self.x <= 2048 * (2 / 3)) {
self.setState('attack');
}
self.lastX = self.x;
},
onExit: function onExit() {
console.log('Enemy2 stops moving');
self.anims['walk'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in moving state: ', event, data);
if (event === GameEvents.COLLISION_ENEMY_HEAD) {
self.setState('dead');
}
}
},
attack: {
// New attack state
onEnter: function onEnter() {
console.log('Enemy2 starts attacking');
self.anims['idle'].play(); // Play idle animation
self.attackTimer = 500; // Set attack timer
},
onUpdate: function onUpdate() {
if (self.attackTimer > 0) {
self.attackTimer--; // Decrease attack timer
} else {
self.anims['idle'].stop(); // Stop idle animation
self.anims['attack'].play(); // Play attack animation
LK.getSound('roar').play();
self.attackTimer = 1000;
}
},
onExit: function onExit() {
console.log('Enemy2 stops attacking');
self.anims['idle'].stop();
self.anims['attack'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in attack state: ', event, data);
if (event === GameEvents.ANIM_FINISHED && data == self.anims['attack']) {
// Shoot a bullet at the player using enemy_horn image
var bullet = new Bullet(self.images.horn);
bullet.x = self.x;
bullet.y = self.y;
bulletContainer.addChild(bullet);
self.anims['attack'].stop();
self.anims['idle'].play();
self.attackTimer = 500;
} else if (event === GameEvents.COLLISION_ENEMY_HEAD) {
self.setState('dead');
} else if (event === GameEvents.BULLET_HIT) {
self.setState('dead');
}
}
},
// End of new attack state
dead: {
onEnter: function onEnter() {
console.log('Enemy2 has died');
LK.getSound('bounce').play();
monsterDeaths++;
storage.monsterDeaths = monsterDeaths;
onEnemyDeath(self);
self.anims['dead'].play();
self.speed = 0;
var y_val = self.y - Math.random() * 150;
var x_val = self.x + 100 + Math.random() * 200;
tween(self, {
x: x_val,
y: y_val,
rotation: Math.PI / 6
}, {
duration: 250,
easing: tween.expoOut,
onFinish: function onFinish() {
tween(self, {
y: 2732 + 300
}, {
duration: 500,
easing: tween.expoIn,
onFinish: function onFinish() {
self.removeFromArray = true;
}
});
}
});
},
onUpdate: function onUpdate() {},
onExit: function onExit() {
console.log('Exiting dead state');
},
onEvent: function onEvent(event, data) {
console.log('Event received in dead state: ', event, data);
}
}
};
self.setState = function (state) {
if (self.state) {
self.states[self.state].onExit();
}
self.state = state;
self.states[self.state].onEnter();
};
self.sendEvent = function (event, data) {
if (self.state) {
self.states[self.state].onEvent(event, data);
}
};
self.update = function () {
self.states[self.state].onUpdate();
};
self.setState('moving');
// Function to check if the enemy has visible horns
self.hasHorns = function () {
return self.images['horn'] && self.images['horn'].visible;
};
});
var Enemy4 = Container.expand(function () {
var self = Container.call(this);
self.images = {
"dead": LK.getAsset('enemy4_dead', {
anchorX: 0.5,
anchorY: 0.5
}),
"idle1": LK.getAsset('enemy4_idle1', {
anchorX: 0.5,
anchorY: 0.5
}),
"idle2": LK.getAsset('enemy4_idle2', {
anchorX: 0.5,
anchorY: 0.5
}),
"horns": LK.getAsset('enemy1_horns', {
anchorX: 0.5,
anchorY: 0.5
})
};
for (var img_name in self.images) {
var img = self.addChild(self.images[img_name]);
img.visible = false;
self.images[img_name] = img;
}
self.anims = {
'walk': new FrameAnimation([self.images.idle1, self.images.idle2], 300),
'dead': new FrameAnimation([self.images.dead], 100)
};
var enemyGraphics = {
height: 300,
width: 300
};
self.headCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 100,
x: -200,
y: 150 - 50
});
self.headCollider.alpha = 0;
self.bodyCollider = self.attachAsset('enemyRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 200,
x: 0
});
self.bodyCollider.y = enemyGraphics.height / 4;
self.bodyCollider.alpha = 0;
self.speed = 8;
self.state;
self.removeFromArray = false;
self.states = {
moving: {
onEnter: function onEnter() {
console.log('Enemy4 starts moving');
self.anims['walk'].play();
},
onUpdate: function onUpdate() {
self.x -= self.speed;
if (self.x < -500) {
self.setState('dead');
}
},
onExit: function onExit() {
console.log('Enemy4 stops moving');
self.anims['walk'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in moving state: ', event, data);
if (event === GameEvents.COLLISION_ENEMY_HEAD) {
data.setState('dead');
} else if (event === GameEvents.BULLET_HIT) {
// Do nothing for Enemy4 when hit by a bullet
} else if (event == GameEvents.COLLISION_PLAYER_BODY) {
self.setState('dead');
}
}
},
dead: {
onEnter: function onEnter() {
console.log('Enemy4 has died');
LK.getSound('bounce').play();
monsterDeaths++;
storage.monsterDeaths = monsterDeaths;
onEnemyDeath(self);
self.anims['dead'].play();
self.speed = 0;
var y_val = self.y - Math.random() * 150;
var x_val = self.x + 100 + Math.random() * 200;
tween(self, {
x: x_val,
y: y_val,
rotation: Math.PI / 6
}, {
duration: 250,
easing: tween.expoOut,
onFinish: function onFinish() {
tween(self, {
y: 2732 + 300
}, {
duration: 500,
easing: tween.expoIn,
onFinish: function onFinish() {
self.removeFromArray = true;
}
});
}
});
},
onUpdate: function onUpdate() {},
onExit: function onExit() {
console.log('Exiting dead state');
},
onEvent: function onEvent(event, data) {
console.log('Event received in dead state: ', event, data);
}
}
};
self.setState = function (state) {
if (self.state) {
self.states[self.state].onExit();
}
self.state = state;
self.states[self.state].onEnter();
};
self.sendEvent = function (event, data) {
if (self.state) {
self.states[self.state].onEvent(event, data);
}
};
self.update = function () {
self.states[self.state].onUpdate();
};
self.setState('moving');
self.hasHorns = function () {
return true;
};
});
//<Assets used in the game will automatically appear here>
// Define a class for the player character
var Player = Container.expand(function () {
var self = Container.call(this);
self.images = {
"idle": LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5
}),
"jump": LK.getAsset('player_jump', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk1": LK.getAsset('walk_1', {
anchorX: 0.5,
anchorY: 0.5
}),
"walk2": LK.getAsset('walk_2', {
anchorX: 0.5,
anchorY: 0.5
}),
'dead': LK.getAsset('player_dead', {
anchorX: 0.5,
anchorY: 0.5
}),
'attack1': LK.getAsset('player_attack1', {
anchorX: 0.5,
anchorY: 0.5
}),
'attack2': LK.getAsset('player_attack2', {
anchorX: 0.5,
anchorY: 0.5
})
};
self.speed = 5;
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.state;
//replacing the asset ref with the image added.
for (var img_name in self.images) {
var img = self.addChild(self.images[img_name]);
img.visible = false;
self.images[img_name] = img;
}
// Add a bodyCollider rectangle to the player character
self.bodyCollider = self.attachAsset('collider', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
color: 0xffff00,
// Yellow color
alpha: 0
});
self.bodyCollider.y = self.images.idle.height / 4; // Position the rectangle on the player's body
//configure the animation frames.
self.anims = {
'walk': new FrameAnimation([self.images.walk1, self.images.walk2], 300),
'jump': new FrameAnimation([self.images.jump], 100),
'idle': [self.images.idle],
'dead': new FrameAnimation([self.images.dead], 100),
'attack': new FrameAnimation([self.images.jump, self.images.attack1, self.images.attack2, self.images.idle], 200)
};
self.states = {
idle: {
onEnter: function onEnter() {
console.log('Entering idle state');
self.anims['walk'].play();
},
onUpdate: function onUpdate() {},
onExit: function onExit() {
console.log('Exiting idle state');
self.anims['walk'].stop();
},
onEvent: function onEvent(event, data) {
if (event === GameEvents.COLLISION_ENEMY_BODY) {
if (data instanceof Enemy4) {
//do nothing.
} else {
self.setState('dead');
}
} else if (event === GameEvents.BULLET_HIT) {
self.setState('dead');
}
}
},
dead: {
onEnter: function onEnter() {
console.log('Player has died');
LK.getSound('player_hit').play();
playerDeaths++;
storage.playerDeaths = playerDeaths;
playerDeathsText.setText('' + playerDeaths);
tween(playerDeathsText.scale, {
x: 1.5,
y: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playerDeathsText.scale, {
x: 1,
y: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
tween(self, {
y: self.y - 400,
rotation: -Math.PI / 6 // 30 degrees in radians
}, {
duration: 250,
easing: tween.expoOut,
onFinish: function onFinish() {
tween(self, {
y: 2732 + 300
}, {
duration: 1000,
easing: tween.expoIn,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
});
// Stop all enemies from moving
for (var j = 0; j < enemies.length; j++) {
enemies[j].speed = 0;
}
self.anims['dead'].play();
// Additional logic for death state can be added here
},
onUpdate: function onUpdate() {},
onExit: function onExit() {
console.log('Exiting death state');
},
onEvent: function onEvent(event, data) {
console.log('Event received in death state: ', event, data);
}
},
attack: {
onEnter: function onEnter() {
console.log('Player is attacking');
LK.getSound('punch_swing').play();
self.anims['attack'].play();
},
onUpdate: function onUpdate() {
// Attack logic can be added here
},
onExit: function onExit() {
console.log('Exiting attack state');
self.anims['attack'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in attack state: ', event, data);
if (event === GameEvents.ANIM_FINISHED) {
self.setState('idle');
} else if (event === GameEvents.COLLISION_ENEMY_HEAD) {
if (data.hasHorns()) {
self.setState('dead');
} else {
data.setState('dead');
}
} else if (event === GameEvents.COLLISION_ENEMY_BODY) {
LK.getSound('punch').play();
data.setState('dead');
} else if (event === GameEvents.BULLET_HIT) {
if (data.speed > 0) {
data.speed = -data.speed;
LK.getSound('punch').play();
} // Reverse bullet direction
}
}
},
jumping: {
onEnter: function onEnter() {
if (!self.isJumping) {
LK.getSound('jump').play();
self.isJumping = true;
self.velocityY = -self.jumpHeight;
self.anims['jump'].play();
console.log("jump Started");
}
},
onUpdate: function onUpdate() {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 1.4; // Increase gravity effect to make descent twice as fast
if (self.y >= 2732 / 2) {
// Ground level
self.y = 2732 / 2;
self.isJumping = false;
self.velocityY = 0;
self.setState('idle');
}
}
},
onExit: function onExit() {
console.log('Exiting jumping state');
self.anims['jump'].stop();
},
onEvent: function onEvent(event, data) {
console.log('Event received in jumping state: ', event, data);
if (event === GameEvents.COLLISION_ENEMY_HEAD) {
if (data.hasHorns()) {
self.setState('dead');
} else {
// Add upward velocity to player
player.velocityY = -player.jumpHeight / 2;
player.isJumping = true;
LK.getSound('bounce').play();
}
} else if (event === GameEvents.COLLISION_ENEMY_BODY) {
if (data instanceof Enemy4) {
// Add upward velocity to player
player.velocityY = -player.jumpHeight / 2;
player.isJumping = true;
LK.getSound('bounce').play();
} else {
self.setState('dead');
}
} else if (event === GameEvents.BULLET_HIT) {
self.setState('dead');
}
}
}
};
self.setState = function (state) {
if (self.state) {
self.states[self.state].onExit();
}
self.state = state;
self.states[self.state].onEnter();
};
self.sendEvent = function (event, data) {
if (self.state) {
self.states[self.state].onEvent(event, data);
}
};
self.update = function () {
self.states[self.state].onUpdate();
};
self.attack = function () {
if (self.state !== 'jumping' && self.state !== 'dead') {
self.setState('attack');
}
};
self.jump = function () {
if (self.state !== 'jumping' && self.state !== 'dead') {
self.setState('jumping');
}
};
//call the initial state.
self.setState('idle');
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
function onEnemyDeath(enemy) {
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
// Increment the count of enemies killed by the player
enemiesKilledByPlayer++;
monsterDeathsText.setText('' + monsterDeaths);
// Check if the score is 8 or above and 5 enemies have been killed
if (LK.getScore() >= 8 && enemiesKilledByPlayer % 5 === 0) {
// Spawn Enemy4
var enemy4 = new Enemy4();
enemy4.x = 2048;
enemy4.y = 2732 / 2;
enemies.push(enemy4);
enemyContainer.addChild(enemy4);
}
}
LK.playMusic('platformer_music'); // Start playing background music
var GameEvents = {
COLLISION_ENEMY_HEAD: 0,
COLLISION_ENEMY_BODY: 1,
COLLISION_PLAYER_BODY: 2,
ANIM_FINISHED: 3,
BULLET_HIT: 4 // New event for when player is hit by enemy bullet
};
// Initialize death counters from storage
var playerDeaths = storage.playerDeaths;
var monsterDeaths = storage.monsterDeaths;
// Track the number of enemies killed by the player
var enemiesKilledByPlayer = 0;
// Define a class for frame animations
var FrameAnimation = function FrameAnimation(assets, frameRate) {
var self = this;
self.assets = assets;
self.frameRate = frameRate;
self.currentFrame = 0;
self.isPlaying = false;
self.interval = null;
// Function to show the current frame
self.showFrame = function () {
for (var i = 0; i < self.assets.length; i++) {
self.assets[i].visible = false;
}
self.assets[self.currentFrame].visible = true;
};
// Play the animation
self.play = function () {
if (!self.isPlaying) {
self.isPlaying = true;
self.showFrame();
if (self.assets.length > 1) {
self.interval = LK.setInterval(function () {
self.currentFrame = (self.currentFrame + 1) % self.assets.length;
self.showFrame();
if (self.currentFrame === 0) {
// Send ANIM_FINISHED event when animation completes a cycle
self.assets[0].parent.sendEvent(GameEvents.ANIM_FINISHED, self);
}
}, self.frameRate);
}
}
};
// Pause the animation
self.pause = function () {
if (self.isPlaying) {
clearInterval(self.interval);
self.isPlaying = false;
}
};
// Resume the animation
self.resume = function () {
if (!self.isPlaying) {
self.play();
}
};
// Stop the animation
self.stop = function () {
LK.clearInterval(self.interval);
self.isPlaying = false;
self.currentFrame = 0;
for (var i = 0; i < self.assets.length; i++) {
self.assets[i].visible = false;
}
};
};
var background = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 2048 / 2;
background.y = 2732 / 2 - 550;
// Initialize player
var player = game.addChild(new Player());
player.x = 150; // Position player on the left side of the screen
player.y = 2732 / 2;
// Initialize enemy container
var enemyContainer = new Container();
game.addChild(enemyContainer);
// Initialize enemies array
var enemies = [];
// Initialize bullet container
var bulletContainer = new Container();
game.addChild(bulletContainer);
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
// Create a new Text2 object to display the score
var scoreText = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
// Create a GUI container
var guiContainer = new Container();
game.addChild(guiContainer);
// Add the score text to the GUI container at the top center of the screen
guiContainer.addChild(scoreText);
scoreText.x = 2048 / 2;
scoreText.y = 20; // Adjusted to align with other top elements
scoreText.anchor.set(0.5, 0); // Center the score text horizontally
// Add a jump button to the bottom of the screen in the GUI container
var jumpButton = LK.getAsset('jump_button', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400
});
jumpButton.x = 2048 / 4;
jumpButton.y = 2732 - jumpButton.height / 2 - 300;
guiContainer.addChild(jumpButton);
// Add an attack button to the bottom of the screen in the GUI container
var attackButton = LK.getAsset('attack_button', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400
});
attackButton.x = 3 * 2048 / 4;
attackButton.y = 2732 - attackButton.height / 2 - 300;
guiContainer.addChild(attackButton);
// Add event listeners to flash buttons black on mouse or touch down
jumpButton.down = function (x, y, obj) {
LK.effects.flashObject(jumpButton, 0x000000, 500);
player.jump();
};
attackButton.down = function (x, y, obj) {
LK.effects.flashObject(attackButton, 0x000000, 500);
player.attack();
};
// Add a music button to the top right corner of the screen
var musicButton = LK.getAsset('music_on', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 200
});
musicButton.x = 2048 - musicButton.width / 2 - 50; // Position it at the top right corner
musicButton.y = musicButton.height / 2 + 50;
guiContainer.addChild(musicButton);
music_off = LK.getAsset('music_off', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 200,
x: musicButton.x,
y: musicButton.y,
visible: false
});
guiContainer.addChild(music_off);
// Add event listener to toggle music on button press
var isMusicPlaying = true; // Initialize music state
musicButton.down = function (x, y, obj) {
LK.effects.flashObject(musicButton, 0x000000, 500);
LK.effects.flashObject(music_off, 0x000000, 500);
if (isMusicPlaying) {
LK.stopMusic(); // Stop playing background music
music_off.visible = true;
} else {
LK.playMusic('platformer_music'); // Start playing background music
music_off.visible = false;
}
isMusicPlaying = !isMusicPlaying; // Toggle music state
};
// Add the score_display image to the GUI container at the top center of the screen
var scoreDisplayImage = LK.getAsset('score_display', {
anchorX: 0.5,
anchorY: 0.0
});
scoreDisplayImage.x = 2048 / 2;
scoreDisplayImage.y = 0; // Align to the top of the screen
guiContainer.addChild(scoreDisplayImage);
// Create Text2 objects to display player and monster deaths
var playerDeathsText = new Text2('' + playerDeaths, {
size: 72,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0.5,
font: "VAG Rounded" // More rounded and thick font
});
var monsterDeathsText = new Text2('' + monsterDeaths, {
size: 72,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0.5,
font: "VAG Rounded" // More rounded and thick font
});
// Position the death counters at the top of the screen
playerDeathsText.x = scoreDisplayImage.x + 150;
playerDeathsText.y = 190;
monsterDeathsText.x = scoreDisplayImage.x - 280;
monsterDeathsText.y = 190;
// Add the death counters to the GUI container
guiContainer.addChild(playerDeathsText);
guiContainer.addChild(monsterDeathsText);
function addEnemy2(game, enemies) {
enemy = new Enemy2();
enemy.x = 2048;
enemy.y = 2732 / 2;
enemies.push(enemy);
enemyContainer.addChild(enemy);
}
// Handle game updates
game.update = function () {
player.update();
// Spawn enemies
if (player.state !== 'dead') {
enemySpawnCounter++;
if (enemySpawnCounter >= enemySpawnInterval) {
//get if enemy2 is on the map.
var enemy2Exists = enemies.some(function (e) {
return e instanceof Enemy2;
});
var enemy;
var playerScore = LK.getScore();
if (!enemy2Exists && playerScore > 10 && Math.random() < 0.4) {
enemy = new Enemy4();
enemy.x = 2048;
enemy.y = 2732 / 2;
enemies.push(enemy);
enemyContainer.addChild(enemy);
} else {
enemy = new Enemy();
enemy.x = 2048;
enemy.y = 2732 / 2;
enemies.push(enemy);
enemyContainer.addChild(enemy);
if (playerScore > 3 && Math.random() < 0.4) {
enemy.images['horns'].visible = true;
}
}
if (!enemy2Exists && playerScore >= 5) {
addEnemy2(game, enemies);
}
// Randomize the spawn interval for the next enemy
enemySpawnInterval = Math.floor(Math.random() * 150) + 50;
enemySpawnCounter = 0;
}
}
// Check collision between player bodyCollider and bullets
for (var k = bulletContainer.children.length - 1; k >= 0; k--) {
var bullet = bulletContainer.children[k];
if (bullet.intersects(player.bodyCollider)) {
// Send BULLET_HIT event to player
player.sendEvent(GameEvents.BULLET_HIT, bullet);
// bullet.destroy();
// bulletContainer.removeChild(bullet);
}
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
// Skip collision checks if player is in the dead state
if (player.state === 'dead') {
continue;
}
//remove the enemies marked for removal.
if (enemies[j].removeFromArray == true) {
enemies[j].destroy();
enemies.splice(j, 1);
continue;
}
//skip collisions if enemy is dead.
if (enemies[j].state === 'dead') {
continue;
}
// Check collision between player bodyCollider and enemy headCollider
if (player.bodyCollider.intersects(enemies[j].headCollider)) {
onEnemyDeath(enemies[j]); // Call onEnemyDeath function
// Send COLLISION_ENEMY_HEAD event to player
player.sendEvent(GameEvents.COLLISION_ENEMY_HEAD, enemies[j]);
enemies[j].sendEvent(GameEvents.COLLISION_ENEMY_HEAD, player);
continue;
}
// Check collision between enemy bodyCollider and player bodyCollider
if (enemies[j].bodyCollider.intersects(player.bodyCollider)) {
// Send COLLISION_ENEMY_BODY event to player
player.sendEvent(GameEvents.COLLISION_ENEMY_BODY, enemies[j]);
enemies[j].sendEvent(GameEvents.COLLISION_PLAYER_BODY, player);
return;
}
}
};
// Handle player jump
game.down = function (x, y, obj) {
if (y > 2732 / 2 && x < 2048 / 2) {
// Check if click is on the left half
player.jump();
} else if (y > 2732 / 2) {
// Otherwise, it's on the right half
player.attack();
}
};