User prompt
PowerUpRed will not cause you to end your game
User prompt
write a description for the game
User prompt
Change game name to Cats Are Rhythmic
User prompt
remove - **Blurred Vision** - Screen becomes slightly blurred making targeting harder
User prompt
lets add new bad power ups inside asset of "powerUpRed" - **Reverse Controls** - Mouse controls are inverted for a duration - **Blurred Vision** - Screen becomes slightly blurred making targeting harder - **Shrinking Targets** - Target boxes become smaller ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
change to 33
User prompt
change bullet speed to 36
User prompt
make it 6
User prompt
spikes falls faster
User prompt
change laser beam's position to the top of the screen from chracter
User prompt
each level pops on screen when pass to next one ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'setText')' in or related to this line: 'levelTxt.setText('Level: ' + currentLevel);' Line Number: 850
User prompt
add a level system ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
i notice, when Power ups touches the secretwall, game over happens, fix it
User prompt
make each good power up difrent asset, named by what they do
User prompt
lets add more power ups, these are good power ups; **Laser Beam** - Creates a continuous laser that can hit multiple notes in a line **Shield** - Protects player from one spike hit **Note Destroyer** - Automatically destroys all spikes on screen ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make moving target 4 seconds,
User prompt
okay now lets head back to "power ups" when we hit a power up the effect of power up shows on left of screen and duration time ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
spikes spawns less than music notes
User prompt
i said lower, not above
User prompt
put the score text a little lower
User prompt
Put the "Combo" text to left of "Score"
User prompt
"spikes" can pass the "secret line"
User prompt
edit the "spike", spike can pass the secretline and our bullets does not affects it, only when crushes to player we lose
User prompt
put the text exact below of the "Music ....." and edit to this : "You can change the music! For "Music 2" Press 'Original' For the "Music 3" Press 'Music 2'
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 33;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
// Default note type
self.noteType = 'normal';
self.pointValue = 100;
self.speed = 3;
// Initialize with normal note graphics
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.graphics = noteGraphics;
self.lane = 0;
self.hasTriggered = false;
self.pulseTimer = 0;
// Method to set note type with different properties
self.setNoteType = function (type) {
self.noteType = type;
// Remove current graphics
self.removeChild(self.graphics);
switch (type) {
case 'fast':
self.graphics = self.attachAsset('noteRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.pointValue = 150;
break;
case 'slow':
self.graphics = self.attachAsset('noteBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.pointValue = 200;
break;
case 'bonus':
self.graphics = self.attachAsset('noteGold', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2.5;
self.pointValue = 300;
break;
case 'challenge':
self.graphics = self.attachAsset('notePurple', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.pointValue = 250;
break;
case 'multiShot':
self.graphics = self.attachAsset('powerUpGreen', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 150;
break;
case 'slowMotion':
self.graphics = self.attachAsset('powerUpGreen', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 150;
break;
case 'scoreMultiplier':
self.graphics = self.attachAsset('powerUpGreen', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 150;
break;
case 'movingTarget':
self.graphics = self.attachAsset('powerUpRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 100;
break;
case 'laserBeam':
self.graphics = self.attachAsset('powerUpBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 200;
break;
case 'shield':
self.graphics = self.attachAsset('powerUpBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 150;
break;
case 'noteDestroyer':
self.graphics = self.attachAsset('powerUpBlue', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 300;
break;
case 'reverseControls':
self.graphics = self.attachAsset('powerUpRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 100;
break;
case 'shrinkingTargets':
self.graphics = self.attachAsset('powerUpRed', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.pointValue = 100;
break;
default:
self.graphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.pointValue = 100;
}
};
self.update = function () {
self.y += self.speed;
// Add visual effects for special notes
if (self.noteType === 'bonus') {
// Golden notes pulse
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.2) * 0.1;
self.graphics.scaleX = scale;
self.graphics.scaleY = scale;
} else if (self.noteType === 'challenge') {
// Purple notes rotate
self.graphics.rotation += 0.05;
} else if (self.noteType === 'multiShot' || self.noteType === 'slowMotion' || self.noteType === 'scoreMultiplier') {
// Good power-ups glow green
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.3) * 0.15;
self.graphics.scaleX = scale;
self.graphics.scaleY = scale;
} else if (self.noteType === 'laserBeam' || self.noteType === 'shield' || self.noteType === 'noteDestroyer') {
// New power-ups glow blue
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.35) * 0.18;
self.graphics.scaleX = scale;
self.graphics.scaleY = scale;
} else if (self.noteType === 'movingTarget' || self.noteType === 'reverseControls' || self.noteType === 'shrinkingTargets') {
// Bad power-ups pulse red
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.4) * 0.2;
self.graphics.scaleX = scale;
self.graphics.scaleY = scale;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add floating gun
var gun = self.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -50
});
self.gun = gun;
// Method to rotate gun towards target with smooth animation
self.aimGunAt = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - (self.y - 50); // Account for gun offset
var targetRotation = Math.atan2(dy, dx);
// Smooth rotation animation
tween(self.gun, {
rotation: targetRotation
}, {
duration: 150,
easing: tween.easeOut
});
};
return self;
});
var Spike = Container.expand(function () {
var self = Container.call(this);
var spikeGraphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6.0;
self.lane = 0;
self.pulseTimer = 0;
self.update = function () {
self.y += self.speed;
// Add pulsing danger effect
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.4) * 0.2;
spikeGraphics.scaleX = scale;
spikeGraphics.scaleY = scale;
// Add rotation for more menacing look
spikeGraphics.rotation += 0.08;
};
return self;
});
var TargetBox = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('targetBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 0;
self.isActive = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF0F8FF,
name: 'Cats Are Rhythmic'
});
/****
* Game Code
****/
// Game variables
var player;
var bullets = [];
var notes = [];
var spikes = [];
var targetBoxes = [];
var staffLines = [];
var score = 0;
// Level system variables
var currentLevel = storage.currentLevel || 1;
var levelScore = storage.levelScore || 0; // Score accumulated in current level
var totalScore = storage.totalScore || 0; // Total score across all levels
var levelThresholds = [0, 1000, 2500, 5000, 8000, 12000, 17000, 23000, 30000, 38000, 47000, 57000, 68000, 80000, 93000, 107000, 122000, 138000, 155000, 173000]; // Score needed for each level
var maxLevel = levelThresholds.length;
var mouseX = 1024;
var noteSpawnTimer = 0;
var noteSpawnInterval = 90; // frames between note spawns
var spikeSpawnTimer = 0;
var spikeSpawnInterval = 300; // frames between spike spawns (much less frequent than notes)
var musicPlaying = false;
var musicGlitchTimer = 0;
var musicGlitchDuration = 18; // 0.3 seconds at 60fps
// Music selection variables
var currentMusicTrack = 'bgmusic';
var musicTracks = ['bgmusic', 'rock_track', 'electronic_track'];
var musicTrackNames = ['Original', 'Music 2', 'Music 3'];
var musicSelectionMenu = [];
var showMusicMenu = false;
// Note preview system
var previewNotes = [];
var nextNoteTypes = [];
// Combo system variables
var combo = 0;
var maxCombo = 0;
// Feedback text variables
var feedbackTexts = [];
// Power-up system variables
var multiShotActive = false;
var multiShotTimer = 0;
var multiShotDuration = 300; // 5 seconds at 60fps
var slowMotionActive = false;
var slowMotionTimer = 0;
var slowMotionDuration = 300; // 5 seconds at 60fps
var scoreMultiplierActive = false;
var scoreMultiplierTimer = 0;
var scoreMultiplierDuration = 300; // 5 seconds at 60fps
var movingTargetActive = false;
var movingTargetTimer = 0;
var movingTargetDuration = 240; // 4 seconds at 60fps
// Power-up display variables
var powerUpDisplayContainer;
var powerUpIconDisplay;
var powerUpNameDisplay;
var powerUpTimerDisplay;
var powerUpProgressBar;
var activePowerUpType = null;
var activePowerUpMaxDuration = 0;
// New power-up system variables
var laserBeamActive = false;
var laserBeamTimer = 0;
var laserBeamDuration = 180; // 3 seconds at 60fps
var laserBeamGraphics = null;
var shieldActive = false;
var shieldHits = 0;
var maxShieldHits = 1;
var shieldGraphics = null;
var noteDestroyerActive = false;
var noteDestroyerTimer = 0;
var noteDestroyerDuration = 1; // Instant effect, 1 frame duration
// Bad power-up system variables
var reverseControlsActive = false;
var reverseControlsTimer = 0;
var reverseControlsDuration = 300; // 5 seconds at 60fps
var shrinkingTargetsActive = false;
var shrinkingTargetsTimer = 0;
var shrinkingTargetsDuration = 240; // 4 seconds at 60fps
var originalTargetSizes = [];
// Setup staff lines
var staffY = 400;
var staffSpacing = 80;
for (var i = 0; i < 5; i++) {
var staffLine = game.addChild(LK.getAsset('staffLine', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: staffY + i * staffSpacing
}));
staffLines.push(staffLine);
}
// Setup note preview indicators
var targetBoxPositions = [512, 853, 1194, 1536];
for (var i = 0; i < 4; i++) {
var previewNote = LK.getAsset('note', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8,
x: targetBoxPositions[i],
y: staffY - 100
});
previewNote.visible = false;
game.addChild(previewNote);
previewNotes.push(previewNote);
nextNoteTypes.push(null);
}
// Setup target boxes
var targetY = staffY + 4 * staffSpacing + 120;
var targetBoxPositions = [512, 853, 1194, 1536]; // 4 evenly spaced positions
for (var i = 0; i < 4; i++) {
var targetBox = game.addChild(new TargetBox());
targetBox.x = targetBoxPositions[i];
targetBox.y = targetY;
targetBox.lane = i;
targetBoxes.push(targetBox);
}
// Setup deletion area below target boxes
var deletionAreaY = targetY + 200;
// Initialize level system
updateLevelDisplay();
increaseDifficultyForLevel();
// Create visible secret wall
var secretWall = game.addChild(LK.getAsset('secretWall', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: deletionAreaY
}));
// Setup player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2500;
// Create aim assistance line
var aimLine = LK.getAsset('staffLine', {
anchorX: 0,
anchorY: 0.5,
width: 2,
height: 2,
alpha: 0.3,
tint: 0xFF0000
});
game.addChild(aimLine);
// Setup score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0x000000
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Setup level display
var levelTxt = new Text2('Level: ' + currentLevel, {
size: 60,
fill: 0x0066CC
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 20;
levelTxt.y = 20;
LK.gui.topLeft.addChild(levelTxt);
// Setup level progress display
var levelProgressTxt = new Text2('', {
size: 45,
fill: 0x666666
});
levelProgressTxt.anchor.set(0, 0);
levelProgressTxt.x = 20;
levelProgressTxt.y = 90;
LK.gui.topLeft.addChild(levelProgressTxt);
// Setup combo display
var comboTxt = new Text2('', {
size: 60,
fill: 0xFF6600
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 90; // Position below score
LK.gui.top.addChild(comboTxt);
// Setup music selection button
var musicMenuBtn = new Text2('Music: ' + musicTrackNames[0], {
size: 50,
fill: 0x000000
});
musicMenuBtn.anchor.set(1, 0);
musicMenuBtn.x = -20; // Position from right edge
musicMenuBtn.y = 20;
LK.gui.topRight.addChild(musicMenuBtn);
// Add help text below music button
var musicHelpTxt = new Text2('You can change the music! For "Music 2" Press \'Original\'\nFor the "Music 3" Press \'Music 2\'', {
size: 35,
fill: 0x666666
});
musicHelpTxt.anchor.set(1, 0);
musicHelpTxt.x = -20;
musicHelpTxt.y = 80;
LK.gui.topRight.addChild(musicHelpTxt);
// Create music selection menu (initially hidden)
for (var i = 0; i < musicTracks.length; i++) {
var menuItem = new Text2(musicTrackNames[i], {
size: 45,
fill: 0x000000
});
menuItem.anchor.set(1, 0);
menuItem.x = -20;
menuItem.y = 80 + i * 60;
menuItem.alpha = 0;
menuItem.trackIndex = i;
LK.gui.topRight.addChild(menuItem);
musicSelectionMenu.push(menuItem);
}
// Create power-up display container on left side of screen
powerUpDisplayContainer = new Container();
powerUpDisplayContainer.x = 50;
powerUpDisplayContainer.y = 200;
powerUpDisplayContainer.alpha = 0;
LK.gui.left.addChild(powerUpDisplayContainer);
// Power-up icon display
powerUpIconDisplay = LK.getAsset('powerUpGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
powerUpIconDisplay.x = 40;
powerUpIconDisplay.y = 40;
powerUpDisplayContainer.addChild(powerUpIconDisplay);
// Power-up name text
powerUpNameDisplay = new Text2('', {
size: 40,
fill: 0x00FF00
});
powerUpNameDisplay.anchor.set(0, 0.5);
powerUpNameDisplay.x = 90;
powerUpNameDisplay.y = 25;
powerUpDisplayContainer.addChild(powerUpNameDisplay);
// Power-up timer text
powerUpTimerDisplay = new Text2('', {
size: 30,
fill: 0xFFFFFF
});
powerUpTimerDisplay.anchor.set(0, 0.5);
powerUpTimerDisplay.x = 90;
powerUpTimerDisplay.y = 55;
powerUpDisplayContainer.addChild(powerUpTimerDisplay);
// Power-up progress bar background
var progressBarBg = LK.getAsset('staffLine', {
anchorX: 0,
anchorY: 0.5,
width: 200,
height: 8,
tint: 0x333333
});
progressBarBg.x = 90;
progressBarBg.y = 75;
powerUpDisplayContainer.addChild(progressBarBg);
// Power-up progress bar fill
powerUpProgressBar = LK.getAsset('staffLine', {
anchorX: 0,
anchorY: 0.5,
width: 200,
height: 8,
tint: 0x00FF00
});
powerUpProgressBar.x = 90;
powerUpProgressBar.y = 75;
powerUpDisplayContainer.addChild(powerUpProgressBar);
// Input handling
game.move = function (x, y, obj) {
mouseX = x;
// Apply reverse controls effect
if (reverseControlsActive) {
var centerX = 1024;
var distanceFromCenter = x - centerX;
player.x = centerX - distanceFromCenter;
} else {
player.x = x;
}
// Continuously aim gun at mouse position
player.aimGunAt(x, y);
// Update aim line
var gunX = player.x;
var gunY = player.y - 50;
var dx = x - gunX;
var dy = y - gunY;
var distance = Math.sqrt(dx * dx + dy * dy);
aimLine.x = gunX;
aimLine.y = gunY;
aimLine.width = Math.min(distance, 300); // Limit line length
aimLine.rotation = Math.atan2(dy, dx);
};
game.down = function (x, y, obj) {
// Check if clicking on music menu button - use simpler coordinate check
if (x > 1600 && y < 80) {
// Toggle music menu
showMusicMenu = !showMusicMenu;
for (var i = 0; i < musicSelectionMenu.length; i++) {
var menuItem = musicSelectionMenu[i];
if (showMusicMenu) {
tween(menuItem, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
} else {
tween(menuItem, {
alpha: 0
}, {
duration: 200,
easing: tween.easeIn
});
}
}
return; // Don't shoot when clicking menu
}
// Check if clicking on menu items
if (showMusicMenu) {
for (var i = 0; i < musicSelectionMenu.length; i++) {
var menuItem = musicSelectionMenu[i];
// Check if clicking in the menu area for this item
if (x > 1600 && y > 80 + i * 60 && y < 130 + i * 60) {
// Select this music track - directly use the menu item's trackIndex
var selectedTrackIndex = menuItem.trackIndex;
currentMusicTrack = musicTracks[selectedTrackIndex];
musicMenuBtn.setText('Music: ' + musicTrackNames[selectedTrackIndex]);
// Stop current music and play new track
LK.stopMusic();
try {
LK.playMusic(currentMusicTrack);
musicPlaying = true;
} catch (e) {
console.log('Error playing music:', currentMusicTrack, 'at index', selectedTrackIndex);
musicPlaying = false;
}
// Hide menu
showMusicMenu = false;
for (var j = 0; j < musicSelectionMenu.length; j++) {
tween(musicSelectionMenu[j], {
alpha: 0
}, {
duration: 200,
easing: tween.easeIn
});
}
return; // Don't shoot when selecting music
}
}
}
// Aim gun at target position
player.aimGunAt(x, y);
if (multiShotActive) {
// Create 3 bullets in spread pattern
for (var i = 0; i < 3; i++) {
var bullet = game.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y - 50; // Spawn from gun position
// Calculate direction to mouse position with spread
var dx = x - player.x;
var dy = y - (player.y - 50); // Account for gun offset
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var angle = Math.atan2(dy, dx);
var spreadAngle = (i - 1) * 0.3; // -0.3, 0, 0.3 radians spread
bullet.directionX = Math.cos(angle + spreadAngle);
bullet.directionY = Math.sin(angle + spreadAngle);
}
bullets.push(bullet);
}
} else {
// Create single bullet from gun position
var bullet = game.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y - 50; // Spawn from gun position
// Calculate direction to mouse position
var dx = x - player.x;
var dy = y - (player.y - 50); // Account for gun offset
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
}
bullets.push(bullet);
}
};
// Generate note type based on probabilities
function generateNoteType() {
var random = Math.random();
if (random < 0.05) {
return 'bonus'; // 5% chance for bonus notes
} else if (random < 0.1) {
return 'challenge'; // 5% chance for challenge notes
} else if (random < 0.2) {
return 'fast'; // 10% chance for fast notes
} else if (random < 0.3) {
return 'slow'; // 10% chance for slow notes
} else if (random < 0.33) {
return 'multiShot'; // 3% chance for multi-shot power-up
} else if (random < 0.36) {
return 'slowMotion'; // 3% chance for slow motion power-up
} else if (random < 0.39) {
return 'scoreMultiplier'; // 3% chance for score multiplier power-up
} else if (random < 0.42) {
return 'movingTarget'; // 3% chance for moving target power-up
} else if (random < 0.445) {
return 'laserBeam'; // 2.5% chance for laser beam power-up
} else if (random < 0.47) {
return 'shield'; // 2.5% chance for shield power-up
} else if (random < 0.49) {
return 'noteDestroyer'; // 2% chance for note destroyer power-up
} else if (random < 0.515) {
return 'reverseControls'; // 2.5% chance for reverse controls power-up
} else if (random < 0.54) {
return 'shrinkingTargets'; // 2.5% chance for shrinking targets power-up
} else {
return 'normal'; // 46% chance for normal notes
}
}
// Update note preview display
function updateNotePreview(lane, noteType) {
if (lane >= 0 && lane < previewNotes.length) {
var preview = previewNotes[lane];
nextNoteTypes[lane] = noteType;
// Set preview note appearance based on type
preview.removeChildren();
var assetId = 'note';
var tintColor = 0xFFFFFF;
switch (noteType) {
case 'fast':
assetId = 'noteRed';
break;
case 'slow':
assetId = 'noteBlue';
break;
case 'bonus':
assetId = 'noteGold';
break;
case 'challenge':
assetId = 'notePurple';
break;
case 'multiShot':
case 'slowMotion':
case 'scoreMultiplier':
assetId = 'powerUpGreen';
break;
case 'movingTarget':
case 'reverseControls':
case 'shrinkingTargets':
assetId = 'powerUpRed';
break;
case 'laserBeam':
case 'shield':
case 'noteDestroyer':
assetId = 'powerUpBlue';
break;
}
var previewGraphics = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
});
preview.addChild(previewGraphics);
preview.visible = true;
// Animate preview appearance
tween(preview, {
alpha: 1.0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
// Hide preview after delay
tween(preview, {
alpha: 0.6,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
}
// Spawn notes
function spawnNote() {
var lane = Math.floor(Math.random() * 4);
var note = game.addChild(new Note());
var targetBoxPositions = [512, 853, 1194, 1536]; // Match target box positions
note.x = targetBoxPositions[lane];
note.y = staffY + lane * staffSpacing - 200;
note.lane = lane;
// Use generated note type
var noteType = generateNoteType();
note.setNoteType(noteType);
// Show preview for next note
var nextLane = Math.floor(Math.random() * 4);
var nextNoteType = generateNoteType();
updateNotePreview(nextLane, nextNoteType);
notes.push(note);
}
// Spawn spikes
function spawnSpike() {
var lane = Math.floor(Math.random() * 4);
var spike = game.addChild(new Spike());
var targetBoxPositions = [512, 853, 1194, 1536]; // Match target box positions
spike.x = targetBoxPositions[lane];
spike.y = staffY + lane * staffSpacing - 200;
spike.lane = lane;
spikes.push(spike);
}
// Check if note is in timing window
function isNoteInTimingWindow(note, targetBox) {
var noteTop = note.y - 35; // Top of note (note height is 70, so 35 from center)
var noteBottom = note.y + 35; // Bottom of note
var targetTop = targetBox.y - 65; // Expanded target area (target height is 130, so 65 from center)
var targetBottom = targetBox.y + 65; // Expanded target area
// Check if any part of the note overlaps with the expanded target area
return noteBottom >= targetTop && noteTop <= targetBottom;
}
// Get timing quality based on note position relative to target center
function getTimingQuality(note, targetBox) {
var distance = Math.abs(note.y - targetBox.y);
if (distance <= 20) {
return 'Perfect!';
} else if (distance <= 40) {
return 'Good';
} else {
return 'Hit';
}
}
// Create particle burst effect
function createParticleBurst(x, y, color, count) {
for (var i = 0; i < count; i++) {
var particle = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
tint: color
});
particle.x = x;
particle.y = y;
game.addChild(particle);
// Random direction and speed
var angle = Math.PI * 2 * i / count + (Math.random() - 0.5) * 0.5;
var speed = 100 + Math.random() * 100;
var targetX = x + Math.cos(angle) * speed;
var targetY = y + Math.sin(angle) * speed;
// Animate particle outward
tween(particle, {
x: targetX,
y: targetY,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
// Check and handle level progression
function checkLevelUp() {
if (currentLevel < maxLevel) {
var nextLevelThreshold = levelThresholds[currentLevel];
if (totalScore >= nextLevelThreshold) {
levelUp();
}
}
}
// Handle level up
function levelUp() {
var previousLevel = currentLevel;
currentLevel++;
// Save level progress
storage.currentLevel = currentLevel;
storage.totalScore = totalScore;
storage.levelScore = 0; // Reset level score for new level
levelScore = 0;
// Create animated level pop-up display
var levelPopUpContainer = new Container();
levelPopUpContainer.x = 1024; // Center of screen
levelPopUpContainer.y = 1366; // Center of screen
levelPopUpContainer.alpha = 0;
levelPopUpContainer.scaleX = 0.1;
levelPopUpContainer.scaleY = 0.1;
game.addChild(levelPopUpContainer);
// Background for pop-up
var popUpBg = LK.getAsset('targetBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 3,
tint: 0x000080,
alpha: 0.9
});
levelPopUpContainer.addChild(popUpBg);
// Level text
var levelPopUpText = new Text2('LEVEL ' + currentLevel, {
size: 120,
fill: 0xFFD700
});
levelPopUpText.anchor.set(0.5, 0.5);
levelPopUpText.y = -30;
levelPopUpContainer.addChild(levelPopUpText);
// Level up text
var levelUpText = new Text2('LEVEL UP!', {
size: 80,
fill: 0x00FF00
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.y = 60;
levelPopUpContainer.addChild(levelUpText);
// Animate pop-up appearance
tween(levelPopUpContainer, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Add pulsing effect to level text
tween(levelPopUpText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut
});
tween(levelPopUpText, {
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeInOut
});
// Remove pop-up after delay
tween(levelPopUpContainer, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8,
y: 1200
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
levelPopUpContainer.destroy();
}
});
// Create level up feedback
createFeedbackText('LEVEL UP!', 1024, 800, 0xFFD700);
createFeedbackText('Level ' + currentLevel, 1024, 860, 0x0066CC);
// Flash screen gold for level up
LK.effects.flashScreen(0xFFD700, 800);
// Update level display
updateLevelDisplay();
// Increase difficulty with level
increaseDifficultyForLevel();
}
// Update level display
function updateLevelDisplay() {
if (levelTxt) {
levelTxt.setText('Level: ' + currentLevel);
}
if (currentLevel < maxLevel) {
var nextThreshold = levelThresholds[currentLevel];
var progress = totalScore - (currentLevel > 1 ? levelThresholds[currentLevel - 1] : 0);
var needed = nextThreshold - (currentLevel > 1 ? levelThresholds[currentLevel - 1] : 0);
if (levelProgressTxt) {
levelProgressTxt.setText(progress + ' / ' + needed);
}
} else {
if (levelProgressTxt) {
levelProgressTxt.setText('MAX LEVEL');
}
}
}
// Increase difficulty based on current level
function increaseDifficultyForLevel() {
// Reduce spawn intervals based on level
noteSpawnInterval = Math.max(30, 90 - (currentLevel - 1) * 3);
spikeSpawnInterval = Math.max(120, 300 - (currentLevel - 1) * 8);
}
// Create feedback text with animation
function createFeedbackText(text, x, y, color) {
var feedbackText = new Text2(text, {
size: 50,
fill: color
});
feedbackText.anchor.set(0.5, 0.5);
feedbackText.x = x;
feedbackText.y = y;
feedbackText.alpha = 1;
feedbackText.scaleX = 0.5;
feedbackText.scaleY = 0.5;
game.addChild(feedbackText);
feedbackTexts.push(feedbackText);
// Animate text appearance
tween(feedbackText, {
scaleX: 1.2,
scaleY: 1.2,
y: y - 50
}, {
duration: 300,
easing: tween.easeOut
});
// Fade out and remove
tween(feedbackText, {
alpha: 0,
y: y - 100
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
feedbackText.destroy();
var index = feedbackTexts.indexOf(feedbackText);
if (index > -1) {
feedbackTexts.splice(index, 1);
}
}
});
}
// Show power-up effect display
function showPowerUpDisplay(powerUpType, duration) {
activePowerUpType = powerUpType;
activePowerUpMaxDuration = duration;
// Set power-up name and icon based on type
var powerUpName = '';
var iconAsset = 'powerUpGreen';
var textColor = 0x00FF00;
switch (powerUpType) {
case 'multiShot':
powerUpName = 'Multi-Shot';
iconAsset = 'powerUpGreen';
textColor = 0x00FF00;
break;
case 'slowMotion':
powerUpName = 'Slow Motion';
iconAsset = 'powerUpGreen';
textColor = 0x00FFFF;
break;
case 'scoreMultiplier':
powerUpName = 'Score x2';
iconAsset = 'powerUpGreen';
textColor = 0xFFD700;
break;
case 'movingTarget':
powerUpName = 'Moving Targets';
iconAsset = 'powerUpRed';
textColor = 0xFF0000;
break;
case 'laserBeam':
powerUpName = 'Laser Beam';
iconAsset = 'powerUpBlue';
textColor = 0x00FFFF;
break;
case 'shield':
powerUpName = 'Shield';
iconAsset = 'powerUpBlue';
textColor = 0x00FFFF;
break;
case 'noteDestroyer':
powerUpName = 'Spike Destroyer';
iconAsset = 'powerUpBlue';
textColor = 0x00FFFF;
break;
case 'reverseControls':
powerUpName = 'Reverse Controls';
iconAsset = 'powerUpRed';
textColor = 0xFF0000;
break;
case 'shrinkingTargets':
powerUpName = 'Shrinking Targets';
iconAsset = 'powerUpRed';
textColor = 0xFF0000;
break;
}
// Update display elements
powerUpDisplayContainer.removeChild(powerUpIconDisplay);
powerUpIconDisplay = LK.getAsset(iconAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
powerUpIconDisplay.x = 40;
powerUpIconDisplay.y = 40;
powerUpDisplayContainer.addChild(powerUpIconDisplay);
powerUpNameDisplay.setText(powerUpName);
powerUpNameDisplay.fill = textColor;
powerUpProgressBar.tint = textColor;
// Animate display appearance
tween(powerUpDisplayContainer, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut
});
tween(powerUpDisplayContainer, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
// Hide power-up effect display
function hidePowerUpDisplay() {
activePowerUpType = null;
activePowerUpMaxDuration = 0;
tween(powerUpDisplayContainer, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn
});
}
// Game update loop
game.update = function () {
// Spawn notes
noteSpawnTimer++;
if (noteSpawnTimer >= noteSpawnInterval) {
spawnNote();
noteSpawnTimer = 0;
}
// Spawn spikes
spikeSpawnTimer++;
if (spikeSpawnTimer >= spikeSpawnInterval) {
spawnSpike();
spikeSpawnTimer = 0;
}
// Update and check bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Remove bullets that go off screen
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Spikes are no longer affected by bullets - they can pass through everything
// Check collision with target boxes
for (var j = 0; j < targetBoxes.length; j++) {
var targetBox = targetBoxes[j];
if (bullet.intersects(targetBox)) {
// Check if there's a note in timing window for this lane
var hitNote = null;
for (var k = 0; k < notes.length; k++) {
var note = notes[k];
if (note.lane === targetBox.lane && !note.hasTriggered && isNoteInTimingWindow(note, targetBox)) {
hitNote = note;
break;
}
}
if (hitNote) {
// Get timing quality for feedback
var timingQuality = getTimingQuality(hitNote, targetBox);
var basePoints = hitNote.pointValue;
var bonusPoints = 0;
var feedbackColor = 0x00FF00;
// Handle power-up activation
if (hitNote.noteType === 'multiShot') {
multiShotActive = true;
multiShotTimer = multiShotDuration;
showPowerUpDisplay('multiShot', multiShotDuration);
createFeedbackText('Multi-Shot!', targetBox.x, targetBox.y - 120, 0x00FF00);
} else if (hitNote.noteType === 'slowMotion') {
slowMotionActive = true;
slowMotionTimer = slowMotionDuration;
showPowerUpDisplay('slowMotion', slowMotionDuration);
createFeedbackText('Slow Motion!', targetBox.x, targetBox.y - 120, 0x00FF00);
} else if (hitNote.noteType === 'scoreMultiplier') {
scoreMultiplierActive = true;
scoreMultiplierTimer = scoreMultiplierDuration;
showPowerUpDisplay('scoreMultiplier', scoreMultiplierDuration);
createFeedbackText('Score x2!', targetBox.x, targetBox.y - 120, 0x00FF00);
} else if (hitNote.noteType === 'movingTarget') {
movingTargetActive = true;
movingTargetTimer = movingTargetDuration;
showPowerUpDisplay('movingTarget', movingTargetDuration);
createFeedbackText('Moving Targets!', targetBox.x, targetBox.y - 120, 0xFF0000);
} else if (hitNote.noteType === 'laserBeam') {
laserBeamActive = true;
laserBeamTimer = laserBeamDuration;
showPowerUpDisplay('laserBeam', laserBeamDuration);
createFeedbackText('Laser Beam!', targetBox.x, targetBox.y - 120, 0x00FFFF);
// Create laser beam visual effect
if (laserBeamGraphics) {
laserBeamGraphics.destroy();
}
laserBeamGraphics = LK.getAsset('laserBeam', {
anchorX: 0.5,
anchorY: 0,
x: player.x,
y: 0,
height: 2732,
alpha: 0.8
});
game.addChild(laserBeamGraphics);
} else if (hitNote.noteType === 'shield') {
if (!shieldActive) {
shieldActive = true;
shieldHits = 0;
showPowerUpDisplay('shield', 999); // Show indefinitely until used
createFeedbackText('Shield Active!', targetBox.x, targetBox.y - 120, 0x00FFFF);
// Create shield visual effect
if (shieldGraphics) {
shieldGraphics.destroy();
}
shieldGraphics = LK.getAsset('shieldEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
shieldGraphics.x = 0;
shieldGraphics.y = 0;
player.addChild(shieldGraphics);
// Animate shield appearance
tween(shieldGraphics, {
alpha: 0.6,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut
});
}
} else if (hitNote.noteType === 'noteDestroyer') {
noteDestroyerActive = true;
noteDestroyerTimer = noteDestroyerDuration;
showPowerUpDisplay('noteDestroyer', noteDestroyerDuration);
createFeedbackText('Spike Destroyer!', targetBox.x, targetBox.y - 120, 0x00FFFF);
// Immediately destroy all spikes on screen
for (var s = spikes.length - 1; s >= 0; s--) {
var spike = spikes[s];
createParticleBurst(spike.x, spike.y, 0xFF4444, 8);
spike.destroy();
spikes.splice(s, 1);
}
// Add bonus points for destroyed spikes
var destroyedCount = spikes.length;
if (destroyedCount > 0) {
score += destroyedCount * 50;
createFeedbackText('+' + destroyedCount * 50 + ' Spike Bonus!', player.x, player.y - 150, 0x00FFFF);
}
} else if (hitNote.noteType === 'reverseControls') {
reverseControlsActive = true;
reverseControlsTimer = reverseControlsDuration;
showPowerUpDisplay('reverseControls', reverseControlsDuration);
createFeedbackText('Reverse Controls!', targetBox.x, targetBox.y - 120, 0xFF0000);
} else if (hitNote.noteType === 'shrinkingTargets') {
shrinkingTargetsActive = true;
shrinkingTargetsTimer = shrinkingTargetsDuration;
showPowerUpDisplay('shrinkingTargets', shrinkingTargetsDuration);
createFeedbackText('Shrinking Targets!', targetBox.x, targetBox.y - 120, 0xFF0000);
// Store original target box sizes
originalTargetSizes = [];
for (var t = 0; t < targetBoxes.length; t++) {
originalTargetSizes.push({
scaleX: targetBoxes[t].scaleX,
scaleY: targetBoxes[t].scaleY
});
// Animate targets shrinking
tween(targetBoxes[t], {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Apply combo multiplier and timing bonus
combo++;
if (combo > maxCombo) {
maxCombo = combo;
}
// Timing bonuses
if (timingQuality === 'Perfect!') {
bonusPoints = Math.floor(basePoints * 0.5);
feedbackColor = 0xFFD700; // Gold
} else if (timingQuality === 'Good') {
bonusPoints = Math.floor(basePoints * 0.2);
feedbackColor = 0x00FF00; // Green
} else {
feedbackColor = 0x88FF88; // Light green
}
// Combo multiplier (every 5 combo adds 10% bonus)
var comboMultiplier = 1 + Math.floor(combo / 5) * 0.1;
// Score multiplier power-up
if (scoreMultiplierActive) {
comboMultiplier *= 2;
}
var totalPoints = Math.floor((basePoints + bonusPoints) * comboMultiplier);
score += totalPoints;
levelScore += totalPoints;
totalScore += totalPoints;
// Check for level up
checkLevelUp();
// Save progress
storage.levelScore = levelScore;
storage.totalScore = totalScore;
hitNote.hasTriggered = true;
// Create feedback text
createFeedbackText(timingQuality, targetBox.x, targetBox.y - 80, feedbackColor);
// Create particle burst effect
var particleColor = feedbackColor;
var particleCount = 8;
if (hitNote.noteType === 'bonus') {
particleColor = 0xFFD700;
particleCount = 12; // More particles for bonus notes
} else if (hitNote.noteType === 'challenge') {
particleColor = 0x8844FF;
} else if (hitNote.noteType === 'fast') {
particleColor = 0xFF4444;
} else if (hitNote.noteType === 'slow') {
particleColor = 0x4444FF;
}
createParticleBurst(hitNote.x, hitNote.y, particleColor, particleCount);
// Show combo if >= 5
if (combo >= 5) {
comboTxt.setText('Combo x' + combo);
// Scale combo text briefly for emphasis
tween(comboTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut
});
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
// Flash different colors based on note type
var flashColor = 0x00FF00; // Default green
if (hitNote.noteType === 'bonus') flashColor = 0xFFD700; // Gold
else if (hitNote.noteType === 'challenge') flashColor = 0x8844FF; // Purple
else if (hitNote.noteType === 'fast') flashColor = 0xFF4444; // Red
else if (hitNote.noteType === 'slow') flashColor = 0x4444FF; // Blue
LK.effects.flashObject(targetBox, flashColor, 500);
LK.getSound('hit').play();
// Start or resume music on successful hit
if (!musicPlaying && musicGlitchTimer === 0) {
try {
LK.playMusic(currentMusicTrack);
musicPlaying = true;
} catch (e) {
console.log('Error playing music:', currentMusicTrack);
musicPlaying = false;
}
} else if (musicGlitchTimer > 0) {
// Resume music after glitch
try {
LK.playMusic(currentMusicTrack);
musicGlitchTimer = 0;
} catch (e) {
console.log('Error resuming music:', currentMusicTrack);
}
}
// Remove the note
hitNote.destroy();
var noteIndex = notes.indexOf(hitNote);
if (noteIndex > -1) {
notes.splice(noteIndex, 1);
}
}
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
// Update score display
scoreTxt.setText('Score: ' + score);
LK.setScore(totalScore); // Use total score for leaderboards
// Update level display
updateLevelDisplay();
break;
}
}
}
// Update power-up timers
if (multiShotTimer > 0) {
multiShotTimer--;
if (multiShotTimer === 0) {
multiShotActive = false;
if (activePowerUpType === 'multiShot') {
hidePowerUpDisplay();
}
}
}
if (slowMotionTimer > 0) {
slowMotionTimer--;
if (slowMotionTimer === 0) {
slowMotionActive = false;
if (activePowerUpType === 'slowMotion') {
hidePowerUpDisplay();
}
}
}
if (scoreMultiplierTimer > 0) {
scoreMultiplierTimer--;
if (scoreMultiplierTimer === 0) {
scoreMultiplierActive = false;
if (activePowerUpType === 'scoreMultiplier') {
hidePowerUpDisplay();
}
}
}
if (movingTargetTimer > 0) {
movingTargetTimer--;
if (movingTargetTimer === 0) {
movingTargetActive = false;
if (activePowerUpType === 'movingTarget') {
hidePowerUpDisplay();
}
// Reset target boxes to original positions
for (var j = 0; j < targetBoxes.length; j++) {
targetBoxes[j].x = targetBoxPositions[j];
}
}
}
// Update new power-up timers
if (laserBeamTimer > 0) {
laserBeamTimer--;
if (laserBeamTimer === 0) {
laserBeamActive = false;
if (laserBeamGraphics) {
laserBeamGraphics.destroy();
laserBeamGraphics = null;
}
if (activePowerUpType === 'laserBeam') {
hidePowerUpDisplay();
}
}
}
if (noteDestroyerTimer > 0) {
noteDestroyerTimer--;
if (noteDestroyerTimer === 0) {
noteDestroyerActive = false;
if (activePowerUpType === 'noteDestroyer') {
hidePowerUpDisplay();
}
}
}
// Update bad power-up timers
if (reverseControlsTimer > 0) {
reverseControlsTimer--;
if (reverseControlsTimer === 0) {
reverseControlsActive = false;
if (activePowerUpType === 'reverseControls') {
hidePowerUpDisplay();
}
}
}
if (shrinkingTargetsTimer > 0) {
shrinkingTargetsTimer--;
if (shrinkingTargetsTimer === 0) {
shrinkingTargetsActive = false;
// Restore original target box sizes
for (var t = 0; t < targetBoxes.length; t++) {
if (originalTargetSizes[t]) {
tween(targetBoxes[t], {
scaleX: originalTargetSizes[t].scaleX,
scaleY: originalTargetSizes[t].scaleY
}, {
duration: 500,
easing: tween.easeOut
});
}
}
if (activePowerUpType === 'shrinkingTargets') {
hidePowerUpDisplay();
}
}
}
// Handle laser beam collision with notes
if (laserBeamActive && laserBeamGraphics) {
// Update laser position to follow player horizontally but stay at top
laserBeamGraphics.x = player.x;
laserBeamGraphics.y = 0;
// Check laser collision with all notes
for (var l = notes.length - 1; l >= 0; l--) {
var note = notes[l];
if (Math.abs(note.x - laserBeamGraphics.x) < 50 && note.y < player.y) {
// Laser hit this note
var laserPoints = note.pointValue;
if (scoreMultiplierActive) {
laserPoints *= 2;
}
score += laserPoints;
createFeedbackText('+' + laserPoints, note.x, note.y - 50, 0x00FFFF);
createParticleBurst(note.x, note.y, 0x00FFFF, 6);
note.destroy();
notes.splice(l, 1);
}
}
}
// Update power-up display timer and progress bar
if (activePowerUpType && activePowerUpMaxDuration > 0) {
var currentTimer = 0;
if (activePowerUpType === 'multiShot') currentTimer = multiShotTimer;else if (activePowerUpType === 'slowMotion') currentTimer = slowMotionTimer;else if (activePowerUpType === 'scoreMultiplier') currentTimer = scoreMultiplierTimer;else if (activePowerUpType === 'movingTarget') currentTimer = movingTargetTimer;else if (activePowerUpType === 'laserBeam') currentTimer = laserBeamTimer;else if (activePowerUpType === 'reverseControls') currentTimer = reverseControlsTimer;else if (activePowerUpType === 'shrinkingTargets') currentTimer = shrinkingTargetsTimer;else if (activePowerUpType === 'shield') {
// Shield shows number of hits remaining instead of timer
powerUpTimerDisplay.setText('Hits: ' + (maxShieldHits - shieldHits));
powerUpProgressBar.width = 200 * ((maxShieldHits - shieldHits) / maxShieldHits);
} else if (activePowerUpType === 'noteDestroyer') currentTimer = noteDestroyerTimer;
// Update timer text (convert frames to seconds) for timed power-ups
if (activePowerUpType !== 'shield') {
var secondsLeft = Math.ceil(currentTimer / 60);
powerUpTimerDisplay.setText(secondsLeft + 's');
// Update progress bar
var progress = currentTimer / activePowerUpMaxDuration;
powerUpProgressBar.width = 200 * progress;
}
}
// Move target boxes if moving target power-up is active
if (movingTargetActive) {
for (var j = 0; j < targetBoxes.length; j++) {
var targetBox = targetBoxes[j];
var originalX = targetBoxPositions[j];
var offset = Math.sin(LK.ticks * 0.05 + j * 0.5) * 100;
targetBox.x = originalX + offset;
}
}
// Update and check notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Apply slow motion effect
if (slowMotionActive) {
note.speed *= 0.5;
}
// Check if note has passed through deletion area
if (note.y > deletionAreaY && !note.hasTriggered) {
// Only trigger game over for regular music notes, not power-ups
if (note.noteType !== 'multiShot' && note.noteType !== 'slowMotion' && note.noteType !== 'scoreMultiplier' && note.noteType !== 'movingTarget' && note.noteType !== 'laserBeam' && note.noteType !== 'shield' && note.noteType !== 'noteDestroyer') {
// Note crashed into secret wall - game over
LK.showGameOver();
return; // Exit update loop since game is over
} else {
// Power-up notes just get removed without penalty
note.destroy();
notes.splice(i, 1);
continue;
}
}
// Remove notes that go off screen
if (note.y > 2800) {
note.destroy();
notes.splice(i, 1);
}
// Restore note speed after slow motion effect
if (slowMotionActive) {
note.speed *= 2; // Restore original speed for next frame
}
}
// Update and check spikes
for (var i = spikes.length - 1; i >= 0; i--) {
var spike = spikes[i];
// Apply slow motion effect
if (slowMotionActive) {
spike.speed *= 0.5;
}
// Check collision with player - game over if spike hits player (unless shield is active)
if (spike.intersects(player)) {
if (shieldActive && shieldHits < maxShieldHits) {
// Shield absorbs the hit
shieldHits++;
createFeedbackText('Shield Hit!', player.x, player.y - 100, 0x00FFFF);
createParticleBurst(spike.x, spike.y, 0x00FFFF, 10);
LK.effects.flashObject(player, 0x00FFFF, 500);
// Remove the spike
spike.destroy();
spikes.splice(i, 1);
// Deactivate shield if max hits reached
if (shieldHits >= maxShieldHits) {
shieldActive = false;
if (shieldGraphics) {
tween(shieldGraphics, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
shieldGraphics.destroy();
shieldGraphics = null;
}
});
}
if (activePowerUpType === 'shield') {
hidePowerUpDisplay();
}
createFeedbackText('Shield Depleted!', player.x, player.y - 120, 0xFF0000);
}
continue;
} else {
// No shield or shield depleted - game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return; // Exit update loop since game is over
}
}
// Spikes can pass through the secret line - no collision check needed
// Remove spikes that go off screen
if (spike.y > 2800) {
spike.destroy();
spikes.splice(i, 1);
}
// Restore spike speed after slow motion effect
if (slowMotionActive) {
spike.speed *= 2; // Restore original speed for next frame
}
}
// Handle music glitch timer
if (musicGlitchTimer > 0) {
musicGlitchTimer--;
if (musicGlitchTimer === 0 && musicPlaying) {
// Resume music after glitch period
try {
LK.playMusic(currentMusicTrack);
} catch (e) {
console.log('Error resuming music after glitch:', currentMusicTrack);
}
}
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
noteSpawnInterval = Math.max(30, noteSpawnInterval - 5);
// Increase note speed slightly
for (var i = 0; i < notes.length; i++) {
notes[i].speed = Math.min(6, notes[i].speed + 0.1);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -256,9 +256,10 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0xF0F8FF
+ backgroundColor: 0xF0F8FF,
+ name: 'Cats Are Rhythmic'
});
/****
* Game Code
Music Note. In-Game asset. 2d. High contrast. No shadows
a circle empty inside, at the edges there is rainbow curly things. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A simple blue cartoon cat standing upright, no accessories or effects, clean and minimal style, no musical notes or particles, not too stylish, designed as the main character for a rhythm game with a cold, minimal theme, light outlines and smooth shading, no background. In-Game asset. 2d. High contrast. No shadows
A dumb looking flat fish like a sardine looking up, ice blue color.. In-Game asset. 2d. High contrast. No shadows
A simple ice blue fishbone icon, clean vector style, no background, minimal design, symmetrical and centered, soft lines, suitable for a 2D rhythm game UI element. In-Game asset. 2d. High contrast. No shadows
Ice blue with a bright color stroke music note. In-Game asset. 2d. High contrast. No shadows
Ice blue with a dark color stroke music notes (note must be simetric).. In-Game asset. 2d. High contrast. No shadows
Good Power Up Green color. In-Game asset. 2d. High contrast. No shadows
Red Color, delete "GOOD" Write "BAD"
Red Spike "Music Note" shape. In-Game asset. 2d. High contrast. No shadows
circle shape, empty inside, transparent , stroke is navy blue.. In-Game asset. 2d. High contrast. No shadows
A huge Laser beam, red. In-Game asset. 2d. High contrast. No shadows