/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Define a class for enemies var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.update = function () { // Track last position for collision detection self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; self.x -= self.speed; if (self.x < -50) { self.destroy(); } }; }); // Define a class for joystick controls var Joystick = Container.expand(function () { var self = Container.call(this); // Create outer circle var outerCircle = LK.getAsset('button', { width: 300, height: 300, color: 0x000000, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); // Create inner circle (the stick) var innerCircle = LK.getAsset('button', { width: 150, height: 150, color: 0x3498db, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.addChild(outerCircle); self.addChild(innerCircle); self.active = false; self.startX = 0; self.startY = 0; self.deltaX = 0; self.deltaY = 0; self.maxDistance = 100; // Max distance the joystick can move self.down = function (x, y) { self.active = true; self.startX = x; self.startY = y; innerCircle.x = 0; innerCircle.y = 0; }; self.move = function (x, y) { if (self.active) { // Calculate delta from start position self.deltaX = x - self.startX; self.deltaY = y - self.startY; // Calculate distance var distance = Math.sqrt(self.deltaX * self.deltaX + self.deltaY * self.deltaY); // Normalize if distance exceeds max if (distance > self.maxDistance) { self.deltaX = self.deltaX / distance * self.maxDistance; self.deltaY = self.deltaY / distance * self.maxDistance; } // Update inner circle position innerCircle.x = self.deltaX; innerCircle.y = self.deltaY; } }; self.up = function () { self.active = false; self.deltaX = 0; self.deltaY = 0; innerCircle.x = 0; innerCircle.y = 0; }; return self; }); // Define a class for the mobile jump button var MobileButton = Container.expand(function () { var self = Container.call(this); // Create the button shape var button = new Container(); var buttonBg = LK.getAsset('button', { width: 200, height: 200, color: 0x3498db, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); button.addChild(buttonBg); // Add jump text var jumpText = new Text2("JUMP", { size: 50, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); jumpText.anchor.set(0.5, 0.5); button.addChild(jumpText); self.addChild(button); // Handle touch events self.down = function () { buttonBg.alpha = 0.7; if (player && typeof player.jump === 'function') { player.jump(); } }; self.up = function () { buttonBg.alpha = 1; }; return self; }); // Define a class for pause menu items var PauseMenuItem = Container.expand(function () { var self = Container.call(this); self.createItem = function (text, y, callback) { var menuText = new Text2(text, { size: 70, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); menuText.anchor.set(0.5, 0.5); menuText.y = y; self.addChild(menuText); self.down = function () { if (callback) { callback(); } }; return self; }; return self; }); //<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); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.jumpHeight = 40; self.isJumping = false; self.velocityY = 0; self.velocityX = 0; self.maxSpeed = 10; self.update = function () { // Track last position for collision detection self.lastX = self.x; self.lastY = self.y; // Apply horizontal movement self.x += self.velocityX; // Keep player within screen bounds if (self.x < 100) { self.x = 100; } if (self.x > 2048 - 100) { self.x = 2048 - 100; } if (self.isJumping) { self.y += self.velocityY; self.velocityY += 0.7; // Decreased gravity effect by 30% if (self.y >= 2732 / 2) { // Ground level self.y = 2732 / 2; self.isJumping = false; self.velocityY = 0; } } // Check for keyboard 's' key press for crouching only when not jumping if (!self.isJumping) { if (LK.isKeyDown && LK.isKeyDown('s')) { self.crouch(); } else if (self.isCrouching) { self.standUp(); // Stand up when 's' key is released } // Removed the else condition that would stand up } }; self.jump = function () { if (!self.isJumping && !self.isCrouching) { self.isJumping = true; self.velocityY = -self.jumpHeight; } }; self.isCrouching = false; self.crouch = function () { if (!self.isCrouching && !self.isJumping) { self.isCrouching = true; // Stop any existing tweens tween.stop(playerGraphics.scale, { y: true }); tween.stop(self, { y: true }); // Animate player crouching with tween tween(playerGraphics.scale, { y: 0.5 }, { duration: 200, easing: tween.easeOut }); // Move player down to compensate for height reduction with animation tween(self, { y: self.y + playerGraphics.height * 0.25 }, { duration: 200, easing: tween.easeOut }); } }; self.standUp = function () { if (self.isCrouching) { self.isCrouching = false; // Stop any existing tweens tween.stop(playerGraphics.scale, { y: true }); tween.stop(self, { y: true }); // Animate player standing up with tween tween(playerGraphics.scale, { y: 1 }, { duration: 200, easing: tween.easeOut }); // Move player back up to original position with animation tween(self, { y: self.y - playerGraphics.height * 0.25 }, { duration: 200, easing: tween.easeOut }); } }; self.moveWithJoystick = function (deltaX, deltaY) { // Normalize the input to proper speed var normalizedX = deltaX / 100; // Based on maxDistance in Joystick var normalizedY = deltaY / 100; // Based on maxDistance in Joystick // Set velocity based on joystick position self.velocityX = normalizedX * self.maxSpeed; // Handle crouching based on joystick Y position (down), only when not jumping if (!self.isJumping) { if (normalizedY > 0.5) { self.crouch(); } else if (normalizedY <= 0.5 && self.isCrouching) { self.standUp(); // Stand up when joystick is not pushed down } // Removed the else condition that would stand up } // Optional: Make the character face the direction it's moving if (normalizedX > 0) { playerGraphics.scale.x = 1; // Face right } else if (normalizedX < 0) { playerGraphics.scale.x = -1; // Face left } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Make background fit the screen properly var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 })); background.x = 2048 / 2; background.y = 2732 / 2; // Game configuration var gameConfig = { touchControlsEnabled: true }; // Check if there's a stored preference for touch controls if (storage && storage.touchControlsEnabled !== undefined) { gameConfig.touchControlsEnabled = storage.touchControlsEnabled; } // Initialize player var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2732 / 2; // Initialize enemies var enemies = []; var enemySpawnInterval = 100; var enemySpawnCounter = 0; // Create a new Text2 object to display the score with better mobile visibility var scoreText = new Text2('Score: 0', { size: 120, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 5 }); // Add the score text to the game GUI at the top center of the screen // Anchoring properly for responsive display scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Handle game updates game.update = function () { player.update(); // Reset player velocity if joystick is not active if (!joystick.active) { player.velocityX = 0; } // Spawn enemies (only if player is not crouching) enemySpawnCounter++; if (enemySpawnCounter >= enemySpawnInterval && !player.isCrouching) { var enemy = new Enemy(); enemy.x = 2048; enemy.y = 2732 / 2; enemies.push(enemy); game.addChild(enemy); // Randomize the spawn interval for the next enemy enemySpawnInterval = Math.floor(Math.random() * 150) + 50; enemySpawnCounter = 0; } // Update enemies with better collision detection for (var j = enemies.length - 1; j >= 0; j--) { enemies[j].update(); // More precise collision detection if (player.intersects(enemies[j])) { if (!enemies[j].lastWasIntersecting) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } enemies[j].lastWasIntersecting = true; } else { enemies[j].lastWasIntersecting = false; // Check if player passed the enemy if (player.x > enemies[j].x && !enemies[j].passed) { enemies[j].passed = true; LK.setScore(LK.getScore() + 1); scoreText.setText(LK.getScore()); // Visual feedback when scoring var pointText = new Text2('+1', { size: 60, fill: 0xFFFFFF }); pointText.x = enemies[j].x; pointText.y = enemies[j].y - 100; game.addChild(pointText); // Animate and remove the +1 text LK.setTimeout(function () { pointText.destroy(); }, 1000); } } } }; // Custom pause handler LK.on('pause', function () { // Create touch controls toggle menu item var toggleItem = new PauseMenuItem().createItem(gameConfig.touchControlsEnabled ? "Disable Touch Controls" : "Enable Touch Controls", 200, function () { // Toggle touch controls setting gameConfig.touchControlsEnabled = !gameConfig.touchControlsEnabled; // Save setting in storage if (storage) { storage.touchControlsEnabled = gameConfig.touchControlsEnabled; } // Update button visibility when setting changes updateButtonVisibility(); // Resume game after changing setting LK.resumeGame(); }); // Position the menu item in the center of the screen toggleItem.x = 2048 / 2; toggleItem.y = 2732 / 2; // Add to pause menu LK.gui.center.addChild(toggleItem); }); // Create joystick for movement var joystick = new Joystick(); joystick.x = 300; // Position on bottom left joystick.y = 2732 - 300; game.addChild(joystick); // Create mobile jump button var mobileButton = new MobileButton(); mobileButton.x = 2048 - 200; // Position on bottom right mobileButton.y = 2732 - 200; game.addChild(mobileButton); // Function to update mobile controls visibility based on settings function updateButtonVisibility() { mobileButton.visible = gameConfig.touchControlsEnabled; joystick.visible = gameConfig.touchControlsEnabled; } // Setup keyboard input handling if not already present if (!LK.isKeyDown) { LK.isKeyDown = function () { var keysDown = {}; LK.on('keydown', function (e) { keysDown[e.key.toLowerCase()] = true; }); LK.on('keyup', function (e) { keysDown[e.key.toLowerCase()] = false; }); return function (key) { return !!keysDown[key.toLowerCase()]; }; }(); } // Initial visibility updateButtonVisibility(); // Handle player jump with improved controls for mobile game.down = function (x, y, obj) { // Already handled by the button's down event when touch controls enabled // For anywhere else on screen: only jump when touch controls are enabled AND not pressing the button if (gameConfig.touchControlsEnabled && obj.event && obj.event.target !== mobileButton && obj.event.target !== joystick) { player.jump(); } }; // Add move handler for joystick controls game.move = function (x, y, obj) { if (gameConfig.touchControlsEnabled && joystick.active) { player.moveWithJoystick(joystick.deltaX, joystick.deltaY); } }; // Initialize the score to zero scoreText.setText('0'); // Make score text more visible on mobile screens scoreText.size = 120;
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Define a class for enemies
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.update = function () {
// Track last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
self.x -= self.speed;
if (self.x < -50) {
self.destroy();
}
};
});
// Define a class for joystick controls
var Joystick = Container.expand(function () {
var self = Container.call(this);
// Create outer circle
var outerCircle = LK.getAsset('button', {
width: 300,
height: 300,
color: 0x000000,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
// Create inner circle (the stick)
var innerCircle = LK.getAsset('button', {
width: 150,
height: 150,
color: 0x3498db,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(outerCircle);
self.addChild(innerCircle);
self.active = false;
self.startX = 0;
self.startY = 0;
self.deltaX = 0;
self.deltaY = 0;
self.maxDistance = 100; // Max distance the joystick can move
self.down = function (x, y) {
self.active = true;
self.startX = x;
self.startY = y;
innerCircle.x = 0;
innerCircle.y = 0;
};
self.move = function (x, y) {
if (self.active) {
// Calculate delta from start position
self.deltaX = x - self.startX;
self.deltaY = y - self.startY;
// Calculate distance
var distance = Math.sqrt(self.deltaX * self.deltaX + self.deltaY * self.deltaY);
// Normalize if distance exceeds max
if (distance > self.maxDistance) {
self.deltaX = self.deltaX / distance * self.maxDistance;
self.deltaY = self.deltaY / distance * self.maxDistance;
}
// Update inner circle position
innerCircle.x = self.deltaX;
innerCircle.y = self.deltaY;
}
};
self.up = function () {
self.active = false;
self.deltaX = 0;
self.deltaY = 0;
innerCircle.x = 0;
innerCircle.y = 0;
};
return self;
});
// Define a class for the mobile jump button
var MobileButton = Container.expand(function () {
var self = Container.call(this);
// Create the button shape
var button = new Container();
var buttonBg = LK.getAsset('button', {
width: 200,
height: 200,
color: 0x3498db,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
button.addChild(buttonBg);
// Add jump text
var jumpText = new Text2("JUMP", {
size: 50,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
jumpText.anchor.set(0.5, 0.5);
button.addChild(jumpText);
self.addChild(button);
// Handle touch events
self.down = function () {
buttonBg.alpha = 0.7;
if (player && typeof player.jump === 'function') {
player.jump();
}
};
self.up = function () {
buttonBg.alpha = 1;
};
return self;
});
// Define a class for pause menu items
var PauseMenuItem = Container.expand(function () {
var self = Container.call(this);
self.createItem = function (text, y, callback) {
var menuText = new Text2(text, {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
menuText.anchor.set(0.5, 0.5);
menuText.y = y;
self.addChild(menuText);
self.down = function () {
if (callback) {
callback();
}
};
return self;
};
return self;
});
//<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);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.velocityX = 0;
self.maxSpeed = 10;
self.update = function () {
// Track last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Apply horizontal movement
self.x += self.velocityX;
// Keep player within screen bounds
if (self.x < 100) {
self.x = 100;
}
if (self.x > 2048 - 100) {
self.x = 2048 - 100;
}
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.7; // Decreased gravity effect by 30%
if (self.y >= 2732 / 2) {
// Ground level
self.y = 2732 / 2;
self.isJumping = false;
self.velocityY = 0;
}
}
// Check for keyboard 's' key press for crouching only when not jumping
if (!self.isJumping) {
if (LK.isKeyDown && LK.isKeyDown('s')) {
self.crouch();
} else if (self.isCrouching) {
self.standUp(); // Stand up when 's' key is released
}
// Removed the else condition that would stand up
}
};
self.jump = function () {
if (!self.isJumping && !self.isCrouching) {
self.isJumping = true;
self.velocityY = -self.jumpHeight;
}
};
self.isCrouching = false;
self.crouch = function () {
if (!self.isCrouching && !self.isJumping) {
self.isCrouching = true;
// Stop any existing tweens
tween.stop(playerGraphics.scale, {
y: true
});
tween.stop(self, {
y: true
});
// Animate player crouching with tween
tween(playerGraphics.scale, {
y: 0.5
}, {
duration: 200,
easing: tween.easeOut
});
// Move player down to compensate for height reduction with animation
tween(self, {
y: self.y + playerGraphics.height * 0.25
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.standUp = function () {
if (self.isCrouching) {
self.isCrouching = false;
// Stop any existing tweens
tween.stop(playerGraphics.scale, {
y: true
});
tween.stop(self, {
y: true
});
// Animate player standing up with tween
tween(playerGraphics.scale, {
y: 1
}, {
duration: 200,
easing: tween.easeOut
});
// Move player back up to original position with animation
tween(self, {
y: self.y - playerGraphics.height * 0.25
}, {
duration: 200,
easing: tween.easeOut
});
}
};
self.moveWithJoystick = function (deltaX, deltaY) {
// Normalize the input to proper speed
var normalizedX = deltaX / 100; // Based on maxDistance in Joystick
var normalizedY = deltaY / 100; // Based on maxDistance in Joystick
// Set velocity based on joystick position
self.velocityX = normalizedX * self.maxSpeed;
// Handle crouching based on joystick Y position (down), only when not jumping
if (!self.isJumping) {
if (normalizedY > 0.5) {
self.crouch();
} else if (normalizedY <= 0.5 && self.isCrouching) {
self.standUp(); // Stand up when joystick is not pushed down
}
// Removed the else condition that would stand up
}
// Optional: Make the character face the direction it's moving
if (normalizedX > 0) {
playerGraphics.scale.x = 1; // Face right
} else if (normalizedX < 0) {
playerGraphics.scale.x = -1; // Face left
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Make background fit the screen properly
var background = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
}));
background.x = 2048 / 2;
background.y = 2732 / 2;
// Game configuration
var gameConfig = {
touchControlsEnabled: true
};
// Check if there's a stored preference for touch controls
if (storage && storage.touchControlsEnabled !== undefined) {
gameConfig.touchControlsEnabled = storage.touchControlsEnabled;
}
// Initialize player
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 / 2;
// Initialize enemies
var enemies = [];
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
// Create a new Text2 object to display the score with better mobile visibility
var scoreText = new Text2('Score: 0', {
size: 120,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 5
});
// Add the score text to the game GUI at the top center of the screen
// Anchoring properly for responsive display
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Handle game updates
game.update = function () {
player.update();
// Reset player velocity if joystick is not active
if (!joystick.active) {
player.velocityX = 0;
}
// Spawn enemies (only if player is not crouching)
enemySpawnCounter++;
if (enemySpawnCounter >= enemySpawnInterval && !player.isCrouching) {
var enemy = new Enemy();
enemy.x = 2048;
enemy.y = 2732 / 2;
enemies.push(enemy);
game.addChild(enemy);
// Randomize the spawn interval for the next enemy
enemySpawnInterval = Math.floor(Math.random() * 150) + 50;
enemySpawnCounter = 0;
}
// Update enemies with better collision detection
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
// More precise collision detection
if (player.intersects(enemies[j])) {
if (!enemies[j].lastWasIntersecting) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
enemies[j].lastWasIntersecting = true;
} else {
enemies[j].lastWasIntersecting = false;
// Check if player passed the enemy
if (player.x > enemies[j].x && !enemies[j].passed) {
enemies[j].passed = true;
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
// Visual feedback when scoring
var pointText = new Text2('+1', {
size: 60,
fill: 0xFFFFFF
});
pointText.x = enemies[j].x;
pointText.y = enemies[j].y - 100;
game.addChild(pointText);
// Animate and remove the +1 text
LK.setTimeout(function () {
pointText.destroy();
}, 1000);
}
}
}
};
// Custom pause handler
LK.on('pause', function () {
// Create touch controls toggle menu item
var toggleItem = new PauseMenuItem().createItem(gameConfig.touchControlsEnabled ? "Disable Touch Controls" : "Enable Touch Controls", 200, function () {
// Toggle touch controls setting
gameConfig.touchControlsEnabled = !gameConfig.touchControlsEnabled;
// Save setting in storage
if (storage) {
storage.touchControlsEnabled = gameConfig.touchControlsEnabled;
}
// Update button visibility when setting changes
updateButtonVisibility();
// Resume game after changing setting
LK.resumeGame();
});
// Position the menu item in the center of the screen
toggleItem.x = 2048 / 2;
toggleItem.y = 2732 / 2;
// Add to pause menu
LK.gui.center.addChild(toggleItem);
});
// Create joystick for movement
var joystick = new Joystick();
joystick.x = 300; // Position on bottom left
joystick.y = 2732 - 300;
game.addChild(joystick);
// Create mobile jump button
var mobileButton = new MobileButton();
mobileButton.x = 2048 - 200; // Position on bottom right
mobileButton.y = 2732 - 200;
game.addChild(mobileButton);
// Function to update mobile controls visibility based on settings
function updateButtonVisibility() {
mobileButton.visible = gameConfig.touchControlsEnabled;
joystick.visible = gameConfig.touchControlsEnabled;
}
// Setup keyboard input handling if not already present
if (!LK.isKeyDown) {
LK.isKeyDown = function () {
var keysDown = {};
LK.on('keydown', function (e) {
keysDown[e.key.toLowerCase()] = true;
});
LK.on('keyup', function (e) {
keysDown[e.key.toLowerCase()] = false;
});
return function (key) {
return !!keysDown[key.toLowerCase()];
};
}();
}
// Initial visibility
updateButtonVisibility();
// Handle player jump with improved controls for mobile
game.down = function (x, y, obj) {
// Already handled by the button's down event when touch controls enabled
// For anywhere else on screen: only jump when touch controls are enabled AND not pressing the button
if (gameConfig.touchControlsEnabled && obj.event && obj.event.target !== mobileButton && obj.event.target !== joystick) {
player.jump();
}
};
// Add move handler for joystick controls
game.move = function (x, y, obj) {
if (gameConfig.touchControlsEnabled && joystick.active) {
player.moveWithJoystick(joystick.deltaX, joystick.deltaY);
}
};
// Initialize the score to zero
scoreText.setText('0');
// Make score text more visible on mobile screens
scoreText.size = 120;