User prompt
But this is now just a half ball. Fix it discoball to a full ball with the other half
User prompt
Thediscoball is not spinning in full 360 circle around y axis. Fix it
User prompt
Move the djdeck down by 12 units
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'y')' in or related to this line: 'var peopleAreaY = djDeck.y - djDeck.height / 2 - 200; // Position above the DJ deck' Line Number: 789
User prompt
Add above the djdesk animated dancing people-womens and mans
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'fogButton.down = function (x, y, obj) {' Line Number: 811
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'on')' in or related to this line: 'fogButton.on('down', function (x, y, obj) {' Line Number: 811
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'interactive')' in or related to this line: 'fogButton.interactive = true;' Line Number: 809
User prompt
Ensure the fog is active if fogbutton pressed
User prompt
Move the fog button down by 77 units
User prompt
Move the fog button left by 777 units
User prompt
Move the fog button under the pause button
User prompt
Add fog button under the pause button.
User prompt
Add fog button asset to the game.
User prompt
Add fog button asset to the game. Place fog button asseet under the pause button.
User prompt
Add fog button under the pause button
User prompt
Please fix the bug: 'fogButton.children[0].children[0].setText is not a function' in or related to this line: 'fogButton.children[0].children[0].setText('FOG'); // Access the Text2 object inside the FXButton's children' Line Number: 808
User prompt
Add fog button tunder the pause button
User prompt
Make bigger fog
User prompt
Change the fog looking for a more realistic discofog
User prompt
Change the fog looking for a more realistic discofog
User prompt
Add FogEffect class for animated fog in upper half of the map βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Turn off the game over event from the game
User prompt
Add animated fog effect to the upper half of the map
User prompt
Move up lasershow by 123 units
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Crossfader: Controls mix between decks var Crossfader = Container.expand(function () { var self = Container.call(this); // State self.value = 0.5; // 0 = left, 1 = right self.dragging = false; // Visuals var track = self.attachAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 0.5 }); var knob = self.attachAsset('crossfaderKnob', { anchorX: 0.5, anchorY: 0.5 }); knob.y = 0; // Methods self.setValue = function (val) { self.value = Math.max(0, Math.min(1, val)); knob.x = (self.value - 0.5) * (track.width - knob.width); }; // Touch events self.down = function (x, y, obj) { self.dragging = true; self.setValue(x / track.width); }; self.up = function (x, y, obj) { self.dragging = false; }; self.move = function (x, y, obj) { if (self.dragging) { self.setValue(x / track.width); } }; return self; }); // DeckPlatter: Represents a turntable platter var DeckPlatter = Container.expand(function () { var self = Container.call(this); // State self.isActive = false; self.isScratching = false; self.lastAngle = 0; self.rotationOffset = 0; self.currentRotation = 0; self.track = 'A'; // 'A' or 'B' self.playing = true; self.scratchSpeed = 0; self.lastTouchAngle = null; // Visuals var platter = self.attachAsset('deckPlatter', { anchorX: 0.5, anchorY: 0.5 }); var highlight = self.attachAsset('deckPlatterHighlight', { anchorX: 0.5, anchorY: 0.5 }); highlight.alpha = 0; var label = self.attachAsset('deckLabel', { anchorX: 0.5, anchorY: 0.5, y: 140 }); // Label text var labelTxt = new Text2(self.track, { size: 40, fill: "#222" }); labelTxt.anchor.set(0.5, 0.5); label.addChild(labelTxt); // Beat light var beatLight = self.attachAsset('beatLight', { anchorX: 0.5, anchorY: 0.5, y: -140 }); beatLight.alpha = 0.2; // Methods self.setActive = function (active) { self.isActive = active; highlight.alpha = active ? 0.4 : 0; }; self.setTrack = function (track) { self.track = track; labelTxt.setText(track); }; self.flashBeat = function () { beatLight.alpha = 1; tween(beatLight, { alpha: 0.2 }, { duration: 200, easing: tween.easeOut }); }; // Touch events self.down = function (x, y, obj) { self.isScratching = true; self.setActive(true); // Calculate angle from center var dx = x - self.width / 2; var dy = y - self.height / 2; self.lastTouchAngle = Math.atan2(dy, dx); self.scratchSpeed = 0; LK.getSound('scratch').play(); }; self.up = function (x, y, obj) { self.isScratching = false; self.setActive(false); self.scratchSpeed = 0; self.lastTouchAngle = null; }; self.move = function (x, y, obj) { if (!self.isScratching) return; // Calculate angle from center var dx = x - self.width / 2; var dy = y - self.height / 2; var angle = Math.atan2(dy, dx); if (self.lastTouchAngle !== null) { var delta = angle - self.lastTouchAngle; // Normalize delta if (delta > Math.PI) delta -= 2 * Math.PI; if (delta < -Math.PI) delta += 2 * Math.PI; self.rotationOffset += delta; self.scratchSpeed = delta; } self.lastTouchAngle = angle; }; // Called every tick self.update = function () { // If not scratching, platter rotates at normal speed if (!self.isScratching && self.playing) { self.rotationOffset += 0.02; // Normal play speed self.scratchSpeed = 0.02; } // Apply rotation self.currentRotation = self.rotationOffset; self.rotation = self.currentRotation; }; return self; }); // Discoball: True 3D disco ball illusion with spinning mirrored tiles and shining white light particles var Discoball = Container.expand(function () { var self = Container.call(this); // Config var ballRadius = 150; var ballDiameter = ballRadius * 2; var numLat = 13; // latitude tiles (vertical) var numLon = 24; // longitude tiles (horizontal) var tileSize = ballDiameter / numLat * 0.95; var tileGap = tileSize * 0.12; var tiles = []; var shineParticles = []; var numShine = 18; var shineRadius = ballRadius * 1.08; var shineMinAlpha = 0.25; var shineMaxAlpha = 0.95; var shineMinSize = tileSize * 0.7; var shineMaxSize = tileSize * 1.7; var spinY = 0; // radians, for y-axis rotation var spinSpeed = 0.012; var spinDir = 1; // --- Mirrored Tiles Grid --- for (var lat = 0; lat < numLat; lat++) { var theta = Math.PI * (lat + 0.5) / numLat; // 0 (top) to PI (bottom) var y = Math.cos(theta) * ballRadius; var r = Math.sin(theta) * ballRadius; for (var lon = 0; lon < numLon; lon++) { var phi = 2 * Math.PI * lon / numLon; // 3D to 2D projection with y-axis spin var x3d = Math.cos(phi) * r; var z3d = Math.sin(phi) * r; // Y-axis spin var x2d = x3d * Math.cos(spinY) - z3d * Math.sin(spinY); var z2d = x3d * Math.sin(spinY) + z3d * Math.cos(spinY); // Only draw front-facing tiles (z2d > 0) if (z2d > 0) { var tile = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: tileSize, height: tileSize }); // Mirror color: light gray, with some random sparkle var base = 0xbb + Math.floor(Math.random() * 0x22); var color = base << 16 | base << 8 | base; tile.tint = color; tile.alpha = 0.92 - 0.18 * (lat / numLat) + Math.random() * 0.08; // Position tile.x = x2d; tile.y = y; // Simulate 3D: scaleX based on z2d tile.scaleX = 1 + 0.18 * (z2d / ballRadius); tile.scaleY = 1; self.addChild(tile); tiles.push({ tile: tile, lat: lat, lon: lon, theta: theta, phi: phi }); } } } // --- Specular highlight (white spot) --- var highlight = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: ballRadius * 0.7, height: ballRadius * 0.36 }); highlight.tint = 0xffffff; highlight.alpha = 0.7; highlight.x = -ballRadius * 0.32; highlight.y = -ballRadius * 0.38; self.addChild(highlight); // --- Shining white light particles --- for (var i = 0; i < numShine; i++) { var angle = 2 * Math.PI * i / numShine + Math.random() * 0.2; var dist = shineRadius * (0.92 + Math.random() * 0.12); var particle = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: shineMinSize + Math.random() * (shineMaxSize - shineMinSize), height: shineMinSize + Math.random() * (shineMaxSize - shineMinSize) }); particle.tint = 0xffffff; particle.alpha = shineMinAlpha + Math.random() * (shineMaxAlpha - shineMinAlpha); particle.x = Math.cos(angle) * dist; particle.y = Math.sin(angle) * dist; self.addChild(particle); shineParticles.push({ particle: particle, baseAngle: angle, baseDist: dist, phase: Math.random() * Math.PI * 2 }); } // --- Light beams (background) --- var numBeams = 32; var beams = []; var lightBeamLength = 1200; // Increased from 800 to 1200 for longer beams for (var i = 0; i < numBeams; i++) { var beam = LK.getAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 0, width: 8, height: lightBeamLength }); beam.tint = 0xffffff; beam.alpha = 0.12 + Math.random() * 0.28; beam.rotation = Math.PI * 2 / numBeams * i + Math.random() * 0.1; beams.push(beam); self.addChild(beam); } // --- Animation --- function animateSpinY() { // Animate spinY between -PI/2 and PI/2 for y-axis illusion var target = spinDir > 0 ? Math.PI / 2 : -Math.PI / 2; tween(self, { _spinY: target }, { duration: 1600, easing: tween.linear, onUpdate: function onUpdate() { // nothing, handled in update }, onFinish: function onFinish() { spinDir *= -1; animateSpinY(); } }); } self._spinY = 0; animateSpinY(); self.update = function () { // Animate y-axis spin spinY += spinSpeed * spinDir; if (spinY > Math.PI / 2) spinY = -Math.PI / 2; if (spinY < -Math.PI / 2) spinY = Math.PI / 2; self._spinY += (spinY - self._spinY) * 0.18; // smooth // Update mirrored tiles positions for y-axis spin for (var i = 0; i < tiles.length; i++) { var t = tiles[i]; // 3D to 2D projection with y-axis spin var x3d = Math.cos(t.phi) * Math.sin(t.theta) * ballRadius; var y3d = Math.cos(t.theta) * ballRadius; var z3d = Math.sin(t.phi) * Math.sin(t.theta) * ballRadius; // Y-axis spin var x2d = x3d * Math.cos(self._spinY) - z3d * Math.sin(self._spinY); var z2d = x3d * Math.sin(self._spinY) + z3d * Math.cos(self._spinY); // Only show front-facing tiles if (z2d > 0) { t.tile.visible = true; t.tile.x = x2d; t.tile.y = y3d; t.tile.scaleX = 1 + 0.18 * (z2d / ballRadius); t.tile.scaleY = 1; // Flicker for disco effect t.tile.alpha = 0.88 - 0.18 * (t.lat / numLat) + Math.random() * 0.09; } else { t.tile.visible = false; } } // Animate highlight to move in a small circle for extra 3D effect var t = Date.now() * 0.001; highlight.x = -ballRadius * 0.32 + Math.cos(t * 1.2) * ballRadius * 0.13; highlight.y = -ballRadius * 0.38 + Math.sin(t * 1.2) * ballRadius * 0.09; // Animate shine particles for (var i = 0; i < shineParticles.length; i++) { var s = shineParticles[i]; var phase = t * 1.2 + s.phase; var r = s.baseDist + Math.sin(phase) * 12; s.particle.x = Math.cos(s.baseAngle + Math.sin(phase) * 0.12) * r; s.particle.y = Math.sin(s.baseAngle + Math.cos(phase) * 0.12) * r; s.particle.alpha = shineMinAlpha + (shineMaxAlpha - shineMinAlpha) * (0.5 + 0.5 * Math.sin(phase * 2 + i)); var size = shineMinSize + (shineMaxSize - shineMinSize) * (0.5 + 0.5 * Math.cos(phase * 1.5 + i)); s.particle.width = size; s.particle.height = size; } // Animate beams (spin and flicker) for (var i = 0; i < beams.length; i++) { var beam = beams[i]; beam.rotation += 0.015; beam.alpha = 0.12 + Math.random() * 0.28; } }; return self; }); // EqualizerWaves: Animated equalizer bars/waves for visual feedback var EqualizerWaves = Container.expand(function () { var self = Container.call(this); // Config var numBars = 32; var barWidth = 40; var barSpacing = 16; var barMaxHeight = 220; var barMinHeight = 40; var bars = []; // Create bars for (var i = 0; i < numBars; i++) { var bar = LK.getAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 1.0, width: barWidth, height: barMinHeight, x: i * (barWidth + barSpacing), y: 0 }); // Rainbow gradient: hue from 0 to 360 across bars var hue = Math.floor(i / numBars * 360); var rgb = hsvToRgb(hue / 360, 1, 1); bar.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2]; // No dark overlay or background is added to the equalizer. self.addChild(bar); bars.push(bar); } // HSV to RGB helper function hsvToRgb(h, s, v) { var r, g, b; var i = Math.floor(h * 6); var f = h * 6 - i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); switch (i % 6) { case 0: r = v, g = t, b = p; break; case 1: r = q, g = v, b = p; break; case 2: r = p, g = v, b = t; break; case 3: r = p, g = q, b = v; break; case 4: r = t, g = p, b = v; break; case 5: r = v, g = p, b = q; break; } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } // Center and scale down the whole equalizer to half size self.width = numBars * (barWidth + barSpacing) * 0.5; self.height = barMaxHeight * 0.5; self.scaleX = 0.5; self.scaleY = 0.5; self.x = 2048 / 2 - self.width / 2; self.y = 600; // Upper half of screen, below GUI // Animation state self.phase = []; for (var j = 0; j < numBars; j++) { self.phase[j] = Math.random() * Math.PI * 2; } // Animate bars self.update = function () { var t = Date.now() * 0.002; for (var i = 0; i < numBars; i++) { // Simulate music: combine sine waves and random var wave = Math.sin(t + self.phase[i]) * 0.5 + 0.5; var beatPulse = (Math.sin(t * 2 + i * 0.2) * 0.5 + 0.5) * 0.5; var randomPulse = Math.random() * 0.15; var h = barMinHeight + (barMaxHeight - barMinHeight) * (wave * 0.6 + beatPulse * 0.3 + randomPulse); bars[i].height = h; } }; return self; }); // FXButton: Triggers a sound effect var FXButton = Container.expand(function () { var self = Container.call(this); // Visuals var btn = self.attachAsset('fxButton', { anchorX: 0.5, anchorY: 0.5 }); var txt = new Text2('FX', { size: 48, fill: "#fff" }); txt.anchor.set(0.5, 0.5); btn.addChild(txt); // State self.cooldown = false; // Touch self.down = function (x, y, obj) { if (self.cooldown) return; self.cooldown = true; LK.getSound('fx').play(); tween(btn, { scaleX: 1.2, scaleY: 1.2 }, { duration: 80, onFinish: function onFinish() { tween(btn, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } }); LK.setTimeout(function () { self.cooldown = false; }, 400); }; return self; }); // LaserShow: Realistic party laser show with moving heads and multi-color animated beams var LaserShow = Container.expand(function () { var self = Container.call(this); // Config var numHeads = 6; var beamsPerHead = 3; var headRadius = 1100; // Increased from 800 to 1100 for wider spread var centerX = 2048 / 2; var centerY = 400; var beamLength = 1600; // Increased from 1200 to 1600 for longer beams var beamWidth = 18; var beamAlpha = 0.65; var headAlpha = 0.7; var heads = []; var beams = []; // Predefined rainbow colors for beams var beamColors = [0xff0000, // red 0xff8000, // orange 0xffff00, // yellow 0x00ff00, // green 0x00ffff, // cyan 0x0000ff, // blue 0x8000ff, // violet 0xff00ff // magenta ]; // Create moving heads and beams for (var h = 0; h < numHeads; h++) { // Head position in a semi-circle var angle = Math.PI * (h + 1) / (numHeads + 1); var hx = centerX + Math.cos(angle) * headRadius; var hy = centerY + Math.sin(angle) * 200; // Head (visual: ellipse, colored) // Use rainbowEllipse for gradient rainbow look var head = LK.getAsset('rainbowEllipse', { anchorX: 0.5, anchorY: 0.5, x: hx, y: hy, width: 20, height: 20 }); head.alpha = headAlpha; // Animate color: store initial hue offset for each head head._rainbowHueOffset = h * (360 / numHeads); self.addChild(head); heads.push(head); // Beams for this head for (var b = 0; b < beamsPerHead; b++) { var beam = LK.getAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 0, x: hx, y: hy, width: beamWidth, height: beamLength }); // Assign color in a rainbow pattern, offset by head and beam beam.tint = beamColors[(h * beamsPerHead + b) % beamColors.length]; beam.alpha = beamAlpha; // Initial rotation beam.rotation = 0; self.addChild(beam); beams.push({ obj: beam, headIdx: h, beamIdx: b, baseAngle: angle }); } } // Animate heads and beams self.update = function () { var t = Date.now() * 0.001; // Animate heads in a subtle up/down and color pulse for (var h = 0; h < heads.length; h++) { var head = heads[h]; // Sway up/down head.y = centerY + Math.sin(Math.PI * (h + 1) / (numHeads + 1)) * 200 + Math.sin(t * 1.2 + h) * 18; // Pulse alpha head.alpha = headAlpha + 0.15 * Math.sin(t * 2 + h); // Animate rainbow color: cycle hue every second // Full cycle every 1 second (t mod 1.0) var hue = (head._rainbowHueOffset + t * 360) % 360 / 360; // HSV to RGB conversion var i = Math.floor(hue * 6); var f = hue * 6 - i; var q = 1 - f; var tcol = 1 - (1 - f); var r, g, b; switch (i % 6) { case 0: r = 1, g = tcol, b = 0; break; case 1: r = q, g = 1, b = 0; break; case 2: r = 0, g = 1, b = tcol; break; case 3: r = 0, g = q, b = 1; break; case 4: r = tcol, g = 0, b = 1; break; case 5: r = 1, g = 0, b = q; break; } var tint = Math.round(r * 255) << 16 | Math.round(g * 255) << 8 | Math.round(b * 255); // Tween the head tint for smooth color change tween(head, { tint: tint }, { duration: 120, easing: tween.linear }); } // Animate beams: sweep, flicker, and color pulse for (var i = 0; i < beams.length; i++) { var beamData = beams[i]; var beam = beamData.obj; var h = beamData.headIdx; var b = beamData.beamIdx; var baseAngle = beamData.baseAngle; // Beam origin follows head var head = heads[h]; beam.x = head.x; beam.y = head.y; // Animate beam angle: base + sweeping + per-beam offset var sweep = Math.sin(t * 1.1 + h + b * 0.7) * 0.25 + Math.sin(t * 0.7 + b) * 0.12; var beatPulse = Math.sin(t * 2.5 + h + b) * 0.08; beam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse; // Animate beam length for flicker var flicker = 1 + 0.12 * Math.sin(t * 3 + h * 2 + b * 1.5 + Math.sin(t * 1.5 + b)); beam.height = beamLength * flicker; // Animate color pulse (simulate RGB laser color mixing) var colorIdx = (h * beamsPerHead + b + Math.floor(t * 2 + h + b)) % beamColors.length; beam.tint = beamColors[colorIdx]; // Animate alpha for strobe effect beam.alpha = beamAlpha + 0.15 * Math.abs(Math.sin(t * 4 + h + b)); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Discoball (top of screen) --- var discoball = new Discoball(); game.addChild(discoball); discoball.x = 2048 / 2; discoball.y = 200; // Position at the top of the screen discoball.scaleX = 0.8; discoball.scaleY = 0.8; // --- Extra white particles for upper half sparkle effect --- var extraWhiteParticles = []; var numExtraParticles = 32; for (var i = 0; i < numExtraParticles; i++) { // Random position in upper half, avoid top 100px (menu) var px = 100 + Math.random() * (2048 - 200); var py = 120 + Math.random() * (1366 - 220); var size = 8 + Math.random() * 10; var particle = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: size, height: size }); particle.tint = 0xffffff; particle.alpha = 0.18 + Math.random() * 0.22; particle.x = px; particle.y = py; game.addChild(particle); extraWhiteParticles.push({ obj: particle, baseX: px, baseY: py, phase: Math.random() * Math.PI * 2, baseAlpha: particle.alpha, baseSize: size }); } // Animate extra particles in game.update // --- Laser Show (upper half) --- var laserShow = new LaserShow(); game.addChild(laserShow); laserShow.y = -456; // Move laser effect up by 456 units (333 + 123) // --- DJ Deck Asset --- var djDeck = LK.getAsset('djDeck', { anchorX: 0.5, anchorY: 0.5 }); game.addChild(djDeck); djDeck.x = 2048 / 2; djDeck.y = 2732 / 2 + 333; // Move the DJ deck down by 333 units // No dark overlay is present, so nothing to remove. // --- Decks --- // Sound effects (dummy, as actual music is handled by LK) // Beat lights // FX Button // Crossfader // Deck platters (turntables) // --- Layout constants --- var deckY = 1366; // Move decks to vertical center of 2732px screen var deckSpacing = 1000; var crossfaderY = 1800; var fxButtonY = 2200; // --- Equalizer Waves (upper half) --- var equalizer = new EqualizerWaves(); game.addChild(equalizer); // --- Decks --- var leftDeck = new DeckPlatter(); leftDeck.setTrack('A'); game.addChild(leftDeck); leftDeck.x = 2048 / 2 - deckSpacing / 2; leftDeck.y = deckY; var rightDeck = new DeckPlatter(); rightDeck.setTrack('B'); game.addChild(rightDeck); rightDeck.x = 2048 / 2 + deckSpacing / 2; rightDeck.y = deckY; // --- Crossfader --- var crossfader = new Crossfader(); game.addChild(crossfader); crossfader.x = 2048 / 2; crossfader.y = crossfaderY; crossfader.setValue(0.5); // --- FX Button --- var fxButton = new FXButton(); game.addChild(fxButton); fxButton.x = 2048 / 2; fxButton.y = fxButtonY; // --- Score / Combo / Energy --- var energy = 50; // 0-100 var combo = 0; var score = 0; // Energy bar var energyBarBg = LK.getAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 0.5, width: 600, height: 40 }); energyBarBg.tint = 0x222222; energyBarBg.y = 0; var energyBar = LK.getAsset('crossfaderTrack', { anchorX: 0.5, anchorY: 0.5, width: 600, height: 40 }); energyBar.tint = 0x00ff00; energyBar.y = 0; var energyBarContainer = new Container(); energyBarContainer.addChild(energyBarBg); energyBarContainer.addChild(energyBar); energyBarContainer.x = 2048 / 2; energyBarContainer.y = 200; LK.gui.top.addChild(energyBarContainer); // Score text var scoreTxt = new Text2('Score: 0', { size: 80, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.x = 2048 / 2; scoreTxt.y = 300; // Combo text var comboTxt = new Text2('', { size: 60, fill: "#ff0" }); comboTxt.anchor.set(0.5, 0); LK.gui.top.addChild(comboTxt); comboTxt.x = 2048 / 2; comboTxt.y = 400; // --- State --- var dragging = null; // Which control is being dragged var lastTouchObj = null; // --- Beat simulation --- var beatInterval = 600; // ms per beat var beatTimer = 0; var lastTickTime = Date.now(); // --- Music --- LK.playMusic('trackA', { loop: true }); LK.playMusic('trackB', { loop: true }); var trackAVol = 1; var trackBVol = 1; // --- Touch handling --- function getTouchedControl(x, y) { // Check decks var lx = leftDeck.toLocal(game.toGlobal({ x: x, y: y })).x; var ly = leftDeck.toLocal(game.toGlobal({ x: x, y: y })).y; if (Math.pow(lx - leftDeck.width / 2, 2) + Math.pow(ly - leftDeck.height / 2, 2) < 200 * 200) return leftDeck; var rx = rightDeck.toLocal(game.toGlobal({ x: x, y: y })).x; var ry = rightDeck.toLocal(game.toGlobal({ x: x, y: y })).y; if (Math.pow(rx - rightDeck.width / 2, 2) + Math.pow(ry - rightDeck.height / 2, 2) < 200 * 200) return rightDeck; // Crossfader var cf = crossfader.toLocal(game.toGlobal({ x: x, y: y })); if (cf.x > 0 && cf.x < crossfader.width && cf.y > 0 && cf.y < crossfader.height) return crossfader; // FX Button var fx = fxButton.toLocal(game.toGlobal({ x: x, y: y })); if (Math.pow(fx.x - fxButton.width / 2, 2) + Math.pow(fx.y - fxButton.height / 2, 2) < 60 * 60) return fxButton; return null; } game.down = function (x, y, obj) { var control = getTouchedControl(x, y); dragging = control; lastTouchObj = obj; if (control && control.down) { // Convert to local var local = control.toLocal(game.toGlobal({ x: x, y: y })); control.down(local.x, local.y, obj); } }; game.up = function (x, y, obj) { if (dragging && dragging.up) { var local = dragging.toLocal(game.toGlobal({ x: x, y: y })); dragging.up(local.x, local.y, obj); } dragging = null; lastTouchObj = null; }; game.move = function (x, y, obj) { if (dragging && dragging.move) { var local = dragging.toLocal(game.toGlobal({ x: x, y: y })); dragging.move(local.x, local.y, obj); } }; // --- Game update --- game.update = function () { // Update discoball animation discoball.update(); // Animate extra white particles (subtle sparkle and movement) if (extraWhiteParticles) { var t = Date.now() * 0.001; for (var i = 0; i < extraWhiteParticles.length; i++) { var p = extraWhiteParticles[i]; // Subtle float and twinkle p.obj.x = p.baseX + Math.sin(t * 1.2 + p.phase + i) * 8; p.obj.y = p.baseY + Math.cos(t * 1.1 + p.phase + i * 0.7) * 6; p.obj.alpha = p.baseAlpha + 0.10 * Math.sin(t * 2.2 + p.phase + i * 0.5); var s = p.baseSize * (0.95 + 0.12 * Math.sin(t * 1.7 + p.phase + i)); p.obj.width = s; p.obj.height = s; } } // Update equalizer animation equalizer.update(); // Update laser show animation laserShow.update(); // Update decks leftDeck.update(); rightDeck.update(); // Simulate beat var now = Date.now(); beatTimer += now - lastTickTime; lastTickTime = now; if (beatTimer >= beatInterval) { beatTimer -= beatInterval; leftDeck.flashBeat(); rightDeck.flashBeat(); LK.getSound('beat').play(); // Energy drops if not scratching or mixing if (!leftDeck.isScratching && !rightDeck.isScratching && crossfader.value > 0.2 && crossfader.value < 0.8) { energy -= 2; combo = 0; } else { // Combo up if scratching or crossfading combo += 1; score += 10 * combo; energy += 2; if (energy > 100) energy = 100; } if (energy < 0) energy = 0; // Update visuals scoreTxt.setText('Score: ' + score); if (combo > 1) { comboTxt.setText('Combo x' + combo); } else { comboTxt.setText(''); } } // Update energy bar energyBar.width = 600 * (energy / 100); // Crossfader logic: adjust music volumes trackAVol = 1 - crossfader.value; trackBVol = crossfader.value; // (In a real game, would set music volumes here, but LK handles music globally.) // End game if energy is 0 if (energy <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } // Win if score is high if (score >= 5000) { LK.effects.flashScreen(0x00ff00, 1000); LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Crossfader: Controls mix between decks
var Crossfader = Container.expand(function () {
var self = Container.call(this);
// State
self.value = 0.5; // 0 = left, 1 = right
self.dragging = false;
// Visuals
var track = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5
});
var knob = self.attachAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5
});
knob.y = 0;
// Methods
self.setValue = function (val) {
self.value = Math.max(0, Math.min(1, val));
knob.x = (self.value - 0.5) * (track.width - knob.width);
};
// Touch events
self.down = function (x, y, obj) {
self.dragging = true;
self.setValue(x / track.width);
};
self.up = function (x, y, obj) {
self.dragging = false;
};
self.move = function (x, y, obj) {
if (self.dragging) {
self.setValue(x / track.width);
}
};
return self;
});
// DeckPlatter: Represents a turntable platter
var DeckPlatter = Container.expand(function () {
var self = Container.call(this);
// State
self.isActive = false;
self.isScratching = false;
self.lastAngle = 0;
self.rotationOffset = 0;
self.currentRotation = 0;
self.track = 'A'; // 'A' or 'B'
self.playing = true;
self.scratchSpeed = 0;
self.lastTouchAngle = null;
// Visuals
var platter = self.attachAsset('deckPlatter', {
anchorX: 0.5,
anchorY: 0.5
});
var highlight = self.attachAsset('deckPlatterHighlight', {
anchorX: 0.5,
anchorY: 0.5
});
highlight.alpha = 0;
var label = self.attachAsset('deckLabel', {
anchorX: 0.5,
anchorY: 0.5,
y: 140
});
// Label text
var labelTxt = new Text2(self.track, {
size: 40,
fill: "#222"
});
labelTxt.anchor.set(0.5, 0.5);
label.addChild(labelTxt);
// Beat light
var beatLight = self.attachAsset('beatLight', {
anchorX: 0.5,
anchorY: 0.5,
y: -140
});
beatLight.alpha = 0.2;
// Methods
self.setActive = function (active) {
self.isActive = active;
highlight.alpha = active ? 0.4 : 0;
};
self.setTrack = function (track) {
self.track = track;
labelTxt.setText(track);
};
self.flashBeat = function () {
beatLight.alpha = 1;
tween(beatLight, {
alpha: 0.2
}, {
duration: 200,
easing: tween.easeOut
});
};
// Touch events
self.down = function (x, y, obj) {
self.isScratching = true;
self.setActive(true);
// Calculate angle from center
var dx = x - self.width / 2;
var dy = y - self.height / 2;
self.lastTouchAngle = Math.atan2(dy, dx);
self.scratchSpeed = 0;
LK.getSound('scratch').play();
};
self.up = function (x, y, obj) {
self.isScratching = false;
self.setActive(false);
self.scratchSpeed = 0;
self.lastTouchAngle = null;
};
self.move = function (x, y, obj) {
if (!self.isScratching) return;
// Calculate angle from center
var dx = x - self.width / 2;
var dy = y - self.height / 2;
var angle = Math.atan2(dy, dx);
if (self.lastTouchAngle !== null) {
var delta = angle - self.lastTouchAngle;
// Normalize delta
if (delta > Math.PI) delta -= 2 * Math.PI;
if (delta < -Math.PI) delta += 2 * Math.PI;
self.rotationOffset += delta;
self.scratchSpeed = delta;
}
self.lastTouchAngle = angle;
};
// Called every tick
self.update = function () {
// If not scratching, platter rotates at normal speed
if (!self.isScratching && self.playing) {
self.rotationOffset += 0.02; // Normal play speed
self.scratchSpeed = 0.02;
}
// Apply rotation
self.currentRotation = self.rotationOffset;
self.rotation = self.currentRotation;
};
return self;
});
// Discoball: True 3D disco ball illusion with spinning mirrored tiles and shining white light particles
var Discoball = Container.expand(function () {
var self = Container.call(this);
// Config
var ballRadius = 150;
var ballDiameter = ballRadius * 2;
var numLat = 13; // latitude tiles (vertical)
var numLon = 24; // longitude tiles (horizontal)
var tileSize = ballDiameter / numLat * 0.95;
var tileGap = tileSize * 0.12;
var tiles = [];
var shineParticles = [];
var numShine = 18;
var shineRadius = ballRadius * 1.08;
var shineMinAlpha = 0.25;
var shineMaxAlpha = 0.95;
var shineMinSize = tileSize * 0.7;
var shineMaxSize = tileSize * 1.7;
var spinY = 0; // radians, for y-axis rotation
var spinSpeed = 0.012;
var spinDir = 1;
// --- Mirrored Tiles Grid ---
for (var lat = 0; lat < numLat; lat++) {
var theta = Math.PI * (lat + 0.5) / numLat; // 0 (top) to PI (bottom)
var y = Math.cos(theta) * ballRadius;
var r = Math.sin(theta) * ballRadius;
for (var lon = 0; lon < numLon; lon++) {
var phi = 2 * Math.PI * lon / numLon;
// 3D to 2D projection with y-axis spin
var x3d = Math.cos(phi) * r;
var z3d = Math.sin(phi) * r;
// Y-axis spin
var x2d = x3d * Math.cos(spinY) - z3d * Math.sin(spinY);
var z2d = x3d * Math.sin(spinY) + z3d * Math.cos(spinY);
// Only draw front-facing tiles (z2d > 0)
if (z2d > 0) {
var tile = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: tileSize,
height: tileSize
});
// Mirror color: light gray, with some random sparkle
var base = 0xbb + Math.floor(Math.random() * 0x22);
var color = base << 16 | base << 8 | base;
tile.tint = color;
tile.alpha = 0.92 - 0.18 * (lat / numLat) + Math.random() * 0.08;
// Position
tile.x = x2d;
tile.y = y;
// Simulate 3D: scaleX based on z2d
tile.scaleX = 1 + 0.18 * (z2d / ballRadius);
tile.scaleY = 1;
self.addChild(tile);
tiles.push({
tile: tile,
lat: lat,
lon: lon,
theta: theta,
phi: phi
});
}
}
}
// --- Specular highlight (white spot) ---
var highlight = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: ballRadius * 0.7,
height: ballRadius * 0.36
});
highlight.tint = 0xffffff;
highlight.alpha = 0.7;
highlight.x = -ballRadius * 0.32;
highlight.y = -ballRadius * 0.38;
self.addChild(highlight);
// --- Shining white light particles ---
for (var i = 0; i < numShine; i++) {
var angle = 2 * Math.PI * i / numShine + Math.random() * 0.2;
var dist = shineRadius * (0.92 + Math.random() * 0.12);
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: shineMinSize + Math.random() * (shineMaxSize - shineMinSize),
height: shineMinSize + Math.random() * (shineMaxSize - shineMinSize)
});
particle.tint = 0xffffff;
particle.alpha = shineMinAlpha + Math.random() * (shineMaxAlpha - shineMinAlpha);
particle.x = Math.cos(angle) * dist;
particle.y = Math.sin(angle) * dist;
self.addChild(particle);
shineParticles.push({
particle: particle,
baseAngle: angle,
baseDist: dist,
phase: Math.random() * Math.PI * 2
});
}
// --- Light beams (background) ---
var numBeams = 32;
var beams = [];
var lightBeamLength = 1200; // Increased from 800 to 1200 for longer beams
for (var i = 0; i < numBeams; i++) {
var beam = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0,
width: 8,
height: lightBeamLength
});
beam.tint = 0xffffff;
beam.alpha = 0.12 + Math.random() * 0.28;
beam.rotation = Math.PI * 2 / numBeams * i + Math.random() * 0.1;
beams.push(beam);
self.addChild(beam);
}
// --- Animation ---
function animateSpinY() {
// Animate spinY between -PI/2 and PI/2 for y-axis illusion
var target = spinDir > 0 ? Math.PI / 2 : -Math.PI / 2;
tween(self, {
_spinY: target
}, {
duration: 1600,
easing: tween.linear,
onUpdate: function onUpdate() {
// nothing, handled in update
},
onFinish: function onFinish() {
spinDir *= -1;
animateSpinY();
}
});
}
self._spinY = 0;
animateSpinY();
self.update = function () {
// Animate y-axis spin
spinY += spinSpeed * spinDir;
if (spinY > Math.PI / 2) spinY = -Math.PI / 2;
if (spinY < -Math.PI / 2) spinY = Math.PI / 2;
self._spinY += (spinY - self._spinY) * 0.18; // smooth
// Update mirrored tiles positions for y-axis spin
for (var i = 0; i < tiles.length; i++) {
var t = tiles[i];
// 3D to 2D projection with y-axis spin
var x3d = Math.cos(t.phi) * Math.sin(t.theta) * ballRadius;
var y3d = Math.cos(t.theta) * ballRadius;
var z3d = Math.sin(t.phi) * Math.sin(t.theta) * ballRadius;
// Y-axis spin
var x2d = x3d * Math.cos(self._spinY) - z3d * Math.sin(self._spinY);
var z2d = x3d * Math.sin(self._spinY) + z3d * Math.cos(self._spinY);
// Only show front-facing tiles
if (z2d > 0) {
t.tile.visible = true;
t.tile.x = x2d;
t.tile.y = y3d;
t.tile.scaleX = 1 + 0.18 * (z2d / ballRadius);
t.tile.scaleY = 1;
// Flicker for disco effect
t.tile.alpha = 0.88 - 0.18 * (t.lat / numLat) + Math.random() * 0.09;
} else {
t.tile.visible = false;
}
}
// Animate highlight to move in a small circle for extra 3D effect
var t = Date.now() * 0.001;
highlight.x = -ballRadius * 0.32 + Math.cos(t * 1.2) * ballRadius * 0.13;
highlight.y = -ballRadius * 0.38 + Math.sin(t * 1.2) * ballRadius * 0.09;
// Animate shine particles
for (var i = 0; i < shineParticles.length; i++) {
var s = shineParticles[i];
var phase = t * 1.2 + s.phase;
var r = s.baseDist + Math.sin(phase) * 12;
s.particle.x = Math.cos(s.baseAngle + Math.sin(phase) * 0.12) * r;
s.particle.y = Math.sin(s.baseAngle + Math.cos(phase) * 0.12) * r;
s.particle.alpha = shineMinAlpha + (shineMaxAlpha - shineMinAlpha) * (0.5 + 0.5 * Math.sin(phase * 2 + i));
var size = shineMinSize + (shineMaxSize - shineMinSize) * (0.5 + 0.5 * Math.cos(phase * 1.5 + i));
s.particle.width = size;
s.particle.height = size;
}
// Animate beams (spin and flicker)
for (var i = 0; i < beams.length; i++) {
var beam = beams[i];
beam.rotation += 0.015;
beam.alpha = 0.12 + Math.random() * 0.28;
}
};
return self;
});
// EqualizerWaves: Animated equalizer bars/waves for visual feedback
var EqualizerWaves = Container.expand(function () {
var self = Container.call(this);
// Config
var numBars = 32;
var barWidth = 40;
var barSpacing = 16;
var barMaxHeight = 220;
var barMinHeight = 40;
var bars = [];
// Create bars
for (var i = 0; i < numBars; i++) {
var bar = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 1.0,
width: barWidth,
height: barMinHeight,
x: i * (barWidth + barSpacing),
y: 0
});
// Rainbow gradient: hue from 0 to 360 across bars
var hue = Math.floor(i / numBars * 360);
var rgb = hsvToRgb(hue / 360, 1, 1);
bar.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
// No dark overlay or background is added to the equalizer.
self.addChild(bar);
bars.push(bar);
}
// HSV to RGB helper
function hsvToRgb(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
// Center and scale down the whole equalizer to half size
self.width = numBars * (barWidth + barSpacing) * 0.5;
self.height = barMaxHeight * 0.5;
self.scaleX = 0.5;
self.scaleY = 0.5;
self.x = 2048 / 2 - self.width / 2;
self.y = 600; // Upper half of screen, below GUI
// Animation state
self.phase = [];
for (var j = 0; j < numBars; j++) {
self.phase[j] = Math.random() * Math.PI * 2;
}
// Animate bars
self.update = function () {
var t = Date.now() * 0.002;
for (var i = 0; i < numBars; i++) {
// Simulate music: combine sine waves and random
var wave = Math.sin(t + self.phase[i]) * 0.5 + 0.5;
var beatPulse = (Math.sin(t * 2 + i * 0.2) * 0.5 + 0.5) * 0.5;
var randomPulse = Math.random() * 0.15;
var h = barMinHeight + (barMaxHeight - barMinHeight) * (wave * 0.6 + beatPulse * 0.3 + randomPulse);
bars[i].height = h;
}
};
return self;
});
// FXButton: Triggers a sound effect
var FXButton = Container.expand(function () {
var self = Container.call(this);
// Visuals
var btn = self.attachAsset('fxButton', {
anchorX: 0.5,
anchorY: 0.5
});
var txt = new Text2('FX', {
size: 48,
fill: "#fff"
});
txt.anchor.set(0.5, 0.5);
btn.addChild(txt);
// State
self.cooldown = false;
// Touch
self.down = function (x, y, obj) {
if (self.cooldown) return;
self.cooldown = true;
LK.getSound('fx').play();
tween(btn, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 80,
onFinish: function onFinish() {
tween(btn, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
LK.setTimeout(function () {
self.cooldown = false;
}, 400);
};
return self;
});
// LaserShow: Realistic party laser show with moving heads and multi-color animated beams
var LaserShow = Container.expand(function () {
var self = Container.call(this);
// Config
var numHeads = 6;
var beamsPerHead = 3;
var headRadius = 1100; // Increased from 800 to 1100 for wider spread
var centerX = 2048 / 2;
var centerY = 400;
var beamLength = 1600; // Increased from 1200 to 1600 for longer beams
var beamWidth = 18;
var beamAlpha = 0.65;
var headAlpha = 0.7;
var heads = [];
var beams = [];
// Predefined rainbow colors for beams
var beamColors = [0xff0000,
// red
0xff8000,
// orange
0xffff00,
// yellow
0x00ff00,
// green
0x00ffff,
// cyan
0x0000ff,
// blue
0x8000ff,
// violet
0xff00ff // magenta
];
// Create moving heads and beams
for (var h = 0; h < numHeads; h++) {
// Head position in a semi-circle
var angle = Math.PI * (h + 1) / (numHeads + 1);
var hx = centerX + Math.cos(angle) * headRadius;
var hy = centerY + Math.sin(angle) * 200;
// Head (visual: ellipse, colored)
// Use rainbowEllipse for gradient rainbow look
var head = LK.getAsset('rainbowEllipse', {
anchorX: 0.5,
anchorY: 0.5,
x: hx,
y: hy,
width: 20,
height: 20
});
head.alpha = headAlpha;
// Animate color: store initial hue offset for each head
head._rainbowHueOffset = h * (360 / numHeads);
self.addChild(head);
heads.push(head);
// Beams for this head
for (var b = 0; b < beamsPerHead; b++) {
var beam = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0,
x: hx,
y: hy,
width: beamWidth,
height: beamLength
});
// Assign color in a rainbow pattern, offset by head and beam
beam.tint = beamColors[(h * beamsPerHead + b) % beamColors.length];
beam.alpha = beamAlpha;
// Initial rotation
beam.rotation = 0;
self.addChild(beam);
beams.push({
obj: beam,
headIdx: h,
beamIdx: b,
baseAngle: angle
});
}
}
// Animate heads and beams
self.update = function () {
var t = Date.now() * 0.001;
// Animate heads in a subtle up/down and color pulse
for (var h = 0; h < heads.length; h++) {
var head = heads[h];
// Sway up/down
head.y = centerY + Math.sin(Math.PI * (h + 1) / (numHeads + 1)) * 200 + Math.sin(t * 1.2 + h) * 18;
// Pulse alpha
head.alpha = headAlpha + 0.15 * Math.sin(t * 2 + h);
// Animate rainbow color: cycle hue every second
// Full cycle every 1 second (t mod 1.0)
var hue = (head._rainbowHueOffset + t * 360) % 360 / 360;
// HSV to RGB conversion
var i = Math.floor(hue * 6);
var f = hue * 6 - i;
var q = 1 - f;
var tcol = 1 - (1 - f);
var r, g, b;
switch (i % 6) {
case 0:
r = 1, g = tcol, b = 0;
break;
case 1:
r = q, g = 1, b = 0;
break;
case 2:
r = 0, g = 1, b = tcol;
break;
case 3:
r = 0, g = q, b = 1;
break;
case 4:
r = tcol, g = 0, b = 1;
break;
case 5:
r = 1, g = 0, b = q;
break;
}
var tint = Math.round(r * 255) << 16 | Math.round(g * 255) << 8 | Math.round(b * 255);
// Tween the head tint for smooth color change
tween(head, {
tint: tint
}, {
duration: 120,
easing: tween.linear
});
}
// Animate beams: sweep, flicker, and color pulse
for (var i = 0; i < beams.length; i++) {
var beamData = beams[i];
var beam = beamData.obj;
var h = beamData.headIdx;
var b = beamData.beamIdx;
var baseAngle = beamData.baseAngle;
// Beam origin follows head
var head = heads[h];
beam.x = head.x;
beam.y = head.y;
// Animate beam angle: base + sweeping + per-beam offset
var sweep = Math.sin(t * 1.1 + h + b * 0.7) * 0.25 + Math.sin(t * 0.7 + b) * 0.12;
var beatPulse = Math.sin(t * 2.5 + h + b) * 0.08;
beam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;
// Animate beam length for flicker
var flicker = 1 + 0.12 * Math.sin(t * 3 + h * 2 + b * 1.5 + Math.sin(t * 1.5 + b));
beam.height = beamLength * flicker;
// Animate color pulse (simulate RGB laser color mixing)
var colorIdx = (h * beamsPerHead + b + Math.floor(t * 2 + h + b)) % beamColors.length;
beam.tint = beamColors[colorIdx];
// Animate alpha for strobe effect
beam.alpha = beamAlpha + 0.15 * Math.abs(Math.sin(t * 4 + h + b));
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- Discoball (top of screen) ---
var discoball = new Discoball();
game.addChild(discoball);
discoball.x = 2048 / 2;
discoball.y = 200; // Position at the top of the screen
discoball.scaleX = 0.8;
discoball.scaleY = 0.8;
// --- Extra white particles for upper half sparkle effect ---
var extraWhiteParticles = [];
var numExtraParticles = 32;
for (var i = 0; i < numExtraParticles; i++) {
// Random position in upper half, avoid top 100px (menu)
var px = 100 + Math.random() * (2048 - 200);
var py = 120 + Math.random() * (1366 - 220);
var size = 8 + Math.random() * 10;
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size
});
particle.tint = 0xffffff;
particle.alpha = 0.18 + Math.random() * 0.22;
particle.x = px;
particle.y = py;
game.addChild(particle);
extraWhiteParticles.push({
obj: particle,
baseX: px,
baseY: py,
phase: Math.random() * Math.PI * 2,
baseAlpha: particle.alpha,
baseSize: size
});
}
// Animate extra particles in game.update
// --- Laser Show (upper half) ---
var laserShow = new LaserShow();
game.addChild(laserShow);
laserShow.y = -456; // Move laser effect up by 456 units (333 + 123)
// --- DJ Deck Asset ---
var djDeck = LK.getAsset('djDeck', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(djDeck);
djDeck.x = 2048 / 2;
djDeck.y = 2732 / 2 + 333; // Move the DJ deck down by 333 units
// No dark overlay is present, so nothing to remove.
// --- Decks ---
// Sound effects (dummy, as actual music is handled by LK)
// Beat lights
// FX Button
// Crossfader
// Deck platters (turntables)
// --- Layout constants ---
var deckY = 1366; // Move decks to vertical center of 2732px screen
var deckSpacing = 1000;
var crossfaderY = 1800;
var fxButtonY = 2200;
// --- Equalizer Waves (upper half) ---
var equalizer = new EqualizerWaves();
game.addChild(equalizer);
// --- Decks ---
var leftDeck = new DeckPlatter();
leftDeck.setTrack('A');
game.addChild(leftDeck);
leftDeck.x = 2048 / 2 - deckSpacing / 2;
leftDeck.y = deckY;
var rightDeck = new DeckPlatter();
rightDeck.setTrack('B');
game.addChild(rightDeck);
rightDeck.x = 2048 / 2 + deckSpacing / 2;
rightDeck.y = deckY;
// --- Crossfader ---
var crossfader = new Crossfader();
game.addChild(crossfader);
crossfader.x = 2048 / 2;
crossfader.y = crossfaderY;
crossfader.setValue(0.5);
// --- FX Button ---
var fxButton = new FXButton();
game.addChild(fxButton);
fxButton.x = 2048 / 2;
fxButton.y = fxButtonY;
// --- Score / Combo / Energy ---
var energy = 50; // 0-100
var combo = 0;
var score = 0;
// Energy bar
var energyBarBg = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 600,
height: 40
});
energyBarBg.tint = 0x222222;
energyBarBg.y = 0;
var energyBar = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 600,
height: 40
});
energyBar.tint = 0x00ff00;
energyBar.y = 0;
var energyBarContainer = new Container();
energyBarContainer.addChild(energyBarBg);
energyBarContainer.addChild(energyBar);
energyBarContainer.x = 2048 / 2;
energyBarContainer.y = 200;
LK.gui.top.addChild(energyBarContainer);
// Score text
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.x = 2048 / 2;
scoreTxt.y = 300;
// Combo text
var comboTxt = new Text2('', {
size: 60,
fill: "#ff0"
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.x = 2048 / 2;
comboTxt.y = 400;
// --- State ---
var dragging = null; // Which control is being dragged
var lastTouchObj = null;
// --- Beat simulation ---
var beatInterval = 600; // ms per beat
var beatTimer = 0;
var lastTickTime = Date.now();
// --- Music ---
LK.playMusic('trackA', {
loop: true
});
LK.playMusic('trackB', {
loop: true
});
var trackAVol = 1;
var trackBVol = 1;
// --- Touch handling ---
function getTouchedControl(x, y) {
// Check decks
var lx = leftDeck.toLocal(game.toGlobal({
x: x,
y: y
})).x;
var ly = leftDeck.toLocal(game.toGlobal({
x: x,
y: y
})).y;
if (Math.pow(lx - leftDeck.width / 2, 2) + Math.pow(ly - leftDeck.height / 2, 2) < 200 * 200) return leftDeck;
var rx = rightDeck.toLocal(game.toGlobal({
x: x,
y: y
})).x;
var ry = rightDeck.toLocal(game.toGlobal({
x: x,
y: y
})).y;
if (Math.pow(rx - rightDeck.width / 2, 2) + Math.pow(ry - rightDeck.height / 2, 2) < 200 * 200) return rightDeck;
// Crossfader
var cf = crossfader.toLocal(game.toGlobal({
x: x,
y: y
}));
if (cf.x > 0 && cf.x < crossfader.width && cf.y > 0 && cf.y < crossfader.height) return crossfader;
// FX Button
var fx = fxButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(fx.x - fxButton.width / 2, 2) + Math.pow(fx.y - fxButton.height / 2, 2) < 60 * 60) return fxButton;
return null;
}
game.down = function (x, y, obj) {
var control = getTouchedControl(x, y);
dragging = control;
lastTouchObj = obj;
if (control && control.down) {
// Convert to local
var local = control.toLocal(game.toGlobal({
x: x,
y: y
}));
control.down(local.x, local.y, obj);
}
};
game.up = function (x, y, obj) {
if (dragging && dragging.up) {
var local = dragging.toLocal(game.toGlobal({
x: x,
y: y
}));
dragging.up(local.x, local.y, obj);
}
dragging = null;
lastTouchObj = null;
};
game.move = function (x, y, obj) {
if (dragging && dragging.move) {
var local = dragging.toLocal(game.toGlobal({
x: x,
y: y
}));
dragging.move(local.x, local.y, obj);
}
};
// --- Game update ---
game.update = function () {
// Update discoball animation
discoball.update();
// Animate extra white particles (subtle sparkle and movement)
if (extraWhiteParticles) {
var t = Date.now() * 0.001;
for (var i = 0; i < extraWhiteParticles.length; i++) {
var p = extraWhiteParticles[i];
// Subtle float and twinkle
p.obj.x = p.baseX + Math.sin(t * 1.2 + p.phase + i) * 8;
p.obj.y = p.baseY + Math.cos(t * 1.1 + p.phase + i * 0.7) * 6;
p.obj.alpha = p.baseAlpha + 0.10 * Math.sin(t * 2.2 + p.phase + i * 0.5);
var s = p.baseSize * (0.95 + 0.12 * Math.sin(t * 1.7 + p.phase + i));
p.obj.width = s;
p.obj.height = s;
}
}
// Update equalizer animation
equalizer.update();
// Update laser show animation
laserShow.update();
// Update decks
leftDeck.update();
rightDeck.update();
// Simulate beat
var now = Date.now();
beatTimer += now - lastTickTime;
lastTickTime = now;
if (beatTimer >= beatInterval) {
beatTimer -= beatInterval;
leftDeck.flashBeat();
rightDeck.flashBeat();
LK.getSound('beat').play();
// Energy drops if not scratching or mixing
if (!leftDeck.isScratching && !rightDeck.isScratching && crossfader.value > 0.2 && crossfader.value < 0.8) {
energy -= 2;
combo = 0;
} else {
// Combo up if scratching or crossfading
combo += 1;
score += 10 * combo;
energy += 2;
if (energy > 100) energy = 100;
}
if (energy < 0) energy = 0;
// Update visuals
scoreTxt.setText('Score: ' + score);
if (combo > 1) {
comboTxt.setText('Combo x' + combo);
} else {
comboTxt.setText('');
}
}
// Update energy bar
energyBar.width = 600 * (energy / 100);
// Crossfader logic: adjust music volumes
trackAVol = 1 - crossfader.value;
trackBVol = crossfader.value;
// (In a real game, would set music volumes here, but LK handles music globally.)
// End game if energy is 0
if (energy <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
// Win if score is high
if (score >= 5000) {
LK.effects.flashScreen(0x00ff00, 1000);
LK.showYouWin();
}
};
Photorealistic Ferris cabin, sideview
Grey circle with transparent inner place, front view
there are 4 piece of holes in the image, repair it
photorealistic grey Tablet lying down on dj deck, front view. The screen should be dark monocrome screen in power of mode without text.
Photorealistic transparent rectange dj deck sample button with white rounded corners, front view. No text needed on image
Transparent ballon shape.
Replace arrow to OK text
Dancing woman in a white top filled with multi-colored UV ink palm prints. UV luminous bracelet on the arm
Photorealistic dollar, front view
Dancing man in a white shirt filled with multi-colored UV ink palm prints. UV luminous bracelet on the arm
White thin pencil in 45 degrees instead of arrow.
Replace arrow to white X
Change the orange filling color from the middle to black
simple grey colored DJZ logo