Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var bottomFloorTop = floors.length > 0 ? bottomFloorY - floors[0].height / 2 : bottomFloorY; // Top edge of the bottom floor' Line Number: 497
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var bottomFloorTop = floors.length > 0 ? bottomFloorY - floors[0].height / 2 : bottomFloorY; // Top edge of the bottom floor' Line Number: 490
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'var bottomFloorTop = bottomFloorY - floors[0].height / 2; // Top edge of the bottom floor' Line Number: 488
User prompt
No. Redo completely the collisions of the dragon and the floors and the positioning of the dragon upons tarting: if falls off the floors / screen.
User prompt
No. Redo completely the collisions of the dragon and the floors and the positioning of the dragon upons tarting: if falls off the floors / screen.
User prompt
No. Redo completely the collisions of the dragon and the floors and the positioning of the dragon upons tarting: if falls off the screen.
User prompt
It did not work. The dragon falls off the floors down.
User prompt
The dragon falls off the screen after i walk a little bit it starts, seems it does not detect collision with floors. Please fix.
User prompt
The dragon falls off the screen when it starts, seems it does not detect collision with floors?
User prompt
The performance is terrible on mobile, as there are many things being checked on a tick level + the tweens. Please, optimize the performance to the max but keeping all the same features intact.
User prompt
For some reasons, sometimes the dragon can't shoot bubbles for quite a long time. Can you please fix that and only that?
User prompt
Remove all .context(...). They don't exist at all!
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'context')' in or related to this line: 'tween(enemy, {' Line Number: 583
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'context')' in or related to this line: 'tween(enemy, {' Line Number: 580
User prompt
Fix these issues: 1. Some enemies don't move. 2. Some platforms seem ephimerous - the dragon player don't stop on them when falling, it crosses them. 3. Sometimes the dragon stops throwing bubbles. Maybe there is something wrong with skipping frames or something like that? Make sure to change only what's necessary.
User prompt
I have several performance issues in the game when jumping with the dragon, possibly due to the tweens and other stuff. Please fix performance issues, simplify, make it lighter to run. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: floors is not defined' in or related to this line: 'for (var i = 0; i < floors.length; i++) {' Line Number: 50
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught ReferenceError: bubbles is not defined' in or related to this line: 'bubbles.push(bubble);' Line Number: 103
User prompt
Please fix the bug: 'Uncaught ReferenceError: bubbles is not defined' in or related to this line: 'bubbles.push(bubble);' Line Number: 103
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Modify the game.down = function () { console.log("click") to only trigger if clicking on start
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Class for Bubbles - optimized for performance
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -5;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move bubble
self.x += self.speed;
// Check for intersection with any floor
var intersectingFloor = null;
for (var i = 0; i < floors.length; i++) {
if (self.intersects(floors[i])) {
intersectingFloor = floors[i];
break;
}
}
// Handle collision with floor
if (intersectingFloor) {
// Create a PoppedBubble at the bubble's position
var pop = game.addChild(new PoppedBubble());
pop.x = self.x;
pop.y = self.y;
// Remove from bubbles array before destroying
var bubbleIndex = bubbles.indexOf(self);
if (bubbleIndex !== -1) {
bubbles.splice(bubbleIndex, 1);
}
// Destroy the bubble
self.destroy();
// Destroy the PoppedBubble after 0.5 seconds
LK.setTimeout(function () {
pop.destroy();
}, 500);
}
};
});
var CapturingBubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.alpha = 0.5;
self.scaleX = 2;
self.scaleY = 2;
self.update = function () {};
});
//<Assets used in the game will automatically appear here>
// Class for the Dragon character - optimized for performance
var Dragon = Container.expand(function () {
var self = Container.call(this);
self.dragonGraphics = self.attachAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.isIntersectingBubble = false;
self.lastWasIntersecting = false;
self.lastX = 0;
self.lastY = 0;
self.shootBubble = function () {
// Create new bubble and ensure it's properly initialized
var bubble = new Bubble();
bubble.x = self.x + 200 * self.scale.x;
bubble.y = self.y - 5;
bubble.lastX = bubble.x;
bubble.lastY = bubble.y;
// If the dragon is looking right, the bubble should move to the right
if (self.scale.x == 1) {
bubble.speed = 25;
} else {
// If the dragon is looking left, the bubble should move to the left
bubble.speed = -25;
}
// Add bubble to game display list first to ensure it's rendered
game.addChild(bubble);
// Ensure bubbles array exists before trying to push to it
if (!bubbles) {
bubbles = [];
}
// Always add bubble to tracking array
bubbles.push(bubble);
// Play bubble sound when a bubble is shot
LK.getSound('bubble').play();
};
});
// Class for Pop - optimized version
var PoppedBubble = Container.expand(function () {
var self = Container.call(this);
var popGraphics = self.attachAsset('poppedBubble', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x09899d
});
/****
* Game Code
****/
function tweenDragonContainer() {
tween(dragonOnContainer, {
y: dragonOnContainer.y + 300
}, {
duration: 1000,
onFinish: function onFinish() {
tween(dragonOnContainer, {
y: dragonOnContainer.y - 300
}, {
duration: 1000
});
}
});
}
var started = false; // Initialize started flag
var intervalId = LK.setInterval(function () {
if (!started) {
tweenDragonContainer();
} else {
LK.clearInterval(intervalId); // Clear interval if started is true
}
}, 4000);
var controlPanel = new Container();
var panelBackground = LK.getAsset('game_background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.8
});
controlPanel.addChild(panelBackground);
var instructionsText = new Text2('INSTRUCTIONS', {
size: 100,
fill: 0xffffff,
align: "center",
font: "Comic Sans MS",
fontWeight: "bold"
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 2048 / 2;
instructionsText.y = 75;
controlPanel.addChild(instructionsText);
// Rainbow color array
var rainbowColors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x8B00FF];
var colorIndex = 0;
// Function to cycle through rainbow colors
function cycleRainbowColors() {
instructionsText.tint = rainbowColors[colorIndex];
colorIndex = (colorIndex + 1) % rainbowColors.length;
}
// Set interval to change color less frequently to improve performance
LK.setInterval(cycleRainbowColors, 1000);
var controlText = new Text2('- Click on 🐲 to shoot 🫧\n- Click above the 🐲 to jump ⬆️.\n- The higher you click, the bigger the jump ⬆️⬆️!', {
size: 85,
// Increased size for better visibility
fill: 0x000000,
align: "center",
font: "Comic Sans MS" // Adding a cool font and bold style
});
controlText.anchor.set(0.5, 0.5);
controlText.x = 2048 / 2;
controlText.y = 400;
controlPanel.addChild(controlText);
var understoodButtonBackgroundBg = LK.getAsset('understoodBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 800,
width: 2000,
alpha: 0.5
});
controlPanel.addChild(understoodButtonBackgroundBg);
var dragonOnContainer = LK.getAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200,
scaleX: 2,
scaleY: 2
});
controlPanel.addChild(dragonOnContainer);
var bubbleOnContainer = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: 0.35
});
dragonOnContainer.addChild(bubbleOnContainer);
var understoodButton = new Text2('Click anywhere to start', {
size: 150,
fill: 0x1570e0,
align: "center"
});
understoodButton.anchor.set(0.5, 0.5);
understoodButton.x = 2048 / 2;
understoodButton.y = 800;
controlPanel.addChild(understoodButton);
game.addChild(controlPanel);
// Add event listener to the 'Understood' button
understoodButton.interactive = true;
understoodButton.buttonMode = true;
game.down = function (x, y, obj) {
controlPanel.destroy();
startGame();
};
// Properly initialize all global variables to prevent undefined errors
var bubbles = []; // Initialize bubbles array to store bubble instances
var floors = []; // Initialize floors array to store floor instances
var behaviours = {}; // Initialize behaviours object
var enemies = [];
var capturingBubbles = [];
var jumpStartY = 0;
var isJumping = false; // Initialize jumping state
var canJump = true; // Initialize jump permission flag
var isFalling = false; // Initialize falling state
var lastShot = 0; // Track the last time a bubble was shot
var lastClick = 0; // Track the last time the screen was clicked
var jumpStartTime = 0; // Initialize jump start time
var dragon; // Will be initialized later
var background; // Will be initialized with a background image
function startGame() {
started = true;
var level = 1;
function restartGame() {
// Clear existing platforms and enemies
floors.forEach(function (floor) {
floor.destroy();
});
floors = [];
enemies.forEach(function (enemy) {
enemy.destroy();
});
enemies = [];
// Recreate floors at the bottom, left, and right margins
for (var i = 0; i < 21; i++) {
var floor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: i * 100,
y: 2732 - 30
});
game.addChild(floor);
floors.push(floor);
}
for (var j = 0; j < 27; j++) {
var leftFloor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: j * 100
});
game.addChild(leftFloor);
floors.push(leftFloor);
}
for (var k = 0; k < 27; k++) {
var rightFloor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 50,
y: k * 100
});
game.addChild(rightFloor);
floors.push(rightFloor);
}
// Destroy the existing dragon
dragon.destroy();
// Recreate the dragon and add it to the game
dragon = game.addChild(new Dragon());
// Reposition dragon at the bottom
dragon.x = 1024; // Center horizontally
dragon.y = 2532; // Position the dragon on top of the floor
// Add new platforms and enemies for the new level
for (var j = 0; j < platformYPositions.length; j++) {
var platformLength = Math.floor(Math.random() * (maxPlatformLength - minPlatformLength + 1)) + minPlatformLength;
var startX = Math.floor(Math.random() * (2048 - platformLength * 100));
var startY = platformYPositions[j];
var randomTint = Math.floor(Math.random() * 16777215);
for (var i = 0; i < platformLength; i++) {
var newX = startX + i * 100;
if (newX > 1900 || newX < 120) {
continue;
}
var platform = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: startX + i * 100,
y: platformYPositions[j]
});
platform.tint = randomTint;
game.addChild(platform);
floors.push(platform);
}
var enemyType = 'enemy' + (i % 5 + 1);
var behaviour = behaviours[enemyType] || easingFunctions[Math.floor(Math.random() * easingFunctions.length)];
behaviours[enemyType] = behaviour;
var enemy = LK.getAsset(enemyType, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + 100,
y: platformYPositions[j] - 100,
type: enemyType
});
if (enemyType === 'enemy5' || enemyType === 'enemy2') {
enemy.tint = Math.floor(Math.random() * 0x7FFFFF) + 0x808080;
}
enemy.captured = false;
game.addChild(enemy);
enemies.push(enemy);
}
}
var background = LK.getAsset('pixel_background_' + level.toString(), {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.95
});
game.addChild(background);
// Simplified utility function that replaces all the complex array handlers
function getMinMaxFromFloors(floors, property) {
var min = Infinity;
var max = -Infinity;
for (var i = 0; i < floors.length; i++) {
var value = floors[i][property];
if (value < min) {
min = value;
}
if (value > max) {
max = value;
}
}
return {
min: min,
max: max
};
}
var jumpStartTime; // Declare jumpStartTime to track the start of the jump
var easingFunctions = [tween.linear, tween.easeIn, tween.easeOut, tween.easeInOut, tween.bounceIn, tween.bounceOut, tween.bounceInOut, tween.elasticIn, tween.elasticOut, tween.elasticInOut, tween.cubicIn, tween.cubicOut, tween.cubitInOut, tween.expoIn, tween.expoOut, tween.expoInOut, tween.sineIn, tween.sineOut, tween.sineInOut];
LK.playMusic('music');
function isStandingOnFloor() {
// Store the dragon's position
var dragonBottom = dragon.y + dragon.height / 2;
for (var i = 0; i < floors.length; i++) {
var floor = floors[i];
var floorTop = floor.y - floor.height / 2;
// More precise collision detection for standing on platforms
if (dragon.intersects(floor) && Math.abs(dragonBottom - floorTop) < 20 && dragon.lastY < dragon.y) {
return true;
}
}
return false;
}
function updateFall() {
if (isFalling) {
// Store last position before moving
var lastY = dragon.y;
// Move dragon downwards with a smaller increment to prevent passing through platforms
dragon.y += 20;
// Check for collisions after moving
var isIntersecting = false;
for (var i = 0; i < floors.length; i++) {
// Check if dragon is intersecting with a floor
if (dragon.intersects(floors[i])) {
isIntersecting = true;
// Only stop falling if we weren't intersecting before (just collided)
if (!dragon.lastWasIntersecting || lastY < floors[i].y - floors[i].height) {
isJumping = false; // Stop jumping
isFalling = false; // Stop falling when colliding with a floor
canJump = true; // Allow jumping again when the dragon hits a floor
dragon.y = floors[i].y - floors[i].height * 1.5; // Align dragon to the top of the floor
break;
}
}
}
// Update last known intersection state
dragon.lastWasIntersecting = isIntersecting;
}
}
//<Assets used in the game will automatically appear here>
// Handle mouse move events to move the dragon
game.move = function (x, y, obj) {
// Ignore the event if the target is outside the screen or close to its margins
if (x > 150 && x < 2048 - 200) {
// Set the target x position for the dragon
dragon.targetX = x;
}
};
var isFalling = false; // Initialize isFalling to track dragon's fall state
var dragon = game.addChild(new Dragon());
dragon.lastY = dragon.y; // Initialize lastY position
dragon.x = 1024; // Center horizontally
dragon.y = 2532; // Position the dragon on top of the floor
// Handle game updates with improved frame handling
game.update = function () {
// Move dragon incrementally towards target x with improved movement
if (dragon.targetX !== undefined) {
var increment = (dragon.targetX - dragon.x) / 5; // Faster movement for better responsiveness
if (Math.abs(dragon.targetX - dragon.x) > 1) {
dragon.x += increment;
}
// Update last known position
dragon.lastX = dragon.x;
dragon.lastY = dragon.y;
// Adjust dragon's scale based on targetX position
if (dragon.targetX < dragon.x) {
dragon.scale.x = -1;
} else {
dragon.scale.x = 1;
}
}
// Always check floor standing to prevent falling through platforms
var standingOnFloor = isStandingOnFloor();
if (!standingOnFloor && !isJumping) {
isFalling = true;
}
// Always update jumping and falling
updateJump();
updateFall();
// Update bubbles every frame for consistent collision detection
updateBubbles();
// Keep enemy movement at higher frequency to fix enemies not moving
if (LK.ticks % 5 === 0) {
updateEnemiesMovement();
}
};
// Handle touch events for shooting bubbles
var lastShot = 0;
var lastClick = 0;
var isJumping = false; // Add a variable to track if the dragon is jumping
var canJump = true; // Initialize canJump flag to allow jumping
game.down = function (x, y, obj) {
var now = Date.now();
if (y < dragon.y - dragon.height && canJump && !isJumping) {
isJumping = true; // Set isJumping to true when the dragon starts jumping
// Play jump sound when the dragon starts jumping
LK.getSound('jump').play();
jumpStartY = y; // Capture the Y position of the mouse click
jumpStartTime = Date.now(); // Initialize jump start time
} else if (!isJumping) {
// Reduce cooldown for more responsive shooting and fix bubble creation
if (now - lastShot > 300) {
// Ensure dragon exists before calling shootBubble
if (dragon && typeof dragon.shootBubble === 'function') {
dragon.shootBubble();
lastShot = now;
}
}
}
lastClick = now;
};
function updateEnemiesMovement() {
// Process all enemies every frame to ensure consistent movement
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy) {
continue;
}
if (enemy.captured) {
if (enemy.isMoving) {
tween.stop(enemy);
enemy.isMoving = false;
enemy.floating = true;
} else if (enemy.floating) {
var enemyRef = enemy; // Create a strong reference to avoid context loss
// Store reference to current enemy in a closure variable
(function (currentEnemy) {
tween(currentEnemy, {
y: 100
}, {
duration: 5000,
easing: tween.linear,
onFinish: function onFinish() {
// Use the closure variable instead of 'this'
if (currentEnemy && currentEnemy.children && currentEnemy.children[1]) {
currentEnemy.children[1].tint = 0xbf5555;
}
if (enemies.length === 0) {
if (level < 5) {
level++;
background.destroy(); // Remove the previous background
background = LK.getAsset('pixel_background_' + level.toString(), {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 - background.height / 2,
alpha: 0.95
});
game.addChild(background); // Add the new background
// Combined level text creation to reduce object creation
var levelText = new Text2('LEVEL ' + level.toString(), {
size: 200,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = 2048 / 2;
levelText.y = 2732 / 2;
game.addChild(levelText);
LK.setTimeout(function () {
levelText.destroy();
}, 2000);
// Restart game with new platforms and enemies
restartGame();
} else {
LK.showYouWin();
}
}
}
});
})(enemyRef);
}
} else {
// Initialize movement if not already moving
if (!enemy.isMoving && !enemy.tweenInitialized) {
enemy.isMoving = true;
enemy.tweenInitialized = true;
// Find all platform floors for this enemy
var platformFloors = [];
var platformY = enemy.y + 100;
for (var j = 0; j < floors.length; j++) {
if (Math.abs(floors[j].y - platformY) < 10 && floors[j].x > 0 && floors[j].x < 2048 - 50) {
platformFloors.push(floors[j]);
}
}
// Only proceed if we found platform floors
if (platformFloors.length > 0) {
// Find min and max X positions
var startX = 2048;
var endX = 0;
for (var j = 0; j < platformFloors.length; j++) {
if (platformFloors[j].x < startX) {
startX = platformFloors[j].x;
}
if (platformFloors[j].x > endX) {
endX = platformFloors[j].x;
}
}
// Ensure we have a valid range to move in
if (startX < endX) {
enemy.alpha = 0.75; // Apply alpha when starting to move
// Store the platform range for this enemy
enemy.startX = startX;
enemy.endX = endX;
// Start the movement tween
// Make sure to attach context to all tweens and store a strong reference to enemy
var enemyRef = enemy; // Create a strong reference to avoid context loss
// Use immediately invoked function to create closure for this enemy
(function (currentEnemy, startPos, endPos) {
function moveToStart(enemy) {
enemy.isMovingRight = false;
tween(enemy, {
x: startPos
}, {
duration: 3000,
easing: tween.linear,
onFinish: function onFinish() {
if (!enemy) {
return;
}
enemy.isMovingRight = true;
moveToEnd(enemy);
}
});
}
function moveToEnd(enemy) {
tween(enemy, {
x: endPos
}, {
duration: 3000,
easing: tween.linear,
onFinish: function onFinish() {
if (!enemy || enemy.isMovingRight === undefined) {
return;
}
enemy.isMovingRight = false;
moveToStart(enemy);
}
});
}
// Start initial movement
tween(currentEnemy, {
x: endPos
}, {
duration: 3000,
easing: behaviours[currentEnemy.type] || tween.linear,
onFinish: function onFinish() {
if (!currentEnemy) {
return;
}
moveToStart(currentEnemy);
}
});
})(enemyRef, enemyRef.startX, enemyRef.endX);
enemy.isMovingRight = true;
}
}
}
// Update enemy direction based on movement
if (enemy.x !== enemy.lastX) {
enemy.scale.x = enemy.x > enemy.lastX ? 1 : -1;
}
// Check for collision with dragon
if (!enemy.captured && dragon.intersects(enemy)) {
// Play game over sound when the dragon dies
LK.getSound('gameover').play();
// Rotate the dragon 90 degrees
dragon.rotation = -3 * Math.PI * dragon.scale.x;
// Animate the dragon falling down - simplified tween with proper context
var dragonRef = dragon; // Create a strong reference to avoid context loss
// Use immediately invoked function to create closure
(function (dragonToTween) {
tween(dragonToTween, {
y: 2732 + dragonToTween.height,
tint: 0xFF0000
}, {
duration: 500,
easing: tween.linear,
onFinish: function onFinish() {
LK.showGameOver();
}
});
})(dragonRef);
}
}
// Update last known position
enemy.lastX = enemy.x;
enemy.lastY = enemy.y;
}
// Always check for collisions with the dragon for all enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.captured && dragon.intersects(enemy)) {
// Game over handling moved outside the loop to avoid duplicate calls
// Just mark for game over
if (!game.gameOverTriggered) {
game.gameOverTriggered = true;
// Play game over sound when the dragon dies
LK.getSound('gameover').play();
// Rotate the dragon 90 degrees
dragon.rotation = -3 * Math.PI * dragon.scale.x;
// Animate the dragon falling down - simplified tween with proper context
var dragonRef = dragon; // Create a strong reference to avoid context loss
// Use immediately invoked function to create closure
(function (dragonToTween) {
tween(dragonToTween, {
y: 2732 + dragonToTween.height,
tint: 0xFF0000
}, {
duration: 500,
easing: tween.linear,
onFinish: function onFinish() {
LK.showGameOver();
}
});
})(dragonRef);
}
break;
}
}
}
function updateBubbles() {
// Ensure bubbles array exists to prevent errors
if (!bubbles) {
bubbles = [];
return;
}
// Process all bubbles every frame for consistent collision detection
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
if (!bubble) {
bubbles.splice(i, 1);
continue;
}
// Call the bubble's update method to move it
if (bubble.update) {
bubble.update();
}
// Check for bubble-bubble intersections
for (var j = i - 1; j >= 0; j--) {
if (j >= bubbles.length) {
continue;
}
var otherBubble = bubbles[j];
if (!otherBubble) {
bubbles.splice(j, 1);
continue;
}
if (bubble.intersects(otherBubble)) {
// Create a PoppedBubble for each intersecting bubble
var pop1 = game.addChild(new PoppedBubble());
pop1.x = bubble.x;
pop1.y = bubble.y;
var pop2 = game.addChild(new PoppedBubble());
pop2.x = otherBubble.x;
pop2.y = otherBubble.y;
// Destroy both bubbles safely
bubble.destroy();
otherBubble.destroy();
// Remove from bubbles array safely (be defensive)
if (i < bubbles.length) {
bubbles.splice(i, 1);
}
// Adjust index after removing item at position i
if (j < bubbles.length) {
if (j >= i) {
bubbles.splice(j - 1, 1);
} else {
bubbles.splice(j, 1);
}
}
// Play pop sound when a bubble is popped
LK.getSound('pop').play();
// Destroy the PoppedBubbles after 0.5 seconds
LK.setTimeout(function () {
pop1.destroy();
pop2.destroy();
}, 500);
// Exit inner loop
break;
}
}
// Skip if bubble was destroyed in collision check
if (!bubble || i >= bubbles.length) {
continue;
}
// Remove bubbles that go off-screen
if (bubble.y < -50 || bubble.x < -50 || bubble.x > 2100) {
bubble.destroy();
if (i < bubbles.length) {
bubbles.splice(i, 1);
}
}
}
// Check for bubble-enemy collisions every frame for more reliable hits
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy || enemy.captured) {
continue;
}
for (var j = bubbles.length - 1; j >= 0; j--) {
var bubble = bubbles[j];
if (!bubble) {
continue;
}
if (bubble.intersects(enemy)) {
// Destroy the original bubble
bubble.destroy();
bubbles.splice(j, 1);
// Create a new bubble as a child of the enemy
var newBubble = new CapturingBubble();
newBubble.x = 0; // Position relative to the enemy
newBubble.y = 0; // Position relative to the enemy
enemy.addChild(newBubble);
enemy.captured = true;
capturingBubbles.push(newBubble);
break;
}
}
}
// Check if the dragon is intersecting a bubble - every frame for reliability
for (var i = bubbles.length - 1; i >= 0; i--) {
if (i >= bubbles.length) {
continue;
} // Safety check
var bubble = bubbles[i];
if (!bubble) {
continue;
}
if (dragon.intersects(bubble)) {
// Create a PoppedBubble at the bubble's position
var pop = game.addChild(new PoppedBubble());
pop.x = bubble.x;
pop.y = bubble.y;
// Destroy the bubble safely
bubble.destroy();
bubbles.splice(i, 1);
// Play pop sound when a bubble is popped
LK.getSound('pop').play();
// Destroy the PoppedBubble after 0.5 seconds
LK.setTimeout(function () {
pop.destroy();
}, 500);
break;
}
}
// Process capturing bubbles every frame for better reliability
if (capturingBubbles.length > 0) {
// Check if the dragon is intersecting a CapturingBubble
for (var i = capturingBubbles.length - 1; i >= 0; i--) {
if (i >= capturingBubbles.length) {
continue;
} // Safety check
var capturingBubble = capturingBubbles[i];
if (!capturingBubble) {
continue;
}
if (dragon.intersects(capturingBubble)) {
// Find and destroy the enemy that is the parent of the CapturingBubble
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (!enemy) {
continue;
}
if (enemy.children && enemy.children.indexOf(capturingBubble) !== -1) {
// Create a PoppedBubble at the capturingBubble's position
var pop = game.addChild(new PoppedBubble());
pop.x = enemy.x;
pop.y = enemy.y;
// Destroy the enemy and capturingBubble
enemy.destroy();
enemies.splice(j, 1);
// Remove from capturing bubbles array
capturingBubbles.splice(i, 1);
// Play pop sound when a capturing bubble is popped
LK.getSound('pop').play();
// Destroy the PoppedBubble after 1 second
LK.setTimeout(function () {
pop.destroy();
}, 1000);
break;
}
}
}
}
}
// Update capturing bubbles
for (var i = capturingBubbles.length - 1; i >= 0; i--) {
if (i >= capturingBubbles.length) {
continue;
} // Safety check
var capturingBubble = capturingBubbles[i];
if (!capturingBubble) {
continue;
}
var enemy = capturingBubble.parent;
if (enemy && enemy.captured && !enemy.floating) {
enemy.y -= 5; // Make the enemy float up more smoothly
}
}
}
function updateJump() {
if (isJumping) {
var jumpHeight = (dragon.y - jumpStartY) / 10;
dragon.y -= jumpHeight; // Move dragon upwards based on calculated jump height
// More efficient intersection check with early termination
var dragonIntersectsFloor = false;
for (var i = 0; i < floors.length; i++) {
if (dragon.intersects(floors[i])) {
dragonIntersectsFloor = true;
if (!dragon.lastWasIntersecting) {
isJumping = false; // Stop jumping
isFalling = true; // Start falling when colliding with a floor
canJump = false; // Disallow jumping again until the dragon hits a floor
dragon.y -= 25;
}
break;
}
}
// Check if jump duration has exceeded 0.4 seconds
if (Date.now() - jumpStartTime >= 400) {
isJumping = false;
isFalling = true;
}
// Update last known intersection state
dragon.lastWasIntersecting = dragonIntersectsFloor;
}
}
// BLOCKS
// Add a floor to the bottom of the screen
var floors = [];
for (var i = 0; i < 21; i++) {
var floor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: i * 100,
y: 2732 - 30
});
game.addChild(floor);
floors.push(floor);
}
// Add continuous floor on the left margin of the screen
for (var j = 0; j < 27; j++) {
var leftFloor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: j * 100
});
game.addChild(leftFloor);
floors.push(leftFloor);
}
// Add continuous floor on the right margin of the screen
for (var k = 0; k < 27; k++) {
var rightFloor = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 50,
y: k * 100
});
game.addChild(rightFloor);
floors.push(rightFloor);
}
// Add random platforms with irregular heights and positions
var platformYPositions = [];
var distinctHeights = [2300, 1900, 1500, 1100, 700]; // Define 4-5 distinct heights
var minPlatformLength = 5;
var maxPlatformLength = 14;
distinctHeights.forEach(function (height) {
platformYPositions.push(height);
});
// Add random platforms with irregular heights and positions
for (var j = 0; j < platformYPositions.length; j++) {
var _behaviours$enemyType;
var platformLength = Math.floor(Math.random() * (maxPlatformLength - minPlatformLength + 1)) + minPlatformLength;
var startX = Math.floor(Math.random() * (2048 - platformLength * 100)); // Random start position
var startY = platformYPositions[j];
// Generate a random tint color for the platforms
var randomTint = Math.floor(Math.random() * 16777215);
for (var i = 0; i < platformLength; i++) {
var newX = startX + i * 100;
if (newX > 1900 || newX < 120) {
continue;
}
var platform = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: startX + i * 100,
y: platformYPositions[j]
});
platform.tint = randomTint; // Apply the random tint to the platform
game.addChild(platform);
floors.push(platform);
}
// Spawn an enemy on top of each platform
var enemyType = 'enemy' + (i % 5 + 1); // Cycle through enemy1 to enemy5
var behaviour = (_behaviours$enemyType = behaviours[enemyType]) !== null && _behaviours$enemyType !== void 0 ? _behaviours$enemyType : easingFunctions[Math.floor(Math.random() * easingFunctions.length)]; // Assign random easing function;
behaviours[enemyType] = behaviour;
var enemy = LK.getAsset(enemyType, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + 100,
y: platformYPositions[j] - 100,
type: enemyType
});
if (enemyType === 'enemy5' || enemyType === 'enemy2') {
enemy.tint = Math.floor(Math.random() * 0x7FFFFF) + 0x808080; // Ensure light tint
}
enemy.captured = false;
game.addChild(enemy);
enemies.push(enemy);
}
/* LEVEL MANAGEMENT 1 */
var levelTextBackground = new Text2('LEVEL ' + level.toString(), {
size: 210,
fill: 0x000000
});
levelTextBackground.anchor.set(0.5, 0.5);
levelTextBackground.x = 2048 / 2;
levelTextBackground.y = 2732 / 2;
game.addChild(levelTextBackground);
LK.setTimeout(function () {
levelTextBackground.destroy();
}, 2000);
var levelText = new Text2('LEVEL ' + level.toString(), {
size: 200,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = 2048 / 2;
levelText.y = 2732 / 2;
game.addChild(levelText);
LK.setTimeout(function () {
levelText.destroy();
}, 2000);
} ===================================================================
--- original.js
+++ change.js
@@ -86,15 +86,16 @@
} else {
// If the dragon is looking left, the bubble should move to the left
bubble.speed = -25;
}
- // Add bubble to game display list
+ // Add bubble to game display list first to ensure it's rendered
game.addChild(bubble);
- // Make sure the bubble gets tracked in our global array
- // Use this pattern to ensure we don't lose track of bubbles
- if (bubbles) {
- bubbles.push(bubble);
+ // Ensure bubbles array exists before trying to push to it
+ if (!bubbles) {
+ bubbles = [];
}
+ // Always add bubble to tracking array
+ bubbles.push(bubble);
// Play bubble sound when a bubble is shot
LK.getSound('bubble').play();
};
});
@@ -230,8 +231,14 @@
var behaviours = {}; // Initialize behaviours object
var enemies = [];
var capturingBubbles = [];
var jumpStartY = 0;
+var isJumping = false; // Initialize jumping state
+var canJump = true; // Initialize jump permission flag
+var isFalling = false; // Initialize falling state
+var lastShot = 0; // Track the last time a bubble was shot
+var lastClick = 0; // Track the last time the screen was clicked
+var jumpStartTime = 0; // Initialize jump start time
var dragon; // Will be initialized later
var background; // Will be initialized with a background image
function startGame() {
started = true;
@@ -451,11 +458,15 @@
LK.getSound('jump').play();
jumpStartY = y; // Capture the Y position of the mouse click
jumpStartTime = Date.now(); // Initialize jump start time
} else if (!isJumping) {
- if (now - lastClick > 500) {
- dragon.shootBubble();
- lastShot = now;
+ // Reduce cooldown for more responsive shooting and fix bubble creation
+ if (now - lastShot > 300) {
+ // Ensure dragon exists before calling shootBubble
+ if (dragon && typeof dragon.shootBubble === 'function') {
+ dragon.shootBubble();
+ lastShot = now;
+ }
}
}
lastClick = now;
};
@@ -668,22 +679,32 @@
}
}
}
function updateBubbles() {
+ // Ensure bubbles array exists to prevent errors
+ if (!bubbles) {
+ bubbles = [];
+ return;
+ }
// Process all bubbles every frame for consistent collision detection
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
if (!bubble) {
+ bubbles.splice(i, 1);
continue;
}
// Call the bubble's update method to move it
if (bubble.update) {
bubble.update();
}
- // Check for bubble-bubble intersections
+ // Check for bubble-bubble intersections
for (var j = i - 1; j >= 0; j--) {
+ if (j >= bubbles.length) {
+ continue;
+ }
var otherBubble = bubbles[j];
if (!otherBubble) {
+ bubbles.splice(j, 1);
continue;
}
if (bubble.intersects(otherBubble)) {
// Create a PoppedBubble for each intersecting bubble
@@ -695,15 +716,19 @@
pop2.y = otherBubble.y;
// Destroy both bubbles safely
bubble.destroy();
otherBubble.destroy();
- // Remove from bubbles array safely
- bubbles.splice(i, 1);
+ // Remove from bubbles array safely (be defensive)
+ if (i < bubbles.length) {
+ bubbles.splice(i, 1);
+ }
// Adjust index after removing item at position i
- if (j >= i) {
- bubbles.splice(j, 1);
- } else {
- bubbles.splice(j, 1);
+ if (j < bubbles.length) {
+ if (j >= i) {
+ bubbles.splice(j - 1, 1);
+ } else {
+ bubbles.splice(j, 1);
+ }
}
// Play pop sound when a bubble is popped
LK.getSound('pop').play();
// Destroy the PoppedBubbles after 0.5 seconds
@@ -721,9 +746,11 @@
}
// Remove bubbles that go off-screen
if (bubble.y < -50 || bubble.x < -50 || bubble.x > 2100) {
bubble.destroy();
- bubbles.splice(i, 1);
+ if (i < bubbles.length) {
+ bubbles.splice(i, 1);
+ }
}
}
// Check for bubble-enemy collisions every frame for more reliable hits
for (var i = enemies.length - 1; i >= 0; i--) {
A version of this bubble but exploded
brick, brown color, pixel style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
better wings, pixel style, more contrasted, more visible, blue color
a pixel clouds background. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a pixel clouds background, with mountains, full height full width Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a similar image. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a pixel clouds background, with mountains, full height full width Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A popped blue bobble, pixel style, bubble booble arcade game inspired. In-Game asset. 2d. High contrast. No shadows
A bubble popping, pixel style, retro. In-Game asset. 2d. High contrast. No shadows