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 = 8;
self.jumpForce = -20;
self.gravity = 1;
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;
// Apply custom width if specified
if (platformData.width && platformData.width > 1) {
platform.graphic.scaleX = platformData.width;
}
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
levelData.hazards.forEach(function (hazardData) {
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 = 30; // Half-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)
if (y < touchStart.y - 100) {
if (isSwapEnabled) {
player.swapDimension();
isSwapEnabled = false;
swapCooldown = 30;
// 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();
}
};
// Initialize the game with the menu
setupMenu(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1091 @@
-/****
+/****
+* 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 = 8;
+ self.jumpForce = -20;
+ self.gravity = 1;
+ 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: 0x000000
-});
\ No newline at end of file
+ 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;
+ // Apply custom width if specified
+ if (platformData.width && platformData.width > 1) {
+ platform.graphic.scaleX = platformData.width;
+ }
+ 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
+ levelData.hazards.forEach(function (hazardData) {
+ 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 = 30; // Half-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)
+ if (y < touchStart.y - 100) {
+ if (isSwapEnabled) {
+ player.swapDimension();
+ isSwapEnabled = false;
+ swapCooldown = 30;
+ // 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();
+ }
+};
+// Initialize the game with the menu
+setupMenu();
\ No newline at end of file
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