User prompt
Bütün tuşların "sadece" yüksekliğini arttır
User prompt
Bu tuşları 4e çıkart. Normal tuşlar olcak ama 4 tane olucak. Bende hepsini farklı tasarlayabilicem
User prompt
Oyunu biraz daha hizlandir. Ve ilerledikçe daha da hizlansin. (Erkenden olmasın bu yavaş yavaş ama kararlı bı sekilde hizlansin) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Uzun notalari kaldır
User prompt
Uzun notaların colliderini düzelt. Basmama rağmen "early" hatası veriyor
User prompt
Bir notaya erken bastığımız zaman o nota yok olsun. Tekrar basmamiza gerek kalmasın. Uzun notalarda da aynı şekilde. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Uzun basmamız gereken notayı çizgiye degdikten sonra başlat tetiğini. Ve bundan sonra her early için eksi puan yiyelim. Not al notalari biraz daha uzat. Ve sıralar arasına görünür bı çizgi çek ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Early ve missed yazısı ekranın tam ortasında büyük olsun. Uzun basmamız gereken notaya bı kere basmamız yeterli olsun. Uzun basmak sadece ekstra puan versin. Zamanında basabildigimiz her tuş icin de "Nice" yazısı yazsın ekranın ortasında diğerlerinin büyüklüğünde. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tuşlara bastigimi belirgin et. Çizgiye gelmeden bastiklarima "early" uyarısı, çizgiden sonra bastiklarima "Missed" uyarısı yazsın. Ve kaçırma sayım olmasın. Tek hakkım olsun. Tuşları büyüt. Tek tiklamali olan Normal olsun uzun basmanız gerek de biraz daha uzun olsun. Tuşa basma animasyonu da ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Piano Tiles Rush
Initial prompt
Bana piano tiles gibi bi oyun yap. 4 sıra olsun. Tuşlar olsun. Basılı tutmalı tuşlar olsun. Her bir tuşun animasyonu olsun.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
currentLevel: 1,
totalGamesPlayed: 0,
achievements: {},
unlockedLevels: 1
});
/****
* Classes
****/
var Particle = Container.expand(function (x, y, color) {
var self = Container.call(this);
var graphics = self.attachAsset('feedbackPerfect', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = color || 0xFFD700;
graphics.width = 20;
graphics.height = 20;
self.x = x;
self.y = y;
self.vx = (Math.random() - 0.5) * 10;
self.vy = (Math.random() - 0.5) * 10 - 5;
self.life = 60;
self.maxLife = 60;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += 0.2; // gravity
self.life--;
self.alpha = self.life / self.maxLife;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var PowerTile = Container.expand(function (laneIndex, powerType) {
var self = Container.call(this);
var graphics = self.attachAsset('quickTile' + laneIndex, {
anchorX: 0.5,
anchorY: 0.5
});
// Tint based on power type
if (powerType === 'double') {
graphics.tint = 0xFFD700; // Gold for double score
} else if (powerType === 'slow') {
graphics.tint = 0x00FFFF; // Cyan for slow time
} else if (powerType === 'shield') {
graphics.tint = 0x00FF00; // Green for shield
}
self.speed = 12;
self.lane = laneIndex || 0;
self.powerType = powerType;
self.hit = false;
self.missed = false;
self.earlyPressed = false;
self.destroyed = false;
// Add pulsing effect
self.pulseTimer = 0;
self.update = function () {
if (self.destroyed) return;
self.y += self.speed;
// Pulsing effect
self.pulseTimer++;
graphics.scaleX = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1;
graphics.scaleY = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1;
// Check if tile is past hit line and not hit
if (self.y > hitLineY + 80 && !self.hit && !self.missed) {
self.missed = true;
comboCount = 0;
comboMultiplier = 1;
perfectStreak = 0;
showFeedback('MISSED', self.lane);
LK.getSound('miss').play();
LK.showGameOver();
}
};
return self;
});
var QuickTile = Container.expand(function (laneIndex) {
var self = Container.call(this);
var assetName = 'quickTile' + laneIndex;
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.lane = laneIndex || 0;
self.hit = false;
self.missed = false;
self.earlyPressed = false;
self.destroyed = false;
self.update = function () {
if (self.destroyed) return;
self.y += self.speed;
// Check if tile is past hit line and not hit
if (self.y > hitLineY + 80 && !self.hit && !self.missed) {
self.missed = true;
comboCount = 0; // Reset combo on miss
comboMultiplier = 1; // Reset multiplier
perfectStreak = 0; // Reset perfect streak
showFeedback('MISSED', self.lane);
LK.getSound('miss').play();
LK.showGameOver();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var lanes = [];
var hitLineY = 2200;
var tiles = [];
var activeLanes = [false, false, false, false];
var comboCount = 0;
var tileSpawnTimer = 0;
var feedbackTexts = [];
var tileSpawnInterval = 45;
var gameSpeed = 1;
var earlyCount = 0;
var keyPressCount = 0;
var particles = [];
var comboMultiplier = 1;
var perfectStreak = 0;
var lastHitTime = 0;
var currentLevel = storage.currentLevel || 1;
var powerTiles = [];
var activePowerUps = {
doubleScore: 0,
slowTime: 0,
shield: 0
};
// Experience and progression system
var playerExp = storage.playerExp || 0;
var playerLevel = storage.playerLevel || 1;
var skillPoints = storage.skillPoints || 0;
var unlockedSkills = storage.unlockedSkills || {};
// Skill tree definitions with meaningful effects
var skills = {
speedBoost: {
name: "Speed Boost",
desc: "Tiles move 10% slower",
cost: 2,
maxLevel: 3,
effect: function effect(level) {
return 0.1 * level;
}
},
scoreMultiplier: {
name: "Score Master",
desc: "Base score +25% per level",
cost: 3,
maxLevel: 4,
effect: function effect(level) {
return 0.25 * level;
}
},
comboExtender: {
name: "Combo Keeper",
desc: "Combo decays 50% slower per level",
cost: 2,
maxLevel: 2,
effect: function effect(level) {
return 0.5 * level;
}
},
perfectWindow: {
name: "Perfect Timing",
desc: "Perfect hit window +10 pixels per level",
cost: 4,
maxLevel: 2,
effect: function effect(level) {
return 10 * level;
}
},
powerUpDuration: {
name: "Power Mastery",
desc: "Power-ups last 50% longer per level",
cost: 3,
maxLevel: 3,
effect: function effect(level) {
return 0.5 * level;
}
}
};
// Level rewards system
var levelRewards = {
2: {
skillPoints: 1,
message: "Skill Point Earned!"
},
3: {
skillPoints: 1,
coins: 50,
message: "Skill Point + 50 Coins!"
},
5: {
skillPoints: 2,
coins: 100,
message: "2 Skill Points + 100 Coins!"
},
7: {
skillPoints: 1,
coins: 75,
message: "Skill Point + 75 Coins!"
},
10: {
skillPoints: 3,
coins: 200,
message: "3 Skill Points + 200 Coins!"
}
};
// Currency system
var coins = storage.coins || 0;
var dailyBonusCollected = storage.dailyBonusCollected || 0;
// Achievement definitions with meaningful rewards
var achievements = {
firstWin: {
name: "First Steps",
desc: "Complete your first game",
unlocked: false,
reward: {
coins: 25,
skillPoints: 1
}
},
perfectionist: {
name: "Perfectionist",
desc: "Get 50 perfect hits in a row",
unlocked: false,
reward: {
coins: 150,
skillPoints: 2
}
},
speedDemon: {
name: "Speed Demon",
desc: "Reach level 5",
unlocked: false,
reward: {
coins: 100,
skillPoints: 1
}
},
comboMaster: {
name: "Combo Master",
desc: "Achieve a 100+ combo",
unlocked: false,
reward: {
coins: 200,
skillPoints: 2
}
},
highScorer: {
name: "High Scorer",
desc: "Score 10,000 points",
unlocked: false,
reward: {
coins: 300,
skillPoints: 3
}
},
coinCollector: {
name: "Coin Collector",
desc: "Collect 500 coins total",
unlocked: false,
reward: {
coins: 100,
skillPoints: 1
}
},
marathoner: {
name: "Marathoner",
desc: "Play 25 games",
unlocked: false,
reward: {
coins: 150,
skillPoints: 2
}
}
};
// Load saved achievements
for (var key in achievements) {
if (storage.achievements && storage.achievements[key]) {
achievements[key].unlocked = true;
}
}
// Load saved skills
if (storage.unlockedSkills) {
for (var skillKey in storage.unlockedSkills) {
unlockedSkills[skillKey] = storage.unlockedSkills[skillKey];
}
}
// Create lanes
for (var i = 0; i < 4; i++) {
var lane = game.addChild(LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5
}));
lane.x = 256 + i * 512;
lane.y = 1366;
lanes.push(lane);
}
// Create hit line
var hitLine = game.addChild(LK.getAsset('hitLine', {
anchorX: 0.5,
anchorY: 0.5
}));
hitLine.x = 1024;
hitLine.y = hitLineY;
// Create lane dividers
for (var i = 1; i < 4; i++) {
var divider = game.addChild(LK.getAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
}));
divider.x = i * 512;
divider.y = 1366;
}
// Create UI
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var comboText = new Text2('Combo: 0', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
var earlyText = new Text2('Early: 0/3', {
size: 60,
fill: 0xFF4444
});
earlyText.anchor.set(0.5, 0);
earlyText.y = 160;
LK.gui.top.addChild(earlyText);
var streakText = new Text2('Streak: 0', {
size: 50,
fill: 0x00FFFF
});
streakText.anchor.set(0.5, 0);
streakText.y = 220;
LK.gui.top.addChild(streakText);
var multiplierText = new Text2('x1', {
size: 80,
fill: 0xFFD700
});
multiplierText.anchor.set(1, 0);
multiplierText.x = -20;
multiplierText.y = 20;
LK.gui.topRight.addChild(multiplierText);
var levelText = new Text2('Level: ' + currentLevel, {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 20;
levelText.y = 20;
LK.gui.topLeft.addChild(levelText);
var highScoreText = new Text2('Best: ' + storage.highScore, {
size: 40,
fill: 0xFFD700
});
highScoreText.anchor.set(0, 0);
highScoreText.x = 20;
highScoreText.y = 80;
LK.gui.topLeft.addChild(highScoreText);
// Add progression UI elements
var expText = new Text2('EXP: ' + playerExp, {
size: 35,
fill: 0x00FFFF
});
expText.anchor.set(0, 0);
expText.x = 20;
expText.y = 120;
LK.gui.topLeft.addChild(expText);
var playerLevelText = new Text2('Player Lv: ' + playerLevel, {
size: 35,
fill: 0xFFD700
});
playerLevelText.anchor.set(0, 0);
playerLevelText.x = 20;
playerLevelText.y = 160;
LK.gui.topLeft.addChild(playerLevelText);
var coinsText = new Text2('Coins: ' + coins, {
size: 40,
fill: 0xFFD700
});
coinsText.anchor.set(1, 0);
coinsText.x = -20;
coinsText.y = 80;
LK.gui.topRight.addChild(coinsText);
var skillPointsText = new Text2('SP: ' + skillPoints, {
size: 35,
fill: 0xFF00FF
});
skillPointsText.anchor.set(1, 0);
skillPointsText.x = -20;
skillPointsText.y = 120;
LK.gui.topRight.addChild(skillPointsText);
// Update all UI on start
updateScoreDisplay();
function updateScoreDisplay() {
scoreText.setText('Score: ' + LK.getScore());
comboText.setText('Combo: ' + comboCount);
earlyText.setText('Early: ' + earlyCount + '/3');
streakText.setText('Streak: ' + perfectStreak);
multiplierText.setText('x' + comboMultiplier);
levelText.setText('Level: ' + currentLevel);
highScoreText.setText('Best: ' + storage.highScore);
expText.setText('EXP: ' + playerExp);
playerLevelText.setText('Player Lv: ' + playerLevel);
coinsText.setText('Coins: ' + coins);
skillPointsText.setText('SP: ' + skillPoints);
// Update multiplier color based on value
if (comboMultiplier >= 4) {
multiplierText.fill = 0xFF0000; // Red for 4x+
} else if (comboMultiplier >= 3) {
multiplierText.fill = 0xFF8800; // Orange for 3x
} else if (comboMultiplier >= 2) {
multiplierText.fill = 0xFFD700; // Gold for 2x
} else {
multiplierText.fill = 0xFFFFFF; // White for 1x
}
// Check achievements
checkAchievements();
}
function showFeedback(text, laneIndex) {
var assetName = 'feedback' + text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
var feedbackImage = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
}));
feedbackImage.x = 1024; // Center of screen
feedbackImage.y = 1366; // Center of screen vertically
feedbackImage.alpha = 1;
feedbackTexts.push(feedbackImage);
// Add score display based on feedback type
var scoreDisplay;
if (text === 'NICE') {
scoreDisplay = game.addChild(LK.getAsset('positiveScoreDisplay', {
anchorX: 0.5,
anchorY: 0.5
}));
} else {
scoreDisplay = game.addChild(LK.getAsset('negativeScoreDisplay', {
anchorX: 0.5,
anchorY: 0.5
}));
}
scoreDisplay.x = 1024; // Center of screen
scoreDisplay.y = 1450; // Below feedback
scoreDisplay.alpha = 1;
feedbackTexts.push(scoreDisplay);
// Create score text overlay
var scoreChangeText = new Text2('', {
size: 60,
fill: text === 'NICE' ? 0x00FF00 : 0xFF0000
});
scoreChangeText.anchor.set(0.5, 0.5);
scoreChangeText.x = scoreDisplay.x;
scoreChangeText.y = scoreDisplay.y;
if (text === 'NICE') {
scoreChangeText.setText('+10');
} else if (text === 'EARLY') {
scoreChangeText.setText('-30');
} else if (text === 'MISSED') {
scoreChangeText.setText('0');
}
game.addChild(scoreChangeText);
feedbackTexts.push(scoreChangeText);
tween(feedbackImage, {
alpha: 0,
y: feedbackImage.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
feedbackImage.destroy();
var index = feedbackTexts.indexOf(feedbackImage);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
tween(scoreDisplay, {
alpha: 0,
y: scoreDisplay.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
scoreDisplay.destroy();
var index = feedbackTexts.indexOf(scoreDisplay);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
tween(scoreChangeText, {
alpha: 0,
y: scoreChangeText.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
scoreChangeText.destroy();
var index = feedbackTexts.indexOf(scoreChangeText);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
}
function spawnTile() {
// 5% chance to spawn power tile (increases with level)
var powerChance = 0.05 + currentLevel * 0.01;
if (Math.random() < powerChance) {
spawnPowerTile();
return;
}
// Adjusted spawn chances based on level
var multiTileChance = 0.3 + currentLevel * 0.05; // More multi-tiles at higher levels
var spawnTwo = Math.random() < multiTileChance;
if (spawnTwo) {
// Spawn two tiles in different lanes
var laneIndex1 = Math.floor(Math.random() * 4);
var laneIndex2;
// Make sure second lane is different from first
do {
laneIndex2 = Math.floor(Math.random() * 4);
} while (laneIndex2 === laneIndex1);
// Create first tile
var tile1 = new QuickTile(laneIndex1);
tile1.x = 256 + laneIndex1 * 512;
tile1.y = -100;
tiles.push(tile1);
game.addChild(tile1);
// Create second tile
var tile2 = new QuickTile(laneIndex2);
tile2.x = 256 + laneIndex2 * 512;
tile2.y = -100;
tiles.push(tile2);
game.addChild(tile2);
} else {
// Spawn single tile
var laneIndex = Math.floor(Math.random() * 4);
var tile = new QuickTile(laneIndex);
tile.x = 256 + laneIndex * 512;
tile.y = -100;
tiles.push(tile);
game.addChild(tile);
}
}
function createParticles(x, y, count, color) {
for (var i = 0; i < count; i++) {
var particle = new Particle(x, y, color);
particles.push(particle);
game.addChild(particle);
}
}
function checkAchievements() {
var currentScore = LK.getScore();
// High Scorer achievement
if (currentScore >= 10000 && !achievements.highScorer.unlocked) {
unlockAchievement('highScorer');
}
// Perfectionist achievement
if (perfectStreak >= 50 && !achievements.perfectionist.unlocked) {
unlockAchievement('perfectionist');
}
// Combo Master achievement
if (comboCount >= 100 && !achievements.comboMaster.unlocked) {
unlockAchievement('comboMaster');
}
// Speed Demon achievement
if (currentLevel >= 5 && !achievements.speedDemon.unlocked) {
unlockAchievement('speedDemon');
}
// Coin Collector achievement
if (coins >= 500 && !achievements.coinCollector.unlocked) {
unlockAchievement('coinCollector');
}
// Marathoner achievement
if (storage.totalGamesPlayed >= 25 && !achievements.marathoner.unlocked) {
unlockAchievement('marathoner');
}
// Update high score
if (currentScore > storage.highScore) {
storage.highScore = currentScore;
}
}
function awardExperience(amount) {
var oldLevel = playerLevel;
playerExp += amount;
storage.playerExp = playerExp;
// Level up calculation (exponential growth)
var expNeeded = playerLevel * 100 + Math.pow(playerLevel, 2) * 50;
if (playerExp >= expNeeded) {
playerLevel++;
storage.playerLevel = playerLevel;
playerExp = 0;
storage.playerExp = 0;
// Award skill points and coins for level up
var skillPointsAwarded = Math.floor(playerLevel / 3) + 1;
var coinsAwarded = playerLevel * 25;
skillPoints += skillPointsAwarded;
coins += coinsAwarded;
storage.skillPoints = skillPoints;
storage.coins = coins;
// Check for level rewards
if (levelRewards[playerLevel]) {
var reward = levelRewards[playerLevel];
if (reward.skillPoints) {
skillPoints += reward.skillPoints;
storage.skillPoints = skillPoints;
}
if (reward.coins) {
coins += reward.coins;
storage.coins = coins;
}
showLevelUpNotification(playerLevel, reward.message);
} else {
showLevelUpNotification(playerLevel, skillPointsAwarded + ' SP + ' + coinsAwarded + ' Coins!');
}
}
updateScoreDisplay();
}
function showLevelUpNotification(level, rewardText) {
var levelUpText = new Text2('PLAYER LEVEL UP!\nLevel ' + level + '\n' + rewardText, {
size: 60,
fill: 0xFF00FF
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 1024;
levelUpText.y = 900;
game.addChild(levelUpText);
LK.effects.flashScreen(0xFF00FF, 1000);
tween(levelUpText, {
alpha: 0,
y: levelUpText.y - 150
}, {
duration: 3000,
onFinish: function onFinish() {
levelUpText.destroy();
}
});
}
function getSkillLevel(skillName) {
return unlockedSkills[skillName] || 0;
}
function applySkillEffects() {
// Apply skill effects to game mechanics
var speedBoostLevel = getSkillLevel('speedBoost');
var scoreMultLevel = getSkillLevel('scoreMultiplier');
var comboExtLevel = getSkillLevel('comboExtender');
var perfectWindowLevel = getSkillLevel('perfectWindow');
var powerDurationLevel = getSkillLevel('powerUpDuration');
return {
speedReduction: speedBoostLevel > 0 ? skills.speedBoost.effect(speedBoostLevel) : 0,
scoreBonus: scoreMultLevel > 0 ? skills.scoreMultiplier.effect(scoreMultLevel) : 0,
comboDecayReduction: comboExtLevel > 0 ? skills.comboExtender.effect(comboExtLevel) : 0,
perfectWindowBonus: perfectWindowLevel > 0 ? skills.perfectWindow.effect(perfectWindowLevel) : 0,
powerUpBonus: powerDurationLevel > 0 ? skills.powerUpDuration.effect(powerDurationLevel) : 0
};
}
function checkDailyBonus() {
var today = Math.floor(Date.now() / 86400000); // Days since epoch
if (dailyBonusCollected < today) {
// Award daily bonus
var dailyCoins = 50 + playerLevel * 10;
coins += dailyCoins;
storage.coins = coins;
dailyBonusCollected = today;
storage.dailyBonusCollected = today;
showPowerUpNotification('Daily Bonus: ' + dailyCoins + ' Coins!', 0xFFD700);
updateScoreDisplay();
}
}
function unlockAchievement(achievementKey) {
achievements[achievementKey].unlocked = true;
if (!storage.achievements) storage.achievements = {};
storage.achievements[achievementKey] = true;
// Award achievement rewards
var achievement = achievements[achievementKey];
if (achievement.reward) {
if (achievement.reward.coins) {
coins += achievement.reward.coins;
storage.coins = coins;
}
if (achievement.reward.skillPoints) {
skillPoints += achievement.reward.skillPoints;
storage.skillPoints = skillPoints;
}
}
// Show achievement notification
showAchievementNotification(achievement);
LK.effects.flashScreen(0xFFD700, 500);
updateScoreDisplay();
}
function showAchievementNotification(achievement) {
var rewardText = '';
if (achievement.reward) {
var rewards = [];
if (achievement.reward.coins) rewards.push(achievement.reward.coins + ' Coins');
if (achievement.reward.skillPoints) rewards.push(achievement.reward.skillPoints + ' SP');
if (rewards.length > 0) rewardText = '\nReward: ' + rewards.join(' + ');
}
var achievementText = new Text2('Achievement Unlocked!\n' + achievement.name + rewardText, {
size: 60,
fill: 0xFFD700
});
achievementText.anchor.set(0.5, 0.5);
achievementText.x = 1024;
achievementText.y = 800;
game.addChild(achievementText);
tween(achievementText, {
alpha: 0,
y: achievementText.y - 100
}, {
duration: 3000,
onFinish: function onFinish() {
achievementText.destroy();
}
});
}
function spawnPowerTile() {
var powerTypes = ['double', 'slow', 'shield'];
var powerType = powerTypes[Math.floor(Math.random() * powerTypes.length)];
var laneIndex = Math.floor(Math.random() * 4);
var powerTile = new PowerTile(laneIndex, powerType);
powerTile.x = 256 + laneIndex * 512;
powerTile.y = -100;
powerTiles.push(powerTile);
game.addChild(powerTile);
}
function activatePowerUp(powerType) {
var skillEffects = applySkillEffects();
var baseDuration = 600; // 10 seconds at 60fps
var enhancedDuration = Math.floor(baseDuration * (1 + skillEffects.powerUpBonus));
if (powerType === 'double') {
activePowerUps.doubleScore = enhancedDuration;
showPowerUpNotification('Double Score!', 0xFFD700);
} else if (powerType === 'slow') {
activePowerUps.slowTime = enhancedDuration;
showPowerUpNotification('Slow Time!', 0x00FFFF);
} else if (powerType === 'shield') {
activePowerUps.shield = enhancedDuration;
showPowerUpNotification('Shield Active!', 0x00FF00);
}
}
function showPowerUpNotification(text, color) {
var powerText = new Text2(text, {
size: 80,
fill: color
});
powerText.anchor.set(0.5, 0.5);
powerText.x = 1024;
powerText.y = 1000;
game.addChild(powerText);
tween(powerText, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5,
y: powerText.y - 100
}, {
duration: 2000,
onFinish: function onFinish() {
powerText.destroy();
}
});
}
function getLaneFromX(x) {
if (x < 512) return 0;
if (x < 1024) return 1;
if (x < 1536) return 2;
return 3;
}
function activateLane(laneIndex) {
if (laneIndex >= 0 && laneIndex < 4) {
activeLanes[laneIndex] = true;
lanes[laneIndex].removeChild(lanes[laneIndex].children[0]);
var activeLane = LK.getAsset('laneActive', {
anchorX: 0.5,
anchorY: 0.5
});
lanes[laneIndex].addChild(activeLane);
}
}
function deactivateLane(laneIndex) {
if (laneIndex >= 0 && laneIndex < 4) {
activeLanes[laneIndex] = false;
lanes[laneIndex].removeChild(lanes[laneIndex].children[0]);
var normalLane = LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5
});
lanes[laneIndex].addChild(normalLane);
}
}
game.down = function (x, y, obj) {
var laneIndex = getLaneFromX(x);
activateLane(laneIndex);
// Increment key press counter
keyPressCount++;
// Increase game speed by 2% every 5 key presses
if (keyPressCount % 5 === 0) {
gameSpeed *= 1.02;
}
// Add lane press animation
tween(lanes[laneIndex], {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
easing: tween.easeOut
});
// Check for tile hits
var hitTile = false;
// Check power tiles first
for (var i = 0; i < powerTiles.length; i++) {
var powerTile = powerTiles[i];
if (powerTile.lane === laneIndex && !powerTile.missed && !powerTile.earlyPressed) {
var distance = Math.abs(powerTile.y - hitLineY);
if (distance <= 80 && !powerTile.hit) {
powerTile.hit = true;
activatePowerUp(powerTile.powerType);
createParticles(powerTile.x, powerTile.y, 12, 0xFFD700);
tween(powerTile, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
if (!powerTile.destroyed) {
powerTile.destroyed = true;
powerTile.destroy();
}
}
});
hitTile = true;
break;
}
}
}
// Check regular tiles
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.lane === laneIndex && !tile.missed && !tile.earlyPressed) {
var distance = Math.abs(tile.y - hitLineY);
if (distance <= 80) {
// Handle QuickTile
if (!tile.hit) {
tile.hit = true;
// Calculate combo multiplier
comboMultiplier = Math.min(4, Math.floor(comboCount / 5) + 1);
var baseScore = 10;
// Apply power-up bonuses
if (activePowerUps.doubleScore > 0) {
baseScore *= 2;
}
var scoreToAdd = baseScore * comboMultiplier;
// Apply skill effects
var skillEffects = applySkillEffects();
var perfectWindow = 20 + skillEffects.perfectWindowBonus;
// Check for perfect timing (with skill enhancement)
var perfectTiming = distance <= perfectWindow;
if (perfectTiming) {
scoreToAdd *= 1.5; // 1.5x bonus for perfect timing
perfectStreak++;
createParticles(tile.x, tile.y, 8, 0xFFD700);
// Screen flash for perfect streak milestones
if (perfectStreak % 10 === 0) {
LK.effects.flashScreen(0xFFD700, 200);
}
} else {
perfectStreak = 0;
createParticles(tile.x, tile.y, 5, 0x00FF00);
}
// Apply score multiplier skill bonus
scoreToAdd *= 1 + skillEffects.scoreBonus;
// Award experience and coins
var expGained = perfectTiming ? 3 : 2;
var coinsGained = perfectTiming ? 2 : 1;
awardExperience(expGained);
coins += coinsGained;
storage.coins = coins;
LK.setScore(LK.getScore() + Math.floor(scoreToAdd));
comboCount++;
lastHitTime = LK.ticks;
// Decrement early count on nice hit (minimum 0)
if (earlyCount > 0) {
earlyCount--;
}
showFeedback('NICE', laneIndex);
// Use random Piano1-Piano5 sounds for each tile hit
var pianoSounds = ['Piano1', 'Piano2', 'Piano3', 'Piano4', 'Piano5'];
var randomSound = pianoSounds[Math.floor(Math.random() * pianoSounds.length)];
LK.getSound(randomSound).play();
// Visual effect
tween(tile, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
if (!tile.destroyed) {
tile.destroyed = true;
tile.destroy();
}
}
});
updateScoreDisplay();
hitTile = true;
break;
}
} else if (tile.y < hitLineY - 80) {
// Early press
tile.earlyPressed = true;
comboCount = 0; // Reset combo on early press
comboMultiplier = 1; // Reset multiplier
perfectStreak = 0; // Reset perfect streak
earlyCount++; // Increment early count
showFeedback('EARLY', laneIndex);
LK.getSound('early').play();
LK.setScore(LK.getScore() - 30); // Deduct 30 points for early press
// Check if 3 earlies reached
if (earlyCount >= 3) {
LK.showGameOver();
}
// Destroy tile immediately on early press
tween(tile, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
if (!tile.destroyed) {
tile.destroyed = true;
tile.destroy();
}
}
});
updateScoreDisplay();
hitTile = true;
break;
}
}
}
};
game.up = function (x, y, obj) {
var laneIndex = getLaneFromX(x);
deactivateLane(laneIndex);
// Add lane release animation
tween(lanes[laneIndex], {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
};
// Start background music
LK.playMusic('Music');
game.update = function () {
// Update power-ups
for (var powerType in activePowerUps) {
if (activePowerUps[powerType] > 0) {
activePowerUps[powerType]--;
}
}
// Apply slow time effect
var currentGameSpeed = gameSpeed;
if (activePowerUps.slowTime > 0) {
currentGameSpeed *= 0.5;
}
// Spawn tiles
tileSpawnTimer++;
var adjustedSpawnInterval = tileSpawnInterval;
if (activePowerUps.slowTime > 0) {
adjustedSpawnInterval *= 2;
}
if (tileSpawnTimer >= adjustedSpawnInterval) {
spawnTile();
tileSpawnTimer = 0;
// Level progression system
var targetScore = currentLevel * 1000;
if (LK.getScore() >= targetScore) {
currentLevel++;
storage.currentLevel = currentLevel;
if (currentLevel > storage.unlockedLevels) {
storage.unlockedLevels = currentLevel;
}
showPowerUpNotification('Level Up! Level ' + currentLevel, 0xFF00FF);
LK.effects.flashScreen(0xFF00FF, 800);
}
// Increase difficulty over time
if (LK.ticks % 300 === 0) {
gameSpeed += 0.15;
tileSpawnInterval = Math.max(25, tileSpawnInterval - 1);
}
}
// Clean up tiles
for (var i = tiles.length - 1; i >= 0; i--) {
var tile = tiles[i];
if (!tile || tile.destroyed) {
tiles.splice(i, 1);
continue;
}
if (tile.y > 2800 || tile.hit || tile.missed && tile.y > hitLineY + 200 || tile.earlyPressed && tile.y > 2800) {
tile.destroyed = true;
tile.destroy();
tiles.splice(i, 1);
}
}
// Clean up power tiles
for (var i = powerTiles.length - 1; i >= 0; i--) {
var powerTile = powerTiles[i];
if (!powerTile || powerTile.destroyed) {
powerTiles.splice(i, 1);
continue;
}
if (powerTile.y > 2800 || powerTile.hit || powerTile.missed && powerTile.y > hitLineY + 200) {
powerTile.destroyed = true;
powerTile.destroy();
powerTiles.splice(i, 1);
}
}
// Apply skill effects
var skillEffects = applySkillEffects();
// Update tile speeds based on game speed and skills
var effectiveSpeed = gameSpeed * (1 - skillEffects.speedReduction);
if (activePowerUps.slowTime > 0) {
effectiveSpeed *= 0.5;
}
for (var i = 0; i < tiles.length; i++) {
if (tiles[i] && !tiles[i].destroyed) {
tiles[i].speed = 12 * effectiveSpeed;
}
}
// Update power tile speeds
for (var i = 0; i < powerTiles.length; i++) {
if (powerTiles[i] && !powerTiles[i].destroyed) {
powerTiles[i].speed = 12 * effectiveSpeed;
}
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (!particle || particle.life <= 0) {
if (particle) particle.destroy();
particles.splice(i, 1);
}
}
// Combo decay system with skill enhancement
var skillEffects = applySkillEffects();
var decayTime = Math.floor(180 * (1 + skillEffects.comboDecayReduction));
if (LK.ticks - lastHitTime > decayTime && comboCount > 0) {
comboCount = Math.max(0, comboCount - 1);
comboMultiplier = Math.min(4, Math.floor(comboCount / 5) + 1);
updateScoreDisplay();
lastHitTime = LK.ticks; // Reset timer to prevent rapid decay
}
// Check daily bonus (once per game)
if (LK.ticks === 60) {
checkDailyBonus();
}
};
// Override game over to save progress and unlock achievements
var originalShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
// Save game stats
storage.totalGamesPlayed++;
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
// Unlock first win achievement if it's the first game
if (storage.totalGamesPlayed === 1 && !achievements.firstWin.unlocked) {
unlockAchievement('firstWin');
}
// Call original game over
originalShowGameOver();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
currentLevel: 1,
totalGamesPlayed: 0,
achievements: {},
unlockedLevels: 1
});
/****
* Classes
****/
var Particle = Container.expand(function (x, y, color) {
var self = Container.call(this);
var graphics = self.attachAsset('feedbackPerfect', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = color || 0xFFD700;
graphics.width = 20;
graphics.height = 20;
self.x = x;
self.y = y;
self.vx = (Math.random() - 0.5) * 10;
self.vy = (Math.random() - 0.5) * 10 - 5;
self.life = 60;
self.maxLife = 60;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += 0.2; // gravity
self.life--;
self.alpha = self.life / self.maxLife;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var PowerTile = Container.expand(function (laneIndex, powerType) {
var self = Container.call(this);
var graphics = self.attachAsset('quickTile' + laneIndex, {
anchorX: 0.5,
anchorY: 0.5
});
// Tint based on power type
if (powerType === 'double') {
graphics.tint = 0xFFD700; // Gold for double score
} else if (powerType === 'slow') {
graphics.tint = 0x00FFFF; // Cyan for slow time
} else if (powerType === 'shield') {
graphics.tint = 0x00FF00; // Green for shield
}
self.speed = 12;
self.lane = laneIndex || 0;
self.powerType = powerType;
self.hit = false;
self.missed = false;
self.earlyPressed = false;
self.destroyed = false;
// Add pulsing effect
self.pulseTimer = 0;
self.update = function () {
if (self.destroyed) return;
self.y += self.speed;
// Pulsing effect
self.pulseTimer++;
graphics.scaleX = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1;
graphics.scaleY = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1;
// Check if tile is past hit line and not hit
if (self.y > hitLineY + 80 && !self.hit && !self.missed) {
self.missed = true;
comboCount = 0;
comboMultiplier = 1;
perfectStreak = 0;
showFeedback('MISSED', self.lane);
LK.getSound('miss').play();
LK.showGameOver();
}
};
return self;
});
var QuickTile = Container.expand(function (laneIndex) {
var self = Container.call(this);
var assetName = 'quickTile' + laneIndex;
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.lane = laneIndex || 0;
self.hit = false;
self.missed = false;
self.earlyPressed = false;
self.destroyed = false;
self.update = function () {
if (self.destroyed) return;
self.y += self.speed;
// Check if tile is past hit line and not hit
if (self.y > hitLineY + 80 && !self.hit && !self.missed) {
self.missed = true;
comboCount = 0; // Reset combo on miss
comboMultiplier = 1; // Reset multiplier
perfectStreak = 0; // Reset perfect streak
showFeedback('MISSED', self.lane);
LK.getSound('miss').play();
LK.showGameOver();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var lanes = [];
var hitLineY = 2200;
var tiles = [];
var activeLanes = [false, false, false, false];
var comboCount = 0;
var tileSpawnTimer = 0;
var feedbackTexts = [];
var tileSpawnInterval = 45;
var gameSpeed = 1;
var earlyCount = 0;
var keyPressCount = 0;
var particles = [];
var comboMultiplier = 1;
var perfectStreak = 0;
var lastHitTime = 0;
var currentLevel = storage.currentLevel || 1;
var powerTiles = [];
var activePowerUps = {
doubleScore: 0,
slowTime: 0,
shield: 0
};
// Experience and progression system
var playerExp = storage.playerExp || 0;
var playerLevel = storage.playerLevel || 1;
var skillPoints = storage.skillPoints || 0;
var unlockedSkills = storage.unlockedSkills || {};
// Skill tree definitions with meaningful effects
var skills = {
speedBoost: {
name: "Speed Boost",
desc: "Tiles move 10% slower",
cost: 2,
maxLevel: 3,
effect: function effect(level) {
return 0.1 * level;
}
},
scoreMultiplier: {
name: "Score Master",
desc: "Base score +25% per level",
cost: 3,
maxLevel: 4,
effect: function effect(level) {
return 0.25 * level;
}
},
comboExtender: {
name: "Combo Keeper",
desc: "Combo decays 50% slower per level",
cost: 2,
maxLevel: 2,
effect: function effect(level) {
return 0.5 * level;
}
},
perfectWindow: {
name: "Perfect Timing",
desc: "Perfect hit window +10 pixels per level",
cost: 4,
maxLevel: 2,
effect: function effect(level) {
return 10 * level;
}
},
powerUpDuration: {
name: "Power Mastery",
desc: "Power-ups last 50% longer per level",
cost: 3,
maxLevel: 3,
effect: function effect(level) {
return 0.5 * level;
}
}
};
// Level rewards system
var levelRewards = {
2: {
skillPoints: 1,
message: "Skill Point Earned!"
},
3: {
skillPoints: 1,
coins: 50,
message: "Skill Point + 50 Coins!"
},
5: {
skillPoints: 2,
coins: 100,
message: "2 Skill Points + 100 Coins!"
},
7: {
skillPoints: 1,
coins: 75,
message: "Skill Point + 75 Coins!"
},
10: {
skillPoints: 3,
coins: 200,
message: "3 Skill Points + 200 Coins!"
}
};
// Currency system
var coins = storage.coins || 0;
var dailyBonusCollected = storage.dailyBonusCollected || 0;
// Achievement definitions with meaningful rewards
var achievements = {
firstWin: {
name: "First Steps",
desc: "Complete your first game",
unlocked: false,
reward: {
coins: 25,
skillPoints: 1
}
},
perfectionist: {
name: "Perfectionist",
desc: "Get 50 perfect hits in a row",
unlocked: false,
reward: {
coins: 150,
skillPoints: 2
}
},
speedDemon: {
name: "Speed Demon",
desc: "Reach level 5",
unlocked: false,
reward: {
coins: 100,
skillPoints: 1
}
},
comboMaster: {
name: "Combo Master",
desc: "Achieve a 100+ combo",
unlocked: false,
reward: {
coins: 200,
skillPoints: 2
}
},
highScorer: {
name: "High Scorer",
desc: "Score 10,000 points",
unlocked: false,
reward: {
coins: 300,
skillPoints: 3
}
},
coinCollector: {
name: "Coin Collector",
desc: "Collect 500 coins total",
unlocked: false,
reward: {
coins: 100,
skillPoints: 1
}
},
marathoner: {
name: "Marathoner",
desc: "Play 25 games",
unlocked: false,
reward: {
coins: 150,
skillPoints: 2
}
}
};
// Load saved achievements
for (var key in achievements) {
if (storage.achievements && storage.achievements[key]) {
achievements[key].unlocked = true;
}
}
// Load saved skills
if (storage.unlockedSkills) {
for (var skillKey in storage.unlockedSkills) {
unlockedSkills[skillKey] = storage.unlockedSkills[skillKey];
}
}
// Create lanes
for (var i = 0; i < 4; i++) {
var lane = game.addChild(LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5
}));
lane.x = 256 + i * 512;
lane.y = 1366;
lanes.push(lane);
}
// Create hit line
var hitLine = game.addChild(LK.getAsset('hitLine', {
anchorX: 0.5,
anchorY: 0.5
}));
hitLine.x = 1024;
hitLine.y = hitLineY;
// Create lane dividers
for (var i = 1; i < 4; i++) {
var divider = game.addChild(LK.getAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
}));
divider.x = i * 512;
divider.y = 1366;
}
// Create UI
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var comboText = new Text2('Combo: 0', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
comboText.y = 100;
LK.gui.top.addChild(comboText);
var earlyText = new Text2('Early: 0/3', {
size: 60,
fill: 0xFF4444
});
earlyText.anchor.set(0.5, 0);
earlyText.y = 160;
LK.gui.top.addChild(earlyText);
var streakText = new Text2('Streak: 0', {
size: 50,
fill: 0x00FFFF
});
streakText.anchor.set(0.5, 0);
streakText.y = 220;
LK.gui.top.addChild(streakText);
var multiplierText = new Text2('x1', {
size: 80,
fill: 0xFFD700
});
multiplierText.anchor.set(1, 0);
multiplierText.x = -20;
multiplierText.y = 20;
LK.gui.topRight.addChild(multiplierText);
var levelText = new Text2('Level: ' + currentLevel, {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 20;
levelText.y = 20;
LK.gui.topLeft.addChild(levelText);
var highScoreText = new Text2('Best: ' + storage.highScore, {
size: 40,
fill: 0xFFD700
});
highScoreText.anchor.set(0, 0);
highScoreText.x = 20;
highScoreText.y = 80;
LK.gui.topLeft.addChild(highScoreText);
// Add progression UI elements
var expText = new Text2('EXP: ' + playerExp, {
size: 35,
fill: 0x00FFFF
});
expText.anchor.set(0, 0);
expText.x = 20;
expText.y = 120;
LK.gui.topLeft.addChild(expText);
var playerLevelText = new Text2('Player Lv: ' + playerLevel, {
size: 35,
fill: 0xFFD700
});
playerLevelText.anchor.set(0, 0);
playerLevelText.x = 20;
playerLevelText.y = 160;
LK.gui.topLeft.addChild(playerLevelText);
var coinsText = new Text2('Coins: ' + coins, {
size: 40,
fill: 0xFFD700
});
coinsText.anchor.set(1, 0);
coinsText.x = -20;
coinsText.y = 80;
LK.gui.topRight.addChild(coinsText);
var skillPointsText = new Text2('SP: ' + skillPoints, {
size: 35,
fill: 0xFF00FF
});
skillPointsText.anchor.set(1, 0);
skillPointsText.x = -20;
skillPointsText.y = 120;
LK.gui.topRight.addChild(skillPointsText);
// Update all UI on start
updateScoreDisplay();
function updateScoreDisplay() {
scoreText.setText('Score: ' + LK.getScore());
comboText.setText('Combo: ' + comboCount);
earlyText.setText('Early: ' + earlyCount + '/3');
streakText.setText('Streak: ' + perfectStreak);
multiplierText.setText('x' + comboMultiplier);
levelText.setText('Level: ' + currentLevel);
highScoreText.setText('Best: ' + storage.highScore);
expText.setText('EXP: ' + playerExp);
playerLevelText.setText('Player Lv: ' + playerLevel);
coinsText.setText('Coins: ' + coins);
skillPointsText.setText('SP: ' + skillPoints);
// Update multiplier color based on value
if (comboMultiplier >= 4) {
multiplierText.fill = 0xFF0000; // Red for 4x+
} else if (comboMultiplier >= 3) {
multiplierText.fill = 0xFF8800; // Orange for 3x
} else if (comboMultiplier >= 2) {
multiplierText.fill = 0xFFD700; // Gold for 2x
} else {
multiplierText.fill = 0xFFFFFF; // White for 1x
}
// Check achievements
checkAchievements();
}
function showFeedback(text, laneIndex) {
var assetName = 'feedback' + text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
var feedbackImage = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
}));
feedbackImage.x = 1024; // Center of screen
feedbackImage.y = 1366; // Center of screen vertically
feedbackImage.alpha = 1;
feedbackTexts.push(feedbackImage);
// Add score display based on feedback type
var scoreDisplay;
if (text === 'NICE') {
scoreDisplay = game.addChild(LK.getAsset('positiveScoreDisplay', {
anchorX: 0.5,
anchorY: 0.5
}));
} else {
scoreDisplay = game.addChild(LK.getAsset('negativeScoreDisplay', {
anchorX: 0.5,
anchorY: 0.5
}));
}
scoreDisplay.x = 1024; // Center of screen
scoreDisplay.y = 1450; // Below feedback
scoreDisplay.alpha = 1;
feedbackTexts.push(scoreDisplay);
// Create score text overlay
var scoreChangeText = new Text2('', {
size: 60,
fill: text === 'NICE' ? 0x00FF00 : 0xFF0000
});
scoreChangeText.anchor.set(0.5, 0.5);
scoreChangeText.x = scoreDisplay.x;
scoreChangeText.y = scoreDisplay.y;
if (text === 'NICE') {
scoreChangeText.setText('+10');
} else if (text === 'EARLY') {
scoreChangeText.setText('-30');
} else if (text === 'MISSED') {
scoreChangeText.setText('0');
}
game.addChild(scoreChangeText);
feedbackTexts.push(scoreChangeText);
tween(feedbackImage, {
alpha: 0,
y: feedbackImage.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
feedbackImage.destroy();
var index = feedbackTexts.indexOf(feedbackImage);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
tween(scoreDisplay, {
alpha: 0,
y: scoreDisplay.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
scoreDisplay.destroy();
var index = feedbackTexts.indexOf(scoreDisplay);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
tween(scoreChangeText, {
alpha: 0,
y: scoreChangeText.y - 100
}, {
duration: 1000,
onFinish: function onFinish() {
scoreChangeText.destroy();
var index = feedbackTexts.indexOf(scoreChangeText);
if (index > -1) feedbackTexts.splice(index, 1);
}
});
}
function spawnTile() {
// 5% chance to spawn power tile (increases with level)
var powerChance = 0.05 + currentLevel * 0.01;
if (Math.random() < powerChance) {
spawnPowerTile();
return;
}
// Adjusted spawn chances based on level
var multiTileChance = 0.3 + currentLevel * 0.05; // More multi-tiles at higher levels
var spawnTwo = Math.random() < multiTileChance;
if (spawnTwo) {
// Spawn two tiles in different lanes
var laneIndex1 = Math.floor(Math.random() * 4);
var laneIndex2;
// Make sure second lane is different from first
do {
laneIndex2 = Math.floor(Math.random() * 4);
} while (laneIndex2 === laneIndex1);
// Create first tile
var tile1 = new QuickTile(laneIndex1);
tile1.x = 256 + laneIndex1 * 512;
tile1.y = -100;
tiles.push(tile1);
game.addChild(tile1);
// Create second tile
var tile2 = new QuickTile(laneIndex2);
tile2.x = 256 + laneIndex2 * 512;
tile2.y = -100;
tiles.push(tile2);
game.addChild(tile2);
} else {
// Spawn single tile
var laneIndex = Math.floor(Math.random() * 4);
var tile = new QuickTile(laneIndex);
tile.x = 256 + laneIndex * 512;
tile.y = -100;
tiles.push(tile);
game.addChild(tile);
}
}
function createParticles(x, y, count, color) {
for (var i = 0; i < count; i++) {
var particle = new Particle(x, y, color);
particles.push(particle);
game.addChild(particle);
}
}
function checkAchievements() {
var currentScore = LK.getScore();
// High Scorer achievement
if (currentScore >= 10000 && !achievements.highScorer.unlocked) {
unlockAchievement('highScorer');
}
// Perfectionist achievement
if (perfectStreak >= 50 && !achievements.perfectionist.unlocked) {
unlockAchievement('perfectionist');
}
// Combo Master achievement
if (comboCount >= 100 && !achievements.comboMaster.unlocked) {
unlockAchievement('comboMaster');
}
// Speed Demon achievement
if (currentLevel >= 5 && !achievements.speedDemon.unlocked) {
unlockAchievement('speedDemon');
}
// Coin Collector achievement
if (coins >= 500 && !achievements.coinCollector.unlocked) {
unlockAchievement('coinCollector');
}
// Marathoner achievement
if (storage.totalGamesPlayed >= 25 && !achievements.marathoner.unlocked) {
unlockAchievement('marathoner');
}
// Update high score
if (currentScore > storage.highScore) {
storage.highScore = currentScore;
}
}
function awardExperience(amount) {
var oldLevel = playerLevel;
playerExp += amount;
storage.playerExp = playerExp;
// Level up calculation (exponential growth)
var expNeeded = playerLevel * 100 + Math.pow(playerLevel, 2) * 50;
if (playerExp >= expNeeded) {
playerLevel++;
storage.playerLevel = playerLevel;
playerExp = 0;
storage.playerExp = 0;
// Award skill points and coins for level up
var skillPointsAwarded = Math.floor(playerLevel / 3) + 1;
var coinsAwarded = playerLevel * 25;
skillPoints += skillPointsAwarded;
coins += coinsAwarded;
storage.skillPoints = skillPoints;
storage.coins = coins;
// Check for level rewards
if (levelRewards[playerLevel]) {
var reward = levelRewards[playerLevel];
if (reward.skillPoints) {
skillPoints += reward.skillPoints;
storage.skillPoints = skillPoints;
}
if (reward.coins) {
coins += reward.coins;
storage.coins = coins;
}
showLevelUpNotification(playerLevel, reward.message);
} else {
showLevelUpNotification(playerLevel, skillPointsAwarded + ' SP + ' + coinsAwarded + ' Coins!');
}
}
updateScoreDisplay();
}
function showLevelUpNotification(level, rewardText) {
var levelUpText = new Text2('PLAYER LEVEL UP!\nLevel ' + level + '\n' + rewardText, {
size: 60,
fill: 0xFF00FF
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 1024;
levelUpText.y = 900;
game.addChild(levelUpText);
LK.effects.flashScreen(0xFF00FF, 1000);
tween(levelUpText, {
alpha: 0,
y: levelUpText.y - 150
}, {
duration: 3000,
onFinish: function onFinish() {
levelUpText.destroy();
}
});
}
function getSkillLevel(skillName) {
return unlockedSkills[skillName] || 0;
}
function applySkillEffects() {
// Apply skill effects to game mechanics
var speedBoostLevel = getSkillLevel('speedBoost');
var scoreMultLevel = getSkillLevel('scoreMultiplier');
var comboExtLevel = getSkillLevel('comboExtender');
var perfectWindowLevel = getSkillLevel('perfectWindow');
var powerDurationLevel = getSkillLevel('powerUpDuration');
return {
speedReduction: speedBoostLevel > 0 ? skills.speedBoost.effect(speedBoostLevel) : 0,
scoreBonus: scoreMultLevel > 0 ? skills.scoreMultiplier.effect(scoreMultLevel) : 0,
comboDecayReduction: comboExtLevel > 0 ? skills.comboExtender.effect(comboExtLevel) : 0,
perfectWindowBonus: perfectWindowLevel > 0 ? skills.perfectWindow.effect(perfectWindowLevel) : 0,
powerUpBonus: powerDurationLevel > 0 ? skills.powerUpDuration.effect(powerDurationLevel) : 0
};
}
function checkDailyBonus() {
var today = Math.floor(Date.now() / 86400000); // Days since epoch
if (dailyBonusCollected < today) {
// Award daily bonus
var dailyCoins = 50 + playerLevel * 10;
coins += dailyCoins;
storage.coins = coins;
dailyBonusCollected = today;
storage.dailyBonusCollected = today;
showPowerUpNotification('Daily Bonus: ' + dailyCoins + ' Coins!', 0xFFD700);
updateScoreDisplay();
}
}
function unlockAchievement(achievementKey) {
achievements[achievementKey].unlocked = true;
if (!storage.achievements) storage.achievements = {};
storage.achievements[achievementKey] = true;
// Award achievement rewards
var achievement = achievements[achievementKey];
if (achievement.reward) {
if (achievement.reward.coins) {
coins += achievement.reward.coins;
storage.coins = coins;
}
if (achievement.reward.skillPoints) {
skillPoints += achievement.reward.skillPoints;
storage.skillPoints = skillPoints;
}
}
// Show achievement notification
showAchievementNotification(achievement);
LK.effects.flashScreen(0xFFD700, 500);
updateScoreDisplay();
}
function showAchievementNotification(achievement) {
var rewardText = '';
if (achievement.reward) {
var rewards = [];
if (achievement.reward.coins) rewards.push(achievement.reward.coins + ' Coins');
if (achievement.reward.skillPoints) rewards.push(achievement.reward.skillPoints + ' SP');
if (rewards.length > 0) rewardText = '\nReward: ' + rewards.join(' + ');
}
var achievementText = new Text2('Achievement Unlocked!\n' + achievement.name + rewardText, {
size: 60,
fill: 0xFFD700
});
achievementText.anchor.set(0.5, 0.5);
achievementText.x = 1024;
achievementText.y = 800;
game.addChild(achievementText);
tween(achievementText, {
alpha: 0,
y: achievementText.y - 100
}, {
duration: 3000,
onFinish: function onFinish() {
achievementText.destroy();
}
});
}
function spawnPowerTile() {
var powerTypes = ['double', 'slow', 'shield'];
var powerType = powerTypes[Math.floor(Math.random() * powerTypes.length)];
var laneIndex = Math.floor(Math.random() * 4);
var powerTile = new PowerTile(laneIndex, powerType);
powerTile.x = 256 + laneIndex * 512;
powerTile.y = -100;
powerTiles.push(powerTile);
game.addChild(powerTile);
}
function activatePowerUp(powerType) {
var skillEffects = applySkillEffects();
var baseDuration = 600; // 10 seconds at 60fps
var enhancedDuration = Math.floor(baseDuration * (1 + skillEffects.powerUpBonus));
if (powerType === 'double') {
activePowerUps.doubleScore = enhancedDuration;
showPowerUpNotification('Double Score!', 0xFFD700);
} else if (powerType === 'slow') {
activePowerUps.slowTime = enhancedDuration;
showPowerUpNotification('Slow Time!', 0x00FFFF);
} else if (powerType === 'shield') {
activePowerUps.shield = enhancedDuration;
showPowerUpNotification('Shield Active!', 0x00FF00);
}
}
function showPowerUpNotification(text, color) {
var powerText = new Text2(text, {
size: 80,
fill: color
});
powerText.anchor.set(0.5, 0.5);
powerText.x = 1024;
powerText.y = 1000;
game.addChild(powerText);
tween(powerText, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5,
y: powerText.y - 100
}, {
duration: 2000,
onFinish: function onFinish() {
powerText.destroy();
}
});
}
function getLaneFromX(x) {
if (x < 512) return 0;
if (x < 1024) return 1;
if (x < 1536) return 2;
return 3;
}
function activateLane(laneIndex) {
if (laneIndex >= 0 && laneIndex < 4) {
activeLanes[laneIndex] = true;
lanes[laneIndex].removeChild(lanes[laneIndex].children[0]);
var activeLane = LK.getAsset('laneActive', {
anchorX: 0.5,
anchorY: 0.5
});
lanes[laneIndex].addChild(activeLane);
}
}
function deactivateLane(laneIndex) {
if (laneIndex >= 0 && laneIndex < 4) {
activeLanes[laneIndex] = false;
lanes[laneIndex].removeChild(lanes[laneIndex].children[0]);
var normalLane = LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5
});
lanes[laneIndex].addChild(normalLane);
}
}
game.down = function (x, y, obj) {
var laneIndex = getLaneFromX(x);
activateLane(laneIndex);
// Increment key press counter
keyPressCount++;
// Increase game speed by 2% every 5 key presses
if (keyPressCount % 5 === 0) {
gameSpeed *= 1.02;
}
// Add lane press animation
tween(lanes[laneIndex], {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
easing: tween.easeOut
});
// Check for tile hits
var hitTile = false;
// Check power tiles first
for (var i = 0; i < powerTiles.length; i++) {
var powerTile = powerTiles[i];
if (powerTile.lane === laneIndex && !powerTile.missed && !powerTile.earlyPressed) {
var distance = Math.abs(powerTile.y - hitLineY);
if (distance <= 80 && !powerTile.hit) {
powerTile.hit = true;
activatePowerUp(powerTile.powerType);
createParticles(powerTile.x, powerTile.y, 12, 0xFFD700);
tween(powerTile, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
if (!powerTile.destroyed) {
powerTile.destroyed = true;
powerTile.destroy();
}
}
});
hitTile = true;
break;
}
}
}
// Check regular tiles
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.lane === laneIndex && !tile.missed && !tile.earlyPressed) {
var distance = Math.abs(tile.y - hitLineY);
if (distance <= 80) {
// Handle QuickTile
if (!tile.hit) {
tile.hit = true;
// Calculate combo multiplier
comboMultiplier = Math.min(4, Math.floor(comboCount / 5) + 1);
var baseScore = 10;
// Apply power-up bonuses
if (activePowerUps.doubleScore > 0) {
baseScore *= 2;
}
var scoreToAdd = baseScore * comboMultiplier;
// Apply skill effects
var skillEffects = applySkillEffects();
var perfectWindow = 20 + skillEffects.perfectWindowBonus;
// Check for perfect timing (with skill enhancement)
var perfectTiming = distance <= perfectWindow;
if (perfectTiming) {
scoreToAdd *= 1.5; // 1.5x bonus for perfect timing
perfectStreak++;
createParticles(tile.x, tile.y, 8, 0xFFD700);
// Screen flash for perfect streak milestones
if (perfectStreak % 10 === 0) {
LK.effects.flashScreen(0xFFD700, 200);
}
} else {
perfectStreak = 0;
createParticles(tile.x, tile.y, 5, 0x00FF00);
}
// Apply score multiplier skill bonus
scoreToAdd *= 1 + skillEffects.scoreBonus;
// Award experience and coins
var expGained = perfectTiming ? 3 : 2;
var coinsGained = perfectTiming ? 2 : 1;
awardExperience(expGained);
coins += coinsGained;
storage.coins = coins;
LK.setScore(LK.getScore() + Math.floor(scoreToAdd));
comboCount++;
lastHitTime = LK.ticks;
// Decrement early count on nice hit (minimum 0)
if (earlyCount > 0) {
earlyCount--;
}
showFeedback('NICE', laneIndex);
// Use random Piano1-Piano5 sounds for each tile hit
var pianoSounds = ['Piano1', 'Piano2', 'Piano3', 'Piano4', 'Piano5'];
var randomSound = pianoSounds[Math.floor(Math.random() * pianoSounds.length)];
LK.getSound(randomSound).play();
// Visual effect
tween(tile, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
if (!tile.destroyed) {
tile.destroyed = true;
tile.destroy();
}
}
});
updateScoreDisplay();
hitTile = true;
break;
}
} else if (tile.y < hitLineY - 80) {
// Early press
tile.earlyPressed = true;
comboCount = 0; // Reset combo on early press
comboMultiplier = 1; // Reset multiplier
perfectStreak = 0; // Reset perfect streak
earlyCount++; // Increment early count
showFeedback('EARLY', laneIndex);
LK.getSound('early').play();
LK.setScore(LK.getScore() - 30); // Deduct 30 points for early press
// Check if 3 earlies reached
if (earlyCount >= 3) {
LK.showGameOver();
}
// Destroy tile immediately on early press
tween(tile, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
if (!tile.destroyed) {
tile.destroyed = true;
tile.destroy();
}
}
});
updateScoreDisplay();
hitTile = true;
break;
}
}
}
};
game.up = function (x, y, obj) {
var laneIndex = getLaneFromX(x);
deactivateLane(laneIndex);
// Add lane release animation
tween(lanes[laneIndex], {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
};
// Start background music
LK.playMusic('Music');
game.update = function () {
// Update power-ups
for (var powerType in activePowerUps) {
if (activePowerUps[powerType] > 0) {
activePowerUps[powerType]--;
}
}
// Apply slow time effect
var currentGameSpeed = gameSpeed;
if (activePowerUps.slowTime > 0) {
currentGameSpeed *= 0.5;
}
// Spawn tiles
tileSpawnTimer++;
var adjustedSpawnInterval = tileSpawnInterval;
if (activePowerUps.slowTime > 0) {
adjustedSpawnInterval *= 2;
}
if (tileSpawnTimer >= adjustedSpawnInterval) {
spawnTile();
tileSpawnTimer = 0;
// Level progression system
var targetScore = currentLevel * 1000;
if (LK.getScore() >= targetScore) {
currentLevel++;
storage.currentLevel = currentLevel;
if (currentLevel > storage.unlockedLevels) {
storage.unlockedLevels = currentLevel;
}
showPowerUpNotification('Level Up! Level ' + currentLevel, 0xFF00FF);
LK.effects.flashScreen(0xFF00FF, 800);
}
// Increase difficulty over time
if (LK.ticks % 300 === 0) {
gameSpeed += 0.15;
tileSpawnInterval = Math.max(25, tileSpawnInterval - 1);
}
}
// Clean up tiles
for (var i = tiles.length - 1; i >= 0; i--) {
var tile = tiles[i];
if (!tile || tile.destroyed) {
tiles.splice(i, 1);
continue;
}
if (tile.y > 2800 || tile.hit || tile.missed && tile.y > hitLineY + 200 || tile.earlyPressed && tile.y > 2800) {
tile.destroyed = true;
tile.destroy();
tiles.splice(i, 1);
}
}
// Clean up power tiles
for (var i = powerTiles.length - 1; i >= 0; i--) {
var powerTile = powerTiles[i];
if (!powerTile || powerTile.destroyed) {
powerTiles.splice(i, 1);
continue;
}
if (powerTile.y > 2800 || powerTile.hit || powerTile.missed && powerTile.y > hitLineY + 200) {
powerTile.destroyed = true;
powerTile.destroy();
powerTiles.splice(i, 1);
}
}
// Apply skill effects
var skillEffects = applySkillEffects();
// Update tile speeds based on game speed and skills
var effectiveSpeed = gameSpeed * (1 - skillEffects.speedReduction);
if (activePowerUps.slowTime > 0) {
effectiveSpeed *= 0.5;
}
for (var i = 0; i < tiles.length; i++) {
if (tiles[i] && !tiles[i].destroyed) {
tiles[i].speed = 12 * effectiveSpeed;
}
}
// Update power tile speeds
for (var i = 0; i < powerTiles.length; i++) {
if (powerTiles[i] && !powerTiles[i].destroyed) {
powerTiles[i].speed = 12 * effectiveSpeed;
}
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (!particle || particle.life <= 0) {
if (particle) particle.destroy();
particles.splice(i, 1);
}
}
// Combo decay system with skill enhancement
var skillEffects = applySkillEffects();
var decayTime = Math.floor(180 * (1 + skillEffects.comboDecayReduction));
if (LK.ticks - lastHitTime > decayTime && comboCount > 0) {
comboCount = Math.max(0, comboCount - 1);
comboMultiplier = Math.min(4, Math.floor(comboCount / 5) + 1);
updateScoreDisplay();
lastHitTime = LK.ticks; // Reset timer to prevent rapid decay
}
// Check daily bonus (once per game)
if (LK.ticks === 60) {
checkDailyBonus();
}
};
// Override game over to save progress and unlock achievements
var originalShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
// Save game stats
storage.totalGamesPlayed++;
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
// Unlock first win achievement if it's the first game
if (storage.totalGamesPlayed === 1 && !achievements.firstWin.unlocked) {
unlockAchievement('firstWin');
}
// Call original game over
originalShowGameOver();
};
A line. In-Game asset. 2d. High contrast. No shadows
A "single" tile of musical note 🎵. In-Game asset. 2d. High contrast. No shadows
A single tile of musical note 🎵 blue. In-Game asset. 2d. High contrast. No shadows
A single tile of musical note green. In-Game asset. 2d. High contrast. No shadows
A single musical tile red. In-Game asset. 2d. High contrast. No shadows
An UI written "NICE". In-Game asset. 2d. High contrast. No shadows
An UI written "Missed". In-Game asset. 2d. High contrast. No shadows
An UI written "Early". In-Game asset. 2d. High contrast. No shadows
A score display written +10 on it. In-Game asset. 2d. High contrast. No shadows
A score Ui that written -30 on it. In-Game asset. 2d. High contrast. No shadows
An image of "Perfect" Written on it. In-Game asset. 2d. High contrast. No shadows