User prompt
buat jangkauan peluru player 2x jauh
User prompt
reduce number of jar
User prompt
reduce number of jar. make jar broke after 3 time hit
User prompt
fix nusic background
User prompt
buat logika saat pindah level ninja dan platform bersama munculnya
User prompt
ninja bisa mati saat 5 kali diserang.
User prompt
buat satu di antar jar yang ada bisa melontar api ke bawah sebagai serangan
User prompt
add sound asset for jar
User prompt
buat jar bisa loncat loncat dan bergerak ke kanan dan ke kiri ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
karakter ninja bisa bolak balik imagenya
User prompt
pertajam gambar background
User prompt
add background asset
User prompt
buat ninja bisa di gerakn dengan di swipe kanan atau kiri
User prompt
buat seluruh platform otomatis bergerak random ke kanan atau ke kiri bolak balik ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat aturan bila seluruh guci hancur baru pindah level ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat naik level setelah guci pecah ditembak
User prompt
buat animasi guci pecah ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat guci guci antik di atas permukaan platform dan guci pecah saat diserang ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Ninja Sky Strike
Initial prompt
buat game random static platform. ninja vs evil terbang
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = (Math.random() - 0.5) * 3; self.speedY = (Math.random() - 0.5) * 3; self.health = 1; self.update = function () { self.x += self.speedX; self.y += self.speedY; // Bounce off screen edges if (self.x < 30 || self.x > 2018) { self.speedX *= -1; } if (self.y < 30 || self.y > 2702) { self.speedY *= -1; } }; return self; }); var FireProjectile = Container.expand(function () { var self = Container.call(this); var fireGraphics = self.attachAsset('fireProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 8; // Downward speed self.lifetime = 0; self.gravity = 0.3; self.update = function () { self.x += self.speedX; self.y += self.speedY; self.speedY += self.gravity; // Fire falls with gravity self.lifetime++; // Add fire effect with slight flickering fireGraphics.alpha = 0.8 + Math.sin(self.lifetime * 0.3) * 0.2; }; return self; }); var Jar = Container.expand(function () { var self = Container.call(this); var jarGraphics = self.attachAsset('jar', { anchorX: 0.5, anchorY: 1.0 }); self.broken = false; self.jumpTimer = Math.random() * 120 + 60; // Random jump intervals self.moveTimer = Math.random() * 180 + 120; // Random movement intervals self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction self.isJumping = false; self.originalY = 0; // Store original platform position self.update = function () { if (!self.broken && self.platform) { // Update timers self.jumpTimer--; self.moveTimer--; // Jump behavior if (self.jumpTimer <= 0 && !self.isJumping) { self.jump(); self.jumpTimer = Math.random() * 180 + 120; // Reset jump timer } // Movement behavior if (self.moveTimer <= 0) { self.moveDirection *= -1; // Change direction self.moveTimer = Math.random() * 240 + 180; // Reset move timer } // Horizontal movement within platform bounds var moveAmount = Math.sin(LK.ticks * 0.05) * 2 * self.moveDirection; var newX = self.platform.x + moveAmount; // Keep jar on platform var platformWidth = self.platform.width || 200; if (newX >= self.platform.x - platformWidth / 3 && newX <= self.platform.x + platformWidth / 3) { self.x = newX; } else { self.x = self.platform.x; } // Keep jar positioned on platform if (!self.isJumping) { self.y = self.platform.y - self.platform.height / 2; self.originalY = self.y; } // Fire attack if this jar can attack if (self.canAttack) { self.attackTimer--; if (self.attackTimer <= 0) { self.fireAttack(); self.attackTimer = Math.random() * 180 + 120; // Random fire intervals } } } }; self.jump = function () { if (!self.isJumping && !self.broken) { self.isJumping = true; var jumpHeight = 80 + Math.random() * 40; // Random jump height // Play jar sound when jumping LK.getSound('jar').play(); // Jump up tween(self, { y: self.originalY - jumpHeight }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Fall back down tween(self, { y: self.originalY }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.isJumping = false; } }); } }); } }; self.breakJar = function () { if (!self.broken) { self.broken = true; LK.getSound('jarBreak').play(); LK.setScore(LK.getScore() + 5); scoreTxt.setText(LK.getScore()); // Track jars broken for level progression jarsBrokenThisLevel++; // Check if all jars are broken (count remaining unbroken jars) var remainingJars = 0; for (var k = 0; k < jars.length; k++) { if (!jars[k].broken) { remainingJars++; } } // Level up only when all jars are broken (only 1 remaining = this jar that just broke) if (remainingJars <= 1) { // Level up! currentLevel++; jarsBrokenThisLevel = 0; levelTxt.setText('Level ' + currentLevel); // Flash screen gold for level up LK.effects.flashScreen(0xFFD700, 800); // Hide ninja temporarily for level transition ninja.alpha = 0; // Generate new platforms and jars for next level LK.setTimeout(function () { // Clear existing platforms and jars for (var i = platforms.length - 1; i >= 0; i--) { platforms[i].destroy(); } for (var j = jars.length - 1; j >= 0; j--) { if (!jars[j].broken) { jars[j].destroy(); } } platforms = []; jars = []; // Reset ninja position to starting position ninja.x = 1024; ninja.y = 2500; ninja.velocityY = 0; ninja.onGround = false; // Make platforms and ninja appear together generatePlatforms(); // Fade in ninja with platforms tween(ninja, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); }, 500); } // Create multiple jar fragments for breaking effect var fragments = []; for (var i = 0; i < 4; i++) { var fragment = LK.getAsset('jar', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, tint: 0x8b4513 }); fragment.x = self.x + (Math.random() - 0.5) * 20; fragment.y = self.y + (Math.random() - 0.5) * 20; fragments.push(fragment); game.addChild(fragment); // Animate each fragment var fragmentSpeedX = (Math.random() - 0.5) * 200; var fragmentSpeedY = -Math.random() * 150 - 50; var fragmentRotation = (Math.random() - 0.5) * 6; tween(fragment, { x: fragment.x + fragmentSpeedX, y: fragment.y + fragmentSpeedY + 100, rotation: fragmentRotation, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { fragment.destroy(); } }); } // Main jar breaking animation - shake and fade tween(jarGraphics, { rotation: 0.3 }, { duration: 50, easing: tween.easeInOut, onFinish: function onFinish() { tween(jarGraphics, { rotation: -0.3, scaleX: 1.2, scaleY: 0.8 }, { duration: 50, easing: tween.easeInOut, onFinish: function onFinish() { tween(jarGraphics, { scaleX: 0.1, scaleY: 0.1, alpha: 0, rotation: 0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); } }); } }); } }; self.fireAttack = function () { if (!self.broken && self.canAttack) { var fireProjectile = new FireProjectile(); fireProjectile.x = self.x; fireProjectile.y = self.y + 20; fireProjectile.speedX = (Math.random() - 0.5) * 2; // Slight horizontal variation fireProjectiles.push(fireProjectile); game.addChild(fireProjectile); LK.getSound('jarFire').play(); } }; return self; }); var Ninja = Container.expand(function () { var self = Container.call(this); var ninjaGraphics = self.attachAsset('ninja', { anchorX: 0.5, anchorY: 0.5 }); self.velocityY = 0; self.onGround = false; self.gravity = 0.8; self.jumpPower = -18; self.health = 5; self.attackCooldown = 0; self.update = function () { // Apply gravity if (!self.onGround) { self.velocityY += self.gravity; } self.y += self.velocityY; // Reset ground state self.onGround = false; // Check platform collisions for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; if (self.intersects(platform) && self.velocityY > 0) { var platformTop = platform.y - platform.height / 2; var ninjaBottom = self.y + self.height / 2; if (ninjaBottom > platformTop - 20) { self.y = platformTop - self.height / 2; self.velocityY = 0; self.onGround = true; // Move ninja with platform self.x += platform.moveSpeed * platform.moveDirection; break; } } } // Fall off screen check if (self.y > 2800) { LK.showGameOver(); } // Reduce attack cooldown if (self.attackCooldown > 0) { self.attackCooldown--; } }; self.jump = function () { if (self.onGround) { self.velocityY = self.jumpPower; self.onGround = false; LK.getSound('jump').play(); } }; self.attack = function (targetX, targetY) { if (self.attackCooldown <= 0) { var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); projectile.speedX = dx / distance * 24; projectile.speedY = dy / distance * 24; projectiles.push(projectile); game.addChild(projectile); self.attackCooldown = 20; LK.getSound('attack').play(); } }; self.moveLeft = function () { self.x -= ninjaSpeed; if (self.x < 50) self.x = 50; // Flip ninja to face left ninjaGraphics.scaleX = -1; }; self.moveRight = function () { self.x += ninjaSpeed; if (self.x > 1998) self.x = 1998; // Flip ninja to face right ninjaGraphics.scaleX = 1; }; return self; }); var Platform = Container.expand(function () { var self = Container.call(this); var platformGraphics = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5 }); self.moveSpeed = Math.random() * 2 + 1; // Random speed between 1-3 self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction self.leftBound = 100; self.rightBound = 1948; self.update = function () { // Move platform horizontally self.x += self.moveSpeed * self.moveDirection; // Bounce off boundaries if (self.x <= self.leftBound || self.x >= self.rightBound) { self.moveDirection *= -1; } }; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.lifetime = 0; self.update = function () { self.x += self.speedX; self.y += self.speedY; self.lifetime++; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb }); /**** * Game Code ****/ // Create background var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, scaleX: 1.0, scaleY: 1.0 }); game.addChild(background); var ninja = new Ninja(); var platforms = []; var enemies = []; var projectiles = []; var jars = []; var fireProjectiles = []; var enemySpawnTimer = 0; var difficultyTimer = 0; var currentLevel = 1; var jarsPerLevel = 5; var jarsBrokenThisLevel = 0; var touchStartX = 0; var touchStartY = 0; var isSwipeMove = false; var ninjaSpeed = 8; var ninjaMaxHealth = 5; var ninjaCurrentHealth = 5; // Create score display var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create level display var levelTxt = new Text2('Level 1', { size: 60, fill: 0xFFD700 }); levelTxt.anchor.set(0, 0); levelTxt.x = 120; levelTxt.y = 20; LK.gui.topLeft.addChild(levelTxt); // Create health display var healthTxt = new Text2('Health: 5', { size: 60, fill: 0xff0000 }); healthTxt.anchor.set(1, 0); healthTxt.x = -20; healthTxt.y = 20; LK.gui.topRight.addChild(healthTxt); // Generate random platforms function generatePlatforms() { platforms = []; // Ground platform var groundPlatform = new Platform(); groundPlatform.x = 1024; groundPlatform.y = 2600; groundPlatform.width = 400; // Start platforms invisible for coordinated appearance groundPlatform.alpha = 0; platforms.push(groundPlatform); game.addChild(groundPlatform); // Animate ground platform appearance tween(groundPlatform, { alpha: 1 }, { duration: 600, easing: tween.easeInOut }); // Random platforms - increase count with level var platformCount = Math.min(8 + currentLevel, 15); for (var i = 0; i < platformCount; i++) { var platform = new Platform(); platform.x = Math.random() * 1600 + 200; platform.y = 2400 - i * 250 - Math.random() * 100; // Make platforms smaller at higher levels for more challenge platform.width = Math.max(150 + Math.random() * 100 - currentLevel * 5, 80); // Start platforms invisible for coordinated appearance platform.alpha = 0; platforms.push(platform); game.addChild(platform); // Animate platform appearance with staggered timing tween(platform, { alpha: 1 }, { duration: 600, delay: i * 100, easing: tween.easeInOut }); // Ensure enough jars are available for level completion var jarChance = Math.min(0.8, 0.6 + currentLevel * 0.05); if (Math.random() < jarChance) { var jar = new Jar(); jar.x = platform.x; jar.y = platform.y - platform.height / 2; jar.platform = platform; // Assign platform reference to jar // Start jars invisible for coordinated appearance jar.alpha = 0; // Randomly make one jar per few platforms a fire attacker jar.canAttack = Math.random() < 0.3; // 30% chance if (jar.canAttack) { jar.attackTimer = Math.random() * 180 + 60; } jars.push(jar); game.addChild(jar); // Animate jar appearance slightly after platform tween(jar, { alpha: 1 }, { duration: 400, delay: i * 100 + 200, easing: tween.easeInOut }); } } } function spawnEnemy() { var enemy = new Enemy(); // Spawn from random edge var side = Math.floor(Math.random() * 4); switch (side) { case 0: // Top enemy.x = Math.random() * 2048; enemy.y = -30; break; case 1: // Right enemy.x = 2078; enemy.y = Math.random() * 2732; break; case 2: // Bottom enemy.x = Math.random() * 2048; enemy.y = 2762; break; case 3: // Left enemy.x = -30; enemy.y = Math.random() * 2732; break; } enemies.push(enemy); game.addChild(enemy); } // Initialize game elements generatePlatforms(); ninja.x = 1024; ninja.y = 2500; game.addChild(ninja); // Touch controls game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; isSwipeMove = false; }; game.up = function (x, y, obj) { if (!isSwipeMove) { // If touching near ninja, jump var dx = x - ninja.x; var dy = y - ninja.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { ninja.jump(); } else { // Attack in direction of touch ninja.attack(x, y); } } }; game.move = function (x, y, obj) { var swipeDistanceX = x - touchStartX; var swipeDistanceY = Math.abs(y - touchStartY); // Detect horizontal swipe (minimum 50px horizontal, less than 100px vertical) if (Math.abs(swipeDistanceX) > 50 && swipeDistanceY < 100) { isSwipeMove = true; if (swipeDistanceX > 0) { // Swipe right ninja.moveRight(); } else { // Swipe left ninja.moveLeft(); } } }; game.update = function () { // Spawn enemies enemySpawnTimer++; difficultyTimer++; var spawnRate = Math.max(180 - Math.floor(difficultyTimer / 300), 60); if (enemySpawnTimer >= spawnRate) { spawnEnemy(); enemySpawnTimer = 0; } // Check projectile vs enemy collisions for (var p = projectiles.length - 1; p >= 0; p--) { var projectile = projectiles[p]; // Remove old projectiles if (projectile.lifetime > 180 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) { projectile.destroy(); projectiles.splice(p, 1); continue; } // Check enemy hits for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; if (projectile.intersects(enemy)) { // Hit enemy LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); LK.getSound('enemyHit').play(); LK.effects.flashObject(enemy, 0xffffff, 200); enemy.destroy(); enemies.splice(e, 1); projectile.destroy(); projectiles.splice(p, 1); break; } // Check jar hits for (var j = jars.length - 1; j >= 0; j--) { var jar = jars[j]; if (!jar.broken && projectile.intersects(jar)) { jar.breakJar(); jars.splice(j, 1); projectile.destroy(); projectiles.splice(p, 1); break; } } } } // Update jar positions to follow their platforms for (var j = 0; j < jars.length; j++) { var jar = jars[j]; if (!jar.broken && jar.platform) { jar.x = jar.platform.x; } } // Check ninja vs enemy collisions for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; if (ninja.intersects(enemy)) { ninja.health--; ninjaCurrentHealth = ninja.health; healthTxt.setText('Health: ' + ninjaCurrentHealth); LK.effects.flashObject(ninja, 0xff0000, 500); enemy.destroy(); enemies.splice(e, 1); if (ninja.health <= 0) { LK.showGameOver(); } } } // Update and check fire projectiles for (var f = fireProjectiles.length - 1; f >= 0; f--) { var fireProjectile = fireProjectiles[f]; // Remove fire projectiles that are off screen or too old if (fireProjectile.lifetime > 300 || fireProjectile.y > 2800 || fireProjectile.x < -50 || fireProjectile.x > 2098) { fireProjectile.destroy(); fireProjectiles.splice(f, 1); continue; } // Check fire projectile vs ninja collision if (fireProjectile.intersects(ninja)) { ninja.health--; ninjaCurrentHealth = ninja.health; healthTxt.setText('Health: ' + ninjaCurrentHealth); LK.effects.flashObject(ninja, 0xff4500, 500); fireProjectile.destroy(); fireProjectiles.splice(f, 1); if (ninja.health <= 0) { LK.showGameOver(); } } } // Keep ninja on screen horizontally if (ninja.x < 40) ninja.x = 40; if (ninja.x > 2008) ninja.x = 2008; }; // Play background music LK.playMusic('ninjai');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 3;
self.speedY = (Math.random() - 0.5) * 3;
self.health = 1;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Bounce off screen edges
if (self.x < 30 || self.x > 2018) {
self.speedX *= -1;
}
if (self.y < 30 || self.y > 2702) {
self.speedY *= -1;
}
};
return self;
});
var FireProjectile = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('fireProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 8; // Downward speed
self.lifetime = 0;
self.gravity = 0.3;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += self.gravity; // Fire falls with gravity
self.lifetime++;
// Add fire effect with slight flickering
fireGraphics.alpha = 0.8 + Math.sin(self.lifetime * 0.3) * 0.2;
};
return self;
});
var Jar = Container.expand(function () {
var self = Container.call(this);
var jarGraphics = self.attachAsset('jar', {
anchorX: 0.5,
anchorY: 1.0
});
self.broken = false;
self.jumpTimer = Math.random() * 120 + 60; // Random jump intervals
self.moveTimer = Math.random() * 180 + 120; // Random movement intervals
self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
self.isJumping = false;
self.originalY = 0; // Store original platform position
self.update = function () {
if (!self.broken && self.platform) {
// Update timers
self.jumpTimer--;
self.moveTimer--;
// Jump behavior
if (self.jumpTimer <= 0 && !self.isJumping) {
self.jump();
self.jumpTimer = Math.random() * 180 + 120; // Reset jump timer
}
// Movement behavior
if (self.moveTimer <= 0) {
self.moveDirection *= -1; // Change direction
self.moveTimer = Math.random() * 240 + 180; // Reset move timer
}
// Horizontal movement within platform bounds
var moveAmount = Math.sin(LK.ticks * 0.05) * 2 * self.moveDirection;
var newX = self.platform.x + moveAmount;
// Keep jar on platform
var platformWidth = self.platform.width || 200;
if (newX >= self.platform.x - platformWidth / 3 && newX <= self.platform.x + platformWidth / 3) {
self.x = newX;
} else {
self.x = self.platform.x;
}
// Keep jar positioned on platform
if (!self.isJumping) {
self.y = self.platform.y - self.platform.height / 2;
self.originalY = self.y;
}
// Fire attack if this jar can attack
if (self.canAttack) {
self.attackTimer--;
if (self.attackTimer <= 0) {
self.fireAttack();
self.attackTimer = Math.random() * 180 + 120; // Random fire intervals
}
}
}
};
self.jump = function () {
if (!self.isJumping && !self.broken) {
self.isJumping = true;
var jumpHeight = 80 + Math.random() * 40; // Random jump height
// Play jar sound when jumping
LK.getSound('jar').play();
// Jump up
tween(self, {
y: self.originalY - jumpHeight
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Fall back down
tween(self, {
y: self.originalY
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
}
};
self.breakJar = function () {
if (!self.broken) {
self.broken = true;
LK.getSound('jarBreak').play();
LK.setScore(LK.getScore() + 5);
scoreTxt.setText(LK.getScore());
// Track jars broken for level progression
jarsBrokenThisLevel++;
// Check if all jars are broken (count remaining unbroken jars)
var remainingJars = 0;
for (var k = 0; k < jars.length; k++) {
if (!jars[k].broken) {
remainingJars++;
}
}
// Level up only when all jars are broken (only 1 remaining = this jar that just broke)
if (remainingJars <= 1) {
// Level up!
currentLevel++;
jarsBrokenThisLevel = 0;
levelTxt.setText('Level ' + currentLevel);
// Flash screen gold for level up
LK.effects.flashScreen(0xFFD700, 800);
// Hide ninja temporarily for level transition
ninja.alpha = 0;
// Generate new platforms and jars for next level
LK.setTimeout(function () {
// Clear existing platforms and jars
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].destroy();
}
for (var j = jars.length - 1; j >= 0; j--) {
if (!jars[j].broken) {
jars[j].destroy();
}
}
platforms = [];
jars = [];
// Reset ninja position to starting position
ninja.x = 1024;
ninja.y = 2500;
ninja.velocityY = 0;
ninja.onGround = false;
// Make platforms and ninja appear together
generatePlatforms();
// Fade in ninja with platforms
tween(ninja, {
alpha: 1
}, {
duration: 800,
easing: tween.easeInOut
});
}, 500);
}
// Create multiple jar fragments for breaking effect
var fragments = [];
for (var i = 0; i < 4; i++) {
var fragment = LK.getAsset('jar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
tint: 0x8b4513
});
fragment.x = self.x + (Math.random() - 0.5) * 20;
fragment.y = self.y + (Math.random() - 0.5) * 20;
fragments.push(fragment);
game.addChild(fragment);
// Animate each fragment
var fragmentSpeedX = (Math.random() - 0.5) * 200;
var fragmentSpeedY = -Math.random() * 150 - 50;
var fragmentRotation = (Math.random() - 0.5) * 6;
tween(fragment, {
x: fragment.x + fragmentSpeedX,
y: fragment.y + fragmentSpeedY + 100,
rotation: fragmentRotation,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
fragment.destroy();
}
});
}
// Main jar breaking animation - shake and fade
tween(jarGraphics, {
rotation: 0.3
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(jarGraphics, {
rotation: -0.3,
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(jarGraphics, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0,
rotation: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
}
});
}
});
}
};
self.fireAttack = function () {
if (!self.broken && self.canAttack) {
var fireProjectile = new FireProjectile();
fireProjectile.x = self.x;
fireProjectile.y = self.y + 20;
fireProjectile.speedX = (Math.random() - 0.5) * 2; // Slight horizontal variation
fireProjectiles.push(fireProjectile);
game.addChild(fireProjectile);
LK.getSound('jarFire').play();
}
};
return self;
});
var Ninja = Container.expand(function () {
var self = Container.call(this);
var ninjaGraphics = self.attachAsset('ninja', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.onGround = false;
self.gravity = 0.8;
self.jumpPower = -18;
self.health = 5;
self.attackCooldown = 0;
self.update = function () {
// Apply gravity
if (!self.onGround) {
self.velocityY += self.gravity;
}
self.y += self.velocityY;
// Reset ground state
self.onGround = false;
// Check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform) && self.velocityY > 0) {
var platformTop = platform.y - platform.height / 2;
var ninjaBottom = self.y + self.height / 2;
if (ninjaBottom > platformTop - 20) {
self.y = platformTop - self.height / 2;
self.velocityY = 0;
self.onGround = true;
// Move ninja with platform
self.x += platform.moveSpeed * platform.moveDirection;
break;
}
}
}
// Fall off screen check
if (self.y > 2800) {
LK.showGameOver();
}
// Reduce attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
self.jump = function () {
if (self.onGround) {
self.velocityY = self.jumpPower;
self.onGround = false;
LK.getSound('jump').play();
}
};
self.attack = function (targetX, targetY) {
if (self.attackCooldown <= 0) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
projectile.speedX = dx / distance * 24;
projectile.speedY = dy / distance * 24;
projectiles.push(projectile);
game.addChild(projectile);
self.attackCooldown = 20;
LK.getSound('attack').play();
}
};
self.moveLeft = function () {
self.x -= ninjaSpeed;
if (self.x < 50) self.x = 50;
// Flip ninja to face left
ninjaGraphics.scaleX = -1;
};
self.moveRight = function () {
self.x += ninjaSpeed;
if (self.x > 1998) self.x = 1998;
// Flip ninja to face right
ninjaGraphics.scaleX = 1;
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveSpeed = Math.random() * 2 + 1; // Random speed between 1-3
self.moveDirection = Math.random() < 0.5 ? -1 : 1; // Random initial direction
self.leftBound = 100;
self.rightBound = 1948;
self.update = function () {
// Move platform horizontally
self.x += self.moveSpeed * self.moveDirection;
// Bounce off boundaries
if (self.x <= self.leftBound || self.x >= self.rightBound) {
self.moveDirection *= -1;
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.lifetime = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.lifetime++;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Create background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 1.0,
scaleY: 1.0
});
game.addChild(background);
var ninja = new Ninja();
var platforms = [];
var enemies = [];
var projectiles = [];
var jars = [];
var fireProjectiles = [];
var enemySpawnTimer = 0;
var difficultyTimer = 0;
var currentLevel = 1;
var jarsPerLevel = 5;
var jarsBrokenThisLevel = 0;
var touchStartX = 0;
var touchStartY = 0;
var isSwipeMove = false;
var ninjaSpeed = 8;
var ninjaMaxHealth = 5;
var ninjaCurrentHealth = 5;
// Create score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create level display
var levelTxt = new Text2('Level 1', {
size: 60,
fill: 0xFFD700
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120;
levelTxt.y = 20;
LK.gui.topLeft.addChild(levelTxt);
// Create health display
var healthTxt = new Text2('Health: 5', {
size: 60,
fill: 0xff0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -20;
healthTxt.y = 20;
LK.gui.topRight.addChild(healthTxt);
// Generate random platforms
function generatePlatforms() {
platforms = [];
// Ground platform
var groundPlatform = new Platform();
groundPlatform.x = 1024;
groundPlatform.y = 2600;
groundPlatform.width = 400;
// Start platforms invisible for coordinated appearance
groundPlatform.alpha = 0;
platforms.push(groundPlatform);
game.addChild(groundPlatform);
// Animate ground platform appearance
tween(groundPlatform, {
alpha: 1
}, {
duration: 600,
easing: tween.easeInOut
});
// Random platforms - increase count with level
var platformCount = Math.min(8 + currentLevel, 15);
for (var i = 0; i < platformCount; i++) {
var platform = new Platform();
platform.x = Math.random() * 1600 + 200;
platform.y = 2400 - i * 250 - Math.random() * 100;
// Make platforms smaller at higher levels for more challenge
platform.width = Math.max(150 + Math.random() * 100 - currentLevel * 5, 80);
// Start platforms invisible for coordinated appearance
platform.alpha = 0;
platforms.push(platform);
game.addChild(platform);
// Animate platform appearance with staggered timing
tween(platform, {
alpha: 1
}, {
duration: 600,
delay: i * 100,
easing: tween.easeInOut
});
// Ensure enough jars are available for level completion
var jarChance = Math.min(0.8, 0.6 + currentLevel * 0.05);
if (Math.random() < jarChance) {
var jar = new Jar();
jar.x = platform.x;
jar.y = platform.y - platform.height / 2;
jar.platform = platform; // Assign platform reference to jar
// Start jars invisible for coordinated appearance
jar.alpha = 0;
// Randomly make one jar per few platforms a fire attacker
jar.canAttack = Math.random() < 0.3; // 30% chance
if (jar.canAttack) {
jar.attackTimer = Math.random() * 180 + 60;
}
jars.push(jar);
game.addChild(jar);
// Animate jar appearance slightly after platform
tween(jar, {
alpha: 1
}, {
duration: 400,
delay: i * 100 + 200,
easing: tween.easeInOut
});
}
}
}
function spawnEnemy() {
var enemy = new Enemy();
// Spawn from random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -30;
break;
case 1:
// Right
enemy.x = 2078;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2762;
break;
case 3:
// Left
enemy.x = -30;
enemy.y = Math.random() * 2732;
break;
}
enemies.push(enemy);
game.addChild(enemy);
}
// Initialize game elements
generatePlatforms();
ninja.x = 1024;
ninja.y = 2500;
game.addChild(ninja);
// Touch controls
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
isSwipeMove = false;
};
game.up = function (x, y, obj) {
if (!isSwipeMove) {
// If touching near ninja, jump
var dx = x - ninja.x;
var dy = y - ninja.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
ninja.jump();
} else {
// Attack in direction of touch
ninja.attack(x, y);
}
}
};
game.move = function (x, y, obj) {
var swipeDistanceX = x - touchStartX;
var swipeDistanceY = Math.abs(y - touchStartY);
// Detect horizontal swipe (minimum 50px horizontal, less than 100px vertical)
if (Math.abs(swipeDistanceX) > 50 && swipeDistanceY < 100) {
isSwipeMove = true;
if (swipeDistanceX > 0) {
// Swipe right
ninja.moveRight();
} else {
// Swipe left
ninja.moveLeft();
}
}
};
game.update = function () {
// Spawn enemies
enemySpawnTimer++;
difficultyTimer++;
var spawnRate = Math.max(180 - Math.floor(difficultyTimer / 300), 60);
if (enemySpawnTimer >= spawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
// Check projectile vs enemy collisions
for (var p = projectiles.length - 1; p >= 0; p--) {
var projectile = projectiles[p];
// Remove old projectiles
if (projectile.lifetime > 180 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
projectile.destroy();
projectiles.splice(p, 1);
continue;
}
// Check enemy hits
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (projectile.intersects(enemy)) {
// Hit enemy
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemy, 0xffffff, 200);
enemy.destroy();
enemies.splice(e, 1);
projectile.destroy();
projectiles.splice(p, 1);
break;
}
// Check jar hits
for (var j = jars.length - 1; j >= 0; j--) {
var jar = jars[j];
if (!jar.broken && projectile.intersects(jar)) {
jar.breakJar();
jars.splice(j, 1);
projectile.destroy();
projectiles.splice(p, 1);
break;
}
}
}
}
// Update jar positions to follow their platforms
for (var j = 0; j < jars.length; j++) {
var jar = jars[j];
if (!jar.broken && jar.platform) {
jar.x = jar.platform.x;
}
}
// Check ninja vs enemy collisions
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (ninja.intersects(enemy)) {
ninja.health--;
ninjaCurrentHealth = ninja.health;
healthTxt.setText('Health: ' + ninjaCurrentHealth);
LK.effects.flashObject(ninja, 0xff0000, 500);
enemy.destroy();
enemies.splice(e, 1);
if (ninja.health <= 0) {
LK.showGameOver();
}
}
}
// Update and check fire projectiles
for (var f = fireProjectiles.length - 1; f >= 0; f--) {
var fireProjectile = fireProjectiles[f];
// Remove fire projectiles that are off screen or too old
if (fireProjectile.lifetime > 300 || fireProjectile.y > 2800 || fireProjectile.x < -50 || fireProjectile.x > 2098) {
fireProjectile.destroy();
fireProjectiles.splice(f, 1);
continue;
}
// Check fire projectile vs ninja collision
if (fireProjectile.intersects(ninja)) {
ninja.health--;
ninjaCurrentHealth = ninja.health;
healthTxt.setText('Health: ' + ninjaCurrentHealth);
LK.effects.flashObject(ninja, 0xff4500, 500);
fireProjectile.destroy();
fireProjectiles.splice(f, 1);
if (ninja.health <= 0) {
LK.showGameOver();
}
}
}
// Keep ninja on screen horizontally
if (ninja.x < 40) ninja.x = 40;
if (ninja.x > 2008) ninja.x = 2008;
};
// Play background music
LK.playMusic('ninjai');
2d anime chibi style ninja hitam jepang. In-Game asset. 2d. High contrast. No shadows
2d anime image pemandangan gunung fuji jepang zaman kuno di kejauhan. wilayah hutan dan bukit bebatuan dari dekat. langit biru cerah. In-Game asset. 2d. High contrast. No shadows
2d anime chibi evil hitam jepang. In-Game asset. 2d. High contrast. No shadows
2d anime image tanah dan bebatuan. In-Game asset. 2d. High contrast. No shadows