/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AdvancedObjectsMenu = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 250;
buttonBg.height = 60;
// Button label
var label = new Text2("Advanced Objects", {
size: 28,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Dropdown container (hidden initially)
var dropdown = new Container();
dropdown.y = 70;
dropdown.visible = false;
self.addChild(dropdown);
// Dropdown background
var dropdownBg = LK.getAsset('block', {
anchorX: 0.5,
anchorY: 0
});
dropdownBg.tint = 0x333333;
dropdownBg.width = 250;
dropdownBg.height = 80;
dropdown.addChild(dropdownBg);
// Car option
var carOption = new Container();
carOption.y = 15;
dropdown.addChild(carOption);
var carLabel = new Text2("Car", {
size: 24,
fill: 0xFFFFFF
});
carLabel.anchor.set(0.5, 0.5);
carOption.addChild(carLabel);
// Draggable state
self.isOpen = false;
self.isDraggingCar = false;
self.currentCar = null;
// Toggle dropdown
self.down = function (x, y, obj) {
// Only toggle if clicking the main button (not the dropdown)
if (!self.isOpen || y < self.y + buttonBg.height / 2) {
self.isOpen = !self.isOpen;
dropdown.visible = self.isOpen;
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
}
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
// Car option interaction
carOption.interactive = true;
carOption.down = function (x, y, obj) {
self.isDraggingCar = true;
// Create a car object that follows the pointer
self.currentCar = new Car();
// Get global position
var globalPos = game.toLocal(self.parent.toGlobal({
x: x,
y: y
}));
self.currentCar.x = globalPos.x;
self.currentCar.y = globalPos.y;
// Add to game
game.addChild(self.currentCar);
// Visual feedback
tween(carLabel, {
alpha: 0.7
}, {
duration: 100
});
};
carOption.move = function (x, y, obj) {
if (self.isDraggingCar && self.currentCar) {
// Get global position
var globalPos = game.toLocal(self.parent.toGlobal({
x: x,
y: y
}));
self.currentCar.x = globalPos.x;
self.currentCar.y = globalPos.y;
}
};
carOption.up = function (x, y, obj) {
if (self.isDraggingCar && self.currentCar) {
// Add physics to the car
physicsObjects.push(self.currentCar);
// Set initial velocity
self.currentCar.velocityX = 0;
self.currentCar.velocityY = 0;
// Reset state
self.isDraggingCar = false;
self.currentCar = null;
// Play sound
LK.getSound('place').play();
}
// Visual feedback
tween(carLabel, {
alpha: 1
}, {
duration: 100
});
};
return self;
});
var BlueScreenButton = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('buttonBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 300;
buttonBg.height = 80;
// Button label
var label = new Text2("BLUE SCREEN OF DEATH", {
size: 24,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Button interaction
self.down = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
// Show blue screen of death
showBlueScreenOfDeath();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
// Car-specific properties
self.type = 'car';
self.width = 200;
self.height = 100;
self.mass = 2;
self.friction = 0.2;
self.restitution = 0.3;
self.velocityX = 0;
self.velocityY = 0;
self.rotation = 0;
self.angularVelocity = 0;
self.isStatic = false;
// Car body
self.visual = self.attachAsset('rectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 100
});
self.visual.tint = 0xff4400; // Orange/red car
// Add a roof/cabin
var roof = LK.getAsset('rectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 100,
height: 50
});
roof.tint = 0xff7700;
roof.y = -25;
self.addChild(roof);
// Add wheels
var frontWheel = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 50,
height: 50
});
frontWheel.tint = 0x333333;
frontWheel.x = 70;
frontWheel.y = 40;
self.addChild(frontWheel);
var rearWheel = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 50,
height: 50
});
rearWheel.tint = 0x333333;
rearWheel.x = -70;
rearWheel.y = 40;
self.addChild(rearWheel);
// Add headlights
var headlight1 = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20
});
headlight1.tint = 0xffffcc;
headlight1.x = 95;
headlight1.y = -15;
self.addChild(headlight1);
var headlight2 = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20
});
headlight2.tint = 0xffffcc;
headlight2.x = 95;
headlight2.y = 15;
self.addChild(headlight2);
// Update method to handle wheels rotation
self.update = function () {
// Rotate wheels based on horizontal velocity
frontWheel.rotation += self.velocityX * 0.03;
rearWheel.rotation += self.velocityX * 0.03;
};
return self;
});
var DraggableButton = Container.expand(function () {
var self = Container.call(this);
// Create visual representation
var buttonVisual = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a label
var label = new Text2("Create", {
size: 24,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Track if we're currently creating an object
self.isCreating = false;
self.currentObject = null;
self.objectType = 'circle'; // Default object type
// Update the visual based on the selected object type
self.updateVisual = function (type) {
if (type) {
self.objectType = type;
}
// Remove existing visual
self.removeChild(buttonVisual);
// Create new visual based on current object type
buttonVisual = self.attachAsset(self.objectType, {
anchorX: 0.5,
anchorY: 0.5
});
// Adjust for triangle shape
if (self.objectType === 'triangle') {
buttonVisual.scaleY = 0.5;
buttonVisual.y = buttonVisual.height / 4;
}
// Make sure label stays on top
self.removeChild(label);
self.addChild(label);
};
// Handle touch/click down
self.down = function (x, y, obj) {
self.isCreating = true;
// Create a new physics object that follows the pointer
self.currentObject = new PhysicsObject(self.objectType, {
mass: 1,
restitution: 0.7,
friction: 0.1
});
// Position at pointer
self.currentObject.x = x;
self.currentObject.y = y;
// Add to game
game.addChild(self.currentObject);
// Visual feedback
tween(buttonVisual, {
alpha: 0.7,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
// Handle movement
self.move = function (x, y, obj) {
if (self.isCreating && self.currentObject) {
self.currentObject.x = x;
self.currentObject.y = y;
}
};
// Handle release
self.up = function (x, y, obj) {
if (self.isCreating && self.currentObject) {
// Add physics to the object
physicsObjects.push(self.currentObject);
// Set initial velocity based on recent movement
if (chaosMode) {
// More chaotic initial velocity in chaos mode
self.currentObject.velocityX = Math.random() * 30 - 15;
self.currentObject.velocityY = Math.random() * -20 - 5;
self.currentObject.angularVelocity = Math.random() * 0.3 - 0.15;
// Sometimes create multiple balls when in chaos mode
if (Math.random() < 0.3) {
for (var i = 0; i < 3; i++) {
createPhysicsObject(x + Math.random() * 100 - 50, y + Math.random() * 100 - 50, self.objectType, {
mass: 0.5 + Math.random(),
restitution: 0.8,
friction: 0.05
});
}
}
} else {
// Normal initial velocity
self.currentObject.velocityX = Math.random() * 10 - 5;
self.currentObject.velocityY = -10; // Initial upward velocity
}
// Reset state
self.isCreating = false;
self.currentObject = null;
// Play sound
LK.getSound('place').play();
}
// Visual feedback
tween(buttonVisual, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
var GlitchButton = Container.expand(function () {
var self = Container.call(this);
// Button properties
self.width = 150;
self.height = 150;
self.isGlitching = false;
self.particles = [];
self.maxParticles = 20;
self.glitchActivated = false;
// Visual appearance
var buttonVisual = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: self.width,
height: self.height
});
buttonVisual.tint = 0x00FFFF; // Cyan
// Text label
var label = new Text2("GLITCH", {
size: 32,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Create particles
for (var i = 0; i < self.maxParticles; i++) {
createParticle();
}
// Create a single particle
function createParticle() {
var particle = new GlitchParticle({
color: Math.random() < 0.5 ? 0x00FFFF : 0xFF00FF,
size: 5 + Math.random() * 15,
distance: 80 + Math.random() * 60,
speed: 0.5 + Math.random() * 1.5,
glitchRate: 0.1 + Math.random() * 0.2
});
// Position relative to button
particle.setOrigin(0, 0);
self.addChild(particle);
self.particles.push(particle);
}
// Button interaction
self.down = function (x, y, obj) {
// Increment glitch counter
glitchCounter++;
// Trigger glitch effect
self.glitchActivated = true;
// Visual feedback
tween(buttonVisual, {
alpha: 0.8,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
// Trigger chaos mode
chaosMode = true;
// Flash screen
LK.effects.flashScreen(0x00FFFF, 500);
// Visual glitch effect for all UI elements
glitchUI();
// Check if we reached 50 glitches
if (glitchCounter >= 50 && !cleaningMode) {
// Activate cleaning mode
cleaningMode = true;
// Hide all UI elements
hideAllUI();
// Start virus cleaning process
startVirusCleaning();
}
// Play sound
LK.getSound('place').play();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonVisual, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
// Update particles
self.update = function () {
// Update each particle
for (var i = 0; i < self.particles.length; i++) {
self.particles[i].update();
}
// Button glitch effect
if (Math.random() < 0.1) {
self.isGlitching = !self.isGlitching;
if (self.isGlitching) {
buttonVisual.tint = Math.random() < 0.5 ? 0xFF00FF : 0x00FFFF;
label.position.x = Math.random() * 10 - 5;
label.position.y = Math.random() * 10 - 5;
// Sometimes change text
if (Math.random() < 0.2) {
label.setText(Math.random() < 0.5 ? "ERR0R" : "GL1TCH");
}
} else {
buttonVisual.tint = 0x00FFFF;
label.position.x = 0;
label.position.y = 0;
label.setText("GLITCH");
}
}
};
return self;
});
// Glitch UI elements function
var GlitchParticle = Container.expand(function (options) {
var self = Container.call(this);
// Default options
options = options || {};
self.size = options.size || Math.random() * 10 + 5;
self.speed = options.speed || Math.random() * 2 + 1;
self.distance = options.distance || 50 + Math.random() * 100;
self.angle = options.angle || Math.random() * Math.PI * 2;
self.rotation = Math.random() * Math.PI * 2;
self.rotationSpeed = Math.random() * 0.2 - 0.1;
self.alpha = 0.7 + Math.random() * 0.3;
self.glitchRate = options.glitchRate || 0.2;
// Visual appearance
var visual = self.attachAsset('square', {
anchorX: 0.5,
anchorY: 0.5
});
visual.width = self.size;
visual.height = self.size;
visual.tint = options.color || 0x00FFFF;
// Animation properties
self.time = 0;
self.originalX = 0;
self.originalY = 0;
self.offsetX = 0;
self.offsetY = 0;
// Update particle position
self.update = function () {
self.time += 0.05;
// Orbital movement
self.offsetX = Math.cos(self.angle + self.time * self.speed) * self.distance;
self.offsetY = Math.sin(self.angle + self.time * self.speed) * self.distance;
self.x = self.originalX + self.offsetX;
self.y = self.originalY + self.offsetY;
// Rotate
visual.rotation += self.rotationSpeed;
// Random glitch effect
if (Math.random() < self.glitchRate) {
visual.x = Math.random() * 10 - 5;
visual.y = Math.random() * 10 - 5;
visual.alpha = 0.5 + Math.random() * 0.5;
visual.tint = Math.random() < 0.5 ? 0x00FFFF : 0xFF00FF;
} else {
visual.x = 0;
visual.y = 0;
visual.alpha = self.alpha;
}
};
// Set origin point
self.setOrigin = function (x, y) {
self.originalX = x;
self.originalY = y;
};
return self;
});
var ObjectSelector = Container.expand(function () {
var self = Container.call(this);
// Create main container
var buttonContainer = new Container();
self.addChild(buttonContainer);
// Header text
var headerText = new Text2("Objects", {
size: 36,
fill: 0xFFFFFF
});
headerText.anchor.set(0.5, 0);
headerText.y = -60;
self.addChild(headerText);
// Create object buttons
var objectTypes = [{
type: 'circle',
label: 'Circle',
color: 0xe74c3c
}, {
type: 'square',
label: 'Square',
color: 0x3498db
}, {
type: 'rectangle',
label: 'Rectangle',
color: 0x2ecc71
}, {
type: 'triangle',
label: 'Triangle',
color: 0x70ae6e
}];
var buttonWidth = 150;
var buttonHeight = 80;
var buttonSpacing = 20;
var buttonsPerRow = 2;
for (var i = 0; i < objectTypes.length; i++) {
var col = i % buttonsPerRow;
var row = Math.floor(i / buttonsPerRow);
var button = new UIButton(objectTypes[i].label, buttonWidth, buttonHeight, objectTypes[i].color);
button.x = col * (buttonWidth + buttonSpacing) - (buttonsPerRow - 1) * (buttonWidth + buttonSpacing) / 2;
button.y = row * (buttonHeight + buttonSpacing);
button.objectType = objectTypes[i].type;
button.onPress = function () {
if (self.onSelectObject) {
self.onSelectObject(this.objectType);
}
};
buttonContainer.addChild(button);
}
return self;
});
var PhysicsObject = Container.expand(function (type, properties) {
var self = Container.call(this);
self.type = type || 'block';
// Default properties
self.mass = (properties === null || properties === void 0 ? void 0 : properties.mass) || 1;
self.friction = (properties === null || properties === void 0 ? void 0 : properties.friction) || 0.1;
self.restitution = (properties === null || properties === void 0 ? void 0 : properties.restitution) || 0.5;
self.isStatic = (properties === null || properties === void 0 ? void 0 : properties.isStatic) || false;
// Physics variables
self.velocityX = 0;
self.velocityY = 0;
self.rotation = 0;
self.angularVelocity = 0;
// Create visual representation
var visual = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
if (type === 'triangle') {
// Make the triangle shape by scaling
visual.scaleY = 0.5;
visual.y = visual.height / 4;
}
self.visual = visual;
// Visual feedback for static objects
if (self.isStatic) {
visual.alpha = 0.7;
}
// Modify the color based on mass
var color = visual.tint;
if (self.mass > 1) {
// Darken for heavier objects
visual.tint = darkenColor(color, 0.2 * (self.mass - 1));
} else if (self.mass < 1) {
// Lighten for lighter objects
visual.tint = lightenColor(color, 0.2 * (1 - self.mass));
}
// Handle interaction
self.down = function (x, y, obj) {
// Only allow dragging if we're in edit mode
if (currentMode === 'edit') {
isDragging = true;
draggedObject = self;
// Store offset for dragging
dragOffsetX = self.x - x;
dragOffsetY = self.y - y;
}
};
return self;
});
var UIButton = Container.expand(function (label, width, height, color) {
var self = Container.call(this);
// Create button background
var background = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
background.tint = color || 0x4d90ff;
background.width = width || 150;
background.height = height || 80;
// Create button label
var labelText = new Text2(label, {
size: 30,
fill: 0xFFFFFF
});
labelText.anchor.set(0.5, 0.5);
self.addChild(labelText);
// Handle button press
self.down = function (x, y, obj) {
tween(background, {
alpha: 0.7
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(background, {
alpha: 1
}, {
duration: 100
});
if (self.onPress) {
self.onPress();
}
};
return self;
});
// Glitch UI elements function
var VirusScanButton = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('buttonBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 300;
buttonBg.height = 80;
// Button label
var label = new Text2("VIRUS SCAN AGAIN", {
size: 30,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Button interaction
self.down = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
// Show blue screen of death
showBlueScreenOfDeath();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Function to hide all UI elements
function hideAllUI() {
// Set background to black
game.setBackgroundColor(0x000000);
// Remove all physics objects
for (var i = physicsObjects.length - 1; i >= 0; i--) {
game.removeChild(physicsObjects[i]);
physicsObjects.splice(i, 1);
}
// Hide all GUI elements
var uiElements = [title, instructions, ballCountText, easterEggHint, circleCreator, clearButton, objectSelectorButton, advancedObjects, glitchButton];
for (var i = 0; i < uiElements.length; i++) {
if (uiElements[i] && uiElements[i].parent) {
uiElements[i].parent.removeChild(uiElements[i]);
}
}
// Clear any existing object selector
if (objectSelector && objectSelector.parent) {
objectSelector.parent.removeChild(objectSelector);
objectSelector = null;
}
}
// Function to start virus cleaning process
function startVirusCleaning() {
// Create cleaning text
var cleaningText = new Text2("CLEANING ALL VIRUSES", {
size: 60,
fill: 0x00FF00
});
cleaningText.anchor.set(0.5, 0.5);
cleaningText.x = 2048 / 2;
cleaningText.y = 2732 / 2 - 100;
LK.gui.addChild(cleaningText);
// Create progress text
var progressText = new Text2("0%", {
size: 50,
fill: 0x00FF00
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 2048 / 2;
progressText.y = 2732 / 2;
LK.gui.addChild(progressText);
// Update progress
var progressInterval = LK.setInterval(function () {
cleanProgress += 1;
progressText.setText(cleanProgress + "%");
// Check if cleaning is complete
if (cleanProgress >= 100) {
LK.clearInterval(progressInterval);
// Remove cleaning texts
LK.gui.removeChild(cleaningText);
LK.gui.removeChild(progressText);
// Show error message
showErrorMessage();
}
}, 100);
}
// Function to show error message
function showErrorMessage() {
// Create error text
var errorText = new Text2("ERROR: PLEASE RESTART THE GAME", {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 2732 / 2;
LK.gui.addChild(errorText);
// Create blinking effect
var blinkInterval = LK.setInterval(function () {
errorText.visible = !errorText.visible;
}, 500);
// Automatically restart the game after a few seconds
LK.setTimeout(function () {
LK.clearInterval(blinkInterval);
LK.showGameOver();
}, 5000);
}
// Function to show blue screen of death
function showBlueScreenOfDeath() {
// Hide all game elements
hideAllUI();
// Clear all UI
LK.gui.removeChildren();
// Set background to blue
game.setBackgroundColor(0x0078D7); // Modern Windows BSOD blue
// Create BSOD content - Windows 10 style
var sadFaceText = new Text2(":(", {
size: 180,
fill: 0xFFFFFF
});
sadFaceText.anchor.set(0, 0);
sadFaceText.x = 400;
sadFaceText.y = 300;
LK.gui.addChild(sadFaceText);
var bsodText = new Text2("Your PC ran into a problem and needs to restart.", {
size: 50,
fill: 0xFFFFFF
});
bsodText.anchor.set(0, 0);
bsodText.x = 400;
bsodText.y = 550;
LK.gui.addChild(bsodText);
var collectingText = new Text2("We're just collecting some error info, and then we'll restart for you.", {
size: 36,
fill: 0xFFFFFF
});
collectingText.anchor.set(0, 0);
collectingText.x = 400;
collectingText.y = 650;
LK.gui.addChild(collectingText);
// Progress counter that goes from 0% to 100%
var progress = 0;
var percentText = new Text2("0% complete", {
size: 36,
fill: 0xFFFFFF
});
percentText.anchor.set(0, 0);
percentText.x = 400;
percentText.y = 800;
LK.gui.addChild(percentText);
// QR code representation (simplified as a white square)
var qrCode = LK.getAsset('square', {
anchorX: 0,
anchorY: 0,
width: 200,
height: 200
});
qrCode.tint = 0xFFFFFF;
qrCode.x = 400;
qrCode.y = 900;
LK.gui.addChild(qrCode);
// Add QR code text indicating it leads to Roblox.com
var qrCodeText = new Text2("Scan to go to: roblox.com", {
size: 30,
fill: 0xFFFFFF
});
qrCodeText.anchor.set(0, 0);
qrCodeText.x = 620;
qrCodeText.y = 950;
LK.gui.addChild(qrCodeText);
var errorCodeText = new Text2("CRITICAL_PROCESS_DIED", {
size: 40,
fill: 0xFFFFFF
});
errorCodeText.anchor.set(0, 0);
errorCodeText.x = 400;
errorCodeText.y = 1150;
LK.gui.addChild(errorCodeText);
var stopCodeText = new Text2("Stop Code: 01X10XX011X0ERROR", {
size: 36,
fill: 0xFFFFFF
});
stopCodeText.anchor.set(0, 0);
stopCodeText.x = 400;
stopCodeText.y = 1200;
LK.gui.addChild(stopCodeText);
// Update progress and auto-restart when done
var progressInterval = LK.setInterval(function () {
progress += 1;
percentText.setText(progress + "% complete");
// When reaches 100%, restart game
if (progress >= 100) {
LK.clearInterval(progressInterval);
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}, 100);
}
// Glitch UI elements function
var GRAVITY = 0.5;
var DRAG = 0.02;
var GROUND_Y = 2500;
// Game state
var physicsObjects = [];
var isSimulating = true;
var currentMode = 'edit'; // Define currentMode variable
var isDragging = false;
var draggedObject = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var selectedObjectType = 'circle';
var objectSelector = null;
var glitchCounter = 0;
var cleaningMode = false;
var cleanProgress = 0;
// Create the ground
var ground = new PhysicsObject('ground', {
isStatic: true
});
ground.x = 2048 / 2;
ground.y = GROUND_Y;
game.addChild(ground);
physicsObjects.push(ground);
// Create a draggable button that creates physics objects
var circleCreator = new DraggableButton();
circleCreator.x = 200;
circleCreator.y = 200;
LK.gui.addChild(circleCreator);
// Add the advanced objects dropdown
var advancedObjects = new AdvancedObjectsMenu();
advancedObjects.x = 450;
advancedObjects.y = 200;
LK.gui.addChild(advancedObjects);
// Create a title
var title = new Text2("Physics Playground", {
size: 50,
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 50;
LK.gui.addChild(title);
// Instructions
var instructions = new Text2("Drag from the circle to create\nobjects that bounce with physics", {
size: 30,
fill: 0xFFFFFF
});
instructions.anchor.set(0.5, 0);
instructions.x = 2048 / 2;
instructions.y = 120;
LK.gui.addChild(instructions);
// Ball counter
var ballCountText = new Text2("Balls: 0", {
size: 30,
fill: 0xFFFFFF
});
ballCountText.anchor.set(0, 0);
ballCountText.x = 50;
ballCountText.y = 50;
LK.gui.addChild(ballCountText);
// Easter egg hint
var easterEggHint = new Text2("What happens at 100?", {
size: 20,
fill: 0xCCCCCC
});
easterEggHint.anchor.set(0, 0);
easterEggHint.x = 50;
easterEggHint.y = 90;
easterEggHint.alpha = 0.7;
LK.gui.addChild(easterEggHint);
// Game area doesn't need specific event handlers since
// the DraggableButton handles its own events
game.down = function (x, y, obj) {};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// Track total balls spawned and chaos mode
var totalBallsSpawned = 0;
var chaosMode = false;
// Update physics in the game loop
game.update = function () {
updatePhysics();
// Update glitch button if it exists
if (glitchButton) {
glitchButton.update();
}
// Extra chaotic effects when in chaos mode
if (chaosMode) {
// Randomly glitch UI sometimes
if (Math.random() < 0.005) {
glitchUI();
}
}
};
// Create a new physics object at specified position
function createPhysicsObject(x, y, type, properties) {
var newObject = new PhysicsObject(type || 'circle', properties || {
mass: 1,
friction: 0.1,
restitution: 0.7
});
newObject.x = x;
newObject.y = y;
game.addChild(newObject);
physicsObjects.push(newObject);
// Set appropriate physics properties based on shape
if (type === 'square' || type === 'rectangle') {
// Squares and rectangles have more friction
newObject.friction = properties && properties.friction || 0.2;
// Squares and rectangles bounce less
newObject.restitution = properties && properties.restitution || 0.4;
} else if (type === 'triangle') {
// Triangles are lighter
newObject.mass = properties && properties.mass || 0.8;
// Triangles have less friction
newObject.friction = properties && properties.friction || 0.05;
// Triangles bounce more
newObject.restitution = properties && properties.restitution || 0.8;
}
// Track ball count and trigger chaos mode at 100
if (type === 'circle' || !type) {
totalBallsSpawned++;
// Show count
if (ballCountText) {
ballCountText.setText("Balls: " + totalBallsSpawned);
}
// Check for chaos threshold
if (totalBallsSpawned >= 100 && !chaosMode) {
chaosMode = true;
// Flash screen
LK.effects.flashScreen(0xFF0000, 500);
// Create visual ball explosion
for (var i = 0; i < 20; i++) {
var angle = Math.random() * Math.PI * 2;
var speed = 20 + Math.random() * 20;
var ball = new PhysicsObject('circle', {
mass: 0.5 + Math.random(),
restitution: 0.9,
friction: 0.05
});
ball.x = x;
ball.y = y;
ball.velocityX = Math.cos(angle) * speed;
ball.velocityY = Math.sin(angle) * speed;
ball.angularVelocity = Math.random() * 0.2 - 0.1;
game.addChild(ball);
physicsObjects.push(ball);
}
}
}
// Play place sound
LK.getSound('place').play();
return newObject;
}
// Update physics for all objects
function updatePhysics() {
for (var i = 0; i < physicsObjects.length; i++) {
var obj = physicsObjects[i];
if (!obj.isStatic) {
// Apply gravity
obj.velocityY += GRAVITY * obj.mass;
// Apply drag
obj.velocityX *= 1 - DRAG;
obj.velocityY *= 1 - DRAG;
obj.angularVelocity *= 1 - DRAG;
// Update position
obj.x += obj.velocityX;
obj.y += obj.velocityY;
// In chaos mode, objects can sometimes teleport
if (chaosMode && Math.random() < 0.01) {
obj.x = Math.random() * 2048;
obj.y = Math.random() * GROUND_Y * 0.7;
obj.velocityX *= -1.5;
obj.velocityY *= -1.5;
obj.visual.alpha = 0.7;
tween(obj.visual, {
alpha: 1,
scaleX: 1 + Math.random() * 0.5,
scaleY: 1 + Math.random() * 0.5
}, {
duration: 300,
easing: tween.easeOutElastic
});
}
// Update rotation with extra spin in chaos mode
obj.rotation += obj.angularVelocity * (chaosMode && Math.random() < 0.1 ? 3 : 1);
obj.visual.rotation = obj.rotation;
// Check boundaries
checkBoundaries(obj);
// Check collisions with other objects
for (var j = 0; j < physicsObjects.length; j++) {
if (i !== j) {
checkCollision(obj, physicsObjects[j]);
}
}
}
}
}
// Check if an object is out of bounds
function checkBoundaries(obj) {
// Left boundary
if (obj.x - obj.visual.width / 2 < 0) {
obj.x = obj.visual.width / 2;
obj.velocityX = -obj.velocityX * obj.restitution;
}
// Right boundary
if (obj.x + obj.visual.width / 2 > 2048) {
obj.x = 2048 - obj.visual.width / 2;
obj.velocityX = -obj.velocityX * obj.restitution;
}
// Bottom boundary
if (obj.y + obj.visual.height / 2 > GROUND_Y - ground.visual.height / 2) {
obj.y = GROUND_Y - ground.visual.height / 2 - obj.visual.height / 2;
obj.velocityY = -obj.velocityY * obj.restitution;
// Apply friction
obj.velocityX *= 1 - obj.friction;
// Play bounce sound if the impact is significant
if (Math.abs(obj.velocityY) > 3) {
LK.getSound('bounce').play();
}
}
}
// Simple collision detection and response
function checkCollision(obj1, obj2) {
if (obj1.intersects(obj2)) {
// Only process if not already processed in reverse
if (obj1.isStatic && obj2.isStatic) {
return; // Two static objects don't interact
}
// Calculate collision vector
var dx = obj2.x - obj1.x;
var dy = obj2.y - obj1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize collision vector
var nx = dx / distance;
var ny = dy / distance;
// Calculate minimum translation distance
var obj1Width = obj1.type === 'car' ? obj1.width / 2 : obj1.visual.width / 2;
var obj2Width = obj2.type === 'car' ? obj2.width / 2 : obj2.visual.width / 2;
var minDist = obj1Width + obj2Width;
var mtd = minDist - distance;
// Resolve collision
if (!obj1.isStatic && !obj2.isStatic) {
// Both objects move
var totalMass = obj1.mass + obj2.mass;
var obj1Ratio = obj1.mass / totalMass;
var obj2Ratio = obj2.mass / totalMass;
obj1.x -= nx * mtd * obj2Ratio;
obj1.y -= ny * mtd * obj2Ratio;
obj2.x += nx * mtd * obj1Ratio;
obj2.y += ny * mtd * obj1Ratio;
// Calculate relative velocity
var vrx = obj2.velocityX - obj1.velocityX;
var vry = obj2.velocityY - obj1.velocityY;
// Calculate impulse
var impulse = -(1 + Math.min(obj1.restitution, obj2.restitution)) * (vrx * nx + vry * ny) / (1 / obj1.mass + 1 / obj2.mass);
// Apply impulse
obj1.velocityX -= impulse * nx / obj1.mass;
obj1.velocityY -= impulse * ny / obj1.mass;
obj2.velocityX += impulse * nx / obj2.mass;
obj2.velocityY += impulse * ny / obj2.mass;
// Add angular velocity based on off-center collision
var impact = Math.abs(impulse);
obj1.angularVelocity += impact * 0.01 * (Math.random() - 0.5);
obj2.angularVelocity += impact * 0.01 * (Math.random() - 0.5);
// Play bounce sound if the impact is significant
if (impact > 3) {
LK.getSound('bounce').play();
}
} else {
// One object is static
var movingObj, staticObj;
if (obj1.isStatic) {
movingObj = obj2;
staticObj = obj1;
nx = -nx;
ny = -ny;
} else {
movingObj = obj1;
staticObj = obj2;
}
// Move the moving object
movingObj.x += nx * mtd;
movingObj.y += ny * mtd;
// Calculate new velocity
var dot = movingObj.velocityX * nx + movingObj.velocityY * ny;
movingObj.velocityX -= (1 + movingObj.restitution) * dot * nx;
movingObj.velocityY -= (1 + movingObj.restitution) * dot * ny;
// Apply friction
var tangentX = -ny;
var tangentY = nx;
var tangentDot = movingObj.velocityX * tangentX + movingObj.velocityY * tangentY;
movingObj.velocityX -= tangentDot * tangentX * staticObj.friction;
movingObj.velocityY -= tangentDot * tangentY * staticObj.friction;
// Add angular velocity
movingObj.angularVelocity += dot * 0.02 * (Math.random() - 0.5);
// Play bounce sound if the impact is significant
if (Math.abs(dot) > 3) {
LK.getSound('bounce').play();
}
}
}
}
// Clear all objects except ground
function clearAll() {
for (var i = physicsObjects.length - 1; i >= 0; i--) {
var obj = physicsObjects[i];
if (obj !== ground) {
game.removeChild(obj);
physicsObjects.splice(i, 1);
}
}
LK.getSound('delete').play();
}
// Add object selector button
var objectSelectorButton = new UIButton("Objects", 150, 80, 0x27ae60);
objectSelectorButton.x = 2048 - 300;
objectSelectorButton.y = 300;
objectSelectorButton.onPress = function () {
if (!objectSelector) {
// Create and show the object selector
objectSelector = new ObjectSelector();
objectSelector.x = 2048 / 2;
objectSelector.y = 2732 / 2;
objectSelector.onSelectObject = function (type) {
selectedObjectType = type;
// Update draggable button appearance
circleCreator.updateVisual(type);
// Hide selector
LK.gui.removeChild(objectSelector);
objectSelector = null;
};
LK.gui.addChild(objectSelector);
} else {
// Hide selector
LK.gui.removeChild(objectSelector);
objectSelector = null;
}
};
LK.gui.addChild(objectSelectorButton);
// Add a clear button
var clearButton = new UIButton("Clear", 150, 80, 0xdc3545);
clearButton.x = 2048 - 100;
clearButton.y = 300;
clearButton.onPress = clearAll;
LK.gui.addChild(clearButton);
// Add the glitch button
var glitchButton = new GlitchButton();
glitchButton.x = 150;
glitchButton.y = 600;
LK.gui.addChild(glitchButton);
// Helper function to darken a color
function darkenColor(color, percent) {
var r = color >> 16 & 0xFF;
var g = color >> 8 & 0xFF;
var b = color & 0xFF;
r = Math.floor(r * (1 - percent));
g = Math.floor(g * (1 - percent));
b = Math.floor(b * (1 - percent));
return r << 16 | g << 8 | b;
}
// Helper function to lighten a color
function lightenColor(color, percent) {
var r = color >> 16 & 0xFF;
var g = color >> 8 & 0xFF;
var b = color & 0xFF;
r = Math.floor(r + (255 - r) * percent);
g = Math.floor(g + (255 - g) * percent);
b = Math.floor(b + (255 - b) * percent);
return r << 16 | g << 8 | b;
}
// Update game physics and glitch effects
game.update = function () {
// Skip normal updates in cleaning mode
if (cleaningMode) {
return;
}
updatePhysics();
// Update glitch button if it exists
if (glitchButton) {
glitchButton.update();
}
// Extra chaotic effects when in chaos mode
if (chaosMode) {
// Randomly glitch UI sometimes
if (Math.random() < 0.005) {
glitchUI();
}
}
};
// Glitch UI elements function
function glitchUI() {
// Elements to glitch
var uiElements = [title, instructions, ballCountText, easterEggHint, circleCreator, clearButton, objectSelectorButton, advancedObjects];
// Apply random transformations to all UI elements
for (var i = 0; i < uiElements.length; i++) {
var element = uiElements[i];
var originalX = element.x;
var originalY = element.y;
var originalRotation = element.rotation || 0;
// Random position and rotation
tween(element, {
x: originalX + Math.random() * 300 - 150,
y: originalY + Math.random() * 300 - 150,
rotation: originalRotation + Math.random() * 0.5 - 0.25
}, {
duration: 300,
easing: tween.easeOutElastic,
onFinish: function (el, origX, origY, origRot) {
return function () {
// Return to original position with a new tween
tween(el, {
x: origX + (Math.random() * 40 - 20),
y: origY + (Math.random() * 40 - 20),
rotation: origRot + (Math.random() * 0.1 - 0.05)
}, {
duration: 500,
easing: tween.easeOutElastic
});
};
}(element, originalX, originalY, originalRotation)
});
// Also apply scale and alpha glitching
tween(element, {
scaleX: 1 + Math.random() * 0.4 - 0.2,
scaleY: 1 + Math.random() * 0.4 - 0.2,
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 200,
easing: tween.easeOutElastic,
onFinish: function onFinish() {
tween(this, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300
});
}
});
}
// Create some temporary glitch particles in random positions
for (var j = 0; j < 30; j++) {
var glitchParticle = new GlitchParticle({
size: 10 + Math.random() * 30,
glitchRate: 0.5
});
glitchParticle.x = Math.random() * 2048;
glitchParticle.y = Math.random() * 1000;
LK.gui.addChild(glitchParticle);
// Remove after a short time
LK.setTimeout(function (particle) {
return function () {
LK.gui.removeChild(particle);
};
}(glitchParticle), 1000 + Math.random() * 2000);
}
}
// Add blue screen of death button at the bottom of the screen
var blueScreenButton = new BlueScreenButton();
blueScreenButton.x = 2048 / 2;
blueScreenButton.y = 2732 - 100;
LK.gui.addChild(blueScreenButton);
// Play background music
LK.playMusic('bgmusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AdvancedObjectsMenu = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 250;
buttonBg.height = 60;
// Button label
var label = new Text2("Advanced Objects", {
size: 28,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Dropdown container (hidden initially)
var dropdown = new Container();
dropdown.y = 70;
dropdown.visible = false;
self.addChild(dropdown);
// Dropdown background
var dropdownBg = LK.getAsset('block', {
anchorX: 0.5,
anchorY: 0
});
dropdownBg.tint = 0x333333;
dropdownBg.width = 250;
dropdownBg.height = 80;
dropdown.addChild(dropdownBg);
// Car option
var carOption = new Container();
carOption.y = 15;
dropdown.addChild(carOption);
var carLabel = new Text2("Car", {
size: 24,
fill: 0xFFFFFF
});
carLabel.anchor.set(0.5, 0.5);
carOption.addChild(carLabel);
// Draggable state
self.isOpen = false;
self.isDraggingCar = false;
self.currentCar = null;
// Toggle dropdown
self.down = function (x, y, obj) {
// Only toggle if clicking the main button (not the dropdown)
if (!self.isOpen || y < self.y + buttonBg.height / 2) {
self.isOpen = !self.isOpen;
dropdown.visible = self.isOpen;
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
}
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
// Car option interaction
carOption.interactive = true;
carOption.down = function (x, y, obj) {
self.isDraggingCar = true;
// Create a car object that follows the pointer
self.currentCar = new Car();
// Get global position
var globalPos = game.toLocal(self.parent.toGlobal({
x: x,
y: y
}));
self.currentCar.x = globalPos.x;
self.currentCar.y = globalPos.y;
// Add to game
game.addChild(self.currentCar);
// Visual feedback
tween(carLabel, {
alpha: 0.7
}, {
duration: 100
});
};
carOption.move = function (x, y, obj) {
if (self.isDraggingCar && self.currentCar) {
// Get global position
var globalPos = game.toLocal(self.parent.toGlobal({
x: x,
y: y
}));
self.currentCar.x = globalPos.x;
self.currentCar.y = globalPos.y;
}
};
carOption.up = function (x, y, obj) {
if (self.isDraggingCar && self.currentCar) {
// Add physics to the car
physicsObjects.push(self.currentCar);
// Set initial velocity
self.currentCar.velocityX = 0;
self.currentCar.velocityY = 0;
// Reset state
self.isDraggingCar = false;
self.currentCar = null;
// Play sound
LK.getSound('place').play();
}
// Visual feedback
tween(carLabel, {
alpha: 1
}, {
duration: 100
});
};
return self;
});
var BlueScreenButton = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('buttonBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 300;
buttonBg.height = 80;
// Button label
var label = new Text2("BLUE SCREEN OF DEATH", {
size: 24,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Button interaction
self.down = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
// Show blue screen of death
showBlueScreenOfDeath();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
// Car-specific properties
self.type = 'car';
self.width = 200;
self.height = 100;
self.mass = 2;
self.friction = 0.2;
self.restitution = 0.3;
self.velocityX = 0;
self.velocityY = 0;
self.rotation = 0;
self.angularVelocity = 0;
self.isStatic = false;
// Car body
self.visual = self.attachAsset('rectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 100
});
self.visual.tint = 0xff4400; // Orange/red car
// Add a roof/cabin
var roof = LK.getAsset('rectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: 100,
height: 50
});
roof.tint = 0xff7700;
roof.y = -25;
self.addChild(roof);
// Add wheels
var frontWheel = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 50,
height: 50
});
frontWheel.tint = 0x333333;
frontWheel.x = 70;
frontWheel.y = 40;
self.addChild(frontWheel);
var rearWheel = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 50,
height: 50
});
rearWheel.tint = 0x333333;
rearWheel.x = -70;
rearWheel.y = 40;
self.addChild(rearWheel);
// Add headlights
var headlight1 = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20
});
headlight1.tint = 0xffffcc;
headlight1.x = 95;
headlight1.y = -15;
self.addChild(headlight1);
var headlight2 = LK.getAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20
});
headlight2.tint = 0xffffcc;
headlight2.x = 95;
headlight2.y = 15;
self.addChild(headlight2);
// Update method to handle wheels rotation
self.update = function () {
// Rotate wheels based on horizontal velocity
frontWheel.rotation += self.velocityX * 0.03;
rearWheel.rotation += self.velocityX * 0.03;
};
return self;
});
var DraggableButton = Container.expand(function () {
var self = Container.call(this);
// Create visual representation
var buttonVisual = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a label
var label = new Text2("Create", {
size: 24,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Track if we're currently creating an object
self.isCreating = false;
self.currentObject = null;
self.objectType = 'circle'; // Default object type
// Update the visual based on the selected object type
self.updateVisual = function (type) {
if (type) {
self.objectType = type;
}
// Remove existing visual
self.removeChild(buttonVisual);
// Create new visual based on current object type
buttonVisual = self.attachAsset(self.objectType, {
anchorX: 0.5,
anchorY: 0.5
});
// Adjust for triangle shape
if (self.objectType === 'triangle') {
buttonVisual.scaleY = 0.5;
buttonVisual.y = buttonVisual.height / 4;
}
// Make sure label stays on top
self.removeChild(label);
self.addChild(label);
};
// Handle touch/click down
self.down = function (x, y, obj) {
self.isCreating = true;
// Create a new physics object that follows the pointer
self.currentObject = new PhysicsObject(self.objectType, {
mass: 1,
restitution: 0.7,
friction: 0.1
});
// Position at pointer
self.currentObject.x = x;
self.currentObject.y = y;
// Add to game
game.addChild(self.currentObject);
// Visual feedback
tween(buttonVisual, {
alpha: 0.7,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
// Handle movement
self.move = function (x, y, obj) {
if (self.isCreating && self.currentObject) {
self.currentObject.x = x;
self.currentObject.y = y;
}
};
// Handle release
self.up = function (x, y, obj) {
if (self.isCreating && self.currentObject) {
// Add physics to the object
physicsObjects.push(self.currentObject);
// Set initial velocity based on recent movement
if (chaosMode) {
// More chaotic initial velocity in chaos mode
self.currentObject.velocityX = Math.random() * 30 - 15;
self.currentObject.velocityY = Math.random() * -20 - 5;
self.currentObject.angularVelocity = Math.random() * 0.3 - 0.15;
// Sometimes create multiple balls when in chaos mode
if (Math.random() < 0.3) {
for (var i = 0; i < 3; i++) {
createPhysicsObject(x + Math.random() * 100 - 50, y + Math.random() * 100 - 50, self.objectType, {
mass: 0.5 + Math.random(),
restitution: 0.8,
friction: 0.05
});
}
}
} else {
// Normal initial velocity
self.currentObject.velocityX = Math.random() * 10 - 5;
self.currentObject.velocityY = -10; // Initial upward velocity
}
// Reset state
self.isCreating = false;
self.currentObject = null;
// Play sound
LK.getSound('place').play();
}
// Visual feedback
tween(buttonVisual, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
var GlitchButton = Container.expand(function () {
var self = Container.call(this);
// Button properties
self.width = 150;
self.height = 150;
self.isGlitching = false;
self.particles = [];
self.maxParticles = 20;
self.glitchActivated = false;
// Visual appearance
var buttonVisual = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5,
width: self.width,
height: self.height
});
buttonVisual.tint = 0x00FFFF; // Cyan
// Text label
var label = new Text2("GLITCH", {
size: 32,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Create particles
for (var i = 0; i < self.maxParticles; i++) {
createParticle();
}
// Create a single particle
function createParticle() {
var particle = new GlitchParticle({
color: Math.random() < 0.5 ? 0x00FFFF : 0xFF00FF,
size: 5 + Math.random() * 15,
distance: 80 + Math.random() * 60,
speed: 0.5 + Math.random() * 1.5,
glitchRate: 0.1 + Math.random() * 0.2
});
// Position relative to button
particle.setOrigin(0, 0);
self.addChild(particle);
self.particles.push(particle);
}
// Button interaction
self.down = function (x, y, obj) {
// Increment glitch counter
glitchCounter++;
// Trigger glitch effect
self.glitchActivated = true;
// Visual feedback
tween(buttonVisual, {
alpha: 0.8,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
// Trigger chaos mode
chaosMode = true;
// Flash screen
LK.effects.flashScreen(0x00FFFF, 500);
// Visual glitch effect for all UI elements
glitchUI();
// Check if we reached 50 glitches
if (glitchCounter >= 50 && !cleaningMode) {
// Activate cleaning mode
cleaningMode = true;
// Hide all UI elements
hideAllUI();
// Start virus cleaning process
startVirusCleaning();
}
// Play sound
LK.getSound('place').play();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonVisual, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
// Update particles
self.update = function () {
// Update each particle
for (var i = 0; i < self.particles.length; i++) {
self.particles[i].update();
}
// Button glitch effect
if (Math.random() < 0.1) {
self.isGlitching = !self.isGlitching;
if (self.isGlitching) {
buttonVisual.tint = Math.random() < 0.5 ? 0xFF00FF : 0x00FFFF;
label.position.x = Math.random() * 10 - 5;
label.position.y = Math.random() * 10 - 5;
// Sometimes change text
if (Math.random() < 0.2) {
label.setText(Math.random() < 0.5 ? "ERR0R" : "GL1TCH");
}
} else {
buttonVisual.tint = 0x00FFFF;
label.position.x = 0;
label.position.y = 0;
label.setText("GLITCH");
}
}
};
return self;
});
// Glitch UI elements function
var GlitchParticle = Container.expand(function (options) {
var self = Container.call(this);
// Default options
options = options || {};
self.size = options.size || Math.random() * 10 + 5;
self.speed = options.speed || Math.random() * 2 + 1;
self.distance = options.distance || 50 + Math.random() * 100;
self.angle = options.angle || Math.random() * Math.PI * 2;
self.rotation = Math.random() * Math.PI * 2;
self.rotationSpeed = Math.random() * 0.2 - 0.1;
self.alpha = 0.7 + Math.random() * 0.3;
self.glitchRate = options.glitchRate || 0.2;
// Visual appearance
var visual = self.attachAsset('square', {
anchorX: 0.5,
anchorY: 0.5
});
visual.width = self.size;
visual.height = self.size;
visual.tint = options.color || 0x00FFFF;
// Animation properties
self.time = 0;
self.originalX = 0;
self.originalY = 0;
self.offsetX = 0;
self.offsetY = 0;
// Update particle position
self.update = function () {
self.time += 0.05;
// Orbital movement
self.offsetX = Math.cos(self.angle + self.time * self.speed) * self.distance;
self.offsetY = Math.sin(self.angle + self.time * self.speed) * self.distance;
self.x = self.originalX + self.offsetX;
self.y = self.originalY + self.offsetY;
// Rotate
visual.rotation += self.rotationSpeed;
// Random glitch effect
if (Math.random() < self.glitchRate) {
visual.x = Math.random() * 10 - 5;
visual.y = Math.random() * 10 - 5;
visual.alpha = 0.5 + Math.random() * 0.5;
visual.tint = Math.random() < 0.5 ? 0x00FFFF : 0xFF00FF;
} else {
visual.x = 0;
visual.y = 0;
visual.alpha = self.alpha;
}
};
// Set origin point
self.setOrigin = function (x, y) {
self.originalX = x;
self.originalY = y;
};
return self;
});
var ObjectSelector = Container.expand(function () {
var self = Container.call(this);
// Create main container
var buttonContainer = new Container();
self.addChild(buttonContainer);
// Header text
var headerText = new Text2("Objects", {
size: 36,
fill: 0xFFFFFF
});
headerText.anchor.set(0.5, 0);
headerText.y = -60;
self.addChild(headerText);
// Create object buttons
var objectTypes = [{
type: 'circle',
label: 'Circle',
color: 0xe74c3c
}, {
type: 'square',
label: 'Square',
color: 0x3498db
}, {
type: 'rectangle',
label: 'Rectangle',
color: 0x2ecc71
}, {
type: 'triangle',
label: 'Triangle',
color: 0x70ae6e
}];
var buttonWidth = 150;
var buttonHeight = 80;
var buttonSpacing = 20;
var buttonsPerRow = 2;
for (var i = 0; i < objectTypes.length; i++) {
var col = i % buttonsPerRow;
var row = Math.floor(i / buttonsPerRow);
var button = new UIButton(objectTypes[i].label, buttonWidth, buttonHeight, objectTypes[i].color);
button.x = col * (buttonWidth + buttonSpacing) - (buttonsPerRow - 1) * (buttonWidth + buttonSpacing) / 2;
button.y = row * (buttonHeight + buttonSpacing);
button.objectType = objectTypes[i].type;
button.onPress = function () {
if (self.onSelectObject) {
self.onSelectObject(this.objectType);
}
};
buttonContainer.addChild(button);
}
return self;
});
var PhysicsObject = Container.expand(function (type, properties) {
var self = Container.call(this);
self.type = type || 'block';
// Default properties
self.mass = (properties === null || properties === void 0 ? void 0 : properties.mass) || 1;
self.friction = (properties === null || properties === void 0 ? void 0 : properties.friction) || 0.1;
self.restitution = (properties === null || properties === void 0 ? void 0 : properties.restitution) || 0.5;
self.isStatic = (properties === null || properties === void 0 ? void 0 : properties.isStatic) || false;
// Physics variables
self.velocityX = 0;
self.velocityY = 0;
self.rotation = 0;
self.angularVelocity = 0;
// Create visual representation
var visual = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
if (type === 'triangle') {
// Make the triangle shape by scaling
visual.scaleY = 0.5;
visual.y = visual.height / 4;
}
self.visual = visual;
// Visual feedback for static objects
if (self.isStatic) {
visual.alpha = 0.7;
}
// Modify the color based on mass
var color = visual.tint;
if (self.mass > 1) {
// Darken for heavier objects
visual.tint = darkenColor(color, 0.2 * (self.mass - 1));
} else if (self.mass < 1) {
// Lighten for lighter objects
visual.tint = lightenColor(color, 0.2 * (1 - self.mass));
}
// Handle interaction
self.down = function (x, y, obj) {
// Only allow dragging if we're in edit mode
if (currentMode === 'edit') {
isDragging = true;
draggedObject = self;
// Store offset for dragging
dragOffsetX = self.x - x;
dragOffsetY = self.y - y;
}
};
return self;
});
var UIButton = Container.expand(function (label, width, height, color) {
var self = Container.call(this);
// Create button background
var background = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
background.tint = color || 0x4d90ff;
background.width = width || 150;
background.height = height || 80;
// Create button label
var labelText = new Text2(label, {
size: 30,
fill: 0xFFFFFF
});
labelText.anchor.set(0.5, 0.5);
self.addChild(labelText);
// Handle button press
self.down = function (x, y, obj) {
tween(background, {
alpha: 0.7
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(background, {
alpha: 1
}, {
duration: 100
});
if (self.onPress) {
self.onPress();
}
};
return self;
});
// Glitch UI elements function
var VirusScanButton = Container.expand(function () {
var self = Container.call(this);
// Create button background
var buttonBg = self.attachAsset('buttonBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x4286f4;
buttonBg.width = 300;
buttonBg.height = 80;
// Button label
var label = new Text2("VIRUS SCAN AGAIN", {
size: 30,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
// Button interaction
self.down = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 0.8,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
// Show blue screen of death
showBlueScreenOfDeath();
};
self.up = function (x, y, obj) {
// Visual feedback
tween(buttonBg, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Function to hide all UI elements
function hideAllUI() {
// Set background to black
game.setBackgroundColor(0x000000);
// Remove all physics objects
for (var i = physicsObjects.length - 1; i >= 0; i--) {
game.removeChild(physicsObjects[i]);
physicsObjects.splice(i, 1);
}
// Hide all GUI elements
var uiElements = [title, instructions, ballCountText, easterEggHint, circleCreator, clearButton, objectSelectorButton, advancedObjects, glitchButton];
for (var i = 0; i < uiElements.length; i++) {
if (uiElements[i] && uiElements[i].parent) {
uiElements[i].parent.removeChild(uiElements[i]);
}
}
// Clear any existing object selector
if (objectSelector && objectSelector.parent) {
objectSelector.parent.removeChild(objectSelector);
objectSelector = null;
}
}
// Function to start virus cleaning process
function startVirusCleaning() {
// Create cleaning text
var cleaningText = new Text2("CLEANING ALL VIRUSES", {
size: 60,
fill: 0x00FF00
});
cleaningText.anchor.set(0.5, 0.5);
cleaningText.x = 2048 / 2;
cleaningText.y = 2732 / 2 - 100;
LK.gui.addChild(cleaningText);
// Create progress text
var progressText = new Text2("0%", {
size: 50,
fill: 0x00FF00
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 2048 / 2;
progressText.y = 2732 / 2;
LK.gui.addChild(progressText);
// Update progress
var progressInterval = LK.setInterval(function () {
cleanProgress += 1;
progressText.setText(cleanProgress + "%");
// Check if cleaning is complete
if (cleanProgress >= 100) {
LK.clearInterval(progressInterval);
// Remove cleaning texts
LK.gui.removeChild(cleaningText);
LK.gui.removeChild(progressText);
// Show error message
showErrorMessage();
}
}, 100);
}
// Function to show error message
function showErrorMessage() {
// Create error text
var errorText = new Text2("ERROR: PLEASE RESTART THE GAME", {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 2732 / 2;
LK.gui.addChild(errorText);
// Create blinking effect
var blinkInterval = LK.setInterval(function () {
errorText.visible = !errorText.visible;
}, 500);
// Automatically restart the game after a few seconds
LK.setTimeout(function () {
LK.clearInterval(blinkInterval);
LK.showGameOver();
}, 5000);
}
// Function to show blue screen of death
function showBlueScreenOfDeath() {
// Hide all game elements
hideAllUI();
// Clear all UI
LK.gui.removeChildren();
// Set background to blue
game.setBackgroundColor(0x0078D7); // Modern Windows BSOD blue
// Create BSOD content - Windows 10 style
var sadFaceText = new Text2(":(", {
size: 180,
fill: 0xFFFFFF
});
sadFaceText.anchor.set(0, 0);
sadFaceText.x = 400;
sadFaceText.y = 300;
LK.gui.addChild(sadFaceText);
var bsodText = new Text2("Your PC ran into a problem and needs to restart.", {
size: 50,
fill: 0xFFFFFF
});
bsodText.anchor.set(0, 0);
bsodText.x = 400;
bsodText.y = 550;
LK.gui.addChild(bsodText);
var collectingText = new Text2("We're just collecting some error info, and then we'll restart for you.", {
size: 36,
fill: 0xFFFFFF
});
collectingText.anchor.set(0, 0);
collectingText.x = 400;
collectingText.y = 650;
LK.gui.addChild(collectingText);
// Progress counter that goes from 0% to 100%
var progress = 0;
var percentText = new Text2("0% complete", {
size: 36,
fill: 0xFFFFFF
});
percentText.anchor.set(0, 0);
percentText.x = 400;
percentText.y = 800;
LK.gui.addChild(percentText);
// QR code representation (simplified as a white square)
var qrCode = LK.getAsset('square', {
anchorX: 0,
anchorY: 0,
width: 200,
height: 200
});
qrCode.tint = 0xFFFFFF;
qrCode.x = 400;
qrCode.y = 900;
LK.gui.addChild(qrCode);
// Add QR code text indicating it leads to Roblox.com
var qrCodeText = new Text2("Scan to go to: roblox.com", {
size: 30,
fill: 0xFFFFFF
});
qrCodeText.anchor.set(0, 0);
qrCodeText.x = 620;
qrCodeText.y = 950;
LK.gui.addChild(qrCodeText);
var errorCodeText = new Text2("CRITICAL_PROCESS_DIED", {
size: 40,
fill: 0xFFFFFF
});
errorCodeText.anchor.set(0, 0);
errorCodeText.x = 400;
errorCodeText.y = 1150;
LK.gui.addChild(errorCodeText);
var stopCodeText = new Text2("Stop Code: 01X10XX011X0ERROR", {
size: 36,
fill: 0xFFFFFF
});
stopCodeText.anchor.set(0, 0);
stopCodeText.x = 400;
stopCodeText.y = 1200;
LK.gui.addChild(stopCodeText);
// Update progress and auto-restart when done
var progressInterval = LK.setInterval(function () {
progress += 1;
percentText.setText(progress + "% complete");
// When reaches 100%, restart game
if (progress >= 100) {
LK.clearInterval(progressInterval);
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}, 100);
}
// Glitch UI elements function
var GRAVITY = 0.5;
var DRAG = 0.02;
var GROUND_Y = 2500;
// Game state
var physicsObjects = [];
var isSimulating = true;
var currentMode = 'edit'; // Define currentMode variable
var isDragging = false;
var draggedObject = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var selectedObjectType = 'circle';
var objectSelector = null;
var glitchCounter = 0;
var cleaningMode = false;
var cleanProgress = 0;
// Create the ground
var ground = new PhysicsObject('ground', {
isStatic: true
});
ground.x = 2048 / 2;
ground.y = GROUND_Y;
game.addChild(ground);
physicsObjects.push(ground);
// Create a draggable button that creates physics objects
var circleCreator = new DraggableButton();
circleCreator.x = 200;
circleCreator.y = 200;
LK.gui.addChild(circleCreator);
// Add the advanced objects dropdown
var advancedObjects = new AdvancedObjectsMenu();
advancedObjects.x = 450;
advancedObjects.y = 200;
LK.gui.addChild(advancedObjects);
// Create a title
var title = new Text2("Physics Playground", {
size: 50,
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 50;
LK.gui.addChild(title);
// Instructions
var instructions = new Text2("Drag from the circle to create\nobjects that bounce with physics", {
size: 30,
fill: 0xFFFFFF
});
instructions.anchor.set(0.5, 0);
instructions.x = 2048 / 2;
instructions.y = 120;
LK.gui.addChild(instructions);
// Ball counter
var ballCountText = new Text2("Balls: 0", {
size: 30,
fill: 0xFFFFFF
});
ballCountText.anchor.set(0, 0);
ballCountText.x = 50;
ballCountText.y = 50;
LK.gui.addChild(ballCountText);
// Easter egg hint
var easterEggHint = new Text2("What happens at 100?", {
size: 20,
fill: 0xCCCCCC
});
easterEggHint.anchor.set(0, 0);
easterEggHint.x = 50;
easterEggHint.y = 90;
easterEggHint.alpha = 0.7;
LK.gui.addChild(easterEggHint);
// Game area doesn't need specific event handlers since
// the DraggableButton handles its own events
game.down = function (x, y, obj) {};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// Track total balls spawned and chaos mode
var totalBallsSpawned = 0;
var chaosMode = false;
// Update physics in the game loop
game.update = function () {
updatePhysics();
// Update glitch button if it exists
if (glitchButton) {
glitchButton.update();
}
// Extra chaotic effects when in chaos mode
if (chaosMode) {
// Randomly glitch UI sometimes
if (Math.random() < 0.005) {
glitchUI();
}
}
};
// Create a new physics object at specified position
function createPhysicsObject(x, y, type, properties) {
var newObject = new PhysicsObject(type || 'circle', properties || {
mass: 1,
friction: 0.1,
restitution: 0.7
});
newObject.x = x;
newObject.y = y;
game.addChild(newObject);
physicsObjects.push(newObject);
// Set appropriate physics properties based on shape
if (type === 'square' || type === 'rectangle') {
// Squares and rectangles have more friction
newObject.friction = properties && properties.friction || 0.2;
// Squares and rectangles bounce less
newObject.restitution = properties && properties.restitution || 0.4;
} else if (type === 'triangle') {
// Triangles are lighter
newObject.mass = properties && properties.mass || 0.8;
// Triangles have less friction
newObject.friction = properties && properties.friction || 0.05;
// Triangles bounce more
newObject.restitution = properties && properties.restitution || 0.8;
}
// Track ball count and trigger chaos mode at 100
if (type === 'circle' || !type) {
totalBallsSpawned++;
// Show count
if (ballCountText) {
ballCountText.setText("Balls: " + totalBallsSpawned);
}
// Check for chaos threshold
if (totalBallsSpawned >= 100 && !chaosMode) {
chaosMode = true;
// Flash screen
LK.effects.flashScreen(0xFF0000, 500);
// Create visual ball explosion
for (var i = 0; i < 20; i++) {
var angle = Math.random() * Math.PI * 2;
var speed = 20 + Math.random() * 20;
var ball = new PhysicsObject('circle', {
mass: 0.5 + Math.random(),
restitution: 0.9,
friction: 0.05
});
ball.x = x;
ball.y = y;
ball.velocityX = Math.cos(angle) * speed;
ball.velocityY = Math.sin(angle) * speed;
ball.angularVelocity = Math.random() * 0.2 - 0.1;
game.addChild(ball);
physicsObjects.push(ball);
}
}
}
// Play place sound
LK.getSound('place').play();
return newObject;
}
// Update physics for all objects
function updatePhysics() {
for (var i = 0; i < physicsObjects.length; i++) {
var obj = physicsObjects[i];
if (!obj.isStatic) {
// Apply gravity
obj.velocityY += GRAVITY * obj.mass;
// Apply drag
obj.velocityX *= 1 - DRAG;
obj.velocityY *= 1 - DRAG;
obj.angularVelocity *= 1 - DRAG;
// Update position
obj.x += obj.velocityX;
obj.y += obj.velocityY;
// In chaos mode, objects can sometimes teleport
if (chaosMode && Math.random() < 0.01) {
obj.x = Math.random() * 2048;
obj.y = Math.random() * GROUND_Y * 0.7;
obj.velocityX *= -1.5;
obj.velocityY *= -1.5;
obj.visual.alpha = 0.7;
tween(obj.visual, {
alpha: 1,
scaleX: 1 + Math.random() * 0.5,
scaleY: 1 + Math.random() * 0.5
}, {
duration: 300,
easing: tween.easeOutElastic
});
}
// Update rotation with extra spin in chaos mode
obj.rotation += obj.angularVelocity * (chaosMode && Math.random() < 0.1 ? 3 : 1);
obj.visual.rotation = obj.rotation;
// Check boundaries
checkBoundaries(obj);
// Check collisions with other objects
for (var j = 0; j < physicsObjects.length; j++) {
if (i !== j) {
checkCollision(obj, physicsObjects[j]);
}
}
}
}
}
// Check if an object is out of bounds
function checkBoundaries(obj) {
// Left boundary
if (obj.x - obj.visual.width / 2 < 0) {
obj.x = obj.visual.width / 2;
obj.velocityX = -obj.velocityX * obj.restitution;
}
// Right boundary
if (obj.x + obj.visual.width / 2 > 2048) {
obj.x = 2048 - obj.visual.width / 2;
obj.velocityX = -obj.velocityX * obj.restitution;
}
// Bottom boundary
if (obj.y + obj.visual.height / 2 > GROUND_Y - ground.visual.height / 2) {
obj.y = GROUND_Y - ground.visual.height / 2 - obj.visual.height / 2;
obj.velocityY = -obj.velocityY * obj.restitution;
// Apply friction
obj.velocityX *= 1 - obj.friction;
// Play bounce sound if the impact is significant
if (Math.abs(obj.velocityY) > 3) {
LK.getSound('bounce').play();
}
}
}
// Simple collision detection and response
function checkCollision(obj1, obj2) {
if (obj1.intersects(obj2)) {
// Only process if not already processed in reverse
if (obj1.isStatic && obj2.isStatic) {
return; // Two static objects don't interact
}
// Calculate collision vector
var dx = obj2.x - obj1.x;
var dy = obj2.y - obj1.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize collision vector
var nx = dx / distance;
var ny = dy / distance;
// Calculate minimum translation distance
var obj1Width = obj1.type === 'car' ? obj1.width / 2 : obj1.visual.width / 2;
var obj2Width = obj2.type === 'car' ? obj2.width / 2 : obj2.visual.width / 2;
var minDist = obj1Width + obj2Width;
var mtd = minDist - distance;
// Resolve collision
if (!obj1.isStatic && !obj2.isStatic) {
// Both objects move
var totalMass = obj1.mass + obj2.mass;
var obj1Ratio = obj1.mass / totalMass;
var obj2Ratio = obj2.mass / totalMass;
obj1.x -= nx * mtd * obj2Ratio;
obj1.y -= ny * mtd * obj2Ratio;
obj2.x += nx * mtd * obj1Ratio;
obj2.y += ny * mtd * obj1Ratio;
// Calculate relative velocity
var vrx = obj2.velocityX - obj1.velocityX;
var vry = obj2.velocityY - obj1.velocityY;
// Calculate impulse
var impulse = -(1 + Math.min(obj1.restitution, obj2.restitution)) * (vrx * nx + vry * ny) / (1 / obj1.mass + 1 / obj2.mass);
// Apply impulse
obj1.velocityX -= impulse * nx / obj1.mass;
obj1.velocityY -= impulse * ny / obj1.mass;
obj2.velocityX += impulse * nx / obj2.mass;
obj2.velocityY += impulse * ny / obj2.mass;
// Add angular velocity based on off-center collision
var impact = Math.abs(impulse);
obj1.angularVelocity += impact * 0.01 * (Math.random() - 0.5);
obj2.angularVelocity += impact * 0.01 * (Math.random() - 0.5);
// Play bounce sound if the impact is significant
if (impact > 3) {
LK.getSound('bounce').play();
}
} else {
// One object is static
var movingObj, staticObj;
if (obj1.isStatic) {
movingObj = obj2;
staticObj = obj1;
nx = -nx;
ny = -ny;
} else {
movingObj = obj1;
staticObj = obj2;
}
// Move the moving object
movingObj.x += nx * mtd;
movingObj.y += ny * mtd;
// Calculate new velocity
var dot = movingObj.velocityX * nx + movingObj.velocityY * ny;
movingObj.velocityX -= (1 + movingObj.restitution) * dot * nx;
movingObj.velocityY -= (1 + movingObj.restitution) * dot * ny;
// Apply friction
var tangentX = -ny;
var tangentY = nx;
var tangentDot = movingObj.velocityX * tangentX + movingObj.velocityY * tangentY;
movingObj.velocityX -= tangentDot * tangentX * staticObj.friction;
movingObj.velocityY -= tangentDot * tangentY * staticObj.friction;
// Add angular velocity
movingObj.angularVelocity += dot * 0.02 * (Math.random() - 0.5);
// Play bounce sound if the impact is significant
if (Math.abs(dot) > 3) {
LK.getSound('bounce').play();
}
}
}
}
// Clear all objects except ground
function clearAll() {
for (var i = physicsObjects.length - 1; i >= 0; i--) {
var obj = physicsObjects[i];
if (obj !== ground) {
game.removeChild(obj);
physicsObjects.splice(i, 1);
}
}
LK.getSound('delete').play();
}
// Add object selector button
var objectSelectorButton = new UIButton("Objects", 150, 80, 0x27ae60);
objectSelectorButton.x = 2048 - 300;
objectSelectorButton.y = 300;
objectSelectorButton.onPress = function () {
if (!objectSelector) {
// Create and show the object selector
objectSelector = new ObjectSelector();
objectSelector.x = 2048 / 2;
objectSelector.y = 2732 / 2;
objectSelector.onSelectObject = function (type) {
selectedObjectType = type;
// Update draggable button appearance
circleCreator.updateVisual(type);
// Hide selector
LK.gui.removeChild(objectSelector);
objectSelector = null;
};
LK.gui.addChild(objectSelector);
} else {
// Hide selector
LK.gui.removeChild(objectSelector);
objectSelector = null;
}
};
LK.gui.addChild(objectSelectorButton);
// Add a clear button
var clearButton = new UIButton("Clear", 150, 80, 0xdc3545);
clearButton.x = 2048 - 100;
clearButton.y = 300;
clearButton.onPress = clearAll;
LK.gui.addChild(clearButton);
// Add the glitch button
var glitchButton = new GlitchButton();
glitchButton.x = 150;
glitchButton.y = 600;
LK.gui.addChild(glitchButton);
// Helper function to darken a color
function darkenColor(color, percent) {
var r = color >> 16 & 0xFF;
var g = color >> 8 & 0xFF;
var b = color & 0xFF;
r = Math.floor(r * (1 - percent));
g = Math.floor(g * (1 - percent));
b = Math.floor(b * (1 - percent));
return r << 16 | g << 8 | b;
}
// Helper function to lighten a color
function lightenColor(color, percent) {
var r = color >> 16 & 0xFF;
var g = color >> 8 & 0xFF;
var b = color & 0xFF;
r = Math.floor(r + (255 - r) * percent);
g = Math.floor(g + (255 - g) * percent);
b = Math.floor(b + (255 - b) * percent);
return r << 16 | g << 8 | b;
}
// Update game physics and glitch effects
game.update = function () {
// Skip normal updates in cleaning mode
if (cleaningMode) {
return;
}
updatePhysics();
// Update glitch button if it exists
if (glitchButton) {
glitchButton.update();
}
// Extra chaotic effects when in chaos mode
if (chaosMode) {
// Randomly glitch UI sometimes
if (Math.random() < 0.005) {
glitchUI();
}
}
};
// Glitch UI elements function
function glitchUI() {
// Elements to glitch
var uiElements = [title, instructions, ballCountText, easterEggHint, circleCreator, clearButton, objectSelectorButton, advancedObjects];
// Apply random transformations to all UI elements
for (var i = 0; i < uiElements.length; i++) {
var element = uiElements[i];
var originalX = element.x;
var originalY = element.y;
var originalRotation = element.rotation || 0;
// Random position and rotation
tween(element, {
x: originalX + Math.random() * 300 - 150,
y: originalY + Math.random() * 300 - 150,
rotation: originalRotation + Math.random() * 0.5 - 0.25
}, {
duration: 300,
easing: tween.easeOutElastic,
onFinish: function (el, origX, origY, origRot) {
return function () {
// Return to original position with a new tween
tween(el, {
x: origX + (Math.random() * 40 - 20),
y: origY + (Math.random() * 40 - 20),
rotation: origRot + (Math.random() * 0.1 - 0.05)
}, {
duration: 500,
easing: tween.easeOutElastic
});
};
}(element, originalX, originalY, originalRotation)
});
// Also apply scale and alpha glitching
tween(element, {
scaleX: 1 + Math.random() * 0.4 - 0.2,
scaleY: 1 + Math.random() * 0.4 - 0.2,
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 200,
easing: tween.easeOutElastic,
onFinish: function onFinish() {
tween(this, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300
});
}
});
}
// Create some temporary glitch particles in random positions
for (var j = 0; j < 30; j++) {
var glitchParticle = new GlitchParticle({
size: 10 + Math.random() * 30,
glitchRate: 0.5
});
glitchParticle.x = Math.random() * 2048;
glitchParticle.y = Math.random() * 1000;
LK.gui.addChild(glitchParticle);
// Remove after a short time
LK.setTimeout(function (particle) {
return function () {
LK.gui.removeChild(particle);
};
}(glitchParticle), 1000 + Math.random() * 2000);
}
}
// Add blue screen of death button at the bottom of the screen
var blueScreenButton = new BlueScreenButton();
blueScreenButton.x = 2048 / 2;
blueScreenButton.y = 2732 - 100;
LK.gui.addChild(blueScreenButton);
// Play background music
LK.playMusic('bgmusic');