User prompt
make the balls move slower
User prompt
Update the fruit init method to use level-based speed multiplier
User prompt
make some balls fly from left to right and straight down. let thembounce of the walls if they have not been sliced
User prompt
decrease how high the balls go by a quarter. spawn new balls from random points on the bottom of the screen and in random directions
User prompt
double the sizes of the fruits and make them go much higher and slower
User prompt
make the fruits bounce higher and slower
Code edit (1 edits merged)
Please save this source code
User prompt
Fruit Ninja Physics
Initial prompt
a fruit slashing game where player swipes to slash fruit. 5 types of fruit of different sizes, the smallest being 200px and increasing with 50 pixels hence. use real physics
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Blade = Container.expand(function () {
var self = Container.call(this);
self.active = false;
self.points = [];
self.maxPoints = 10;
self.trail = [];
for (var i = 0; i < self.maxPoints; i++) {
var trailPart = self.attachAsset('blade', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.trail.push(trailPart);
}
self.update = function () {
// Update trail visuals
for (var i = 0; i < self.trail.length; i++) {
if (i < self.points.length) {
var point = self.points[i];
var trailPart = self.trail[i];
trailPart.x = point.x;
trailPart.y = point.y;
trailPart.alpha = 1 - i / self.points.length;
if (i > 0) {
var prevPoint = self.points[i - 1];
var angle = Math.atan2(point.y - prevPoint.y, point.x - prevPoint.x);
trailPart.rotation = angle;
}
} else {
self.trail[i].alpha = 0;
}
}
};
self.addPoint = function (x, y) {
self.points.unshift({
x: x,
y: y
});
if (self.points.length > self.maxPoints) {
self.points.pop();
}
};
self.reset = function () {
self.points = [];
self.active = false;
for (var i = 0; i < self.trail.length; i++) {
self.trail[i].alpha = 0;
}
};
return self;
});
var Fruit = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'apple';
self.sliced = false;
self.width = 0;
self.height = 0;
self.points = 0;
self.baseSpeed = 0;
var fruitGraphics;
switch (self.type) {
case 'watermelon':
self.width = 240;
self.height = 240;
self.points = 5;
self.baseSpeed = 3.5; // Much slower base speed
break;
case 'apple':
self.width = 180;
self.height = 180;
self.points = 4;
self.baseSpeed = 4; // Much slower base speed
break;
case 'orange':
self.width = 160;
self.height = 160;
self.points = 3;
self.baseSpeed = 4.5; // Much slower base speed
break;
case 'kiwi':
self.width = 120;
self.height = 120;
self.points = 2;
self.baseSpeed = 5; // Much slower base speed
break;
case 'strawberry':
self.width = 100;
self.height = 100;
self.points = 1;
self.baseSpeed = 5.5; // Much slower base speed
break;
case 'bomb':
self.width = 160;
self.height = 160;
self.points = -10;
self.baseSpeed = 4; // Much slower base speed
break;
}
fruitGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.gravity = 0.0625; // Increased gravity by 25% for lower bounces
self.rotationSpeed = (Math.random() - 0.5) * 0.05; // Slower rotation
self.init = function (x, y, direction) {
self.x = x;
self.y = y;
var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16;
var speed = self.baseSpeed + Math.random() * 3;
self.vx = Math.cos(angle) * speed;
self.vy = -Math.sin(angle) * speed - 15; // Reduced initial upward velocity by 25% for lower bounces
};
self.slice = function () {
if (self.sliced || self.type === 'bomb') {
return;
}
self.sliced = true;
// Remove the whole fruit
fruitGraphics.alpha = 0;
// Create two halves
var half1 = self.attachAsset(self.type + '_half', {
anchorX: 0.5,
anchorY: 0,
y: -self.height / 4
});
var half2 = self.attachAsset(self.type + '_half', {
anchorX: 0.5,
anchorY: 0,
y: -self.height / 4,
rotation: Math.PI
});
// Apply different physics to the halves
half1.vx = self.vx + (Math.random() - 0.5) * 2;
half1.vy = self.vy;
half1.rotationSpeed = (Math.random() - 0.5) * 0.2;
half2.vx = self.vx - (Math.random() - 0.5) * 2;
half2.vy = self.vy;
half2.rotationSpeed = (Math.random() - 0.5) * 0.2;
self.half1 = half1;
self.half2 = half2;
return self.points;
};
self.update = function () {
if (!self.sliced) {
// Update whole fruit
self.vy += self.gravity;
self.x += self.vx;
self.y += self.vy;
self.rotation += self.rotationSpeed;
} else {
// Update halves
self.half1.vy += self.gravity;
self.half1.x += self.half1.vx;
self.half1.y += self.half1.vy;
self.half1.rotation += self.half1.rotationSpeed;
self.half2.vy += self.gravity;
self.half2.x += self.half2.vx;
self.half2.y += self.half2.vy;
self.half2.rotation += self.half2.rotationSpeed;
}
};
self.isOffScreen = function () {
return self.y > 2732 + self.height;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x3498DB
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SPAWN_INTERVAL_MIN = 2000; // Longer spawn intervals for slower fruits
var SPAWN_INTERVAL_MAX = 3500;
var SPAWN_COUNT_MIN = 1;
var SPAWN_COUNT_MAX = 2; // Fewer fruits at once to avoid overcrowding with larger fruits
var FRUIT_TYPES = ['watermelon', 'apple', 'orange', 'kiwi', 'strawberry'];
var BOMB_PROBABILITY = 0.1;
// Game variables
var fruits = [];
var blade = null;
var lastSpawnTime = 0;
var nextSpawnTime = 0;
var gameActive = true;
var comboCount = 0;
var comboTimer = 0;
var comboTimeout = 1000; // ms to reset combo
// UI elements
var scoreTxt;
var comboTxt;
function setupGame() {
// Create blade
blade = game.addChild(new Blade());
// Set up score display
scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 30;
LK.gui.top.addChild(scoreTxt);
// Set up combo display
comboTxt = new Text2('', {
size: 60,
fill: 0xFFFF00
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 140;
comboTxt.alpha = 0;
LK.gui.top.addChild(comboTxt);
// Set initial spawn time
nextSpawnTime = Date.now() + Math.random() * (SPAWN_INTERVAL_MAX - SPAWN_INTERVAL_MIN) + SPAWN_INTERVAL_MIN;
// Play background music
LK.playMusic('gameMusic');
}
function spawnFruits() {
var count = Math.floor(Math.random() * (SPAWN_COUNT_MAX - SPAWN_COUNT_MIN + 1)) + SPAWN_COUNT_MIN;
for (var i = 0; i < count; i++) {
var isBomb = Math.random() < BOMB_PROBABILITY;
var type = isBomb ? 'bomb' : FRUIT_TYPES[Math.floor(Math.random() * FRUIT_TYPES.length)];
var fruit = new Fruit(type);
var x = Math.random() * (GAME_WIDTH - 200) + 100;
var direction = Math.random(); // Random direction between 0 and 1
fruit.init(x, GAME_HEIGHT, direction);
game.addChild(fruit);
fruits.push(fruit);
}
// Schedule next spawn
nextSpawnTime = Date.now() + Math.random() * (SPAWN_INTERVAL_MAX - SPAWN_INTERVAL_MIN) + SPAWN_INTERVAL_MIN;
}
function updateCombo() {
if (comboCount > 1) {
comboTxt.setText('COMBO x' + comboCount + '!');
comboTxt.alpha = 1;
// Add combo bonus points
LK.setScore(LK.getScore() + comboCount * 2);
// Play combo sound
LK.getSound('combo').play();
// Animate combo text
tween(comboTxt, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut
});
}
comboCount = 0;
}
function handleBladeCollisions() {
if (!blade.active || blade.points.length < 2) {
return;
}
var startPoint = blade.points[0];
var endPoint = blade.points[1];
for (var i = 0; i < fruits.length; i++) {
var fruit = fruits[i];
if (!fruit.sliced && lineIntersectsCircle(startPoint.x, startPoint.y, endPoint.x, endPoint.y, fruit.x, fruit.y, fruit.width / 2)) {
if (fruit.type === 'bomb') {
// Game over when hitting a bomb
LK.getSound('explosion').play();
LK.effects.flashScreen(0xFF0000, 800);
LK.showGameOver();
return;
}
// Slice the fruit
var points = fruit.slice();
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore());
// Play slice sound
LK.getSound('slice').play();
// Update combo
comboCount++;
comboTimer = Date.now() + comboTimeout;
}
}
}
function lineIntersectsCircle(x1, y1, x2, y2, cx, cy, r) {
// Find the closest point on the line segment to the circle center
var dx = x2 - x1;
var dy = y2 - y1;
var len = Math.sqrt(dx * dx + dy * dy);
// Normalize direction vector
dx /= len;
dy /= len;
// Vector from line start to circle center
var vx = cx - x1;
var vy = cy - y1;
// Project this vector onto the line direction
var projection = vx * dx + vy * dy;
// Clamp projection to line segment
projection = Math.max(0, Math.min(len, projection));
// Find the closest point on the line segment
var closestX = x1 + projection * dx;
var closestY = y1 + projection * dy;
// Check if this point is within the circle
var distanceSquared = (cx - closestX) * (cx - closestX) + (cy - closestY) * (cy - closestY);
return distanceSquared <= r * r;
}
// Game update function
game.update = function () {
// Check if we need to spawn new fruits
var currentTime = Date.now();
if (currentTime >= nextSpawnTime) {
spawnFruits();
}
// Update all fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
fruit.update();
// Remove fruits that are off-screen
if (fruit.isOffScreen()) {
fruit.destroy();
fruits.splice(i, 1);
}
}
// Check for blade collisions
handleBladeCollisions();
// Update blade
blade.update();
// Check combo timer
if (comboCount > 0 && Date.now() > comboTimer) {
updateCombo();
}
};
// Handle touch/mouse events
game.down = function (x, y, obj) {
blade.active = true;
blade.reset();
blade.addPoint(x, y);
};
game.move = function (x, y, obj) {
if (blade.active) {
blade.addPoint(x, y);
handleBladeCollisions();
}
};
game.up = function (x, y, obj) {
blade.active = false;
};
// Start the game
setupGame(); ===================================================================
--- original.js
+++ change.js
@@ -109,17 +109,17 @@
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
- self.gravity = 0.05; // Greatly reduced gravity for much higher, slower bounces
+ self.gravity = 0.0625; // Increased gravity by 25% for lower bounces
self.rotationSpeed = (Math.random() - 0.5) * 0.05; // Slower rotation
self.init = function (x, y, direction) {
self.x = x;
self.y = y;
var angle = direction * (Math.PI / 4) + Math.random() * Math.PI / 8 - Math.PI / 16;
var speed = self.baseSpeed + Math.random() * 3;
self.vx = Math.cos(angle) * speed;
- self.vy = -Math.sin(angle) * speed - 20; // Much stronger initial upward velocity for higher bounces
+ self.vy = -Math.sin(angle) * speed - 15; // Reduced initial upward velocity by 25% for lower bounces
};
self.slice = function () {
if (self.sliced || self.type === 'bomb') {
return;
@@ -237,9 +237,9 @@
var isBomb = Math.random() < BOMB_PROBABILITY;
var type = isBomb ? 'bomb' : FRUIT_TYPES[Math.floor(Math.random() * FRUIT_TYPES.length)];
var fruit = new Fruit(type);
var x = Math.random() * (GAME_WIDTH - 200) + 100;
- var direction = x < GAME_WIDTH / 2 ? 0 : 1; // 0 is right, 1 is left
+ var direction = Math.random(); // Random direction between 0 and 1
fruit.init(x, GAME_HEIGHT, direction);
game.addChild(fruit);
fruits.push(fruit);
}
red bomb. In-Game asset. 2d. High contrast. No shadows
Head of pepe meme. each face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of doge meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of troll face meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of think smart guy meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Head of white y u no meme. face shaped as a marble shaped face made in blender 3D. In-Game asset. 2d. High contrast. No shadows
Explosion. In-Game asset. 2d. High contrast. No shadows
Clock. In-Game asset. 3d. High contrast. No shadows
Red Heart. In-Game asset. 3d. High contrast. No shadows
gattling gun. In-Game asset. 2d. High contrast. No shadows