/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Block obstacle var Block = Container.expand(function () { var self = Container.call(this); var blockGfx = self.attachAsset('block', { anchorX: 0.5, anchorY: 1 }); self.width = blockGfx.width; self.height = blockGfx.height; self.type = 'block'; self.update = function () { self.x -= obstacleSpeed; }; return self; }); // Player Cube var Cube = Container.expand(function () { var self = Container.call(this); var cubeGfx = self.attachAsset('cube', { anchorX: 0.5, anchorY: 1 }); self.width = cubeGfx.width; self.height = cubeGfx.height; self.velY = 0; self.isOnGround = false; // Jump method self.jump = function () { if (self.isOnGround) { self.velY = -36; // Increased jump velocity for higher jump self.isOnGround = false; } }; // Update method self.update = function () { // Gravity self.velY += 2.1; // Slightly increased gravity to balance higher jump arc if (self.velY > 60) self.velY = 60; self.y += self.velY; // Check for landing on top of a block self.isOnGround = false; for (var i = 0; i < obstacles.length; ++i) { var obs = obstacles[i]; if (obs.type === 'block') { // Check if cube is falling and feet are just above the block, and horizontally overlapping var cubeBottom = self.y; var prevCubeBottom = self.y - self.velY; var blockTop = obs.y - obs.height; var blockLeft = obs.x - obs.width / 2; var blockRight = obs.x + obs.width / 2; var cubeLeft = self.x - self.width / 2; var cubeRight = self.x + self.width / 2; if (self.velY >= 0 && prevCubeBottom <= blockTop && cubeBottom >= blockTop && cubeRight > blockLeft && cubeLeft < blockRight) { self.y = blockTop; self.velY = 0; self.isOnGround = true; break; } } } // Prevent falling below ground if (self.y > groundY) { self.y = groundY; self.velY = 0; self.isOnGround = true; } }; return self; }); // Flying obstacle for flying section var FlyingObstacle = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('spike', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.type = 'flyingObstacle'; self.passed = false; self.lastX = 0; self.update = function () { self.x -= flyingObstacleSpeed; }; return self; }); // Minicoin collectible var Minicoin = Container.expand(function () { var self = Container.call(this); var coinGfx = self.attachAsset('minicoin', { anchorX: 0.5, anchorY: 1 }); self.width = coinGfx.width; self.height = coinGfx.height; self.type = 'minicoin'; self.collected = false; self.update = function () { self.x -= obstacleSpeed; }; return self; }); // Ship player for flying section var Ship = Container.expand(function () { var self = Container.call(this); var shipGfx = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); self.width = shipGfx.width; self.height = shipGfx.height; self.velY = 0; self.targetY = 0; self.isFlying = true; self.lastY = 0; self.update = function () { // Smoothly move toward targetY (touch/move position) var dy = self.targetY - self.y; self.velY = dy * 0.18; self.y += self.velY; // Clamp to screen if (self.y < 100 + self.height / 2) self.y = 100 + self.height / 2; if (self.y > groundY - 200) self.y = groundY - 200; }; return self; }); // ShopIcon class for shop UI var ShopIcon = Container.expand(function () { var self = Container.call(this); self.iconId = null; self.price = 0; self.purchased = false; self.selected = false; var iconGfx = null; var priceTxt = null; var selectBorder = null; // Initialize the icon display self.initIcon = function (iconId, price, purchased, selected) { self.iconId = iconId; self.price = price; self.purchased = purchased; self.selected = selected; if (iconGfx) { self.removeChild(iconGfx); } iconGfx = self.attachAsset(iconId, { anchorX: 0.5, anchorY: 0.5 }); iconGfx.x = 0; iconGfx.y = 0; if (priceTxt) { self.removeChild(priceTxt); } priceTxt = new Text2(purchased ? selected ? "Selected" : "Owned" : price + " pts", { size: 48, fill: purchased ? selected ? 0x44bb44 : 0x888888 : 0x222222 }); priceTxt.anchor.set(0.5, 0); priceTxt.x = 0; priceTxt.y = 70; self.addChild(priceTxt); if (selectBorder) { self.removeChild(selectBorder); } selectBorder = null; if (selected) { selectBorder = LK.getAsset('block', { anchorX: 0.5, anchorY: 0.5 }); selectBorder.width = 140; selectBorder.height = 140; selectBorder.tint = 0x44bb44; selectBorder.alpha = 0.3; selectBorder.x = 0; selectBorder.y = 0; self.addChild(selectBorder); self.setChildIndex(selectBorder, 0); } }; // Handle icon tap: buy or select self.down = function (x, y, obj) { if (!self.purchased && score >= self.price) { score -= self.price; scoreTxt.setText(score); self.purchased = true; // Save purchase storage['shop_' + self.iconId] = true; } if (self.purchased) { // Deselect all others for (var i = 0; i < shopIcons.length; ++i) { shopIcons[i].selected = false; shopIcons[i].initIcon(shopIcons[i].iconId, shopIcons[i].price, !!storage['shop_' + shopIcons[i].iconId] || shopIcons[i].price === 0, false); } self.selected = true; self.initIcon(self.iconId, self.price, self.purchased, true); // Save selection storage['selected_icon'] = self.iconId; // Change player icon setPlayerIcon(self.iconId); } }; return self; }); // Spike obstacle var Spike = Container.expand(function () { var self = Container.call(this); var spikeGfx = self.attachAsset('spike', { anchorX: 0.5, anchorY: 1 }); self.width = spikeGfx.width; self.height = spikeGfx.height; self.type = 'spike'; self.update = function () { self.x -= obstacleSpeed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf0f0f0 }); /**** * Game Code ****/ // Removed old cube asset and re-added it // Constants // Cube player // Ground // Spike obstacle // Block obstacle // New ship asset // Deleted and re-added player asset var groundHeight = 80; var groundY = 2732 - groundHeight; var startX = 400; var startY = groundY; var obstacleSpeed = 12; var minObstacleGap = 420; var maxObstacleGap = 700; var lastObstacleX = 0; var score = 0; var gameStarted = false; // Arrays var obstacles = []; // --- Flying section variables --- var flyingSectionStarted = false; var flyingSectionTriggered = false; var flyingObstacles = []; var ship = null; var flyingObstacleSpeed = 16; var flyingSectionStartX = 1800; // X position to trigger flying section var flyingSectionEndX = 400; // X position to end flying section (ship lands) var flyingSectionDuration = 1200; // px to fly var flyingSectionScore = 0; var flyingSectionMaxScore = 10; var flyingSectionProgress = 0; var flyingSectionActive = false; var flyingSectionShipStartY = 1000; var flyingSectionShipStartX = 400; var flyingSectionShipEndX = 1800; var flyingSectionShipTargetX = 1800; var flyingSectionShipLanded = false; var flyingSectionObstacleGap = 320; var flyingSectionLastObstacleX = 0; var flyingSectionPassedObstacles = 0; // Add background var background = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); background.x = 0; background.y = 0; game.addChild(background); // Add ground var ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0 }); ground.x = 0; ground.y = groundY; game.addChild(ground); // Add player cube (deleted and re-added) var cube = new Cube(); cube.x = startX; cube.y = startY; game.addChild(cube); // Shop UI variables var shopIcons = []; var shopBg = LK.getAsset('block', { anchorX: 0.5, anchorY: 0.5 }); shopBg.width = 900; shopBg.height = 400; shopBg.x = 2048 / 2; shopBg.y = 2732 / 2; shopBg.tint = 0xffffff; shopBg.alpha = 0.97; shopBg.visible = false; var shopTitle = new Text2('Shop', { size: 100, fill: 0x222222 }); shopTitle.anchor.set(0.5, 0); shopTitle.x = 2048 / 2; shopTitle.y = 2732 / 2 - 180; shopTitle.visible = false; var closeShopBtn = new Text2('Close', { size: 70, fill: 0xcc2222 }); closeShopBtn.anchor.set(0.5, 0.5); closeShopBtn.x = 2048 / 2 + 350; closeShopBtn.y = 2732 / 2 - 170; closeShopBtn.visible = false; closeShopBtn.down = function (x, y, obj) { showShop(false); }; LK.gui.center.addChild(shopBg); LK.gui.center.addChild(shopTitle); LK.gui.center.addChild(closeShopBtn); // Shop icon data var iconShopData = [{ iconId: 'icon1', price: 0 }, // Default, free { iconId: 'icon2', price: 50 }, { iconId: 'icon3', price: 100 }]; // Helper: set player icon function setPlayerIcon(iconId) { if (cube && cube.children && cube.children.length > 0) { // Remove old icon for (var i = cube.children.length - 1; i >= 0; --i) { var ch = cube.children[i]; if (ch.assetId && (ch.assetId === 'cube' || ch.assetId === 'icon1' || ch.assetId === 'icon2' || ch.assetId === 'icon3')) { cube.removeChild(ch); } } // Add new icon var newIcon = cube.attachAsset(iconId, { anchorX: 0.5, anchorY: 1 }); newIcon.x = 0; newIcon.y = 0; cube.width = newIcon.width; cube.height = newIcon.height; } } // Helper: show/hide shop function showShop(show) { shopBg.visible = show; shopTitle.visible = show; closeShopBtn.visible = show; for (var i = 0; i < shopIcons.length; ++i) { shopIcons[i].visible = show; } if (show) { gameStarted = false; } } // Create shop icons for (var i = 0; i < iconShopData.length; ++i) { var iconId = iconShopData[i].iconId; var price = iconShopData[i].price; var purchased = !!storage['shop_' + iconId] || price === 0; var selected = false; var selectedIconId = storage['selected_icon']; if (!selectedIconId && price === 0) selected = true; if (selectedIconId && selectedIconId === iconId) selected = true; var shopIcon = new ShopIcon(); shopIcon.x = 2048 / 2 - 250 + i * 250; shopIcon.y = 2732 / 2 + 40; shopIcon.initIcon(iconId, price, purchased, selected); shopIcon.visible = false; LK.gui.center.addChild(shopIcon); shopIcons.push(shopIcon); if (selected) { setPlayerIcon(iconId); } } // Shop button var shopBtn = new Text2('Shop', { size: 80, fill: 0x2266cc }); shopBtn.anchor.set(0.5, 0.5); shopBtn.x = 2048 / 2; shopBtn.y = 2732 / 2; shopBtn.down = function (x, y, obj) { showShop(true); // Optionally, you could pause the game here if needed, but shop UI already disables gameplay. }; LK.gui.center.addChild(shopBtn); // Score text var scoreTxt = new Text2('0', { size: 120, fill: 0x222222 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Progress bar variables var progressBarBg = LK.getAsset('block', { anchorX: 0, anchorY: 0 }); progressBarBg.width = 800; progressBarBg.height = 40; progressBarBg.x = 624; // center horizontally (2048-800)/2 progressBarBg.y = 160; progressBarBg.tint = 0xcccccc; var progressBarFill = LK.getAsset('block', { anchorX: 0, anchorY: 0 }); progressBarFill.width = 0; progressBarFill.height = 40; progressBarFill.x = 624; progressBarFill.y = 160; progressBarFill.tint = 0x44bb44; LK.gui.top.addChild(progressBarBg); LK.gui.top.addChild(progressBarFill); var progressPercent = 0; var progressMax = 100; // 100% var progressPerScore = 2; // Each point increases progress by 2% var winShown = false; // Win text and replay button var winText = new Text2('You win!', { size: 180, fill: 0x228822 }); winText.anchor.set(0.5, 0.5); winText.x = 2048 / 2; winText.y = 2732 / 2 - 120; winText.visible = false; var replayBtn = new Text2('Replay', { size: 120, fill: 0x2266cc }); replayBtn.anchor.set(0.5, 0.5); replayBtn.x = 2048 / 2; replayBtn.y = 2732 / 2 + 80; replayBtn.visible = false; LK.gui.center.addChild(winText); LK.gui.center.addChild(replayBtn); // Replay handler replayBtn.down = function (x, y, obj) { if (winShown) { winText.visible = false; replayBtn.visible = false; winShown = false; resetGame(); gameStarted = true; LK.playMusic('Mad'); } }; // Helper: spawn obstacle function spawnObstacle() { // Randomly choose spike or block structure var type = Math.random() < 0.6 ? 'spike' : 'block'; if (type === 'spike') { var obs = new Spike(); obs.x = 2048 + 100; obs.y = groundY; obstacles.push(obs); game.addChild(obs); lastObstacleX = obs.x; } else { // Structure: always 1 block high for passable platforms var platformHeight = 1; var platformLength = Math.floor(Math.random() * 3) + 2; // 2 to 4 blocks long var baseX = 2048 + 100; var blockW = 120; var blockH = 120; var minicoinsOnTop = Math.random() < 0.8; // 80% chance to spawn coins for (var i = 0; i < platformLength; ++i) { // Only one block high var block = new Block(); block.x = baseX + i * blockW; block.y = groundY - 0 * blockH; obstacles.push(block); game.addChild(block); lastObstacleX = block.x; // Place minicoins on top of the structure if (minicoinsOnTop) { var coin = new Minicoin(); coin.x = baseX + i * blockW; coin.y = groundY - blockH - 10; // 10px above top block obstacles.push(coin); game.addChild(coin); } } // Place a single spike on a random block in the structure if (platformLength > 1) { var spikeIndex = Math.floor(Math.random() * platformLength); var spike = new Spike(); spike.x = baseX + spikeIndex * blockW; spike.y = groundY; obstacles.push(spike); game.addChild(spike); } } } // Helper: reset game state function resetGame() { // Remove obstacles for (var i = 0; i < obstacles.length; ++i) { obstacles[i].destroy(); } obstacles.length = 0; // Remove flying obstacles for (var i = 0; i < flyingObstacles.length; ++i) { flyingObstacles[i].destroy(); } flyingObstacles.length = 0; // Hide ship if (ship) { ship.visible = false; } cube.x = startX; cube.y = startY; cube.velY = 0; cube.isOnGround = true; lastObstacleX = 1200; score = 0; scoreTxt.setText(score); progressPercent = 0; progressBarFill.width = 0; winText.visible = false; replayBtn.visible = false; winShown = false; gameStarted = false; // Reset flying section state flyingSectionStarted = false; flyingSectionTriggered = false; flyingSectionActive = false; flyingSectionShipLanded = false; // Hide shop UI on reset showShop(false); // Update shop icons (in case of new purchases) for (var i = 0; i < shopIcons.length; ++i) { var iconId = shopIcons[i].iconId; var purchased = !!storage['shop_' + iconId] || iconShopData[i].price === 0; var selectedIconId = storage['selected_icon']; var selected = selectedIconId && selectedIconId === iconId || !selectedIconId && iconShopData[i].price === 0; shopIcons[i].initIcon(iconId, iconShopData[i].price, purchased, selected); } } // Start game on first tap game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; return; } // If in flying section, do nothing on tap if (flyingSectionActive) return; cube.jump(); }; // Ship control: move ship to touch/move Y in flying section game.move = function (x, y, obj) { if (flyingSectionActive && ship && ship.visible) { // Convert to local game coordinates if needed ship.targetY = y; } }; // Main update loop game.update = function () { if (!gameStarted || winShown) return; // --- FLYING SECTION TRIGGER --- if (!flyingSectionTriggered && score >= 15) { // Start flying section after 15 points flyingSectionTriggered = true; flyingSectionStarted = true; flyingSectionActive = true; // Hide cube, show ship cube.visible = false; if (!ship) { ship = new Ship(); ship.x = flyingSectionShipStartX; ship.y = flyingSectionShipStartY; game.addChild(ship); } ship.visible = true; ship.x = flyingSectionShipStartX; ship.y = flyingSectionShipStartY; ship.targetY = flyingSectionShipStartY; // Remove all ground obstacles for (var i = obstacles.length - 1; i >= 0; --i) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Reset flying obstacles for (var i = flyingObstacles.length - 1; i >= 0; --i) { flyingObstacles[i].destroy(); flyingObstacles.splice(i, 1); } flyingSectionLastObstacleX = 2048 + 200; flyingSectionPassedObstacles = 0; flyingSectionProgress = 0; flyingSectionScore = 0; flyingSectionShipLanded = false; } // --- FLYING SECTION ACTIVE --- if (flyingSectionActive) { // Update ship if (ship) { ship.update(); } // Move ship forward if (ship && !flyingSectionShipLanded) { ship.x += 10; if (ship.x > flyingSectionShipTargetX) ship.x = flyingSectionShipTargetX; } // Spawn flying obstacles if (flyingSectionLastObstacleX - ship.x < 1200) { var gap = flyingSectionObstacleGap + Math.random() * 180; var obs = new FlyingObstacle(); obs.x = flyingSectionLastObstacleX + gap; obs.y = 400 + Math.random() * (groundY - 600); flyingObstacles.push(obs); game.addChild(obs); flyingSectionLastObstacleX = obs.x; } // Update flying obstacles for (var i = flyingObstacles.length - 1; i >= 0; --i) { var obs = flyingObstacles[i]; obs.update(); // Remove if off screen if (obs.x < -200) { obs.destroy(); flyingObstacles.splice(i, 1); continue; } // Collision with ship if (ship && ship.intersects(obs)) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } // Score: passed obstacle if (!obs.passed && obs.x + obs.width / 2 < ship.x - ship.width / 2) { obs.passed = true; flyingSectionScore += 1; score += 2; scoreTxt.setText(score); // Progress bar progressPercent = Math.min(progressPercent + progressPerScore * 2, progressMax); progressBarFill.width = progressPercent / progressMax * 800; if (progressPercent >= progressMax && !winShown) { winShown = true; gameStarted = false; winText.visible = true; replayBtn.visible = true; } } } // End flying section after enough distance or obstacles if (ship && ship.x >= flyingSectionShipTargetX && !flyingSectionShipLanded) { flyingSectionShipLanded = true; flyingSectionActive = false; // Hide ship, show cube, reset cube position ship.visible = false; cube.visible = true; cube.x = ship.x; cube.y = groundY; cube.velY = 0; cube.isOnGround = true; // Remove all flying obstacles for (var i = flyingObstacles.length - 1; i >= 0; --i) { flyingObstacles[i].destroy(); flyingObstacles.splice(i, 1); } // Continue normal section, spawn obstacles ahead lastObstacleX = cube.x + 600; } return; } // Update player cube.update(); // Update obstacles for (var i = obstacles.length - 1; i >= 0; --i) { var obs = obstacles[i]; obs.update(); // Remove if off screen if (obs.x < -200) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection if (obs.type === 'minicoin') { if (!obs.collected && cube.intersects(obs)) { obs.collected = true; score += 5; // Minicoin gives 5 points scoreTxt.setText(score); // Play coin sound LK.getSound('Coin').play(); // Update progress progressPercent = Math.min(progressPercent + progressPerScore * 5, progressMax); progressBarFill.width = progressPercent / progressMax * 800; if (progressPercent >= progressMax && !winShown) { winShown = true; gameStarted = false; winText.visible = true; replayBtn.visible = true; // LK.pauseGame(); //{30} // Removed: not needed, LK handles game state on win } obs.destroy(); obstacles.splice(i, 1); continue; } } else { if (cube.intersects(obs)) { // Flash screen and game over LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } // Score: passed obstacle if (!obs.passed && obs.x + obs.width / 2 < cube.x - cube.width / 2) { obs.passed = true; score += 1; scoreTxt.setText(score); // Update progress progressPercent = Math.min(progressPercent + progressPerScore, progressMax); progressBarFill.width = progressPercent / progressMax * 800; if (progressPercent >= progressMax && !winShown) { winShown = true; gameStarted = false; winText.visible = true; replayBtn.visible = true; // LK.pauseGame(); //{3h} // Removed: not needed, LK handles game state on win } } } } // Spawn new obstacles if (obstacles.length === 0 || 2048 - lastObstacleX > minObstacleGap + Math.random() * (maxObstacleGap - minObstacleGap)) { spawnObstacle(); } }; // Reset game on game over LK.on('gameover', function () { resetGame(); LK.playMusic('Mad'); }); // Initial state resetGame(); // Play music asset when the game starts LK.playMusic('Mad'); // Shop icon assets (add more as needed)
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Block obstacle
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGfx = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 1
});
self.width = blockGfx.width;
self.height = blockGfx.height;
self.type = 'block';
self.update = function () {
self.x -= obstacleSpeed;
};
return self;
});
// Player Cube
var Cube = Container.expand(function () {
var self = Container.call(this);
var cubeGfx = self.attachAsset('cube', {
anchorX: 0.5,
anchorY: 1
});
self.width = cubeGfx.width;
self.height = cubeGfx.height;
self.velY = 0;
self.isOnGround = false;
// Jump method
self.jump = function () {
if (self.isOnGround) {
self.velY = -36; // Increased jump velocity for higher jump
self.isOnGround = false;
}
};
// Update method
self.update = function () {
// Gravity
self.velY += 2.1; // Slightly increased gravity to balance higher jump arc
if (self.velY > 60) self.velY = 60;
self.y += self.velY;
// Check for landing on top of a block
self.isOnGround = false;
for (var i = 0; i < obstacles.length; ++i) {
var obs = obstacles[i];
if (obs.type === 'block') {
// Check if cube is falling and feet are just above the block, and horizontally overlapping
var cubeBottom = self.y;
var prevCubeBottom = self.y - self.velY;
var blockTop = obs.y - obs.height;
var blockLeft = obs.x - obs.width / 2;
var blockRight = obs.x + obs.width / 2;
var cubeLeft = self.x - self.width / 2;
var cubeRight = self.x + self.width / 2;
if (self.velY >= 0 && prevCubeBottom <= blockTop && cubeBottom >= blockTop && cubeRight > blockLeft && cubeLeft < blockRight) {
self.y = blockTop;
self.velY = 0;
self.isOnGround = true;
break;
}
}
}
// Prevent falling below ground
if (self.y > groundY) {
self.y = groundY;
self.velY = 0;
self.isOnGround = true;
}
};
return self;
});
// Flying obstacle for flying section
var FlyingObstacle = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.type = 'flyingObstacle';
self.passed = false;
self.lastX = 0;
self.update = function () {
self.x -= flyingObstacleSpeed;
};
return self;
});
// Minicoin collectible
var Minicoin = Container.expand(function () {
var self = Container.call(this);
var coinGfx = self.attachAsset('minicoin', {
anchorX: 0.5,
anchorY: 1
});
self.width = coinGfx.width;
self.height = coinGfx.height;
self.type = 'minicoin';
self.collected = false;
self.update = function () {
self.x -= obstacleSpeed;
};
return self;
});
// Ship player for flying section
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGfx = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = shipGfx.width;
self.height = shipGfx.height;
self.velY = 0;
self.targetY = 0;
self.isFlying = true;
self.lastY = 0;
self.update = function () {
// Smoothly move toward targetY (touch/move position)
var dy = self.targetY - self.y;
self.velY = dy * 0.18;
self.y += self.velY;
// Clamp to screen
if (self.y < 100 + self.height / 2) self.y = 100 + self.height / 2;
if (self.y > groundY - 200) self.y = groundY - 200;
};
return self;
});
// ShopIcon class for shop UI
var ShopIcon = Container.expand(function () {
var self = Container.call(this);
self.iconId = null;
self.price = 0;
self.purchased = false;
self.selected = false;
var iconGfx = null;
var priceTxt = null;
var selectBorder = null;
// Initialize the icon display
self.initIcon = function (iconId, price, purchased, selected) {
self.iconId = iconId;
self.price = price;
self.purchased = purchased;
self.selected = selected;
if (iconGfx) {
self.removeChild(iconGfx);
}
iconGfx = self.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 0.5
});
iconGfx.x = 0;
iconGfx.y = 0;
if (priceTxt) {
self.removeChild(priceTxt);
}
priceTxt = new Text2(purchased ? selected ? "Selected" : "Owned" : price + " pts", {
size: 48,
fill: purchased ? selected ? 0x44bb44 : 0x888888 : 0x222222
});
priceTxt.anchor.set(0.5, 0);
priceTxt.x = 0;
priceTxt.y = 70;
self.addChild(priceTxt);
if (selectBorder) {
self.removeChild(selectBorder);
}
selectBorder = null;
if (selected) {
selectBorder = LK.getAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
selectBorder.width = 140;
selectBorder.height = 140;
selectBorder.tint = 0x44bb44;
selectBorder.alpha = 0.3;
selectBorder.x = 0;
selectBorder.y = 0;
self.addChild(selectBorder);
self.setChildIndex(selectBorder, 0);
}
};
// Handle icon tap: buy or select
self.down = function (x, y, obj) {
if (!self.purchased && score >= self.price) {
score -= self.price;
scoreTxt.setText(score);
self.purchased = true;
// Save purchase
storage['shop_' + self.iconId] = true;
}
if (self.purchased) {
// Deselect all others
for (var i = 0; i < shopIcons.length; ++i) {
shopIcons[i].selected = false;
shopIcons[i].initIcon(shopIcons[i].iconId, shopIcons[i].price, !!storage['shop_' + shopIcons[i].iconId] || shopIcons[i].price === 0, false);
}
self.selected = true;
self.initIcon(self.iconId, self.price, self.purchased, true);
// Save selection
storage['selected_icon'] = self.iconId;
// Change player icon
setPlayerIcon(self.iconId);
}
};
return self;
});
// Spike obstacle
var Spike = Container.expand(function () {
var self = Container.call(this);
var spikeGfx = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1
});
self.width = spikeGfx.width;
self.height = spikeGfx.height;
self.type = 'spike';
self.update = function () {
self.x -= obstacleSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf0f0f0
});
/****
* Game Code
****/
// Removed old cube asset and re-added it
// Constants
// Cube player
// Ground
// Spike obstacle
// Block obstacle
// New ship asset
// Deleted and re-added player asset
var groundHeight = 80;
var groundY = 2732 - groundHeight;
var startX = 400;
var startY = groundY;
var obstacleSpeed = 12;
var minObstacleGap = 420;
var maxObstacleGap = 700;
var lastObstacleX = 0;
var score = 0;
var gameStarted = false;
// Arrays
var obstacles = [];
// --- Flying section variables ---
var flyingSectionStarted = false;
var flyingSectionTriggered = false;
var flyingObstacles = [];
var ship = null;
var flyingObstacleSpeed = 16;
var flyingSectionStartX = 1800; // X position to trigger flying section
var flyingSectionEndX = 400; // X position to end flying section (ship lands)
var flyingSectionDuration = 1200; // px to fly
var flyingSectionScore = 0;
var flyingSectionMaxScore = 10;
var flyingSectionProgress = 0;
var flyingSectionActive = false;
var flyingSectionShipStartY = 1000;
var flyingSectionShipStartX = 400;
var flyingSectionShipEndX = 1800;
var flyingSectionShipTargetX = 1800;
var flyingSectionShipLanded = false;
var flyingSectionObstacleGap = 320;
var flyingSectionLastObstacleX = 0;
var flyingSectionPassedObstacles = 0;
// Add background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
background.x = 0;
background.y = 0;
game.addChild(background);
// Add ground
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
});
ground.x = 0;
ground.y = groundY;
game.addChild(ground);
// Add player cube (deleted and re-added)
var cube = new Cube();
cube.x = startX;
cube.y = startY;
game.addChild(cube);
// Shop UI variables
var shopIcons = [];
var shopBg = LK.getAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
shopBg.width = 900;
shopBg.height = 400;
shopBg.x = 2048 / 2;
shopBg.y = 2732 / 2;
shopBg.tint = 0xffffff;
shopBg.alpha = 0.97;
shopBg.visible = false;
var shopTitle = new Text2('Shop', {
size: 100,
fill: 0x222222
});
shopTitle.anchor.set(0.5, 0);
shopTitle.x = 2048 / 2;
shopTitle.y = 2732 / 2 - 180;
shopTitle.visible = false;
var closeShopBtn = new Text2('Close', {
size: 70,
fill: 0xcc2222
});
closeShopBtn.anchor.set(0.5, 0.5);
closeShopBtn.x = 2048 / 2 + 350;
closeShopBtn.y = 2732 / 2 - 170;
closeShopBtn.visible = false;
closeShopBtn.down = function (x, y, obj) {
showShop(false);
};
LK.gui.center.addChild(shopBg);
LK.gui.center.addChild(shopTitle);
LK.gui.center.addChild(closeShopBtn);
// Shop icon data
var iconShopData = [{
iconId: 'icon1',
price: 0
},
// Default, free
{
iconId: 'icon2',
price: 50
}, {
iconId: 'icon3',
price: 100
}];
// Helper: set player icon
function setPlayerIcon(iconId) {
if (cube && cube.children && cube.children.length > 0) {
// Remove old icon
for (var i = cube.children.length - 1; i >= 0; --i) {
var ch = cube.children[i];
if (ch.assetId && (ch.assetId === 'cube' || ch.assetId === 'icon1' || ch.assetId === 'icon2' || ch.assetId === 'icon3')) {
cube.removeChild(ch);
}
}
// Add new icon
var newIcon = cube.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 1
});
newIcon.x = 0;
newIcon.y = 0;
cube.width = newIcon.width;
cube.height = newIcon.height;
}
}
// Helper: show/hide shop
function showShop(show) {
shopBg.visible = show;
shopTitle.visible = show;
closeShopBtn.visible = show;
for (var i = 0; i < shopIcons.length; ++i) {
shopIcons[i].visible = show;
}
if (show) {
gameStarted = false;
}
}
// Create shop icons
for (var i = 0; i < iconShopData.length; ++i) {
var iconId = iconShopData[i].iconId;
var price = iconShopData[i].price;
var purchased = !!storage['shop_' + iconId] || price === 0;
var selected = false;
var selectedIconId = storage['selected_icon'];
if (!selectedIconId && price === 0) selected = true;
if (selectedIconId && selectedIconId === iconId) selected = true;
var shopIcon = new ShopIcon();
shopIcon.x = 2048 / 2 - 250 + i * 250;
shopIcon.y = 2732 / 2 + 40;
shopIcon.initIcon(iconId, price, purchased, selected);
shopIcon.visible = false;
LK.gui.center.addChild(shopIcon);
shopIcons.push(shopIcon);
if (selected) {
setPlayerIcon(iconId);
}
}
// Shop button
var shopBtn = new Text2('Shop', {
size: 80,
fill: 0x2266cc
});
shopBtn.anchor.set(0.5, 0.5);
shopBtn.x = 2048 / 2;
shopBtn.y = 2732 / 2;
shopBtn.down = function (x, y, obj) {
showShop(true);
// Optionally, you could pause the game here if needed, but shop UI already disables gameplay.
};
LK.gui.center.addChild(shopBtn);
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Progress bar variables
var progressBarBg = LK.getAsset('block', {
anchorX: 0,
anchorY: 0
});
progressBarBg.width = 800;
progressBarBg.height = 40;
progressBarBg.x = 624; // center horizontally (2048-800)/2
progressBarBg.y = 160;
progressBarBg.tint = 0xcccccc;
var progressBarFill = LK.getAsset('block', {
anchorX: 0,
anchorY: 0
});
progressBarFill.width = 0;
progressBarFill.height = 40;
progressBarFill.x = 624;
progressBarFill.y = 160;
progressBarFill.tint = 0x44bb44;
LK.gui.top.addChild(progressBarBg);
LK.gui.top.addChild(progressBarFill);
var progressPercent = 0;
var progressMax = 100; // 100%
var progressPerScore = 2; // Each point increases progress by 2%
var winShown = false;
// Win text and replay button
var winText = new Text2('You win!', {
size: 180,
fill: 0x228822
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2 - 120;
winText.visible = false;
var replayBtn = new Text2('Replay', {
size: 120,
fill: 0x2266cc
});
replayBtn.anchor.set(0.5, 0.5);
replayBtn.x = 2048 / 2;
replayBtn.y = 2732 / 2 + 80;
replayBtn.visible = false;
LK.gui.center.addChild(winText);
LK.gui.center.addChild(replayBtn);
// Replay handler
replayBtn.down = function (x, y, obj) {
if (winShown) {
winText.visible = false;
replayBtn.visible = false;
winShown = false;
resetGame();
gameStarted = true;
LK.playMusic('Mad');
}
};
// Helper: spawn obstacle
function spawnObstacle() {
// Randomly choose spike or block structure
var type = Math.random() < 0.6 ? 'spike' : 'block';
if (type === 'spike') {
var obs = new Spike();
obs.x = 2048 + 100;
obs.y = groundY;
obstacles.push(obs);
game.addChild(obs);
lastObstacleX = obs.x;
} else {
// Structure: always 1 block high for passable platforms
var platformHeight = 1;
var platformLength = Math.floor(Math.random() * 3) + 2; // 2 to 4 blocks long
var baseX = 2048 + 100;
var blockW = 120;
var blockH = 120;
var minicoinsOnTop = Math.random() < 0.8; // 80% chance to spawn coins
for (var i = 0; i < platformLength; ++i) {
// Only one block high
var block = new Block();
block.x = baseX + i * blockW;
block.y = groundY - 0 * blockH;
obstacles.push(block);
game.addChild(block);
lastObstacleX = block.x;
// Place minicoins on top of the structure
if (minicoinsOnTop) {
var coin = new Minicoin();
coin.x = baseX + i * blockW;
coin.y = groundY - blockH - 10; // 10px above top block
obstacles.push(coin);
game.addChild(coin);
}
}
// Place a single spike on a random block in the structure
if (platformLength > 1) {
var spikeIndex = Math.floor(Math.random() * platformLength);
var spike = new Spike();
spike.x = baseX + spikeIndex * blockW;
spike.y = groundY;
obstacles.push(spike);
game.addChild(spike);
}
}
}
// Helper: reset game state
function resetGame() {
// Remove obstacles
for (var i = 0; i < obstacles.length; ++i) {
obstacles[i].destroy();
}
obstacles.length = 0;
// Remove flying obstacles
for (var i = 0; i < flyingObstacles.length; ++i) {
flyingObstacles[i].destroy();
}
flyingObstacles.length = 0;
// Hide ship
if (ship) {
ship.visible = false;
}
cube.x = startX;
cube.y = startY;
cube.velY = 0;
cube.isOnGround = true;
lastObstacleX = 1200;
score = 0;
scoreTxt.setText(score);
progressPercent = 0;
progressBarFill.width = 0;
winText.visible = false;
replayBtn.visible = false;
winShown = false;
gameStarted = false;
// Reset flying section state
flyingSectionStarted = false;
flyingSectionTriggered = false;
flyingSectionActive = false;
flyingSectionShipLanded = false;
// Hide shop UI on reset
showShop(false);
// Update shop icons (in case of new purchases)
for (var i = 0; i < shopIcons.length; ++i) {
var iconId = shopIcons[i].iconId;
var purchased = !!storage['shop_' + iconId] || iconShopData[i].price === 0;
var selectedIconId = storage['selected_icon'];
var selected = selectedIconId && selectedIconId === iconId || !selectedIconId && iconShopData[i].price === 0;
shopIcons[i].initIcon(iconId, iconShopData[i].price, purchased, selected);
}
}
// Start game on first tap
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
return;
}
// If in flying section, do nothing on tap
if (flyingSectionActive) return;
cube.jump();
};
// Ship control: move ship to touch/move Y in flying section
game.move = function (x, y, obj) {
if (flyingSectionActive && ship && ship.visible) {
// Convert to local game coordinates if needed
ship.targetY = y;
}
};
// Main update loop
game.update = function () {
if (!gameStarted || winShown) return;
// --- FLYING SECTION TRIGGER ---
if (!flyingSectionTriggered && score >= 15) {
// Start flying section after 15 points
flyingSectionTriggered = true;
flyingSectionStarted = true;
flyingSectionActive = true;
// Hide cube, show ship
cube.visible = false;
if (!ship) {
ship = new Ship();
ship.x = flyingSectionShipStartX;
ship.y = flyingSectionShipStartY;
game.addChild(ship);
}
ship.visible = true;
ship.x = flyingSectionShipStartX;
ship.y = flyingSectionShipStartY;
ship.targetY = flyingSectionShipStartY;
// Remove all ground obstacles
for (var i = obstacles.length - 1; i >= 0; --i) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Reset flying obstacles
for (var i = flyingObstacles.length - 1; i >= 0; --i) {
flyingObstacles[i].destroy();
flyingObstacles.splice(i, 1);
}
flyingSectionLastObstacleX = 2048 + 200;
flyingSectionPassedObstacles = 0;
flyingSectionProgress = 0;
flyingSectionScore = 0;
flyingSectionShipLanded = false;
}
// --- FLYING SECTION ACTIVE ---
if (flyingSectionActive) {
// Update ship
if (ship) {
ship.update();
}
// Move ship forward
if (ship && !flyingSectionShipLanded) {
ship.x += 10;
if (ship.x > flyingSectionShipTargetX) ship.x = flyingSectionShipTargetX;
}
// Spawn flying obstacles
if (flyingSectionLastObstacleX - ship.x < 1200) {
var gap = flyingSectionObstacleGap + Math.random() * 180;
var obs = new FlyingObstacle();
obs.x = flyingSectionLastObstacleX + gap;
obs.y = 400 + Math.random() * (groundY - 600);
flyingObstacles.push(obs);
game.addChild(obs);
flyingSectionLastObstacleX = obs.x;
}
// Update flying obstacles
for (var i = flyingObstacles.length - 1; i >= 0; --i) {
var obs = flyingObstacles[i];
obs.update();
// Remove if off screen
if (obs.x < -200) {
obs.destroy();
flyingObstacles.splice(i, 1);
continue;
}
// Collision with ship
if (ship && ship.intersects(obs)) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
// Score: passed obstacle
if (!obs.passed && obs.x + obs.width / 2 < ship.x - ship.width / 2) {
obs.passed = true;
flyingSectionScore += 1;
score += 2;
scoreTxt.setText(score);
// Progress bar
progressPercent = Math.min(progressPercent + progressPerScore * 2, progressMax);
progressBarFill.width = progressPercent / progressMax * 800;
if (progressPercent >= progressMax && !winShown) {
winShown = true;
gameStarted = false;
winText.visible = true;
replayBtn.visible = true;
}
}
}
// End flying section after enough distance or obstacles
if (ship && ship.x >= flyingSectionShipTargetX && !flyingSectionShipLanded) {
flyingSectionShipLanded = true;
flyingSectionActive = false;
// Hide ship, show cube, reset cube position
ship.visible = false;
cube.visible = true;
cube.x = ship.x;
cube.y = groundY;
cube.velY = 0;
cube.isOnGround = true;
// Remove all flying obstacles
for (var i = flyingObstacles.length - 1; i >= 0; --i) {
flyingObstacles[i].destroy();
flyingObstacles.splice(i, 1);
}
// Continue normal section, spawn obstacles ahead
lastObstacleX = cube.x + 600;
}
return;
}
// Update player
cube.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; --i) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.x < -200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (obs.type === 'minicoin') {
if (!obs.collected && cube.intersects(obs)) {
obs.collected = true;
score += 5; // Minicoin gives 5 points
scoreTxt.setText(score);
// Play coin sound
LK.getSound('Coin').play();
// Update progress
progressPercent = Math.min(progressPercent + progressPerScore * 5, progressMax);
progressBarFill.width = progressPercent / progressMax * 800;
if (progressPercent >= progressMax && !winShown) {
winShown = true;
gameStarted = false;
winText.visible = true;
replayBtn.visible = true;
// LK.pauseGame(); //{30} // Removed: not needed, LK handles game state on win
}
obs.destroy();
obstacles.splice(i, 1);
continue;
}
} else {
if (cube.intersects(obs)) {
// Flash screen and game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
// Score: passed obstacle
if (!obs.passed && obs.x + obs.width / 2 < cube.x - cube.width / 2) {
obs.passed = true;
score += 1;
scoreTxt.setText(score);
// Update progress
progressPercent = Math.min(progressPercent + progressPerScore, progressMax);
progressBarFill.width = progressPercent / progressMax * 800;
if (progressPercent >= progressMax && !winShown) {
winShown = true;
gameStarted = false;
winText.visible = true;
replayBtn.visible = true;
// LK.pauseGame(); //{3h} // Removed: not needed, LK handles game state on win
}
}
}
}
// Spawn new obstacles
if (obstacles.length === 0 || 2048 - lastObstacleX > minObstacleGap + Math.random() * (maxObstacleGap - minObstacleGap)) {
spawnObstacle();
}
};
// Reset game on game over
LK.on('gameover', function () {
resetGame();
LK.playMusic('Mad');
});
// Initial state
resetGame();
// Play music asset when the game starts
LK.playMusic('Mad');
// Shop icon assets (add more as needed)