User prompt
Karpuzdan sonra bir tanede kabak ekleyelim
Code edit (1 edits merged)
Please save this source code
User prompt
Gerçek meyve resimleri kullanabilir misin? Birde patlama efekti ekranin titremesi olmasi onceki meyva parcalara ayriliyor gibi patlasin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Oyun karpuzda bitmesin en yüksek puanı toplamaya çalısalım. En yüksek skor rekor kırilana kadar hafızada tutulsun. Birde meyveler birbirine degdigi anda birlessin hala birlesmedigi yada gec birleştiği oluyor birlesme efektini patlama efekti gibi yapabilir miuyiz iki meyve birlesince oatlayacak ve yeni meyve oluşacak ↪💡 Consider importing and using the following plugins: @upit/storage.v1, @upit/tween.v1
User prompt
Meyver random gelsin ilk baslarda benzer meyveler gelsin biestirmek kolay olsun diye ama zamanla meyveleri birlestirmek zorlaşsın
User prompt
Meyveler birlesirken bir birlesme efekti olsun ve bir birleşme sesi çıksın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fizik kurallari gecerli olsun her meyvenin bir agırlığı olsun meyveler üst üste bindığınde bu agırlıga göre saga yada sola gitsin bir meyvaya kenarından vurunca etki tepki kuralı geri fizik kurallarına gore uzaklassin meyva
User prompt
Meyve birlesme sıralarıni kücükten büyüğe göre sıralar misın? Birde skor ve sonraki meyve kısmi sağda olsun
Code edit (7 edits merged)
Please save this source code
User prompt
Taban düz çizgi seklinde olsun ve yeşil olsun
User prompt
Alttada bir taban olsun havada duruyor meyveler
User prompt
Sag ve sola duvar koyalım
User prompt
Biraz küçült meyveleri
User prompt
Son yaptigim alan degisiklikleriningeri alirmisin
Code edit (1 edits merged)
Please save this source code
User prompt
Meyve isimleri Türkçe olsun ve ortadaki score ve sonraki meyve kısmi sağ kösee gözüksün onlarda türkçe olsun
User prompt
Meyveler biraz daha buyuk olsun ve birbiri üstüne gecemesin fizik kuralları geçerli olsun yani
User prompt
İlk baslangicta meyveler duserken kırmızı cizgiye değebilir oyun bitmemeli asagida biriken meyveler kırmızı cizgiye değerse oyun bitecek
User prompt
Ekrana dokununca direk game over siyor meyveler düşmüyor meyveyi sağa sola çekerek uygun meyve üstüne düşürmeye çalışmamız gerek
Code edit (1 edits merged)
Please save this source code
User prompt
Fruit Fusion Drop
Initial prompt
Yukardan düşen meyveleri birleştirip daha büyük meyveler yapma ile ilgili bir oyun istiyorum yukarda bir cizgi olacak ve o cizgiye değecek sekilde meyve dolmuş olursa oyun bitecek. 2 meyve birleşince yeni bjr meyve oluşacak. Örnegin 2 üzüm birleşti bir erik oluştu iki erik birleşti bir elma oluştu gibi. En son en büyük meyve karpuz olsun karpuza ulaşan oyunu kazanmış olsun.
/****
* 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;
self.merged = false;
self.velocityY = 0;
self.velocityX = 0;
self.gravity = 0.5;
self.friction = 0.98;
self.bounce = 0.3;
self.hasSettled = false;
self.settleTimer = 0;
self.hasPassedDangerLine = false; // Track if fruit completed initial drop
// Weight system based on fruit size
var fruitWeights = {
'cherry': 1,
'grape': 2,
'strawberry': 3,
'greenplum': 4,
'apricot': 5,
'kiwi': 6,
'plum': 7,
'apple': 8,
'orange': 9,
'peach': 10,
'quince': 11,
'melon': 12,
'watermelon': 15
};
self.weight = fruitWeights[type] || 1;
var fruitGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.getRadius = function () {
return fruitGraphics.width / 2;
};
// Method to apply external force (like being hit by another fruit)
self.applyImpulse = function (impulseX, impulseY) {
// Heavier fruits are less affected by external forces
var forceMultiplier = 1 / Math.sqrt(self.weight / 2);
self.velocityX += impulseX * forceMultiplier;
self.velocityY += impulseY * forceMultiplier;
self.hasSettled = false;
self.settleTimer = 0;
};
self.update = function () {
if (self.merged) {
return;
}
// Apply weight-based physics
var weightedGravity = self.gravity * Math.sqrt(self.weight / 5); // Heavier fruits fall faster
self.velocityY += weightedGravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision with weight-based bouncing
var groundY = 2732 - 100;
if (self.y + self.getRadius() > groundY) {
self.y = groundY - self.getRadius();
// Heavier fruits bounce less
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityY *= -weightedBounce;
self.velocityX *= self.friction;
// Apply weight-based settling
var settleThreshold = 2 - self.weight * 0.1;
if (Math.abs(self.velocityY) < settleThreshold) {
self.velocityY = 0;
}
}
// Track if fruit has completed initial drop phase
if (!self.hasPassedDangerLine && self.y + self.getRadius() > dangerLineY + 20) {
self.hasPassedDangerLine = true;
}
// Check if fruit has settled (low velocity for some time)
if (Math.abs(self.velocityY) < 2 && Math.abs(self.velocityX) < 2) {
self.settleTimer++;
if (self.settleTimer > 10) {
// 10 frames = 0.17 seconds at 60fps - faster settling detection
self.hasSettled = true;
}
} else {
self.settleTimer = 0;
self.hasSettled = false; // Reset settled state when fruit starts moving again
}
// Wall collisions with weight-based bouncing
if (self.x - self.getRadius() < 20) {
self.x = 20 + self.getRadius();
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityX *= -weightedBounce;
}
if (self.x + self.getRadius() > 2048 - 20) {
self.x = 2048 - 20 - self.getRadius();
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityX *= -weightedBounce;
}
// Fruit collision detection with weight-based physics
for (var i = 0; i < fruits.length; i++) {
var otherFruit = fruits[i];
if (otherFruit === self || otherFruit.merged) {
continue;
}
var dx = self.x - otherFruit.x;
var dy = self.y - otherFruit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = self.getRadius() + otherFruit.getRadius();
if (distance < minDistance && distance > 0) {
// Calculate collision response with weight-based physics
var overlap = minDistance - distance;
var normalX = dx / distance;
var normalY = dy / distance;
// Weight-based separation (heavier fruits move less)
var totalWeight = self.weight + otherFruit.weight;
var selfSeparationRatio = otherFruit.weight / totalWeight;
var otherSeparationRatio = self.weight / totalWeight;
var separationX = normalX * overlap * selfSeparationRatio;
var separationY = normalY * overlap * selfSeparationRatio;
var otherSeparationX = -normalX * overlap * otherSeparationRatio;
var otherSeparationY = -normalY * overlap * otherSeparationRatio;
// Apply weight-based separation
self.x += separationX;
self.y += separationY;
otherFruit.x += otherSeparationX;
otherFruit.y += otherSeparationY;
// Calculate relative velocity
var relativeVelocityX = self.velocityX - otherFruit.velocityX;
var relativeVelocityY = self.velocityY - otherFruit.velocityY;
var velocityAlongNormal = relativeVelocityX * normalX + relativeVelocityY * normalY;
// Don't resolve if velocities are separating
if (velocityAlongNormal > 0) {
continue;
}
// Calculate restitution (bounciness)
var restitution = Math.min(self.bounce, otherFruit.bounce);
var impulseScalar = -(1 + restitution) * velocityAlongNormal;
impulseScalar /= 1 / self.weight + 1 / otherFruit.weight;
// Apply impulse with weight consideration
var impulseX = impulseScalar * normalX;
var impulseY = impulseScalar * normalY;
self.velocityX += impulseX / self.weight;
self.velocityY += impulseY / self.weight;
otherFruit.velocityX -= impulseX / otherFruit.weight;
otherFruit.velocityY -= impulseY / otherFruit.weight;
// Weight-based stacking effect - lighter fruits get pushed more
if (self.weight < otherFruit.weight) {
// Lighter fruit on top gets pushed sideways
var pushForce = (otherFruit.weight - self.weight) * 0.2;
self.velocityX += normalX * pushForce;
} else if (otherFruit.weight < self.weight) {
// Other lighter fruit gets pushed
var pushForce = (self.weight - otherFruit.weight) * 0.2;
otherFruit.velocityX -= normalX * pushForce;
}
}
}
// Check if fruits touch top red line (danger line) - immediate game over
if (self.y - self.getRadius() <= dangerLineY + 1) {
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
};
return self;
});
var FruitParticle = Container.expand(function (x, y, fruitType) {
var self = Container.call(this);
self.x = x;
self.y = y;
// Create smaller piece of the original fruit
var particleGraphics = self.attachAsset(fruitType, {
anchorX: 0.5,
anchorY: 0.5
});
// Make it smaller like a fragment
self.scaleX = 0.3 + Math.random() * 0.2;
self.scaleY = 0.3 + Math.random() * 0.2;
// Random velocity for explosion effect
self.velocityX = (Math.random() - 0.5) * 20;
self.velocityY = (Math.random() - 0.5) * 20 - 10; // Bias upward
self.velocityY -= Math.random() * 10; // Extra upward force
// Physics properties
self.gravity = 0.8;
self.friction = 0.95;
self.bounce = 0.3;
self.life = 120; // Particle life in frames
// Rotation for spinning effect
self.rotationSpeed = (Math.random() - 0.5) * 0.3;
self.update = function () {
// Apply physics
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += self.rotationSpeed;
// Apply friction
self.velocityX *= self.friction;
// Ground collision
var groundY = 2732 - 100;
if (self.y + 20 > groundY) {
self.y = groundY - 20;
self.velocityY *= -self.bounce;
self.velocityX *= self.friction;
}
// Wall collisions
if (self.x < 20) {
self.x = 20;
self.velocityX *= -self.bounce;
}
if (self.x > 2048 - 20) {
self.x = 2048 - 20;
self.velocityX *= -self.bounce;
}
// Fade out over time
self.life--;
if (self.life < 60) {
self.alpha = self.life / 60;
}
// Remove when life is over
if (self.life <= 0) {
self.destroy();
// Remove from particles array
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i] === self) {
particles.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var fruitTypes = ['cherry', 'grape', 'strawberry', 'greenplum', 'apricot', 'kiwi', 'plum', 'apple', 'orange', 'peach', 'quince', 'melon', 'watermelon'];
var fruitScores = [5, 25, 10, 35, 40, 50, 75, 120, 180, 500, 300, 1000, 2000];
var watermelonMergeCount = 0;
var fruits = [];
var particles = [];
var dropX = 1024;
var currentFruitType = 'cherry';
var dangerLineY = 250;
var canDrop = true;
var gameStartTime = Date.now();
var totalDrops = 0;
var highScore = 0;
var dangerLineTouches = 0; // Counter for danger line touches
// Create walls
var leftWall = game.addChild(LK.getAsset('walls', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 20,
height: 2732
}));
var rightWall = game.addChild(LK.getAsset('walls', {
anchorX: 0,
anchorY: 0,
x: 2048 - 20,
y: 0,
width: 20,
height: 2732
}));
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100,
width: 2048,
height: 20
}));
// Create danger line
var dangerLine = game.addChild(LK.getAsset('dangerLine', {
anchorX: 0,
anchorY: 0,
x: 0,
y: dangerLineY
}));
// Create score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFD700,
fontWeight: 'bold'
});
scoreTxt.anchor.set(1, 0);
scoreTxt.x = -60; // Move score text 150 pixels left from right edge
scoreTxt.y = 30; // Move score text to top right corner
LK.gui.topRight.addChild(scoreTxt);
// Create next fruit indicator
var nextFruitTxt = new Text2('Next: Pineapple', {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
nextFruitTxt.anchor.set(0, 0);
nextFruitTxt.x = 50;
nextFruitTxt.y = 90;
LK.gui.topLeft.addChild(nextFruitTxt);
// Create high score text
var highScoreTxt = new Text2('Best Score: ' + highScore, {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
highScoreTxt.anchor.set(0, 0);
highScoreTxt.x = 50;
highScoreTxt.y = 30;
LK.gui.topLeft.addChild(highScoreTxt);
// Create preview fruit
var previewFruit = game.addChild(LK.getAsset(currentFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropX,
y: dangerLineY + 314,
alpha: 0.7
}));
function getRandomFruitType() {
var gameTimeSeconds = (Date.now() - gameStartTime) / 1000;
var currentScore = LK.getScore();
// Progressive difficulty based on time and score
var maxFruitIndex = 0; // Start with only cherry
var availableFruits = 1;
// Time-based progression (every 30 seconds, unlock next fruit type)
var timeBasedUnlocks = Math.floor(gameTimeSeconds / 30);
availableFruits = Math.min(availableFruits + timeBasedUnlocks, fruitTypes.length);
// Score-based progression (unlock fruits based on score milestones)
var scoreBasedUnlocks = 0;
if (currentScore >= 30) {
scoreBasedUnlocks = 1;
} // grape
if (currentScore >= 60) {
scoreBasedUnlocks = 2;
} // strawberry
if (currentScore >= 100) {
scoreBasedUnlocks = 3;
} // green plum
if (currentScore >= 150) {
scoreBasedUnlocks = 4;
} // apricot
if (currentScore >= 210) {
scoreBasedUnlocks = 5;
} // kiwi
if (currentScore >= 280) {
scoreBasedUnlocks = 6;
} // plum
if (currentScore >= 360) {
scoreBasedUnlocks = 7;
} // apple
if (currentScore >= 460) {
scoreBasedUnlocks = 8;
} // orange
if (currentScore >= 580) {
scoreBasedUnlocks = 9;
} // peach
if (currentScore >= 720) {
scoreBasedUnlocks = 10;
} // quince
if (currentScore >= 890) {
scoreBasedUnlocks = 11;
} // melon
if (currentScore >= 1100) {
scoreBasedUnlocks = 12;
} // watermelon
availableFruits = Math.max(availableFruits, scoreBasedUnlocks + 1);
maxFruitIndex = Math.min(availableFruits - 1, fruitTypes.length - 1);
// Early game weighting - favor smaller fruits
var weights = [];
for (var i = 0; i <= maxFruitIndex; i++) {
// Weight smaller fruits more heavily early in the game
var baseWeight = maxFruitIndex - i + 1;
// Additional weighting for very early game
if (totalDrops < 20) {
if (i === 0) {
baseWeight *= 4;
} // Heavy favor for cherry
else if (i === 1) {
baseWeight *= 2;
} // Medium favor for strawberry
} else if (totalDrops < 50) {
if (i <= 1) {
baseWeight *= 2;
} // Favor first two fruits
}
weights.push(baseWeight);
}
// Weighted random selection
var totalWeight = 0;
for (var i = 0; i < weights.length; i++) {
totalWeight += weights[i];
}
var randomValue = Math.random() * totalWeight;
var currentWeight = 0;
for (var i = 0; i < weights.length; i++) {
currentWeight += weights[i];
if (randomValue <= currentWeight) {
return fruitTypes[i];
}
}
// Fallback
return fruitTypes[0];
}
function updatePreviewFruit() {
game.removeChild(previewFruit);
previewFruit = game.addChild(LK.getAsset(currentFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropX,
y: dangerLineY + 314,
alpha: 0.7
}));
var capitalizedType = currentFruitType.charAt(0).toUpperCase() + currentFruitType.slice(1);
nextFruitTxt.setText('Next: ' + capitalizedType);
}
function dropFruit() {
if (!canDrop) {
return;
}
var newFruit = new Fruit(currentFruitType);
newFruit.x = dropX;
newFruit.y = dangerLineY + 364; // Start fruits even further below the danger line
fruits.push(newFruit);
game.addChild(newFruit);
LK.getSound('drop').play();
totalDrops++;
currentFruitType = getRandomFruitType();
updatePreviewFruit();
canDrop = false;
LK.setTimeout(function () {
canDrop = true;
}, 500);
}
function checkMerges() {
for (var i = 0; i < fruits.length; i++) {
if (fruits[i].merged) {
continue;
}
for (var j = i + 1; j < fruits.length; j++) {
if (fruits[j].merged) {
continue;
}
var fruit1 = fruits[i];
var fruit2 = fruits[j];
if (fruit1.type === fruit2.type) {
var dx = fruit1.x - fruit2.x;
var dy = fruit1.y - fruit2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = fruit1.getRadius() + fruit2.getRadius();
// Merge immediately when fruits touch (with small buffer for instant merging)
if (distance <= minDistance + 5) {
mergeFruits(fruit1, fruit2);
break;
}
}
}
}
}
function mergeFruits(fruit1, fruit2) {
var currentTypeIndex = fruitTypes.indexOf(fruit1.type);
// Handle watermelon merging - they can merge up to 10 times then get destroyed
if (fruit1.type === 'watermelon') {
watermelonMergeCount++;
if (watermelonMergeCount >= 10) {
// Create explosive particle effect for destruction
var particleCount = 15 + Math.floor(Math.random() * 10); // 15-25 particles
for (var p = 0; p < particleCount; p++) {
var particle = new FruitParticle((fruit1.x + fruit2.x) / 2 + (Math.random() - 0.5) * 100, (fruit1.y + fruit2.y) / 2 + (Math.random() - 0.5) * 100, fruit1.type);
particles.push(particle);
game.addChild(particle);
}
// Add score for destruction
LK.setScore(LK.getScore() + 2000);
scoreTxt.setText(LK.getScore());
// Play merge sound
LK.getSound('merge').play();
// Mark fruits as merged and remove them
fruit1.merged = true;
fruit2.merged = true;
// Remove from fruits array
for (var i = fruits.length - 1; i >= 0; i--) {
if (fruits[i].merged) {
fruits[i].destroy();
fruits.splice(i, 1);
}
}
return;
}
}
if (currentTypeIndex < fruitTypes.length - 1) {
var nextType = fruitTypes[currentTypeIndex + 1];
// Create new merged fruit
var mergedFruit = new Fruit(nextType);
mergedFruit.x = (fruit1.x + fruit2.x) / 2;
mergedFruit.y = (fruit1.y + fruit2.y) / 2;
// Create explosive particle effect - fragments of the original fruits
var particleCount = 8 + Math.floor(Math.random() * 6); // 8-14 particles
for (var p = 0; p < particleCount; p++) {
var particle = new FruitParticle((fruit1.x + fruit2.x) / 2 + (Math.random() - 0.5) * 60, (fruit1.y + fruit2.y) / 2 + (Math.random() - 0.5) * 60, fruit1.type);
particles.push(particle);
game.addChild(particle);
}
// Create explosive merge effect
mergedFruit.scaleX = 0.1;
mergedFruit.scaleY = 0.1;
// First explosion - quick scale up
tween(mergedFruit, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Second bounce - scale down to normal
tween(mergedFruit, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
}
});
// Add stronger screen shake effect for explosion
var originalX = game.x;
var originalY = game.y;
var shakeAmount = 20; // Increased shake
var shakeDuration = 30; // Shorter, more intense shake
// Multiple shake cycles for more impact
for (var shakeCount = 0; shakeCount < 6; shakeCount++) {
(function (count) {
LK.setTimeout(function () {
var currentShake = shakeAmount * (1 - count / 6); // Diminishing shake
tween(game, {
x: originalX + (Math.random() - 0.5) * currentShake * 2,
y: originalY + (Math.random() - 0.5) * currentShake * 2
}, {
duration: shakeDuration,
easing: tween.easeOut
});
}, count * shakeDuration);
})(shakeCount);
}
// Return to original position
LK.setTimeout(function () {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
easing: tween.easeOut
});
}, 200);
// Add rotation effect for extra visual impact
tween(mergedFruit, {
rotation: Math.PI * 2
}, {
duration: 350,
easing: tween.easeOut
});
// Add tint effect that fades from bright to normal
mergedFruit.tint = 0xFFFF00;
tween(mergedFruit, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
fruits.push(mergedFruit);
game.addChild(mergedFruit);
// Add score
var scoreToAdd = fruitScores[currentTypeIndex + 1];
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
// Check and update high score
var currentScore = LK.getScore();
if (currentScore > highScore) {
highScore = currentScore;
highScoreTxt.setText('Best Score: ' + highScore);
// Flash high score text when broken
LK.effects.flashObject(highScoreTxt, 0xFFD700, 1000);
}
// Continue playing even after watermelon - no win condition
// Play merge sound
LK.getSound('merge').play();
// Flash effect
LK.effects.flashObject(mergedFruit, 0xFFFF00, 500);
// Push away nearby fruits from explosion
var mergeX = mergedFruit.x;
var mergeY = mergedFruit.y;
var explosionRadius = 200;
for (var k = 0; k < fruits.length; k++) {
if (fruits[k] !== mergedFruit && !fruits[k].merged) {
var dx = fruits[k].x - mergeX;
var dy = fruits[k].y - mergeY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius && distance > 0) {
var force = (explosionRadius - distance) / explosionRadius * 15;
var normalX = dx / distance;
var normalY = dy / distance;
fruits[k].applyImpulse(normalX * force, normalY * force);
}
}
}
}
// Mark fruits as merged and remove them
fruit1.merged = true;
fruit2.merged = true;
// Remove from fruits array
for (var i = fruits.length - 1; i >= 0; i--) {
if (fruits[i].merged) {
fruits[i].destroy();
fruits.splice(i, 1);
}
}
}
var isDragging = false;
game.move = function (x, y, obj) {
if (canDrop && isDragging) {
dropX = Math.max(40, Math.min(2048 - 40, x));
previewFruit.x = dropX;
}
};
game.down = function (x, y, obj) {
if (canDrop) {
isDragging = true;
dropX = Math.max(40, Math.min(2048 - 40, x));
previewFruit.x = dropX;
}
};
game.up = function (x, y, obj) {
if (canDrop && isDragging) {
isDragging = false;
dropFruit();
}
};
game.update = function () {
for (var i = 0; i < fruits.length; i++) {
fruits[i].update();
}
// Update particles
for (var i = 0; i < particles.length; i++) {
particles[i].update();
}
checkMerges();
};
// Initialize first fruit type
updatePreviewFruit(); /****
* 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;
self.merged = false;
self.velocityY = 0;
self.velocityX = 0;
self.gravity = 0.5;
self.friction = 0.98;
self.bounce = 0.3;
self.hasSettled = false;
self.settleTimer = 0;
self.hasPassedDangerLine = false; // Track if fruit completed initial drop
// Weight system based on fruit size
var fruitWeights = {
'cherry': 1,
'grape': 2,
'strawberry': 3,
'greenplum': 4,
'apricot': 5,
'kiwi': 6,
'plum': 7,
'apple': 8,
'orange': 9,
'peach': 10,
'quince': 11,
'melon': 12,
'watermelon': 15
};
self.weight = fruitWeights[type] || 1;
var fruitGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.getRadius = function () {
return fruitGraphics.width / 2;
};
// Method to apply external force (like being hit by another fruit)
self.applyImpulse = function (impulseX, impulseY) {
// Heavier fruits are less affected by external forces
var forceMultiplier = 1 / Math.sqrt(self.weight / 2);
self.velocityX += impulseX * forceMultiplier;
self.velocityY += impulseY * forceMultiplier;
self.hasSettled = false;
self.settleTimer = 0;
};
self.update = function () {
if (self.merged) {
return;
}
// Apply weight-based physics
var weightedGravity = self.gravity * Math.sqrt(self.weight / 5); // Heavier fruits fall faster
self.velocityY += weightedGravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Ground collision with weight-based bouncing
var groundY = 2732 - 100;
if (self.y + self.getRadius() > groundY) {
self.y = groundY - self.getRadius();
// Heavier fruits bounce less
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityY *= -weightedBounce;
self.velocityX *= self.friction;
// Apply weight-based settling
var settleThreshold = 2 - self.weight * 0.1;
if (Math.abs(self.velocityY) < settleThreshold) {
self.velocityY = 0;
}
}
// Track if fruit has completed initial drop phase
if (!self.hasPassedDangerLine && self.y + self.getRadius() > dangerLineY + 20) {
self.hasPassedDangerLine = true;
}
// Check if fruit has settled (low velocity for some time)
if (Math.abs(self.velocityY) < 2 && Math.abs(self.velocityX) < 2) {
self.settleTimer++;
if (self.settleTimer > 10) {
// 10 frames = 0.17 seconds at 60fps - faster settling detection
self.hasSettled = true;
}
} else {
self.settleTimer = 0;
self.hasSettled = false; // Reset settled state when fruit starts moving again
}
// Wall collisions with weight-based bouncing
if (self.x - self.getRadius() < 20) {
self.x = 20 + self.getRadius();
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityX *= -weightedBounce;
}
if (self.x + self.getRadius() > 2048 - 20) {
self.x = 2048 - 20 - self.getRadius();
var weightedBounce = self.bounce * (1 / Math.sqrt(self.weight / 3));
self.velocityX *= -weightedBounce;
}
// Fruit collision detection with weight-based physics
for (var i = 0; i < fruits.length; i++) {
var otherFruit = fruits[i];
if (otherFruit === self || otherFruit.merged) {
continue;
}
var dx = self.x - otherFruit.x;
var dy = self.y - otherFruit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = self.getRadius() + otherFruit.getRadius();
if (distance < minDistance && distance > 0) {
// Calculate collision response with weight-based physics
var overlap = minDistance - distance;
var normalX = dx / distance;
var normalY = dy / distance;
// Weight-based separation (heavier fruits move less)
var totalWeight = self.weight + otherFruit.weight;
var selfSeparationRatio = otherFruit.weight / totalWeight;
var otherSeparationRatio = self.weight / totalWeight;
var separationX = normalX * overlap * selfSeparationRatio;
var separationY = normalY * overlap * selfSeparationRatio;
var otherSeparationX = -normalX * overlap * otherSeparationRatio;
var otherSeparationY = -normalY * overlap * otherSeparationRatio;
// Apply weight-based separation
self.x += separationX;
self.y += separationY;
otherFruit.x += otherSeparationX;
otherFruit.y += otherSeparationY;
// Calculate relative velocity
var relativeVelocityX = self.velocityX - otherFruit.velocityX;
var relativeVelocityY = self.velocityY - otherFruit.velocityY;
var velocityAlongNormal = relativeVelocityX * normalX + relativeVelocityY * normalY;
// Don't resolve if velocities are separating
if (velocityAlongNormal > 0) {
continue;
}
// Calculate restitution (bounciness)
var restitution = Math.min(self.bounce, otherFruit.bounce);
var impulseScalar = -(1 + restitution) * velocityAlongNormal;
impulseScalar /= 1 / self.weight + 1 / otherFruit.weight;
// Apply impulse with weight consideration
var impulseX = impulseScalar * normalX;
var impulseY = impulseScalar * normalY;
self.velocityX += impulseX / self.weight;
self.velocityY += impulseY / self.weight;
otherFruit.velocityX -= impulseX / otherFruit.weight;
otherFruit.velocityY -= impulseY / otherFruit.weight;
// Weight-based stacking effect - lighter fruits get pushed more
if (self.weight < otherFruit.weight) {
// Lighter fruit on top gets pushed sideways
var pushForce = (otherFruit.weight - self.weight) * 0.2;
self.velocityX += normalX * pushForce;
} else if (otherFruit.weight < self.weight) {
// Other lighter fruit gets pushed
var pushForce = (self.weight - otherFruit.weight) * 0.2;
otherFruit.velocityX -= normalX * pushForce;
}
}
}
// Check if fruits touch top red line (danger line) - immediate game over
if (self.y - self.getRadius() <= dangerLineY + 1) {
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
};
return self;
});
var FruitParticle = Container.expand(function (x, y, fruitType) {
var self = Container.call(this);
self.x = x;
self.y = y;
// Create smaller piece of the original fruit
var particleGraphics = self.attachAsset(fruitType, {
anchorX: 0.5,
anchorY: 0.5
});
// Make it smaller like a fragment
self.scaleX = 0.3 + Math.random() * 0.2;
self.scaleY = 0.3 + Math.random() * 0.2;
// Random velocity for explosion effect
self.velocityX = (Math.random() - 0.5) * 20;
self.velocityY = (Math.random() - 0.5) * 20 - 10; // Bias upward
self.velocityY -= Math.random() * 10; // Extra upward force
// Physics properties
self.gravity = 0.8;
self.friction = 0.95;
self.bounce = 0.3;
self.life = 120; // Particle life in frames
// Rotation for spinning effect
self.rotationSpeed = (Math.random() - 0.5) * 0.3;
self.update = function () {
// Apply physics
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += self.rotationSpeed;
// Apply friction
self.velocityX *= self.friction;
// Ground collision
var groundY = 2732 - 100;
if (self.y + 20 > groundY) {
self.y = groundY - 20;
self.velocityY *= -self.bounce;
self.velocityX *= self.friction;
}
// Wall collisions
if (self.x < 20) {
self.x = 20;
self.velocityX *= -self.bounce;
}
if (self.x > 2048 - 20) {
self.x = 2048 - 20;
self.velocityX *= -self.bounce;
}
// Fade out over time
self.life--;
if (self.life < 60) {
self.alpha = self.life / 60;
}
// Remove when life is over
if (self.life <= 0) {
self.destroy();
// Remove from particles array
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i] === self) {
particles.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var fruitTypes = ['cherry', 'grape', 'strawberry', 'greenplum', 'apricot', 'kiwi', 'plum', 'apple', 'orange', 'peach', 'quince', 'melon', 'watermelon'];
var fruitScores = [5, 25, 10, 35, 40, 50, 75, 120, 180, 500, 300, 1000, 2000];
var watermelonMergeCount = 0;
var fruits = [];
var particles = [];
var dropX = 1024;
var currentFruitType = 'cherry';
var dangerLineY = 250;
var canDrop = true;
var gameStartTime = Date.now();
var totalDrops = 0;
var highScore = 0;
var dangerLineTouches = 0; // Counter for danger line touches
// Create walls
var leftWall = game.addChild(LK.getAsset('walls', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 20,
height: 2732
}));
var rightWall = game.addChild(LK.getAsset('walls', {
anchorX: 0,
anchorY: 0,
x: 2048 - 20,
y: 0,
width: 20,
height: 2732
}));
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100,
width: 2048,
height: 20
}));
// Create danger line
var dangerLine = game.addChild(LK.getAsset('dangerLine', {
anchorX: 0,
anchorY: 0,
x: 0,
y: dangerLineY
}));
// Create score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFD700,
fontWeight: 'bold'
});
scoreTxt.anchor.set(1, 0);
scoreTxt.x = -60; // Move score text 150 pixels left from right edge
scoreTxt.y = 30; // Move score text to top right corner
LK.gui.topRight.addChild(scoreTxt);
// Create next fruit indicator
var nextFruitTxt = new Text2('Next: Pineapple', {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
nextFruitTxt.anchor.set(0, 0);
nextFruitTxt.x = 50;
nextFruitTxt.y = 90;
LK.gui.topLeft.addChild(nextFruitTxt);
// Create high score text
var highScoreTxt = new Text2('Best Score: ' + highScore, {
size: 50,
fill: 0x000000,
fontWeight: 'bold'
});
highScoreTxt.anchor.set(0, 0);
highScoreTxt.x = 50;
highScoreTxt.y = 30;
LK.gui.topLeft.addChild(highScoreTxt);
// Create preview fruit
var previewFruit = game.addChild(LK.getAsset(currentFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropX,
y: dangerLineY + 314,
alpha: 0.7
}));
function getRandomFruitType() {
var gameTimeSeconds = (Date.now() - gameStartTime) / 1000;
var currentScore = LK.getScore();
// Progressive difficulty based on time and score
var maxFruitIndex = 0; // Start with only cherry
var availableFruits = 1;
// Time-based progression (every 30 seconds, unlock next fruit type)
var timeBasedUnlocks = Math.floor(gameTimeSeconds / 30);
availableFruits = Math.min(availableFruits + timeBasedUnlocks, fruitTypes.length);
// Score-based progression (unlock fruits based on score milestones)
var scoreBasedUnlocks = 0;
if (currentScore >= 30) {
scoreBasedUnlocks = 1;
} // grape
if (currentScore >= 60) {
scoreBasedUnlocks = 2;
} // strawberry
if (currentScore >= 100) {
scoreBasedUnlocks = 3;
} // green plum
if (currentScore >= 150) {
scoreBasedUnlocks = 4;
} // apricot
if (currentScore >= 210) {
scoreBasedUnlocks = 5;
} // kiwi
if (currentScore >= 280) {
scoreBasedUnlocks = 6;
} // plum
if (currentScore >= 360) {
scoreBasedUnlocks = 7;
} // apple
if (currentScore >= 460) {
scoreBasedUnlocks = 8;
} // orange
if (currentScore >= 580) {
scoreBasedUnlocks = 9;
} // peach
if (currentScore >= 720) {
scoreBasedUnlocks = 10;
} // quince
if (currentScore >= 890) {
scoreBasedUnlocks = 11;
} // melon
if (currentScore >= 1100) {
scoreBasedUnlocks = 12;
} // watermelon
availableFruits = Math.max(availableFruits, scoreBasedUnlocks + 1);
maxFruitIndex = Math.min(availableFruits - 1, fruitTypes.length - 1);
// Early game weighting - favor smaller fruits
var weights = [];
for (var i = 0; i <= maxFruitIndex; i++) {
// Weight smaller fruits more heavily early in the game
var baseWeight = maxFruitIndex - i + 1;
// Additional weighting for very early game
if (totalDrops < 20) {
if (i === 0) {
baseWeight *= 4;
} // Heavy favor for cherry
else if (i === 1) {
baseWeight *= 2;
} // Medium favor for strawberry
} else if (totalDrops < 50) {
if (i <= 1) {
baseWeight *= 2;
} // Favor first two fruits
}
weights.push(baseWeight);
}
// Weighted random selection
var totalWeight = 0;
for (var i = 0; i < weights.length; i++) {
totalWeight += weights[i];
}
var randomValue = Math.random() * totalWeight;
var currentWeight = 0;
for (var i = 0; i < weights.length; i++) {
currentWeight += weights[i];
if (randomValue <= currentWeight) {
return fruitTypes[i];
}
}
// Fallback
return fruitTypes[0];
}
function updatePreviewFruit() {
game.removeChild(previewFruit);
previewFruit = game.addChild(LK.getAsset(currentFruitType, {
anchorX: 0.5,
anchorY: 0.5,
x: dropX,
y: dangerLineY + 314,
alpha: 0.7
}));
var capitalizedType = currentFruitType.charAt(0).toUpperCase() + currentFruitType.slice(1);
nextFruitTxt.setText('Next: ' + capitalizedType);
}
function dropFruit() {
if (!canDrop) {
return;
}
var newFruit = new Fruit(currentFruitType);
newFruit.x = dropX;
newFruit.y = dangerLineY + 364; // Start fruits even further below the danger line
fruits.push(newFruit);
game.addChild(newFruit);
LK.getSound('drop').play();
totalDrops++;
currentFruitType = getRandomFruitType();
updatePreviewFruit();
canDrop = false;
LK.setTimeout(function () {
canDrop = true;
}, 500);
}
function checkMerges() {
for (var i = 0; i < fruits.length; i++) {
if (fruits[i].merged) {
continue;
}
for (var j = i + 1; j < fruits.length; j++) {
if (fruits[j].merged) {
continue;
}
var fruit1 = fruits[i];
var fruit2 = fruits[j];
if (fruit1.type === fruit2.type) {
var dx = fruit1.x - fruit2.x;
var dy = fruit1.y - fruit2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = fruit1.getRadius() + fruit2.getRadius();
// Merge immediately when fruits touch (with small buffer for instant merging)
if (distance <= minDistance + 5) {
mergeFruits(fruit1, fruit2);
break;
}
}
}
}
}
function mergeFruits(fruit1, fruit2) {
var currentTypeIndex = fruitTypes.indexOf(fruit1.type);
// Handle watermelon merging - they can merge up to 10 times then get destroyed
if (fruit1.type === 'watermelon') {
watermelonMergeCount++;
if (watermelonMergeCount >= 10) {
// Create explosive particle effect for destruction
var particleCount = 15 + Math.floor(Math.random() * 10); // 15-25 particles
for (var p = 0; p < particleCount; p++) {
var particle = new FruitParticle((fruit1.x + fruit2.x) / 2 + (Math.random() - 0.5) * 100, (fruit1.y + fruit2.y) / 2 + (Math.random() - 0.5) * 100, fruit1.type);
particles.push(particle);
game.addChild(particle);
}
// Add score for destruction
LK.setScore(LK.getScore() + 2000);
scoreTxt.setText(LK.getScore());
// Play merge sound
LK.getSound('merge').play();
// Mark fruits as merged and remove them
fruit1.merged = true;
fruit2.merged = true;
// Remove from fruits array
for (var i = fruits.length - 1; i >= 0; i--) {
if (fruits[i].merged) {
fruits[i].destroy();
fruits.splice(i, 1);
}
}
return;
}
}
if (currentTypeIndex < fruitTypes.length - 1) {
var nextType = fruitTypes[currentTypeIndex + 1];
// Create new merged fruit
var mergedFruit = new Fruit(nextType);
mergedFruit.x = (fruit1.x + fruit2.x) / 2;
mergedFruit.y = (fruit1.y + fruit2.y) / 2;
// Create explosive particle effect - fragments of the original fruits
var particleCount = 8 + Math.floor(Math.random() * 6); // 8-14 particles
for (var p = 0; p < particleCount; p++) {
var particle = new FruitParticle((fruit1.x + fruit2.x) / 2 + (Math.random() - 0.5) * 60, (fruit1.y + fruit2.y) / 2 + (Math.random() - 0.5) * 60, fruit1.type);
particles.push(particle);
game.addChild(particle);
}
// Create explosive merge effect
mergedFruit.scaleX = 0.1;
mergedFruit.scaleY = 0.1;
// First explosion - quick scale up
tween(mergedFruit, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Second bounce - scale down to normal
tween(mergedFruit, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
}
});
// Add stronger screen shake effect for explosion
var originalX = game.x;
var originalY = game.y;
var shakeAmount = 20; // Increased shake
var shakeDuration = 30; // Shorter, more intense shake
// Multiple shake cycles for more impact
for (var shakeCount = 0; shakeCount < 6; shakeCount++) {
(function (count) {
LK.setTimeout(function () {
var currentShake = shakeAmount * (1 - count / 6); // Diminishing shake
tween(game, {
x: originalX + (Math.random() - 0.5) * currentShake * 2,
y: originalY + (Math.random() - 0.5) * currentShake * 2
}, {
duration: shakeDuration,
easing: tween.easeOut
});
}, count * shakeDuration);
})(shakeCount);
}
// Return to original position
LK.setTimeout(function () {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
easing: tween.easeOut
});
}, 200);
// Add rotation effect for extra visual impact
tween(mergedFruit, {
rotation: Math.PI * 2
}, {
duration: 350,
easing: tween.easeOut
});
// Add tint effect that fades from bright to normal
mergedFruit.tint = 0xFFFF00;
tween(mergedFruit, {
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.easeOut
});
fruits.push(mergedFruit);
game.addChild(mergedFruit);
// Add score
var scoreToAdd = fruitScores[currentTypeIndex + 1];
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
// Check and update high score
var currentScore = LK.getScore();
if (currentScore > highScore) {
highScore = currentScore;
highScoreTxt.setText('Best Score: ' + highScore);
// Flash high score text when broken
LK.effects.flashObject(highScoreTxt, 0xFFD700, 1000);
}
// Continue playing even after watermelon - no win condition
// Play merge sound
LK.getSound('merge').play();
// Flash effect
LK.effects.flashObject(mergedFruit, 0xFFFF00, 500);
// Push away nearby fruits from explosion
var mergeX = mergedFruit.x;
var mergeY = mergedFruit.y;
var explosionRadius = 200;
for (var k = 0; k < fruits.length; k++) {
if (fruits[k] !== mergedFruit && !fruits[k].merged) {
var dx = fruits[k].x - mergeX;
var dy = fruits[k].y - mergeY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius && distance > 0) {
var force = (explosionRadius - distance) / explosionRadius * 15;
var normalX = dx / distance;
var normalY = dy / distance;
fruits[k].applyImpulse(normalX * force, normalY * force);
}
}
}
}
// Mark fruits as merged and remove them
fruit1.merged = true;
fruit2.merged = true;
// Remove from fruits array
for (var i = fruits.length - 1; i >= 0; i--) {
if (fruits[i].merged) {
fruits[i].destroy();
fruits.splice(i, 1);
}
}
}
var isDragging = false;
game.move = function (x, y, obj) {
if (canDrop && isDragging) {
dropX = Math.max(40, Math.min(2048 - 40, x));
previewFruit.x = dropX;
}
};
game.down = function (x, y, obj) {
if (canDrop) {
isDragging = true;
dropX = Math.max(40, Math.min(2048 - 40, x));
previewFruit.x = dropX;
}
};
game.up = function (x, y, obj) {
if (canDrop && isDragging) {
isDragging = false;
dropFruit();
}
};
game.update = function () {
for (var i = 0; i < fruits.length; i++) {
fruits[i].update();
}
// Update particles
for (var i = 0; i < particles.length; i++) {
particles[i].update();
}
checkMerges();
};
// Initialize first fruit type
updatePreviewFruit();