User prompt
Remove the whole spawn collectible code.
User prompt
Add the collectable spawning function to game update with obstacle.
User prompt
if the obstacle lastPath is 0 then coin current path should be 1 and if obstacle lastPath is 1 then coin last Path should be 0.
Code edit (1 edits merged)
Please save this source code
User prompt
currently the lives and sheild speed is slower than the coin and path, make it eaqual speed.
User prompt
Remove the redundent code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'x')' in or related to this line: 'newObstacle.x = newCollectible.x + i * newObstacle.width;' Line Number: 351
User prompt
Now there is some issue with our logic, so now what i want is, move the obstacle to the collectible and consider it in collectible chance.
User prompt
remove the overlap check from spawnable fuction
Code edit (1 edits merged)
Please save this source code
User prompt
still sometimes the coins and obstacle groups are spawned on the same path same location, fix this issue.
User prompt
from line 394 to 404 you are checking the overlap of obstacle and coins, but that logic is not working for the group of coins and obstacles. You can change a logic to, when obstacles(groups) are spawned on the lower path, spawn coins group in front of the obstacle group ( on the upper path), and if obstacles(groups) are spawned on the upper path then spawn coins group in front of the obstacle group ( on the lower path).
User prompt
still not visible to me.
User prompt
fix the bug coin text is not visible.
User prompt
move the coin display on the top right corner
User prompt
dd the display text for coin on the same y location of Score, but the x location should be on right.
User prompt
function spawnCollectible() { // ... (rest of the code for life and shield spawning remains the same) // 50% chance to spawn a coin var newCoin = new Coin(); var randomPath = Math.random() > 0.5 ? 1 : 2; // Choose a random path (1 or 2) var validPosition = false; var maxAttempts = 10; // Maximum attempts to find a valid spawn position var attempts = 0; while (!validPosition && attempts < maxAttempts) { newCoin.x = 2048 + Math.random() * 500; // Place coin on the path OPPOSITE to the most recent obstacle if (randomPath === 1) { // If the obstacle was on path 1 newCoin.y = 2732 * 2 / 3 + 80; // Place coin on path 2 newCoin.rotation = Math.PI; // Rotate 180 degrees } else { // If the obstacle was on path 2 newCoin.y = 2732 / 3 - 80; // Place coin on path 1 newCoin.rotation = 0; // No rotation } // Check for overlap with obstacles validPosition = true; for (var j = 0; j < game.children.length; j++) { if (game.children[j] instanceof Obstacle && newCoin.intersects(game.children[j])) { validPosition = false; break; } } attempts++; } // If a valid position is found within the attempts, add the coin and its group if (validPosition) { coins.push(newCoin); game.addChild(newCoin); // Spawn coin group (rest of the code for spawning grouped coins remains the same) // ... } } Explanation of Changes: Track Last Path: We've introduced a variable lastPath to keep track of the path where the most recent obstacle was spawned. Opposite Path Placement: Now, the coin is placed on the opposite path to the last spawned obstacle. Overlap Check: An overlap check ensures the coin's initial position doesn't collide with any existing obstacles. If it does, the coin is repositioned, and the process repeats until a valid position is found. Limited Attempts: A maximum of 10 attempts are allowed to find a valid position to avoid infinite loops in case there's no space.
User prompt
To prevent coins from overlapping with obstacles when they spawn, we'll need to modify the coin spawning logic in the spawnCollectible function. Here's the improved code with the necessary adjustments: JavaScript function spawnCollectible() { // ... (rest of the code for life and shield spawning remains the same) // 50% chance to spawn a coin var newCoin = new Coin(); var randomPath = Math.random() > 0.5 ? 1 : 2; // Choose a random path (1 or 2) var validPosition = false; var maxAttempts = 10; // Maximum attempts to find a valid spawn position var attempts = 0; while (!validPosition && attempts < maxAttempts) { newCoin.x = 2048 + Math.random() * 500; // Place coin on the path OPPOSITE to the most recent obstacle if (randomPath === 1) { // If the obstacle was on path 1 newCoin.y = 2732 * 2 / 3 + 80; // Place coin on path 2 newCoin.rotation = Math.PI; // Rotate 180 degrees } else { // If the obstacle was on path 2 newCoin.y = 2732 / 3 - 80; // Place coin on path 1 newCoin.rotation = 0; // No rotation } // Check for overlap with obstacles validPosition = true; for (var j = 0; j < game.children.length; j++) { if (game.children[j] instanceof Obstacle && newCoin.intersects(game.children[j])) { validPosition = false; break; } } attempts++; } // If a valid position is found within the attempts, add the coin and its group if (validPosition) { coins.push(newCoin); game.addChild(newCoin); // Spawn coin group (rest of the code for spawning grouped coins remains the same) // ... } } Use code with caution. Key Changes: Track Last Path: We've introduced a variable lastPath to keep track of the path where the most recent obstacle was spawned. Opposite Path Placement: Now, the coin is placed on the opposite path to the last spawned obstacle. Overlap Check: An overlap check ensures the coin's initial position doesn't collide with any existing obstacles. If it does, the coin is repositioned, and the process repeats until a valid position is found. Limited Attempts: A maximum of 10 attempts are allowed to find a valid position to avoid infinite loops in case there's no space.
User prompt
Bug Identification: The main issue is that the code section responsible for spawning collectibles has a logic error. Here's the problematic part: JavaScript var collectibleChance = Math.random(); if (collectibleChance < 0.2) { // ... spawn a life } else if (collectibleChance < 0.5) { // ... spawn a shield } else { // ... spawn a coin } Use code with caution. In this logic: There's a 20% chance of spawning a life (collectibleChance < 0.2). If a life isn't spawned, there's then a 30% chance of spawning a shield (collectibleChance < 0.5). However, this check is flawed because if a life wasn't spawned, then collectibleChance is already guaranteed to be at least 0.2. So, the condition for spawning a shield will never be true. This leaves the remaining 50% chance always allocated to spawning coins. Solution: To fix this, you need to adjust the conditions for spawning lives and shields: JavaScript var collectibleChance = Math.random(); if (collectibleChance < 0.2) { // ... spawn a life } else if (collectibleChance >= 0.2 && collectibleChance < 0.5) { // Correct the condition // ... spawn a shield } else { // ... spawn a coin } Use code with caution. Now, the logic is: 0% to 20%: Spawn a life 20% to 50%: Spawn a shield 50% to 100%: Spawn a coin This way, each collectible type has its intended chance of spawning.
User prompt
Sheild chance : 30 % Health Chance : 20 % Coin Chance : 50 %
User prompt
sheild and lives are not spawning fix the bug
User prompt
increase the frequency of the coins
Code edit (1 edits merged)
Please save this source code
User prompt
remove this probabilty between the collectables.
/****
* Classes
****/
var Background = Container.expand(function () {
var self = Container.call(this);
var backgroundGraphics = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
backgroundGraphics.alpha = 0.5;
var zoomDirection = 1;
self.update = function () {
if (this.scale.x >= 1.0025) {
zoomDirection = -1;
} else if (this.scale.x <= 0.9975) {
zoomDirection = 1;
}
this.scale.x += 0.000025 * zoomDirection;
this.scale.y += 0.000025 * zoomDirection;
};
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x -= 30;
if (self.x < -self.width) {
self.destroy();
}
};
});
var Dash = Container.expand(function () {
var self = Container.call(this);
var dashGraphics = self.attachAsset('dash', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.opacity = 0.4;
self.update = function () {
self.x -= self.speed;
self.alpha -= 0.01;
if (self.alpha <= 0) {
self.destroy();
}
};
});
var DisplayLife = Container.expand(function () {
var self = Container.call(this);
var lifeGraphics = self.attachAsset('life', {
anchorX: 0.5,
anchorY: 0.5
});
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.update = function () {
self.x -= self.speed;
self.x += Math.sin(LK.ticks / 10) * 2.5;
if (self.x < -self.width) {
self.destroy();
}
};
});
var Life = Container.expand(function () {
var self = Container.call(this);
var lifeGraphics = self.attachAsset('life', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x -= 5;
if (self.x < -self.width) {
self.destroy();
}
};
});
var Ninja = Container.expand(function () {
var self = Container.call(this);
var ninjaGraphics = self.attachAsset('ninja', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.update = function () {
if (self.currentPath === 'lower' && self.y >= path2.y - self.height && !self.dashActive) {
var dash = new Dash();
dash.x = self.x - self.width / 2;
dash.y = self.y;
game.addChildAt(dash, game.getChildIndex(ninja));
self.dashActive = true;
LK.setTimeout(function () {
dash.destroy();
self.dashActive = false;
}, 100);
} else if (self.currentPath === 'upper' && self.y <= path1.y - self.height && !self.dashActive) {
var dash = new Dash();
dash.x = self.x - self.width / 2;
dash.y = self.y;
game.addChildAt(dash, game.getChildIndex(ninja));
self.dashActive = true;
LK.setTimeout(function () {
dash.destroy();
self.dashActive = false;
}, 50);
}
if (self.currentPath === 'upper' && self.y > path1.y - self.height - 50) {
self.y -= 10;
if (self.y <= path1.y - self.height - 50) {
self.y = path1.y - self.height - 50;
}
} else if (self.currentPath === 'lower' && self.y < path2.y - self.height + 50) {
self.y += 10;
if (self.y >= path2.y - self.height + 50) {
self.y = path2.y - self.height + 50;
}
}
scoreTxt.setText(ninja.distanceTraveled + 'm'); // Update the score display
for (var i = coins.length - 1; i >= 0; i--) {
if (self.intersects(coins[i])) {
coinCounter++;
scoreMultiplier = 2;
LK.setTimeout(function () {
scoreMultiplier = 1;
}, 5000);
coins[i].destroy();
coins.splice(i, 1);
i--;
}
}
for (var i = lives.length - 1; i >= 0; i--) {
if (self.intersects(lives[i])) {
self.lives++;
lives[i].destroy();
lives.splice(i, 1);
i--;
// Update the display lives
var life = game.addChild(new DisplayLife());
life.x = 100 + (self.lives - 1) * 100;
life.y = path1.y - 150;
game.setChildIndex(life, game.children.length - 1);
}
}
for (var i = shields.length - 1; i >= 0; i--) {
if (self.intersects(shields[i])) {
self.invincible = true;
ninjaGraphics.tint = 0x0000ff; // Change tint to blue
// Add shield icon and timer display
if (!self.shieldIcon) {
self.shieldIcon = new Text2('10s', {
size: 100,
fill: "#ffffff"
});
self.shieldIcon.anchor.set(0.5, 0.5);
self.shieldIcon.x = 100;
self.shieldIcon.y = 2732 / 2;
LK.gui.left.addChild(self.shieldIcon);
}
var shieldTimeLeft = 10;
self.shieldInterval = LK.setInterval(function () {
shieldTimeLeft--;
self.shieldIcon.setText(shieldTimeLeft + 's');
if (shieldTimeLeft <= 0) {
LK.clearInterval(self.shieldInterval);
self.shieldIcon.destroy();
self.shieldIcon = null;
}
}, 1000);
if (self.shieldTimeout) {
LK.clearTimeout(self.shieldTimeout);
}
self.shieldTimeout = LK.setTimeout(function () {
self.invincible = false;
ninjaGraphics.tint = 0xffffff; // Reset tint to white
self.shieldTimeout = null;
if (self.shieldIcon) {
self.shieldIcon.destroy();
self.shieldIcon = null;
}
LK.clearInterval(self.shieldInterval);
}, 10000);
shields[i].destroy();
shields.splice(i, 1);
i--;
}
}
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] instanceof Obstacle && self.intersects(game.children[i])) {
if (self.invincible) {
// Destroy the obstacle and show destruction effect
LK.effects.flashObject(game.children[i], 0xff0000, 500); // Flash red before destroying
game.children[i].destroy();
continue; // Skip the rest of the loop for this obstacle
}
// Reduce the lives by one
self.lives--;
// Update the display
updateDisplayLives();
// If no lives left, game over
if (self.lives === 0) {
LK.showGameOver();
}
// Make ninja invincible for 3 seconds if not already invincible
if (!self.invincible) {
self.invincible = true;
ninjaGraphics.alpha = 1;
var opacityDirection = -1;
var _opacityChange = function opacityChange() {
ninjaGraphics.alpha += 0.18 * opacityDirection;
if (ninjaGraphics.alpha <= 0.1) {
opacityDirection = 1;
} else if (ninjaGraphics.alpha >= 1) {
opacityDirection = -1;
}
if (self.invincible) {
LK.setTimeout(_opacityChange, 60);
} else {
ninjaGraphics.alpha = 1;
}
};
LK.setTimeout(_opacityChange, 60);
LK.setTimeout(function () {
self.invincible = false;
ninjaGraphics.alpha = 1; // Reset opacity to 1 when invincibility ends
}, 3000);
if (self.shieldTimeout) {
LK.clearTimeout(self.shieldTimeout);
self.shieldTimeout = null;
}
}
}
}
};
self.down = function () {
if (self.currentPath === 'lower') {
targetPath = 'upper';
self.y -= 20;
self.x += 10;
} else {
targetPath = 'lower';
self.y += 20;
self.x -= 10;
}
};
self.up = function () {
targetPath = null;
};
});
var NinjaStar = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('ninjaStar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -5;
self.update = function () {
self.y += self.speed;
};
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 30;
self.update = function () {
self.x -= self.speed;
if (self.x < -self.width) {
self.destroy();
}
};
});
var Path = Container.expand(function () {
var self = Container.call(this);
var pathGraphics = self.attachAsset('path', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 30;
self.update = function () {
self.x -= self.speed;
if (self.x < -self.width) {
self.destroy();
}
};
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x -= 5;
if (self.x < -self.width) {
self.destroy();
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var coins = [];
var lives = [];
var shields = [];
var coinCounter = 0;
var scoreMultiplier = 1;
var invincible = false;
function spawnCollectible() {
var newCollectible = new Coin();
coins.push(newCollectible);
var randomPath = Math.random() > 0.5 ? 1 : 2;
var validPosition = false;
var maxAttempts = 10;
var attempts = 0;
while (!validPosition && attempts < maxAttempts) {
newCollectible.x = 2048 + Math.random() * 500; // Introduce random horizontal spacing
if (randomPath === 1) {
newCollectible.y = 2732 * 2 / 3 - 80; // Place coin on the opposite path
newCollectible.rotation = 0; // No rotation
} else {
newCollectible.y = 2732 / 3 + 80; // Place coin on the opposite path
newCollectible.rotation = Math.PI; // Rotate 180 degrees
}
validPosition = true;
for (var j = 0; j < game.children.length; j++) {
if (game.children[j] instanceof Obstacle && newCollectible.intersects(game.children[j])) {
validPosition = false;
break;
}
}
attempts++;
}
var newLife = new Life();
lives.push(newLife);
game.addChild(newLife);
var newShield = new Shield();
shields.push(newShield);
game.addChild(newShield);
var coinGroupSize = [5, 7, 12][Math.floor(Math.random() * 3)]; // Group size of 5, 7, or 12
for (var i = 0; i < coinGroupSize; i++) {
var groupedCoin = new Coin();
groupedCoin.x = newCollectible.x + i * 150; // Horizontal spacing between coins in a group
groupedCoin.y = newCollectible.y;
groupedCoin.rotation = newCollectible.rotation;
// Check for overlap with obstacles
var overlap = false;
for (var j = 0; j < game.children.length; j++) {
if (game.children[j] instanceof Obstacle && groupedCoin.intersects(game.children[j])) {
overlap = true;
break;
}
}
if (!overlap) {
coins.push(groupedCoin);
game.addChild(groupedCoin);
}
}
}
LK.setInterval(spawnCollectible, 3000);
var background = game.addChild(new Background());
var path1 = game.addChild(new Path());
path1.y = 2732 / 3;
var path2 = game.addChild(new Path());
path2.y = 2732 * 2 / 3;
var ninja = game.addChild(new Ninja());
ninja.x = 1024;
ninja.y = path2.y - ninja.height;
ninja.currentPath = 'lower';
ninja.lives = 3;
ninja.distanceTraveled = 0; // Initialize distance traveled to 0
var targetPath;
// Display the lives a little bit more up in y axis from the upper path
function updateDisplayLives() {
for (var i = game.children.length - 1; i >= 0; i--) {
if (game.children[i] instanceof DisplayLife) {
game.children[i].destroy();
}
}
for (var i = 0; i < ninja.lives; i++) {
var life = game.addChild(new DisplayLife());
life.x = 100 + i * 100; // Move the lives little bit right on x axis
life.y = path1.y - 150; // Move lives a little bit more up
game.setChildIndex(life, game.children.length - 1);
}
}
updateDisplayLives();
// Display the score based on the distance traveled
var scoreTxt = new Text2('0m', {
resolution: 2,
size: 100,
fill: "#ffffff",
font: "lexend"
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = path1.y - 450; // Move the score display a little bit more up, above the upper path
LK.gui.top.addChild(scoreTxt);
game.down = function (x, y, obj) {
if (ninja.currentPath === 'lower' && ninja.y >= path2.y - ninja.height || ninja.currentPath === 'upper' && ninja.y <= path1.y - ninja.height) {
if (ninja.currentPath === 'lower') {
targetPath = 'upper';
ninja.y -= 500; // Increase the jump speed
ninja.scale.y *= -1; // Flip vertically
// No code to insert, we are removing the timeout that destroys the dash
} else {
targetPath = 'lower';
ninja.y += 500; // Increase the jump speed
ninja.scale.y *= -1; // Flip vertically
// No code to insert, we are removing the timeout that destroys the dash
}
ninja.currentPath = targetPath;
}
};
game.update = function () {
var lastPath = 0;
if (LK.ticks % 50 == 0) {
var randomPath = Math.random() > 0.5 ? 1 : 2;
var spawnDistance = randomPath === lastPath ? 512 : 4096;
var obstacleGroupSize = Math.floor(Math.random() * 3) + 1;
for (var i = 0; i < obstacleGroupSize; i++) {
var newObstacle = new Obstacle();
newObstacle.x = spawnDistance + i * newObstacle.width;
if (randomPath === 1) {
newObstacle.y = 2732 / 3 + 80;
} else {
newObstacle.y = 2732 * 2 / 3 - 80;
}
if (randomPath === 1) {
newObstacle.rotation = Math.PI; // Rotate 180 degrees
} else {
newObstacle.rotation = 0; // No rotation
}
game.addChildAt(newObstacle, game.children.length);
}
lastPath = randomPath;
}
if (LK.ticks % 20 == 0) {
var newPath1 = new Path();
newPath1.x = 2048 + 100; // Increase the x-coordinate by 100 to create a gap
newPath1.y = 2732 / 3;
game.addChild(newPath1);
var newPath2 = new Path();
newPath2.x = 2048 + 100; // Increase the x-coordinate by 100 to create a gap
newPath2.y = 2732 * 2 / 3;
game.addChild(newPath2);
ninja.distanceTraveled += 100; // Increase distance traveled by 100 meters for each new path
}
};
Ninja Star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A minimalist icon depicting a ninja head silhouette in black. The silhouette should be simple and recognizable, with a headband or mask detail. The background should be transparent or a contrasting color (e.g., red or white).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Coin. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Shield. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Transparent sheild bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Create a series of curved, tapered lines that originate from the ninja's body and extend outward in the direction of movement. The lines should vary in length and thickness, with a sense of energy and dynamism.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
backgroundMusic
Sound effect
coinCollect
Sound effect
jumpSound
Sound effect
footstepSound1
Sound effect
footstepSound2
Sound effect
footstepSound3
Sound effect
shooterSpawn
Sound effect
destructorSpawn
Sound effect
attackerSpawn
Sound effect
shooterAttack
Sound effect
destructorAttack
Sound effect
attackerAttack
Sound effect
enemyHit
Sound effect
shieldCollect
Sound effect
shieldCollectSound
Sound effect
ninjaGrunt
Sound effect
destructorAttackSound
Sound effect