/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function (type) { var self = Container.call(this); var assetName = type === 'armored' ? 'armoredEnemy' : type === 'shooting' ? 'shootingEnemy' : 'basicEnemy'; var enemyGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1.0 }); self.type = type || 'basic'; self.speed = type === 'armored' ? -3 : type === 'shooting' ? -2 : -4; self.maxHealth = type === 'shooting' ? 2 : 1; self.health = self.maxHealth; self.damage = type === 'armored' ? 30 : type === 'shooting' ? 25 : 20; self.points = type === 'armored' ? 30 : type === 'shooting' ? 25 : 10; // Direction tracking for all enemy types self.direction = self.speed > 0 ? 1 : -1; // Track current direction for all enemies self.lastDirection = self.direction; // Track last direction to detect changes // Armored enemy movement properties if (type === 'armored') { self.baseSpeed = Math.abs(self.speed); // Store base speed value self.direction = self.speed > 0 ? 1 : -1; // Track current direction self.lastX = 0; // Track last position for direction changes self.directionChangeTimer = 0; self.directionChangeInterval = 120 + Math.random() * 120; // Random interval 2-4 seconds } // Shooting properties for shooting enemies if (type === 'shooting') { self.shootTimer = 0; self.shootInterval = 60; // Shoot every 1 second (60 frames at 60fps) self.bulletsShot = 0; // Track number of bullets fired self.maxBullets = 1; // Maximum bullets this enemy can shoot - only one bullet per enemy self.shoot = function () { // Check if enemy has bullets remaining if (self.bulletsShot >= self.maxBullets) { return; // Don't shoot if limit reached } // Determine direction to shoot towards player var direction = player.x > self.x ? 1 : -1; var bullet = game.addChild(new EnemyBullet(direction)); bullet.x = self.x; bullet.y = self.y - 40; enemyBullets.push(bullet); self.bulletsShot++; // Increment bullet count }; } self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); LK.getSound('enemyHit').play(); if (self.health <= 0) { // Create main explosion effect var explosionEffect = game.addChild(LK.getAsset('slashEffect', { anchorX: 0.5, anchorY: 0.5 })); explosionEffect.x = self.x; explosionEffect.y = self.y - 40; explosionEffect.tint = 0xff4500; // Orange explosion color explosionEffect.alpha = 0.9; explosionEffect.scaleX = 0.5; explosionEffect.scaleY = 0.5; // Animate main explosion effect tween(explosionEffect, { scaleX: 3.0, scaleY: 3.0, alpha: 0 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { explosionEffect.destroy(); } }); // Create fragmented explosion pieces var fragmentCount = 6 + Math.floor(Math.random() * 4); // 6-9 fragments for (var f = 0; f < fragmentCount; f++) { var fragment = game.addChild(LK.getAsset(assetName, { anchorX: 0.5, anchorY: 0.5 })); fragment.x = self.x; fragment.y = self.y - 40; fragment.tint = 0xff6600; // Darker orange for fragments fragment.alpha = 0.8; fragment.scaleX = 0.3 + Math.random() * 0.4; // Random size 0.3-0.7 fragment.scaleY = 0.3 + Math.random() * 0.4; fragment.rotation = Math.random() * Math.PI * 2; // Random rotation // Calculate random scatter direction var angle = Math.PI * 2 / fragmentCount * f + (Math.random() - 0.5) * 0.8; var velocity = 150 + Math.random() * 100; // Random velocity 150-250 var targetX = fragment.x + Math.cos(angle) * velocity; var targetY = fragment.y + Math.sin(angle) * velocity; // Animate fragment scatter with rotation and fade tween(fragment, { x: targetX, y: targetY, rotation: fragment.rotation + (Math.random() - 0.5) * Math.PI * 4, scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 600 + Math.random() * 400, // Random duration 600-1000ms easing: tween.easeOut, onFinish: function onFinish() { fragment.destroy(); } }); } // Award points LK.setScore(LK.getScore() + self.points); // Chance to drop power-up if (Math.random() < 0.15) { var powerUp = game.addChild(new PowerUp()); powerUp.x = self.x; powerUp.y = self.y - 20; powerUps.push(powerUp); } // Remove from enemies array var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } self.destroy(); } }; // Initialize jumping properties self.baseY = 0; self.isJumping = false; self.jumpTimer = 0; self.jumpInterval = 150 + Math.random() * 90; // Random jump interval between 2.5-4 seconds for long jumps self.startJump = function () { if (!self.isJumping) { self.isJumping = true; self.baseY = self.y; var baseX = self.x; var jumpDistance = 200 + Math.random() * 150; // Long horizontal jump 200-350 pixels var jumpHeight = 120 + Math.random() * 80; // Higher jump 120-200 pixels // Jump direction based on movement direction var jumpDirectionX = self.speed > 0 ? jumpDistance : -jumpDistance; // Long jump with arc motion - jump up and forward tween(self, { y: self.baseY - jumpHeight, x: baseX + jumpDirectionX }, { duration: 800, // Longer duration for long jump easing: tween.easeOut, onFinish: function onFinish() { // Fall back down while continuing forward motion tween(self, { y: self.baseY }, { duration: 600, easing: tween.bounceOut, onFinish: function onFinish() { self.isJumping = false; } }); } }); } }; self.update = function () { // Handle armored enemy direction changes if (self.type === 'armored') { // Initialize lastX if not set if (self.lastX === 0) self.lastX = self.x; // Check for screen boundaries and change direction if (self.x <= 100 && self.direction === -1 || self.x >= 1948 && self.direction === 1) { self.direction *= -1; // Reverse direction self.speed = self.baseSpeed * self.direction; } // Random direction changes self.directionChangeTimer++; if (self.directionChangeTimer >= self.directionChangeInterval) { self.direction *= -1; // Reverse direction self.speed = self.baseSpeed * self.direction; self.directionChangeTimer = 0; self.directionChangeInterval = 120 + Math.random() * 120; // Reset random interval } // Update lastX self.lastX = self.x; } // Update direction based on speed for all enemy types (including armored) self.direction = self.speed > 0 ? 1 : -1; // Flip enemy image based on screen position for all enemy types var targetScale; if (self.x < 1024) { // Left half of screen (2048/2 = 1024) targetScale = -1; // Face left } else { // Right half of screen targetScale = 1; // Face right } // Only animate if the scale needs to change if (enemyGraphics.scaleX !== targetScale) { tween(enemyGraphics, { scaleX: targetScale }, { duration: 200, easing: tween.easeOut }); } self.x += self.speed; // Handle jumping self.jumpTimer++; if (self.jumpTimer >= self.jumpInterval && !self.isJumping) { self.startJump(); self.jumpTimer = 0; self.jumpInterval = 150 + Math.random() * 90; // Reset random interval for long jumps } // Handle shooting for shooting enemies if (self.type === 'shooting') { self.shootTimer++; if (self.shootTimer >= self.shootInterval && self.bulletsShot < self.maxBullets) { self.shoot(); self.shootTimer = 0; } } // Check collision with player if (self.intersects(player) && !player.invulnerable) { player.takeDamage(self.damage); } }; return self; }); var EnemyBullet = Container.expand(function (direction) { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.damage = 15; self.direction = direction || 1; // 1 for right, -1 for left self.update = function () { self.x += self.speed * self.direction; // Check collision with player if (self.intersects(player) && !player.invulnerable) { player.takeDamage(self.damage); // Remove from enemyBullets array var index = enemyBullets.indexOf(self); if (index > -1) { enemyBullets.splice(index, 1); } self.destroy(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); self.maxHealth = 100; self.health = self.maxHealth; self.slashDamage = 1; self.slashRange = 150; self.isSlashing = false; self.slashCooldown = 0; self.isDashing = false; self.dashCooldown = 0; self.dashDistance = 200; self.dashDuration = 300; self.invulnerable = false; self.invulnerabilityTime = 0; self.facingDirection = 1; // 1 for right, -1 for left self.isJumping = false; self.baseY = 0; self.dashSlash = function () { if (self.slashCooldown <= 0 && self.dashCooldown <= 0 && !self.isSlashing && !self.isDashing) { self.isDashing = true; self.isSlashing = true; self.slashCooldown = 60; // 1 second cooldown self.dashCooldown = 60; var startX = self.x; var dashTargetX = self.facingDirection > 0 ? Math.min(startX + self.dashDistance, 2048 - 40) : Math.max(startX - self.dashDistance, 40); // Dash forward with tween tween(self, { x: dashTargetX }, { duration: self.dashDuration, easing: tween.easeOut, onFinish: function onFinish() { self.isDashing = false; } }); // Create extended slash effect during dash var slashEffect = game.addChild(LK.getAsset('slashEffect', { anchorX: 0.5, anchorY: 0.5 })); slashEffect.x = self.x + 75 * self.facingDirection; slashEffect.y = self.y - 60; slashEffect.alpha = 0.9; slashEffect.scaleX = 2.0 * self.facingDirection; slashEffect.scaleY = 1.5; // Follow player during dash var slashFollowInterval = LK.setInterval(function () { if (self.isDashing) { slashEffect.x = self.x + 75 * self.facingDirection; } }, 16); // Animate slash effect tween(slashEffect, { scaleX: 2.5, scaleY: 2.0, alpha: 0 }, { duration: self.dashDuration, onFinish: function onFinish() { LK.clearInterval(slashFollowInterval); slashEffect.destroy(); } }); LK.getSound('slash').play(); // Extended damage check during dash var damageCheckInterval = LK.setInterval(function () { if (self.isDashing) { for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); var enemyInFront = self.facingDirection > 0 ? enemy.x > self.x - 50 && enemy.x < self.x + 150 : enemy.x < self.x + 50 && enemy.x > self.x - 150; if (distance < self.slashRange * 1.5 && enemyInFront) { enemy.takeDamage(self.slashDamage * 2); // Double damage during dash } } // Check for enemy bullet hits during dash for (var j = enemyBullets.length - 1; j >= 0; j--) { var bullet = enemyBullets[j]; var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2)); var bulletInFront = self.facingDirection > 0 ? bullet.x > self.x - 50 && bullet.x < self.x + 150 : bullet.x < self.x + 50 && bullet.x > self.x - 150; if (bulletDistance < self.slashRange * 1.5 && bulletInFront) { // Destroy the bullet bullet.destroy(); enemyBullets.splice(j, 1); // Award small points for destroying bullets LK.setScore(LK.getScore() + 5); } } } }, 30); LK.setTimeout(function () { LK.clearInterval(damageCheckInterval); self.isSlashing = false; }, self.dashDuration); } }; self.slash = function () { if (self.slashCooldown <= 0 && !self.isSlashing && !self.isDashing) { self.isSlashing = true; self.slashCooldown = 20; // 1/3 second at 60fps // Create slash effect var slashEffect = game.addChild(LK.getAsset('slashEffect', { anchorX: 0.5, anchorY: 0.5 })); slashEffect.x = self.x + 75 * self.facingDirection; slashEffect.y = self.y - 60; slashEffect.alpha = 0.8; slashEffect.scaleX = self.facingDirection; // Animate slash effect tween(slashEffect, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { slashEffect.destroy(); } }); LK.getSound('slash').play(); // Check for enemy hits for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); var enemyInRange = self.facingDirection > 0 ? enemy.x > self.x - 50 && enemy.x < self.x + self.slashRange : enemy.x < self.x + 50 && enemy.x > self.x - self.slashRange; if (distance < self.slashRange && enemyInRange) { enemy.takeDamage(self.slashDamage); } } // Check for enemy bullet hits for (var j = enemyBullets.length - 1; j >= 0; j--) { var bullet = enemyBullets[j]; var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2)); var bulletInRange = self.facingDirection > 0 ? bullet.x > self.x - 50 && bullet.x < self.x + self.slashRange : bullet.x < self.x + 50 && bullet.x > self.x - self.slashRange; if (bulletDistance < self.slashRange && bulletInRange) { // Destroy the bullet bullet.destroy(); enemyBullets.splice(j, 1); // Award small points for destroying bullets LK.setScore(LK.getScore() + 5); } } LK.setTimeout(function () { self.isSlashing = false; }, 200); } }; self.jump = function () { if (!self.isJumping) { self.isJumping = true; self.baseY = self.y; var jumpHeight = 200; // Jump height in pixels // Jump up with tween tween(self, { y: self.baseY - jumpHeight }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Fall back down tween(self, { y: self.baseY }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.isJumping = false; } }); } }); } }; self.takeDamage = function (damage) { if (!self.invulnerable) { self.health -= damage; self.invulnerable = true; self.invulnerabilityTime = 120; // 2 seconds at 60fps // Flash effect LK.effects.flashObject(self, 0xff0000, 500); if (self.health <= 0) { self.health = 0; LK.showGameOver(); } } }; self.update = function () { // Update player image direction based on facing direction playerGraphics.scaleX = self.facingDirection; if (self.slashCooldown > 0) { self.slashCooldown--; } if (self.dashCooldown > 0) { self.dashCooldown--; } if (self.invulnerabilityTime > 0) { self.invulnerabilityTime--; if (self.invulnerabilityTime <= 0) { self.invulnerable = false; } } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.bobOffset = 0; self.update = function () { self.x += self.speed; self.bobOffset += 0.1; self.y += Math.sin(self.bobOffset) * 0.5; // Check collision with player if (self.intersects(player)) { self.collect(); } }; self.collect = function () { LK.getSound('powerUpSound').play(); // Random power-up effect var powerType = Math.floor(Math.random() * 3); switch (powerType) { case 0: // Increased damage player.slashDamage += 1; break; case 1: // Wider slash range player.slashRange += 50; break; case 2: // Temporary invincibility player.invulnerable = true; player.invulnerabilityTime = 300; // 5 seconds break; } // Remove from powerUps array var index = powerUps.indexOf(self); if (index > -1) { powerUps.splice(index, 1); } self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Game variables var player; var enemies = []; var powerUps = []; var enemyBullets = []; var enemySpawnTimer = 0; var enemySpawnRate = 180; // Start spawning every 3 seconds var gameTime = 0; var healthBar; var healthBarBg; // Create UI elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 120; scoreTxt.y = 50; LK.gui.topLeft.addChild(scoreTxt); // Create health bar background healthBarBg = game.addChild(LK.getAsset('healthBarBg', { anchorX: 0, anchorY: 0 })); healthBarBg.x = 120; healthBarBg.y = 120; // Create health bar healthBar = game.addChild(LK.getAsset('healthBar', { anchorX: 0, anchorY: 0 })); healthBar.x = 122; healthBar.y = 122; // Create health text var healthTxt = new Text2('Health', { size: 40, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); healthTxt.x = 120; healthTxt.y = 160; game.addChild(healthTxt); // Create background var background = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; // Create player player = game.addChild(new Player()); player.x = 300; player.y = 2732 - 150; // Near bottom of screen // Start background music LK.playMusic('bgmusic'); // Touch controls for movement and slashing var isDragging = false; var lastTouchX = 0; var lastTouchY = 0; var swipeThreshold = 100; // Minimum distance for swipe detection game.down = function (x, y, obj) { isDragging = true; lastTouchX = x; lastTouchY = y; // Set facing direction based on touch position relative to player if (x < player.x) { player.facingDirection = -1; // Face left } else { player.facingDirection = 1; // Face right } player.dashSlash(); }; game.move = function (x, y, obj) { if (isDragging) { var deltaX = x - lastTouchX; player.x += deltaX * 0.5; // Smooth movement multiplier // Keep player within screen bounds if (player.x < 40) player.x = 40; if (player.x > 2048 - 40) player.x = 2048 - 40; lastTouchX = x; } }; game.up = function (x, y, obj) { if (isDragging) { var deltaY = lastTouchY - y; // Upward swipe has positive deltaY var deltaX = Math.abs(x - lastTouchX); // Check for upward swipe (vertical movement greater than horizontal and above threshold) if (deltaY > swipeThreshold && deltaY > deltaX) { player.jump(); } } isDragging = false; }; // Spawn enemies function spawnEnemy() { var rand = Math.random(); var enemyType = rand < 0.5 ? 'basic' : rand < 0.8 ? 'armored' : 'shooting'; var enemy = game.addChild(new Enemy(enemyType)); // Randomly spawn from left or right var spawnFromRight = Math.random() < 0.5; if (spawnFromRight) { enemy.x = 2048 + 100; // Start off-screen right enemy.speed = enemy.type === 'armored' ? -3 : enemy.type === 'shooting' ? -2 : -4; // Move left } else { enemy.x = -100; // Start off-screen left enemy.speed = enemy.type === 'armored' ? 3 : enemy.type === 'shooting' ? 2 : 4; // Move right } enemy.y = 2732 - 150 + Math.random() * 100 - 50; // Vary height slightly enemies.push(enemy); } // Main game loop game.update = function () { gameTime++; // Update score display scoreTxt.setText('Score: ' + LK.getScore()); // Update health bar var healthPercent = player.health / player.maxHealth; healthBar.width = 200 * healthPercent; // Spawn enemies enemySpawnTimer++; if (enemySpawnTimer >= enemySpawnRate) { spawnEnemy(); enemySpawnTimer = 0; // Increase difficulty over time if (enemySpawnRate > 60) { // Minimum spawn rate enemySpawnRate -= 0.5; } } // Clean up off-screen enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.x < -100 || enemy.x > 2048 + 100) { enemy.destroy(); enemies.splice(i, 1); } } // Clean up off-screen power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; if (powerUp.x < -100) { powerUp.destroy(); powerUps.splice(i, 1); } } // Clean up off-screen enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < -100 || bullet.x > 2048 + 100) { bullet.destroy(); enemyBullets.splice(i, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var assetName = type === 'armored' ? 'armoredEnemy' : type === 'shooting' ? 'shootingEnemy' : 'basicEnemy';
var enemyGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
self.type = type || 'basic';
self.speed = type === 'armored' ? -3 : type === 'shooting' ? -2 : -4;
self.maxHealth = type === 'shooting' ? 2 : 1;
self.health = self.maxHealth;
self.damage = type === 'armored' ? 30 : type === 'shooting' ? 25 : 20;
self.points = type === 'armored' ? 30 : type === 'shooting' ? 25 : 10;
// Direction tracking for all enemy types
self.direction = self.speed > 0 ? 1 : -1; // Track current direction for all enemies
self.lastDirection = self.direction; // Track last direction to detect changes
// Armored enemy movement properties
if (type === 'armored') {
self.baseSpeed = Math.abs(self.speed); // Store base speed value
self.direction = self.speed > 0 ? 1 : -1; // Track current direction
self.lastX = 0; // Track last position for direction changes
self.directionChangeTimer = 0;
self.directionChangeInterval = 120 + Math.random() * 120; // Random interval 2-4 seconds
}
// Shooting properties for shooting enemies
if (type === 'shooting') {
self.shootTimer = 0;
self.shootInterval = 60; // Shoot every 1 second (60 frames at 60fps)
self.bulletsShot = 0; // Track number of bullets fired
self.maxBullets = 1; // Maximum bullets this enemy can shoot - only one bullet per enemy
self.shoot = function () {
// Check if enemy has bullets remaining
if (self.bulletsShot >= self.maxBullets) {
return; // Don't shoot if limit reached
}
// Determine direction to shoot towards player
var direction = player.x > self.x ? 1 : -1;
var bullet = game.addChild(new EnemyBullet(direction));
bullet.x = self.x;
bullet.y = self.y - 40;
enemyBullets.push(bullet);
self.bulletsShot++; // Increment bullet count
};
}
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
LK.getSound('enemyHit').play();
if (self.health <= 0) {
// Create main explosion effect
var explosionEffect = game.addChild(LK.getAsset('slashEffect', {
anchorX: 0.5,
anchorY: 0.5
}));
explosionEffect.x = self.x;
explosionEffect.y = self.y - 40;
explosionEffect.tint = 0xff4500; // Orange explosion color
explosionEffect.alpha = 0.9;
explosionEffect.scaleX = 0.5;
explosionEffect.scaleY = 0.5;
// Animate main explosion effect
tween(explosionEffect, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
explosionEffect.destroy();
}
});
// Create fragmented explosion pieces
var fragmentCount = 6 + Math.floor(Math.random() * 4); // 6-9 fragments
for (var f = 0; f < fragmentCount; f++) {
var fragment = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
}));
fragment.x = self.x;
fragment.y = self.y - 40;
fragment.tint = 0xff6600; // Darker orange for fragments
fragment.alpha = 0.8;
fragment.scaleX = 0.3 + Math.random() * 0.4; // Random size 0.3-0.7
fragment.scaleY = 0.3 + Math.random() * 0.4;
fragment.rotation = Math.random() * Math.PI * 2; // Random rotation
// Calculate random scatter direction
var angle = Math.PI * 2 / fragmentCount * f + (Math.random() - 0.5) * 0.8;
var velocity = 150 + Math.random() * 100; // Random velocity 150-250
var targetX = fragment.x + Math.cos(angle) * velocity;
var targetY = fragment.y + Math.sin(angle) * velocity;
// Animate fragment scatter with rotation and fade
tween(fragment, {
x: targetX,
y: targetY,
rotation: fragment.rotation + (Math.random() - 0.5) * Math.PI * 4,
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 600 + Math.random() * 400,
// Random duration 600-1000ms
easing: tween.easeOut,
onFinish: function onFinish() {
fragment.destroy();
}
});
}
// Award points
LK.setScore(LK.getScore() + self.points);
// Chance to drop power-up
if (Math.random() < 0.15) {
var powerUp = game.addChild(new PowerUp());
powerUp.x = self.x;
powerUp.y = self.y - 20;
powerUps.push(powerUp);
}
// Remove from enemies array
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
self.destroy();
}
};
// Initialize jumping properties
self.baseY = 0;
self.isJumping = false;
self.jumpTimer = 0;
self.jumpInterval = 150 + Math.random() * 90; // Random jump interval between 2.5-4 seconds for long jumps
self.startJump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.baseY = self.y;
var baseX = self.x;
var jumpDistance = 200 + Math.random() * 150; // Long horizontal jump 200-350 pixels
var jumpHeight = 120 + Math.random() * 80; // Higher jump 120-200 pixels
// Jump direction based on movement direction
var jumpDirectionX = self.speed > 0 ? jumpDistance : -jumpDistance;
// Long jump with arc motion - jump up and forward
tween(self, {
y: self.baseY - jumpHeight,
x: baseX + jumpDirectionX
}, {
duration: 800,
// Longer duration for long jump
easing: tween.easeOut,
onFinish: function onFinish() {
// Fall back down while continuing forward motion
tween(self, {
y: self.baseY
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
}
};
self.update = function () {
// Handle armored enemy direction changes
if (self.type === 'armored') {
// Initialize lastX if not set
if (self.lastX === 0) self.lastX = self.x;
// Check for screen boundaries and change direction
if (self.x <= 100 && self.direction === -1 || self.x >= 1948 && self.direction === 1) {
self.direction *= -1; // Reverse direction
self.speed = self.baseSpeed * self.direction;
}
// Random direction changes
self.directionChangeTimer++;
if (self.directionChangeTimer >= self.directionChangeInterval) {
self.direction *= -1; // Reverse direction
self.speed = self.baseSpeed * self.direction;
self.directionChangeTimer = 0;
self.directionChangeInterval = 120 + Math.random() * 120; // Reset random interval
}
// Update lastX
self.lastX = self.x;
}
// Update direction based on speed for all enemy types (including armored)
self.direction = self.speed > 0 ? 1 : -1;
// Flip enemy image based on screen position for all enemy types
var targetScale;
if (self.x < 1024) {
// Left half of screen (2048/2 = 1024)
targetScale = -1; // Face left
} else {
// Right half of screen
targetScale = 1; // Face right
}
// Only animate if the scale needs to change
if (enemyGraphics.scaleX !== targetScale) {
tween(enemyGraphics, {
scaleX: targetScale
}, {
duration: 200,
easing: tween.easeOut
});
}
self.x += self.speed;
// Handle jumping
self.jumpTimer++;
if (self.jumpTimer >= self.jumpInterval && !self.isJumping) {
self.startJump();
self.jumpTimer = 0;
self.jumpInterval = 150 + Math.random() * 90; // Reset random interval for long jumps
}
// Handle shooting for shooting enemies
if (self.type === 'shooting') {
self.shootTimer++;
if (self.shootTimer >= self.shootInterval && self.bulletsShot < self.maxBullets) {
self.shoot();
self.shootTimer = 0;
}
}
// Check collision with player
if (self.intersects(player) && !player.invulnerable) {
player.takeDamage(self.damage);
}
};
return self;
});
var EnemyBullet = Container.expand(function (direction) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 15;
self.direction = direction || 1; // 1 for right, -1 for left
self.update = function () {
self.x += self.speed * self.direction;
// Check collision with player
if (self.intersects(player) && !player.invulnerable) {
player.takeDamage(self.damage);
// Remove from enemyBullets array
var index = enemyBullets.indexOf(self);
if (index > -1) {
enemyBullets.splice(index, 1);
}
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.slashDamage = 1;
self.slashRange = 150;
self.isSlashing = false;
self.slashCooldown = 0;
self.isDashing = false;
self.dashCooldown = 0;
self.dashDistance = 200;
self.dashDuration = 300;
self.invulnerable = false;
self.invulnerabilityTime = 0;
self.facingDirection = 1; // 1 for right, -1 for left
self.isJumping = false;
self.baseY = 0;
self.dashSlash = function () {
if (self.slashCooldown <= 0 && self.dashCooldown <= 0 && !self.isSlashing && !self.isDashing) {
self.isDashing = true;
self.isSlashing = true;
self.slashCooldown = 60; // 1 second cooldown
self.dashCooldown = 60;
var startX = self.x;
var dashTargetX = self.facingDirection > 0 ? Math.min(startX + self.dashDistance, 2048 - 40) : Math.max(startX - self.dashDistance, 40);
// Dash forward with tween
tween(self, {
x: dashTargetX
}, {
duration: self.dashDuration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isDashing = false;
}
});
// Create extended slash effect during dash
var slashEffect = game.addChild(LK.getAsset('slashEffect', {
anchorX: 0.5,
anchorY: 0.5
}));
slashEffect.x = self.x + 75 * self.facingDirection;
slashEffect.y = self.y - 60;
slashEffect.alpha = 0.9;
slashEffect.scaleX = 2.0 * self.facingDirection;
slashEffect.scaleY = 1.5;
// Follow player during dash
var slashFollowInterval = LK.setInterval(function () {
if (self.isDashing) {
slashEffect.x = self.x + 75 * self.facingDirection;
}
}, 16);
// Animate slash effect
tween(slashEffect, {
scaleX: 2.5,
scaleY: 2.0,
alpha: 0
}, {
duration: self.dashDuration,
onFinish: function onFinish() {
LK.clearInterval(slashFollowInterval);
slashEffect.destroy();
}
});
LK.getSound('slash').play();
// Extended damage check during dash
var damageCheckInterval = LK.setInterval(function () {
if (self.isDashing) {
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
var enemyInFront = self.facingDirection > 0 ? enemy.x > self.x - 50 && enemy.x < self.x + 150 : enemy.x < self.x + 50 && enemy.x > self.x - 150;
if (distance < self.slashRange * 1.5 && enemyInFront) {
enemy.takeDamage(self.slashDamage * 2); // Double damage during dash
}
}
// Check for enemy bullet hits during dash
for (var j = enemyBullets.length - 1; j >= 0; j--) {
var bullet = enemyBullets[j];
var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2));
var bulletInFront = self.facingDirection > 0 ? bullet.x > self.x - 50 && bullet.x < self.x + 150 : bullet.x < self.x + 50 && bullet.x > self.x - 150;
if (bulletDistance < self.slashRange * 1.5 && bulletInFront) {
// Destroy the bullet
bullet.destroy();
enemyBullets.splice(j, 1);
// Award small points for destroying bullets
LK.setScore(LK.getScore() + 5);
}
}
}
}, 30);
LK.setTimeout(function () {
LK.clearInterval(damageCheckInterval);
self.isSlashing = false;
}, self.dashDuration);
}
};
self.slash = function () {
if (self.slashCooldown <= 0 && !self.isSlashing && !self.isDashing) {
self.isSlashing = true;
self.slashCooldown = 20; // 1/3 second at 60fps
// Create slash effect
var slashEffect = game.addChild(LK.getAsset('slashEffect', {
anchorX: 0.5,
anchorY: 0.5
}));
slashEffect.x = self.x + 75 * self.facingDirection;
slashEffect.y = self.y - 60;
slashEffect.alpha = 0.8;
slashEffect.scaleX = self.facingDirection;
// Animate slash effect
tween(slashEffect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
slashEffect.destroy();
}
});
LK.getSound('slash').play();
// Check for enemy hits
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
var enemyInRange = self.facingDirection > 0 ? enemy.x > self.x - 50 && enemy.x < self.x + self.slashRange : enemy.x < self.x + 50 && enemy.x > self.x - self.slashRange;
if (distance < self.slashRange && enemyInRange) {
enemy.takeDamage(self.slashDamage);
}
}
// Check for enemy bullet hits
for (var j = enemyBullets.length - 1; j >= 0; j--) {
var bullet = enemyBullets[j];
var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2));
var bulletInRange = self.facingDirection > 0 ? bullet.x > self.x - 50 && bullet.x < self.x + self.slashRange : bullet.x < self.x + 50 && bullet.x > self.x - self.slashRange;
if (bulletDistance < self.slashRange && bulletInRange) {
// Destroy the bullet
bullet.destroy();
enemyBullets.splice(j, 1);
// Award small points for destroying bullets
LK.setScore(LK.getScore() + 5);
}
}
LK.setTimeout(function () {
self.isSlashing = false;
}, 200);
}
};
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.baseY = self.y;
var jumpHeight = 200; // Jump height in pixels
// Jump up with tween
tween(self, {
y: self.baseY - jumpHeight
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Fall back down
tween(self, {
y: self.baseY
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
}
};
self.takeDamage = function (damage) {
if (!self.invulnerable) {
self.health -= damage;
self.invulnerable = true;
self.invulnerabilityTime = 120; // 2 seconds at 60fps
// Flash effect
LK.effects.flashObject(self, 0xff0000, 500);
if (self.health <= 0) {
self.health = 0;
LK.showGameOver();
}
}
};
self.update = function () {
// Update player image direction based on facing direction
playerGraphics.scaleX = self.facingDirection;
if (self.slashCooldown > 0) {
self.slashCooldown--;
}
if (self.dashCooldown > 0) {
self.dashCooldown--;
}
if (self.invulnerabilityTime > 0) {
self.invulnerabilityTime--;
if (self.invulnerabilityTime <= 0) {
self.invulnerable = false;
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -2;
self.bobOffset = 0;
self.update = function () {
self.x += self.speed;
self.bobOffset += 0.1;
self.y += Math.sin(self.bobOffset) * 0.5;
// Check collision with player
if (self.intersects(player)) {
self.collect();
}
};
self.collect = function () {
LK.getSound('powerUpSound').play();
// Random power-up effect
var powerType = Math.floor(Math.random() * 3);
switch (powerType) {
case 0:
// Increased damage
player.slashDamage += 1;
break;
case 1:
// Wider slash range
player.slashRange += 50;
break;
case 2:
// Temporary invincibility
player.invulnerable = true;
player.invulnerabilityTime = 300; // 5 seconds
break;
}
// Remove from powerUps array
var index = powerUps.indexOf(self);
if (index > -1) {
powerUps.splice(index, 1);
}
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var powerUps = [];
var enemyBullets = [];
var enemySpawnTimer = 0;
var enemySpawnRate = 180; // Start spawning every 3 seconds
var gameTime = 0;
var healthBar;
var healthBarBg;
// Create UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
// Create health bar background
healthBarBg = game.addChild(LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
}));
healthBarBg.x = 120;
healthBarBg.y = 120;
// Create health bar
healthBar = game.addChild(LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
}));
healthBar.x = 122;
healthBar.y = 122;
// Create health text
var healthTxt = new Text2('Health', {
size: 40,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 120;
healthTxt.y = 160;
game.addChild(healthTxt);
// Create background
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Create player
player = game.addChild(new Player());
player.x = 300;
player.y = 2732 - 150; // Near bottom of screen
// Start background music
LK.playMusic('bgmusic');
// Touch controls for movement and slashing
var isDragging = false;
var lastTouchX = 0;
var lastTouchY = 0;
var swipeThreshold = 100; // Minimum distance for swipe detection
game.down = function (x, y, obj) {
isDragging = true;
lastTouchX = x;
lastTouchY = y;
// Set facing direction based on touch position relative to player
if (x < player.x) {
player.facingDirection = -1; // Face left
} else {
player.facingDirection = 1; // Face right
}
player.dashSlash();
};
game.move = function (x, y, obj) {
if (isDragging) {
var deltaX = x - lastTouchX;
player.x += deltaX * 0.5; // Smooth movement multiplier
// Keep player within screen bounds
if (player.x < 40) player.x = 40;
if (player.x > 2048 - 40) player.x = 2048 - 40;
lastTouchX = x;
}
};
game.up = function (x, y, obj) {
if (isDragging) {
var deltaY = lastTouchY - y; // Upward swipe has positive deltaY
var deltaX = Math.abs(x - lastTouchX);
// Check for upward swipe (vertical movement greater than horizontal and above threshold)
if (deltaY > swipeThreshold && deltaY > deltaX) {
player.jump();
}
}
isDragging = false;
};
// Spawn enemies
function spawnEnemy() {
var rand = Math.random();
var enemyType = rand < 0.5 ? 'basic' : rand < 0.8 ? 'armored' : 'shooting';
var enemy = game.addChild(new Enemy(enemyType));
// Randomly spawn from left or right
var spawnFromRight = Math.random() < 0.5;
if (spawnFromRight) {
enemy.x = 2048 + 100; // Start off-screen right
enemy.speed = enemy.type === 'armored' ? -3 : enemy.type === 'shooting' ? -2 : -4; // Move left
} else {
enemy.x = -100; // Start off-screen left
enemy.speed = enemy.type === 'armored' ? 3 : enemy.type === 'shooting' ? 2 : 4; // Move right
}
enemy.y = 2732 - 150 + Math.random() * 100 - 50; // Vary height slightly
enemies.push(enemy);
}
// Main game loop
game.update = function () {
gameTime++;
// Update score display
scoreTxt.setText('Score: ' + LK.getScore());
// Update health bar
var healthPercent = player.health / player.maxHealth;
healthBar.width = 200 * healthPercent;
// Spawn enemies
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
// Increase difficulty over time
if (enemySpawnRate > 60) {
// Minimum spawn rate
enemySpawnRate -= 0.5;
}
}
// Clean up off-screen enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -100 || enemy.x > 2048 + 100) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Clean up off-screen power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Clean up off-screen enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < -100 || bullet.x > 2048 + 100) {
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
};
efek slash kepala naga petir ke depan. In-Game asset. 2d. High contrast. No shadows
side scroller blue steel armored ninja aksi koreographi dua tangan memegang pedang ke depan In-Game asset. 2d. No shadows
side scroller image fat orc samurai front holding big axe. In-Game asset. 2d. High contrast. No shadows
side scroller kepala evil kelinci berapi. In-Game asset. 2d. High contrast. No shadows
realistic 2d anime style front field old samurai palace temple with pig evil ornament at midnight. In-Game asset. 2d. High contrast. No shadows