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.3; // Reduced gravity for slower falling
self.isGrounded = false;
self.isDimensionLight = true;
self.isDead = false;
self.isGliding = false;
self.collectedTrophies = 0;
self.totalTrophies = 0;
// 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;
}
// Track if player is gliding
var isGliding = Math.abs(self.velocityX) > 3 && !self.isGrounded && self.velocityY > 0;
// Apply gravity with gliding effect
if (isGliding) {
// Reduced gravity when gliding
self.velocityY += self.gravity * 0.3;
// Cap fall speed while gliding
if (self.velocityY > 5) {
self.velocityY = 5;
}
} else {
// Normal gravity
self.velocityY += self.gravity;
}
// Apply velocities
self.x += self.velocityX;
self.y += self.velocityY;
// Simple friction
if (Math.abs(self.velocityX) > 0.1) {
// Less friction while gliding
self.velocityX *= isGliding ? 0.98 : 0.9;
} else {
self.velocityX = 0;
}
// Visual effect for gliding
if (isGliding && !self.isGliding) {
self.isGliding = true;
// Stretch horizontally while gliding
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 300
});
} else if (!isGliding && self.isGliding) {
self.isGliding = false;
// Return to normal shape
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
// 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;
});
var Trophy = Container.expand(function () {
var self = Container.call(this);
// Create trophy graphic - using goal asset with different color
self.graphic = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
// Apply gold color tint
self.graphic.tint = 0xFFD700;
// Hover animation
self.animate = function () {
tween(self, {
y: self.y - 10
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 10
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: self.animate
});
}
});
};
// Start animation
self.animate();
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 trophies = [];
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: 500,
type: 'shadow',
width: 1
}, {
x: 900,
y: 600,
type: 'light',
width: 1
}, {
x: 1200,
y: 700,
type: 'shadow',
width: 1
}, {
x: 1500,
y: 800,
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
}],
trophies: [{
x: 750,
y: 450
}, {
x: 1350,
y: 650
}, {
x: 750,
y: 1350
}, {
x: 1050,
y: 1950
}],
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" + "- MOVE HORIZONTALLY TO GLIDE\n\n" + "GOAL:\n" + "- NAVIGATE THROUGH PLATFORMS\n" + "- LIGHT PLATFORMS ARE SOLID IN LIGHT DIMENSION\n" + "- SHADOW PLATFORMS ARE SOLID IN SHADOW DIMENSION\n" + "- COLLECT ALL GOLDEN TROPHIES\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 = [];
trophies.forEach(function (trophy) {
game.removeChild(trophy);
});
trophies = [];
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 trophy counter text
var trophyText = new Text2("TROPHIES: 0/0", {
size: 40,
fill: 0xFFD700
});
trophyText.anchor.set(0.5, 0);
trophyText.x = 2048 / 2;
trophyText.y = 180;
game.addChild(trophyText);
touchControls.trophyText = trophyText;
// 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 trophies
if (levelData.trophies) {
player.totalTrophies = levelData.trophies.length;
player.collectedTrophies = 0;
levelData.trophies.forEach(function (trophyData) {
var trophy = new Trophy();
trophy.x = trophyData.x;
trophy.y = trophyData.y;
trophy.collected = false;
trophies.push(trophy);
game.addChild(trophy);
});
// Update trophy counter
if (touchControls.trophyText) {
touchControls.trophyText.setText("TROPHIES: " + player.collectedTrophies + "/" + player.totalTrophies);
}
}
// 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) {
// For the final level, require all trophies to be collected before completing
if (currentLevel === totalLevels && player.collectedTrophies < player.totalTrophies) {
// Show message that trophies are required
var missingTrophiesText = new Text2("COLLECT ALL TROPHIES FIRST!", {
size: 60,
fill: 0xFFD700
});
missingTrophiesText.anchor.set(0.5, 0.5);
missingTrophiesText.x = 2048 / 2;
missingTrophiesText.y = 2732 / 2;
game.addChild(missingTrophiesText);
// Flash and remove after 2 seconds
tween(missingTrophiesText, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
game.removeChild(missingTrophiesText);
}
});
return;
}
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 trophies
trophies.forEach(function (trophy, index) {
if (!trophy.collected && player.intersects(trophy)) {
// Collect trophy
trophy.collected = true;
player.collectedTrophies++;
// Update trophy counter
if (touchControls.trophyText) {
touchControls.trophyText.setText("TROPHIES: " + player.collectedTrophies + "/" + player.totalTrophies);
}
// Trophy collection animation
tween(trophy, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(trophy);
}
});
}
});
// 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
@@ -151,8 +151,9 @@
self.gravity = 0.3; // Reduced gravity for slower falling
self.isGrounded = false;
self.isDimensionLight = true;
self.isDead = false;
+ self.isGliding = false;
self.collectedTrophies = 0;
self.totalTrophies = 0;
// Create light and shadow versions of player
self.lightForm = self.attachAsset('playerLight', {
@@ -220,19 +221,52 @@
self.update = function () {
if (self.isDead) {
return;
}
- // Apply gravity
- self.velocityY += self.gravity;
+ // Track if player is gliding
+ var isGliding = Math.abs(self.velocityX) > 3 && !self.isGrounded && self.velocityY > 0;
+ // Apply gravity with gliding effect
+ if (isGliding) {
+ // Reduced gravity when gliding
+ self.velocityY += self.gravity * 0.3;
+ // Cap fall speed while gliding
+ if (self.velocityY > 5) {
+ self.velocityY = 5;
+ }
+ } else {
+ // Normal 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;
+ // Less friction while gliding
+ self.velocityX *= isGliding ? 0.98 : 0.9;
} else {
self.velocityX = 0;
}
+ // Visual effect for gliding
+ if (isGliding && !self.isGliding) {
+ self.isGliding = true;
+ // Stretch horizontally while gliding
+ tween(self, {
+ scaleX: 1.3,
+ scaleY: 0.8
+ }, {
+ duration: 300
+ });
+ } else if (!isGliding && self.isGliding) {
+ self.isGliding = false;
+ // Return to normal shape
+ tween(self, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 300
+ });
+ }
// Screen bounds
if (self.x < 30) {
self.x = 30;
} else if (self.x > 2048 - 30) {
@@ -763,9 +797,9 @@
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" + "- COLLECT ALL GOLDEN TROPHIES\n" + "- REACH THE GREEN GOAL TO COMPLETE LEVEL", {
+ var instructionText = new Text2("CONTROLS:\n" + "- TAP LEFT/RIGHT SIDES TO MOVE\n" + "- TAP CENTER TO JUMP\n" + "- SWIPE UP TO SWAP DIMENSIONS\n" + "- MOVE HORIZONTALLY TO GLIDE\n\n" + "GOAL:\n" + "- NAVIGATE THROUGH PLATFORMS\n" + "- LIGHT PLATFORMS ARE SOLID IN LIGHT DIMENSION\n" + "- SHADOW PLATFORMS ARE SOLID IN SHADOW DIMENSION\n" + "- COLLECT ALL GOLDEN TROPHIES\n" + "- REACH THE GREEN GOAL TO COMPLETE LEVEL", {
size: 40,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
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