/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function (characterData) {
var self = Container.call(this);
self.characterData = characterData;
self.isOnBoard = false;
self.originalPosition = {
x: 0,
y: 0
};
self.boardSlot = null;
self.soundInstance = null;
self.soundTimer = null;
var characterGraphics = self.attachAsset(characterData.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Make character interactive
self.interactive = true;
// Add character name text
var nameText = new Text2(characterData.name, {
size: 45,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = 90;
self.addChild(nameText);
self.playSound = function () {
if (self.soundInstance) {
self.soundInstance.stop();
}
// Clear any existing sound timer
if (self.soundTimer) {
LK.clearInterval(self.soundTimer);
}
// Function to play sound once
function playSoundOnce() {
self.soundInstance = LK.getSound(characterData.soundId);
self.soundInstance.play({
loop: false
}); // Play without looping
}
// Play sound immediately
playSoundOnce();
// Set up timer to play sound every 1.3 seconds
self.soundTimer = LK.setInterval(function () {
playSoundOnce();
}, 1300);
// Visual feedback - bounce animation
tween(characterGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Continuous singing animation
self.singAnimation = LK.setInterval(function () {
// Wobble effect
tween(characterGraphics, {
rotation: 0.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
rotation: -0.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
// Pulsing effect based on sound type
if (characterData.type === 'beat') {
tween(characterGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
} else if (characterData.type === 'voice') {
// Smooth scaling for voice
tween(characterGraphics, {
scaleY: 1.15
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
}, 600);
};
self.stopSound = function () {
if (self.soundInstance) {
self.soundInstance.stop();
self.soundInstance = null;
}
// Clear sound timer
if (self.soundTimer) {
LK.clearInterval(self.soundTimer);
self.soundTimer = null;
}
// Stop singing animation
if (self.singAnimation) {
LK.clearInterval(self.singAnimation);
self.singAnimation = null;
}
// Reset rotation
tween(characterGraphics, {
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
self.returnToOriginalPosition = function () {
tween(self, {
x: self.originalPosition.x,
y: self.originalPosition.y
}, {
duration: 300,
easing: tween.easeOut
});
};
return self;
});
var MixingSlot = Container.expand(function (slotIndex) {
var self = Container.call(this);
self.slotIndex = slotIndex;
self.character = null;
self.isEmpty = true;
var slotGraphics = self.attachAsset('mixing_slot', {
anchorX: 0.5,
anchorY: 0.5
});
self.addCharacter = function (character) {
if (self.character) {
self.removeCharacter();
}
self.character = character;
self.isEmpty = false;
character.isOnBoard = true;
character.boardSlot = self;
// Store the character's parent container
var characterParent = character.parent;
// Check if character is Lily
var isLilyCharacter = character.characterData.name === "Lily";
// Check if character is a horror character (but not Horror Inky)
var isHorrorCharacter = character.characterData.name.indexOf("Horror") !== -1 && character.characterData.name !== "Horror Inky";
// Check if character is Loaf Wenda
var isLoafCharacter = character.characterData.name === "Loaf Wenda";
if (isLilyCharacter) {
// Replace slot graphics with lily version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_lily', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (isHorrorCharacter) {
// Replace slot graphics with horror version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_horror', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (isLoafCharacter) {
// Replace slot graphics with loaf version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_loaf', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Use regular active slot
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Visual feedback - glow effect
tween(slotGraphics, {
tint: 0x888888,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slotGraphics, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Position character directly to slot position (both are in game coordinates)
tween(character, {
x: self.x,
y: self.y - 50
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(character, {
y: self.y
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
character.playSound();
}
});
}
});
};
self.removeCharacter = function () {
if (self.character) {
var characterToRemove = self.character;
self.character.stopSound();
self.character.isOnBoard = false;
self.character.boardSlot = null;
// Animate character up before returning
tween(characterToRemove, {
y: characterToRemove.y - 100,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
characterToRemove.returnToOriginalPosition();
// Reset scale after returning
tween(characterToRemove, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
self.character = null;
}
self.isEmpty = true;
// Reset slot graphics to default mixing slot
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot', {
anchorX: 0.5,
anchorY: 0.5
});
// Fade slot back to normal
tween(slotGraphics, {
tint: 0xFFFFFF,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slotGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
};
self.containsPoint = function (x, y) {
// Use fixed size for slot hit detection
var halfWidth = 90; // Half of slot width
var halfHeight = 90; // Half of slot height
return x >= self.x - halfWidth && x <= self.x + halfWidth && y >= self.y - halfHeight && y <= self.y + halfHeight;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Add background image
var bgImage = game.attachAsset('Bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.27
});
bgImage.x = 2048 / 2;
bgImage.y = 2732 / 2;
// Sound assets for each character
// Character data
// Characters
// Mixing board slots
// Sounds
var characterData = [{
name: "Oren",
assetId: "oren",
soundId: "oren_beat",
type: "beat"
}, {
name: "Horror Oren",
assetId: "horror_oren",
soundId: "horror_oren_beat",
type: "beat"
}, {
name: "Raddy",
assetId: "raddy",
soundId: "raddy_beat",
type: "beat"
}, {
name: "Horror Raddy",
assetId: "horror_raddy",
soundId: "horror_raddy_effect",
type: "effect"
}, {
name: "Wenda",
assetId: "wenda",
soundId: "wenda_voice",
type: "voice"
}, {
name: "Horror Wenda",
assetId: "horror_wenda",
soundId: "horror_wenda_voice",
type: "voice"
}, {
name: "Alt Horror Wenda",
assetId: "alt_horror_wenda",
soundId: "alt_horror_wenda_effect",
type: "effect"
}, {
name: "Jevin",
assetId: "jevin",
soundId: "jevin_voice",
type: "voice"
}, {
name: "Horror Jevin",
assetId: "horror_jevin",
soundId: "horror_jevin_voice",
type: "voice"
}, {
name: "Inky",
assetId: "inky",
soundId: "inky_effect",
type: "effect"
}, {
name: "Horror Inky",
assetId: "horror_inky",
soundId: "horror_inky_effect",
type: "effect"
}, {
//{3r_new}
name: "Alt Horror Jevin",
assetId: "alt_horror_jevin",
soundId: "alt_horror_jevin_voice",
type: "voice" //{3s_new}
}, {
name: "Cool Guy",
assetId: "Cool_Guy",
soundId: "Cool_Guy_voice",
type: "voice"
}, {
name: "Horror Cool Guy",
assetId: "horror_cool_guy",
soundId: "horror_cool_guy_voice",
type: "voice"
}, {
//{3O_new}
name: "Lily",
assetId: "lily",
soundId: "lily_voice",
type: "voice" //{3P_new}
}, {
name: "Horror Lily",
assetId: "horror_lily",
soundId: "horror_lily_voice",
type: "voice"
}, {
name: "Loaf Wenda",
assetId: "Loaf_wenda",
soundId: "loaf_wenda_voice",
type: "voice"
}];
// Game elements
var characters = [];
var mixingSlots = [];
var draggedCharacter = null;
var dragOffset = {
x: 0,
//{3t_new}
y: 0 //{3u_new}
}; //{3v_new}
// Title
var titleText = new Text2("Sprunki Beat Mixer", {
size: 120,
fill: 0xFFFFFF //{3w_new}
}); //{3x_new}
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 100;
game.addChild(titleText);
// Title dance animation
LK.setInterval(function () {
// Bounce effect
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1,
y: 80
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0,
y: 100
}, {
duration: 400,
easing: tween.bounceOut
});
}
});
// Color pulse effect
tween(titleText, {
tint: 0x00ff88
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
tint: 0xffffff
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
}, 1200);
// Subtle rotation wobble
LK.setInterval(function () {
tween(titleText, {
rotation: 0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
rotation: -0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
}, 1800);
// Create mixing board slots
var slotStartX = 2048 / 2 - 5 * 300 / 2;
var slotY = 800;
for (var i = 0; i < 5; i++) {
var slot = new MixingSlot(i);
slot.x = slotStartX + i * 300;
slot.y = slotY;
mixingSlots.push(slot);
game.addChild(slot);
} //{3y_new}
// Create characters
var charactersPerRow = 5;
var characterStartX = 2048 / 2 - charactersPerRow * 300 / 2;
var characterStartY = 1660;
for (var i = 0; i < characterData.length; i++) {
var character = new Character(characterData[i]);
var row = Math.floor(i / charactersPerRow);
var col = i % charactersPerRow;
character.x = characterStartX + col * 300;
character.y = characterStartY + row * 300;
character.originalPosition.x = character.x;
character.originalPosition.y = character.y;
characters.push(character);
game.addChild(character);
// Start continuous dance animation for all characters
var characterGraphics = character.children[0]; // Get the attached asset
(function (charGraphics, charData) {
LK.setInterval(function () {
// Wobble effect
tween(charGraphics, {
rotation: 0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
rotation: -0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
// Pulsing effect based on sound type
if (charData.type === 'beat') {
tween(charGraphics, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(charGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
} else if (charData.type === 'voice') {
// Smooth scaling for voice
tween(charGraphics, {
scaleY: 1.1
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
}, 600);
})(characterGraphics, character.characterData);
} //{3z_new}
// Slot alternation timer - only Horror Lily alternates between horror/lily slots every second
var slotAlternationState = false;
LK.setInterval(function () {
slotAlternationState = !slotAlternationState;
for (var i = 0; i < mixingSlots.length; i++) {
var slot = mixingSlots[i];
if (slot.character) {
// Only Horror Lily should alternate between horror and lily slots
var isHorrorLily = slot.character.characterData.name === "Horror Lily";
var isLily = slot.character.characterData.name === "Lily";
if (isHorrorLily) {
var currentSlotGraphics = slot.children[0];
slot.removeChild(currentSlotGraphics);
var newAssetId;
if (slotAlternationState) {
newAssetId = 'mixing_slot_active_horror';
} else {
newAssetId = 'mixing_slot_active_lily';
}
var newSlotGraphics = slot.attachAsset(newAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
} else if (!isLily) {
// Spin other mixing slots (not lily, not alternating horror lily)
var slotGraphics = slot.children[0];
tween(slotGraphics, {
rotation: slotGraphics.rotation + Math.PI * 2
}, {
duration: 1000,
easing: tween.linear
});
}
} else {
// Spin empty slots
var slotGraphics = slot.children[0];
tween(slotGraphics, {
rotation: slotGraphics.rotation + Math.PI * 2
}, {
duration: 1000,
easing: tween.linear
});
}
}
}, 1000);
// Instructions
var instructionText = new Text2("Drag characters to mixing slots to create beats!", {
size: 60,
fill: 0xFFFFFF //{3A_new}
}); //{3B_new}
instructionText.anchor.set(0.5, 0);
instructionText.x = 2048 / 2;
instructionText.y = 1200;
game.addChild(instructionText);
// Helper functions
function getCharacterAt(x, y) {
for (var i = characters.length - 1; i >= 0; i--) {
var character = characters[i];
// Use character position and asset dimensions for hit detection
var characterAsset = character.children[0]; // The attached asset
if (characterAsset) {
var halfWidth = characterAsset.width / 2;
var halfHeight = characterAsset.height / 2;
if (x >= character.x - halfWidth && x <= character.x + halfWidth && y >= character.y - halfHeight && y <= character.y + halfHeight) {
return character;
}
}
}
return null;
}
function getMixingSlotAt(x, y) {
for (var i = 0; i < mixingSlots.length; i++) {
if (mixingSlots[i].containsPoint(x, y)) {
return mixingSlots[i];
}
}
return null;
}
// Event handlers
game.down = function (x, y, obj) {
// Check if we're tapping on a character first (prioritize character interaction)
var character = getCharacterAt(x, y);
if (character) {
// If character is on board, only allow tap to remove (no dragging)
if (character.isOnBoard && character.boardSlot) {
// Remove character from slot with a single tap
character.boardSlot.removeCharacter();
return;
}
// If character is not on board, start dragging
if (!character.isOnBoard) {
draggedCharacter = character;
dragOffset.x = x - character.x;
dragOffset.y = y - character.y;
// Bring to front - store parent reference before removing
var parentContainer = character.parent;
parentContainer.removeChild(character);
parentContainer.addChild(character);
// Visual feedback
tween(character, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
return;
}
}
// If no character found, check if we're tapping on a slot with a character
var slot = getMixingSlotAt(x, y);
if (slot && !slot.isEmpty) {
// Remove character from slot with a single tap
slot.removeCharacter();
return;
}
};
game.move = function (x, y, obj) {
if (draggedCharacter && draggedCharacter.parent) {
// Ensure the dragged character follows the cursor smoothly
draggedCharacter.x = x - dragOffset.x;
draggedCharacter.y = y - dragOffset.y;
// Highlight slot when hovering
var hoverSlot = getMixingSlotAt(x, y);
for (var i = 0; i < mixingSlots.length; i++) {
var slot = mixingSlots[i];
if (slot === hoverSlot && slot.isEmpty) {
tween(slot, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
} else {
tween(slot, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
}
} else if (!draggedCharacter) {
// Hover effect for characters only when not dragging
var hoverCharacter = getCharacterAt(x, y);
for (var i = 0; i < characters.length; i++) {
var character = characters[i];
if (character === hoverCharacter && !character.isOnBoard) {
tween(character, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
easing: tween.easeOut
});
} else if (!character.isOnBoard) {
tween(character, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
}
}
};
game.up = function (x, y, obj) {
if (draggedCharacter) {
var slot = getMixingSlotAt(x, y);
// Check if we're dropping on an empty slot
if (slot && slot.isEmpty) {
slot.addCharacter(draggedCharacter);
} else if (slot && !slot.isEmpty) {
// Handle swapping characters between slots
var swapCharacter = slot.character;
// Remove character from slot
slot.removeCharacter();
// Add dragged character to slot
slot.addCharacter(draggedCharacter);
// Return swapped character to original position
if (swapCharacter) swapCharacter.returnToOriginalPosition();
} else {
// Return to original position if not dropped on a valid slot
draggedCharacter.returnToOriginalPosition();
}
// Reset scale
tween(draggedCharacter, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
draggedCharacter = null;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function (characterData) {
var self = Container.call(this);
self.characterData = characterData;
self.isOnBoard = false;
self.originalPosition = {
x: 0,
y: 0
};
self.boardSlot = null;
self.soundInstance = null;
self.soundTimer = null;
var characterGraphics = self.attachAsset(characterData.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Make character interactive
self.interactive = true;
// Add character name text
var nameText = new Text2(characterData.name, {
size: 45,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = 90;
self.addChild(nameText);
self.playSound = function () {
if (self.soundInstance) {
self.soundInstance.stop();
}
// Clear any existing sound timer
if (self.soundTimer) {
LK.clearInterval(self.soundTimer);
}
// Function to play sound once
function playSoundOnce() {
self.soundInstance = LK.getSound(characterData.soundId);
self.soundInstance.play({
loop: false
}); // Play without looping
}
// Play sound immediately
playSoundOnce();
// Set up timer to play sound every 1.3 seconds
self.soundTimer = LK.setInterval(function () {
playSoundOnce();
}, 1300);
// Visual feedback - bounce animation
tween(characterGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Continuous singing animation
self.singAnimation = LK.setInterval(function () {
// Wobble effect
tween(characterGraphics, {
rotation: 0.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
rotation: -0.1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
// Pulsing effect based on sound type
if (characterData.type === 'beat') {
tween(characterGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
} else if (characterData.type === 'voice') {
// Smooth scaling for voice
tween(characterGraphics, {
scaleY: 1.15
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(characterGraphics, {
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
}, 600);
};
self.stopSound = function () {
if (self.soundInstance) {
self.soundInstance.stop();
self.soundInstance = null;
}
// Clear sound timer
if (self.soundTimer) {
LK.clearInterval(self.soundTimer);
self.soundTimer = null;
}
// Stop singing animation
if (self.singAnimation) {
LK.clearInterval(self.singAnimation);
self.singAnimation = null;
}
// Reset rotation
tween(characterGraphics, {
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
self.returnToOriginalPosition = function () {
tween(self, {
x: self.originalPosition.x,
y: self.originalPosition.y
}, {
duration: 300,
easing: tween.easeOut
});
};
return self;
});
var MixingSlot = Container.expand(function (slotIndex) {
var self = Container.call(this);
self.slotIndex = slotIndex;
self.character = null;
self.isEmpty = true;
var slotGraphics = self.attachAsset('mixing_slot', {
anchorX: 0.5,
anchorY: 0.5
});
self.addCharacter = function (character) {
if (self.character) {
self.removeCharacter();
}
self.character = character;
self.isEmpty = false;
character.isOnBoard = true;
character.boardSlot = self;
// Store the character's parent container
var characterParent = character.parent;
// Check if character is Lily
var isLilyCharacter = character.characterData.name === "Lily";
// Check if character is a horror character (but not Horror Inky)
var isHorrorCharacter = character.characterData.name.indexOf("Horror") !== -1 && character.characterData.name !== "Horror Inky";
// Check if character is Loaf Wenda
var isLoafCharacter = character.characterData.name === "Loaf Wenda";
if (isLilyCharacter) {
// Replace slot graphics with lily version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_lily', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (isHorrorCharacter) {
// Replace slot graphics with horror version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_horror', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (isLoafCharacter) {
// Replace slot graphics with loaf version
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active_loaf', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Use regular active slot
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot_active', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Visual feedback - glow effect
tween(slotGraphics, {
tint: 0x888888,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slotGraphics, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Position character directly to slot position (both are in game coordinates)
tween(character, {
x: self.x,
y: self.y - 50
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(character, {
y: self.y
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
character.playSound();
}
});
}
});
};
self.removeCharacter = function () {
if (self.character) {
var characterToRemove = self.character;
self.character.stopSound();
self.character.isOnBoard = false;
self.character.boardSlot = null;
// Animate character up before returning
tween(characterToRemove, {
y: characterToRemove.y - 100,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
characterToRemove.returnToOriginalPosition();
// Reset scale after returning
tween(characterToRemove, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
self.character = null;
}
self.isEmpty = true;
// Reset slot graphics to default mixing slot
self.removeChild(slotGraphics);
slotGraphics = self.attachAsset('mixing_slot', {
anchorX: 0.5,
anchorY: 0.5
});
// Fade slot back to normal
tween(slotGraphics, {
tint: 0xFFFFFF,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(slotGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
};
self.containsPoint = function (x, y) {
// Use fixed size for slot hit detection
var halfWidth = 90; // Half of slot width
var halfHeight = 90; // Half of slot height
return x >= self.x - halfWidth && x <= self.x + halfWidth && y >= self.y - halfHeight && y <= self.y + halfHeight;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Add background image
var bgImage = game.attachAsset('Bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.27
});
bgImage.x = 2048 / 2;
bgImage.y = 2732 / 2;
// Sound assets for each character
// Character data
// Characters
// Mixing board slots
// Sounds
var characterData = [{
name: "Oren",
assetId: "oren",
soundId: "oren_beat",
type: "beat"
}, {
name: "Horror Oren",
assetId: "horror_oren",
soundId: "horror_oren_beat",
type: "beat"
}, {
name: "Raddy",
assetId: "raddy",
soundId: "raddy_beat",
type: "beat"
}, {
name: "Horror Raddy",
assetId: "horror_raddy",
soundId: "horror_raddy_effect",
type: "effect"
}, {
name: "Wenda",
assetId: "wenda",
soundId: "wenda_voice",
type: "voice"
}, {
name: "Horror Wenda",
assetId: "horror_wenda",
soundId: "horror_wenda_voice",
type: "voice"
}, {
name: "Alt Horror Wenda",
assetId: "alt_horror_wenda",
soundId: "alt_horror_wenda_effect",
type: "effect"
}, {
name: "Jevin",
assetId: "jevin",
soundId: "jevin_voice",
type: "voice"
}, {
name: "Horror Jevin",
assetId: "horror_jevin",
soundId: "horror_jevin_voice",
type: "voice"
}, {
name: "Inky",
assetId: "inky",
soundId: "inky_effect",
type: "effect"
}, {
name: "Horror Inky",
assetId: "horror_inky",
soundId: "horror_inky_effect",
type: "effect"
}, {
//{3r_new}
name: "Alt Horror Jevin",
assetId: "alt_horror_jevin",
soundId: "alt_horror_jevin_voice",
type: "voice" //{3s_new}
}, {
name: "Cool Guy",
assetId: "Cool_Guy",
soundId: "Cool_Guy_voice",
type: "voice"
}, {
name: "Horror Cool Guy",
assetId: "horror_cool_guy",
soundId: "horror_cool_guy_voice",
type: "voice"
}, {
//{3O_new}
name: "Lily",
assetId: "lily",
soundId: "lily_voice",
type: "voice" //{3P_new}
}, {
name: "Horror Lily",
assetId: "horror_lily",
soundId: "horror_lily_voice",
type: "voice"
}, {
name: "Loaf Wenda",
assetId: "Loaf_wenda",
soundId: "loaf_wenda_voice",
type: "voice"
}];
// Game elements
var characters = [];
var mixingSlots = [];
var draggedCharacter = null;
var dragOffset = {
x: 0,
//{3t_new}
y: 0 //{3u_new}
}; //{3v_new}
// Title
var titleText = new Text2("Sprunki Beat Mixer", {
size: 120,
fill: 0xFFFFFF //{3w_new}
}); //{3x_new}
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 100;
game.addChild(titleText);
// Title dance animation
LK.setInterval(function () {
// Bounce effect
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1,
y: 80
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0,
y: 100
}, {
duration: 400,
easing: tween.bounceOut
});
}
});
// Color pulse effect
tween(titleText, {
tint: 0x00ff88
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
tint: 0xffffff
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
}, 1200);
// Subtle rotation wobble
LK.setInterval(function () {
tween(titleText, {
rotation: 0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
rotation: -0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
}, 1800);
// Create mixing board slots
var slotStartX = 2048 / 2 - 5 * 300 / 2;
var slotY = 800;
for (var i = 0; i < 5; i++) {
var slot = new MixingSlot(i);
slot.x = slotStartX + i * 300;
slot.y = slotY;
mixingSlots.push(slot);
game.addChild(slot);
} //{3y_new}
// Create characters
var charactersPerRow = 5;
var characterStartX = 2048 / 2 - charactersPerRow * 300 / 2;
var characterStartY = 1660;
for (var i = 0; i < characterData.length; i++) {
var character = new Character(characterData[i]);
var row = Math.floor(i / charactersPerRow);
var col = i % charactersPerRow;
character.x = characterStartX + col * 300;
character.y = characterStartY + row * 300;
character.originalPosition.x = character.x;
character.originalPosition.y = character.y;
characters.push(character);
game.addChild(character);
// Start continuous dance animation for all characters
var characterGraphics = character.children[0]; // Get the attached asset
(function (charGraphics, charData) {
LK.setInterval(function () {
// Wobble effect
tween(charGraphics, {
rotation: 0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
rotation: -0.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
});
// Pulsing effect based on sound type
if (charData.type === 'beat') {
tween(charGraphics, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(charGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
} else if (charData.type === 'voice') {
// Smooth scaling for voice
tween(charGraphics, {
scaleY: 1.1
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(charGraphics, {
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
}, 600);
})(characterGraphics, character.characterData);
} //{3z_new}
// Slot alternation timer - only Horror Lily alternates between horror/lily slots every second
var slotAlternationState = false;
LK.setInterval(function () {
slotAlternationState = !slotAlternationState;
for (var i = 0; i < mixingSlots.length; i++) {
var slot = mixingSlots[i];
if (slot.character) {
// Only Horror Lily should alternate between horror and lily slots
var isHorrorLily = slot.character.characterData.name === "Horror Lily";
var isLily = slot.character.characterData.name === "Lily";
if (isHorrorLily) {
var currentSlotGraphics = slot.children[0];
slot.removeChild(currentSlotGraphics);
var newAssetId;
if (slotAlternationState) {
newAssetId = 'mixing_slot_active_horror';
} else {
newAssetId = 'mixing_slot_active_lily';
}
var newSlotGraphics = slot.attachAsset(newAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
} else if (!isLily) {
// Spin other mixing slots (not lily, not alternating horror lily)
var slotGraphics = slot.children[0];
tween(slotGraphics, {
rotation: slotGraphics.rotation + Math.PI * 2
}, {
duration: 1000,
easing: tween.linear
});
}
} else {
// Spin empty slots
var slotGraphics = slot.children[0];
tween(slotGraphics, {
rotation: slotGraphics.rotation + Math.PI * 2
}, {
duration: 1000,
easing: tween.linear
});
}
}
}, 1000);
// Instructions
var instructionText = new Text2("Drag characters to mixing slots to create beats!", {
size: 60,
fill: 0xFFFFFF //{3A_new}
}); //{3B_new}
instructionText.anchor.set(0.5, 0);
instructionText.x = 2048 / 2;
instructionText.y = 1200;
game.addChild(instructionText);
// Helper functions
function getCharacterAt(x, y) {
for (var i = characters.length - 1; i >= 0; i--) {
var character = characters[i];
// Use character position and asset dimensions for hit detection
var characterAsset = character.children[0]; // The attached asset
if (characterAsset) {
var halfWidth = characterAsset.width / 2;
var halfHeight = characterAsset.height / 2;
if (x >= character.x - halfWidth && x <= character.x + halfWidth && y >= character.y - halfHeight && y <= character.y + halfHeight) {
return character;
}
}
}
return null;
}
function getMixingSlotAt(x, y) {
for (var i = 0; i < mixingSlots.length; i++) {
if (mixingSlots[i].containsPoint(x, y)) {
return mixingSlots[i];
}
}
return null;
}
// Event handlers
game.down = function (x, y, obj) {
// Check if we're tapping on a character first (prioritize character interaction)
var character = getCharacterAt(x, y);
if (character) {
// If character is on board, only allow tap to remove (no dragging)
if (character.isOnBoard && character.boardSlot) {
// Remove character from slot with a single tap
character.boardSlot.removeCharacter();
return;
}
// If character is not on board, start dragging
if (!character.isOnBoard) {
draggedCharacter = character;
dragOffset.x = x - character.x;
dragOffset.y = y - character.y;
// Bring to front - store parent reference before removing
var parentContainer = character.parent;
parentContainer.removeChild(character);
parentContainer.addChild(character);
// Visual feedback
tween(character, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
return;
}
}
// If no character found, check if we're tapping on a slot with a character
var slot = getMixingSlotAt(x, y);
if (slot && !slot.isEmpty) {
// Remove character from slot with a single tap
slot.removeCharacter();
return;
}
};
game.move = function (x, y, obj) {
if (draggedCharacter && draggedCharacter.parent) {
// Ensure the dragged character follows the cursor smoothly
draggedCharacter.x = x - dragOffset.x;
draggedCharacter.y = y - dragOffset.y;
// Highlight slot when hovering
var hoverSlot = getMixingSlotAt(x, y);
for (var i = 0; i < mixingSlots.length; i++) {
var slot = mixingSlots[i];
if (slot === hoverSlot && slot.isEmpty) {
tween(slot, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
} else {
tween(slot, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
}
} else if (!draggedCharacter) {
// Hover effect for characters only when not dragging
var hoverCharacter = getCharacterAt(x, y);
for (var i = 0; i < characters.length; i++) {
var character = characters[i];
if (character === hoverCharacter && !character.isOnBoard) {
tween(character, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
easing: tween.easeOut
});
} else if (!character.isOnBoard) {
tween(character, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
}
}
};
game.up = function (x, y, obj) {
if (draggedCharacter) {
var slot = getMixingSlotAt(x, y);
// Check if we're dropping on an empty slot
if (slot && slot.isEmpty) {
slot.addCharacter(draggedCharacter);
} else if (slot && !slot.isEmpty) {
// Handle swapping characters between slots
var swapCharacter = slot.character;
// Remove character from slot
slot.removeCharacter();
// Add dragged character to slot
slot.addCharacter(draggedCharacter);
// Return swapped character to original position
if (swapCharacter) swapCharacter.returnToOriginalPosition();
} else {
// Return to original position if not dropped on a valid slot
draggedCharacter.returnToOriginalPosition();
}
// Reset scale
tween(draggedCharacter, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
draggedCharacter = null;
}
};
oren_beat
Sound effect
horror_oren_beat
Sound effect
raddy_beat
Sound effect
horror_raddy_effect
Sound effect
wenda_voice
Sound effect
horror_wenda_voice
Sound effect
alt_horror_wenda_effect
Sound effect
jevin_voice
Sound effect
horror_jevin_voice
Sound effect
inky_effect
Sound effect
alt_horror_jevin_voice
Sound effect
horror_inky_effect
Sound effect
Cool_Guy_voice
Sound effect
horror_cool_guy_voice
Sound effect
lily_voice
Sound effect
horror_lily_voice
Sound effect
loaf_wenda_voice
Sound effect