/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Shape = Container.expand(function (options) {
var self = Container.call(this);
self.attachAsset('shape', {
width: options.width,
height: options.height,
anchorX: options.anchorX || 0,
anchorY: options.anchorY || 0,
color: options.color || 0x66ff00,
alpha: typeof options.alpha === 'number' ? options.alpha : 0
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Helper function to find a child by name.
function findChildByName(container, name) {
for (var i = 0; i < container.children.length; i++) {
if (container.children[i].name === name) {
return container.children[i];
}
}
return null;
}
/****
* Global Variables
****/
var jumpColGlobal = null;
var isPressHeld = false;
var pressHoldStartTime = 0;
var pressDownX = 0;
var pressDownY = 0;
var mouseX = 0;
var mouseY = 0;
game.move = function (x, y) {
mouseX = x;
mouseY = y;
};
var projectiles = [];
var score = 0;
var scoreTxt;
function updateScoreDisplay() {
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('High Score: ' + highScore);
}
game.removeChild(scoreTxt);
scoreTxt = createScoreText(score);
scoreTxt.scaleX = 1.0;
scoreTxt.scaleY = 1.0;
game.addChild(scoreTxt);
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
function createScoreText(value) {
var shadow = new Text2(String(value), {
size: 600,
fill: 0x000000,
fontFamily: "Arial"
});
shadow.name = "shadow";
shadow.anchor.set(0.5, 0);
shadow.x = 4;
shadow.y = 4;
var main = new Text2(String(value), {
size: 600,
fill: 0xFF69B4,
fontFamily: "Arial"
});
main.name = "main";
main.anchor.set(0.5, 0);
var container = new Container();
container.name = "scoreTxt";
container.x = 1024;
container.y = 50;
container.addChild(shadow);
container.addChild(main);
return container;
}
scoreTxt = createScoreText(score);
scoreTxt.scaleX = 1.0;
scoreTxt.scaleY = 1.0;
LK.playMusic('bgm', {
loop: true
});
var bg01 = LK.getAsset('bg01', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
game.addChild(bg01);
game.addChild(scoreTxt);
var highScore = storage.highScore || 0;
var highScoreTxt = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFFFFF
});
highScoreTxt.name = 'highScoreTxt';
highScoreTxt.anchor.set(1, 1);
highScoreTxt.x = 1900;
highScoreTxt.y = 2720;
game.addChild(highScoreTxt);
/****
* Persistent Power Helmet HUD (for filling up)
****/
var helmetMeter = 0;
var helmetMeterMax = 120;
var powerHelmet = new Container();
powerHelmet.name = "powerHelmet";
var helmetSprite = powerHelmet.attachAsset('helmet', {
anchorX: 0.5,
anchorY: 0.5
});
powerHelmet.x = 2048 - helmetSprite.width / 2 - 20;
powerHelmet.y = 130;
var helmetFillContainer = new Container();
helmetFillContainer.name = "helmetFillContainer";
var fillBar = new Shape({
width: helmetSprite.width * 0.05,
height: 40,
color: 0xFFFFFF,
alpha: 1
});
fillBar.anchorX = 0;
fillBar.anchorY = 0.5;
fillBar.x = -helmetSprite.width / 2;
fillBar.y = helmetSprite.height / 2 - 15;
helmetFillContainer.addChild(fillBar);
game.addChild(powerHelmet);
powerHelmet.addChild(helmetFillContainer);
function updateHelmetDisplay() {
var fraction = helmetMeter / helmetMeterMax;
if (helmetMeter <= 0) {
fillBar.visible = false;
} else {
fillBar.visible = true;
if (fraction > 1) {
fraction = 1;
}
fillBar.width = fraction * helmetSprite.width;
}
}
/****
* Petals
****/
var petals = [];
for (var i = 0; i < 50; i++) {
var petal = new Container();
petal.attachAsset('petals', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.random() * Math.PI * 2
});
petal.x = Math.random() * 2048;
petal.y = Math.random() * 2732;
petal.speedY = Math.random() * 2 + 1;
petal.speedX = Math.random() * 2 - 1;
petal.update = function () {
this.y += this.speedY;
this.x += this.speedX;
if (this.y > 2732) {
this.y = -50;
this.x = Math.random() * 2048;
}
};
petals.push(petal);
game.addChild(petal);
}
/****
* Player Setup with Custom Collision
****/
var player = new Container();
var visualContainer = new Container();
visualContainer.name = 'visual';
// Attach the player_idle asset with centered anchors.
var playerSprite = visualContainer.attachAsset('player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
player.addChild(visualContainer);
// Position the player in the scene.
player.x = 1024;
player.y = 2732 - 250;
// Add the player to the game.
game.addChild(player);
// Replace the normal collision with a custom collision shape centered on the player.
var idleCollision = player.attachAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 120,
alpha: 0 // Set to 0 for production (use a nonzero value for debugging)
});
idleCollision.name = 'idleCollision';
/****
* Idle Animations
****/
function startBreathingAnimation() {
tween(player, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: startBreathingAnimation
});
}
});
}
function startTiltAnimation() {
tween(player, {
rotation: Math.PI / 32
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
rotation: -Math.PI / 32
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
rotation: 0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: startTiltAnimation
});
}
});
}
});
}
startBreathingAnimation();
startTiltAnimation();
/****
* Attack Collider
****/
var attackCol = LK.getAsset('attackcol', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.75
});
game.addChild(attackCol);
attackCol.visible = false;
attackCol.alpha = 0;
/****
* Power-Up: Helmet HUD & Special
****/
var featherEffects = [];
function spawnFeatherMove() {
if (!specialIdleActive) {
return;
}
for (var i = -2; i <= 2; i++) {
var feather = new Container();
feather.attachAsset('feather', {
anchorX: 0.5,
anchorY: 0.5
});
feather.x = player.x + i * 50;
feather.y = player.y;
game.addChild(feather);
featherEffects.push(feather);
tween(feather, {
x: feather.x + i * 500,
y: feather.y + (Math.random() * 200 - 100),
alpha: 0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
feather.destroy();
}
});
}
}
var helmetActive = false;
var specialIdleActive = false;
function activateHelmetPowerUp() {
if (helmetActive) {
return;
}
helmetActive = true;
// Switch to special_idle.
swapPlayerVisual('special_idle', player.x, player.y, visualContainer.scaleX);
specialIdleActive = true;
LK.getSound('warcry').play();
LK.effects.flashScreen(0xFFFFFF, 100);
var shakeIntensity = 10,
shakeDuration = 500;
var shakeStartTime = Date.now();
var originalPosition = {
x: game.x,
y: game.y
};
function shakeScreen() {
var elapsed = Date.now() - shakeStartTime;
if (elapsed < shakeDuration) {
var offsetX = (Math.random() - 0.5) * shakeIntensity;
var offsetY = (Math.random() - 0.5) * shakeIntensity;
game.x = originalPosition.x + offsetX;
game.y = originalPosition.y + offsetY;
LK.setTimeout(shakeScreen, 16);
} else {
game.x = originalPosition.x;
game.y = originalPosition.y;
}
}
shakeScreen();
spawnFeatherMove();
LK.setTimeout(spawnFeatherMove, 1500);
LK.setTimeout(spawnFeatherMove, 3000);
LK.setTimeout(function () {
while (featherEffects.length) {
featherEffects.pop().destroy();
}
specialIdleActive = false;
if (!isJumping) {
swapPlayerVisual('player_idle', player.x, player.y, visualContainer.scaleX, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
LK.effects.flashScreen(0xFFFFFF, 100);
helmetActive = false;
helmetMeter = 0;
updateHelmetDisplay();
}, 4000);
}
/****
* spawnEnemy and spawnShield
****/
function spawnEnemy() {
var e = new Container();
var hitbox = new Shape({
width: 200,
height: 209,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00FF00,
alpha: 0
});
hitbox.x = 0;
hitbox.y = 0;
e.addChild(hitbox);
var gfx = e.attachAsset('enemy01', {
anchorX: 0.5,
anchorY: 0.5
});
var fromLeft = Math.random() < 0.5;
e.x = fromLeft ? -gfx.width / 2 : 2048 + gfx.width / 2;
e.y = 2732 - 225;
e.speedX = fromLeft ? Math.random() * 6 + 2 : -(Math.random() * 6 + 2);
if (Math.abs(e.speedX) >= 6) {
gfx.tint = 0xFF0000;
} else if (Math.abs(e.speedX) <= 3) {
gfx.tint = 0x0000FF;
}
gfx.scaleX = fromLeft ? 1 : -1;
var baseY = e.y;
function bounce() {
tween(e, {
y: baseY - 50
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: function onFinish() {
tween(e, {
y: baseY
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: bounce
});
}
});
}
bounce();
enemies.push(e);
game.addChild(e);
}
function spawnShield() {
var shield = new Container();
var hitbox = new Shape({
width: 200,
height: 209,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00FF00,
alpha: 0
});
hitbox.x = 0;
hitbox.y = 0;
shield.addChild(hitbox);
var gfx = shield.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
var fromLeft = Math.random() < 0.5;
shield.x = fromLeft ? -gfx.width / 2 : 2048 + gfx.width / 2;
shield.y = 2732 - 225;
shield.speedX = fromLeft ? Math.random() * 6 + 2 : -(Math.random() * 6 + 2);
// Mark shield enemy – these won't die on melee/throw hits.
shield.isShield = true;
// Apply a distinct tint to shield enemies.
gfx.tint = 0xFFD700;
gfx.scaleX = fromLeft ? 1 : -1;
var baseY = shield.y;
function bounce() {
tween(shield, {
y: baseY - 50
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: function onFinish() {
tween(shield, {
y: baseY
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: bounce
});
}
});
}
bounce();
enemies.push(shield);
game.addChild(shield);
}
// Spawn regular enemies every ~1.5 seconds.
var enemySpawnInterval = Math.random() * 1500 + 1000;
var shieldSpawnInterval = 10000;
LK.setInterval(spawnEnemy, enemySpawnInterval);
LK.setInterval(spawnShield, shieldSpawnInterval);
// Increase spawn speed by 5% every 30 real life seconds
enemySpawnInterval *= 0.95;
shieldSpawnInterval *= 0.95;
LK.setInterval(function () {
LK.setInterval(spawnEnemy, enemySpawnInterval);
LK.setInterval(spawnShield, shieldSpawnInterval);
}, 30000);
/****
* Swap Player Sprite Function
* IMPORTANT: We add a check so that if specialIdleActive is true and we aren’t explicitly switching to 'special_idle', then no swap is performed.
****/
function swapPlayerVisual(newVisualId, x, y, flip, onDone) {
// Prevent overriding the special_idle state while it’s active.
if (specialIdleActive && newVisualId !== 'special_idle') {
return;
}
var visualContainer = player.findChildByName('visual');
if (!visualContainer) {
visualContainer = new Container();
visualContainer.name = 'visual';
player.addChild(visualContainer);
} else {
visualContainer.removeChildAt(0);
}
playerSprite = visualContainer.attachAsset(newVisualId, {
anchorX: 0.5,
anchorY: 0.5,
y: newVisualId === 'special_idle' ? -100 : 0,
scaleX: newVisualId === 'special_idle' ? 1.25 : 1,
scaleY: newVisualId === 'special_idle' ? 1.25 : 1
});
visualContainer.scaleX = flip;
player.x = x;
player.y = y;
if (newVisualId === 'player_jump') {
flip = Math.random() < 0.5 ? -1 : 1;
visualContainer.scaleX = flip;
jumpColGlobal = LK.getAsset('jumpcol', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y + player.height / 2,
alpha: 0
});
game.addChild(jumpColGlobal);
tween(jumpColGlobal, {
y: jumpColGlobal.y - 600
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(jumpColGlobal, {
y: 2732 - 250 + player.height / 2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
jumpColGlobal.destroy();
jumpColGlobal = null;
}
});
}
});
}
if (typeof onDone === 'function') {
if (newVisualId === 'player_idle') {
startBreathingAnimation();
startTiltAnimation();
}
onDone();
}
}
/****
* Input Logic
****/
var isSequenceRunning = false;
var isJumping = false;
var playerState = 'idle';
game.down = function (x, y) {
// Do not process input if an action is running or special_idle is active.
if (isSequenceRunning || specialIdleActive) {
return;
}
isPressHeld = true;
pressHoldStartTime = Date.now();
pressDownX = x;
pressDownY = y;
// If click occurs in upper part and player is not already jumping, start jump sequence.
if (y < 2732 * 2.2 / 3 && !isJumping) {
isJumping = true;
LK.getSound('hup').play();
swapPlayerVisual('player_jump', player.x, player.y);
// Generate dust effects.
for (var i = 0; i < 10; i++) {
var p = LK.getAsset('dust', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() * 100 - 50),
y: player.y + (Math.random() * 100 - 50)
});
game.addChild(p);
tween(p, {
alpha: 0,
x: p.x + (Math.random() * 200 - 100),
y: p.y - Math.random() * 200
}, {
duration: 500,
onFinish: function onFinish() {
p.destroy();
}
});
}
tween(player, {
y: player.y - 600
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
y: 2732 - 250
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
for (var j = 0; j < 10; j++) {
var pp = LK.getAsset('dust', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() * 100 - 50),
y: player.y + (Math.random() * 100 - 50)
});
game.addChild(pp);
tween(pp, {
alpha: 0,
x: pp.x + (Math.random() * 200 - 100),
y: pp.y + Math.random() * 200
}, {
duration: 500,
onFinish: function onFinish() {
pp.destroy();
}
});
}
isJumping = false;
var landingFlip = Math.random() < 0.5 ? -1 : 1;
if (specialIdleActive) {
swapPlayerVisual('special_idle', 1024, 2732 - 250, landingFlip);
} else {
swapPlayerVisual('player_idle', 1024, 2732 - 250, landingFlip, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
var v = player.findChildByName('visual');
if (v) {
var dir = v.scaleX < 0 ? -1 : 1;
tween(v, {
scaleX: dir * 1.3,
scaleY: 1.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(v, {
scaleX: dir * 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
}
}
});
}
});
return;
}
// Process attack input.
isSequenceRunning = true;
var flip = x < 1024 ? -1 : 1;
swapPlayerVisual('player_attackf01', 1024, 2732 - 250, flip);
LK.getSound('retroslash').play();
var vis = player.findChildByName('visual');
if (vis) {
tween(vis, {
scaleX: flip * 1.3,
scaleY: 1.3
}, {
duration: 30,
onFinish: function onFinish() {
tween(vis, {
scaleX: flip * 1.0,
scaleY: 1.0
}, {
duration: 60
});
}
});
}
LK.setTimeout(function () {
swapPlayerVisual('player_attackf02', 1024, 2732 - 250, flip);
attackCol.width = 180;
attackCol.height = 180;
attackCol.x = flip === -1 ? 874 : 1174;
attackCol.y = 2732 - 250;
attackCol.scaleX = flip;
attackCol.visible = true;
LK.setTimeout(function () {
if (attackCol) {
attackCol.visible = false;
}
if (!specialIdleActive) {
swapPlayerVisual('player_idle', 1024, 2732 - 250, 1, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
isSequenceRunning = false;
playerState = 'idle';
}, 150);
}, 150);
};
/****
* Enemies Array & Spawn
****/
var enemies = [];
LK.setInterval(spawnEnemy, Math.random() * 2000 + 1500);
LK.setInterval(spawnShield, 15000);
/****
* Projectile Logic (Throw Attack)
* Note: For throw, we use only the f01 animation then immediately revert back to idle.
****/
function spawnProjectile(targetX, targetY) {
var flip = targetX < player.x ? -1 : 1;
// Use only player_attackf01 for the throw.
swapPlayerVisual('player_attackf01', player.x, player.y, flip);
var proj = new Container();
proj.attachAsset('player_throw', {
anchorX: 0.5,
anchorY: 0.5
});
LK.getSound('throwsnd').play();
proj.x = player.x;
proj.y = player.y;
var cloudSmoke = LK.getAsset('cloudsmoke', {
anchorX: 0.5,
anchorY: 0.5,
x: proj.x,
y: proj.y,
alpha: 0.75
});
game.addChild(cloudSmoke);
tween(cloudSmoke, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
cloudSmoke.destroy();
}
});
var dx = targetX - player.x,
dy = targetY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist !== 0) {
dx /= dist;
dy /= dist;
}
var speed = 40;
proj.vx = dx * speed;
proj.vy = dy * speed;
proj.scaleX = targetX < player.x ? -1 : 1;
proj.distanceTraveled = 0;
proj.maxDistance = 1000;
projectiles.push(proj);
game.addChild(proj);
LK.setTimeout(function () {
// Revert directly to idle after throw.
swapPlayerVisual('player_idle', player.x, player.y, flip, function () {
startBreathingAnimation();
startTiltAnimation();
});
}, 300);
}
/****
* Coins
****/
var coins = [];
function dropCoin(x, y) {
var rand = Math.random();
if (rand < 0.5) {
var coin = new Container();
coin.type = 'silver';
coin.attachAsset('silver_coin', {
anchorX: 0.5,
anchorY: 0.5
});
coin.x = x;
coin.y = y;
game.addChild(coin);
coins.push(coin);
loopCoinTween(coin, y);
} else if (rand < 0.6) {
var coin = new Container();
coin.type = 'gold';
coin.attachAsset('gold_coin', {
anchorX: 0.5,
anchorY: 0.5
});
coin.x = x;
coin.y = y;
game.addChild(coin);
coins.push(coin);
loopCoinTween(coin, y);
}
}
/****
* Looping Tween Functions
****/
function loopCoinTween(coin, baseY) {
tween(coin, {
y: baseY - 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coin, {
y: baseY + 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
loopCoinTween(coin, baseY);
}
});
}
});
}
/****
* Enemy Hit Logic – Also fills the helmet meter
****/
function handleEnemyHit(enemy, index, attackType) {
if (!enemies.includes(enemy) || enemy.hit) {
return;
}
// Ignore melee/throw hits if enemy is a shield.
if (enemy.isShield && (attackType === 'melee' || attackType === 'throw')) {
return;
}
enemy.hit = true;
LK.getSound('slimedeath').play();
if (enemy.bounceTween && typeof enemy.bounceTween.cancel === 'function') {
enemy.bounceTween.cancel();
}
tween(enemy, {
tint: 0xFF0000
}, {
duration: 0,
onFinish: function onFinish() {
tween(enemy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(enemy, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0
}, {
duration: 100,
onFinish: function onFinish() {
var idx = enemies.indexOf(enemy);
if (idx !== -1) {
enemies.splice(idx, 1);
}
enemy.hit = false;
enemy.destroy();
if (!enemy.coinsDropped) {
dropCoin(enemy.x, enemy.y);
enemy.coinsDropped = true;
}
// Increase helmetMeter based on attack type.
if (attackType === 'melee') {
helmetMeter += 5;
} else if (attackType === 'throw') {
helmetMeter += 5;
} else if (attackType === 'special_idle') {
helmetMeter += 15;
}
if (helmetMeter >= helmetMeterMax) {
helmetMeter = helmetMeterMax;
activateHelmetPowerUp();
helmetMeter = 0;
}
updateHelmetDisplay();
if (!enemy.scoreCounted) {
if (attackType === 'melee') {
score += 2;
} else if (attackType === 'throw') {
score += 1;
} else {
score++;
}
updateScoreDisplay();
enemy.scoreCounted = true;
}
}
});
}
});
}
});
}
function handleEnemyJumpHit(enemy, index) {
if (!enemies.includes(enemy)) {
return;
}
LK.getSound('boing').play();
if (enemy.bounceTween && typeof enemy.bounceTween.cancel === 'function') {
enemy.bounceTween.cancel();
}
tween(enemy, {
tint: 0xFF0000
}, {
duration: 0,
onFinish: function onFinish() {
var targetX = enemy.x < 1024 ? -300 : 2048 + 300;
var targetY = enemy.y - 600;
tween(enemy, {
x: targetX,
y: targetY,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
var idx = enemies.indexOf(enemy);
if (idx !== -1) {
enemies.splice(idx, 1);
}
enemy.destroy();
if (!enemy.coinsDropped) {
dropCoin(enemy.x, enemy.y);
enemy.coinsDropped = true;
}
helmetMeter += 10;
if (helmetMeter >= helmetMeterMax) {
helmetMeter = helmetMeterMax;
activateHelmetPowerUp();
helmetMeter = 0;
}
updateHelmetDisplay();
if (!enemy.scoreCounted) {
score += 3;
updateScoreDisplay();
enemy.scoreCounted = true;
}
}
});
}
});
}
/****
* findChildByName Helper
****/
Container.prototype.findChildByName = function (name) {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i].name === name) {
return this.children[i];
}
}
return null;
};
/****
* game.up to Reset Press
****/
game.up = function (x, y) {
isPressHeld = false;
pressHoldStartTime = 0;
};
/****
* Main Update
****/
game.update = function () {
if (isPressHeld) {
var holdDuration = Date.now() - pressHoldStartTime;
if (holdDuration > 500) {
console.log("Long press detected, spawn projectile!");
isPressHeld = false;
spawnProjectile(pressDownX, pressDownY);
}
}
for (var p = projectiles.length - 1; p >= 0; p--) {
var proj = projectiles[p];
proj.x += proj.vx;
proj.y += proj.vy;
var stepDist = Math.sqrt(proj.vx * proj.vx + proj.vy * proj.vy);
proj.distanceTraveled += stepDist;
if (proj.distanceTraveled > proj.maxDistance) {
projectiles.splice(p, 1);
proj.destroy();
continue;
}
if (proj.x < -100 || proj.x > 2148 || proj.y < -100 || proj.y > 2832) {
projectiles.splice(p, 1);
proj.destroy();
continue;
}
for (var ei = enemies.length - 1; ei >= 0; ei--) {
var enemy = enemies[ei];
if (proj.intersects(enemy)) {
handleEnemyHit(enemy, ei, 'throw');
projectiles.splice(p, 1);
proj.destroy();
break;
}
}
}
for (var f = featherEffects.length - 1; f >= 0; f--) {
var feather = featherEffects[f];
for (var ei = enemies.length - 1; ei >= 0; ei--) {
var enemy = enemies[ei];
if (feather.intersects(enemy)) {
handleEnemyHit(enemy, ei, 'feather');
featherEffects.splice(f, 1);
feather.destroy();
break;
}
}
}
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.x += e.speedX;
if (e.x < -300 || e.x > 2048 + 300) {
var index = enemies.indexOf(e);
if (index !== -1) {
enemies.splice(index, 1);
}
e.destroy();
continue;
}
if (jumpColGlobal && jumpColGlobal.visible && e.intersects(jumpColGlobal)) {
handleEnemyJumpHit(e, i);
continue;
}
if (attackCol.visible && e.intersects(attackCol)) {
handleEnemyHit(e, i, 'melee');
}
var idleCollision = player.findChildByName('idleCollision');
if (!isJumping && !attackCol.visible && idleCollision && e.intersects(idleCollision)) {
if (specialIdleActive) {
handleEnemyHit(e, i, 'special_idle');
continue;
} else {
storage.lastScore = score;
LK.showGameOver();
}
}
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.collecting && Math.abs(coin.x - mouseX) < 32.5 && Math.abs(coin.y - mouseY) < 32.5) {
coin.collecting = true;
tween(coin, {
x: scoreTxt.x,
y: scoreTxt.y,
alpha: 0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
var index = coins.indexOf(coin);
if (index !== -1) {
coins.splice(index, 1);
}
if (coin.type === 'silver') {
LK.getSound('silversnd').play();
score += 5;
} else if (coin.type === 'gold') {
LK.getSound('goldsnd').play();
score += 10;
}
updateScoreDisplay();
coin.destroy();
}
});
}
}
// Helmet HUD: No collision logic.
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Shape = Container.expand(function (options) {
var self = Container.call(this);
self.attachAsset('shape', {
width: options.width,
height: options.height,
anchorX: options.anchorX || 0,
anchorY: options.anchorY || 0,
color: options.color || 0x66ff00,
alpha: typeof options.alpha === 'number' ? options.alpha : 0
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Helper function to find a child by name.
function findChildByName(container, name) {
for (var i = 0; i < container.children.length; i++) {
if (container.children[i].name === name) {
return container.children[i];
}
}
return null;
}
/****
* Global Variables
****/
var jumpColGlobal = null;
var isPressHeld = false;
var pressHoldStartTime = 0;
var pressDownX = 0;
var pressDownY = 0;
var mouseX = 0;
var mouseY = 0;
game.move = function (x, y) {
mouseX = x;
mouseY = y;
};
var projectiles = [];
var score = 0;
var scoreTxt;
function updateScoreDisplay() {
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('High Score: ' + highScore);
}
game.removeChild(scoreTxt);
scoreTxt = createScoreText(score);
scoreTxt.scaleX = 1.0;
scoreTxt.scaleY = 1.0;
game.addChild(scoreTxt);
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
function createScoreText(value) {
var shadow = new Text2(String(value), {
size: 600,
fill: 0x000000,
fontFamily: "Arial"
});
shadow.name = "shadow";
shadow.anchor.set(0.5, 0);
shadow.x = 4;
shadow.y = 4;
var main = new Text2(String(value), {
size: 600,
fill: 0xFF69B4,
fontFamily: "Arial"
});
main.name = "main";
main.anchor.set(0.5, 0);
var container = new Container();
container.name = "scoreTxt";
container.x = 1024;
container.y = 50;
container.addChild(shadow);
container.addChild(main);
return container;
}
scoreTxt = createScoreText(score);
scoreTxt.scaleX = 1.0;
scoreTxt.scaleY = 1.0;
LK.playMusic('bgm', {
loop: true
});
var bg01 = LK.getAsset('bg01', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
game.addChild(bg01);
game.addChild(scoreTxt);
var highScore = storage.highScore || 0;
var highScoreTxt = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFFFFF
});
highScoreTxt.name = 'highScoreTxt';
highScoreTxt.anchor.set(1, 1);
highScoreTxt.x = 1900;
highScoreTxt.y = 2720;
game.addChild(highScoreTxt);
/****
* Persistent Power Helmet HUD (for filling up)
****/
var helmetMeter = 0;
var helmetMeterMax = 120;
var powerHelmet = new Container();
powerHelmet.name = "powerHelmet";
var helmetSprite = powerHelmet.attachAsset('helmet', {
anchorX: 0.5,
anchorY: 0.5
});
powerHelmet.x = 2048 - helmetSprite.width / 2 - 20;
powerHelmet.y = 130;
var helmetFillContainer = new Container();
helmetFillContainer.name = "helmetFillContainer";
var fillBar = new Shape({
width: helmetSprite.width * 0.05,
height: 40,
color: 0xFFFFFF,
alpha: 1
});
fillBar.anchorX = 0;
fillBar.anchorY = 0.5;
fillBar.x = -helmetSprite.width / 2;
fillBar.y = helmetSprite.height / 2 - 15;
helmetFillContainer.addChild(fillBar);
game.addChild(powerHelmet);
powerHelmet.addChild(helmetFillContainer);
function updateHelmetDisplay() {
var fraction = helmetMeter / helmetMeterMax;
if (helmetMeter <= 0) {
fillBar.visible = false;
} else {
fillBar.visible = true;
if (fraction > 1) {
fraction = 1;
}
fillBar.width = fraction * helmetSprite.width;
}
}
/****
* Petals
****/
var petals = [];
for (var i = 0; i < 50; i++) {
var petal = new Container();
petal.attachAsset('petals', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.random() * Math.PI * 2
});
petal.x = Math.random() * 2048;
petal.y = Math.random() * 2732;
petal.speedY = Math.random() * 2 + 1;
petal.speedX = Math.random() * 2 - 1;
petal.update = function () {
this.y += this.speedY;
this.x += this.speedX;
if (this.y > 2732) {
this.y = -50;
this.x = Math.random() * 2048;
}
};
petals.push(petal);
game.addChild(petal);
}
/****
* Player Setup with Custom Collision
****/
var player = new Container();
var visualContainer = new Container();
visualContainer.name = 'visual';
// Attach the player_idle asset with centered anchors.
var playerSprite = visualContainer.attachAsset('player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
player.addChild(visualContainer);
// Position the player in the scene.
player.x = 1024;
player.y = 2732 - 250;
// Add the player to the game.
game.addChild(player);
// Replace the normal collision with a custom collision shape centered on the player.
var idleCollision = player.attachAsset('shape', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 120,
alpha: 0 // Set to 0 for production (use a nonzero value for debugging)
});
idleCollision.name = 'idleCollision';
/****
* Idle Animations
****/
function startBreathingAnimation() {
tween(player, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: startBreathingAnimation
});
}
});
}
function startTiltAnimation() {
tween(player, {
rotation: Math.PI / 32
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
rotation: -Math.PI / 32
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
rotation: 0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: startTiltAnimation
});
}
});
}
});
}
startBreathingAnimation();
startTiltAnimation();
/****
* Attack Collider
****/
var attackCol = LK.getAsset('attackcol', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.75
});
game.addChild(attackCol);
attackCol.visible = false;
attackCol.alpha = 0;
/****
* Power-Up: Helmet HUD & Special
****/
var featherEffects = [];
function spawnFeatherMove() {
if (!specialIdleActive) {
return;
}
for (var i = -2; i <= 2; i++) {
var feather = new Container();
feather.attachAsset('feather', {
anchorX: 0.5,
anchorY: 0.5
});
feather.x = player.x + i * 50;
feather.y = player.y;
game.addChild(feather);
featherEffects.push(feather);
tween(feather, {
x: feather.x + i * 500,
y: feather.y + (Math.random() * 200 - 100),
alpha: 0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
feather.destroy();
}
});
}
}
var helmetActive = false;
var specialIdleActive = false;
function activateHelmetPowerUp() {
if (helmetActive) {
return;
}
helmetActive = true;
// Switch to special_idle.
swapPlayerVisual('special_idle', player.x, player.y, visualContainer.scaleX);
specialIdleActive = true;
LK.getSound('warcry').play();
LK.effects.flashScreen(0xFFFFFF, 100);
var shakeIntensity = 10,
shakeDuration = 500;
var shakeStartTime = Date.now();
var originalPosition = {
x: game.x,
y: game.y
};
function shakeScreen() {
var elapsed = Date.now() - shakeStartTime;
if (elapsed < shakeDuration) {
var offsetX = (Math.random() - 0.5) * shakeIntensity;
var offsetY = (Math.random() - 0.5) * shakeIntensity;
game.x = originalPosition.x + offsetX;
game.y = originalPosition.y + offsetY;
LK.setTimeout(shakeScreen, 16);
} else {
game.x = originalPosition.x;
game.y = originalPosition.y;
}
}
shakeScreen();
spawnFeatherMove();
LK.setTimeout(spawnFeatherMove, 1500);
LK.setTimeout(spawnFeatherMove, 3000);
LK.setTimeout(function () {
while (featherEffects.length) {
featherEffects.pop().destroy();
}
specialIdleActive = false;
if (!isJumping) {
swapPlayerVisual('player_idle', player.x, player.y, visualContainer.scaleX, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
LK.effects.flashScreen(0xFFFFFF, 100);
helmetActive = false;
helmetMeter = 0;
updateHelmetDisplay();
}, 4000);
}
/****
* spawnEnemy and spawnShield
****/
function spawnEnemy() {
var e = new Container();
var hitbox = new Shape({
width: 200,
height: 209,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00FF00,
alpha: 0
});
hitbox.x = 0;
hitbox.y = 0;
e.addChild(hitbox);
var gfx = e.attachAsset('enemy01', {
anchorX: 0.5,
anchorY: 0.5
});
var fromLeft = Math.random() < 0.5;
e.x = fromLeft ? -gfx.width / 2 : 2048 + gfx.width / 2;
e.y = 2732 - 225;
e.speedX = fromLeft ? Math.random() * 6 + 2 : -(Math.random() * 6 + 2);
if (Math.abs(e.speedX) >= 6) {
gfx.tint = 0xFF0000;
} else if (Math.abs(e.speedX) <= 3) {
gfx.tint = 0x0000FF;
}
gfx.scaleX = fromLeft ? 1 : -1;
var baseY = e.y;
function bounce() {
tween(e, {
y: baseY - 50
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: function onFinish() {
tween(e, {
y: baseY
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: bounce
});
}
});
}
bounce();
enemies.push(e);
game.addChild(e);
}
function spawnShield() {
var shield = new Container();
var hitbox = new Shape({
width: 200,
height: 209,
anchorX: 0.5,
anchorY: 0.5,
color: 0x00FF00,
alpha: 0
});
hitbox.x = 0;
hitbox.y = 0;
shield.addChild(hitbox);
var gfx = shield.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
var fromLeft = Math.random() < 0.5;
shield.x = fromLeft ? -gfx.width / 2 : 2048 + gfx.width / 2;
shield.y = 2732 - 225;
shield.speedX = fromLeft ? Math.random() * 6 + 2 : -(Math.random() * 6 + 2);
// Mark shield enemy – these won't die on melee/throw hits.
shield.isShield = true;
// Apply a distinct tint to shield enemies.
gfx.tint = 0xFFD700;
gfx.scaleX = fromLeft ? 1 : -1;
var baseY = shield.y;
function bounce() {
tween(shield, {
y: baseY - 50
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: function onFinish() {
tween(shield, {
y: baseY
}, {
duration: 500,
easing: tween.bounceInOut,
onFinish: bounce
});
}
});
}
bounce();
enemies.push(shield);
game.addChild(shield);
}
// Spawn regular enemies every ~1.5 seconds.
var enemySpawnInterval = Math.random() * 1500 + 1000;
var shieldSpawnInterval = 10000;
LK.setInterval(spawnEnemy, enemySpawnInterval);
LK.setInterval(spawnShield, shieldSpawnInterval);
// Increase spawn speed by 5% every 30 real life seconds
enemySpawnInterval *= 0.95;
shieldSpawnInterval *= 0.95;
LK.setInterval(function () {
LK.setInterval(spawnEnemy, enemySpawnInterval);
LK.setInterval(spawnShield, shieldSpawnInterval);
}, 30000);
/****
* Swap Player Sprite Function
* IMPORTANT: We add a check so that if specialIdleActive is true and we aren’t explicitly switching to 'special_idle', then no swap is performed.
****/
function swapPlayerVisual(newVisualId, x, y, flip, onDone) {
// Prevent overriding the special_idle state while it’s active.
if (specialIdleActive && newVisualId !== 'special_idle') {
return;
}
var visualContainer = player.findChildByName('visual');
if (!visualContainer) {
visualContainer = new Container();
visualContainer.name = 'visual';
player.addChild(visualContainer);
} else {
visualContainer.removeChildAt(0);
}
playerSprite = visualContainer.attachAsset(newVisualId, {
anchorX: 0.5,
anchorY: 0.5,
y: newVisualId === 'special_idle' ? -100 : 0,
scaleX: newVisualId === 'special_idle' ? 1.25 : 1,
scaleY: newVisualId === 'special_idle' ? 1.25 : 1
});
visualContainer.scaleX = flip;
player.x = x;
player.y = y;
if (newVisualId === 'player_jump') {
flip = Math.random() < 0.5 ? -1 : 1;
visualContainer.scaleX = flip;
jumpColGlobal = LK.getAsset('jumpcol', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y + player.height / 2,
alpha: 0
});
game.addChild(jumpColGlobal);
tween(jumpColGlobal, {
y: jumpColGlobal.y - 600
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(jumpColGlobal, {
y: 2732 - 250 + player.height / 2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
jumpColGlobal.destroy();
jumpColGlobal = null;
}
});
}
});
}
if (typeof onDone === 'function') {
if (newVisualId === 'player_idle') {
startBreathingAnimation();
startTiltAnimation();
}
onDone();
}
}
/****
* Input Logic
****/
var isSequenceRunning = false;
var isJumping = false;
var playerState = 'idle';
game.down = function (x, y) {
// Do not process input if an action is running or special_idle is active.
if (isSequenceRunning || specialIdleActive) {
return;
}
isPressHeld = true;
pressHoldStartTime = Date.now();
pressDownX = x;
pressDownY = y;
// If click occurs in upper part and player is not already jumping, start jump sequence.
if (y < 2732 * 2.2 / 3 && !isJumping) {
isJumping = true;
LK.getSound('hup').play();
swapPlayerVisual('player_jump', player.x, player.y);
// Generate dust effects.
for (var i = 0; i < 10; i++) {
var p = LK.getAsset('dust', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() * 100 - 50),
y: player.y + (Math.random() * 100 - 50)
});
game.addChild(p);
tween(p, {
alpha: 0,
x: p.x + (Math.random() * 200 - 100),
y: p.y - Math.random() * 200
}, {
duration: 500,
onFinish: function onFinish() {
p.destroy();
}
});
}
tween(player, {
y: player.y - 600
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
y: 2732 - 250
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
for (var j = 0; j < 10; j++) {
var pp = LK.getAsset('dust', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x + (Math.random() * 100 - 50),
y: player.y + (Math.random() * 100 - 50)
});
game.addChild(pp);
tween(pp, {
alpha: 0,
x: pp.x + (Math.random() * 200 - 100),
y: pp.y + Math.random() * 200
}, {
duration: 500,
onFinish: function onFinish() {
pp.destroy();
}
});
}
isJumping = false;
var landingFlip = Math.random() < 0.5 ? -1 : 1;
if (specialIdleActive) {
swapPlayerVisual('special_idle', 1024, 2732 - 250, landingFlip);
} else {
swapPlayerVisual('player_idle', 1024, 2732 - 250, landingFlip, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
var v = player.findChildByName('visual');
if (v) {
var dir = v.scaleX < 0 ? -1 : 1;
tween(v, {
scaleX: dir * 1.3,
scaleY: 1.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(v, {
scaleX: dir * 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
}
}
});
}
});
return;
}
// Process attack input.
isSequenceRunning = true;
var flip = x < 1024 ? -1 : 1;
swapPlayerVisual('player_attackf01', 1024, 2732 - 250, flip);
LK.getSound('retroslash').play();
var vis = player.findChildByName('visual');
if (vis) {
tween(vis, {
scaleX: flip * 1.3,
scaleY: 1.3
}, {
duration: 30,
onFinish: function onFinish() {
tween(vis, {
scaleX: flip * 1.0,
scaleY: 1.0
}, {
duration: 60
});
}
});
}
LK.setTimeout(function () {
swapPlayerVisual('player_attackf02', 1024, 2732 - 250, flip);
attackCol.width = 180;
attackCol.height = 180;
attackCol.x = flip === -1 ? 874 : 1174;
attackCol.y = 2732 - 250;
attackCol.scaleX = flip;
attackCol.visible = true;
LK.setTimeout(function () {
if (attackCol) {
attackCol.visible = false;
}
if (!specialIdleActive) {
swapPlayerVisual('player_idle', 1024, 2732 - 250, 1, function () {
startBreathingAnimation();
startTiltAnimation();
});
}
isSequenceRunning = false;
playerState = 'idle';
}, 150);
}, 150);
};
/****
* Enemies Array & Spawn
****/
var enemies = [];
LK.setInterval(spawnEnemy, Math.random() * 2000 + 1500);
LK.setInterval(spawnShield, 15000);
/****
* Projectile Logic (Throw Attack)
* Note: For throw, we use only the f01 animation then immediately revert back to idle.
****/
function spawnProjectile(targetX, targetY) {
var flip = targetX < player.x ? -1 : 1;
// Use only player_attackf01 for the throw.
swapPlayerVisual('player_attackf01', player.x, player.y, flip);
var proj = new Container();
proj.attachAsset('player_throw', {
anchorX: 0.5,
anchorY: 0.5
});
LK.getSound('throwsnd').play();
proj.x = player.x;
proj.y = player.y;
var cloudSmoke = LK.getAsset('cloudsmoke', {
anchorX: 0.5,
anchorY: 0.5,
x: proj.x,
y: proj.y,
alpha: 0.75
});
game.addChild(cloudSmoke);
tween(cloudSmoke, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
cloudSmoke.destroy();
}
});
var dx = targetX - player.x,
dy = targetY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist !== 0) {
dx /= dist;
dy /= dist;
}
var speed = 40;
proj.vx = dx * speed;
proj.vy = dy * speed;
proj.scaleX = targetX < player.x ? -1 : 1;
proj.distanceTraveled = 0;
proj.maxDistance = 1000;
projectiles.push(proj);
game.addChild(proj);
LK.setTimeout(function () {
// Revert directly to idle after throw.
swapPlayerVisual('player_idle', player.x, player.y, flip, function () {
startBreathingAnimation();
startTiltAnimation();
});
}, 300);
}
/****
* Coins
****/
var coins = [];
function dropCoin(x, y) {
var rand = Math.random();
if (rand < 0.5) {
var coin = new Container();
coin.type = 'silver';
coin.attachAsset('silver_coin', {
anchorX: 0.5,
anchorY: 0.5
});
coin.x = x;
coin.y = y;
game.addChild(coin);
coins.push(coin);
loopCoinTween(coin, y);
} else if (rand < 0.6) {
var coin = new Container();
coin.type = 'gold';
coin.attachAsset('gold_coin', {
anchorX: 0.5,
anchorY: 0.5
});
coin.x = x;
coin.y = y;
game.addChild(coin);
coins.push(coin);
loopCoinTween(coin, y);
}
}
/****
* Looping Tween Functions
****/
function loopCoinTween(coin, baseY) {
tween(coin, {
y: baseY - 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coin, {
y: baseY + 20
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
loopCoinTween(coin, baseY);
}
});
}
});
}
/****
* Enemy Hit Logic – Also fills the helmet meter
****/
function handleEnemyHit(enemy, index, attackType) {
if (!enemies.includes(enemy) || enemy.hit) {
return;
}
// Ignore melee/throw hits if enemy is a shield.
if (enemy.isShield && (attackType === 'melee' || attackType === 'throw')) {
return;
}
enemy.hit = true;
LK.getSound('slimedeath').play();
if (enemy.bounceTween && typeof enemy.bounceTween.cancel === 'function') {
enemy.bounceTween.cancel();
}
tween(enemy, {
tint: 0xFF0000
}, {
duration: 0,
onFinish: function onFinish() {
tween(enemy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(enemy, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0
}, {
duration: 100,
onFinish: function onFinish() {
var idx = enemies.indexOf(enemy);
if (idx !== -1) {
enemies.splice(idx, 1);
}
enemy.hit = false;
enemy.destroy();
if (!enemy.coinsDropped) {
dropCoin(enemy.x, enemy.y);
enemy.coinsDropped = true;
}
// Increase helmetMeter based on attack type.
if (attackType === 'melee') {
helmetMeter += 5;
} else if (attackType === 'throw') {
helmetMeter += 5;
} else if (attackType === 'special_idle') {
helmetMeter += 15;
}
if (helmetMeter >= helmetMeterMax) {
helmetMeter = helmetMeterMax;
activateHelmetPowerUp();
helmetMeter = 0;
}
updateHelmetDisplay();
if (!enemy.scoreCounted) {
if (attackType === 'melee') {
score += 2;
} else if (attackType === 'throw') {
score += 1;
} else {
score++;
}
updateScoreDisplay();
enemy.scoreCounted = true;
}
}
});
}
});
}
});
}
function handleEnemyJumpHit(enemy, index) {
if (!enemies.includes(enemy)) {
return;
}
LK.getSound('boing').play();
if (enemy.bounceTween && typeof enemy.bounceTween.cancel === 'function') {
enemy.bounceTween.cancel();
}
tween(enemy, {
tint: 0xFF0000
}, {
duration: 0,
onFinish: function onFinish() {
var targetX = enemy.x < 1024 ? -300 : 2048 + 300;
var targetY = enemy.y - 600;
tween(enemy, {
x: targetX,
y: targetY,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
var idx = enemies.indexOf(enemy);
if (idx !== -1) {
enemies.splice(idx, 1);
}
enemy.destroy();
if (!enemy.coinsDropped) {
dropCoin(enemy.x, enemy.y);
enemy.coinsDropped = true;
}
helmetMeter += 10;
if (helmetMeter >= helmetMeterMax) {
helmetMeter = helmetMeterMax;
activateHelmetPowerUp();
helmetMeter = 0;
}
updateHelmetDisplay();
if (!enemy.scoreCounted) {
score += 3;
updateScoreDisplay();
enemy.scoreCounted = true;
}
}
});
}
});
}
/****
* findChildByName Helper
****/
Container.prototype.findChildByName = function (name) {
for (var i = 0; i < this.children.length; i++) {
if (this.children[i].name === name) {
return this.children[i];
}
}
return null;
};
/****
* game.up to Reset Press
****/
game.up = function (x, y) {
isPressHeld = false;
pressHoldStartTime = 0;
};
/****
* Main Update
****/
game.update = function () {
if (isPressHeld) {
var holdDuration = Date.now() - pressHoldStartTime;
if (holdDuration > 500) {
console.log("Long press detected, spawn projectile!");
isPressHeld = false;
spawnProjectile(pressDownX, pressDownY);
}
}
for (var p = projectiles.length - 1; p >= 0; p--) {
var proj = projectiles[p];
proj.x += proj.vx;
proj.y += proj.vy;
var stepDist = Math.sqrt(proj.vx * proj.vx + proj.vy * proj.vy);
proj.distanceTraveled += stepDist;
if (proj.distanceTraveled > proj.maxDistance) {
projectiles.splice(p, 1);
proj.destroy();
continue;
}
if (proj.x < -100 || proj.x > 2148 || proj.y < -100 || proj.y > 2832) {
projectiles.splice(p, 1);
proj.destroy();
continue;
}
for (var ei = enemies.length - 1; ei >= 0; ei--) {
var enemy = enemies[ei];
if (proj.intersects(enemy)) {
handleEnemyHit(enemy, ei, 'throw');
projectiles.splice(p, 1);
proj.destroy();
break;
}
}
}
for (var f = featherEffects.length - 1; f >= 0; f--) {
var feather = featherEffects[f];
for (var ei = enemies.length - 1; ei >= 0; ei--) {
var enemy = enemies[ei];
if (feather.intersects(enemy)) {
handleEnemyHit(enemy, ei, 'feather');
featherEffects.splice(f, 1);
feather.destroy();
break;
}
}
}
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.x += e.speedX;
if (e.x < -300 || e.x > 2048 + 300) {
var index = enemies.indexOf(e);
if (index !== -1) {
enemies.splice(index, 1);
}
e.destroy();
continue;
}
if (jumpColGlobal && jumpColGlobal.visible && e.intersects(jumpColGlobal)) {
handleEnemyJumpHit(e, i);
continue;
}
if (attackCol.visible && e.intersects(attackCol)) {
handleEnemyHit(e, i, 'melee');
}
var idleCollision = player.findChildByName('idleCollision');
if (!isJumping && !attackCol.visible && idleCollision && e.intersects(idleCollision)) {
if (specialIdleActive) {
handleEnemyHit(e, i, 'special_idle');
continue;
} else {
storage.lastScore = score;
LK.showGameOver();
}
}
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.collecting && Math.abs(coin.x - mouseX) < 32.5 && Math.abs(coin.y - mouseY) < 32.5) {
coin.collecting = true;
tween(coin, {
x: scoreTxt.x,
y: scoreTxt.y,
alpha: 0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
var index = coins.indexOf(coin);
if (index !== -1) {
coins.splice(index, 1);
}
if (coin.type === 'silver') {
LK.getSound('silversnd').play();
score += 5;
} else if (coin.type === 'gold') {
LK.getSound('goldsnd').play();
score += 10;
}
updateScoreDisplay();
coin.destroy();
}
});
}
}
// Helmet HUD: No collision logic.
};
high definition super nintendo background of a japanese sakura tree forest Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
2d snes dust particle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
silver coin, $ sign on it, snes art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
gold coin, $ sign on it, snes art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
snes white feather. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
add a wooden shield