User prompt
Make sure that harpoons intersecting with powerboxes activate the powerboxes (collect them) for the user
User prompt
Some trail segments seem to not be destroyed, especially those created after a powerbox.
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'destroy')' in or related to this line: 'harpoon.trail.destroy();' Line Number: 1031
Code edit (2 edits merged)
Please save this source code
User prompt
The trail now is 1 and it's scaled (self.trail.height) going from the startY to self.y. Instead, please divide that height by 100 and generate 1 trail per each 100 pixels.
User prompt
The trails, redo them completely. THere should be 1 trail always attached to the harpoon, rendering from the harpoon y position to 100 pixels below. And then if 1 more trail segment per 100 pixels of distance between the harpoon and the player on y
User prompt
I don't see any trail at all.
User prompt
As the harpoon goes up, generate "trail" segments using the "trail" asset from the player to the harpoon as it goes up.
User prompt
Remove the trails / line completely
Code edit (1 edits merged)
Please save this source code
User prompt
Segment heights are small. They sholuld be higher. And segments hsould stack on top of each other, they are being now overlapped on the same place
Code edit (1 edits merged)
Please save this source code
User prompt
Only harpoons at the player position are being drawn. They are not drawn higher than that! There should be m ore segments higher one of top of another, up to the harpoon!
User prompt
Redo the harppon and the trails completely. Here is what I need: When fired, the harpoon shoots straight upward from the player’s position, extending all the way to the top of the screen in a perfect vertical line. The harpoon itself is instant— abd the trail / cable follows after, covering the space between the player and the harpoon, as the harpoon goes up. Creating an effect of "trail". The condition: the trail should consist of different segments of height 100 pixels. So if you have 100 pixels, it's 1 trail segment. If you have 200, 2 segments. If you have 250, 3 segments (last segment 50 pixels as it's the last).
User prompt
No trails are renderer at all.
User prompt
I don't see the trails? What happened? As the harpoon goes up, trails should be generated from the player to the harpoon
User prompt
You've got it wrong: the trail segments are drawn from the player to the harpoon!
User prompt
Harpoon should always be up, trails should always follow below, like this> ^^^ | | | |
User prompt
Reverse the rendering of the trail segments and the harpoon
User prompt
Something is not right: the harpoon should be going up first, and then the trail and trail segments should follow below, but can't never overpass it. A trail can-t have an upper position than a harpoon.
User prompt
Ok the issue now is that the trail should always be below the harpoon, now the trail segments are rendered above the harpoon. The logic is the following: as the harpoon goes up, it will be generating trail segments.
User prompt
Ok, the trail is 1 and it gets scaled vertically. The issue - the texture gets a lot of distorsion as we scale it on y. Please do the following - instead of scaling the trail, create trails one after another so that the texture is kept intact. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Make the bubbles spawn not at a 10% from the bottom, but a 25% from the bottom
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Box class
var Box = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('box', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// Increase the scale to enlarge the bounding box
scaleY: 1.2
});
self.speed = 5;
self.lastIntersecting = false; // Track last intersection state with player
self.update = function () {
self.y += self.speed;
// Check for player intersection transitions
var currentIntersecting = self.intersects(player);
if (!self.lastIntersecting && currentIntersecting) {
// Flash the box briefly to indicate collection is possible
tween(boxGraphics, {
tint: 0xFFFF00,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(boxGraphics, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
if (self.y > 2732) {
self.destroy();
}
};
});
// Box1 class
var Box1 = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('box1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// Increase the scale to enlarge the bounding box
scaleY: 1.2
});
self.speed = 5;
self.lastIntersecting = false; // Track last intersection state with player
self.update = function () {
self.y += self.speed;
// Check for player intersection transitions
var currentIntersecting = self.intersects(player);
if (!self.lastIntersecting && currentIntersecting) {
// Flash the box briefly to indicate collection is possible
tween(boxGraphics, {
tint: 0xFF00FF,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(boxGraphics, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
if (self.y > 2732) {
self.destroy();
}
};
});
// Box2 class
var Box2 = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('box2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// Increase the scale to enlarge the bounding box
scaleY: 1.2
});
self.speed = 7;
self.lastIntersecting = false; // Track last intersection state with player
self.update = function () {
self.y += self.speed;
// Check for player intersection transitions
var currentIntersecting = self.intersects(player);
if (!self.lastIntersecting && currentIntersecting) {
// Flash the box briefly to indicate collection is possible
tween(boxGraphics, {
tint: 0x00FFFF,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(boxGraphics, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
if (self.y > 2732) {
self.destroy();
}
};
});
// Box3 class
var Box3 = Container.expand(function () {
var self = Container.call(this);
var boxGraphics = self.attachAsset('box3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// Increase the scale to enlarge the bounding box
scaleY: 1.2
});
self.speed = 9;
self.lastIntersecting = false; // Track last intersection state with player
self.update = function () {
self.y += self.speed;
// Check for player intersection transitions
var currentIntersecting = self.intersects(player);
if (!self.lastIntersecting && currentIntersecting) {
// Flash the box briefly to indicate collection is possible with heart color
tween(boxGraphics, {
tint: 0xFF0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(boxGraphics, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
self.lastIntersecting = currentIntersecting;
if (self.y > 2732) {
self.destroy();
}
};
});
// The assets will be automatically created and loaded by the LK engine.
// Bubble class
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0 // Start transparent
});
// Make the bubble opaque after 1 second
tween(bubbleGraphics, {
alpha: 1
}, {
duration: 1000
});
self.speed = -10; // Negative speed to move upward
self.lastY = undefined; // Track last position for intersection checks
self.hasHitTop = false; // Flag to track if lantern has gone off screen at top
self.update = function () {
if (self.lastY === undefined) {
self.lastY = self.y;
}
self.y += self.speed;
if (self.y < 1200) {
// Start tinting when approaching the top
tween(self, {
tint: 0xFF0000
}, {
duration: 500,
easing: tween.linear
});
}
// Check if the lantern is going off the top of the screen without being destroyed
if (self.lastY >= 0 && self.y < 0 && !self.hasHitTop) {
self.hasHitTop = true; // Mark as hit top to prevent multiple life deductions
// Player didn't destroy the lantern in time
lives -= 1;
// Create explosion effect at the top where the lantern left
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = 10; // Just at the edge of the screen
game.addChild(explosion);
// Play explosion sound
LK.getSound('explosion').play();
// Remove a heart icon when a life is lost
if (hearts.length > lives) {
var heartToRemove = hearts.pop();
if (heartToRemove) {
tween(heartToRemove.scale, {
x: 0,
y: 0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
heartToRemove.destroy();
}
});
}
}
if (lives < 0) {
// Handle player death with dramatic effect
handlePlayerDeath();
return;
}
self.destroy();
}
// Handle going completely off screen
// Note: Not removing the lantern when it intersects with player
// as per the requirement that player collision shouldn't remove lives
if (self.y < -200) {
self.destroy();
}
self.lastY = self.y;
};
});
// Explosion class with color customization
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
// Extend self with tint property accessor/mutator to allow tinting the explosion
Object.defineProperty(self, 'tint', {
get: function get() {
return explosionGraphics.tint;
},
set: function set(value) {
explosionGraphics.tint = value;
}
});
// Apply explosion animation
tween(explosionGraphics, {
scaleX: explosionGraphics.scaleX + 1,
scaleY: explosionGraphics.scaleY + 1
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.destroy();
}
});
self.update = function () {
// The explosion will disappear after a while
if (self.alpha > 0) {
self.alpha -= 0.005;
} else {
self.destroy();
}
};
});
// Harpoon class
var Harpoon = Container.expand(function () {
var self = Container.call(this);
var harpoonGraphics = self.attachAsset('harpoon', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -30; // Fast speed for instant vertical movement
self.maxDistance = 2732; // Maximum distance - entire screen height
self.startY = 0; // Will store the starting Y position
self.playerY = 0; // Will store the player's Y position
self.trail = null; // Will store the trail
self.update = function () {
// Store initial position on first update
if (self.startY === 0) {
self.startY = self.y;
self.playerY = player.y - 200; // Store player's position
// Create trail on first update
self.trail = new Trail();
self.trail.x = self.x;
self.trail.y = self.playerY;
game.addChild(self.trail);
// Ensure trail is below harpoon in rendering order
game.setChildIndex(self.trail, game.getChildIndex(self));
}
// Move harpoon up at constant speed
self.y += self.speed;
// Update trail to connect player position to harpoon
if (self.trail) {
self.trail.x = self.x;
self.trail.updateTrail(self.playerY, self.y);
}
// Destroy when reaching top of screen or maximum distance
if (self.y < 0 || self.startY - self.y > self.maxDistance) {
if (self.trail) {
self.trail.destroy();
}
self.destroy();
}
};
// Override destroy to also remove trail
var originalDestroy = self.destroy;
self.destroy = function () {
if (self.trail) {
self.trail.destroy();
}
originalDestroy.call(self);
};
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.update = function () {
if (self.direction && self.direction === 'left') {
self.x -= self.speed;
} else if (self.direction === 'right') {
self.x += self.speed;
}
};
self.shoot = function () {
var harpoon = new Harpoon();
// Position harpoon at player
harpoon.x = player.x;
harpoon.y = player.y - 200;
// Initialize harpoon properties
harpoon.startY = harpoon.y;
harpoon.playerY = player.y - 200;
// Flag normal harpoons (from player) to allow them to create boxes
harpoon.isPlayerCreated = true;
// Then add the harpoon
game.addChild(harpoon);
// Play crossbow sound
LK.getSound('crossbow').play();
};
});
// PlayerDeathEffect class - creates a dramatic death sequence with rainbow colors
var PlayerDeathEffect = Container.expand(function () {
var self = Container.call(this);
// Create the main container for all death effect elements
var effectContainer = new Container();
self.addChild(effectContainer);
// Rainbow colors array (red, orange, yellow, green, blue, indigo, violet)
var rainbowColors = [
// Indigo
0x9400D3,
// Violet
0xfaadad,
// Red
0xFF7F00,
// Orange
0xFFFF00,
// Yellow
0x00FF00,
// Green
0x0000FF,
// Blue
0x4B0082];
// Add a full-screen overlay for dramatic effect
var overlay = LK.getAsset('deadBg', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Full width (2048px)
scaleY: 27.32,
// Full height (2732px)
tint: rainbowColors[0],
// Start with red
alpha: 0
});
effectContainer.addChild(overlay);
// Add dramatic text
var gameOverText = new Text2('GAME OVER', {
size: 150,
fill: 0xFFFFFF,
font: "'Comic Sans MS', cursive, sans-serif"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 / 2;
gameOverText.alpha = 0;
gameOverText.scale.set(0.1);
effectContainer.addChild(gameOverText);
// Function to create a rainbow tint sequence
function createRainbowTintSequence(target, startIndex, duration) {
var colorIndex = startIndex % rainbowColors.length;
var nextColorIndex = (colorIndex + 1) % rainbowColors.length;
tween(target, {
tint: rainbowColors[nextColorIndex]
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
createRainbowTintSequence(target, nextColorIndex, duration);
}
});
}
// Add rainbow flickering effect
self.startEffect = function () {
// Pulse the overlay with rainbow colors
tween(overlay, {
alpha: 0.5
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
// Start the rainbow color sequence
createRainbowTintSequence(overlay, 0, 300);
}
});
// Show and scale the text
tween(gameOverText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
easing: tween.elasticOut
});
// Create explosion effects at random positions with rainbow colors
for (var i = 0; i < 5; i++) {
LK.setTimeout(function (colorIndex) {
var explosion = new Explosion();
explosion.x = Math.random() * 2048;
explosion.y = Math.random() * 2732;
// Give each explosion a different color from the rainbow
explosion.tint = rainbowColors[colorIndex % rainbowColors.length];
effectContainer.addChild(explosion);
// Play explosion sound
LK.getSound('explosion').play();
}.bind(null, i), 300 * i);
}
// Show actual game over screen after the effect
LK.setTimeout(function () {
self.destroy();
LK.showGameOver();
}, 2500); // Show game over after 2.5 seconds
};
return self;
});
// PowerUpText class
var PowerUpText = Container.expand(function () {
var self = Container.call(this);
var textGraphics = self.attachAsset('PowerUpText', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.y -= 2;
if (self.y < 0) {
self.destroy();
}
};
});
// Trail class
var Trail = Container.expand(function () {
var self = Container.call(this);
self.segments = [];
self.segmentHeight = 100; // Fixed segment height of 100 pixels
self.createSegment = function (yOffset, height) {
var segment = new Container();
var segmentGraphics = segment.attachAsset('trail', {
anchorX: 0.5,
anchorY: 0,
scaleY: height / 100 // Scale to match desired height
});
segment.y = yOffset;
segment.height = height; // Store segment height for later adjustments
self.addChild(segment);
self.segments.push(segment);
return segment;
};
// Update existing segments or create new ones
self.updateTrail = function (startY, endY) {
// Calculate total distance
var totalHeight = startY - endY;
if (totalHeight <= 0) {
return;
}
// Calculate number of segments needed
var numSegments = Math.ceil(totalHeight / self.segmentHeight);
// Create or update segments
for (var i = 0; i < numSegments; i++) {
var segmentHeight = i === numSegments - 1 && totalHeight % self.segmentHeight !== 0 ? totalHeight % self.segmentHeight : self.segmentHeight;
// Calculate y position for this segment (stacking from bottom to top)
var yPos = -totalHeight + i * self.segmentHeight;
// Create or update segment
if (i < self.segments.length) {
self.segments[i].y = yPos;
self.segments[i].height = segmentHeight;
self.segments[i].children[0].scaleY = segmentHeight / 100;
} else {
self.createSegment(yPos, segmentHeight);
}
}
// Remove excess segments
while (self.segments.length > numSegments) {
var segment = self.segments.pop();
segment.destroy();
}
};
// The trail doesn't need its own update movement since it's positioned relative to the harpoon
self.update = function () {
// Trail no longer moves independently
// Its position is now fully controlled by the Harpoon
if (self.y > 2732) {
self.destroy();
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFFFFFFF // Init game with black background
});
/****
* Game Code
****/
var background = game.attachAsset('Landscape', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.setChildIndex(background, 0);
// Add a warning zone at the top to indicate the danger area
var warningZone = new Container();
var warningGraphics = LK.getAsset('scoreBg', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
// Make it span the entire width (2048px)
scaleY: 1.5,
tint: 0xFF3333,
// Red tint to indicate danger
alpha: 0.3 // Semi-transparent
});
warningZone.addChild(warningGraphics);
warningZone.x = 0;
warningZone.y = 0;
game.addChild(warningZone);
var player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 180;
game.addChild(player); // Add player after trail to ensure correct rendering order
// Add a description text for the warning zone
var warningText = new Text2('Lanterns escaping at the top will cost a life!', {
size: 30,
fill: 0xFFFFFF,
font: "'Comic Sans MS', cursive, sans-serif"
});
warningText.anchor.set(0.5, 0);
warningText.x = 2048 / 2;
warningText.y = 130;
game.addChild(warningText);
// Make the warning text pulse to draw attention
var _pulseWarning = function pulseWarning() {
tween(warningText.scale, {
x: 1.2,
y: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(warningText.scale, {
x: 1.0,
y: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: _pulseWarning
});
}
});
};
_pulseWarning();
game.move = function (x, y, obj) {
player.x = x;
if (x < 2048 / 2 && player.scaleX > 0 || x >= 2048 / 2 && player.scaleX < 0) {
player.scaleX *= -1; // Mirror the player image
}
};
var score = 0;
var lives = 3;
var scoreBackground = new Container();
var scoreBgGraphics = scoreBackground.attachAsset('scoreBg', {
anchorX: 0.5,
anchorY: 0.1,
scaleX: 5,
scaleY: 5,
alpha: 1
});
scoreBackground.addChild(scoreBgGraphics);
scoreBackground.x = 0;
scoreBackground.y = 0;
LK.gui.top.addChild(scoreBackground);
var scoreTxt = new Text2('Lanterns destroyed: 0', {
size: 30,
fill: 0xFF3659,
font: "'Comic Sans MS', cursive, sans-serif"
});
scoreTxt.anchor.set(0.5, -0.1);
scoreBackground.addChild(scoreTxt);
var hearts = [];
for (var i = 0; i < lives; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: -1 * (i + 1) * 50,
// Position hearts with some spacing
y: 50
});
LK.gui.topRight.addChild(heart);
hearts.push(heart);
}
// Function to apply box effects based on box type
function applyBoxEffect(box) {
// Check if the collected box is an instance of Box1
if (box instanceof Box1) {
// If we already have box1 harpoons, destroy them first
var existingHarpoons = game.children.filter(function (child) {
return child instanceof Harpoon && child.isFromBox1 === true;
});
existingHarpoons.forEach(function (harpoon) {
harpoon.destroy();
});
// Create six additional harpoons
for (var i = 1; i <= 3; i++) {
var leftHarpoon = new Harpoon();
leftHarpoon.x = player.x - i * 150;
leftHarpoon.y = player.y - 200;
leftHarpoon.startY = leftHarpoon.y;
leftHarpoon.playerY = player.y - 200;
// Mark harpoons created by box power-up
leftHarpoon.isPlayerCreated = false;
leftHarpoon.isFromBox1 = true; // Mark specifically as from Box1 power-up
// Add the harpoon
game.addChild(leftHarpoon);
var rightHarpoon = new Harpoon();
rightHarpoon.x = player.x + i * 150;
rightHarpoon.y = player.y - 200;
rightHarpoon.startY = rightHarpoon.y;
rightHarpoon.playerY = player.y - 200;
// Mark harpoons created by box power-up
rightHarpoon.isPlayerCreated = false;
rightHarpoon.isFromBox1 = true; // Mark specifically as from Box1 power-up
// Add the harpoon
game.addChild(rightHarpoon);
// Set a timeout to remove the additional harpoons after 5 seconds
LK.setTimeout(function (lh, rh) {
lh.destroy();
rh.destroy();
}.bind(null, leftHarpoon, rightHarpoon), 5000);
}
}
// Check if the collected box is an instance of Box and reduce bubble speed
if (box instanceof Box) {
var bubbles = game.children.filter(function (child) {
return child instanceof Bubble;
});
bubbles.forEach(function (bubble) {
bubble.speed /= 2;
});
LK.setTimeout(function () {
bubbles.forEach(function (bubble) {
bubble.speed *= 2;
});
}, 5000);
}
// Check if the collected box is an instance of Box3 and lives are less than 3
if (box instanceof Box3 && lives < 3) {
lives += 1;
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: -1 * lives * 50,
y: 50
});
LK.gui.topRight.addChild(heart);
hearts.push(heart);
}
// Check if the collected box is an instance of Box2
if (box instanceof Box2) {
var bubbles = game.children.filter(function (child) {
return child instanceof Bubble;
});
var bubblesDestroyed = bubbles.length;
bubbles.forEach(function (bubble) {
bubble.destroy();
});
score += bubblesDestroyed;
scoreTxt.setText("Lanterns destroyed: " + score.toString());
tween(scoreTxt.scale, {
x: 2,
y: 2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(scoreTxt.scale, {
x: 1,
y: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
// Create toast message based on box type
showToastForBox(box);
}
// Function to show toast message for box effects
function showToastForBox(box) {
var toastText = new Text2('', {
size: 250,
fill: 0xFFC0CB,
font: "'Comic Sans MS', cursive, sans-serif"
});
var toastTextBg = new Text2('', {
size: 255,
fill: 0xFF00AA,
font: "'Comic Sans MS', cursive, sans-serif"
});
toastText.anchor.set(0.5, 0.5);
toastText.x = 2048 / 2;
toastText.y = 2732 / 2;
toastTextBg.anchor.set(0.5, 0.5);
toastTextBg.x = 2048 / 2;
toastTextBg.y = 2732 / 2;
game.addChild(toastText);
game.addChild(toastTextBg);
if (box instanceof Box1) {
toastText.setText("Smash!");
toastTextBg.setText("Smash!");
} else if (box instanceof Box2) {
toastText.setText("Destruction!");
toastTextBg.setText("Destruction!");
} else if (box instanceof Box) {
toastText.setText("Less madness!");
toastTextBg.setText("Less madness!");
} else if (box instanceof Box3) {
toastText.setText("Life up!");
toastTextBg.setText("Life up!");
}
// Tween the toast text to fade out and destroy after 2 seconds
tween(toastText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
toastText.destroy();
}
});
tween(toastTextBg, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
toastTextBg.destroy();
}
});
}
// Function to handle player death sequence with rainbow colors
function handlePlayerDeath() {
// Rainbow colors array
var rainbowColors = [0xFF0000,
// Red
0xFF7F00,
// Orange
0xFFFF00,
// Yellow
0x00FF00,
// Green
0x0000FF,
// Blue
0x4B0082,
// Indigo
0x9400D3 // Violet
];
// Create dramatic death effect
var deathEffect = new PlayerDeathEffect();
game.addChild(deathEffect);
deathEffect.startEffect();
// Mark game as over to stop spawning bubbles
game.isGameOver = true;
// Create a function for sequential rainbow color animation
function playerRainbowSequence(colorIndex) {
if (colorIndex >= rainbowColors.length) {
// One full cycle completed, start fading out
tween(player, {
alpha: 0,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
return;
}
tween(player, {
alpha: 0.3,
tint: rainbowColors[colorIndex]
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
playerRainbowSequence(colorIndex + 1);
}
});
}
// Start the rainbow sequence
playerRainbowSequence(0);
}
var lastShot = -999;
game.down = function (x, y, obj) {
if (LK.ticks - lastShot > 10) {
player.shoot();
lastShot = LK.ticks;
}
};
// Start the music 'chinese' upon starting the game
LK.playMusic('chinese');
game.update = function () {
// Initialize game.isGameOver if it doesn't exist
if (game.isGameOver === undefined) {
game.isGameOver = false;
}
// Only spawn new bubbles if game isn't over
if (!game.isGameOver && LK.ticks % 50 == 0) {
var newBubble = new Bubble();
newBubble.x = Math.random() * 2048;
newBubble.y = 2732 * 0.75; // Start at 25% from bottom of screen
game.addChild(newBubble);
var randomTween = {
delta: Math.random() * (300 - 100) + 100,
// Random delta between 100 and 300
duration: Math.random() * (1500 - 800) + 800,
// Random duration between 800 and 1500
easing: [tween.easeIn, tween.easeOut, tween.elasticIn, tween.elasticOut, tween.bounceIn, tween.bounceOut, tween.easeInOut, tween.bounceInOut, tween.elasticInOut][Math.floor(Math.random() * 9)] // Random easing
};
tween(newBubble, {
x: Math.max(0, Math.min(2048, newBubble.x + randomTween.delta))
}, {
duration: randomTween.duration,
easing: randomTween.easing,
onFinish: function onFinish() {
tween(newBubble, {
x: Math.max(0, Math.min(2048, newBubble.x - randomTween.delta))
}, {
duration: randomTween.duration,
easing: randomTween.easing
});
}
});
}
var bubbles = game.children.filter(function (child) {
return child instanceof Bubble;
});
var harpoons = game.children.filter(function (child) {
return child instanceof Harpoon;
});
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
// Check for player intersection but don't damage the player
// We allow lanterns to pass through the player harmlessly
if (bubble.intersects(player)) {
// Don't destroy the bubble or harm the player
// This allows the bubble to continue moving up
// It will only damage the player if it exits off the top without being destroyed
}
for (var j = 0; j < harpoons.length; j++) {
var harpoon = harpoons[j];
// Basic collision detection for harpoon
if (bubble.intersects(harpoon) || Math.abs(bubble.x - harpoon.x) < 50 && Math.abs(bubble.y - harpoon.y) < 300) {
bubble.destroy();
LK.getSound('explosion').play();
harpoon.destroy();
bubbles.splice(i, 1); // Remove bubble from the array
score += 1;
scoreTxt.setText("Lanterns destroyed: " + score.toString());
tween(scoreTxt.scale, {
x: 2,
y: 2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(scoreTxt.scale, {
x: 1,
y: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
harpoons.splice(j, 1); // Remove harpoon from the array
// Create an explosion at the intersection point
var explosion = new Explosion();
explosion.x = bubble.x;
explosion.y = bubble.y;
game.addChild(explosion);
// Create a box at the intersection point with a 5% probability (half the previous 10%)
// Only spawn boxes when balloons are popped by player harpoons, not by explosion effects
if (!game.children.some(function (child) {
return child instanceof Box || child instanceof Box1 || child instanceof Box2 || child instanceof Box3;
})) {
// Only create boxes when bubble is popped by a player-created harpoon, not by power-up harpoons
// Check explicitly that the harpoon was created by the player, not by any box power-up
if (Math.random() < 0.5 && harpoon instanceof Harpoon && harpoon.isPlayerCreated === true) {
var boxType = Math.floor(Math.random() * 4);
var box;
switch (boxType) {
case 0:
box = new Box();
break;
case 1:
box = new Box1();
break;
case 2:
box = new Box2();
break;
case 3:
box = new Box3();
break;
}
box.x = bubble.x;
box.y = bubble.y;
game.addChild(box);
}
}
}
}
var boxes = game.children.filter(function (child) {
return child instanceof Box || child instanceof Box1 || child instanceof Box2 || child instanceof Box3;
});
for (var k = 0; k < boxes.length; k++) {
var box = boxes[k];
// Check if player collects/intersects the box
if (box.intersects(player)) {
// Create collection animation
tween(box.scale, {
x: 0,
y: 0
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function (boxToDestroy) {
boxToDestroy.destroy();
}.bind(null, box)
});
// Play pickup sound
LK.getSound('powerup').play();
// Apply the power-up effect based on box type using centralized handler
applyBoxEffect(box);
// Remove box from tracking array
boxes.splice(k, 1);
// Break out of the loop since we've handled the box
break;
}
// Check for harpoon intersecting with boxes
for (var l = 0; l < harpoons.length; l++) {
var harpoon = harpoons[l];
if (box.intersects(harpoon)) {
// Store reference to box before destroying it
var boxToApplyEffect = box;
// Destroy elements
box.destroy();
LK.getSound('powerup').play();
harpoon.destroy();
// Apply the power-up effect based on box type using centralized handler
applyBoxEffect(boxToApplyEffect);
// Remove from arrays
boxes.splice(k, 1);
harpoons.splice(l, 1);
break;
}
}
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -300,21 +300,45 @@
self.speed = -30; // Fast speed for instant vertical movement
self.maxDistance = 2732; // Maximum distance - entire screen height
self.startY = 0; // Will store the starting Y position
self.playerY = 0; // Will store the player's Y position
+ self.trail = null; // Will store the trail
self.update = function () {
// Store initial position on first update
if (self.startY === 0) {
self.startY = self.y;
self.playerY = player.y - 200; // Store player's position
+ // Create trail on first update
+ self.trail = new Trail();
+ self.trail.x = self.x;
+ self.trail.y = self.playerY;
+ game.addChild(self.trail);
+ // Ensure trail is below harpoon in rendering order
+ game.setChildIndex(self.trail, game.getChildIndex(self));
}
// Move harpoon up at constant speed
self.y += self.speed;
+ // Update trail to connect player position to harpoon
+ if (self.trail) {
+ self.trail.x = self.x;
+ self.trail.updateTrail(self.playerY, self.y);
+ }
// Destroy when reaching top of screen or maximum distance
if (self.y < 0 || self.startY - self.y > self.maxDistance) {
+ if (self.trail) {
+ self.trail.destroy();
+ }
self.destroy();
}
};
+ // Override destroy to also remove trail
+ var originalDestroy = self.destroy;
+ self.destroy = function () {
+ if (self.trail) {
+ self.trail.destroy();
+ }
+ originalDestroy.call(self);
+ };
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
@@ -470,21 +494,48 @@
self.segments = [];
self.segmentHeight = 100; // Fixed segment height of 100 pixels
self.createSegment = function (yOffset, height) {
var segment = new Container();
- var segmentGraphics = segment.attachAsset('line', {
+ var segmentGraphics = segment.attachAsset('trail', {
anchorX: 0.5,
anchorY: 0,
- width: 18,
- alpha: 0.9,
- scaleY: height / 600 // Adjust scaling factor to match line asset height
+ scaleY: height / 100 // Scale to match desired height
});
segment.y = yOffset;
segment.height = height; // Store segment height for later adjustments
self.addChild(segment);
self.segments.push(segment);
return segment;
};
+ // Update existing segments or create new ones
+ self.updateTrail = function (startY, endY) {
+ // Calculate total distance
+ var totalHeight = startY - endY;
+ if (totalHeight <= 0) {
+ return;
+ }
+ // Calculate number of segments needed
+ var numSegments = Math.ceil(totalHeight / self.segmentHeight);
+ // Create or update segments
+ for (var i = 0; i < numSegments; i++) {
+ var segmentHeight = i === numSegments - 1 && totalHeight % self.segmentHeight !== 0 ? totalHeight % self.segmentHeight : self.segmentHeight;
+ // Calculate y position for this segment (stacking from bottom to top)
+ var yPos = -totalHeight + i * self.segmentHeight;
+ // Create or update segment
+ if (i < self.segments.length) {
+ self.segments[i].y = yPos;
+ self.segments[i].height = segmentHeight;
+ self.segments[i].children[0].scaleY = segmentHeight / 100;
+ } else {
+ self.createSegment(yPos, segmentHeight);
+ }
+ }
+ // Remove excess segments
+ while (self.segments.length > numSegments) {
+ var segment = self.segments.pop();
+ segment.destroy();
+ }
+ };
// The trail doesn't need its own update movement since it's positioned relative to the harpoon
self.update = function () {
// Trail no longer moves independently
// Its position is now fully controlled by the Harpoon
a green cross, icon, pixel style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a sand clock pixel style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a bomb, pixel style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a pixel harpoon, vertical and looking up, retro like in pang games.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A banner to show a message, pixel art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
two harpoons looking up, retro, pixel. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A chinese flying paper lantern, retro pixel style. In-Game asset. 2d. High contrast. No shadows
fireworks, retro pixel style, colorful. In-Game asset. 2d. High contrast. No shadows
A chinese pixel background of an arcade game, sunset, retro style,. In-Game asset. 2d. High contrast. No shadows