User prompt
Pies ponle mejores efectos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ponlos em el escudo del rango hay.
User prompt
El contador de rnagos hay estaran los efectos.
User prompt
Mejor al supremo
User prompt
Please fix the bug: 'self.createCosmicDust is not a function' in or related to this line: 'self.createCosmicDust(0xff8800);' Line Number: 292
User prompt
Anade afectos a los rangos segun su rango el leyenda podria tener efecto de estrellitas etc.
User prompt
El multiplicador lo tengo siempre
User prompt
Pon un x10 de puntos.
User prompt
Pon mi score en 0 y mi rango ponlo en noob quita mi rango de hacker. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Quita la laderboard ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Reinia mi rango a noob ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Reinicio mi rango a noob ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Quita mis puntos. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Agrega escudos para los rangos. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Agrega escudos para los rangos. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Mucho pon mas pocos porque en si el juego es dificil agrega mas rangos como en noob puede estar noob I noob II noob III en los otros tambien. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Has que el ramgo se guarde en el sentido estamos en pro y termina la partida y empezamos otra empezamos en pro has que subir de rango sea mas dificil el rango que estemos aparesca en el menu. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Pon los rangos el score sirve el rango has que el ranga aparesca en el menu ese rango se tiene que guardar. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Has un sistema de rangos de noob pro dios hacker inparable etc. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard[k] = tempLeaderboard[k].score;' Line Number: 668 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard[k + '.score'] = tempLeaderboard[k].score;' Line Number: 693 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Pon la lederboar mas abajo.
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'currentLeaderboard[newIndex] = {};' Line Number: 660 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'currentLeaderboard[newIndex] = {};' Line Number: 660 ↪💡 Consider importing and using the following plugins: @upit/storage.v1 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'currentLeaderboard[newIndex] = {};' Line Number: 660 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
masterVolume: 0.7,
musicVolume: 0.8,
sfxVolume: 0.8,
graphicsQuality: "high",
leaderboard: [],
playerName: "Player",
currentRank: "noob"
});
/****
* Classes
****/
var Arrow = Container.expand(function (direction, column) {
var self = Container.call(this);
var arrowGraphic = self.attachAsset('arrow_' + direction, {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = direction;
self.column = column;
// Calculate dynamic speed based on current level and speed multiplier
var currentSpeed = baseSpeed * speedMultiplier;
self.speed = Math.min(currentSpeed, baseSpeed * maxSpeedMultiplier); // Apply speed cap
self.hitTested = false;
self.animationPhase = Math.random() * Math.PI * 2; // Random phase for animations
self.pulseSpeed = 0.8 + Math.random() * 0.4; // Random pulse speed
self.glowIntensity = 0.3 + Math.random() * 0.7; // Random glow intensity
self.sparkleTimer = Math.random() * 60; // Random sparkle timing
// Add initial entrance animation
arrowGraphic.scaleX = 0.1;
arrowGraphic.scaleY = 0.1;
arrowGraphic.alpha = 0.5;
tween(arrowGraphic, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300,
easing: tween.bounceOut
});
self.update = function () {
self.y += self.speed;
// Add dynamic pulsing animation
self.animationPhase += self.pulseSpeed * 0.1;
arrowGraphic.scaleX = 1 + 0.1 * Math.sin(self.animationPhase);
arrowGraphic.scaleY = 1 + 0.1 * Math.sin(self.animationPhase + 1);
// Add rotation wobble
arrowGraphic.rotation = 0.1 * Math.sin(self.animationPhase * 0.7);
// Add glow effect
arrowGraphic.alpha = 0.8 + 0.2 * Math.sin(self.animationPhase * 1.5);
// Add sparkle effect periodically
self.sparkleTimer++;
if (self.sparkleTimer >= 30) {
self.sparkleTimer = 0;
var sparkle = LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8
});
sparkle.x = self.x + (Math.random() - 0.5) * 60;
sparkle.y = self.y + (Math.random() - 0.5) * 60;
sparkle.tint = self.direction === 'left' ? 0xff4757 : self.direction === 'down' ? 0x5352ed : self.direction === 'up' ? 0x2ed573 : 0xffa502;
game.addChild(sparkle);
tween(sparkle, {
scaleX: 0.3,
scaleY: 0.3,
alpha: 0,
y: sparkle.y - 50
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
};
return self;
});
var ComboEffect = Container.expand(function (x, y, comboValue) {
var self = Container.call(this);
// Create combo burst effect
var comboText = new Text2(comboValue + 'x COMBO!', {
size: 80,
fill: 0xFFD700
});
comboText.anchor.set(0.5, 0.5);
comboText.x = 0;
comboText.y = 0;
comboText.scaleX = 0.1;
comboText.scaleY = 0.1;
comboText.alpha = 1;
self.addChild(comboText);
// Create sparkle effects around combo text
for (var i = 0; i < 8; i++) {
var sparkle = self.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8
}));
var angle = i / 8 * Math.PI * 2;
var radius = 80;
sparkle.x = Math.cos(angle) * radius;
sparkle.y = Math.sin(angle) * radius;
sparkle.tint = 0xFFD700;
// Animate sparkles
tween(sparkle, {
scaleX: 0.3,
scaleY: 0.3,
alpha: 0,
x: Math.cos(angle) * (radius + 100),
y: Math.sin(angle) * (radius + 100)
}, {
duration: 1000,
easing: tween.easeOut
});
}
self.x = x;
self.y = y;
// Animate combo text
tween(comboText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(comboText, {
scaleX: 0.8,
scaleY: 0.8,
alpha: 0,
y: -50
}, {
duration: 700,
easing: tween.easeOut
});
}
});
// Destroy after animation
LK.setTimeout(function () {
self.destroy();
}, 1200);
return self;
});
var HitEffect = Container.expand(function (x, y) {
var self = Container.call(this);
var effectGraphic = self.attachAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.8
});
self.x = x;
self.y = y;
// Animate the effect
tween(effectGraphic, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var MissEffect = Container.expand(function (x, y) {
var self = Container.call(this);
// Create multiple miss text elements that animate outward
var missTexts = [];
var directions = [{
x: -1,
y: -1
}, {
x: 1,
y: -1
}, {
x: -1,
y: 1
}, {
x: 1,
y: 1
}, {
x: 0,
y: -1
}, {
x: 0,
y: 1
}, {
x: -1,
y: 0
}, {
x: 1,
y: 0
}];
for (var i = 0; i < 4; i++) {
var missText = new Text2('MISS', {
size: 60 + Math.random() * 40,
fill: 0xFF3333
});
missText.anchor.set(0.5, 0.5);
missText.x = 0;
missText.y = 0;
missText.alpha = 0.9;
self.addChild(missText);
missTexts.push(missText);
}
self.x = x;
self.y = y;
// Animate miss texts flying outward
for (var i = 0; i < missTexts.length; i++) {
var text = missTexts[i];
var dir = directions[i % directions.length];
var distance = 150 + Math.random() * 100;
tween(text, {
x: dir.x * distance,
y: dir.y * distance,
alpha: 0,
rotation: (Math.random() - 0.5) * Math.PI,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800,
easing: tween.easeOut
});
}
// Destroy after animation
LK.setTimeout(function () {
self.destroy();
}, 900);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c2c54
});
/****
* Game Code
****/
// Game constants
var COLUMN_COUNT = 4;
var COLUMN_WIDTH = 2048 / COLUMN_COUNT;
var TARGET_Y = 2400;
var SPAWN_Y = -100;
var HIT_ZONE_HEIGHT = 80;
// Game state
var arrows = [];
var score = 0;
var combo = 0;
var missCount = 0;
var maxMisses = 10;
var gameStarted = false;
var gameState = 'start'; // 'start', 'countdown', 'playing', 'gameover'
var countdownValue = 3;
var countdownTimer = 0;
var arrowSpawnTimer = 0;
var spawnInterval = 45; // frames between arrow spawns
// Health bar system
var healthBar = 50; // Current health (0-100)
var maxHealth = 100;
var healthPerHit = 15; // Health gained per successful hit (increased)
var healthPerMiss = 8; // Health lost per miss (reduced for fairness)
var currentLevelHits = 0; // Current hits in this level (tracking for statistics)
// Level system with progressive speed increases
var level = 1;
var baseSpeed = 8;
var baseSpawnInterval = 45;
var speedMultiplier = 1.0; // Speed multiplier that increases with level
var maxSpeedMultiplier = 3.0; // Maximum speed cap for balance
var scoresPerLevel = [0, 1000, 2500, 5000, 8000, 12000, 17000, 23000, 30000, 40000];
// Direction mapping
var directions = ['left', 'down', 'up', 'right'];
var columnPositions = [];
// Rank system
var ranks = [{
name: "noob",
minScore: 0,
color: 0x888888
}, {
name: "pro",
minScore: 5000,
color: 0x00ff00
}, {
name: "dios",
minScore: 15000,
color: 0xffd700
}, {
name: "hacker",
minScore: 30000,
color: 0xff00ff
}, {
name: "imparable",
minScore: 50000,
color: 0x00ffff
}];
function getRankFromScore(score) {
var currentRank = ranks[0];
for (var i = 0; i < ranks.length; i++) {
if (score >= ranks[i].minScore) {
currentRank = ranks[i];
}
}
return currentRank;
}
function updatePlayerRank(score) {
var newRank = getRankFromScore(score);
var oldRankName = storage.currentRank;
if (newRank.name !== oldRankName) {
storage.currentRank = newRank.name;
showRankUpEffect(newRank);
return true;
}
return false;
}
function showRankUpEffect(rank) {
// Create rank up text
var rankUpTxt = new Text2('RANK UP!', {
size: 100,
fill: rank.color
});
rankUpTxt.anchor.set(0.5, 0.5);
rankUpTxt.x = 0;
rankUpTxt.y = -50;
rankUpTxt.alpha = 0;
rankUpTxt.scaleX = 0.1;
rankUpTxt.scaleY = 0.1;
LK.gui.center.addChild(rankUpTxt);
// Create new rank text
var newRankTxt = new Text2(rank.name.toUpperCase(), {
size: 80,
fill: rank.color
});
newRankTxt.anchor.set(0.5, 0.5);
newRankTxt.x = 0;
newRankTxt.y = 50;
newRankTxt.alpha = 0;
newRankTxt.scaleX = 0.1;
newRankTxt.scaleY = 0.1;
LK.gui.center.addChild(newRankTxt);
// Animate rank up effect
tween(rankUpTxt, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(rankUpTxt, {
alpha: 0,
y: -150
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
rankUpTxt.destroy();
}
});
}
});
// Animate new rank text
LK.setTimeout(function () {
tween(newRankTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(newRankTxt, {
alpha: 0,
y: 150
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
newRankTxt.destroy();
}
});
}
});
}, 400);
// Flash screen with rank color
LK.effects.flashScreen(rank.color, 1000);
// Create celebration particles
for (var i = 0; i < 20; i++) {
LK.setTimeout(function () {
var particle = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2,
alpha: 0.8
}));
particle.x = 1024 + (Math.random() - 0.5) * 600;
particle.y = 1366 + (Math.random() - 0.5) * 400;
particle.tint = rank.color;
var angle = Math.random() * Math.PI * 2;
var distance = 200 + Math.random() * 300;
tween(particle, {
x: particle.x + Math.cos(angle) * distance,
y: particle.y + Math.sin(angle) * distance,
scaleX: 0.05,
scaleY: 0.05,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}, i * 50);
}
}
// Calculate column positions
for (var i = 0; i < COLUMN_COUNT; i++) {
columnPositions.push(COLUMN_WIDTH * i + COLUMN_WIDTH / 2);
}
// Create target zones
var targetZones = [];
for (var i = 0; i < COLUMN_COUNT; i++) {
var targetZone = game.addChild(LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
}));
targetZone.x = columnPositions[i];
targetZone.y = TARGET_Y;
targetZones.push(targetZone);
// Add enhanced pulsing animation to target zones with particle effects
tween(targetZone, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.6
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(targetZone, {
scaleX: 0.9,
scaleY: 0.9,
alpha: 0.2
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
// Add floating particles around target zone
LK.setTimeout(function () {
for (var p = 0; p < 4; p++) {
var particle = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.05,
alpha: 0.8
}));
var angle = p / 4 * Math.PI * 2;
var radius = 80;
particle.x = targetZone.x + Math.cos(angle) * radius;
particle.y = targetZone.y + Math.sin(angle) * radius;
particle.tint = i === 0 ? 0xff4757 : i === 1 ? 0x5352ed : i === 2 ? 0x2ed573 : 0xffa502;
tween(particle, {
scaleX: 0.15,
scaleY: 0.15,
alpha: 0,
x: targetZone.x + Math.cos(angle) * (radius + 60),
y: targetZone.y + Math.sin(angle) * (radius + 60)
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}, Math.random() * 1000);
}
// Create control zones at bottom of screen
var controlZones = [];
// Position control zones at the very bottom for better mobile reach
var controlZoneY = TARGET_Y + 200; // Moved even further down
// Make the control zones smaller to prevent overlapping but still comfortable for mobile
var controlZoneWidth = COLUMN_WIDTH * 0.9;
var controlZoneHeight = 350; // Reduced height to prevent button overlap
for (var i = 0; i < COLUMN_COUNT; i++) {
var controlZone = game.addChild(LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
// Slightly visible for better feedback
alpha: 0.15,
width: controlZoneWidth,
height: controlZoneHeight
}));
controlZone.x = columnPositions[i];
controlZone.y = controlZoneY;
controlZone.columnIndex = i;
// Color coding for visual feedback
controlZone.tint = i === 0 ? 0xff4757 : i === 1 ? 0x5352ed : i === 2 ? 0x2ed573 : 0xffa502;
controlZones.push(controlZone);
}
// Add decorative background elements
var rockets = [];
var confetti = [];
var comets = [];
// Create rocket decorations
for (var i = 0; i < 8; i++) {
var rocket = game.addChild(LK.getAsset('arrow_up', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.8,
alpha: 0.15
}));
rocket.x = Math.random() * 2048;
rocket.y = Math.random() * 2732;
rocket.speed = 1 + Math.random() * 2;
rocket.tint = Math.random() > 0.5 ? 0xFF6B6B : 0x4ECDC4;
rockets.push(rocket);
}
// Create confetti pieces with enhanced colors
for (var i = 0; i < 25; i++) {
var confettiPiece = game.addChild(LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.2
}));
confettiPiece.x = Math.random() * 2048;
confettiPiece.y = Math.random() * 2732;
confettiPiece.speed = 0.3 + Math.random() * 1;
confettiPiece.rotationSpeed = (Math.random() - 0.5) * 0.1;
var colors = [0xFF6B6B, 0xF9CA24, 0xF0932B, 0xEB4D4B, 0x6C5CE7, 0xFF00FF, 0x00FF00];
confettiPiece.tint = colors[Math.floor(Math.random() * colors.length)];
confetti.push(confettiPiece);
}
// Create comet decorations
for (var i = 0; i < 6; i++) {
var comet = game.addChild(LK.getAsset('arrow_right', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.2,
alpha: 0.25
}));
comet.x = Math.random() * 2048;
comet.y = Math.random() * 2732;
comet.speed = 2 + Math.random() * 3;
comet.rotation = Math.random() * Math.PI * 2;
comet.tint = Math.random() > 0.5 ? 0x00FFFF : 0xFFFFFF;
comets.push(comet);
}
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 50,
fill: 0xFFD700
});
comboTxt.anchor.set(0.5, 0);
comboTxt.x = 0;
comboTxt.y = 120;
LK.gui.top.addChild(comboTxt);
var levelTxt = new Text2('Level: 1', {
size: 50,
fill: 0xFF6B6B
});
levelTxt.anchor.set(1, 0);
levelTxt.x = -50;
levelTxt.y = 50;
LK.gui.topRight.addChild(levelTxt);
// Initialize rank text with stored rank
var storedRank = storage.currentRank || "noob";
var initialRankData = null;
for (var r = 0; r < ranks.length; r++) {
if (ranks[r].name === storedRank) {
initialRankData = ranks[r];
break;
}
}
if (!initialRankData) {
initialRankData = ranks[0]; // fallback to noob
}
var rankTxt = new Text2('RANK: ' + initialRankData.name.toUpperCase(), {
size: 45,
fill: initialRankData.color
});
rankTxt.anchor.set(1, 0);
rankTxt.x = -50;
rankTxt.y = 110;
LK.gui.topRight.addChild(rankTxt);
// Health bar UI with improved visuals
var healthBarBg = LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 0.8,
alpha: 0.6
});
healthBarBg.tint = 0x333333;
healthBarBg.x = 0;
healthBarBg.y = 150;
LK.gui.top.addChild(healthBarBg);
var healthBarBorder = LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.2,
scaleY: 1,
alpha: 0.8
});
healthBarBorder.tint = 0xFFFFFF;
healthBarBorder.x = 0;
healthBarBorder.y = 150;
LK.gui.top.addChild(healthBarBorder);
var healthBarFill = LK.getAsset('target_zone', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.6
});
healthBarFill.tint = 0x00FF88;
healthBarFill.x = -280;
healthBarFill.y = 150;
LK.gui.top.addChild(healthBarFill);
var healthTxt = new Text2('FILL TO LEVEL UP', {
size: 45,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0.5, 0.5);
healthTxt.x = 0;
healthTxt.y = 200;
LK.gui.top.addChild(healthTxt);
var accuracyTxt = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
accuracyTxt.anchor.set(0.5, 0.5);
accuracyTxt.x = 0;
accuracyTxt.y = -200;
accuracyTxt.alpha = 0;
LK.gui.center.addChild(accuracyTxt);
// Start screen elements
var startTxt = new Text2('TAP TO START', {
size: 100,
fill: 0xFFFFFF
});
startTxt.anchor.set(0.5, 0.5);
startTxt.x = 0;
startTxt.y = 0;
LK.gui.center.addChild(startTxt);
var titleTxt = new Text2('RHYTHM ARROWS', {
size: 120,
fill: 0x00FFFF
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 0;
titleTxt.y = -300;
LK.gui.center.addChild(titleTxt);
var subtitleTxt = new Text2('Hit the arrows in rhythm!', {
size: 50,
fill: 0xFFD700
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = 0;
subtitleTxt.y = 100;
LK.gui.center.addChild(subtitleTxt);
var countdownTxt = new Text2('3', {
size: 200,
fill: 0xFFD700
});
countdownTxt.anchor.set(0.5, 0.5);
countdownTxt.x = 0;
countdownTxt.y = 0;
countdownTxt.alpha = 0;
LK.gui.center.addChild(countdownTxt);
// Game over screen elements
var gameOverTxt = new Text2('GAME OVER', {
size: 100,
fill: 0xFF0000
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.x = 0;
gameOverTxt.y = -200;
gameOverTxt.alpha = 0;
LK.gui.center.addChild(gameOverTxt);
var finalComboTxt = new Text2('', {
size: 60,
fill: 0xFFD700
});
finalComboTxt.anchor.set(0.5, 0.5);
finalComboTxt.x = 0;
finalComboTxt.y = -100;
finalComboTxt.alpha = 0;
LK.gui.center.addChild(finalComboTxt);
var finalMissTxt = new Text2('', {
size: 60,
fill: 0xFF6B6B
});
finalMissTxt.anchor.set(0.5, 0.5);
finalMissTxt.x = 0;
finalMissTxt.y = -40;
finalMissTxt.alpha = 0;
LK.gui.center.addChild(finalMissTxt);
var restartTxt = new Text2('TAP TO PLAY AGAIN', {
size: 80,
fill: 0x00FFFF
});
restartTxt.anchor.set(0.5, 0.5);
restartTxt.x = 0;
restartTxt.y = 100;
restartTxt.alpha = 0;
LK.gui.center.addChild(restartTxt);
// Loading screen elements
var loadingTxt = new Text2('LOADING...', {
size: 80,
fill: 0x00FFFF
});
loadingTxt.anchor.set(0.5, 0.5);
loadingTxt.x = 0;
loadingTxt.y = 0;
loadingTxt.alpha = 0;
LK.gui.center.addChild(loadingTxt);
var loadingBar = LK.getAsset('target_zone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0.5,
alpha: 0
});
loadingBar.tint = 0x00FFFF;
loadingBar.x = 0;
loadingBar.y = 100;
LK.gui.center.addChild(loadingBar);
// Leaderboard UI elements
var leaderboardTxt = new Text2('LEADERBOARD', {
size: 80,
fill: 0xFFD700
});
leaderboardTxt.anchor.set(0.5, 0.5);
leaderboardTxt.x = 0;
leaderboardTxt.y = -150;
leaderboardTxt.alpha = 0;
LK.gui.center.addChild(leaderboardTxt);
var leaderboardEntries = [];
for (var i = 0; i < 5; i++) {
var entryTxt = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
entryTxt.anchor.set(0.5, 0.5);
entryTxt.x = 0;
entryTxt.y = -50 + i * 60;
entryTxt.alpha = 0;
LK.gui.center.addChild(entryTxt);
leaderboardEntries.push(entryTxt);
}
var newRecordTxt = new Text2('NEW RECORD!', {
size: 90,
fill: 0xFFD700
});
newRecordTxt.anchor.set(0.5, 0.5);
newRecordTxt.x = 0;
newRecordTxt.y = -100;
newRecordTxt.alpha = 0;
LK.gui.center.addChild(newRecordTxt);
// Leaderboard Functions
function addScoreToLeaderboard(playerScore, playerLevel, playerCombo) {
// Initialize leaderboard if it doesn't exist
if (!storage.leaderboard) {
storage.leaderboard = [];
}
// Get current leaderboard scores
var currentLeaderboard = storage.leaderboard;
// Add new score to local array for sorting
var tempLeaderboard = [];
for (var j = 0; j < currentLeaderboard.length; j++) {
tempLeaderboard[j] = currentLeaderboard[j];
}
tempLeaderboard[tempLeaderboard.length] = playerScore;
// Sort by score (highest first)
tempLeaderboard.sort(function (a, b) {
return b - a;
});
// Keep only top 10 scores
if (tempLeaderboard.length > 10) {
tempLeaderboard = tempLeaderboard.slice(0, 10);
}
// Store back to storage with flat structure
storage.leaderboard = [];
for (var k = 0; k < tempLeaderboard.length; k++) {
// Store literal score values directly
storage.leaderboard[k] = tempLeaderboard[k];
}
// Check if this is a new record (top score)
return tempLeaderboard[0] === playerScore;
}
function displayLeaderboard() {
// Show leaderboard title
leaderboardTxt.alpha = 1;
tween(leaderboardTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(leaderboardTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
// Display top 5 scores using simplified storage structure
var maxEntries = Math.min(5, storage.leaderboard.length || 0);
for (var i = 0; i < maxEntries; i++) {
var entryScore = storage.leaderboard[i];
if (entryScore !== undefined) {
var entryText = i + 1 + '. Score: ' + entryScore;
leaderboardEntries[i].setText(entryText);
leaderboardEntries[i].alpha = 0;
// Animate each entry with delay
(function (index, entryElement) {
LK.setTimeout(function () {
tween(entryElement, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(entryElement, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}, index * 200);
})(i, leaderboardEntries[i]);
}
}
// Hide unused entries
for (var i = maxEntries; i < 5; i++) {
leaderboardEntries[i].alpha = 0;
}
}
function hideLeaderboard() {
// Hide all leaderboard elements
tween(leaderboardTxt, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
for (var i = 0; i < leaderboardEntries.length; i++) {
tween(leaderboardEntries[i], {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
tween(newRecordTxt, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
// Functions
function spawnArrow() {
var column = Math.floor(Math.random() * COLUMN_COUNT);
var direction = directions[column];
var arrow = new Arrow(direction, column);
arrow.x = columnPositions[column];
arrow.y = SPAWN_Y;
arrows.push(arrow);
game.addChild(arrow);
// Add enhanced entrance trail effect based on speed level
var trailCount = Math.min(5, 3 + Math.floor(speedMultiplier));
for (var t = 0; t < trailCount; t++) {
var trail = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + speedMultiplier * 0.1,
scaleY: 0.2 + speedMultiplier * 0.1,
alpha: 0.6 + speedMultiplier * 0.2
}));
trail.x = arrow.x + (Math.random() - 0.5) * (40 + speedMultiplier * 10);
trail.y = arrow.y - t * (30 + speedMultiplier * 5);
trail.tint = direction === 'left' ? 0xff4757 : direction === 'down' ? 0x5352ed : direction === 'up' ? 0x2ed573 : 0xffa502;
// Add intensity glow for higher speeds
if (speedMultiplier > 1.5) {
trail.tint = 0xFFFFFF; // White hot trail for high speeds
}
var trailDuration = Math.max(400, 600 - speedMultiplier * 50);
tween(trail, {
scaleX: 0.05,
scaleY: 0.05,
alpha: 0,
y: trail.y + (100 + speedMultiplier * 20)
}, {
duration: trailDuration,
easing: tween.easeOut,
onFinish: function onFinish() {
trail.destroy();
}
});
}
// Add entrance burst effect
var burst = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
}));
burst.x = arrow.x;
burst.y = arrow.y;
burst.tint = 0xFFFFFF;
tween(burst, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
burst.destroy();
}
});
}
function checkHit(arrow) {
var distance = Math.abs(arrow.y - TARGET_Y);
if (distance <= HIT_ZONE_HEIGHT * 0.8) {
// Perfect hit - more generous perfect zone
return 'perfect';
} else if (distance <= HIT_ZONE_HEIGHT * 3) {
// Good hit - much more generous good zone
return 'good';
}
return null;
}
function processHit(arrow, accuracy) {
var points = 0;
var comboMultiplier = Math.floor(combo / 10) + 1;
if (accuracy === 'perfect') {
points = 100 * comboMultiplier;
var perfectSound = LK.getSound('hit_perfect');
perfectSound.volume = storage.masterVolume * storage.sfxVolume;
perfectSound.play();
showAccuracyText('PERFECT!', 0x00ff00);
// Extra effect for perfect hits
LK.effects.flashScreen(0x00ff00, 100);
} else if (accuracy === 'good') {
points = 50 * comboMultiplier;
var goodSound = LK.getSound('hit_good');
goodSound.volume = storage.masterVolume * storage.sfxVolume;
goodSound.play();
showAccuracyText('GOOD', 0xffff00);
}
score += points;
combo++;
// Check for rank up
updatePlayerRank(score);
// Increase health bar
healthBar = Math.min(maxHealth, healthBar + healthPerHit);
currentLevelHits++;
// Check if health bar is full to advance to next level
if (healthBar >= maxHealth) {
level++;
currentLevelHits = 0;
// Reset health bar to starting level for next challenge
healthBar = 50;
// Increase speed multiplier progressively with each level
speedMultiplier = Math.min(1.0 + (level - 1) * 0.15, maxSpeedMultiplier);
// Slightly reduce spawn interval for more challenge but keep it balanced
spawnInterval = Math.max(25, baseSpawnInterval - Math.floor((level - 1) * 1.2));
// Show enhanced level up effect with speed notification
showAccuracyText('LEVEL ' + level + '! HEALTH FULL!', 0x00ffff);
LK.effects.flashScreen(0x00ffff, 700);
// Add speed burst visual effect
tween(game, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(game, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
// Create multiple hit effects for high combos
var effectCount = Math.min(3, Math.floor(combo / 25) + 1);
for (var i = 0; i < effectCount; i++) {
LK.setTimeout(function () {
var effect = new HitEffect(arrow.x + (Math.random() - 0.5) * 50, arrow.y + (Math.random() - 0.5) * 50);
game.addChild(effect);
}, i * 50);
}
// Enhanced combo system with multiple milestone effects
if (combo % 5 === 0 && combo > 0) {
// Create spectacular combo effect
var comboEffect = new ComboEffect(arrow.x, arrow.y - 100, combo);
game.addChild(comboEffect);
// Different effects based on combo milestones
if (combo >= 100) {
// LEGENDARY combo (100+)
LK.effects.flashScreen(0xFFD700, 800);
tween(comboTxt, {
scaleX: 3,
scaleY: 3,
tint: 0xFFD700,
rotation: 0.5
}, {
duration: 500,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFD700,
rotation: 0
}, {
duration: 600,
easing: tween.easeOut
});
}
});
} else if (combo >= 50) {
// EPIC combo (50+)
LK.effects.flashScreen(0xFF6B6B, 500);
tween(comboTxt, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFF6B6B,
rotation: 0.3
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700,
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
});
} else if (combo >= 25) {
// SUPER combo (25+)
LK.effects.flashScreen(0x4ECDC4, 300);
tween(comboTxt, {
scaleX: 2.2,
scaleY: 2.2,
tint: 0x4ECDC4
}, {
duration: 350,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFD700
}, {
duration: 450,
easing: tween.easeOut
});
}
});
} else {
// Regular combo milestone (5, 10, 15, 20)
tween(comboTxt, {
scaleX: 2,
scaleY: 2,
tint: 0x00FFFF
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1,
tint: 0xFFD700
}, {
duration: 400,
easing: tween.easeOut
});
}
});
}
// Create confetti burst for high combos
if (combo >= 25) {
var confettiCount = Math.min(30, combo / 2);
for (var c = 0; c < confettiCount; c++) {
LK.setTimeout(function () {
var burstConfetti = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.15,
alpha: 0.9
}));
burstConfetti.x = arrow.x + (Math.random() - 0.5) * 300;
burstConfetti.y = arrow.y + (Math.random() - 0.5) * 300;
var colors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0xF9CA24, 0xF0932B, 0xFFD700, 0x00FFFF];
burstConfetti.tint = colors[Math.floor(Math.random() * colors.length)];
tween(burstConfetti, {
y: burstConfetti.y - 400,
x: burstConfetti.x + (Math.random() - 0.5) * 200,
alpha: 0,
rotation: Math.random() * Math.PI * 4,
scaleX: 0.02,
scaleY: 0.02
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
burstConfetti.destroy();
}
});
}, c * 20);
}
}
// Create firework effect for mega combos
if (combo >= 75) {
for (var f = 0; f < 5; f++) {
var firework = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
}));
firework.x = arrow.x + (Math.random() - 0.5) * 400;
firework.y = arrow.y + (Math.random() - 0.5) * 200;
firework.tint = 0xFFFFFF;
tween(firework, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
firework.destroy();
}
});
}
}
}
// Remove arrow
arrow.destroy();
var arrowIndex = arrows.indexOf(arrow);
if (arrowIndex > -1) {
arrows.splice(arrowIndex, 1);
}
updateUI();
}
function processMiss() {
combo = 0;
missCount++;
var missSound = LK.getSound('miss');
missSound.volume = storage.masterVolume * storage.sfxVolume;
missSound.play();
showAccuracyText('MISS', 0xff0000);
// Create miss effect animation instead of screen flash
var missEffect = new MissEffect(1024, 1366);
game.addChild(missEffect);
// Shake the screen slightly for miss feedback
tween(game, {
x: 10
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(game, {
x: -10
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(game, {
x: 0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
// Decrease health bar
healthBar = Math.max(0, healthBar - healthPerMiss);
// Check if health bar reached 0
if (healthBar <= 0) {
showGameOverScreen();
}
updateUI();
}
function showAccuracyText(text, color) {
accuracyTxt.setText(text);
accuracyTxt.fill = color;
accuracyTxt.alpha = 1;
accuracyTxt.scaleX = 0.2;
accuracyTxt.scaleY = 0.2;
accuracyTxt.rotation = 0;
// Create spectacular effects based on accuracy type
if (text === 'PERFECT!') {
// Create burst of sparkles for perfect hits
for (var s = 0; s < 12; s++) {
var sparkle = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
}));
sparkle.x = 1024;
sparkle.y = 1366;
sparkle.tint = s % 2 === 0 ? 0x00FFFF : 0xFFD700;
var angle = s / 12 * Math.PI * 2;
var distance = 200 + Math.random() * 100;
tween(sparkle, {
x: 1024 + Math.cos(angle) * distance,
y: 1366 + Math.sin(angle) * distance,
scaleX: 0.5,
scaleY: 0.5,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
// Enhanced perfect text animation
tween(accuracyTxt, {
scaleX: 2.5,
scaleY: 2.5,
rotation: 0.5
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(accuracyTxt, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
}
});
} else if (text === 'GOOD') {
// Create ring effect for good hits
for (var r = 0; r < 8; r++) {
var ring = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2,
alpha: 0.8
}));
ring.x = 1024;
ring.y = 1366;
ring.tint = 0xFFFF00;
var ringAngle = r / 8 * Math.PI * 2;
var ringDistance = 120;
tween(ring, {
x: 1024 + Math.cos(ringAngle) * ringDistance,
y: 1366 + Math.sin(ringAngle) * ringDistance,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
ring.destroy();
}
});
}
// Enhanced good text animation
tween(accuracyTxt, {
scaleX: 2.0,
scaleY: 2.0,
rotation: 0.2
}, {
duration: 250,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(accuracyTxt, {
scaleX: 1.2,
scaleY: 1.2,
rotation: 0,
alpha: 0
}, {
duration: 700,
easing: tween.easeOut
});
}
});
} else {
// Default animation for MISS
tween(accuracyTxt, {
scaleX: 1.5,
scaleY: 1.5,
rotation: text === 'PERFECT!' ? 0.3 : 0.1
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(accuracyTxt, {
scaleX: 1,
scaleY: 1,
rotation: 0,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut
});
}
});
}
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: ' + combo);
levelTxt.setText('Level: ' + level);
// Update rank display using stored rank
var storedRank = storage.currentRank || "noob";
var currentRankData = null;
for (var r = 0; r < ranks.length; r++) {
if (ranks[r].name === storedRank) {
currentRankData = ranks[r];
break;
}
}
if (!currentRankData) {
currentRankData = ranks[0]; // fallback to noob
}
rankTxt.setText('RANK: ' + currentRankData.name.toUpperCase());
rankTxt.fill = currentRankData.color;
// Update health bar with smooth animation
var healthPercent = healthBar / maxHealth;
var targetScaleX = 2 * healthPercent;
// Animate health bar changes smoothly
tween(healthBarFill, {
scaleX: targetScaleX
}, {
duration: 300,
easing: tween.easeOut
});
// Change color based on health level with smooth transitions
var targetColor;
if (healthPercent > 0.7) {
targetColor = 0x00FF88; // Bright green
} else if (healthPercent > 0.5) {
targetColor = 0x88FF00; // Yellow-green
} else if (healthPercent > 0.3) {
targetColor = 0xFFAA00; // Orange
} else {
targetColor = 0xFF3333; // Bright red
}
// Animate color change
tween(healthBarFill, {
tint: targetColor
}, {
duration: 200,
easing: tween.easeOut
});
// Pulse effect when health is critical
if (healthPercent <= 0.2) {
tween(healthBarFill, {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(healthBarFill, {
alpha: 1
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
}
function startCountdown() {
gameState = 'countdown';
startTxt.alpha = 0;
// Hide leaderboard if visible
hideLeaderboard();
// Fade out title elements
tween(titleTxt, {
alpha: 0,
y: -400
}, {
duration: 800,
easing: tween.easeOut
});
tween(subtitleTxt, {
alpha: 0,
y: 200
}, {
duration: 800,
easing: tween.easeOut
});
countdownTxt.alpha = 1;
countdownValue = 3;
countdownTimer = 0;
}
function showCountdownNumber() {
if (countdownValue > 0) {
countdownTxt.setText(countdownValue.toString());
countdownTxt.fill = countdownValue === 3 ? 0xFF0000 : countdownValue === 2 ? 0xFFA500 : 0x00FF00;
} else {
countdownTxt.setText('GO!');
countdownTxt.fill = 0x00FFFF;
}
countdownTxt.scaleX = 3;
countdownTxt.scaleY = 3;
countdownTxt.rotation = 0.5;
countdownTxt.alpha = 1;
// Animate scale down with bounce effect
tween(countdownTxt, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 800,
easing: tween.bounceOut
});
// Animate alpha fade out after scale animation
LK.setTimeout(function () {
tween(countdownTxt, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
}, 600);
}
function restartGame() {
// Show loading screen first
gameState = 'loading';
loadingTxt.alpha = 1;
loadingBar.alpha = 1;
loadingBar.scaleX = 0;
// Animate loading bar
tween(loadingBar, {
scaleX: 3
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// After loading, reset game
// Reset all game variables
score = 0;
combo = 0;
missCount = 0;
level = 1;
healthBar = 50;
currentLevelHits = 0;
arrowSpawnTimer = 0;
spawnInterval = 45;
speedMultiplier = 1.0; // Reset speed multiplier to base level
gameState = 'start';
gameStarted = false;
// Reset rank to noob
storage.currentRank = "noob";
// Clear all arrows
for (var i = arrows.length - 1; i >= 0; i--) {
arrows[i].destroy();
}
arrows = [];
// Stop music
LK.stopMusic();
// Reset UI visibility - show title again
startTxt.alpha = 1;
titleTxt.alpha = 1; // Show title again
titleTxt.y = -300;
titleTxt.rotation = 0;
subtitleTxt.alpha = 1;
subtitleTxt.y = 100;
countdownTxt.alpha = 0;
// Properly hide all game over elements
gameOverTxt.alpha = 0;
gameOverTxt.scaleX = 1;
gameOverTxt.scaleY = 1;
finalComboTxt.alpha = 0;
finalComboTxt.y = -100;
finalMissTxt.alpha = 0;
finalMissTxt.y = -40;
restartTxt.alpha = 0;
accuracyTxt.alpha = 0;
// Stop any active tweens on game over elements
tween.stop(gameOverTxt);
tween.stop(finalComboTxt);
tween.stop(finalMissTxt);
tween.stop(restartTxt);
// Hide loading screen
loadingTxt.alpha = 0;
loadingBar.alpha = 0;
// Hide leaderboard
hideLeaderboard();
// Update UI
updateUI();
}
});
}
function showGameOverScreen() {
gameState = 'gameover';
// Add score to leaderboard and check for new record
var isNewRecord = addScoreToLeaderboard(score, level, combo);
// Flash screen with dramatic effect
LK.effects.flashScreen(0x8B0000, 1000);
// Show new record notification if applicable
if (isNewRecord) {
newRecordTxt.alpha = 0;
newRecordTxt.scaleX = 0.1;
newRecordTxt.scaleY = 0.1;
tween(newRecordTxt, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add sparkle effect for new record
for (var s = 0; s < 15; s++) {
var sparkle = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 1
}));
sparkle.x = 1024 + (Math.random() - 0.5) * 400;
sparkle.y = 1366 - 300 + (Math.random() - 0.5) * 100;
sparkle.tint = 0xFFD700;
var angle = Math.random() * Math.PI * 2;
tween(sparkle, {
x: sparkle.x + Math.cos(angle) * 200,
y: sparkle.y + Math.sin(angle) * 200,
scaleX: 0.4,
scaleY: 0.4,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
sparkle.destroy();
}
});
}
}
});
LK.effects.flashScreen(0xFFD700, 1500);
}
// Show game over elements with staggered animations
gameOverTxt.alpha = 0;
gameOverTxt.scaleX = 0.1;
gameOverTxt.scaleY = 0.1;
tween(gameOverTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.bounceOut
});
// Animate final stats with delay
LK.setTimeout(function () {
finalComboTxt.setText('Level Reached: ' + level);
finalComboTxt.alpha = 0;
finalComboTxt.y = -50;
tween(finalComboTxt, {
alpha: 1,
y: -100
}, {
duration: 600,
easing: tween.easeOut
});
}, 400);
LK.setTimeout(function () {
finalMissTxt.setText('Misses: ' + missCount);
finalMissTxt.alpha = 0;
finalMissTxt.y = 10;
tween(finalMissTxt, {
alpha: 1,
y: -40
}, {
duration: 600,
easing: tween.easeOut
});
}, 800);
// Show leaderboard after stats
LK.setTimeout(function () {
displayLeaderboard();
}, 1400);
// Remove restart text animation - keep it hidden
restartTxt.alpha = 0;
}
function handleColumnTap(columnIndex) {
// Find the closest arrow in the specified column
var closestArrow = null;
var closestDistance = Infinity;
var closestArrowIndex = -1;
for (var i = 0; i < arrows.length; i++) {
var arrow = arrows[i];
if (!arrow.hitTested && arrow.column === columnIndex) {
var distance = Math.abs(arrow.y - TARGET_Y);
if (distance < closestDistance) {
closestDistance = distance;
closestArrow = arrow;
closestArrowIndex = i;
}
}
}
if (closestArrow) {
// Check if arrow is close enough to the target zone to register a hit
// Use a larger detection range (150 pixels) to detect arrows approaching the target
if (closestDistance <= 150) {
var accuracy = checkHit(closestArrow);
if (accuracy) {
// Remove arrow from array and destroy it
closestArrow.destroy();
arrows.splice(closestArrowIndex, 1);
// Process the hit without calling processHit (which also destroys the arrow)
var points = 0;
var comboMultiplier = Math.floor(combo / 10) + 1;
if (accuracy === 'perfect') {
points = 100 * comboMultiplier;
var perfectSound = LK.getSound('hit_perfect');
perfectSound.volume = storage.masterVolume * storage.sfxVolume;
perfectSound.play();
showAccuracyText('PERFECT!', 0x00ff00);
// Extra effect for perfect hits
LK.effects.flashScreen(0x00ff00, 100);
} else if (accuracy === 'good') {
points = 50 * comboMultiplier;
var goodSound = LK.getSound('hit_good');
goodSound.volume = storage.masterVolume * storage.sfxVolume;
goodSound.play();
showAccuracyText('GOOD', 0xffff00);
}
score += points;
combo++;
// Check for rank up
updatePlayerRank(score);
// Increase health bar
healthBar = Math.min(maxHealth, healthBar + healthPerHit);
currentLevelHits++;
// Check if health bar is full to advance to next level
if (healthBar >= maxHealth) {
level++;
currentLevelHits = 0;
// Reset health bar to starting level for next challenge
healthBar = 50;
// Increase speed multiplier progressively with each level
speedMultiplier = Math.min(1.0 + (level - 1) * 0.15, maxSpeedMultiplier);
// Slightly reduce spawn interval for more challenge but keep it balanced
spawnInterval = Math.max(25, baseSpawnInterval - Math.floor((level - 1) * 1.2));
// Show enhanced level up effect with speed notification
showAccuracyText('LEVEL ' + level + '! HEALTH FULL!', 0x00ffff);
LK.effects.flashScreen(0x00ffff, 700);
// Add speed burst visual effect
tween(game, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(game, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
// Create multiple hit effects for high combos
var effectCount = Math.min(3, Math.floor(combo / 25) + 1);
for (var i = 0; i < effectCount; i++) {
LK.setTimeout(function () {
var effect = new HitEffect(closestArrow.x + (Math.random() - 0.5) * 50, closestArrow.y + (Math.random() - 0.5) * 50);
game.addChild(effect);
}, i * 50);
}
// Enhanced combo animations with milestone effects
if (combo % 5 === 0 && combo > 0) {
// Create combo effect at hit location
var comboEffect = new ComboEffect(closestArrow.x, closestArrow.y - 100, combo);
game.addChild(comboEffect);
// Scale combo text animation based on milestone
var targetScale = combo >= 50 ? 2.5 : combo >= 25 ? 2.0 : 1.8;
var targetColor = combo >= 100 ? 0xFFD700 : combo >= 50 ? 0xFF6B6B : combo >= 25 ? 0x4ECDC4 : 0x00FFFF;
tween(comboTxt, {
scaleX: targetScale,
scaleY: targetScale,
tint: targetColor
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: combo >= 25 ? 1.2 : 1,
scaleY: combo >= 25 ? 1.2 : 1,
tint: 0xFFD700
}, {
duration: 500,
easing: tween.easeOut
});
}
});
}
updateUI();
} else {
processMiss();
}
} else {
// Arrow exists but is too far from target zone - count as miss
processMiss();
}
} else {
// Tapped when no arrow was in range for this column
processMiss();
}
}
// Input handling
game.down = function (x, y, obj) {
// Start countdown when screen is tapped
if (gameState === 'start') {
startCountdown();
return; // Prevent other actions when start countdown begins
}
if (gameState === 'gameover') {
restartGame();
} else if (gameState === 'playing') {
// Determine which column was tapped based on x position
var tappedColumn = -1;
for (var i = 0; i < COLUMN_COUNT; i++) {
var columnLeft = columnPositions[i] - COLUMN_WIDTH / 2;
var columnRight = columnPositions[i] + COLUMN_WIDTH / 2;
if (x >= columnLeft && x <= columnRight) {
tappedColumn = i;
break;
}
}
if (tappedColumn >= 0) {
// Enhanced visual feedback for control zone tap
var controlZone = controlZones[tappedColumn];
var originalAlpha = controlZone.alpha;
var originalScale = controlZone.scaleX;
// Flash and scale effect
controlZone.alpha = 0.8;
controlZone.scaleX = originalScale * 1.1;
controlZone.scaleY = controlZone.scaleY * 1.1;
tween(controlZone, {
alpha: originalAlpha,
scaleX: originalScale,
scaleY: originalScale
}, {
duration: 150,
easing: tween.easeOut
});
// Add ripple effect
var effect = new HitEffect(controlZone.x, controlZone.y - 50);
game.addChild(effect);
handleColumnTap(tappedColumn);
} else {
processMiss();
}
}
};
// Main game loop
game.update = function () {
// Enhanced rocket animations with trails and speed variation
for (var i = 0; i < rockets.length; i++) {
var rocket = rockets[i];
rocket.y -= rocket.speed + Math.sin(LK.ticks * 0.05 + i) * 0.5;
rocket.rotation += 0.02 + Math.sin(LK.ticks * 0.03 + i) * 0.01;
// Enhanced wobble with varying amplitude
rocket.x += Math.sin(LK.ticks * 0.02 + i) * (1 + Math.cos(LK.ticks * 0.01 + i));
// Scale pulsing effect
rocket.scaleX = 0.3 + 0.05 * Math.sin(LK.ticks * 0.08 + i);
rocket.scaleY = 0.8 + 0.1 * Math.sin(LK.ticks * 0.06 + i);
// Color shifting
var colorPhase = LK.ticks * 0.03 + i;
if (i % 2 === 0) {
rocket.alpha = 0.15 + 0.1 * Math.sin(colorPhase);
}
if (rocket.y < -100) {
rocket.y = 2732 + 100;
rocket.x = Math.random() * 2048;
rocket.speed = 1 + Math.random() * 3; // Randomize speed on reset
}
}
// Enhanced confetti with spiral motion and color cycling
for (var i = 0; i < confetti.length; i++) {
var piece = confetti[i];
piece.y -= piece.speed;
piece.rotation += piece.rotationSpeed + Math.sin(LK.ticks * 0.02 + i) * 0.02;
// Enhanced spiral motion
var spiralRadius = 20 + 10 * Math.sin(LK.ticks * 0.015 + i);
piece.x += Math.sin(LK.ticks * 0.01 + i) * 0.5 + Math.cos(LK.ticks * 0.02 + i) * spiralRadius * 0.02;
// Scale animation
piece.scaleX = 0.1 + 0.05 * Math.sin(LK.ticks * 0.05 + i);
piece.scaleY = 0.1 + 0.05 * Math.cos(LK.ticks * 0.04 + i);
// Alpha pulsing
piece.alpha = 0.2 + 0.15 * Math.sin(LK.ticks * 0.06 + i);
if (piece.y < -50) {
piece.y = 2732 + 50;
piece.x = Math.random() * 2048;
}
}
// Enhanced comets with dynamic trails and speed bursts
for (var i = 0; i < comets.length; i++) {
var comet = comets[i];
// Enhanced movement with speed bursts
var speedMultiplier = 1 + 0.5 * Math.sin(LK.ticks * 0.02 + i);
comet.x += Math.cos(comet.rotation) * comet.speed * speedMultiplier;
comet.y += Math.sin(comet.rotation) * comet.speed * speedMultiplier;
// Enhanced trail effect with varying opacity and scale
comet.alpha = 0.15 + 0.15 * Math.sin(LK.ticks * 0.1 + i);
comet.scaleX = 0.6 + 0.2 * Math.sin(LK.ticks * 0.08 + i);
comet.scaleY = 0.2 + 0.1 * Math.cos(LK.ticks * 0.06 + i);
// Slight rotation wobble
comet.rotation += Math.sin(LK.ticks * 0.03 + i) * 0.01;
// Reset position when off screen
if (comet.x < -100 || comet.x > 2148 || comet.y < -100 || comet.y > 2832) {
comet.x = Math.random() * 2048;
comet.y = Math.random() * 2732;
comet.rotation = Math.random() * Math.PI * 2;
comet.speed = 2 + Math.random() * 4; // Randomize speed on reset
}
}
if (gameState === 'loading') {
// Animate loading text
loadingTxt.alpha = 0.7 + 0.3 * Math.sin(LK.ticks * 0.15);
return;
}
if (gameState === 'start') {
// Show leaderboard on start screen if it has entries
if (storage.leaderboard && storage.leaderboard.length > 0 && LK.ticks % 300 === 0) {
displayLeaderboard();
}
// Update rank display on start screen
updateUI();
// Animate start text with rainbow effect and enhanced pulsing
startTxt.alpha = 0.7 + 0.3 * Math.sin(LK.ticks * 0.15);
startTxt.scaleX = 1 + 0.1 * Math.sin(LK.ticks * 0.12);
startTxt.scaleY = 1 + 0.1 * Math.sin(LK.ticks * 0.12);
var colorPhase = LK.ticks * 0.08;
var r = Math.sin(colorPhase) * 127 + 128;
var g = Math.sin(colorPhase + 2) * 127 + 128;
var b = Math.sin(colorPhase + 4) * 127 + 128;
startTxt.fill = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
// Enhanced title animation with floating and rotation
titleTxt.y = -300 + 15 * Math.sin(LK.ticks * 0.08);
titleTxt.rotation = 0.15 * Math.sin(LK.ticks * 0.06);
titleTxt.scaleX = 1 + 0.05 * Math.sin(LK.ticks * 0.1);
titleTxt.scaleY = 1 + 0.05 * Math.sin(LK.ticks * 0.1);
// Enhanced subtitle animation with color shifting
subtitleTxt.alpha = 0.6 + 0.4 * Math.sin(LK.ticks * 0.12);
subtitleTxt.y = 100 + 5 * Math.sin(LK.ticks * 0.1);
var subColorPhase = LK.ticks * 0.06;
var subR = Math.sin(subColorPhase + 1) * 127 + 128;
var subG = Math.sin(subColorPhase + 3) * 127 + 128;
var subB = Math.sin(subColorPhase + 5) * 127 + 128;
subtitleTxt.fill = Math.floor(subR) << 16 | Math.floor(subG) << 8 | Math.floor(subB);
return;
}
if (gameState === 'countdown') {
countdownTimer++;
if (countdownTimer === 1) {
showCountdownNumber();
} else if (countdownTimer >= 60) {
countdownValue--;
if (countdownValue > 0) {
countdownTimer = 0;
showCountdownNumber();
} else {
// Start the game
gameState = 'playing';
gameStarted = true;
countdownTxt.alpha = 0;
LK.playMusic('background_music');
}
}
return;
}
if (gameState === 'gameover') {
// Keep restart text hidden and add animated background effects
restartTxt.alpha = 0;
// Add swirling particles effect during game over
for (var p = 0; p < 3; p++) {
if (Math.random() < 0.1) {
var particle = game.addChild(LK.getAsset('hit_effect', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.3
}));
particle.x = Math.random() * 2048;
particle.y = 2732 + 50;
particle.tint = Math.random() > 0.5 ? 0xFF6B6B : 0x4ECDC4;
tween(particle, {
y: -50,
rotation: Math.PI * 4,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
return;
}
// Game playing state
// Spawn arrows
arrowSpawnTimer++;
if (arrowSpawnTimer >= spawnInterval) {
spawnArrow();
arrowSpawnTimer = 0;
}
// Update arrows and check for misses
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Check if arrow passed the target zone without being hit
if (!arrow.hitTested && arrow.y > TARGET_Y + HIT_ZONE_HEIGHT) {
arrow.hitTested = true;
processMiss();
}
// Remove arrows that are off screen
if (arrow.y > 2732 + 100) {
arrow.destroy();
arrows.splice(i, 1);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -595,11 +595,23 @@
levelTxt.anchor.set(1, 0);
levelTxt.x = -50;
levelTxt.y = 50;
LK.gui.topRight.addChild(levelTxt);
-var rankTxt = new Text2('RANK: NOOB', {
+// Initialize rank text with stored rank
+var storedRank = storage.currentRank || "noob";
+var initialRankData = null;
+for (var r = 0; r < ranks.length; r++) {
+ if (ranks[r].name === storedRank) {
+ initialRankData = ranks[r];
+ break;
+ }
+}
+if (!initialRankData) {
+ initialRankData = ranks[0]; // fallback to noob
+}
+var rankTxt = new Text2('RANK: ' + initialRankData.name.toUpperCase(), {
size: 45,
- fill: 0x888888
+ fill: initialRankData.color
});
rankTxt.anchor.set(1, 0);
rankTxt.x = -50;
rankTxt.y = 110;
@@ -1362,10 +1374,20 @@
function updateUI() {
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: ' + combo);
levelTxt.setText('Level: ' + level);
- // Update rank display
- var currentRankData = getRankFromScore(score);
+ // Update rank display using stored rank
+ var storedRank = storage.currentRank || "noob";
+ var currentRankData = null;
+ for (var r = 0; r < ranks.length; r++) {
+ if (ranks[r].name === storedRank) {
+ currentRankData = ranks[r];
+ break;
+ }
+ }
+ if (!currentRankData) {
+ currentRankData = ranks[0]; // fallback to noob
+ }
rankTxt.setText('RANK: ' + currentRankData.name.toUpperCase());
rankTxt.fill = currentRankData.color;
// Update health bar with smooth animation
var healthPercent = healthBar / maxHealth;
@@ -1877,8 +1899,10 @@
// Show leaderboard on start screen if it has entries
if (storage.leaderboard && storage.leaderboard.length > 0 && LK.ticks % 300 === 0) {
displayLeaderboard();
}
+ // Update rank display on start screen
+ updateUI();
// Animate start text with rainbow effect and enhanced pulsing
startTxt.alpha = 0.7 + 0.3 * Math.sin(LK.ticks * 0.15);
startTxt.scaleX = 1 + 0.1 * Math.sin(LK.ticks * 0.12);
startTxt.scaleY = 1 + 0.1 * Math.sin(LK.ticks * 0.12);