/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Define a class for enemies
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(enemyType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.enemyType = enemyType;
// Apply spinning animation to 'ls' enemy type
if (enemyType === 'ls') {
// Start spinning animation in left (counter-clockwise) direction
tween(enemyGraphics, {
rotation: Math.PI * 2 * -1 // Negative for left/counter-clockwise direction
}, {
duration: 2000,
// 2 seconds for a full rotation
easing: tween.linear,
repeat: Infinity,
// Use Infinity instead of loop: true for continuous spinning
loop: true // Continuous spinning
});
}
self.update = function () {
// Special behavior for ls asset - bounce down from top right
if (self.enemyType === 'ls') {
// Add vertical movement properties first time
if (self.verticalSpeed === undefined) {
self.verticalSpeed = 3; // Initial downward speed
self.gravity = 0.1; // Gravity effect
self.bounceStrength = 2; // How strong the bounce is
// Start from top-right corner
self.y = 100; // Near top
self.x = 2048 + 100; // Off right edge
}
// Track if this asset is in the spinning out state
if (self.spinningOut) {
// Move toward right top corner
var targetX = 2048 + 200;
var targetY = -200;
// Calculate direction vector
var dirX = targetX - self.x;
var dirY = targetY - self.y;
// Normalize and apply speed
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > 0) {
dirX = dirX / length * (self.spinSpeed || 15);
dirY = dirY / length * (self.spinSpeed || 15);
}
// Move toward target
self.x += dirX;
self.y += dirY;
// Increase rotation speed
self.children[0].rotation += 0.2;
} else {
// Normal behavior when not spinning out
// Apply gravity to vertical speed
self.verticalSpeed += self.gravity;
self.y += self.verticalSpeed;
// Bounce when hitting bottom at 3/4 of the screen height instead of center
if (self.y > 2732 * 0.75) {
// Bounce at 3/4 screen height
self.y = 2732 * 0.75;
self.verticalSpeed = -self.verticalSpeed * (self.bounceStrength * 0.3); // Even lower bounce power
// Reduce bounce strength much more quickly
self.bounceStrength *= 0.5;
}
// Horizontal movement
self.x -= self.speed;
}
} else if (self.enemyType === 'enemy3') {
// Special behavior for enemy3 - attack from right bottom corner
if (self.initialPosition === undefined) {
// Set initial position at right bottom corner
self.x = 2048 + 100; // Off right edge
self.y = 2732 - 550; // Bottom of screen with small margin, moved up by 450 units
self.initialPosition = true;
}
// Move diagonally up-left (towards Mario)
self.x -= self.speed * 1.2;
self.y -= self.speed * 0.6;
} else {
// Original behavior for other enemy types
self.x -= self.speed;
}
// Destroy when off screen
if (self.x < -50) {
self.destroy();
}
};
return self; // Return self to make the class inheritable
});
// Define a class for displaying the God Mode text
var GodModeText = Container.expand(function () {
var self = Container.call(this);
// Create the text
var godModeText = new Text2('GOD MODE', {
size: 80,
fill: 0xFF8C00 // Orange color
});
godModeText.anchor.set(0.5, 0.5);
self.addChild(godModeText);
// Initialize with invisible state
godModeText.alpha = 0;
// Create timer text
var timerText = new Text2('', {
size: 80,
fill: 0xFF8C00 // Orange color for timer
});
timerText.anchor.set(0.5, 0.5);
timerText.y = 80; // Position below the GOD MODE text
self.addChild(timerText);
// Initialize timer value
self.timerValue = 5; // 5 seconds duration
self.timerInterval = null;
// Method to show the animation
self.showAnimation = function () {
// Play god mode sound
LK.getSound('godmode').play();
// Stop any existing animations
tween.stop(godModeText);
// Reset and start the timer
self.timerValue = 5;
timerText.setText(self.timerValue);
timerText.alpha = 1;
// Clear any existing timer
if (self.timerInterval) {
LK.clearInterval(self.timerInterval);
}
// Start countdown timer
self.timerInterval = LK.setInterval(function () {
self.timerValue -= 1;
if (self.timerValue > 0) {
timerText.setText(self.timerValue);
} else if (self.timerValue === 0) {
timerText.setText(self.timerValue);
LK.clearInterval(self.timerInterval);
self.timerInterval = null;
}
}, 1000);
// Animate in with fireflame effect
godModeText.tint = 0xFF5500; // Orange-red fire color
tween(godModeText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Create flickering flame animation
function fireflameFlicker() {
// Random fire colors between orange-red and yellow
var fireColors = [0xFF5500, 0xFF8800, 0xFFAA00, 0xFFFF00];
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
// Random scale for fire flicker effect
var randomScale = 1.0 + Math.random() * 0.3;
// Apply the flame effect
tween(godModeText, {
tint: randomColor,
scaleX: randomScale,
scaleY: randomScale,
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 100 + Math.random() * 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Continue the flame effect if still visible
if (godModeText.alpha > 0) {
fireflameFlicker();
}
}
});
}
// Start the flame flicker effect
fireflameFlicker();
// Hide after 3 seconds
LK.setTimeout(function () {
// Stop the pulse animation
tween.stop(godModeText);
// Stop and hide the timer
if (self.timerInterval) {
LK.clearInterval(self.timerInterval);
self.timerInterval = null;
}
tween(timerText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
// Animate out
tween(godModeText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
}, 3000);
}
});
};
return self;
});
// Define a class for the life counter
var LifeCounter = Container.expand(function () {
var self = Container.call(this);
// Create a simple white line instead of using an asset
var lineGraphics = LK.getAsset('enemy2', {
anchorX: 0.0,
anchorY: 0.0,
scaleX: 2048,
scaleY: 10,
tint: 0xFFFFFF // White color
});
self.addChild(lineGraphics);
self.width = 2048; // Full width
self.update = function () {
// Update the width of the line based on Mario's life
if (game.Mario) {
lineGraphics.scale.x = 2048 * game.Mario.life;
}
};
});
// Define a class for the dragon ball lightning effect
var LightningEffect = Container.expand(function () {
var self = Container.call(this);
// Set active status flag
self.isActive = false;
// Create lightning bolts
self.bolts = [];
var colors = [0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00];
// Create multiple lightning bolts around Mario
for (var i = 0; i < 5; i++) {
var bolt = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25 + Math.random() * 10,
scaleY: 25 + Math.random() * 10
});
bolt.tint = colors[Math.floor(Math.random() * colors.length)];
bolt.alpha = 0; // Start with invisible bolts
bolt.rotation = Math.random() * Math.PI * 2;
bolt.distance = 80 + Math.random() * 40;
bolt.speed = 0.1 + Math.random() * 0.1;
bolt.originalScale = {
x: bolt.scale.x,
y: bolt.scale.y
};
self.bolts.push(bolt);
}
// Animate the lightning
self.animate = function () {
// Stop any existing animations
for (var i = 0; i < self.bolts.length; i++) {
tween.stop(self.bolts[i]);
}
// Start new animations
for (var i = 0; i < self.bolts.length; i++) {
var bolt = self.bolts[i];
// Randomize the bolt appearance
bolt.rotation = Math.random() * Math.PI * 2;
bolt.scale.x = bolt.originalScale.x * (0.8 + Math.random() * 0.4);
bolt.scale.y = bolt.originalScale.y * (0.8 + Math.random() * 0.4);
// Animate the bolt with pulse effect
tween(bolt, {
alpha: 0.2 + Math.random() * 0.5,
scaleX: bolt.originalScale.x * (0.7 + Math.random() * 0.6),
scaleY: bolt.originalScale.y * (0.7 + Math.random() * 0.6)
}, {
duration: 300 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function () {
// Create a callback closure to maintain the correct bolt reference
var currentBolt = bolt;
return function () {
// Animate back
tween(currentBolt, {
alpha: 0.6 + Math.random() * 0.4,
scaleX: currentBolt.originalScale.x * (0.9 + Math.random() * 0.3),
scaleY: currentBolt.originalScale.y * (0.9 + Math.random() * 0.3)
}, {
duration: 300 + Math.random() * 400,
easing: tween.easeIn
});
};
}()
});
}
};
self.update = function () {
// Position the lightning bolts around Mario
for (var i = 0; i < self.bolts.length; i++) {
var bolt = self.bolts[i];
var angle = bolt.rotation + self.parent.rotation + bolt.speed * LK.ticks;
bolt.x = Math.cos(angle) * bolt.distance;
bolt.y = Math.sin(angle) * bolt.distance;
// Make bolts invisible when effect is not active
if (!self.isActive) {
bolt.alpha = 0;
}
// Ensure bolts remain visible when effect is active
else if (self.isActive && bolt.alpha < 0.7) {
bolt.alpha = 0.7 + Math.random() * 0.3;
}
}
// Periodically refresh animations only when not in active state
if (LK.ticks % 30 === 0 && self.isActive) {
self.animate();
}
};
return self;
});
//<Assets used in the game will automatically appear here>
// Define a class for the player character
var Player = Container.expand(function (characterType) {
var self = Container.call(this);
var assetType = characterType === 'YM' ? 'YM' : characterType === 'MB' ? 'MB' : 'Mario';
var MarioGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
// Add the lightning effect
self.lightning = self.addChild(new LightningEffect());
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.7; // Decreased gravity effect by 30%
if (self.y >= 2732 / 2) {
// Ground level
self.y = 2732 / 2;
self.isJumping = false;
self.velocityY = 0;
}
}
// Update the lightning effect
if (self.lightning) {
self.lightning.update();
}
};
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.velocityY = -self.jumpHeight;
// Play jump sound
LK.getSound('jump').play();
// Activate lightning effect animation with a more intense glow when jumping, but only if lightning is already active
if (self.lightning && self.lightning.isActive) {
// Intensify the lightning effect
for (var i = 0; i < self.lightning.bolts.length; i++) {
var bolt = self.lightning.bolts[i];
tween(bolt, {
alpha: 0.9,
scaleX: bolt.originalScale.x * 1.5,
scaleY: bolt.originalScale.y * 1.5
}, {
duration: 300,
easing: tween.elasticOut
});
}
// Reset to normal after a short time
LK.setTimeout(function () {
self.lightning.animate();
}, 500);
}
}
};
});
// Define a class for power-ups
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.floatOffset = 0;
self.collected = false;
// Make power-up glow with tween animation and add shiny flashing effect
tween(powerGraphics, {
alpha: 0.7,
tint: 0xffffff
}, {
duration: 1000,
easing: tween.sinusoidalInOut,
loop: true,
yoyo: true
});
// Add shiny flashing effect
function createShinyEffect() {
// Tween to bright yellow-white (shiny effect)
tween(powerGraphics, {
tint: 0xffffff,
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Tween back to normal gold
tween(powerGraphics, {
tint: 0xffd700,
alpha: 0.8,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 250,
easing: tween.easeIn,
onFinish: function onFinish() {
// Schedule next flash after a shorter random delay
LK.setTimeout(createShinyEffect, 300 + Math.random() * 400);
}
});
}
});
}
// Start the shiny effect sequence
LK.setTimeout(createShinyEffect, 200 + Math.random() * 300);
self.update = function () {
// Move power-up from right to left
self.x -= self.speed;
// Floating up and down motion
self.floatOffset += 0.05;
self.y = self.originalY + Math.sin(self.floatOffset) * 20;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
};
return self;
});
// Define a class for displaying the SHARKNADO title
var SharknadoTitle = Container.expand(function () {
var self = Container.call(this);
// Create the text with chrome-silver-black styling
var sharknadoText = new Text2('SHARKNADO!', {
size: 240,
fill: 0xDDDDDD,
// Silver base color
dropShadow: true,
dropShadowColor: 0x333333,
// Dark shadow for 3D effect
dropShadowDistance: 3
});
// Set anchor to center horizontally
sharknadoText.anchor.set(0.5, 0.5);
self.addChild(sharknadoText);
// Initialize as invisible
self.visible = false;
// Method to show the title
self.show = function () {
if (self.visible) return; // Already visible
self.visible = true;
// Clear any existing animations
tween.stop(sharknadoText);
// Reset and animate in
sharknadoText.alpha = 0;
sharknadoText.scale.set(0.5, 0.5);
// Track original position for shake effect
self.originalX = self.x;
self.originalY = self.y;
// Animate in with chrome shine effect
tween(sharknadoText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Add pulsing animation
tween(sharknadoText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.sinusoidalInOut,
yoyo: true,
loop: true
});
// Start shaking animation
self.startShaking();
}
});
};
// Method to hide the title
self.hide = function () {
if (!self.visible) return; // Already hidden
// Stop any existing animations
tween.stop(sharknadoText);
// Stop shaking
self.stopShaking();
// Animate out
tween(sharknadoText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.visible = false;
}
});
};
// Start shaking animation for SHARKNADO title
self.startShaking = function () {
// Clear any existing shake interval
self.stopShaking();
// Create new shake interval
self.shakeInterval = LK.setInterval(function () {
// Random offset for shake effect (more horizontal than vertical)
var offsetX = (Math.random() - 0.5) * 20; // -10 to +10 pixels
var offsetY = (Math.random() - 0.5) * 10; // -5 to +5 pixels
// Apply shake
self.x = self.originalX + offsetX;
self.y = self.originalY + offsetY;
// Apply slight rotation for more dramatic effect
sharknadoText.rotation = (Math.random() - 0.5) * 0.05; // Small random rotation
}, 50); // Shake every 50ms for realistic earthquake effect
};
// Stop shaking animation
self.stopShaking = function () {
if (self.shakeInterval) {
LK.clearInterval(self.shakeInterval);
self.shakeInterval = null;
// Reset position and rotation
if (self.originalX !== undefined) {
self.x = self.originalX;
self.y = self.originalY;
sharknadoText.rotation = 0;
}
}
};
return self;
});
// Define a class for the TB popup
var TbPopup = Container.expand(function () {
var self = Container.call(this);
// Get TB asset
var tbGraphics = self.attachAsset('tb', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize as invisible
self.alpha = 0;
self.visible = false;
// Method to show the popup
self.show = function () {
if (self.visible) return; // Already visible
// Stop any existing animations
tween.stop(self);
// Reset and make visible
self.visible = true;
self.scale.set(0.2, 0.2);
// Animate in
tween(self, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.elasticOut
});
};
// Method to hide the popup
self.hide = function () {
if (!self.visible) return; // Already hidden
// Animate out
tween(self, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.visible = false;
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// All references to 'Mri' asset have been renamed to 'MB'
//<Assets used in the game will automatically appear here>
game.lastSpawnTime = 0;
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Play background music
LK.playMusic('music1', {
loop: true
});
// Character selection menu implementation
var characterSelectionContainer = new Container();
characterSelectionContainer.x = 2048 / 2;
characterSelectionContainer.y = 2732 / 2;
game.addChild(characterSelectionContainer);
// Dim background overlay
var overlay = LK.getAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2048,
scaleY: 2732,
tint: 0x000000,
alpha: 0.7
});
characterSelectionContainer.addChild(overlay);
// Title text
var selectText = new Text2('Select Your Character', {
size: 120,
fill: 0xFFFFFF
});
selectText.anchor.set(0.5, 0.5);
selectText.y = -400;
characterSelectionContainer.addChild(selectText);
// (Mario option removed)
// MB option
var mbOption = LK.getAsset('MB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
mbOption.x = 0;
mbOption.y = 0;
characterSelectionContainer.addChild(mbOption);
var mbLabel = new Text2('MB', {
size: 70,
fill: 0xFFFFFF
});
mbLabel.anchor.set(0.5, 0);
mbLabel.x = mbOption.x;
mbLabel.y = 280;
characterSelectionContainer.addChild(mbLabel);
// YM option
var ymOption = LK.getAsset('YM', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
ymOption.x = 500;
ymOption.y = 0;
characterSelectionContainer.addChild(ymOption);
var ymLabel = new Text2('YM', {
size: 70,
fill: 0xFFFFFF
});
ymLabel.anchor.set(0.5, 0);
ymLabel.x = ymOption.x;
ymLabel.y = 280; // moved down by 100 units
characterSelectionContainer.addChild(ymLabel);
// Store selected character type
var selectedCharacterType = null;
// Helper to highlight selection
function highlightOption(option) {
mbOption.alpha = 0.7;
ymOption.alpha = 0.7;
option.alpha = 1.0;
}
// (Mario option event handler removed)
// Touch/click handlers for MB
mbOption.down = function (x, y, obj) {
highlightOption(mbOption);
selectedCharacterType = 'MB';
confirmButton.alpha = 1;
confirmButton.interactive = true;
};
// Touch/click handlers for YM
ymOption.down = function (x, y, obj) {
highlightOption(ymOption);
selectedCharacterType = 'YM';
confirmButton.alpha = 1;
confirmButton.interactive = true;
};
// Confirm button
var confirmButton = new Text2('Start Game', {
size: 90,
fill: 0x00FF00
});
confirmButton.anchor.set(0.5, 0.5);
confirmButton.y = 400;
confirmButton.alpha = 0.5;
confirmButton.interactive = false;
characterSelectionContainer.addChild(confirmButton);
// Confirm button handler
confirmButton.down = function (x, y, obj) {
if (!selectedCharacterType) return;
// Remove menu
characterSelectionContainer.destroy();
// Proceed to game setup
setupPlayer(selectedCharacterType);
};
// Add down event listeners
mbOption.interactive = true;
ymOption.interactive = true;
confirmButton.interactive = false;
// Setup player function
function setupPlayer(characterType) {
// Initialize player with selected character
var Mario = game.addChild(new Player(characterType));
Mario.x = 2048 / 2 - 200;
Mario.y = 2732 / 2;
Mario.life = 1;
// Store reference globally for other code
game.Mario = Mario;
// Update all references in game code to use game.Mario if needed
}
// Patch Player class to accept characterType
// (see Classes section for Player class patch)
// Initialize the life counter and add it to the game
var lifeCounter = game.addChild(new LifeCounter());
lifeCounter.y = 0; // Position it at the top of the screen
// Create TB popup for enemy3
var tbPopup = game.addChild(new TbPopup());
tbPopup.x = 160; // Position on the left side, moved left by 40 units
tbPopup.y = 2732 / 2 - 777; // Center vertically, then move up by 777 units
// Create life percentage text
var lifePercentText = new Text2('100%', {
size: 40,
fill: 0x7FFF00 // Bright neon green to match the life bar
});
// Add the life percentage text to the GUI
LK.gui.topRight.addChild(lifePercentText);
// Position the text
lifePercentText.anchor.set(1, 0); // Right align
lifePercentText.x = -20; // Add right margin
lifePercentText.y = 20; // Add top margin
// Initialize enemies
var enemies = [];
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
// Initialize power-ups
var powerups = [];
var powerupSpawnInterval = 300;
var powerupSpawnCounter = 0;
// Create GodModeText instance
var godModeText = game.addChild(new GodModeText());
godModeText.x = 2048 / 2; // Center horizontally
godModeText.y = 2732 / 2 - 1050; // Position above the center (moved up by 650 units)
// Create a new Text2 object to display the score
var scoreLabelText = new Text2('Defeated enemies: ', {
size: 40,
fill: 0xFFFFFF
});
var scoreText = new Text2('0', {
size: 50,
fill: 0xFFFFFF
});
// Create the SHARKNADO title
var sharknadoTitle = game.addChild(new SharknadoTitle());
sharknadoTitle.x = 2048 / 2; // Center horizontally
sharknadoTitle.y = scoreText.y + 200; // Position further below the score text (moved down by 100 units)
// Add the score label and text to the game GUI at the top center of the screen
LK.gui.top.addChild(scoreLabelText);
LK.gui.top.addChild(scoreText);
// Position the label and score text
scoreLabelText.anchor.set(1, 0); // Right align the label
scoreText.anchor.set(0, 0); // Left align the score
scoreLabelText.x = 2048 / 2 - 880; // Position to the left of center, moved 880 units left
scoreLabelText.y = 20; // Add a small top margin
scoreText.x = 2048 / 2 - 840; // Position to the right of center, moved 840 units left
scoreText.y = 10; // Add a small top margin
// Set up a regular interval to check and ensure enemy spawning
var enemyWaveScheduler = LK.setInterval(function () {
// If there are no enemies on screen for more than 3 seconds, spawn a new wave
if (enemies.length === 0 && LK.ticks - game.lastSpawnTime > 180) {
// 3 seconds at 60fps
// Reset spawn counter to trigger spawn on next update
enemySpawnCounter = enemySpawnInterval;
}
}, 1000); // Check every second
// Handle game updates
game.update = function () {
if (game.Mario) game.Mario.update();
// Prevent enemies and powerups from spawning until player is selected
if (!game.Mario) {
return;
}
// Spawn enemies
enemySpawnCounter++;
// Define maximum number of active enemies allowed at once
var maxEnemies = Math.min(40, LK.getScore() + 5); // Scales with score up to 40 enemies
// Track time since last enemy spawn
if (!game.lastSpawnTime) {
game.lastSpawnTime = LK.ticks;
}
// Calculate time passed since last spawn (in frames, 60fps means 240 frames = 4 seconds)
var framesSinceLastSpawn = LK.ticks - game.lastSpawnTime;
// Force spawn if more than 4 seconds have passed without enemies
var forceSpawn = framesSinceLastSpawn > 240;
if (enemySpawnCounter >= enemySpawnInterval && enemies.length < maxEnemies || forceSpawn && enemies.length === 0) {
// Define enemy types
var enemyTypes = ['enemy', 'enemy1', 'enemy2', 'enemy3', 'jjb', 'ls'];
// Keep track of the last enemy type to avoid repetition
if (!game.lastEnemyTypeIndex) {
game.lastEnemyTypeIndex = -1;
}
// Reset last spawn time
game.lastSpawnTime = LK.ticks;
// Only spawn one enemy at a time
var _spawnEnemy = function spawnEnemy() {
// Check if we reached the maximum number of enemies
if (enemies.length >= maxEnemies) {
// Check if we've reached a permanent limit (meaning we can't spawn more enemies)
if (maxEnemies >= 40 && LK.getScore() >= 35) {
// If all current enemies are defeated, show win message
if (enemies.length === 0) {
LK.showYouWin();
}
}
return; // Don't spawn more enemies if we reached the limit
}
// Check if we're already in process of spawning (avoid duplicate calls)
if (game.isSpawningEnemy) {
return; // Prevent multiple simultaneous spawns
}
game.isSpawningEnemy = true;
// Get a new enemy type that is different from the last one
var availableTypes = [];
for (var t = 0; t < enemyTypes.length; t++) {
// Skip enemy2 type which is too small to be visible (4x4)
if (t !== game.lastEnemyTypeIndex && enemyTypes[t] !== 'enemy2') {
availableTypes.push({
index: t,
type: enemyTypes[t]
});
}
}
// Randomly select from available types
var selectedType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
game.lastEnemyTypeIndex = selectedType.index;
var enemy = new Enemy(selectedType.type);
enemy.x = 2048 + 100; // Fixed distance from edge of screen
enemy.y = 2732 / 2;
enemies.push(enemy);
game.addChild(enemy);
// Schedule the next enemy spawn with a fixed 1 second delay to ensure sequential spawning
if (enemies.length < maxEnemies) {
game.nextEnemyTimeout = LK.setTimeout(function () {
// Force an enemy spawn by setting the spawn counter to threshold
enemySpawnCounter = enemySpawnInterval;
// Update last spawn time to now
game.lastSpawnTime = LK.ticks;
// Reset spawning flag to allow next enemy spawn
game.isSpawningEnemy = false;
}, 1000); // Exactly 1 second delay between spawns
} else {
// Reset spawning flag if we're not spawning more
game.isSpawningEnemy = false;
}
};
_spawnEnemy();
// Randomize the spawn interval for the next enemy, but ensure it's not too long
enemySpawnInterval = Math.floor(Math.random() * 120) + 30; // Reduced max interval
enemySpawnCounter = 0;
}
// Spawn power-ups
powerupSpawnCounter++;
if (powerupSpawnCounter >= powerupSpawnInterval) {
var powerup = new PowerUp();
powerup.x = 2048 + 200; // Start a bit off screen
powerup.y = 2732 / 2 - 200; // Above the players level
powerup.originalY = powerup.y; // Store original Y for floating animation
powerup.lastWasIntersecting = false; // For tracking intersection
powerups.push(powerup);
game.addChild(powerup);
// Randomize the spawn interval for the next power-up
powerupSpawnInterval = Math.floor(Math.random() * 400) + 300;
powerupSpawnCounter = 0;
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
if (game.Mario && game.Mario.intersects(enemies[j])) {
// Check if enemy is jjb type and play JJBE sound
if (enemies[j].enemyType === 'jjb' && !enemies[j].jjbeSoundPlayed && !(game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) && !(game.Mario && game.Mario.isJumping) // Do not play if Mario is jumping on jjb
) {
// Play JJBE sound when Mario hits jjb asset and mark it as played
// Only play if not in godmode and not jumping
LK.getSound('JJBE').play();
enemies[j].jjbeSoundPlayed = true;
} else if (enemies[j].enemyType === 'jjb' && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive && !enemies[j].aniSoundPlayed) {
// Play Ani sound if godmode is active and Mario touches jjb asset
LK.getSound('Ani').play();
enemies[j].aniSoundPlayed = true;
}
// Special handling for JJB assets during God mode - spin horizontally and disappear
if (enemies[j].enemyType === 'jjb' && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Start the spinning animation if not already spinning
if (!enemies[j].spinningOut) {
enemies[j].spinningOut = true;
// Stop movement
enemies[j].speed = 0;
// Get the JJB asset graphic
var jjbGraphic = enemies[j].children[0];
// First horizontal 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally
}, {
duration: 150,
// 0.15 second for first half spin
easing: tween.linear,
onFinish: function onFinish() {
// Continue to full 360
tween(jjbGraphic, {
scaleX: 1 // Back to original
}, {
duration: 150,
// 0.15 second for second half spin
easing: tween.linear,
onFinish: function onFinish() {
// Second 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally again
}, {
duration: 150,
// 0.15 second for third half spin
easing: tween.linear,
onFinish: function onFinish() {
// Complete second 360
tween(jjbGraphic, {
scaleX: 1 // Back to original
}, {
duration: 150,
// 0.15 second for second full spin
easing: tween.linear,
onFinish: function onFinish() {
// Third 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally third time
}, {
duration: 150,
// 0.15 second for fifth half spin
easing: tween.linear,
onFinish: function onFinish() {
// Complete third 360
tween(jjbGraphic, {
scaleX: 1,
// Back to original
alpha: 0 // Fade out
}, {
duration: 150,
// 0.15 second for final half spin and fade
easing: tween.linear,
onFinish: function onFinish() {
// Remove the enemy after spinning
enemies[j].destroy();
enemies.splice(j, 1);
// Add points for defeating enemy
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
});
}
});
}
});
}
});
}
});
}
});
// Mark as being handled to prevent other collision effects
return;
}
}
// Special handling for 'ls' or 'enemy3' assets during God mode
if ((enemies[j].enemyType === 'ls' || enemies[j].enemyType === 'enemy3') && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Start the spinning out animation if not already spinning
if (!enemies[j].spinningOut) {
enemies[j].spinningOut = true;
enemies[j].spinSpeed = 15; // Speed at which it flies out
// Play dog sound when ls or enemy3 starts spinning out
LK.getSound('dog').play();
// Increase rotation animation
tween(enemies[j].children[0], {
rotation: Math.PI * 10
}, {
duration: 2000,
easing: tween.linear
});
// Add points for special effect
LK.setScore(LK.getScore() + 1); // Count by one to match other defeat methods
scoreText.setText(LK.getScore());
}
// Don't remove from array yet - let it spin out of screen
} else if (game.Mario && (game.Mario.isJumping || game.Mario.lightning && game.Mario.lightning.isActive)) {
// Mario jumped on top of the enemy or has active lightning shield, destroy the enemy
enemies[j].destroy();
enemies.splice(j, 1);
// Add points for defeating enemy
if (game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Add 1 point when defeating with lightning shield - changed from 2 to 1 to count consistently
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
} else if (game.Mario && game.Mario.isJumping) {
// Add 1 point when jumping on enemy
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
} else {
if (game.Mario) {
game.Mario.life -= 0.005; // Decrease Mario's life by 0.5%
if (game.Mario.life <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
}
// Update power-ups
for (var k = powerups.length - 1; k >= 0; k--) {
var powerup = powerups[k];
powerup.update();
// Check for collision with Mario
var currentIntersecting = game.Mario && game.Mario.intersects(powerup);
if (!powerup.lastWasIntersecting && currentIntersecting) {
// Power-up collected - apply effect
powerup.collected = true;
// Apply power-up effect
if (game.Mario) {
game.Mario.life = Math.min(1, game.Mario.life + 0.3); // Restore 30% of life
// Flash effect when collecting power-up
LK.effects.flashObject(game.Mario, 0xFFD700, 500);
}
// Show God mode text animation for 3 seconds
godModeText.showAnimation();
// Play god mode sound
LK.getSound('godmode').play();
// Enhance lightning effect for 5 seconds
if (game.Mario && game.Mario.lightning) {
// Set effect active flag
game.Mario.lightning.isActive = true;
for (var i = 0; i < game.Mario.lightning.bolts.length; i++) {
var bolt = game.Mario.lightning.bolts[i];
tween(bolt, {
alpha: 1,
scaleX: bolt.originalScale.x * 2,
scaleY: bolt.originalScale.y * 2
}, {
duration: 500,
easing: tween.elasticOut
});
}
// Update timer with the godmode duration (5 seconds)
godModeText.timerValue = 5;
// Reset to normal after 5 seconds (5000ms)
LK.setTimeout(function () {
game.Mario.lightning.isActive = false;
game.Mario.lightning.animate();
}, 5000);
}
// Remove the power-up
powerup.destroy();
powerups.splice(k, 1);
}
// Update tracking state
if (powerup) {
powerup.lastWasIntersecting = currentIntersecting;
}
}
// Sort enemies by their x position to ensure they never cover each other in display order
enemies.sort(function (a, b) {
return a.x - b.x;
});
// Check if there's any active ls asset in the map to show/hide SHARKNADO title
var hasActiveLS = false;
var hasEnemy3 = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].enemyType === 'ls' && enemies[i].x > -50 && enemies[i].x < 2048 + 50) {
hasActiveLS = true;
}
if (enemies[i].enemyType === 'enemy3' && enemies[i].x > -50 && enemies[i].x < 2048 + 50) {
hasEnemy3 = true;
}
}
// Show or hide SHARKNADO title based on ls asset presence
if (hasActiveLS) {
sharknadoTitle.show();
} else {
sharknadoTitle.hide();
}
// Show or hide TB popup based on enemy3 presence
if (hasEnemy3) {
tbPopup.show();
} else {
tbPopup.hide();
}
// Update the life counter
lifeCounter.update();
// Update life percentage text
if (game.Mario) {
lifePercentText.setText(Math.round(game.Mario.life * 100) + '%');
}
};
// Create watermark text
var watermarkText = new Text2('@jzubora', {
size: 20,
fill: 0x888888 // Grey color
});
// Position at bottom right
watermarkText.anchor.set(1, 1); // Bottom right anchor
LK.gui.bottomRight.addChild(watermarkText);
watermarkText.x = -20; // 20px margin from right
watermarkText.y = -20; // 20px margin from bottom
// Handle player jump
game.down = function (x, y, obj) {
if (game.Mario) game.Mario.jump();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Define a class for enemies
var Enemy = Container.expand(function (enemyType) {
var self = Container.call(this);
var enemyGraphics = self.attachAsset(enemyType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.enemyType = enemyType;
// Apply spinning animation to 'ls' enemy type
if (enemyType === 'ls') {
// Start spinning animation in left (counter-clockwise) direction
tween(enemyGraphics, {
rotation: Math.PI * 2 * -1 // Negative for left/counter-clockwise direction
}, {
duration: 2000,
// 2 seconds for a full rotation
easing: tween.linear,
repeat: Infinity,
// Use Infinity instead of loop: true for continuous spinning
loop: true // Continuous spinning
});
}
self.update = function () {
// Special behavior for ls asset - bounce down from top right
if (self.enemyType === 'ls') {
// Add vertical movement properties first time
if (self.verticalSpeed === undefined) {
self.verticalSpeed = 3; // Initial downward speed
self.gravity = 0.1; // Gravity effect
self.bounceStrength = 2; // How strong the bounce is
// Start from top-right corner
self.y = 100; // Near top
self.x = 2048 + 100; // Off right edge
}
// Track if this asset is in the spinning out state
if (self.spinningOut) {
// Move toward right top corner
var targetX = 2048 + 200;
var targetY = -200;
// Calculate direction vector
var dirX = targetX - self.x;
var dirY = targetY - self.y;
// Normalize and apply speed
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > 0) {
dirX = dirX / length * (self.spinSpeed || 15);
dirY = dirY / length * (self.spinSpeed || 15);
}
// Move toward target
self.x += dirX;
self.y += dirY;
// Increase rotation speed
self.children[0].rotation += 0.2;
} else {
// Normal behavior when not spinning out
// Apply gravity to vertical speed
self.verticalSpeed += self.gravity;
self.y += self.verticalSpeed;
// Bounce when hitting bottom at 3/4 of the screen height instead of center
if (self.y > 2732 * 0.75) {
// Bounce at 3/4 screen height
self.y = 2732 * 0.75;
self.verticalSpeed = -self.verticalSpeed * (self.bounceStrength * 0.3); // Even lower bounce power
// Reduce bounce strength much more quickly
self.bounceStrength *= 0.5;
}
// Horizontal movement
self.x -= self.speed;
}
} else if (self.enemyType === 'enemy3') {
// Special behavior for enemy3 - attack from right bottom corner
if (self.initialPosition === undefined) {
// Set initial position at right bottom corner
self.x = 2048 + 100; // Off right edge
self.y = 2732 - 550; // Bottom of screen with small margin, moved up by 450 units
self.initialPosition = true;
}
// Move diagonally up-left (towards Mario)
self.x -= self.speed * 1.2;
self.y -= self.speed * 0.6;
} else {
// Original behavior for other enemy types
self.x -= self.speed;
}
// Destroy when off screen
if (self.x < -50) {
self.destroy();
}
};
return self; // Return self to make the class inheritable
});
// Define a class for displaying the God Mode text
var GodModeText = Container.expand(function () {
var self = Container.call(this);
// Create the text
var godModeText = new Text2('GOD MODE', {
size: 80,
fill: 0xFF8C00 // Orange color
});
godModeText.anchor.set(0.5, 0.5);
self.addChild(godModeText);
// Initialize with invisible state
godModeText.alpha = 0;
// Create timer text
var timerText = new Text2('', {
size: 80,
fill: 0xFF8C00 // Orange color for timer
});
timerText.anchor.set(0.5, 0.5);
timerText.y = 80; // Position below the GOD MODE text
self.addChild(timerText);
// Initialize timer value
self.timerValue = 5; // 5 seconds duration
self.timerInterval = null;
// Method to show the animation
self.showAnimation = function () {
// Play god mode sound
LK.getSound('godmode').play();
// Stop any existing animations
tween.stop(godModeText);
// Reset and start the timer
self.timerValue = 5;
timerText.setText(self.timerValue);
timerText.alpha = 1;
// Clear any existing timer
if (self.timerInterval) {
LK.clearInterval(self.timerInterval);
}
// Start countdown timer
self.timerInterval = LK.setInterval(function () {
self.timerValue -= 1;
if (self.timerValue > 0) {
timerText.setText(self.timerValue);
} else if (self.timerValue === 0) {
timerText.setText(self.timerValue);
LK.clearInterval(self.timerInterval);
self.timerInterval = null;
}
}, 1000);
// Animate in with fireflame effect
godModeText.tint = 0xFF5500; // Orange-red fire color
tween(godModeText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Create flickering flame animation
function fireflameFlicker() {
// Random fire colors between orange-red and yellow
var fireColors = [0xFF5500, 0xFF8800, 0xFFAA00, 0xFFFF00];
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
// Random scale for fire flicker effect
var randomScale = 1.0 + Math.random() * 0.3;
// Apply the flame effect
tween(godModeText, {
tint: randomColor,
scaleX: randomScale,
scaleY: randomScale,
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 100 + Math.random() * 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Continue the flame effect if still visible
if (godModeText.alpha > 0) {
fireflameFlicker();
}
}
});
}
// Start the flame flicker effect
fireflameFlicker();
// Hide after 3 seconds
LK.setTimeout(function () {
// Stop the pulse animation
tween.stop(godModeText);
// Stop and hide the timer
if (self.timerInterval) {
LK.clearInterval(self.timerInterval);
self.timerInterval = null;
}
tween(timerText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
// Animate out
tween(godModeText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
}, 3000);
}
});
};
return self;
});
// Define a class for the life counter
var LifeCounter = Container.expand(function () {
var self = Container.call(this);
// Create a simple white line instead of using an asset
var lineGraphics = LK.getAsset('enemy2', {
anchorX: 0.0,
anchorY: 0.0,
scaleX: 2048,
scaleY: 10,
tint: 0xFFFFFF // White color
});
self.addChild(lineGraphics);
self.width = 2048; // Full width
self.update = function () {
// Update the width of the line based on Mario's life
if (game.Mario) {
lineGraphics.scale.x = 2048 * game.Mario.life;
}
};
});
// Define a class for the dragon ball lightning effect
var LightningEffect = Container.expand(function () {
var self = Container.call(this);
// Set active status flag
self.isActive = false;
// Create lightning bolts
self.bolts = [];
var colors = [0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00];
// Create multiple lightning bolts around Mario
for (var i = 0; i < 5; i++) {
var bolt = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25 + Math.random() * 10,
scaleY: 25 + Math.random() * 10
});
bolt.tint = colors[Math.floor(Math.random() * colors.length)];
bolt.alpha = 0; // Start with invisible bolts
bolt.rotation = Math.random() * Math.PI * 2;
bolt.distance = 80 + Math.random() * 40;
bolt.speed = 0.1 + Math.random() * 0.1;
bolt.originalScale = {
x: bolt.scale.x,
y: bolt.scale.y
};
self.bolts.push(bolt);
}
// Animate the lightning
self.animate = function () {
// Stop any existing animations
for (var i = 0; i < self.bolts.length; i++) {
tween.stop(self.bolts[i]);
}
// Start new animations
for (var i = 0; i < self.bolts.length; i++) {
var bolt = self.bolts[i];
// Randomize the bolt appearance
bolt.rotation = Math.random() * Math.PI * 2;
bolt.scale.x = bolt.originalScale.x * (0.8 + Math.random() * 0.4);
bolt.scale.y = bolt.originalScale.y * (0.8 + Math.random() * 0.4);
// Animate the bolt with pulse effect
tween(bolt, {
alpha: 0.2 + Math.random() * 0.5,
scaleX: bolt.originalScale.x * (0.7 + Math.random() * 0.6),
scaleY: bolt.originalScale.y * (0.7 + Math.random() * 0.6)
}, {
duration: 300 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function () {
// Create a callback closure to maintain the correct bolt reference
var currentBolt = bolt;
return function () {
// Animate back
tween(currentBolt, {
alpha: 0.6 + Math.random() * 0.4,
scaleX: currentBolt.originalScale.x * (0.9 + Math.random() * 0.3),
scaleY: currentBolt.originalScale.y * (0.9 + Math.random() * 0.3)
}, {
duration: 300 + Math.random() * 400,
easing: tween.easeIn
});
};
}()
});
}
};
self.update = function () {
// Position the lightning bolts around Mario
for (var i = 0; i < self.bolts.length; i++) {
var bolt = self.bolts[i];
var angle = bolt.rotation + self.parent.rotation + bolt.speed * LK.ticks;
bolt.x = Math.cos(angle) * bolt.distance;
bolt.y = Math.sin(angle) * bolt.distance;
// Make bolts invisible when effect is not active
if (!self.isActive) {
bolt.alpha = 0;
}
// Ensure bolts remain visible when effect is active
else if (self.isActive && bolt.alpha < 0.7) {
bolt.alpha = 0.7 + Math.random() * 0.3;
}
}
// Periodically refresh animations only when not in active state
if (LK.ticks % 30 === 0 && self.isActive) {
self.animate();
}
};
return self;
});
//<Assets used in the game will automatically appear here>
// Define a class for the player character
var Player = Container.expand(function (characterType) {
var self = Container.call(this);
var assetType = characterType === 'YM' ? 'YM' : characterType === 'MB' ? 'MB' : 'Mario';
var MarioGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
// Add the lightning effect
self.lightning = self.addChild(new LightningEffect());
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.7; // Decreased gravity effect by 30%
if (self.y >= 2732 / 2) {
// Ground level
self.y = 2732 / 2;
self.isJumping = false;
self.velocityY = 0;
}
}
// Update the lightning effect
if (self.lightning) {
self.lightning.update();
}
};
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.velocityY = -self.jumpHeight;
// Play jump sound
LK.getSound('jump').play();
// Activate lightning effect animation with a more intense glow when jumping, but only if lightning is already active
if (self.lightning && self.lightning.isActive) {
// Intensify the lightning effect
for (var i = 0; i < self.lightning.bolts.length; i++) {
var bolt = self.lightning.bolts[i];
tween(bolt, {
alpha: 0.9,
scaleX: bolt.originalScale.x * 1.5,
scaleY: bolt.originalScale.y * 1.5
}, {
duration: 300,
easing: tween.elasticOut
});
}
// Reset to normal after a short time
LK.setTimeout(function () {
self.lightning.animate();
}, 500);
}
}
};
});
// Define a class for power-ups
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.floatOffset = 0;
self.collected = false;
// Make power-up glow with tween animation and add shiny flashing effect
tween(powerGraphics, {
alpha: 0.7,
tint: 0xffffff
}, {
duration: 1000,
easing: tween.sinusoidalInOut,
loop: true,
yoyo: true
});
// Add shiny flashing effect
function createShinyEffect() {
// Tween to bright yellow-white (shiny effect)
tween(powerGraphics, {
tint: 0xffffff,
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Tween back to normal gold
tween(powerGraphics, {
tint: 0xffd700,
alpha: 0.8,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 250,
easing: tween.easeIn,
onFinish: function onFinish() {
// Schedule next flash after a shorter random delay
LK.setTimeout(createShinyEffect, 300 + Math.random() * 400);
}
});
}
});
}
// Start the shiny effect sequence
LK.setTimeout(createShinyEffect, 200 + Math.random() * 300);
self.update = function () {
// Move power-up from right to left
self.x -= self.speed;
// Floating up and down motion
self.floatOffset += 0.05;
self.y = self.originalY + Math.sin(self.floatOffset) * 20;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
};
return self;
});
// Define a class for displaying the SHARKNADO title
var SharknadoTitle = Container.expand(function () {
var self = Container.call(this);
// Create the text with chrome-silver-black styling
var sharknadoText = new Text2('SHARKNADO!', {
size: 240,
fill: 0xDDDDDD,
// Silver base color
dropShadow: true,
dropShadowColor: 0x333333,
// Dark shadow for 3D effect
dropShadowDistance: 3
});
// Set anchor to center horizontally
sharknadoText.anchor.set(0.5, 0.5);
self.addChild(sharknadoText);
// Initialize as invisible
self.visible = false;
// Method to show the title
self.show = function () {
if (self.visible) return; // Already visible
self.visible = true;
// Clear any existing animations
tween.stop(sharknadoText);
// Reset and animate in
sharknadoText.alpha = 0;
sharknadoText.scale.set(0.5, 0.5);
// Track original position for shake effect
self.originalX = self.x;
self.originalY = self.y;
// Animate in with chrome shine effect
tween(sharknadoText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Add pulsing animation
tween(sharknadoText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.sinusoidalInOut,
yoyo: true,
loop: true
});
// Start shaking animation
self.startShaking();
}
});
};
// Method to hide the title
self.hide = function () {
if (!self.visible) return; // Already hidden
// Stop any existing animations
tween.stop(sharknadoText);
// Stop shaking
self.stopShaking();
// Animate out
tween(sharknadoText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.visible = false;
}
});
};
// Start shaking animation for SHARKNADO title
self.startShaking = function () {
// Clear any existing shake interval
self.stopShaking();
// Create new shake interval
self.shakeInterval = LK.setInterval(function () {
// Random offset for shake effect (more horizontal than vertical)
var offsetX = (Math.random() - 0.5) * 20; // -10 to +10 pixels
var offsetY = (Math.random() - 0.5) * 10; // -5 to +5 pixels
// Apply shake
self.x = self.originalX + offsetX;
self.y = self.originalY + offsetY;
// Apply slight rotation for more dramatic effect
sharknadoText.rotation = (Math.random() - 0.5) * 0.05; // Small random rotation
}, 50); // Shake every 50ms for realistic earthquake effect
};
// Stop shaking animation
self.stopShaking = function () {
if (self.shakeInterval) {
LK.clearInterval(self.shakeInterval);
self.shakeInterval = null;
// Reset position and rotation
if (self.originalX !== undefined) {
self.x = self.originalX;
self.y = self.originalY;
sharknadoText.rotation = 0;
}
}
};
return self;
});
// Define a class for the TB popup
var TbPopup = Container.expand(function () {
var self = Container.call(this);
// Get TB asset
var tbGraphics = self.attachAsset('tb', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize as invisible
self.alpha = 0;
self.visible = false;
// Method to show the popup
self.show = function () {
if (self.visible) return; // Already visible
// Stop any existing animations
tween.stop(self);
// Reset and make visible
self.visible = true;
self.scale.set(0.2, 0.2);
// Animate in
tween(self, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.elasticOut
});
};
// Method to hide the popup
self.hide = function () {
if (!self.visible) return; // Already hidden
// Animate out
tween(self, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.visible = false;
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// All references to 'Mri' asset have been renamed to 'MB'
//<Assets used in the game will automatically appear here>
game.lastSpawnTime = 0;
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
// Play background music
LK.playMusic('music1', {
loop: true
});
// Character selection menu implementation
var characterSelectionContainer = new Container();
characterSelectionContainer.x = 2048 / 2;
characterSelectionContainer.y = 2732 / 2;
game.addChild(characterSelectionContainer);
// Dim background overlay
var overlay = LK.getAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2048,
scaleY: 2732,
tint: 0x000000,
alpha: 0.7
});
characterSelectionContainer.addChild(overlay);
// Title text
var selectText = new Text2('Select Your Character', {
size: 120,
fill: 0xFFFFFF
});
selectText.anchor.set(0.5, 0.5);
selectText.y = -400;
characterSelectionContainer.addChild(selectText);
// (Mario option removed)
// MB option
var mbOption = LK.getAsset('MB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
mbOption.x = 0;
mbOption.y = 0;
characterSelectionContainer.addChild(mbOption);
var mbLabel = new Text2('MB', {
size: 70,
fill: 0xFFFFFF
});
mbLabel.anchor.set(0.5, 0);
mbLabel.x = mbOption.x;
mbLabel.y = 280;
characterSelectionContainer.addChild(mbLabel);
// YM option
var ymOption = LK.getAsset('YM', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
ymOption.x = 500;
ymOption.y = 0;
characterSelectionContainer.addChild(ymOption);
var ymLabel = new Text2('YM', {
size: 70,
fill: 0xFFFFFF
});
ymLabel.anchor.set(0.5, 0);
ymLabel.x = ymOption.x;
ymLabel.y = 280; // moved down by 100 units
characterSelectionContainer.addChild(ymLabel);
// Store selected character type
var selectedCharacterType = null;
// Helper to highlight selection
function highlightOption(option) {
mbOption.alpha = 0.7;
ymOption.alpha = 0.7;
option.alpha = 1.0;
}
// (Mario option event handler removed)
// Touch/click handlers for MB
mbOption.down = function (x, y, obj) {
highlightOption(mbOption);
selectedCharacterType = 'MB';
confirmButton.alpha = 1;
confirmButton.interactive = true;
};
// Touch/click handlers for YM
ymOption.down = function (x, y, obj) {
highlightOption(ymOption);
selectedCharacterType = 'YM';
confirmButton.alpha = 1;
confirmButton.interactive = true;
};
// Confirm button
var confirmButton = new Text2('Start Game', {
size: 90,
fill: 0x00FF00
});
confirmButton.anchor.set(0.5, 0.5);
confirmButton.y = 400;
confirmButton.alpha = 0.5;
confirmButton.interactive = false;
characterSelectionContainer.addChild(confirmButton);
// Confirm button handler
confirmButton.down = function (x, y, obj) {
if (!selectedCharacterType) return;
// Remove menu
characterSelectionContainer.destroy();
// Proceed to game setup
setupPlayer(selectedCharacterType);
};
// Add down event listeners
mbOption.interactive = true;
ymOption.interactive = true;
confirmButton.interactive = false;
// Setup player function
function setupPlayer(characterType) {
// Initialize player with selected character
var Mario = game.addChild(new Player(characterType));
Mario.x = 2048 / 2 - 200;
Mario.y = 2732 / 2;
Mario.life = 1;
// Store reference globally for other code
game.Mario = Mario;
// Update all references in game code to use game.Mario if needed
}
// Patch Player class to accept characterType
// (see Classes section for Player class patch)
// Initialize the life counter and add it to the game
var lifeCounter = game.addChild(new LifeCounter());
lifeCounter.y = 0; // Position it at the top of the screen
// Create TB popup for enemy3
var tbPopup = game.addChild(new TbPopup());
tbPopup.x = 160; // Position on the left side, moved left by 40 units
tbPopup.y = 2732 / 2 - 777; // Center vertically, then move up by 777 units
// Create life percentage text
var lifePercentText = new Text2('100%', {
size: 40,
fill: 0x7FFF00 // Bright neon green to match the life bar
});
// Add the life percentage text to the GUI
LK.gui.topRight.addChild(lifePercentText);
// Position the text
lifePercentText.anchor.set(1, 0); // Right align
lifePercentText.x = -20; // Add right margin
lifePercentText.y = 20; // Add top margin
// Initialize enemies
var enemies = [];
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
// Initialize power-ups
var powerups = [];
var powerupSpawnInterval = 300;
var powerupSpawnCounter = 0;
// Create GodModeText instance
var godModeText = game.addChild(new GodModeText());
godModeText.x = 2048 / 2; // Center horizontally
godModeText.y = 2732 / 2 - 1050; // Position above the center (moved up by 650 units)
// Create a new Text2 object to display the score
var scoreLabelText = new Text2('Defeated enemies: ', {
size: 40,
fill: 0xFFFFFF
});
var scoreText = new Text2('0', {
size: 50,
fill: 0xFFFFFF
});
// Create the SHARKNADO title
var sharknadoTitle = game.addChild(new SharknadoTitle());
sharknadoTitle.x = 2048 / 2; // Center horizontally
sharknadoTitle.y = scoreText.y + 200; // Position further below the score text (moved down by 100 units)
// Add the score label and text to the game GUI at the top center of the screen
LK.gui.top.addChild(scoreLabelText);
LK.gui.top.addChild(scoreText);
// Position the label and score text
scoreLabelText.anchor.set(1, 0); // Right align the label
scoreText.anchor.set(0, 0); // Left align the score
scoreLabelText.x = 2048 / 2 - 880; // Position to the left of center, moved 880 units left
scoreLabelText.y = 20; // Add a small top margin
scoreText.x = 2048 / 2 - 840; // Position to the right of center, moved 840 units left
scoreText.y = 10; // Add a small top margin
// Set up a regular interval to check and ensure enemy spawning
var enemyWaveScheduler = LK.setInterval(function () {
// If there are no enemies on screen for more than 3 seconds, spawn a new wave
if (enemies.length === 0 && LK.ticks - game.lastSpawnTime > 180) {
// 3 seconds at 60fps
// Reset spawn counter to trigger spawn on next update
enemySpawnCounter = enemySpawnInterval;
}
}, 1000); // Check every second
// Handle game updates
game.update = function () {
if (game.Mario) game.Mario.update();
// Prevent enemies and powerups from spawning until player is selected
if (!game.Mario) {
return;
}
// Spawn enemies
enemySpawnCounter++;
// Define maximum number of active enemies allowed at once
var maxEnemies = Math.min(40, LK.getScore() + 5); // Scales with score up to 40 enemies
// Track time since last enemy spawn
if (!game.lastSpawnTime) {
game.lastSpawnTime = LK.ticks;
}
// Calculate time passed since last spawn (in frames, 60fps means 240 frames = 4 seconds)
var framesSinceLastSpawn = LK.ticks - game.lastSpawnTime;
// Force spawn if more than 4 seconds have passed without enemies
var forceSpawn = framesSinceLastSpawn > 240;
if (enemySpawnCounter >= enemySpawnInterval && enemies.length < maxEnemies || forceSpawn && enemies.length === 0) {
// Define enemy types
var enemyTypes = ['enemy', 'enemy1', 'enemy2', 'enemy3', 'jjb', 'ls'];
// Keep track of the last enemy type to avoid repetition
if (!game.lastEnemyTypeIndex) {
game.lastEnemyTypeIndex = -1;
}
// Reset last spawn time
game.lastSpawnTime = LK.ticks;
// Only spawn one enemy at a time
var _spawnEnemy = function spawnEnemy() {
// Check if we reached the maximum number of enemies
if (enemies.length >= maxEnemies) {
// Check if we've reached a permanent limit (meaning we can't spawn more enemies)
if (maxEnemies >= 40 && LK.getScore() >= 35) {
// If all current enemies are defeated, show win message
if (enemies.length === 0) {
LK.showYouWin();
}
}
return; // Don't spawn more enemies if we reached the limit
}
// Check if we're already in process of spawning (avoid duplicate calls)
if (game.isSpawningEnemy) {
return; // Prevent multiple simultaneous spawns
}
game.isSpawningEnemy = true;
// Get a new enemy type that is different from the last one
var availableTypes = [];
for (var t = 0; t < enemyTypes.length; t++) {
// Skip enemy2 type which is too small to be visible (4x4)
if (t !== game.lastEnemyTypeIndex && enemyTypes[t] !== 'enemy2') {
availableTypes.push({
index: t,
type: enemyTypes[t]
});
}
}
// Randomly select from available types
var selectedType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
game.lastEnemyTypeIndex = selectedType.index;
var enemy = new Enemy(selectedType.type);
enemy.x = 2048 + 100; // Fixed distance from edge of screen
enemy.y = 2732 / 2;
enemies.push(enemy);
game.addChild(enemy);
// Schedule the next enemy spawn with a fixed 1 second delay to ensure sequential spawning
if (enemies.length < maxEnemies) {
game.nextEnemyTimeout = LK.setTimeout(function () {
// Force an enemy spawn by setting the spawn counter to threshold
enemySpawnCounter = enemySpawnInterval;
// Update last spawn time to now
game.lastSpawnTime = LK.ticks;
// Reset spawning flag to allow next enemy spawn
game.isSpawningEnemy = false;
}, 1000); // Exactly 1 second delay between spawns
} else {
// Reset spawning flag if we're not spawning more
game.isSpawningEnemy = false;
}
};
_spawnEnemy();
// Randomize the spawn interval for the next enemy, but ensure it's not too long
enemySpawnInterval = Math.floor(Math.random() * 120) + 30; // Reduced max interval
enemySpawnCounter = 0;
}
// Spawn power-ups
powerupSpawnCounter++;
if (powerupSpawnCounter >= powerupSpawnInterval) {
var powerup = new PowerUp();
powerup.x = 2048 + 200; // Start a bit off screen
powerup.y = 2732 / 2 - 200; // Above the players level
powerup.originalY = powerup.y; // Store original Y for floating animation
powerup.lastWasIntersecting = false; // For tracking intersection
powerups.push(powerup);
game.addChild(powerup);
// Randomize the spawn interval for the next power-up
powerupSpawnInterval = Math.floor(Math.random() * 400) + 300;
powerupSpawnCounter = 0;
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
if (game.Mario && game.Mario.intersects(enemies[j])) {
// Check if enemy is jjb type and play JJBE sound
if (enemies[j].enemyType === 'jjb' && !enemies[j].jjbeSoundPlayed && !(game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) && !(game.Mario && game.Mario.isJumping) // Do not play if Mario is jumping on jjb
) {
// Play JJBE sound when Mario hits jjb asset and mark it as played
// Only play if not in godmode and not jumping
LK.getSound('JJBE').play();
enemies[j].jjbeSoundPlayed = true;
} else if (enemies[j].enemyType === 'jjb' && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive && !enemies[j].aniSoundPlayed) {
// Play Ani sound if godmode is active and Mario touches jjb asset
LK.getSound('Ani').play();
enemies[j].aniSoundPlayed = true;
}
// Special handling for JJB assets during God mode - spin horizontally and disappear
if (enemies[j].enemyType === 'jjb' && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Start the spinning animation if not already spinning
if (!enemies[j].spinningOut) {
enemies[j].spinningOut = true;
// Stop movement
enemies[j].speed = 0;
// Get the JJB asset graphic
var jjbGraphic = enemies[j].children[0];
// First horizontal 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally
}, {
duration: 150,
// 0.15 second for first half spin
easing: tween.linear,
onFinish: function onFinish() {
// Continue to full 360
tween(jjbGraphic, {
scaleX: 1 // Back to original
}, {
duration: 150,
// 0.15 second for second half spin
easing: tween.linear,
onFinish: function onFinish() {
// Second 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally again
}, {
duration: 150,
// 0.15 second for third half spin
easing: tween.linear,
onFinish: function onFinish() {
// Complete second 360
tween(jjbGraphic, {
scaleX: 1 // Back to original
}, {
duration: 150,
// 0.15 second for second full spin
easing: tween.linear,
onFinish: function onFinish() {
// Third 360 spin
tween(jjbGraphic, {
scaleX: -1 // Flip horizontally third time
}, {
duration: 150,
// 0.15 second for fifth half spin
easing: tween.linear,
onFinish: function onFinish() {
// Complete third 360
tween(jjbGraphic, {
scaleX: 1,
// Back to original
alpha: 0 // Fade out
}, {
duration: 150,
// 0.15 second for final half spin and fade
easing: tween.linear,
onFinish: function onFinish() {
// Remove the enemy after spinning
enemies[j].destroy();
enemies.splice(j, 1);
// Add points for defeating enemy
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
});
}
});
}
});
}
});
}
});
}
});
// Mark as being handled to prevent other collision effects
return;
}
}
// Special handling for 'ls' or 'enemy3' assets during God mode
if ((enemies[j].enemyType === 'ls' || enemies[j].enemyType === 'enemy3') && game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Start the spinning out animation if not already spinning
if (!enemies[j].spinningOut) {
enemies[j].spinningOut = true;
enemies[j].spinSpeed = 15; // Speed at which it flies out
// Play dog sound when ls or enemy3 starts spinning out
LK.getSound('dog').play();
// Increase rotation animation
tween(enemies[j].children[0], {
rotation: Math.PI * 10
}, {
duration: 2000,
easing: tween.linear
});
// Add points for special effect
LK.setScore(LK.getScore() + 1); // Count by one to match other defeat methods
scoreText.setText(LK.getScore());
}
// Don't remove from array yet - let it spin out of screen
} else if (game.Mario && (game.Mario.isJumping || game.Mario.lightning && game.Mario.lightning.isActive)) {
// Mario jumped on top of the enemy or has active lightning shield, destroy the enemy
enemies[j].destroy();
enemies.splice(j, 1);
// Add points for defeating enemy
if (game.Mario && game.Mario.lightning && game.Mario.lightning.isActive) {
// Add 1 point when defeating with lightning shield - changed from 2 to 1 to count consistently
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
} else if (game.Mario && game.Mario.isJumping) {
// Add 1 point when jumping on enemy
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
} else {
if (game.Mario) {
game.Mario.life -= 0.005; // Decrease Mario's life by 0.5%
if (game.Mario.life <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
}
// Update power-ups
for (var k = powerups.length - 1; k >= 0; k--) {
var powerup = powerups[k];
powerup.update();
// Check for collision with Mario
var currentIntersecting = game.Mario && game.Mario.intersects(powerup);
if (!powerup.lastWasIntersecting && currentIntersecting) {
// Power-up collected - apply effect
powerup.collected = true;
// Apply power-up effect
if (game.Mario) {
game.Mario.life = Math.min(1, game.Mario.life + 0.3); // Restore 30% of life
// Flash effect when collecting power-up
LK.effects.flashObject(game.Mario, 0xFFD700, 500);
}
// Show God mode text animation for 3 seconds
godModeText.showAnimation();
// Play god mode sound
LK.getSound('godmode').play();
// Enhance lightning effect for 5 seconds
if (game.Mario && game.Mario.lightning) {
// Set effect active flag
game.Mario.lightning.isActive = true;
for (var i = 0; i < game.Mario.lightning.bolts.length; i++) {
var bolt = game.Mario.lightning.bolts[i];
tween(bolt, {
alpha: 1,
scaleX: bolt.originalScale.x * 2,
scaleY: bolt.originalScale.y * 2
}, {
duration: 500,
easing: tween.elasticOut
});
}
// Update timer with the godmode duration (5 seconds)
godModeText.timerValue = 5;
// Reset to normal after 5 seconds (5000ms)
LK.setTimeout(function () {
game.Mario.lightning.isActive = false;
game.Mario.lightning.animate();
}, 5000);
}
// Remove the power-up
powerup.destroy();
powerups.splice(k, 1);
}
// Update tracking state
if (powerup) {
powerup.lastWasIntersecting = currentIntersecting;
}
}
// Sort enemies by their x position to ensure they never cover each other in display order
enemies.sort(function (a, b) {
return a.x - b.x;
});
// Check if there's any active ls asset in the map to show/hide SHARKNADO title
var hasActiveLS = false;
var hasEnemy3 = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].enemyType === 'ls' && enemies[i].x > -50 && enemies[i].x < 2048 + 50) {
hasActiveLS = true;
}
if (enemies[i].enemyType === 'enemy3' && enemies[i].x > -50 && enemies[i].x < 2048 + 50) {
hasEnemy3 = true;
}
}
// Show or hide SHARKNADO title based on ls asset presence
if (hasActiveLS) {
sharknadoTitle.show();
} else {
sharknadoTitle.hide();
}
// Show or hide TB popup based on enemy3 presence
if (hasEnemy3) {
tbPopup.show();
} else {
tbPopup.hide();
}
// Update the life counter
lifeCounter.update();
// Update life percentage text
if (game.Mario) {
lifePercentText.setText(Math.round(game.Mario.life * 100) + '%');
}
};
// Create watermark text
var watermarkText = new Text2('@jzubora', {
size: 20,
fill: 0x888888 // Grey color
});
// Position at bottom right
watermarkText.anchor.set(1, 1); // Bottom right anchor
LK.gui.bottomRight.addChild(watermarkText);
watermarkText.x = -20; // 20px margin from right
watermarkText.y = -20; // 20px margin from bottom
// Handle player jump
game.down = function (x, y, obj) {
if (game.Mario) game.Mario.jump();
};
Ghibli style but more realistic
NeonYellow powerup logo. In-Game asset. 2d. High contrast. No shadows
Running Sith jar-jar binks in ghibli style. In-Game asset. 2d. High contrast. No shadows
Shark with lasergun on his head, sideview, ghibli style. In-Game asset. 2d. High contrast. No shadows
White textbubble with thin black frame. 'Run away! A killer rabbit!' text in bubble. In-Game asset. 2d. High contrast. No shadows
Remove 3. Stripe from the shoe and the kit
İstanbul TCG yazsın
Ön tarafında Taylan tütün yazılı asker elinde sopası olsun vursun
Üstünde ibrahim muğli yazan baretli işçi tekme atarken. In-Game asset. 2d. High contrast. No shadows