User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var fruitGraphics = self.attachAsset(self.type.id, {' Line Number: 39
User prompt
the game goes to game over randomly after releasing balls, fix this bug
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var fruitGraphics = self.attachAsset(self.type.id, {' Line Number: 39
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var fruitGraphics = self.attachAsset(self.type.id, {' Line Number: 36
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'setText')' in or related to this line: 'scoreText.setText("SCORE: " + LK.getScore());' Line Number: 303
Code edit (1 edits merged)
Please save this source code
User prompt
Fruit Fusion: Bouncy Merge Mania
Initial prompt
Fruit merge - physics based game with bouncing balls
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Fruit = Container.expand(function (type) { var self = Container.call(this); self.type = type || FruitTypes.CHERRY; self.vx = 0; self.vy = 0; self.gravity = 0.5; self.friction = 0.98; self.elasticity = 0.7; self.merging = false; self.isStatic = false; var fruitGraphics = self.attachAsset(self.type.id, { anchorX: 0.5, anchorY: 0.5 }); // Show point value on fruit var pointsText = new Text2(self.type.points.toString(), { size: self.type.size * 0.4, fill: 0xFFFFFF }); pointsText.anchor.set(0.5, 0.5); self.addChild(pointsText); self.update = function () { if (self.isStatic || self.merging) { return; } // Apply gravity self.vy += self.gravity; // Apply velocity self.x += self.vx; self.y += self.vy; // Apply friction self.vx *= self.friction; self.vy *= self.friction; // Wall collision if (self.x < wallLeft.x + wallLeft.width / 2 + self.type.size / 2) { self.x = wallLeft.x + wallLeft.width / 2 + self.type.size / 2; self.vx = -self.vx * self.elasticity; if (Math.abs(self.vx) > 1) { LK.getSound('bounce').play(); } } if (self.x > wallRight.x - wallRight.width / 2 - self.type.size / 2) { self.x = wallRight.x - wallRight.width / 2 - self.type.size / 2; self.vx = -self.vx * self.elasticity; if (Math.abs(self.vx) > 1) { LK.getSound('bounce').play(); } } // Floor collision if (self.y > gameFloor.y - gameFloor.height / 2 - self.type.size / 2) { self.y = gameFloor.y - gameFloor.height / 2 - self.type.size / 2; self.vy = -self.vy * self.elasticity; // If we're barely moving, stop completely if (Math.abs(self.vy) < 2) { self.vy = 0; } if (Math.abs(self.vy) > 1) { LK.getSound('bounce').play(); } } }; self.merge = function (otherFruit) { if (self.merging || !self.type.next) { return; } self.merging = true; otherFruit.merging = true; // Calculate midpoint between fruits for new fruit position var midX = (self.x + otherFruit.x) / 2; var midY = (self.y + otherFruit.y) / 2; // Create merge animation tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 200, easing: tween.easeOut }); tween(otherFruit, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Create new merged fruit var newFruit = new Fruit(self.type.next); newFruit.x = midX; newFruit.y = midY; newFruit.scaleX = 0.5; newFruit.scaleY = 0.5; game.addChild(newFruit); fruits.push(newFruit); // Add merge points LK.setScore(LK.getScore() + self.type.next.points); updateScoreDisplay(); // Animate new fruit growing tween(newFruit, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.bounceOut }); // Remove old fruits var indexSelf = fruits.indexOf(self); if (indexSelf !== -1) { fruits.splice(indexSelf, 1); } self.destroy(); var indexOther = fruits.indexOf(otherFruit); if (indexOther !== -1) { fruits.splice(indexOther, 1); } otherFruit.destroy(); // Play merge sound LK.getSound('merge').play(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf6e58d }); /**** * Game Code ****/ // Game variables var FruitTypes = { CHERRY: { id: 'cherry', size: 70, points: 1, next: 'grape' }, GRAPE: { id: 'grape', size: 90, points: 3, next: 'apple' }, APPLE: { id: 'apple', size: 120, points: 6, next: 'orange' }, ORANGE: { id: 'orange', size: 150, points: 10, next: 'watermelon' }, WATERMELON: { id: 'watermelon', size: 200, points: 15, next: null } }; var gameWidth = 2048; var gameHeight = 2732; var fruits = []; var nextFruit = null; var nextFruitDisplay = null; var canDropFruit = true; var wallLeft, wallRight, gameFloor; var dropPoint = { x: gameWidth / 2, y: 200 }; var gameOver = false; var scoreText; // Setup game boundaries function setupBoundaries() { // Left wall wallLeft = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); wallLeft.x = 0; wallLeft.y = gameHeight / 2; // Right wall wallRight = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); wallRight.x = gameWidth; wallRight.y = gameHeight / 2; // Floor gameFloor = game.addChild(LK.getAsset('floor', { anchorX: 0.5, anchorY: 0.5 })); gameFloor.x = gameWidth / 2; gameFloor.y = gameHeight; } // Create new next fruit function createNextFruit() { // Determine which fruit to spawn (for now just start with smaller fruits) var fruitProbability = Math.random(); var fruitType; if (fruitProbability < 0.6) { fruitType = FruitTypes.CHERRY; } else if (fruitProbability < 0.85) { fruitType = FruitTypes.GRAPE; } else { fruitType = FruitTypes.APPLE; } nextFruit = fruitType; // Update display if (nextFruitDisplay) { nextFruitDisplay.destroy(); } // Background for next fruit var nextBg = LK.getAsset('nextFruitBg', { anchorX: 0.5, anchorY: 0.5 }); LK.gui.top.addChild(nextBg); nextBg.x = 150; nextBg.y = 150; // The next fruit preview var fruitPreview = LK.getAsset(fruitType.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); // Next label var nextLabel = new Text2("NEXT", { size: 40, fill: 0xFFFFFF }); nextLabel.anchor.set(0.5, 0.5); nextLabel.y = -100; nextFruitDisplay = new Container(); nextFruitDisplay.addChild(nextBg); nextFruitDisplay.addChild(fruitPreview); nextFruitDisplay.addChild(nextLabel); LK.gui.topLeft.addChild(nextFruitDisplay); nextFruitDisplay.x = 150; nextFruitDisplay.y = 150; } // Drop fruit at specified position function dropFruit(x) { if (!canDropFruit || gameOver) { return; } // Create new fruit var newFruit = new Fruit(nextFruit); newFruit.x = x; newFruit.y = dropPoint.y; // Add small random x velocity to make it interesting newFruit.vx = (Math.random() - 0.5) * 3; game.addChild(newFruit); fruits.push(newFruit); // Play drop sound LK.getSound('drop').play(); // Prepare next fruit createNextFruit(); // Prevent spam dropping canDropFruit = false; LK.setTimeout(function () { canDropFruit = true; }, 500); } // Update score display function updateScoreDisplay() { scoreText.setText("SCORE: " + LK.getScore()); } // Setup UI function setupUI() { // Score display scoreText = new Text2("SCORE: 0", { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); scoreText.y = 30; } // Check for fruit collisions function checkFruitCollisions() { for (var i = 0; i < fruits.length; i++) { for (var j = i + 1; j < fruits.length; j++) { var fruit1 = fruits[i]; var fruit2 = fruits[j]; // Skip if either fruit is already merging if (fruit1.merging || fruit2.merging) { continue; } // Check if fruits are the same type if (fruit1.type === fruit2.type) { // Calculate distance between centers var dx = fruit2.x - fruit1.x; var dy = fruit2.y - fruit1.y; var distance = Math.sqrt(dx * dx + dy * dy); // Check if they are overlapping var combinedRadius = (fruit1.type.size + fruit2.type.size) / 2; if (distance < combinedRadius * 0.8) { // Merge fruits fruit1.merge(fruit2); break; } } } } } // Check if game is over (too many fruits on screen or stacked too high) function checkGameOver() { if (gameOver) { return; } if (fruits.length > 30) { gameOver = true; LK.showGameOver(); return; } // Check if any fruits are too high for (var i = 0; i < fruits.length; i++) { if (fruits[i].y < 300 && !fruits[i].merging && fruits[i].vy < 1) { var isFruitMoving = Math.abs(fruits[i].vx) > 0.5 || Math.abs(fruits[i].vy) > 0.5; if (!isFruitMoving) { gameOver = true; LK.showGameOver(); return; } } } } // Initialize game function initGame() { LK.setScore(0); updateScoreDisplay(); gameOver = false; fruits = []; // Start background music LK.playMusic('bgmusic'); // Setup game elements setupBoundaries(); setupUI(); createNextFruit(); } // Event handlers game.down = function (x, y) { // Don't allow drops too close to the edges var minX = wallLeft.x + wallLeft.width / 2 + 100; var maxX = wallRight.x - wallRight.width / 2 - 100; if (x > minX && x < maxX) { dropFruit(x); } }; // Game update loop game.update = function () { // Check for fruit collisions checkFruitCollisions(); // Check game over conditions checkGameOver(); }; // Initialize the game initGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,379 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Fruit = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.type = type || FruitTypes.CHERRY;
+ self.vx = 0;
+ self.vy = 0;
+ self.gravity = 0.5;
+ self.friction = 0.98;
+ self.elasticity = 0.7;
+ self.merging = false;
+ self.isStatic = false;
+ var fruitGraphics = self.attachAsset(self.type.id, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Show point value on fruit
+ var pointsText = new Text2(self.type.points.toString(), {
+ size: self.type.size * 0.4,
+ fill: 0xFFFFFF
+ });
+ pointsText.anchor.set(0.5, 0.5);
+ self.addChild(pointsText);
+ self.update = function () {
+ if (self.isStatic || self.merging) {
+ return;
+ }
+ // Apply gravity
+ self.vy += self.gravity;
+ // Apply velocity
+ self.x += self.vx;
+ self.y += self.vy;
+ // Apply friction
+ self.vx *= self.friction;
+ self.vy *= self.friction;
+ // Wall collision
+ if (self.x < wallLeft.x + wallLeft.width / 2 + self.type.size / 2) {
+ self.x = wallLeft.x + wallLeft.width / 2 + self.type.size / 2;
+ self.vx = -self.vx * self.elasticity;
+ if (Math.abs(self.vx) > 1) {
+ LK.getSound('bounce').play();
+ }
+ }
+ if (self.x > wallRight.x - wallRight.width / 2 - self.type.size / 2) {
+ self.x = wallRight.x - wallRight.width / 2 - self.type.size / 2;
+ self.vx = -self.vx * self.elasticity;
+ if (Math.abs(self.vx) > 1) {
+ LK.getSound('bounce').play();
+ }
+ }
+ // Floor collision
+ if (self.y > gameFloor.y - gameFloor.height / 2 - self.type.size / 2) {
+ self.y = gameFloor.y - gameFloor.height / 2 - self.type.size / 2;
+ self.vy = -self.vy * self.elasticity;
+ // If we're barely moving, stop completely
+ if (Math.abs(self.vy) < 2) {
+ self.vy = 0;
+ }
+ if (Math.abs(self.vy) > 1) {
+ LK.getSound('bounce').play();
+ }
+ }
+ };
+ self.merge = function (otherFruit) {
+ if (self.merging || !self.type.next) {
+ return;
+ }
+ self.merging = true;
+ otherFruit.merging = true;
+ // Calculate midpoint between fruits for new fruit position
+ var midX = (self.x + otherFruit.x) / 2;
+ var midY = (self.y + otherFruit.y) / 2;
+ // Create merge animation
+ tween(self, {
+ alpha: 0,
+ scaleX: 0.5,
+ scaleY: 0.5
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ tween(otherFruit, {
+ alpha: 0,
+ scaleX: 0.5,
+ scaleY: 0.5
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Create new merged fruit
+ var newFruit = new Fruit(self.type.next);
+ newFruit.x = midX;
+ newFruit.y = midY;
+ newFruit.scaleX = 0.5;
+ newFruit.scaleY = 0.5;
+ game.addChild(newFruit);
+ fruits.push(newFruit);
+ // Add merge points
+ LK.setScore(LK.getScore() + self.type.next.points);
+ updateScoreDisplay();
+ // Animate new fruit growing
+ tween(newFruit, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 300,
+ easing: tween.bounceOut
+ });
+ // Remove old fruits
+ var indexSelf = fruits.indexOf(self);
+ if (indexSelf !== -1) {
+ fruits.splice(indexSelf, 1);
+ }
+ self.destroy();
+ var indexOther = fruits.indexOf(otherFruit);
+ if (indexOther !== -1) {
+ fruits.splice(indexOther, 1);
+ }
+ otherFruit.destroy();
+ // Play merge sound
+ LK.getSound('merge').play();
+ }
+ });
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0xf6e58d
+});
+
+/****
+* Game Code
+****/
+// Game variables
+var FruitTypes = {
+ CHERRY: {
+ id: 'cherry',
+ size: 70,
+ points: 1,
+ next: 'grape'
+ },
+ GRAPE: {
+ id: 'grape',
+ size: 90,
+ points: 3,
+ next: 'apple'
+ },
+ APPLE: {
+ id: 'apple',
+ size: 120,
+ points: 6,
+ next: 'orange'
+ },
+ ORANGE: {
+ id: 'orange',
+ size: 150,
+ points: 10,
+ next: 'watermelon'
+ },
+ WATERMELON: {
+ id: 'watermelon',
+ size: 200,
+ points: 15,
+ next: null
+ }
+};
+var gameWidth = 2048;
+var gameHeight = 2732;
+var fruits = [];
+var nextFruit = null;
+var nextFruitDisplay = null;
+var canDropFruit = true;
+var wallLeft, wallRight, gameFloor;
+var dropPoint = {
+ x: gameWidth / 2,
+ y: 200
+};
+var gameOver = false;
+var scoreText;
+// Setup game boundaries
+function setupBoundaries() {
+ // Left wall
+ wallLeft = game.addChild(LK.getAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ wallLeft.x = 0;
+ wallLeft.y = gameHeight / 2;
+ // Right wall
+ wallRight = game.addChild(LK.getAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ wallRight.x = gameWidth;
+ wallRight.y = gameHeight / 2;
+ // Floor
+ gameFloor = game.addChild(LK.getAsset('floor', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ gameFloor.x = gameWidth / 2;
+ gameFloor.y = gameHeight;
+}
+// Create new next fruit
+function createNextFruit() {
+ // Determine which fruit to spawn (for now just start with smaller fruits)
+ var fruitProbability = Math.random();
+ var fruitType;
+ if (fruitProbability < 0.6) {
+ fruitType = FruitTypes.CHERRY;
+ } else if (fruitProbability < 0.85) {
+ fruitType = FruitTypes.GRAPE;
+ } else {
+ fruitType = FruitTypes.APPLE;
+ }
+ nextFruit = fruitType;
+ // Update display
+ if (nextFruitDisplay) {
+ nextFruitDisplay.destroy();
+ }
+ // Background for next fruit
+ var nextBg = LK.getAsset('nextFruitBg', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ LK.gui.top.addChild(nextBg);
+ nextBg.x = 150;
+ nextBg.y = 150;
+ // The next fruit preview
+ var fruitPreview = LK.getAsset(fruitType.id, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.7,
+ scaleY: 0.7
+ });
+ // Next label
+ var nextLabel = new Text2("NEXT", {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ nextLabel.anchor.set(0.5, 0.5);
+ nextLabel.y = -100;
+ nextFruitDisplay = new Container();
+ nextFruitDisplay.addChild(nextBg);
+ nextFruitDisplay.addChild(fruitPreview);
+ nextFruitDisplay.addChild(nextLabel);
+ LK.gui.topLeft.addChild(nextFruitDisplay);
+ nextFruitDisplay.x = 150;
+ nextFruitDisplay.y = 150;
+}
+// Drop fruit at specified position
+function dropFruit(x) {
+ if (!canDropFruit || gameOver) {
+ return;
+ }
+ // Create new fruit
+ var newFruit = new Fruit(nextFruit);
+ newFruit.x = x;
+ newFruit.y = dropPoint.y;
+ // Add small random x velocity to make it interesting
+ newFruit.vx = (Math.random() - 0.5) * 3;
+ game.addChild(newFruit);
+ fruits.push(newFruit);
+ // Play drop sound
+ LK.getSound('drop').play();
+ // Prepare next fruit
+ createNextFruit();
+ // Prevent spam dropping
+ canDropFruit = false;
+ LK.setTimeout(function () {
+ canDropFruit = true;
+ }, 500);
+}
+// Update score display
+function updateScoreDisplay() {
+ scoreText.setText("SCORE: " + LK.getScore());
+}
+// Setup UI
+function setupUI() {
+ // Score display
+ scoreText = new Text2("SCORE: 0", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ scoreText.anchor.set(0.5, 0);
+ LK.gui.top.addChild(scoreText);
+ scoreText.y = 30;
+}
+// Check for fruit collisions
+function checkFruitCollisions() {
+ for (var i = 0; i < fruits.length; i++) {
+ for (var j = i + 1; j < fruits.length; j++) {
+ var fruit1 = fruits[i];
+ var fruit2 = fruits[j];
+ // Skip if either fruit is already merging
+ if (fruit1.merging || fruit2.merging) {
+ continue;
+ }
+ // Check if fruits are the same type
+ if (fruit1.type === fruit2.type) {
+ // Calculate distance between centers
+ var dx = fruit2.x - fruit1.x;
+ var dy = fruit2.y - fruit1.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // Check if they are overlapping
+ var combinedRadius = (fruit1.type.size + fruit2.type.size) / 2;
+ if (distance < combinedRadius * 0.8) {
+ // Merge fruits
+ fruit1.merge(fruit2);
+ break;
+ }
+ }
+ }
+ }
+}
+// Check if game is over (too many fruits on screen or stacked too high)
+function checkGameOver() {
+ if (gameOver) {
+ return;
+ }
+ if (fruits.length > 30) {
+ gameOver = true;
+ LK.showGameOver();
+ return;
+ }
+ // Check if any fruits are too high
+ for (var i = 0; i < fruits.length; i++) {
+ if (fruits[i].y < 300 && !fruits[i].merging && fruits[i].vy < 1) {
+ var isFruitMoving = Math.abs(fruits[i].vx) > 0.5 || Math.abs(fruits[i].vy) > 0.5;
+ if (!isFruitMoving) {
+ gameOver = true;
+ LK.showGameOver();
+ return;
+ }
+ }
+ }
+}
+// Initialize game
+function initGame() {
+ LK.setScore(0);
+ updateScoreDisplay();
+ gameOver = false;
+ fruits = [];
+ // Start background music
+ LK.playMusic('bgmusic');
+ // Setup game elements
+ setupBoundaries();
+ setupUI();
+ createNextFruit();
+}
+// Event handlers
+game.down = function (x, y) {
+ // Don't allow drops too close to the edges
+ var minX = wallLeft.x + wallLeft.width / 2 + 100;
+ var maxX = wallRight.x - wallRight.width / 2 - 100;
+ if (x > minX && x < maxX) {
+ dropFruit(x);
+ }
+};
+// Game update loop
+game.update = function () {
+ // Check for fruit collisions
+ checkFruitCollisions();
+ // Check game over conditions
+ checkGameOver();
+};
+// Initialize the game
+initGame();
\ No newline at end of file