User prompt
Make it so you can glide ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make you sell the trophies on the last platform
User prompt
Make it so the platforms are closer
User prompt
Make it so it’s a little easier
User prompt
Make it so you fall slower
User prompt
Make it easier
Code edit (1 edits merged)
Please save this source code
User prompt
Shadow Swap: Dimension Shifter
Initial prompt
Genre: Puzzle Platformer Concept: You play as a shadow who can “swap places” with light! The world is filled with puzzles where light and shadow behave like solid platforms or traps. You must swap between shadow and light form to navigate tricky levels, avoid enemies, and activate switches. Key Features: • Light = visible, passable platforms. • Shadow = invisible paths and walls only shadows can use. • Swapping at the right time is the key to survival. • Boss levels where you race against moving light sources.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, unlockedLevels: 1 }); /**** * Classes ****/ var DimensionSwitch = Container.expand(function () { var self = Container.call(this); // Create switch graphic self.graphic = self.attachAsset('dimensionSwitch', { anchorX: 0.5, anchorY: 0.5 }); // Create pulsing animation self.pulseAnimation = function () { tween(self.graphic, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.graphic, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: self.pulseAnimation }); } }); }; // Start pulsing self.pulseAnimation(); return self; }); var Goal = Container.expand(function () { var self = Container.call(this); // Create goal graphic self.graphic = self.attachAsset('goal', { anchorX: 0.5, anchorY: 0.5 }); // Animate the goal self.animateGoal = function () { tween(self, { rotation: Math.PI * 2 }, { duration: 3000, onFinish: function onFinish() { self.rotation = 0; self.animateGoal(); } }); }; // Start animation self.animateGoal(); return self; }); var Hazard = Container.expand(function () { var self = Container.call(this); // Create hazard graphic self.graphic = self.attachAsset('hazard', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var LevelButton = Container.expand(function (levelNum) { var self = Container.call(this); self.levelNum = levelNum; // Create button background self.background = self.attachAsset('levelSelectButton', { anchorX: 0.5, anchorY: 0.5 }); // Create level text self.text = new Text2(levelNum.toString(), { size: 50, fill: 0xFFFFFF }); self.text.anchor.set(0.5, 0.5); self.addChild(self.text); // Interactive events self.down = function (x, y, obj) { if (storage.unlockedLevels >= self.levelNum) { tween(self, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); } }; self.up = function (x, y, obj) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (storage.unlockedLevels >= self.levelNum) { storage.currentLevel = self.levelNum; startGame(); } } }); }; // Update appearance based on level unlock status self.updateAppearance = function () { if (storage.unlockedLevels >= self.levelNum) { self.background.alpha = 1; self.text.alpha = 1; } else { self.background.alpha = 0.5; self.text.setText("🔒"); } }; self.updateAppearance(); return self; }); var Platform = Container.expand(function (type) { var self = Container.call(this); // Platform properties self.type = type || 'light'; // 'light' or 'shadow' // Create platform graphic self.graphic = self.attachAsset(self.type === 'light' ? 'lightPlatform' : 'shadowPlatform', { anchorX: 0.5, anchorY: 0.5 }); // Check if platform is solid in current dimension self.isSolid = function (isDimensionLight) { return self.type === 'light' && isDimensionLight || self.type === 'shadow' && !isDimensionLight; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); // Player properties self.velocityX = 0; self.velocityY = 0; self.speed = 10; self.jumpForce = -24; self.gravity = 0.5; self.isGrounded = false; self.isDimensionLight = true; self.isDead = false; // Create light and shadow versions of player self.lightForm = self.attachAsset('playerLight', { anchorX: 0.5, anchorY: 0.5 }); self.shadowForm = self.attachAsset('playerShadow', { anchorX: 0.5, anchorY: 0.5, visible: false }); // Swap dimensions self.swapDimension = function () { if (self.isDead) { return; } self.isDimensionLight = !self.isDimensionLight; self.lightForm.visible = self.isDimensionLight; self.shadowForm.visible = !self.isDimensionLight; LK.getSound('swap').play(); // Visual effect for dimension swap LK.effects.flashObject(self, self.isDimensionLight ? 0xFFFFFF : 0x000000, 300); }; // Jump action self.jump = function () { if (self.isGrounded && !self.isDead) { self.velocityY = self.jumpForce; self.isGrounded = false; LK.getSound('jump').play(); } }; // Move left self.moveLeft = function () { if (!self.isDead) { self.velocityX = -self.speed; } }; // Move right self.moveRight = function () { if (!self.isDead) { self.velocityX = self.speed; } }; // Stop horizontal movement self.stopMoving = function () { self.velocityX = 0; }; // Kill player self.die = function () { if (!self.isDead) { self.isDead = true; LK.getSound('death').play(); tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { // Let the game handle the reset restartLevel(); } }); } }; // Physics update self.update = function () { if (self.isDead) { return; } // Apply gravity self.velocityY += self.gravity; // Apply velocities self.x += self.velocityX; self.y += self.velocityY; // Simple friction if (Math.abs(self.velocityX) > 0.1) { self.velocityX *= 0.9; } else { self.velocityX = 0; } // Screen bounds if (self.x < 30) { self.x = 30; } else if (self.x > 2048 - 30) { self.x = 2048 - 30; } if (self.y > 2732) { self.die(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Game states var STATE_MENU = 'menu'; var STATE_GAME = 'game'; var gameState = STATE_MENU; // Game elements var player; var platforms = []; var hazards = []; var dimensionSwitches = []; var goal; var levelButtons = []; var touchControls = {}; var background; // Game logic variables var totalLevels = 5; var currentLevel = storage.currentLevel || 1; var isSwapEnabled = true; var swapCooldown = 0; var levelComplete = false; // Level designs var levels = [ // Level 1: Simple introduction { playerStart: { x: 300, y: 300 }, platforms: [{ x: 300, y: 400, type: 'light', width: 1 }, { x: 600, y: 600, type: 'shadow', width: 1 }, { x: 900, y: 800, type: 'light', width: 1 }, { x: 1200, y: 1000, type: 'shadow', width: 1 }, { x: 1500, y: 1200, type: 'light', width: 1 }], dimensionSwitches: [{ x: 600, y: 520 }, { x: 1200, y: 920 }], hazards: [], goal: { x: 1500, y: 1120 } }, // Level 2: Platforms and hazards { playerStart: { x: 200, y: 300 }, platforms: [{ x: 200, y: 400, type: 'light', width: 1 }, { x: 500, y: 500, type: 'shadow', width: 1 }, { x: 800, y: 600, type: 'light', width: 1 }, { x: 1100, y: 700, type: 'shadow', width: 1 }, { x: 1400, y: 800, type: 'light', width: 1 }, { x: 1700, y: 900, type: 'shadow', width: 1 }], dimensionSwitches: [{ x: 500, y: 420 }, { x: 1100, y: 620 }], hazards: [{ x: 800, y: 500 }, { x: 1400, y: 700 }], goal: { x: 1700, y: 820 } }, // Level 3: More complex puzzle { playerStart: { x: 150, y: 300 }, platforms: [{ x: 150, y: 400, type: 'light', width: 1 }, { x: 450, y: 400, type: 'shadow', width: 1 }, { x: 750, y: 500, type: 'light', width: 1 }, { x: 1050, y: 500, type: 'shadow', width: 1 }, { x: 1350, y: 600, type: 'light', width: 1 }, { x: 1650, y: 600, type: 'shadow', width: 1 }, { x: 1650, y: 800, type: 'light', width: 1 }, { x: 1350, y: 800, type: 'shadow', width: 1 }, { x: 1050, y: 1000, type: 'light', width: 1 }, { x: 750, y: 1000, type: 'shadow', width: 1 }], dimensionSwitches: [{ x: 450, y: 320 }, { x: 1050, y: 420 }, { x: 1650, y: 520 }, { x: 1050, y: 920 }], hazards: [{ x: 750, y: 400 }, { x: 1350, y: 500 }, { x: 1350, y: 900 }], goal: { x: 750, y: 920 } }, // Level 4: Advanced obstacles { playerStart: { x: 200, y: 200 }, platforms: [{ x: 200, y: 300, type: 'light', width: 1 }, { x: 500, y: 300, type: 'shadow', width: 1 }, { x: 800, y: 400, type: 'light', width: 1 }, { x: 1100, y: 400, type: 'shadow', width: 1 }, { x: 1400, y: 500, type: 'light', width: 1 }, { x: 1700, y: 500, type: 'shadow', width: 1 }, { x: 1400, y: 700, type: 'shadow', width: 1 }, { x: 1100, y: 700, type: 'light', width: 1 }, { x: 800, y: 900, type: 'shadow', width: 1 }, { x: 500, y: 900, type: 'light', width: 1 }, { x: 200, y: 1100, type: 'shadow', width: 1 }, { x: 500, y: 1100, type: 'light', width: 1 }], dimensionSwitches: [{ x: 500, y: 220 }, { x: 1100, y: 320 }, { x: 1400, y: 620 }, { x: 800, y: 820 }, { x: 200, y: 1020 }], hazards: [{ x: 800, y: 300 }, { x: 1400, y: 400 }, { x: 1100, y: 600 }, { x: 500, y: 800 }], goal: { x: 500, y: 1020 } }, // Level 5: Final challenge { playerStart: { x: 150, y: 200 }, platforms: [{ x: 150, y: 300, type: 'light', width: 1 }, { x: 450, y: 400, type: 'shadow', width: 1 }, { x: 750, y: 500, type: 'light', width: 1 }, { x: 1050, y: 600, type: 'shadow', width: 1 }, { x: 1350, y: 700, type: 'light', width: 1 }, { x: 1650, y: 800, type: 'shadow', width: 1 }, { x: 1350, y: 1000, type: 'shadow', width: 1 }, { x: 1050, y: 1200, type: 'light', width: 1 }, { x: 750, y: 1400, type: 'shadow', width: 1 }, { x: 450, y: 1600, type: 'light', width: 1 }, { x: 750, y: 1800, type: 'shadow', width: 1 }, { x: 1050, y: 2000, type: 'light', width: 1 }, { x: 1350, y: 2200, type: 'shadow', width: 1 }, { x: 1650, y: 2400, type: 'light', width: 1 }], dimensionSwitches: [{ x: 450, y: 320 }, { x: 1050, y: 520 }, { x: 1650, y: 720 }, { x: 1050, y: 1120 }, { x: 450, y: 1520 }, { x: 1050, y: 1920 }, { x: 1650, y: 2320 }], hazards: [{ x: 750, y: 400 }, { x: 1350, y: 600 }, { x: 1350, y: 900 }, { x: 750, y: 1300 }, { x: 750, y: 1700 }, { x: 1350, y: 2100 }], goal: { x: 1650, y: 2320 } }]; // Initialize menu function setupMenu() { gameState = STATE_MENU; clearLevel(); // Create title text var titleText = new Text2("SHADOW SWAP", { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; game.addChild(titleText); // Create level selection text var levelSelectText = new Text2("SELECT LEVEL", { size: 60, fill: 0xFFFFFF }); levelSelectText.anchor.set(0.5, 0.5); levelSelectText.x = 2048 / 2; levelSelectText.y = 550; game.addChild(levelSelectText); // Create level selection buttons for (var i = 0; i < totalLevels; i++) { var button = new LevelButton(i + 1); button.x = 2048 / 2 + (i - 2) * 250; button.y = 700; levelButtons.push(button); game.addChild(button); } // Create instruction text var instructionText = new Text2("CONTROLS:\n" + "- TAP LEFT/RIGHT SIDES TO MOVE\n" + "- TAP CENTER TO JUMP\n" + "- SWIPE UP TO SWAP DIMENSIONS\n\n" + "GOAL:\n" + "- NAVIGATE THROUGH PLATFORMS\n" + "- LIGHT PLATFORMS ARE SOLID IN LIGHT DIMENSION\n" + "- SHADOW PLATFORMS ARE SOLID IN SHADOW DIMENSION\n" + "- REACH THE GREEN GOAL TO COMPLETE LEVEL", { size: 40, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0); instructionText.x = 2048 / 2; instructionText.y = 900; game.addChild(instructionText); } // Start game with the selected level function startGame() { gameState = STATE_GAME; clearLevel(); setupLevel(storage.currentLevel); LK.playMusic('gameBgm'); } // Clear all game elements function clearLevel() { // Remove all game objects if (player) { game.removeChild(player); player = null; } platforms.forEach(function (platform) { game.removeChild(platform); }); platforms = []; hazards.forEach(function (hazard) { game.removeChild(hazard); }); hazards = []; dimensionSwitches.forEach(function (dimensionSwitch) { game.removeChild(dimensionSwitch); }); dimensionSwitches = []; if (goal) { game.removeChild(goal); goal = null; } levelButtons.forEach(function (button) { game.removeChild(button); }); levelButtons = []; // Remove any other UI elements for (var key in touchControls) { if (touchControls[key]) { game.removeChild(touchControls[key]); } } touchControls = {}; // Reset game state levelComplete = false; isSwapEnabled = true; swapCooldown = 0; // Clear any existing children while (game.children.length > 0) { game.removeChild(game.children[0]); } } // Set up a level function setupLevel(levelNum) { currentLevel = levelNum; var levelData = levels[levelNum - 1] || levels[0]; // Create background background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); background.x = 2048 / 2; background.y = 2732 / 2; game.addChild(background); // Create level text var levelText = new Text2("LEVEL " + currentLevel, { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.x = 2048 / 2; levelText.y = 50; game.addChild(levelText); // Create dimension indicator var dimensionText = new Text2("DIMENSION: LIGHT", { size: 40, fill: 0xFFFFFF }); dimensionText.anchor.set(0.5, 0); dimensionText.x = 2048 / 2; dimensionText.y = 120; game.addChild(dimensionText); touchControls.dimensionText = dimensionText; // Create player player = new Player(); player.x = levelData.playerStart.x; player.y = levelData.playerStart.y; game.addChild(player); // Create platforms levelData.platforms.forEach(function (platformData) { var platform = new Platform(platformData.type); platform.x = platformData.x; platform.y = platformData.y; // Make all platforms 1.5x wider for easier landing platform.graphic.scaleX = platformData.width ? platformData.width * 1.5 : 1.5; platforms.push(platform); game.addChild(platform); }); // Create dimension switches levelData.dimensionSwitches.forEach(function (switchData) { var dimensionSwitch = new DimensionSwitch(); dimensionSwitch.x = switchData.x; dimensionSwitch.y = switchData.y; dimensionSwitches.push(dimensionSwitch); game.addChild(dimensionSwitch); }); // Create hazards (limit the number of hazards per level to make it easier) var hazardCount = 0; levelData.hazards.forEach(function (hazardData) { // Only create 2/3 of the hazards to make game easier hazardCount++; if (hazardCount % 3 !== 0) { // Skip every third hazard var hazard = new Hazard(); hazard.x = hazardData.x; hazard.y = hazardData.y; hazards.push(hazard); game.addChild(hazard); } }); // Create goal goal = new Goal(); goal.x = levelData.goal.x; goal.y = levelData.goal.y; game.addChild(goal); // Touch controls areas (invisible) var leftControl = LK.getAsset('lightPlatform', { anchorX: 0, anchorY: 0, alpha: 0 }); leftControl.width = 2048 / 3; leftControl.height = 2732; leftControl.x = 0; leftControl.y = 0; game.addChild(leftControl); touchControls.left = leftControl; var rightControl = LK.getAsset('lightPlatform', { anchorX: 0, anchorY: 0, alpha: 0 }); rightControl.width = 2048 / 3; rightControl.height = 2732; rightControl.x = 2048 * 2 / 3; rightControl.y = 0; game.addChild(rightControl); touchControls.right = rightControl; var centerControl = LK.getAsset('lightPlatform', { anchorX: 0, anchorY: 0, alpha: 0 }); centerControl.width = 2048 / 3; centerControl.height = 2732; centerControl.x = 2048 / 3; centerControl.y = 0; game.addChild(centerControl); touchControls.center = centerControl; } // Restart current level function restartLevel() { clearLevel(); setupLevel(currentLevel); } // Complete level and move to next function completeLevel() { if (!levelComplete) { levelComplete = true; LK.getSound('win').play(); // Update unlocked levels if (currentLevel >= storage.unlockedLevels) { storage.unlockedLevels = currentLevel + 1; if (storage.unlockedLevels > totalLevels) { storage.unlockedLevels = totalLevels; } } // Show win animation tween(player, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.showYouWin(); // Move to next level if (currentLevel < totalLevels) { storage.currentLevel = currentLevel + 1; } else { // If all levels completed, go back to menu setupMenu(); } } }); } } // Check collisions between player and platforms function checkPlatformCollisions() { var wasGrounded = player.isGrounded; player.isGrounded = false; platforms.forEach(function (platform) { if (platform.isSolid(player.isDimensionLight) && player.intersects(platform)) { // Calculate collision sides var playerBottom = player.y + player.lightForm.height / 2; var playerTop = player.y - player.lightForm.height / 2; var playerLeft = player.x - player.lightForm.width / 2; var playerRight = player.x + player.lightForm.width / 2; var platformBottom = platform.y + platform.graphic.height / 2; var platformTop = platform.y - platform.graphic.height / 2; var platformLeft = platform.x - platform.graphic.width / 2; var platformRight = platform.x + platform.graphic.width / 2; // Calculate penetration depths var fromTop = playerBottom - platformTop; var fromBottom = platformBottom - playerTop; var fromLeft = playerRight - platformLeft; var fromRight = platformRight - playerLeft; // Find minimum penetration var minPenetration = Math.min(fromTop, fromBottom, fromLeft, fromRight); // Resolve collision based on minimum penetration if (minPenetration === fromTop && player.velocityY > 0) { player.y = platformTop - player.lightForm.height / 2; player.velocityY = 0; player.isGrounded = true; } else if (minPenetration === fromBottom && player.velocityY < 0) { player.y = platformBottom + player.lightForm.height / 2; player.velocityY = 0; } else if (minPenetration === fromLeft && player.velocityX > 0) { player.x = platformLeft - player.lightForm.width / 2; player.velocityX = 0; } else if (minPenetration === fromRight && player.velocityX < 0) { player.x = platformRight + player.lightForm.width / 2; player.velocityX = 0; } } }); // Landing effect if (!wasGrounded && player.isGrounded) { tween(player, { scaleX: 1.2, scaleY: 0.8 }, { duration: 100, onFinish: function onFinish() { tween(player, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } } // Check other game object interactions function checkInteractions() { // Check dimension switches dimensionSwitches.forEach(function (dimensionSwitch) { if (player.intersects(dimensionSwitch) && isSwapEnabled) { player.swapDimension(); isSwapEnabled = false; swapCooldown = 45; // 0.75-second cooldown at 60 FPS // Update dimension text if (touchControls.dimensionText) { touchControls.dimensionText.setText("DIMENSION: " + (player.isDimensionLight ? "LIGHT" : "SHADOW")); } // Animate the switch tween(dimensionSwitch, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, onFinish: function onFinish() { tween(dimensionSwitch, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } }); // Check hazards hazards.forEach(function (hazard) { if (player.intersects(hazard)) { player.die(); } }); // Check goal if (player.intersects(goal)) { completeLevel(); } // Swap cooldown if (!isSwapEnabled) { swapCooldown--; if (swapCooldown <= 0) { isSwapEnabled = true; } } } // Touch controls var touchStart = { x: 0, y: 0 }; var isTouching = false; var movingLeft = false; var movingRight = false; game.down = function (x, y, obj) { if (gameState === STATE_GAME) { touchStart.x = x; touchStart.y = y; isTouching = true; // Check which control area was touched if (x < 2048 / 3) { // Left side - move left movingLeft = true; player.moveLeft(); } else if (x > 2048 * 2 / 3) { // Right side - move right movingRight = true; player.moveRight(); } else { // Center - jump player.jump(); } } }; game.move = function (x, y, obj) { if (gameState === STATE_GAME && isTouching) { // Check for swipe up (dimension swap) - reduced distance required if (y < touchStart.y - 70) { if (isSwapEnabled) { player.swapDimension(); isSwapEnabled = false; swapCooldown = 45; // Update dimension text if (touchControls.dimensionText) { touchControls.dimensionText.setText("DIMENSION: " + (player.isDimensionLight ? "LIGHT" : "SHADOW")); } } // Reset touch to prevent multiple swipes isTouching = false; } } }; game.up = function (x, y, obj) { if (gameState === STATE_GAME) { isTouching = false; // Stop horizontal movement if this was a movement control if (movingLeft || movingRight) { player.stopMoving(); movingLeft = false; movingRight = false; } } }; // Main game update loop game.update = function () { if (gameState === STATE_GAME && !levelComplete && player && !player.isDead) { // Update player physics player.update(); // Check collisions and interactions checkPlatformCollisions(); checkInteractions(); // Update platform visuals based on current dimension platforms.forEach(function (platform) { // Make solid platforms more visible (higher alpha) in current dimension if (platform.isSolid(player.isDimensionLight)) { platform.graphic.alpha = 1.0; } else { platform.graphic.alpha = 0.5; } }); } }; // Initialize the game with the menu setupMenu();
===================================================================
--- original.js
+++ change.js
@@ -147,9 +147,9 @@
self.velocityX = 0;
self.velocityY = 0;
self.speed = 10;
self.jumpForce = -24;
- self.gravity = 0.8;
+ self.gravity = 0.5;
self.isGrounded = false;
self.isDimensionLight = true;
self.isDead = false;
// Create light and shadow versions of player
Switch. In-Game asset. 2d. High contrast. No shadows
Trophy. In-Game asset. 2d. High contrast. No shadows
Hazard. In-Game asset. 2d. High contrast. No shadows
A shadow ninja. In-Game asset. 2d. High contrast. No shadows
A shadow ninja. In-Game asset. 2d. High contrast. shadow
Shadow platform. In-Game asset. 2d. High contrast. No shadows