/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ //Storage library which should be used for persistent game data // var storage = LK.import('@upit/storage.v1'); //Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions // var facekit = LK.import('@upit/facekit.v1'); //Classes can only be defined here. You cannot create inline classes in the games code. var Bullet = Container.expand(function () { var self = Container.call(this); //Create and attach asset. This is the same as calling var xxx = self.addChild(LK.getAsset(...)) var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); //Set bullet speed self.speed = 20; // Bullet speed //If this instance of bullet is attached, this method will be called every tick by the LK engine automatically. //To not manually call .updated methods. If you want to manually call a method every tick on a class, use a different name than update. //As .update is called from the LK engine directly, .update cannot have method arguments. self.update = function () { self.y -= self.speed; // Move bullet upwards }; return self; //You must return self if you want other classes to be able to inherit from this class }); var Door = Container.expand(function () { var self = Container.call(this); self.attachAsset('door_asset', { anchorX: 0.5, anchorY: 0.5 }); return self; }); //Make a Character class by using the LK expand method to extend Container. var HealthBar = Container.expand(function () { var self = Container.call(this); var maxWidth = 200; var height = 20; var background = self.addChild(LK.getAsset('bullet', { // Using bullet as a temporary graphic width: maxWidth, height: height, tint: 0x808080, // Grey background anchorX: 0, anchorY: 0 })); var foreground = self.addChild(LK.getAsset('bullet', { // Using bullet as a temporary graphic width: maxWidth, height: height, tint: 0x00ff00, // Green foreground anchorX: 0, anchorY: 0 })); self.setMaxHealth = function (maxHealth) { self._maxHealth = maxHealth; self.setHealth(maxHealth); }; self.setHealth = function (health) { self._health = Math.max(0, Math.min(self._maxHealth, health)); foreground.width = self._health / self._maxHealth * maxWidth; }; self.getHealth = function () { return self._health; }; return self; }); var Key = Container.expand(function () { var self = Container.call(this); self.attachAsset('key_asset', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Note = Container.expand(function () { var self = Container.call(this); self.attachAsset('note_asset', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var PlayerCharacter = Container.expand(function () { var self = Container.call(this); //Get and automatically addChild to self asset with id 'player' with the anchor point set to .5, .5 var characterGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Clamp position to be within the bottom half of the screen // Ensure self.width and self.height are valid (assets are loaded) if (self.width && self.height) { self.x = Math.max(characterGraphics.width / 2, Math.min(2048 - characterGraphics.width / 2, self.x)); // Y position is not changed by horizontal swipes, but we keep its clamping logic. // Y position can now be changed by vertical swipes. Clamp Y to full screen height. self.y = Math.max(characterGraphics.height / 2, Math.min(2732 - characterGraphics.height / 2, self.y)); } }; return self; //You must return self if you want other classes to be able to inherit from this class }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Golden key // Light yellow for the note // Add key asset //Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property. //Only include the plugins you need to create the game. //We have access to the following plugins. (Note that the variable names used are mandetory for each plugin) // Initialize music // Blue character // Purple alien // Yellow bullet // Initialize assets used in this game. Scale them according to what is needed for the game. // or via static code analysis based on their usage in the code. // Assets are automatically created and loaded either dynamically during gameplay /* Supported Types: 1. Shape: - Simple geometric figures with these properties: * width: (required) pixel width of the shape. * height: (required) pixel height of the shape. * color: (required) color of the shape. * shape: (required) type of shape. Valid options: 'box', 'ellipse'. 2. Image: - Imported images with these properties: * width: (required) pixel resolution width. * height: (required) pixel resolution height. * id: (required) identifier for the image. * flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip). * flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip). * orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values: - 0: No rotation. - 1: Rotate 90 degrees. - 2: Rotate 180 degrees. - 3: Rotate 270 degrees. Note: Width and height remain unchanged upon flipping. 3. Sound: - Sound effects with these properties: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. 4. Music: - In contract to sound effects, only one music can be played at a time - Music is using the same API to initilize just like sound. - Music loops by default - Music with these config options: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. * start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping * end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping */ //Init game with black background //Note game dimensions are 2048x2732 // Global variables var alien; var character; var bullets = []; var scoreTxt; // dragNode is no longer used with swipe controls var lastCharacterIntersectingAlien = false; var touchStartX = 0; // Stores the initial X position of a touch/swipe var touchStartY = 0; // Stores the initial Y position of a touch/swipe var characterInitialX = 0; // Stores the character's X position at the start of a swipe var characterInitialY = 0; // Stores the character's Y position at the start of a swipe var isSwiping = false; // Flag to indicate if a swipe is in progress var swipeAxis = 'none'; // Determines swipe axis: 'none', 'horizontal', 'vertical' var SWIPE_THRESHOLD = 20; // Minimum pixel distance to determine swipe axis var WIN_SCORE = 50; // Score to win // var monsterHealth = 100; // Monster's initial health (REMOVED) // var monsterMaxHealth = 100; // Monster's maximum health (REMOVED) // var healthBar; // Health bar instance (REMOVED) var alienHitCount = 0; // Tracks how many times the alien has been hit var alienDefeated = false; // Tracks if the alien has been defeated and dropped the item var keyInstance = null; // Key instance var hasKey = false; // Tracks if the player has collected the key var noteInstance = null; // Note instance var doorInstance = null; // Door instance var playerLives = 3; // Player starts with 3 lives var characterLastIntersectingDoor = false; // Tracks if character was intersecting door in the previous frame // var monsterLives = 4; // Monster starts with 4 lives (REMOVED) // Change background color game.setBackgroundColor(0x1a1a1a); // Dark grey background // Create and position the alien in the center alien = game.addChild(LK.getAsset('alien', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); alien.lastIntersectingCharacter = false; // Initialize for intersection tracking alien.lastIntersectingBullet = false; // Initialize for intersection tracking // Health bar creation removed as per new hit count logic // Create and position the player character at the bottom center character = game.addChild(new PlayerCharacter()); character.x = 2048 / 2; character.y = 2732 - character.height / 2 - 100; // Position near bottom character.lastIntersectingAlien = false; // Initialize for intersection tracking // Create and position the door doorInstance = game.addChild(new Door()); doorInstance.x = 2048 / 2; doorInstance.y = 150; // Position at the top-center area // Initialize key variables keyInstance = null; hasKey = false; // Create and add score display scoreTxt = new Text2('0', { size: 150, fill: 0xFFFFFF }); scoreTxt.setText(LK.getScore()); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Mouse or touch up event on the game object // Mouse or touch down event on the game object to start dragging the character game.down = function (x, y, obj) { // Initialize swipe tracking variables touchStartX = x; touchStartY = y; if (character) { // Ensure character exists characterInitialX = character.x; characterInitialY = character.y; } isSwiping = true; swipeAxis = 'none'; // Reset swipe axis determination // Check if the key was tapped if (keyInstance !== null && !hasKey) { // Only allow tap if key exists and not yet collected var keyLocalPos = keyInstance.toLocal({ x: x, y: y }); // Assuming keyInstance has its asset as the first child and anchor is 0.5, 0.5 var keyAsset = keyInstance.children[0]; if (keyAsset && Math.abs(keyLocalPos.x) <= keyAsset.width / 2 && Math.abs(keyLocalPos.y) <= keyAsset.height / 2) { hasKey = true; // Player now "has" the key // keyInstance is NOT destroyed. It will now follow the player. LK.getSound('Rah').play(); // Play sound for collecting the key (re-using 'Rah') // The game doesn't end here; player now has the key for a future door. isSwiping = false; // Stop swipe processing as an action occurred swipeAxis = 'none'; return; // Exit early, an action was performed } } }; game.up = function (x, y, obj) { // Stop character movement on touch up isSwiping = false; swipeAxis = 'none'; // Reset swipe axis }; // Ask LK engine to update game every game tick // Mouse or touch move event on the game object to move the character game.move = function (x, y, obj) { if (isSwiping && character) { var currentX = x; // Current touch x from event var currentY = y; // Current touch y from event var deltaX = currentX - touchStartX; var deltaY = currentY - touchStartY; if (swipeAxis === 'none') { // Determine swipe axis if not already determined if (Math.abs(deltaX) > SWIPE_THRESHOLD || Math.abs(deltaY) > SWIPE_THRESHOLD) { if (Math.abs(deltaX) > Math.abs(deltaY)) { swipeAxis = 'horizontal'; } else { swipeAxis = 'vertical'; } } } // Move character based on determined swipe axis if (swipeAxis === 'horizontal') { character.x = characterInitialX + deltaX; } else if (swipeAxis === 'vertical') { character.y = characterInitialY + deltaY; } // Clamping will be handled by character.update() } }; game.update = function () { // Update and manage bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // We always keep track of last and current values to detect state changes if (bullet.lastY === undefined) bullet.lastY = bullet.y; // Initialize lastY for tracking changes on Y if (bullet.lastIntersectingAlien === undefined) bullet.lastIntersectingAlien = false; // Initialize for intersection tracking // Off-Screen Detection: Destroy bullet if it goes off the top edge if (bullet.lastY >= -bullet.height && bullet.y < -bullet.height) { bullet.destroy(); // Destroy can only be called from the main 'Game' class bullets.splice(i, 1); continue; // Skip further checks for this bullet } // Intersection Detection: Check for bullet collision with alien var currentIntersectingAlien = bullet.intersects(alien); if (!bullet.lastIntersectingAlien && currentIntersectingAlien) { // Intersection just started LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); LK.getSound('hit').play(); // Play hit sound // Increment alien hit count alienHitCount++; // Check if alien has been hit 4 times and not yet defeated if (alienHitCount >= 4 && !alienDefeated) { alienDefeated = true; // Mark alien as defeated to prevent multiple item drops if (keyInstance === null) { // Check if keyInstance is null // Create key only if it doesn't exist keyInstance = game.addChild(new Key()); // Create a Key instance keyInstance.x = alien.x; // Position key at alien's last position keyInstance.y = alien.y; // Drop a note as well if (noteInstance === null) { // Check if noteInstance is null noteInstance = game.addChild(new Note()); noteInstance.x = alien.x + (keyInstance.width || 80) + 20; // Position note next to the key noteInstance.y = alien.y; } // The alien is now "defeated" in terms of dropping the key. // Alien continues to be active unless explicitly made inactive later. } } // Winning condition (if score is still a win condition) if (LK.getScore() >= WIN_SCORE) { LK.showYouWin(); // Show "you win" and reset } bullet.destroy(); // Destroy bullet on hit bullets.splice(i, 1); continue; // Skip further checks for this bullet } // Update last known states bullet.lastY = bullet.y; bullet.lastIntersectingAlien = currentIntersectingAlien; } // Character movement is handled by the PlayerCharacter update method. // Move the alien towards the character (only if not fully defeated, e.g. invisible/inactive) // For simplicity, alien continues to move. If you want it to stop after dropping note: // if (!alienDefeated || (alienDefeated && noteInstance !== null)) { // Example: stop if note is dropped and still on screen if (alien && alien.visible) { // Assuming alien might be made invisible var moveSpeed = 5; // Adjust speed as needed if (character && character.visible) { // Ensure character exists and is visible var dx = character.x - alien.x; var dy = character.y - alien.y; var angle = Math.atan2(dy, dx); alien.x += Math.cos(angle) * moveSpeed; alien.y += Math.sin(angle) * moveSpeed; } } // Check for character collision with alien if (alien && alien.visible && character && character.visible) { // Check visibility var currentCharacterIntersectingAlien = character.intersects(alien); if (!lastCharacterIntersectingAlien && currentCharacterIntersectingAlien) { // Collision just started playerLives--; // Player loses a life LK.effects.flashScreen(0xff0000, 1000); // Flash screen red if (playerLives <= 0) { LK.showGameOver(); // Show game over and reset } else { // Player still has lives. } } lastCharacterIntersectingAlien = currentCharacterIntersectingAlien; } else { lastCharacterIntersectingAlien = false; // Reset if alien or character is not active for collision } // Make the key follow the player if collected if (hasKey && keyInstance && character && character.visible) { // Position key slightly above the player character var keyAssetGraphics = keyInstance.children[0]; // Assuming asset is the first child var keyHeight = keyAssetGraphics ? keyAssetGraphics.height : 80; // Use actual or default height var playerCharGraphics = character.children[0]; var playerHeight = playerCharGraphics ? playerCharGraphics.height : 100; keyInstance.x = character.x; keyInstance.y = character.y - playerHeight / 2 - keyHeight / 2 - 10; // Adjust offset as needed } // Check for player collision with door if player has the key var currentCharacterIntersectingDoor = false; // Local var for current frame's intersection state with the door if (doorInstance && doorInstance.visible && character && character.visible && hasKey) { // Ensure door, character are valid and visible, and player has the key currentCharacterIntersectingDoor = character.intersects(doorInstance); if (!characterLastIntersectingDoor && currentCharacterIntersectingDoor) { // Check for the start of an intersection // Intersection just started doorInstance.visible = false; // "Opens" the door by making it invisible if (keyInstance && keyInstance.visible) { // If key exists and is visible keyInstance.visible = false; // Make the key invisible as it has been "used" } LK.showYouWin(); // Player with key + door collision = win (transition to "new room") } } // Update the 'last intersecting' state for the door for the next frame. // This is crucial for detecting only the *initial* moment of intersection. if (doorInstance && character) { // Only update if door and character are still valid characterLastIntersectingDoor = currentCharacterIntersectingDoor; } else { // If door or character becomes invalid (e.g., destroyed), reset the tracking state. characterLastIntersectingDoor = false; } // Fire a bullet periodically (every 15 ticks = ~4 times per second) if (LK.ticks % 15 == 0) { var newBullet = new Bullet(); // We always keep track of last and current values newBullet.x = character.x; newBullet.y = character.y; newBullet.lastY = newBullet.y; // Initialize lastY for tracking changes on Y newBullet.lastIntersectingAlien = newBullet.intersects(alien); // Initialize for intersection tracking bullets.push(newBullet); game.addChild(newBullet); LK.getSound('shoot').play(); // Play shoot sound } }; // Play background music LK.playMusic('bgmusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
//Storage library which should be used for persistent game data
// var storage = LK.import('@upit/storage.v1');
//Library for using the camera (the background becomes the user's camera video feed) and the microphone. It can access face coordinates for interactive play, as well detect microphone volume / voice interactions
// var facekit = LK.import('@upit/facekit.v1');
//Classes can only be defined here. You cannot create inline classes in the games code.
var Bullet = Container.expand(function () {
var self = Container.call(this);
//Create and attach asset. This is the same as calling var xxx = self.addChild(LK.getAsset(...))
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
//Set bullet speed
self.speed = 20; // Bullet speed
//If this instance of bullet is attached, this method will be called every tick by the LK engine automatically.
//To not manually call .updated methods. If you want to manually call a method every tick on a class, use a different name than update.
//As .update is called from the LK engine directly, .update cannot have method arguments.
self.update = function () {
self.y -= self.speed; // Move bullet upwards
};
return self; //You must return self if you want other classes to be able to inherit from this class
});
var Door = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('door_asset', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
//Make a Character class by using the LK expand method to extend Container.
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var maxWidth = 200;
var height = 20;
var background = self.addChild(LK.getAsset('bullet', {
// Using bullet as a temporary graphic
width: maxWidth,
height: height,
tint: 0x808080,
// Grey background
anchorX: 0,
anchorY: 0
}));
var foreground = self.addChild(LK.getAsset('bullet', {
// Using bullet as a temporary graphic
width: maxWidth,
height: height,
tint: 0x00ff00,
// Green foreground
anchorX: 0,
anchorY: 0
}));
self.setMaxHealth = function (maxHealth) {
self._maxHealth = maxHealth;
self.setHealth(maxHealth);
};
self.setHealth = function (health) {
self._health = Math.max(0, Math.min(self._maxHealth, health));
foreground.width = self._health / self._maxHealth * maxWidth;
};
self.getHealth = function () {
return self._health;
};
return self;
});
var Key = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('key_asset', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('note_asset', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var PlayerCharacter = Container.expand(function () {
var self = Container.call(this);
//Get and automatically addChild to self asset with id 'player' with the anchor point set to .5, .5
var characterGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Clamp position to be within the bottom half of the screen
// Ensure self.width and self.height are valid (assets are loaded)
if (self.width && self.height) {
self.x = Math.max(characterGraphics.width / 2, Math.min(2048 - characterGraphics.width / 2, self.x));
// Y position is not changed by horizontal swipes, but we keep its clamping logic.
// Y position can now be changed by vertical swipes. Clamp Y to full screen height.
self.y = Math.max(characterGraphics.height / 2, Math.min(2732 - characterGraphics.height / 2, self.y));
}
};
return self; //You must return self if you want other classes to be able to inherit from this class
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Golden key
// Light yellow for the note
// Add key asset
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Only include the plugins you need to create the game.
//We have access to the following plugins. (Note that the variable names used are mandetory for each plugin)
// Initialize music
// Blue character
// Purple alien
// Yellow bullet
// Initialize assets used in this game. Scale them according to what is needed for the game.
// or via static code analysis based on their usage in the code.
// Assets are automatically created and loaded either dynamically during gameplay
/*
Supported Types:
1. Shape:
- Simple geometric figures with these properties:
* width: (required) pixel width of the shape.
* height: (required) pixel height of the shape.
* color: (required) color of the shape.
* shape: (required) type of shape. Valid options: 'box', 'ellipse'.
2. Image:
- Imported images with these properties:
* width: (required) pixel resolution width.
* height: (required) pixel resolution height.
* id: (required) identifier for the image.
* flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip).
* flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip).
* orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values:
- 0: No rotation.
- 1: Rotate 90 degrees.
- 2: Rotate 180 degrees.
- 3: Rotate 270 degrees.
Note: Width and height remain unchanged upon flipping.
3. Sound:
- Sound effects with these properties:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
4. Music:
- In contract to sound effects, only one music can be played at a time
- Music is using the same API to initilize just like sound.
- Music loops by default
- Music with these config options:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
* start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping
* end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping
*/
//Init game with black background
//Note game dimensions are 2048x2732
// Global variables
var alien;
var character;
var bullets = [];
var scoreTxt;
// dragNode is no longer used with swipe controls
var lastCharacterIntersectingAlien = false;
var touchStartX = 0; // Stores the initial X position of a touch/swipe
var touchStartY = 0; // Stores the initial Y position of a touch/swipe
var characterInitialX = 0; // Stores the character's X position at the start of a swipe
var characterInitialY = 0; // Stores the character's Y position at the start of a swipe
var isSwiping = false; // Flag to indicate if a swipe is in progress
var swipeAxis = 'none'; // Determines swipe axis: 'none', 'horizontal', 'vertical'
var SWIPE_THRESHOLD = 20; // Minimum pixel distance to determine swipe axis
var WIN_SCORE = 50; // Score to win
// var monsterHealth = 100; // Monster's initial health (REMOVED)
// var monsterMaxHealth = 100; // Monster's maximum health (REMOVED)
// var healthBar; // Health bar instance (REMOVED)
var alienHitCount = 0; // Tracks how many times the alien has been hit
var alienDefeated = false; // Tracks if the alien has been defeated and dropped the item
var keyInstance = null; // Key instance
var hasKey = false; // Tracks if the player has collected the key
var noteInstance = null; // Note instance
var doorInstance = null; // Door instance
var playerLives = 3; // Player starts with 3 lives
var characterLastIntersectingDoor = false; // Tracks if character was intersecting door in the previous frame
// var monsterLives = 4; // Monster starts with 4 lives (REMOVED)
// Change background color
game.setBackgroundColor(0x1a1a1a); // Dark grey background
// Create and position the alien in the center
alien = game.addChild(LK.getAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
alien.lastIntersectingCharacter = false; // Initialize for intersection tracking
alien.lastIntersectingBullet = false; // Initialize for intersection tracking
// Health bar creation removed as per new hit count logic
// Create and position the player character at the bottom center
character = game.addChild(new PlayerCharacter());
character.x = 2048 / 2;
character.y = 2732 - character.height / 2 - 100; // Position near bottom
character.lastIntersectingAlien = false; // Initialize for intersection tracking
// Create and position the door
doorInstance = game.addChild(new Door());
doorInstance.x = 2048 / 2;
doorInstance.y = 150; // Position at the top-center area
// Initialize key variables
keyInstance = null;
hasKey = false;
// Create and add score display
scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.setText(LK.getScore());
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Mouse or touch up event on the game object
// Mouse or touch down event on the game object to start dragging the character
game.down = function (x, y, obj) {
// Initialize swipe tracking variables
touchStartX = x;
touchStartY = y;
if (character) {
// Ensure character exists
characterInitialX = character.x;
characterInitialY = character.y;
}
isSwiping = true;
swipeAxis = 'none'; // Reset swipe axis determination
// Check if the key was tapped
if (keyInstance !== null && !hasKey) {
// Only allow tap if key exists and not yet collected
var keyLocalPos = keyInstance.toLocal({
x: x,
y: y
});
// Assuming keyInstance has its asset as the first child and anchor is 0.5, 0.5
var keyAsset = keyInstance.children[0];
if (keyAsset && Math.abs(keyLocalPos.x) <= keyAsset.width / 2 && Math.abs(keyLocalPos.y) <= keyAsset.height / 2) {
hasKey = true; // Player now "has" the key
// keyInstance is NOT destroyed. It will now follow the player.
LK.getSound('Rah').play(); // Play sound for collecting the key (re-using 'Rah')
// The game doesn't end here; player now has the key for a future door.
isSwiping = false; // Stop swipe processing as an action occurred
swipeAxis = 'none';
return; // Exit early, an action was performed
}
}
};
game.up = function (x, y, obj) {
// Stop character movement on touch up
isSwiping = false;
swipeAxis = 'none'; // Reset swipe axis
};
// Ask LK engine to update game every game tick
// Mouse or touch move event on the game object to move the character
game.move = function (x, y, obj) {
if (isSwiping && character) {
var currentX = x; // Current touch x from event
var currentY = y; // Current touch y from event
var deltaX = currentX - touchStartX;
var deltaY = currentY - touchStartY;
if (swipeAxis === 'none') {
// Determine swipe axis if not already determined
if (Math.abs(deltaX) > SWIPE_THRESHOLD || Math.abs(deltaY) > SWIPE_THRESHOLD) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
swipeAxis = 'horizontal';
} else {
swipeAxis = 'vertical';
}
}
}
// Move character based on determined swipe axis
if (swipeAxis === 'horizontal') {
character.x = characterInitialX + deltaX;
} else if (swipeAxis === 'vertical') {
character.y = characterInitialY + deltaY;
}
// Clamping will be handled by character.update()
}
};
game.update = function () {
// Update and manage bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// We always keep track of last and current values to detect state changes
if (bullet.lastY === undefined) bullet.lastY = bullet.y; // Initialize lastY for tracking changes on Y
if (bullet.lastIntersectingAlien === undefined) bullet.lastIntersectingAlien = false; // Initialize for intersection tracking
// Off-Screen Detection: Destroy bullet if it goes off the top edge
if (bullet.lastY >= -bullet.height && bullet.y < -bullet.height) {
bullet.destroy(); // Destroy can only be called from the main 'Game' class
bullets.splice(i, 1);
continue; // Skip further checks for this bullet
}
// Intersection Detection: Check for bullet collision with alien
var currentIntersectingAlien = bullet.intersects(alien);
if (!bullet.lastIntersectingAlien && currentIntersectingAlien) {
// Intersection just started
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('hit').play(); // Play hit sound
// Increment alien hit count
alienHitCount++;
// Check if alien has been hit 4 times and not yet defeated
if (alienHitCount >= 4 && !alienDefeated) {
alienDefeated = true; // Mark alien as defeated to prevent multiple item drops
if (keyInstance === null) {
// Check if keyInstance is null
// Create key only if it doesn't exist
keyInstance = game.addChild(new Key()); // Create a Key instance
keyInstance.x = alien.x; // Position key at alien's last position
keyInstance.y = alien.y;
// Drop a note as well
if (noteInstance === null) {
// Check if noteInstance is null
noteInstance = game.addChild(new Note());
noteInstance.x = alien.x + (keyInstance.width || 80) + 20; // Position note next to the key
noteInstance.y = alien.y;
}
// The alien is now "defeated" in terms of dropping the key.
// Alien continues to be active unless explicitly made inactive later.
}
}
// Winning condition (if score is still a win condition)
if (LK.getScore() >= WIN_SCORE) {
LK.showYouWin(); // Show "you win" and reset
}
bullet.destroy(); // Destroy bullet on hit
bullets.splice(i, 1);
continue; // Skip further checks for this bullet
}
// Update last known states
bullet.lastY = bullet.y;
bullet.lastIntersectingAlien = currentIntersectingAlien;
}
// Character movement is handled by the PlayerCharacter update method.
// Move the alien towards the character (only if not fully defeated, e.g. invisible/inactive)
// For simplicity, alien continues to move. If you want it to stop after dropping note:
// if (!alienDefeated || (alienDefeated && noteInstance !== null)) { // Example: stop if note is dropped and still on screen
if (alien && alien.visible) {
// Assuming alien might be made invisible
var moveSpeed = 5; // Adjust speed as needed
if (character && character.visible) {
// Ensure character exists and is visible
var dx = character.x - alien.x;
var dy = character.y - alien.y;
var angle = Math.atan2(dy, dx);
alien.x += Math.cos(angle) * moveSpeed;
alien.y += Math.sin(angle) * moveSpeed;
}
}
// Check for character collision with alien
if (alien && alien.visible && character && character.visible) {
// Check visibility
var currentCharacterIntersectingAlien = character.intersects(alien);
if (!lastCharacterIntersectingAlien && currentCharacterIntersectingAlien) {
// Collision just started
playerLives--; // Player loses a life
LK.effects.flashScreen(0xff0000, 1000); // Flash screen red
if (playerLives <= 0) {
LK.showGameOver(); // Show game over and reset
} else {
// Player still has lives.
}
}
lastCharacterIntersectingAlien = currentCharacterIntersectingAlien;
} else {
lastCharacterIntersectingAlien = false; // Reset if alien or character is not active for collision
}
// Make the key follow the player if collected
if (hasKey && keyInstance && character && character.visible) {
// Position key slightly above the player character
var keyAssetGraphics = keyInstance.children[0]; // Assuming asset is the first child
var keyHeight = keyAssetGraphics ? keyAssetGraphics.height : 80; // Use actual or default height
var playerCharGraphics = character.children[0];
var playerHeight = playerCharGraphics ? playerCharGraphics.height : 100;
keyInstance.x = character.x;
keyInstance.y = character.y - playerHeight / 2 - keyHeight / 2 - 10; // Adjust offset as needed
}
// Check for player collision with door if player has the key
var currentCharacterIntersectingDoor = false; // Local var for current frame's intersection state with the door
if (doorInstance && doorInstance.visible && character && character.visible && hasKey) {
// Ensure door, character are valid and visible, and player has the key
currentCharacterIntersectingDoor = character.intersects(doorInstance);
if (!characterLastIntersectingDoor && currentCharacterIntersectingDoor) {
// Check for the start of an intersection
// Intersection just started
doorInstance.visible = false; // "Opens" the door by making it invisible
if (keyInstance && keyInstance.visible) {
// If key exists and is visible
keyInstance.visible = false; // Make the key invisible as it has been "used"
}
LK.showYouWin(); // Player with key + door collision = win (transition to "new room")
}
}
// Update the 'last intersecting' state for the door for the next frame.
// This is crucial for detecting only the *initial* moment of intersection.
if (doorInstance && character) {
// Only update if door and character are still valid
characterLastIntersectingDoor = currentCharacterIntersectingDoor;
} else {
// If door or character becomes invalid (e.g., destroyed), reset the tracking state.
characterLastIntersectingDoor = false;
}
// Fire a bullet periodically (every 15 ticks = ~4 times per second)
if (LK.ticks % 15 == 0) {
var newBullet = new Bullet();
// We always keep track of last and current values
newBullet.x = character.x;
newBullet.y = character.y;
newBullet.lastY = newBullet.y; // Initialize lastY for tracking changes on Y
newBullet.lastIntersectingAlien = newBullet.intersects(alien); // Initialize for intersection tracking
bullets.push(newBullet);
game.addChild(newBullet);
LK.getSound('shoot').play(); // Play shoot sound
}
};
// Play background music
LK.playMusic('bgmusic');
A blue demon alien. In-Game asset. High contrast. No shadows
The character is a little boy that is sad and 17 years old. In-Game asset. 2d. High contrast. No shadows. Kid
Key. In-Game asset. High contrast. No shadows. 2d
Door. In-Game asset. No shadows. 2d
A note that says dear player I ate classmates from alien. In-Game asset. High contrast. No shadows