User prompt
can you make the lasers also detect the player and end the game
User prompt
can you make the colliders more accurate so the it detects the player from all sides
User prompt
can you add more obstacles
User prompt
the player should just jump across the walls. It shouldn't jump upwards
User prompt
the game stops producing obstacles after player gets 8 points. That is a bug. Could you fish it
Code edit (1 edits merged)
Please save this source code
User prompt
Ninja Wall Jump
Initial prompt
I want a ninja tuning game. The game will be vertical. There are 2 walls in each side with obstacles. Every time the player taps the ninja character jumps to the other wall.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Ninja class
var Ninja = Container.expand(function () {
var self = Container.call(this);
var ninjaGfx = self.attachAsset('ninja', {
anchorX: 0.5,
anchorY: 0.5
});
// 0: left wall, 1: right wall
self.wallSide = 0;
// Current vertical speed (for jump animation)
self.vy = 0;
// Is currently jumping
self.isJumping = false;
// Called every tick
self.update = function () {
// Gravity effect (for jump arc)
if (self.isJumping) {
self.y += self.vy;
self.vy += 2.5; // gravity
// If reached or passed targetY, snap to targetY and stop jumping
if (self.vy > 0 && self.y >= self.targetY || self.vy < 0 && self.y <= self.targetY) {
self.y = self.targetY;
self.isJumping = false;
self.vy = 0;
}
}
};
// Start jump to other wall, upward by jumpHeight
self.jump = function (jumpHeight, wallX) {
if (self.isJumping) return;
self.isJumping = true;
self.wallSide = 1 - self.wallSide;
self.targetY = self.y - jumpHeight;
self.vy = -40; // initial jump velocity
// Tween x to other wall
tween(self, {
x: wallX
}, {
duration: 120,
easing: tween.cubicOut
});
// Play jump sound
LK.getSound('jump').play();
};
return self;
});
// Obstacle class (spike or barrier)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// type: 'spike' or 'barrier'
self.type = 'spike';
self.wallSide = 0; // 0: left, 1: right
self.passed = false; // Has ninja passed this obstacle
// Set up asset
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
if (type === 'spike') {
self.asset = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.asset = self.attachAsset('barrier', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
// Called every tick
self.update = function () {
// Obstacles move downward as the ninja climbs
self.y += obstacleSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Sound for jump
// Obstacle (barrier) - blue box
// Obstacle (spike) - yellow ellipse
// Wall - tall, thin, gray
// Ninja (player) - a small box, red
// Game constants
var wallGap = 1200; // horizontal distance between walls
var wallMargin = 200; // margin from screen edge
var ninjaStartY = 2000;
var jumpHeight = 320; // vertical jump per tap
var obstacleMinGap = 400; // min vertical gap between obstacles
var obstacleMaxGap = 700; // max vertical gap between obstacles
var obstacleSpeed = 8; // how fast obstacles move down
var ninjaXLeft = wallMargin + 50; // center of left wall
var ninjaXRight = 2048 - wallMargin - 50; // center of right wall
// Walls
var leftWall = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0
});
leftWall.x = wallMargin + leftWall.width / 2;
leftWall.y = 0;
game.addChild(leftWall);
var rightWall = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0
});
rightWall.x = 2048 - wallMargin - rightWall.width / 2;
rightWall.y = 0;
game.addChild(rightWall);
// Ninja
var ninja = new Ninja();
ninja.x = ninjaXLeft;
ninja.y = ninjaStartY;
ninja.wallSide = 0;
game.addChild(ninja);
// Obstacles array
var obstacles = [];
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// For touch input
var isGameStarted = false;
var isDead = false;
// For obstacle generation
var lastObstacleY = ninjaStartY - 500;
// Helper: generate a new obstacle above the last one
function spawnObstacle() {
var obs = new Obstacle();
// Randomly choose type
obs.setType(Math.random() < 0.5 ? 'spike' : 'barrier');
// Alternate wall side
obs.wallSide = Math.random() < 0.5 ? 0 : 1;
// X position
obs.x = obs.wallSide === 0 ? ninjaXLeft : ninjaXRight;
// Y position: above last obstacle
var gap = obstacleMinGap + Math.random() * (obstacleMaxGap - obstacleMinGap);
obs.y = lastObstacleY - gap;
lastObstacleY = obs.y;
// For barrier, offset horizontally so it sticks out from wall
if (obs.type === 'barrier') {
obs.x += obs.wallSide === 0 ? 90 : -90;
}
obstacles.push(obs);
game.addChild(obs);
}
// Initial obstacles
for (var i = 0; i < 8; i++) {
spawnObstacle();
}
// Move handler: tap anywhere to jump
game.down = function (x, y, obj) {
if (isDead) return;
if (!isGameStarted) {
isGameStarted = true;
}
// Only allow jump if not already jumping
if (!ninja.isJumping) {
// Jump to other wall
var targetX = ninja.wallSide === 0 ? ninjaXRight : ninjaXLeft;
ninja.jump(jumpHeight, targetX);
}
};
// Main update loop
game.update = function () {
if (isDead) return;
// Ninja update
ninja.update();
// Move obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove obstacles that are off screen
if (obs.y > 2732 + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Check for collision (only if ninja is not jumping, i.e. landed)
if (!ninja.isJumping && !obs.passed) {
// Only check obstacles on the same wall as ninja
if (obs.wallSide === ninja.wallSide) {
// For spike: collision if close enough
if (obs.type === 'spike') {
var dx = Math.abs(ninja.x - obs.x);
var dy = Math.abs(ninja.y - obs.y);
if (dx < 90 && dy < 90) {
// Dead
isDead = true;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
} else if (obs.type === 'barrier') {
// Barrier is horizontal, check vertical overlap
var dx = Math.abs(ninja.x - obs.x);
var dy = Math.abs(ninja.y - obs.y);
if (dx < 120 && dy < 60) {
// Dead
isDead = true;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
}
// Score: passed obstacle (only once per obstacle)
if (!obs.passed && ninja.y < obs.y) {
obs.passed = true;
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
}
}
// Camera: move everything down as ninja climbs
if (ninja.y < 1000) {
var dy = 1000 - ninja.y;
ninja.y += dy;
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].y += dy;
}
lastObstacleY += dy;
}
// Spawn new obstacles if needed
while (lastObstacleY > -200) {
spawnObstacle();
}
};
// Reset game state on game over (handled by LK, but for safety)
game.onDestroy = function () {
obstacles = [];
isGameStarted = false;
isDead = false;
score = 0;
LK.setScore(0);
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,259 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Ninja class
+var Ninja = Container.expand(function () {
+ var self = Container.call(this);
+ var ninjaGfx = self.attachAsset('ninja', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // 0: left wall, 1: right wall
+ self.wallSide = 0;
+ // Current vertical speed (for jump animation)
+ self.vy = 0;
+ // Is currently jumping
+ self.isJumping = false;
+ // Called every tick
+ self.update = function () {
+ // Gravity effect (for jump arc)
+ if (self.isJumping) {
+ self.y += self.vy;
+ self.vy += 2.5; // gravity
+ // If reached or passed targetY, snap to targetY and stop jumping
+ if (self.vy > 0 && self.y >= self.targetY || self.vy < 0 && self.y <= self.targetY) {
+ self.y = self.targetY;
+ self.isJumping = false;
+ self.vy = 0;
+ }
+ }
+ };
+ // Start jump to other wall, upward by jumpHeight
+ self.jump = function (jumpHeight, wallX) {
+ if (self.isJumping) return;
+ self.isJumping = true;
+ self.wallSide = 1 - self.wallSide;
+ self.targetY = self.y - jumpHeight;
+ self.vy = -40; // initial jump velocity
+ // Tween x to other wall
+ tween(self, {
+ x: wallX
+ }, {
+ duration: 120,
+ easing: tween.cubicOut
+ });
+ // Play jump sound
+ LK.getSound('jump').play();
+ };
+ return self;
+});
+// Obstacle class (spike or barrier)
+var Obstacle = Container.expand(function () {
+ var self = Container.call(this);
+ // type: 'spike' or 'barrier'
+ self.type = 'spike';
+ self.wallSide = 0; // 0: left, 1: right
+ self.passed = false; // Has ninja passed this obstacle
+ // Set up asset
+ self.setType = function (type) {
+ self.type = type;
+ if (self.asset) {
+ self.removeChild(self.asset);
+ }
+ if (type === 'spike') {
+ self.asset = self.attachAsset('spike', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else {
+ self.asset = self.attachAsset('barrier', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ };
+ // Called every tick
+ self.update = function () {
+ // Obstacles move downward as the ninja climbs
+ self.y += obstacleSpeed;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x181818
+});
+
+/****
+* Game Code
+****/
+// Sound for jump
+// Obstacle (barrier) - blue box
+// Obstacle (spike) - yellow ellipse
+// Wall - tall, thin, gray
+// Ninja (player) - a small box, red
+// Game constants
+var wallGap = 1200; // horizontal distance between walls
+var wallMargin = 200; // margin from screen edge
+var ninjaStartY = 2000;
+var jumpHeight = 320; // vertical jump per tap
+var obstacleMinGap = 400; // min vertical gap between obstacles
+var obstacleMaxGap = 700; // max vertical gap between obstacles
+var obstacleSpeed = 8; // how fast obstacles move down
+var ninjaXLeft = wallMargin + 50; // center of left wall
+var ninjaXRight = 2048 - wallMargin - 50; // center of right wall
+// Walls
+var leftWall = LK.getAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0
+});
+leftWall.x = wallMargin + leftWall.width / 2;
+leftWall.y = 0;
+game.addChild(leftWall);
+var rightWall = LK.getAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0
+});
+rightWall.x = 2048 - wallMargin - rightWall.width / 2;
+rightWall.y = 0;
+game.addChild(rightWall);
+// Ninja
+var ninja = new Ninja();
+ninja.x = ninjaXLeft;
+ninja.y = ninjaStartY;
+ninja.wallSide = 0;
+game.addChild(ninja);
+// Obstacles array
+var obstacles = [];
+// Score
+var score = 0;
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// For touch input
+var isGameStarted = false;
+var isDead = false;
+// For obstacle generation
+var lastObstacleY = ninjaStartY - 500;
+// Helper: generate a new obstacle above the last one
+function spawnObstacle() {
+ var obs = new Obstacle();
+ // Randomly choose type
+ obs.setType(Math.random() < 0.5 ? 'spike' : 'barrier');
+ // Alternate wall side
+ obs.wallSide = Math.random() < 0.5 ? 0 : 1;
+ // X position
+ obs.x = obs.wallSide === 0 ? ninjaXLeft : ninjaXRight;
+ // Y position: above last obstacle
+ var gap = obstacleMinGap + Math.random() * (obstacleMaxGap - obstacleMinGap);
+ obs.y = lastObstacleY - gap;
+ lastObstacleY = obs.y;
+ // For barrier, offset horizontally so it sticks out from wall
+ if (obs.type === 'barrier') {
+ obs.x += obs.wallSide === 0 ? 90 : -90;
+ }
+ obstacles.push(obs);
+ game.addChild(obs);
+}
+// Initial obstacles
+for (var i = 0; i < 8; i++) {
+ spawnObstacle();
+}
+// Move handler: tap anywhere to jump
+game.down = function (x, y, obj) {
+ if (isDead) return;
+ if (!isGameStarted) {
+ isGameStarted = true;
+ }
+ // Only allow jump if not already jumping
+ if (!ninja.isJumping) {
+ // Jump to other wall
+ var targetX = ninja.wallSide === 0 ? ninjaXRight : ninjaXLeft;
+ ninja.jump(jumpHeight, targetX);
+ }
+};
+// Main update loop
+game.update = function () {
+ if (isDead) return;
+ // Ninja update
+ ninja.update();
+ // Move obstacles
+ for (var i = obstacles.length - 1; i >= 0; i--) {
+ var obs = obstacles[i];
+ obs.update();
+ // Remove obstacles that are off screen
+ if (obs.y > 2732 + 100) {
+ obs.destroy();
+ obstacles.splice(i, 1);
+ continue;
+ }
+ // Check for collision (only if ninja is not jumping, i.e. landed)
+ if (!ninja.isJumping && !obs.passed) {
+ // Only check obstacles on the same wall as ninja
+ if (obs.wallSide === ninja.wallSide) {
+ // For spike: collision if close enough
+ if (obs.type === 'spike') {
+ var dx = Math.abs(ninja.x - obs.x);
+ var dy = Math.abs(ninja.y - obs.y);
+ if (dx < 90 && dy < 90) {
+ // Dead
+ isDead = true;
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ } else if (obs.type === 'barrier') {
+ // Barrier is horizontal, check vertical overlap
+ var dx = Math.abs(ninja.x - obs.x);
+ var dy = Math.abs(ninja.y - obs.y);
+ if (dx < 120 && dy < 60) {
+ // Dead
+ isDead = true;
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ }
+ }
+ }
+ // Score: passed obstacle (only once per obstacle)
+ if (!obs.passed && ninja.y < obs.y) {
+ obs.passed = true;
+ score += 1;
+ LK.setScore(score);
+ scoreTxt.setText(score);
+ }
+ }
+ // Camera: move everything down as ninja climbs
+ if (ninja.y < 1000) {
+ var dy = 1000 - ninja.y;
+ ninja.y += dy;
+ for (var i = 0; i < obstacles.length; i++) {
+ obstacles[i].y += dy;
+ }
+ lastObstacleY += dy;
+ }
+ // Spawn new obstacles if needed
+ while (lastObstacleY > -200) {
+ spawnObstacle();
+ }
+};
+// Reset game state on game over (handled by LK, but for safety)
+game.onDestroy = function () {
+ obstacles = [];
+ isGameStarted = false;
+ isDead = false;
+ score = 0;
+ LK.setScore(0);
+};
\ No newline at end of file