User prompt
start should spawn less often
User prompt
Make sure combos continue and not stop at 2.
User prompt
Yes, implement it
User prompt
star should move from right to left and move up and down, add a tween to make this effect ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Change how the start moves. Initially make it move like the flying koopas
User prompt
star power up, should have a different movement. it should move forward, like the enemies, but also oscilate up and down. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add boroders to score and coins in hud
User prompt
add border tot tap to start
User prompt
add white border to ttitle text
User prompt
title text should be NES red
User prompt
Increase the goombas size over time when they are spawning ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a red square behind the game title
User prompt
when game speed increases goomba size should also increase
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'groundY')' in or related to this line: 'tween(automatedPlayer, {' Line Number: 864
User prompt
Fix double paralax in homescreen. only the one with player moving should be happening
User prompt
remoeve double paralax speed in homepage
User prompt
add paralax scrolling also to the main menu background
User prompt
tap to start should be 400 pixxels below
User prompt
tap to start should be belwo the middle of the screen
User prompt
Better, move tap to start move below
User prompt
main menu background should do paralax too
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'groundY')' in or related to this line: 'tween(automatedPlayer, {' Line Number: 864
Code edit (1 edits merged)
Please save this source code
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 0
});
/****
* Classes
****/
var AutomatedPlayer = Container.expand(function () {
var self = Container.call(this);
self.runAnimation = ['player_run1', 'player_run2', 'player_run3'];
self.sprites = [];
self.runFrame = 0;
self.animationCounter = 0;
self.animationSpeed = 0.1;
// Pre-attach all sprites
for (var i = 0; i < self.runAnimation.length; i++) {
var sprite = self.attachAsset(self.runAnimation[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
self.groundY = 2732 - 400; // 400 pixels from bottom
self.y = -200; // Start off-screen at the top
self.showFrame = function (index) {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Show the appropriate sprite
self.sprites[index].alpha = 1;
};
self.update = function () {
// Running animation
self.animationCounter += self.animationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.runFrame = (self.runFrame + 1) % self.runAnimation.length;
self.showFrame(self.runFrame);
}
// Move right automatically
self.x += 5;
// Wrap around when reaching edge
if (self.x > 2048 + 100) {
self.x = -100;
}
};
return self;
});
var Background = Container.expand(function () {
var self = Container.call(this);
var backgrounds = ['background1', 'background2', 'background3'];
var randomBackground = backgrounds[Math.floor(Math.random() * backgrounds.length)];
var backgroundGraphics = self.attachAsset(randomBackground, {
anchorX: 0,
anchorY: 0
});
self.sprites = [backgroundGraphics]; // Store sprites for access
self.speed = 3;
self.update = function () {
if (!game.playerDead) {
// Increase speed over time, up to a reasonable maximum
self.speed = 3 + Math.min(8, Math.floor(LK.ticks / 300) * 0.3);
// Double speed during star power
if (starPowerActive) {
self.speed *= 2;
}
self.x -= self.speed;
}
if (self.x <= -2048) {
self.x = 2048;
}
};
});
var Background2 = Container.expand(function () {
var self = Container.call(this);
var backgrounds = ['background1', 'background2', 'background3'];
var randomBackground = backgrounds[Math.floor(Math.random() * backgrounds.length)];
var backgroundGraphics = self.attachAsset(randomBackground, {
anchorX: 0,
anchorY: 0
});
self.sprites = [backgroundGraphics]; // Store sprites for access
self.speed = 3;
self.update = function () {
if (!game.playerDead) {
// Increase speed over time, up to a reasonable maximum
self.speed = 3 + Math.min(8, Math.floor(LK.ticks / 300) * 0.3);
// Double speed during star power
if (starPowerActive) {
self.speed *= 2;
}
self.x -= self.speed;
}
if (self.x <= -2048) {
self.x = 2048;
}
};
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 3;
self.collected = false;
self.y = 2732 - 600; // Position coins higher than the ground
self.update = function () {
if (!game.playerDead) {
// Increase speed over time, up to a reasonable maximum
self.speed = 3 + Math.min(8, Math.floor(LK.ticks / 300) * 0.3);
// Double speed during star power
if (starPowerActive) {
self.speed *= 2;
}
self.x -= self.speed;
// Removed oscillation to keep coins from moving up and down
if (!self.oscillating) {
self.oscillating = true;
// No pulsing animation for coins
self.scale.x = 1;
self.scale.y = 1;
}
}
if (self.x < -100) {
// Cancel any active tweens when destroying
tween.stop(self);
tween.stop(self.scale);
self.destroy();
}
};
});
// ComboDisplay handles showing combo text on screen
var ComboDisplay = Container.expand(function () {
var self = Container.call(this);
var comboText = new Text2('', {
size: 60,
fill: 0xFFD700,
// Gold color for combo text
font: "'Press Start 2P', monospace"
});
comboText.anchor.set(0.5, 0.5);
self.addChild(comboText);
self.showCombo = function (comboCount, points) {
comboText.setText('COMBO x' + comboCount + '!\n+' + points + ' POINTS!');
comboText.alpha = 1;
// Animate the combo text with a scale effect
comboText.scale.x = 1.2;
comboText.scale.y = 1.2;
tween(comboText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8,
y: comboText.y - 60 // Move up as it fades but not as far
}, {
duration: 800,
easing: tween.easeOut
});
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
self.runFrames = ['turtle1', 'turtle2'];
self.sprites = [];
// Pre-attach all sprites
for (var i = 0; i < self.runFrames.length; i++) {
var sprite = self.attachAsset(self.runFrames[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
self.speed = 6 + Math.random() * 2;
self.passed = false;
self.isJumping = false;
self.velocityY = 0;
self.canHarmPlayer = true; // Flag to track if enemy can harm player
self.groundY = 2732 - 400; // 400 pixels from bottom
self.y = self.groundY; // Set initial position to ground level
self.runFrameIndex = 0;
self.runFrameCounter = 0;
self.runFrameDelay = 15;
self.showFrame = function (index) {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Show the appropriate sprite
self.sprites[index].alpha = 1;
};
self.update = function () {
// Calculate base speed
var currentSpeed = self.speed + Math.floor(LK.ticks / 300) * 0.2; // Increase speed over time faster
// Double speed during star power
if (starPowerActive) {
currentSpeed *= 2;
}
self.x -= currentSpeed;
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.5; // Gravity effect
if (self.y > 2732) {
self.destroy();
}
} else {
self.runFrameCounter++;
if (self.runFrameCounter >= self.runFrameDelay) {
self.runFrameIndex = (self.runFrameIndex + 1) % self.runFrames.length;
self.showFrame(self.runFrameIndex);
self.runFrameCounter = 0;
}
}
if (self.x < -100) {
self.destroy();
}
};
});
var FlyKoopa = Container.expand(function () {
var self = Container.call(this);
self.runFrames = ['flykoopa1', 'flykoopa2'];
self.sprites = [];
// Pre-attach all sprites
for (var i = 0; i < self.runFrames.length; i++) {
var sprite = self.attachAsset(self.runFrames[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
self.speed = 4 + Math.random() * 2;
self.runFrameIndex = 0;
self.runFrameCounter = 0;
self.runFrameDelay = 15;
self.isJumping = false;
self.velocityY = 0;
self.canHarmPlayer = true; // Flag to track if enemy can harm player
self.showFrame = function (index) {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Show the appropriate sprite
self.sprites[index].alpha = 1;
};
self.update = function () {
// Increase speed over time, up to a reasonable maximum
self.speed = 4 + Math.random() * 2 + Math.min(6, Math.floor(LK.ticks / 300) * 0.3);
// Double speed during star power
if (starPowerActive) {
self.speed *= 2;
}
self.x -= self.speed;
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.5; // Gravity effect
if (self.y > 2732) {
self.destroy();
}
} else {
self.runFrameCounter++;
if (self.runFrameCounter >= self.runFrameDelay) {
self.runFrameIndex = (self.runFrameIndex + 1) % self.runFrames.length;
self.showFrame(self.runFrameIndex);
self.runFrameCounter = 0;
}
}
if (self.x < -100) {
self.destroy();
}
};
});
var Goomba = Container.expand(function () {
var self = Container.call(this);
self.runFrames = ['goomba1', 'goomba2'];
self.sprites = [];
// Pre-attach all sprites
for (var i = 0; i < self.runFrames.length; i++) {
var sprite = self.attachAsset(self.runFrames[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
self.speed = 4 + Math.random() * 2;
self.passed = false;
self.isJumping = false;
self.velocityY = 0;
self.canHarmPlayer = true; // Flag to track if enemy can harm player
self.groundY = 2732 - 400; // 400 pixels from bottom
self.y = self.groundY; // Set initial position to ground level
self.runFrameIndex = 0;
self.runFrameCounter = 0;
self.runFrameDelay = 15;
self.showFrame = function (index) {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Show the appropriate sprite
self.sprites[index].alpha = 1;
};
self.update = function () {
// Increase speed over time, up to a reasonable maximum
self.speed = 4 + Math.random() * 2 + Math.min(6, Math.floor(LK.ticks / 300) * 0.3);
// Double speed during star power
if (starPowerActive) {
self.speed *= 2;
}
self.x -= self.speed;
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.5; // Gravity effect
if (self.y > 2732) {
self.destroy();
}
} else {
self.runFrameCounter++;
if (self.runFrameCounter >= self.runFrameDelay) {
self.runFrameIndex = (self.runFrameIndex + 1) % self.runFrames.length;
self.showFrame(self.runFrameIndex);
self.runFrameCounter = 0;
}
}
if (self.x < -100) {
self.destroy();
}
};
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Add background image
var background = self.attachAsset('background3', {
anchorX: 0,
anchorY: 0
});
// Title text
var titleText = new Text2('OG Mario\nVs\nMonsters', {
size: 180,
fill: 0xD94A38,
//{3t} // NES Mario brick-red color
font: "'Press Start 2P', monospace",
align: 'center',
// Add text alignment directly in the options
stroke: 0xFFFFFF,
// White border
strokeThickness: 8 // Border thickness
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 4; // Position higher on screen
self.addChild(titleText);
// No subtitle text
// Play button
var playButton = new Text2('TAP TO START', {
size: 120,
fill: 0xFCA817,
// NES Mario gold coin color
font: "'Press Start 2P', monospace",
stroke: 0xFFFFFF,
// Add white border
strokeThickness: 6 // Set border thickness
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 2048 / 2;
playButton.y = 2732 / 2; // Centered vertically
self.addChild(playButton);
// Make the play button "pulse" for attention
self.animationCounter = 0;
self.update = function () {
self.animationCounter += 0.05;
playButton.scale.x = 1 + Math.sin(self.animationCounter) * 0.1;
playButton.scale.y = 1 + Math.sin(self.animationCounter) * 0.1;
};
// Handle button clicks
self.down = function (x, y, obj) {
// Default behavior - start game
if (self.onPlayClick) {
self.onPlayClick();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
self.runAnimation = ['player_run1', 'player_run2', 'player_run3'];
self.jumpAnimation = ['player_jump'];
self.currentState = 'running';
self.sprites = [];
self.runFrame = 0;
self.jumpFrame = 0;
self.animationCounter = 0;
self.animationSpeed = 0.1;
// Pre-attach all sprites
for (var i = 0; i < self.runAnimation.length; i++) {
var sprite = self.attachAsset(self.runAnimation[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
for (var j = 0; j < self.jumpAnimation.length; j++) {
var jumpSprite = self.attachAsset(self.jumpAnimation[j], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
jumpSprite.alpha = 0;
self.sprites.push(jumpSprite);
}
self.speed = 5; // Base speed, will increase in update function
self.jumpHeight = 25;
self.isJumping = false;
self.canDoubleJump = false; // Track if double jump is available
self.hasDoubleJumped = false; // Track if double jump was used
self.isDashing = false; // Track if player is currently dashing
self.isInvincible = false; // Track if player is invincible
self.dashCooldown = false; // Dash cooldown
self.swipeStartX = null; // Track swipe start position
self.swipeStartY = null;
self.velocityY = 0;
self.groundY = 2732 - 400; // 400 pixels from bottom
self.y = self.groundY; // Set initial position to ground level
self.runFrameDelay = 10;
self.showFrame = function (frameType, index) {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Show the appropriate sprite based on state and frame index
if (frameType === 'run') {
self.sprites[index].alpha = 1;
} else if (frameType === 'jump') {
self.sprites[self.runAnimation.length + index].alpha = 1;
}
};
// Dash functionality removed
// Swipe handling removed
self.down = function (x, y, obj) {
// Down handler simplified, no swipe tracking
};
self.up = function (x, y, obj) {
// Up handler simplified, no swipe handling
};
self.move = function (x, y, obj) {
// Move handler simplified, no swipe detection
};
self.update = function () {
// Update player speed based on game progress and background speed
// Use background speed as base for player speed scaling if available
var speedMultiplier = 1;
if (game.background && game.background.speed) {
speedMultiplier = game.background.speed / 3;
}
self.speed = 5 + Math.min(5, Math.floor(LK.ticks / 300) * 0.3 * speedMultiplier);
// Make player blink fast during star power
if (starPowerActive) {
// Cancel any existing tween on player
tween.stop(self);
// Use tween to create a more advanced flashing effect with color changes
if (!self.starTweenActive) {
var _flashNextColor = function flashNextColor() {
// Apply the next color in the sequence
tween(self, {
tint: colors[colorIndex]
}, {
duration: 150,
// Fast color transitions
easing: tween.linear,
onFinish: function onFinish() {
// Cycle to the next color
colorIndex = (colorIndex + 1) % colors.length;
// Continue the cycle if star power is still active
if (starPowerActive) {
_flashNextColor();
} else {
self.tint = 0xFFFFFF; // Reset tint when star power ends
self.starTweenActive = false;
}
}
});
}; // Start the flash sequence
self.starTweenActive = true;
// Create rapid color cycling effect
var colors = [0xFFFF00, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF00FF];
var colorIndex = 0;
_flashNextColor();
}
} else {
// Ensure player is fully visible when star power ends
self.alpha = 1;
self.tint = 0xFFFFFF; // Reset tint
self.starTweenActive = false;
}
if (self.isJumping) {
self.y += self.velocityY;
// Scale gravity based on game speed - faster speed = faster falling
var gravityMultiplier = speedMultiplier > 1 ? speedMultiplier * 0.8 : 1;
self.velocityY += 0.3 * gravityMultiplier;
// Show jump sprite
self.showFrame('jump', 0);
if (self.y >= self.groundY - 30) {
if (self.y < 0) {
// Prevent jump from exceeding the top of the screen
self.y = 0;
self.velocityY = 0;
}
if (!self.isDead) {
self.y = self.groundY - 30;
self.isJumping = false;
self.hasDoubleJumped = false; // Reset double jump when landing
self.velocityY = 0;
self.currentState = 'running';
// Reset combo state when landing
if (comboActive) {
comboActive = false;
// comboCount will be reset to 0 when the next combo starts
// No need to display combo here, it's shown on each stomp
// No need to manage comboDisplayObj here anymore
}
}
}
} else {
// Running animation
self.animationCounter += self.animationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.runFrame = (self.runFrame + 1) % self.runAnimation.length;
self.showFrame('run', self.runFrame);
}
}
};
self.jump = function () {
// Get speed multiplier based on background speed
var speedMultiplier = 1;
if (game.background && game.background.speed) {
speedMultiplier = game.background.speed / 3;
}
// Increase jump height slightly with game speed to help player clear obstacles
var jumpHeightMultiplier = Math.min(1.3, 1 + (speedMultiplier - 1) * 0.3);
// Regular jump when not jumping
if (!self.isJumping) {
self.isJumping = true;
LK.getSound('jump').play();
self.velocityY = -self.jumpHeight * jumpHeightMultiplier;
self.currentState = 'jumping';
self.showFrame('jump', 0);
}
// Double jump when already jumping (always available)
else if (self.isJumping && !self.hasDoubleJumped) {
LK.getSound('jump').play();
self.velocityY = -self.jumpHeight * 0.8 * jumpHeightMultiplier; // Slightly lower second jump
self.hasDoubleJumped = true;
// No flash effect for double jump to make it distinct from dash
}
};
});
var Star = Container.expand(function () {
var self = Container.call(this);
// Use star asset directly instead of recoloring coin
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Set star color to bright yellow for emphasis
starGraphics.tint = 0xFFFF00;
self.speed = 3;
self.collected = false;
self.speed = 5; // Initial horizontal speed
self.velocityY = 0; // Vertical velocity for gravity/bouncing
self.gravity = 0.5; // Gravity strength
self.bounceVelocity = -12; // Upward velocity on bounce
self.groundY = 2732 - 400; // Ground level, same as player/enemies
self.y = 2732 - 600; // Initial Y position (can be adjusted)
self.collected = false;
// Oscillation tween removed
// Add animation (if needed later, currently unused)
self.animationCounter = 0;
self.update = function () {
if (!game.playerDead) {
// --- Horizontal Movement ---
// Increase base horizontal speed over time, matching background speed scaling
var baseSpeed = 5 + Math.min(8, Math.floor(LK.ticks / 300) * 0.3);
var currentSpeed = baseSpeed;
// Double speed during star power
if (starPowerActive) {
currentSpeed *= 2;
}
self.x -= currentSpeed;
// --- Vertical Movement (Gravity & Bouncing) ---
self.velocityY += self.gravity; // Apply gravity
self.y += self.velocityY; // Update vertical position
// Check for ground collision and bounce
if (self.y >= self.groundY) {
self.y = self.groundY; // Correct position to ground level
self.velocityY = self.bounceVelocity; // Apply bounce velocity upwards
}
} else {
// If player is dead, star just falls off screen (original simple fall)
self.y += self.velocityY;
self.velocityY += self.gravity; // Apply gravity even when player is dead
if (self.y > 2732 + 100) {
// Check slightly below screen bottom
self.destroy();
}
}
// --- Off-screen Check (Left Edge) ---
if (self.x < -100) {
// No tweens to stop anymore
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
// Helper function to adjust music playback rate as LK.setMusicPlaybackRate is not available
/****
*-Seperator-
****/
var game = new LK.Game({
backgroundColor: 0x5C94FC // NES Mario sky blue background color
});
/****
* Game Code
****/
// We can't use document.createElement in this environment
// Instead, we'll rely on the font already being available in the system
// or being loaded by the LK engine automatically
// No additional code needed for font loading in this environment
// Game state variables
// Helper function to adjust music playback rate as LK.setMusicPlaybackRate is not available
// The font 'Press Start 2P' is a web font that should be loaded from Google Fonts
// For reference: the font is used with font: "'Press Start 2P', monospace"
function setMusicPlaybackRate(rate) {
// Check if music is playing before trying to adjust it
// Use the sound API instead of the non-existent LK.getMusic function
var music = LK.getSound('theme');
if (music) {
// Set the playback rate if available on the audio element
if (music.playbackRate !== undefined) {
music.playbackRate = rate;
}
}
}
var gameStarted = false;
var showingUpgradeMenu = false;
var mainMenu;
var upgradeMenu;
var background;
var background2;
var player;
var enemies = [];
var enemySpawnInterval = 80;
var enemySpawnCounter = 0;
var coinObjects = []; // Renamed from 'coins' to avoid conflict with coin counter
var coinSpawnInterval = Math.max(40, 150 - Math.floor(LK.ticks / 300) * 2); // Decrease interval faster, minimum 40
var coinSpawnCounter = 0;
var stars = []; // Array to store star power-ups
var starSpawnInterval = 800; // Spawn stars less frequently than coins
var starSpawnCounter = 0;
var starPowerActive = false; // Track if star power is active
var starPowerDuration = 10 * 60; // 10 seconds at 60fps
var starPowerTimer = 0; // Timer for star power
// Combo system variables
var comboCount = 0;
var comboActive = false;
var comboDisplayObj = null;
// Score system
var score = 0;
var coins = storage.coins || 0; // Get persistent coin count
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFCE29F,
//{67} // NES light tan/cream color
font: "'Press Start 2P', monospace",
stroke: 0xFFFFFF,
// White border
strokeThickness: 4 // Border thickness
});
// Speed indicator removed from HUD
scoreText.anchor.set(1, 0);
scoreText.x = -50;
scoreText.y = 50;
LK.gui.topRight.addChild(scoreText);
// Coin count display
var coinText = new Text2('Coins: ' + coins, {
size: 50,
fill: 0xFCA817,
//{6d} // NES Mario gold coin color
// Gold color for coins
font: "'Press Start 2P', monospace",
stroke: 0xFFFFFF,
// White border
strokeThickness: 4 // Border thickness
});
coinText.anchor.set(1, 0);
coinText.x = -50;
coinText.y = 120; // Position below score
LK.gui.topRight.addChild(coinText);
// Combo indicator removed from HUD
scoreText.alpha = 0; // Hide score initially
coinText.alpha = 0; // Hide coin count initially
// Always enable double jump, no upgrades needed
storage.doubleJumpPurchased = true;
// Dash is removed
// Create parallax backgrounds for main menu animation
background = game.addChild(new Background());
background.x = 0;
background.y = 0;
background2 = game.addChild(new Background2());
background2.x = 2048;
background2.y = 0;
// Create automated player for main menu
var automatedPlayer = game.addChild(new AutomatedPlayer());
automatedPlayer.x = -100;
// Show main menu with elements on top of background
mainMenu = game.addChild(new MainMenu());
// Animate title text with tween
// First position title off-screen at the top
if (mainMenu.children && mainMenu.children[1]) {
var titleText = mainMenu.children[1]; // Get the title text
titleText.y = -200; // Start from above the screen
// Animate title dropping from top
tween(titleText, {
y: 2732 / 4 // Final position (center)
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add shake effect after dropping
var originalX = titleText.x;
var originalY = titleText.y;
var shakeCount = 0;
var maxShakes = 5;
function shakeTitle() {
// Shake in random direction
var shakeX = originalX + (Math.random() * 40 - 20);
var shakeY = originalY + (Math.random() * 20 - 10);
tween(titleText, {
x: shakeX,
y: shakeY
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
shakeCount++;
if (shakeCount < maxShakes) {
shakeTitle(); // Continue shaking
} else {
// Return to original position
tween(titleText, {
x: originalX,
y: originalY
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
// Start playing game theme music
LK.playMusic('theme');
// Drop the automated player from top if it exists
if (automatedPlayer && automatedPlayer.groundY !== undefined) {
tween(automatedPlayer, {
y: automatedPlayer.groundY - 30
}, {
duration: 1000,
easing: tween.bounceOut
});
}
}
});
}
}
});
}
shakeTitle(); // Start the shake sequence
}
});
}
mainMenu.onPlayClick = function () {
// Start the game
gameStarted = true;
if (mainMenu) {
// Add null check before destroying
mainMenu.destroy();
mainMenu = null;
}
// Initialize game elements - handled in game.down
};
game.update = function () {
// Handle menu states
if (!gameStarted) {
// When in menu mode, update backgrounds for parallax effect and menu
if (background) {
background.update();
}
if (background2) {
background2.update();
}
// Update automated player if it exists
if (typeof automatedPlayer !== 'undefined' && automatedPlayer) {
automatedPlayer.update();
}
// Update the menu
if (mainMenu) {
mainMenu.update();
}
return;
}
// Game hasn't been initialized yet - start it
if (!player) {
// Initialize game elements
// Player and GUI should already be created in game.down
// Set background reference for other objects
game.background = background;
}
// Game play update logic
background.update();
background2.update();
player.update();
enemySpawnCounter++;
coinSpawnCounter++;
starSpawnCounter++;
// Handle star power-up timer
if (starPowerActive) {
starPowerTimer--;
if (starPowerTimer <= 0) {
starPowerActive = false;
player.isInvincible = false;
// Return background tint to normal
background.sprites[0].tint = 0xFFFFFF;
background2.sprites[0].tint = 0xFFFFFF;
// Switch back to regular theme music
LK.stopMusic();
LK.playMusic('theme');
}
}
if (coinSpawnCounter >= coinSpawnInterval) {
var coin = new Coin();
coin.x = 2048 + Math.random() * 200;
// Set a reasonable height range for coins (not too low, not too high)
coin.y = Math.max(300, Math.min(2732 - 600, Math.random() * (2732 - 800)));
coinObjects.push(coin);
game.addChild(coin);
coinSpawnCounter = 0;
}
// Spawn star power-ups occasionally, but only if star power is not active
if (starSpawnCounter >= starSpawnInterval && !starPowerActive) {
var star = new Star();
star.x = 2048 + Math.random() * 200;
// Set a reasonable height range for stars (not too low, not too high)
star.y = Math.max(300, Math.min(2732 - 600, Math.random() * (2732 - 800)));
stars.push(star);
game.addChild(star);
starSpawnCounter = 0;
starSpawnInterval = Math.floor(Math.random() * 300) + 300; // Random interval between 300-600 ticks
}
if (enemySpawnCounter >= enemySpawnInterval) {
var enemyType = Math.random() < 0.33 ? 'Enemy' : Math.random() < 0.5 ? 'Goomba' : 'FlyKoopa';
var enemy;
if (enemyType === 'Enemy') {
enemy = new Enemy();
} else if (enemyType === 'Goomba') {
enemy = new Goomba();
} else {
enemy = new FlyKoopa();
// Ensure FlyKoopas spawn in the middle to upper part of the screen, not too low
enemy.y = Math.max(300, Math.min(2732 - 600, Math.random() * (2732 - 800)));
}
enemy.x = 2048 + Math.random() * 200;
if (enemyType === 'FlyKoopa') {
// Height for FlyKoopa is already set earlier, no need to set it again
} else {
enemy.y = enemy.groundY; // Use groundY for initial position
}
enemies.push(enemy);
game.addChild(enemy);
enemySpawnInterval = Math.max(15, Math.floor(Math.random() * 100) + 60 - Math.floor(LK.ticks / 300) * 2); // Decrease interval faster, minimum 15
enemySpawnCounter = 0;
}
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
if (player.intersects(enemies[j])) {
if (starPowerActive && enemies[j].canHarmPlayer !== false) {
// Star power is active - instantly defeat enemy with special effect
enemies[j].velocityY = -15; // Stronger pop up effect for star power
enemies[j].isJumping = true;
enemies[j].canHarmPlayer = false;
LK.getSound('stomp').play();
// Create a sparkle effect
LK.effects.flashObject(enemies[j], 0xFFFF00, 300);
// Handle combo tracking - activate combo mode if not already active
if (!comboActive) {
comboActive = true;
comboCount = 0; // Start count at 0, first stomp makes it 1
}
// Increment combo count
comboCount++;
// Calculate score with combo bonus
var starEnemyPoints = 100 * comboCount; // Points scale with combo
score += starEnemyPoints;
// Display flash text for combo count if more than 1
if (comboCount > 1) {
// Create a *new* combo display object for each stomp in the combo
var currentComboDisplay = game.addChild(new ComboDisplay());
currentComboDisplay.x = enemies[j].x;
currentComboDisplay.y = enemies[j].y - 50;
currentComboDisplay.showCombo(comboCount, starEnemyPoints);
// We don't store this in the global comboDisplayObj anymore
}
scoreText.setText('Score: ' + score);
LK.setScore(score);
} else if (!player.isDead && player.isJumping && player.velocityY > 0 && player.y < enemies[j].y) {
// Player is falling and lands on enemy
enemies[j].velocityY = -10; // Pop up effect for enemy
player.velocityY = -15; // Bounce Mario upwards
LK.getSound('stomp').play(); // Play stomp sound
// Handle combo tracking - activate combo mode if not already active
if (!comboActive) {
comboActive = true;
comboCount = 0; // Start count at 0, first stomp makes it 1
}
// Increment combo count
comboCount++;
// Calculate score with combo bonus
var enemyPoints = 50 * comboCount; // Points scale with combo
score += enemyPoints;
// Display flash text for combo count if more than 1
if (comboCount > 1) {
// Create a *new* combo display object for each stomp in the combo
var currentComboDisplay = game.addChild(new ComboDisplay());
currentComboDisplay.x = enemies[j].x;
currentComboDisplay.y = enemies[j].y - 50;
currentComboDisplay.showCombo(comboCount, enemyPoints);
// We don't store this in the global comboDisplayObj anymore
}
scoreText.setText('Score: ' + score);
LK.setScore(score);
enemies[j].isJumping = true;
enemies[j].canHarmPlayer = false; // Enemy can no longer harm player
} else if (enemies[j].canHarmPlayer !== false && !player.isInvincible) {
if (!player.isDead && enemies[j].canHarmPlayer !== false) {
LK.getSound('dead').play(); // Play dead sound
player.isDead = true;
game.playerDead = true;
player.velocityY = -10; // Pop up effect similar to enemy
player.isJumping = true;
LK.setTimeout(function () {
// Save final score before game over
LK.setScore(score);
LK.showGameOver();
}, 3000); // Delay game over by 3 seconds
}
}
} else if (player.x > enemies[j].x && !enemies[j].passed) {
enemies[j].passed = true;
}
if (enemies[j].x < -100) {
enemies.splice(j, 1);
}
}
for (var k = coinObjects.length - 1; k >= 0; k--) {
coinObjects[k].update();
if (player.intersects(coinObjects[k])) {
if (!coinObjects[k].collected) {
coinObjects[k].collected = true;
LK.getSound('Coin').play(); // Play coin sound
// Increase score when collecting coins
score += 10;
// Separate coin counter
coins++;
// Update storage for persistence
storage.coins = coins;
// Update displays
scoreText.setText('Score: ' + score);
coinText.setText('Coins: ' + coins);
LK.setScore(score);
// Create a coin pickup effect
// Visual effects for coin collection - similar to star power but smaller
LK.effects.flashObject(player, 0xFCA817, 300); // Gold flash
// Create a coin burst effect
for (var i = 0; i < 8; i++) {
var angle = i / 8 * Math.PI * 2;
var distance = 60;
var particleX = coinObjects[k].x + Math.cos(angle) * distance;
var particleY = coinObjects[k].y + Math.sin(angle) * distance;
var particle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4,
x: coinObjects[k].x,
y: coinObjects[k].y,
alpha: 0.8
});
particle.tint = 0xFCA817; // Gold tint
game.addChild(particle);
// Animate particles outward
tween(particle, {
x: particleX,
y: particleY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800,
easing: tween.easeOut
});
// Remove particles after animation
LK.setTimeout(function (p) {
return function () {
if (p && p.parent) {
p.parent.removeChild(p);
}
};
}(particle), 800);
}
coinObjects[k].destroy();
coinObjects.splice(k, 1);
}
}
}
// Update and check star power-ups
for (var s = stars.length - 1; s >= 0; s--) {
stars[s].update();
if (player.intersects(stars[s])) {
if (!stars[s].collected) {
stars[s].collected = true;
// Switch music to star power theme
LK.stopMusic();
LK.playMusic('starman2');
// Activate star power
starPowerActive = true;
starPowerTimer = starPowerDuration;
player.isInvincible = true;
// Visual effects for star power
LK.effects.flashObject(player, 0xFFFF00, 500); // Yellow flash
// Create a star burst effect
for (var i = 0; i < 12; i++) {
var angle = i / 12 * Math.PI * 2;
var distance = 100;
var particleX = player.x + Math.cos(angle) * distance;
var particleY = player.y + Math.sin(angle) * distance;
var particle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: player.x,
y: player.y,
alpha: 0.8
});
particle.tint = 0xFFFF00; // Yellow tint
game.addChild(particle);
// Animate particles outward
tween(particle, {
x: particleX,
y: particleY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut
});
// Remove particles after animation
LK.setTimeout(function (p) {
return function () {
if (p && p.parent) {
p.parent.removeChild(p);
}
};
}(particle), 1000);
}
// Change background tint for star power effect
if (background.sprites && background.sprites.length > 0) {
background.sprites[0].tint = 0xFFFFAA; // Slight yellow tint
}
if (background2.sprites && background2.sprites.length > 0) {
background2.sprites[0].tint = 0xFFFFAA; // Slight yellow tint
}
// Add extra points for star
score += 100;
scoreText.setText('Score: ' + score);
LK.setScore(score);
// Remove the star
stars[s].destroy();
stars.splice(s, 1);
}
} else if (stars[s].x < -100) {
stars[s].destroy();
stars.splice(s, 1);
}
}
// Update speed display and music speed
if (background && !game.playerDead) {
var speedMultiplier = (background.speed / 3).toFixed(1);
// Speed text update removed
// Combo text update removed
// Adjust music playback rate based on game speed
var musicPlaybackRate = Math.min(1.5, 0.8 + background.speed / 3 * 0.2);
// Increase music speed during star power
if (starPowerActive) {
musicPlaybackRate = Math.min(2.0, musicPlaybackRate * 1.2);
}
setMusicPlaybackRate(musicPlaybackRate);
}
};
game.down = function (x, y, obj) {
if (!gameStarted) {
// Transition to game on tap
gameStarted = true;
if (mainMenu && mainMenu.destroy) {
mainMenu.destroy();
mainMenu = null;
}
if (typeof automatedPlayer !== 'undefined' && automatedPlayer) {
automatedPlayer.destroy();
automatedPlayer = null;
}
// Background will be kept and reused for actual gameplay
// We don't need to initialize background in the game.update function
// since we already have it
// Show score and coin count
scoreText.alpha = 1;
coinText.alpha = 1;
// Create player
player = game.addChild(new Player());
player.x = 2048 / 4;
player.y = player.groundY - 30;
return;
} else {
// Pass event to player
player.down(x, y, obj);
// In-game tap makes player jump
player.jump();
}
};
game.up = function (x, y, obj) {
if (!gameStarted) {
return;
}
// Pass touch up event to player
if (player) {
player.up(x, y, obj);
}
};
game.move = function (x, y, obj) {
if (!gameStarted) {
return;
}
// Pass touch move event to player
if (player) {
player.move(x, y, obj);
}
}; ===================================================================
--- original.js
+++ change.js
@@ -651,16 +651,16 @@
/****
* Game Code
****/
-// For reference: the font is used with font: "'Press Start 2P', monospace"
-// The font 'Press Start 2P' is a web font that should be loaded from Google Fonts
-// Helper function to adjust music playback rate as LK.setMusicPlaybackRate is not available
-// Game state variables
-// No additional code needed for font loading in this environment
-// or being loaded by the LK engine automatically
-// Instead, we'll rely on the font already being available in the system
// We can't use document.createElement in this environment
+// Instead, we'll rely on the font already being available in the system
+// or being loaded by the LK engine automatically
+// No additional code needed for font loading in this environment
+// Game state variables
+// Helper function to adjust music playback rate as LK.setMusicPlaybackRate is not available
+// The font 'Press Start 2P' is a web font that should be loaded from Google Fonts
+// For reference: the font is used with font: "'Press Start 2P', monospace"
function setMusicPlaybackRate(rate) {
// Check if music is playing before trying to adjust it
// Use the sound API instead of the non-existent LK.getMusic function
var music = LK.getSound('theme');
@@ -684,9 +684,9 @@
var coinObjects = []; // Renamed from 'coins' to avoid conflict with coin counter
var coinSpawnInterval = Math.max(40, 150 - Math.floor(LK.ticks / 300) * 2); // Decrease interval faster, minimum 40
var coinSpawnCounter = 0;
var stars = []; // Array to store star power-ups
-var starSpawnInterval = 500; // Spawn stars less frequently than coins
+var starSpawnInterval = 800; // Spawn stars less frequently than coins
var starSpawnCounter = 0;
var starPowerActive = false; // Track if star power is active
var starPowerDuration = 10 * 60; // 10 seconds at 60fps
var starPowerTimer = 0; // Timer for star power