/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.originalTint = getRandomFluorescentColor();
self.tint = self.originalTint;
self.rotation = Math.PI * 2 * Math.random();
particleGraphics.blendMode = 1;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
var scoreDisplay;
var currentDirection = null;
var swipeStartX = null;
var swipeStartY = null;
var isCorrectSwipe = false;
var canSwipe = true;
// Array to store score particles
var scoreParticles = [];
// Timer variables
var timerParticles = [];
var timerDuration = 5000; // 5 seconds per round in milliseconds
var roundStartTime = 0;
var timerRadius = 150; // Radius of the timer ring around score
// Function to generate bright fluorescent colors
function getRandomFluorescentColor() {
var fluorColors = [0xFF00FF,
// Magenta
0x00FFFF,
// Cyan
0xFFFF00,
// Yellow
0x00FF00,
// Lime
0xFF0080,
// Hot Pink
0x80FF00,
// Chartreuse
0xFF8000,
// Orange
0x00FF80,
// Spring Green
0x8000FF,
// Purple
0xFF0040,
// Rose
0x40FF00,
// Green Yellow
0x00FFBF // Turquoise
];
return fluorColors[Math.floor(Math.random() * fluorColors.length)];
}
// Digit patterns for particles (5x7 grid for each digit)
var digitPatterns = {
'0': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'1': [[0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1]],
'2': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1]],
'3': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'4': [[1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1]],
'5': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'6': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'7': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]],
'8': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'9': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]]
};
function updateScoreDisplay(score) {
// Clear existing score particles
scoreParticles.forEach(function (particle) {
particle.destroy();
});
scoreParticles = [];
var scoreString = score.toString();
var digitSpacing = 80; // Space between digits
var particleSize = 12; // Size of each particle in the digit
var startX = -(scoreString.length - 1) * digitSpacing / 2;
// Create particles for each digit
for (var digitIndex = 0; digitIndex < scoreString.length; digitIndex++) {
var digit = scoreString[digitIndex];
var pattern = digitPatterns[digit];
var digitX = startX + digitIndex * digitSpacing;
// Create particles based on pattern
for (var row = 0; row < pattern.length; row++) {
for (var col = 0; col < pattern[row].length; col++) {
if (pattern[row][col] === 1) {
var particle = scoreContainer.addChild(new Particle());
particle.x = digitX + (col - 2) * particleSize;
particle.y = (row - 3) * particleSize;
particle.scale.set(0.3, 0.3);
particle.tint = 0xFFFFFF; // White color for score
scoreParticles.push(particle);
}
}
}
}
}
// Initialize score display container
var scoreContainer = new Container();
scoreContainer.x = 1024; // Center horizontally
scoreContainer.y = 250; // Position lower to accommodate timer ring
game.addChild(scoreContainer);
// Function to create timer ring
function createTimerRing() {
// Clear existing timer particles
timerParticles.forEach(function (particle) {
particle.destroy();
});
timerParticles = [];
// Create particles in a circle
var particleCount = 60; // Number of particles in the ring
for (var i = 0; i < particleCount; i++) {
// Start from top (-PI/2) and go clockwise
var angle = -Math.PI / 2 + i / particleCount * Math.PI * 2;
var particle = scoreContainer.addChild(new Particle());
// Position in circle around score
particle.x = Math.cos(angle) * timerRadius;
particle.y = Math.sin(angle) * timerRadius;
particle.scale.set(0.2, 0.2);
particle.tint = 0x00FF00; // Start with green
particle.timerIndex = i;
particle.baseAngle = angle;
timerParticles.push(particle);
}
}
// Initialize score display
updateScoreDisplay(0);
// Initialize timer ring
createTimerRing();
for (var i = 0; i < 500; i++) {
var particle = game.addChild(new Particle());
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * 300;
particle.x = 1024 + Math.cos(angle) * radius;
particle.y = 1366 + Math.sin(angle) * radius;
particle.scale.set(4, 4);
// Initialize cloud movement parameters
particle.cloudAngle = angle;
particle.cloudRadius = radius;
particle.cloudSpeed = 0.01 + Math.random() * 0.02;
particle.driftSpeed = 0.5 + Math.random() * 1;
}
// Create letter positions for directional words - centered on screen
var letterPositions = {
UP: [
// U
{
x: 724,
y: 1200
}, {
x: 724,
y: 1300
}, {
x: 724,
y: 1400
}, {
x: 724,
y: 1500
}, {
x: 824,
y: 1500
}, {
x: 924,
y: 1500
}, {
x: 1024,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 1024,
y: 1400
}, {
x: 1024,
y: 1500
},
// P
{
x: 1224,
y: 1200
}, {
x: 1224,
y: 1300
}, {
x: 1224,
y: 1400
}, {
x: 1224,
y: 1500
}, {
x: 1324,
y: 1200
}, {
x: 1424,
y: 1200
}, {
x: 1424,
y: 1300
}, {
x: 1324,
y: 1350
}, {
x: 1424,
y: 1350
}],
DOWN: [
// D
{
x: 324,
y: 1200
}, {
x: 324,
y: 1300
}, {
x: 324,
y: 1400
}, {
x: 324,
y: 1500
}, {
x: 424,
y: 1200
}, {
x: 524,
y: 1250
}, {
x: 524,
y: 1450
}, {
x: 424,
y: 1500
},
// O
{
x: 724,
y: 1250
}, {
x: 724,
y: 1450
}, {
x: 774,
y: 1200
}, {
x: 874,
y: 1200
}, {
x: 924,
y: 1250
}, {
x: 924,
y: 1450
}, {
x: 774,
y: 1500
}, {
x: 874,
y: 1500
},
// W
{
x: 1124,
y: 1200
}, {
x: 1144,
y: 1300
}, {
x: 1164,
y: 1400
}, {
x: 1184,
y: 1500
}, {
x: 1274,
y: 1400
}, {
x: 1364,
y: 1400
}, {
x: 1384,
y: 1500
}, {
x: 1404,
y: 1400
}, {
x: 1424,
y: 1300
}, {
x: 1444,
y: 1200
},
// N
{
x: 1574,
y: 1200
}, {
x: 1574,
y: 1300
}, {
x: 1574,
y: 1400
}, {
x: 1574,
y: 1500
}, {
x: 1644,
y: 1280
}, {
x: 1714,
y: 1360
}, {
x: 1784,
y: 1440
}, {
x: 1854,
y: 1200
}, {
x: 1854,
y: 1300
}, {
x: 1854,
y: 1400
}, {
x: 1854,
y: 1500
}],
LEFT: [
// L
{
x: 424,
y: 1200
}, {
x: 424,
y: 1300
}, {
x: 424,
y: 1400
}, {
x: 424,
y: 1500
}, {
x: 524,
y: 1500
}, {
x: 624,
y: 1500
},
// E
{
x: 824,
y: 1200
}, {
x: 824,
y: 1300
}, {
x: 824,
y: 1400
}, {
x: 824,
y: 1500
}, {
x: 924,
y: 1200
}, {
x: 1024,
y: 1200
}, {
x: 924,
y: 1350
}, {
x: 924,
y: 1500
}, {
x: 1024,
y: 1500
},
// F
{
x: 1224,
y: 1200
}, {
x: 1224,
y: 1300
}, {
x: 1224,
y: 1400
}, {
x: 1224,
y: 1500
}, {
x: 1324,
y: 1200
}, {
x: 1424,
y: 1200
}, {
x: 1324,
y: 1350
},
// T
{
x: 1624,
y: 1200
}, {
x: 1724,
y: 1200
}, {
x: 1824,
y: 1200
}, {
x: 1724,
y: 1300
}, {
x: 1724,
y: 1400
}, {
x: 1724,
y: 1500
}],
RIGHT: [
// Shifted left by 225px to fit on screen
// R
{
x: 49,
// 274 - 225
y: 1200
}, {
x: 49,
// 274 - 225
y: 1300
}, {
x: 49,
// 274 - 225
y: 1400
}, {
x: 49,
// 274 - 225
y: 1500
}, {
x: 149,
// 374 - 225
y: 1200
}, {
x: 249,
// 474 - 225
y: 1200
}, {
x: 249,
// 474 - 225
y: 1300
}, {
x: 149,
// 374 - 225
y: 1350
}, {
x: 249,
// 474 - 225
y: 1400
}, {
x: 349,
// 574 - 225
y: 1500
},
// I
{
x: 549,
// 774 - 225
y: 1200
}, {
x: 649,
// 874 - 225
y: 1200
}, {
x: 749,
// 974 - 225
y: 1200
}, {
x: 649,
// 874 - 225
y: 1300
}, {
x: 649,
// 874 - 225
y: 1400
}, {
x: 549,
// 774 - 225
y: 1500
}, {
x: 649,
// 874 - 225
y: 1500
}, {
x: 749,
// 974 - 225
y: 1500
},
// G
{
x: 949,
// 1174 - 225
y: 1250
}, {
x: 999,
// 1224 - 225
y: 1200
}, {
x: 1099,
// 1324 - 225
y: 1200
}, {
x: 1149,
// 1374 - 225
y: 1200
}, {
x: 949,
// 1174 - 225
y: 1350
}, {
x: 949,
// 1174 - 225
y: 1450
}, {
x: 999,
// 1224 - 225
y: 1500
}, {
x: 1099,
// 1324 - 225
y: 1500
}, {
x: 1149,
// 1374 - 225
y: 1450
}, {
x: 1149,
// 1374 - 225
y: 1400
}, {
x: 1099,
// 1324 - 225
y: 1400
},
// H
{
x: 1349,
// 1574 - 225
y: 1200
}, {
x: 1349,
// 1574 - 225
y: 1300
}, {
x: 1349,
// 1574 - 225
y: 1400
}, {
x: 1349,
// 1574 - 225
y: 1500
}, {
x: 1449,
// 1674 - 225
y: 1350
}, {
x: 1549,
// 1774 - 225
y: 1350
}, {
x: 1649,
// 1874 - 225
y: 1200
}, {
x: 1649,
// 1874 - 225
y: 1300
}, {
x: 1649,
// 1874 - 225
y: 1400
}, {
x: 1649,
// 1874 - 225
y: 1500
},
// T
{
x: 1799,
// 2024 - 225
y: 1200
}, {
x: 1899,
// 2124 - 225
y: 1200
}, {
x: 1999,
// 2224 - 225
y: 1200
}, {
x: 1899,
// 2124 - 225
y: 1300
}, {
x: 1899,
// 2124 - 225
y: 1400
}, {
x: 1899,
// 2124 - 225
y: 1500
}]
};
// NOT letter positions (reusable)
var notLetterPositions = {
// N
0: {
x: 574,
y: 1100
},
1: {
x: 574,
y: 1200
},
2: {
x: 574,
y: 1300
},
3: {
x: 574,
y: 1400
},
4: {
x: 644,
y: 1180
},
5: {
x: 714,
y: 1260
},
6: {
x: 784,
y: 1340
},
7: {
x: 854,
y: 1100
},
8: {
x: 854,
y: 1200
},
9: {
x: 854,
y: 1300
},
10: {
x: 854,
y: 1400
},
// O
11: {
x: 1024,
y: 1150
},
12: {
x: 1024,
y: 1350
},
13: {
x: 1074,
y: 1100
},
14: {
x: 1174,
y: 1100
},
15: {
x: 1224,
y: 1150
},
16: {
x: 1224,
y: 1350
},
17: {
x: 1074,
y: 1400
},
18: {
x: 1174,
y: 1400
},
// T
19: {
x: 1324,
y: 1100
},
20: {
x: 1424,
y: 1100
},
21: {
x: 1524,
y: 1100
},
22: {
x: 1424,
y: 1200
},
23: {
x: 1424,
y: 1300
},
24: {
x: 1424,
y: 1400
}
};
// Function to generate NOT direction positions
function getNotDirectionPositions(direction) {
var positions = [];
// Add NOT letters
for (var i = 0; i < 25; i++) {
positions.push(notLetterPositions[i]);
}
// Add direction letters with y offset
var basePositions = letterPositions[direction];
var yOffset = 300; // Move direction word down
for (var j = 0; j < basePositions.length; j++) {
positions.push({
x: basePositions[j].x,
y: basePositions[j].y + yOffset
});
}
return positions;
}
game.move = function (x, y) {
// Not used for swipe detection, but required by engine
};
game.up = function (x, y) {
if (!canSwipe || swipeStartX === null || swipeStartY === null) return;
var swipeDeltaX = x - swipeStartX;
var swipeDeltaY = y - swipeStartY;
var swipeThreshold = 100;
var detectedDirection = null;
if (Math.abs(swipeDeltaX) > Math.abs(swipeDeltaY)) {
if (swipeDeltaX > swipeThreshold) {
detectedDirection = 'RIGHT';
} else if (swipeDeltaX < -swipeThreshold) {
detectedDirection = 'LEFT';
}
} else {
if (swipeDeltaY > swipeThreshold) {
detectedDirection = 'DOWN';
} else if (swipeDeltaY < -swipeThreshold) {
detectedDirection = 'UP';
}
}
var isCorrect = false;
if (currentDirection.indexOf('NOT ') === 0) {
// For NOT directions, any swipe except the forbidden one is correct
var forbiddenDirection = currentDirection.substring(4); // Remove 'NOT ' prefix
if (detectedDirection !== null && detectedDirection !== forbiddenDirection) {
isCorrect = true;
}
} else {
// For regular directions, must match exactly
isCorrect = detectedDirection === currentDirection;
}
if (isCorrect) {
// Correct swipe!
isCorrectSwipe = true;
LK.setScore(LK.getScore() + 1);
updateScoreDisplay(LK.getScore());
// Flash green for correct
LK.effects.flashScreen(0x00FF00, 300);
// Check win condition
if (LK.getScore() >= 20) {
LK.showYouWin();
return;
}
// Start next round
canSwipe = false;
showNextDirection();
} else if (detectedDirection !== null) {
// Wrong swipe - game over
LK.effects.flashScreen(0xFF0000, 300);
LK.showGameOver();
}
swipeStartX = null;
swipeStartY = null;
};
function showNextDirection() {
// Reset timer for new round
roundStartTime = Date.now();
// Reset timer particles to full visibility
timerParticles.forEach(function (particle) {
particle.alpha = 1;
particle.scale.set(0.2, 0.2);
particle.tint = 0x00FF00; // Reset to green
});
// Choose random direction - include NOT directions
var directions = ['UP', 'DOWN', 'LEFT', 'RIGHT', 'NOT UP', 'NOT DOWN', 'NOT LEFT', 'NOT RIGHT'];
currentDirection = directions[Math.floor(Math.random() * directions.length)];
var directionColors = {
UP: 0xFFFF00,
// Bright Yellow
DOWN: 0x00FFFF,
// Bright Cyan
LEFT: 0x00FF00,
// Bright Green
RIGHT: 0xFF00FF,
// Bright Magenta
'NOT UP': 0xFF4500,
// Orange Red
'NOT DOWN': 0x00CED1,
// Dark Turquoise
'NOT LEFT': 0x32CD32,
// Lime Green
'NOT RIGHT': 0xFF1493 // Deep Pink
};
// Get particles
var particles = [];
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] instanceof Particle) {
particles.push(game.children[i]);
}
}
// Animate particles to scatter first
var scatterDuration = 500;
particles.forEach(function (particle, index) {
var angle = Math.random() * Math.PI * 2;
var radius = 400 + Math.random() * 800;
tween(particle, {
x: 1024 + Math.cos(angle) * radius,
y: 1366 + Math.sin(angle) * radius,
scaleX: 0.5,
scaleY: 0.5,
rotation: Math.random() * Math.PI * 2,
tint: particle.originalTint
}, {
duration: scatterDuration,
easing: tween.easeOut
});
});
// After scatter, form the word
LK.setTimeout(function () {
// Get letter positions for the current direction
var positions;
if (currentDirection.indexOf('NOT ') === 0) {
// For NOT directions, generate combined positions
var baseDirection = currentDirection.substring(4); // Remove 'NOT ' prefix
positions = getNotDirectionPositions(baseDirection);
} else {
// For regular directions, use existing positions
positions = letterPositions[currentDirection].slice();
}
// Clone and shuffle the positions
var shuffledPositions = positions.slice();
for (var i = shuffledPositions.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = shuffledPositions[i];
shuffledPositions[i] = shuffledPositions[j];
shuffledPositions[j] = temp;
}
var tweenFunctions = [tween.easeIn, tween.easeOut, tween.elasticOut, tween.bounceOut, tween.easeInOut];
var randomTweenFunction = tweenFunctions[Math.floor(Math.random() * tweenFunctions.length)];
// Use direction color for the word
var wordColor = directionColors[currentDirection];
particles.forEach(function (particle, index) {
if (index < shuffledPositions.length) {
// Form letter
// Clear cloud parameters so particle is identified as word particle
delete particle.cloudAngle;
delete particle.cloudRadius;
delete particle.cloudSpeed;
delete particle.driftSpeed;
tween(particle, {
x: shuffledPositions[index].x,
y: shuffledPositions[index].y,
scaleX: 1.2,
// Increased scale for better readability
scaleY: 1.2,
// Increased scale for better readability
rotation: 0,
tint: wordColor // Same color for all particles in the word
}, {
duration: 800,
easing: randomTweenFunction,
delay: index * 10
});
} else {
// Extra particles float around in cloud-like motion
var angle = Math.random() * Math.PI * 2;
var radius = 300 + Math.random() * 400;
var targetX = 1024 + Math.cos(angle) * radius;
var targetY = 1366 + Math.sin(angle) * radius;
// Store cloud movement parameters on particle
particle.cloudAngle = angle;
particle.cloudRadius = radius;
particle.cloudSpeed = 0.01 + Math.random() * 0.02;
particle.driftSpeed = 0.5 + Math.random() * 1;
tween(particle, {
x: targetX,
y: targetY,
scaleX: 0.2,
scaleY: 0.2,
rotation: Math.random() * Math.PI * 2,
tint: particle.originalTint
}, {
duration: 1000,
easing: tween.linear
});
}
});
// Enable swiping after animation
LK.setTimeout(function () {
canSwipe = true;
}, 900);
}, scatterDuration + 100);
}
// Add continuous movement for background particles
game.update = function () {
// Move particles that are in cloud formation
for (var i = 0; i < game.children.length; i++) {
var particle = game.children[i];
if (particle instanceof Particle) {
// Check if particle is part of the word (not in cloud formation)
if (particle.cloudAngle === undefined) {
// Add small wiggle to word particles
var wiggleX = Math.sin(Date.now() * 0.003 + i) * 0.5;
var wiggleY = Math.cos(Date.now() * 0.003 + i) * 0.5;
particle.x = particle.x + wiggleX;
particle.y = particle.y + wiggleY;
} else {
// Original cloud movement for background particles
// Update cloud angle for circular drift
particle.cloudAngle += particle.cloudSpeed;
// Calculate new position within cloud shape
var centerX = 1024;
var centerY = 1366;
var cloudX = centerX + Math.cos(particle.cloudAngle) * particle.cloudRadius;
var cloudY = centerY + Math.sin(particle.cloudAngle) * particle.cloudRadius;
// Add some drift movement
var driftX = Math.sin(Date.now() * 0.001 * particle.driftSpeed) * 20;
var driftY = Math.cos(Date.now() * 0.001 * particle.driftSpeed) * 15;
// Apply movement
particle.x = cloudX + driftX;
particle.y = cloudY + driftY;
// Gentle rotation
particle.rotation += 0.01;
}
}
}
// Add wiggle effect to score particles
scoreParticles.forEach(function (particle, index) {
var wiggleX = Math.sin(Date.now() * 0.002 + index * 0.1) * 0.3;
var wiggleY = Math.cos(Date.now() * 0.002 + index * 0.1) * 0.3;
particle.x = particle.x + wiggleX;
particle.y = particle.y + wiggleY;
});
// Update timer ring
if (canSwipe && roundStartTime > 0) {
var elapsedTime = Date.now() - roundStartTime;
var timeRemaining = Math.max(0, timerDuration - elapsedTime);
var progress = timeRemaining / timerDuration;
// Update timer particles
timerParticles.forEach(function (particle, index) {
// Calculate threshold for this particle (inverted so it depletes clockwise from top)
var threshold = 1 - index / timerParticles.length;
if (threshold > progress) {
particle.alpha = 0.1; // Fade out depleted particles
particle.scale.set(0.1, 0.1);
} else {
particle.alpha = 1;
particle.scale.set(0.2, 0.2);
// Change color based on time remaining
if (progress < 0.2) {
particle.tint = 0xFF0000; // Red when low on time
} else if (progress < 0.5) {
particle.tint = 0xFFFF00; // Yellow when half time
} else {
particle.tint = 0x00FF00; // Green when plenty of time
}
// Add pulsing effect when time is low
if (progress < 0.2) {
var pulse = Math.sin(Date.now() * 0.01) * 0.1 + 0.2;
particle.scale.set(pulse, pulse);
}
}
// Add gentle orbital movement
var orbitOffset = Math.sin(Date.now() * 0.001 + index * 0.1) * 5;
particle.x = Math.cos(particle.baseAngle) * (timerRadius + orbitOffset);
particle.y = Math.sin(particle.baseAngle) * (timerRadius + orbitOffset);
});
// Check if time ran out
if (timeRemaining === 0 && canSwipe) {
// Time's up - game over
canSwipe = false;
LK.effects.flashScreen(0xFF0000, 500);
LK.showGameOver();
}
}
};
// Start the first round
showNextDirection();
game.down = function (x, y) {
if (!canSwipe) return;
swipeStartX = x;
swipeStartY = y;
isCorrectSwipe = false;
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.originalTint = getRandomFluorescentColor();
self.tint = self.originalTint;
self.rotation = Math.PI * 2 * Math.random();
particleGraphics.blendMode = 1;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
var scoreDisplay;
var currentDirection = null;
var swipeStartX = null;
var swipeStartY = null;
var isCorrectSwipe = false;
var canSwipe = true;
// Array to store score particles
var scoreParticles = [];
// Timer variables
var timerParticles = [];
var timerDuration = 5000; // 5 seconds per round in milliseconds
var roundStartTime = 0;
var timerRadius = 150; // Radius of the timer ring around score
// Function to generate bright fluorescent colors
function getRandomFluorescentColor() {
var fluorColors = [0xFF00FF,
// Magenta
0x00FFFF,
// Cyan
0xFFFF00,
// Yellow
0x00FF00,
// Lime
0xFF0080,
// Hot Pink
0x80FF00,
// Chartreuse
0xFF8000,
// Orange
0x00FF80,
// Spring Green
0x8000FF,
// Purple
0xFF0040,
// Rose
0x40FF00,
// Green Yellow
0x00FFBF // Turquoise
];
return fluorColors[Math.floor(Math.random() * fluorColors.length)];
}
// Digit patterns for particles (5x7 grid for each digit)
var digitPatterns = {
'0': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'1': [[0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1]],
'2': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1]],
'3': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'4': [[1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1]],
'5': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'6': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'7': [[1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]],
'8': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]],
'9': [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [1, 1, 1, 1, 1]]
};
function updateScoreDisplay(score) {
// Clear existing score particles
scoreParticles.forEach(function (particle) {
particle.destroy();
});
scoreParticles = [];
var scoreString = score.toString();
var digitSpacing = 80; // Space between digits
var particleSize = 12; // Size of each particle in the digit
var startX = -(scoreString.length - 1) * digitSpacing / 2;
// Create particles for each digit
for (var digitIndex = 0; digitIndex < scoreString.length; digitIndex++) {
var digit = scoreString[digitIndex];
var pattern = digitPatterns[digit];
var digitX = startX + digitIndex * digitSpacing;
// Create particles based on pattern
for (var row = 0; row < pattern.length; row++) {
for (var col = 0; col < pattern[row].length; col++) {
if (pattern[row][col] === 1) {
var particle = scoreContainer.addChild(new Particle());
particle.x = digitX + (col - 2) * particleSize;
particle.y = (row - 3) * particleSize;
particle.scale.set(0.3, 0.3);
particle.tint = 0xFFFFFF; // White color for score
scoreParticles.push(particle);
}
}
}
}
}
// Initialize score display container
var scoreContainer = new Container();
scoreContainer.x = 1024; // Center horizontally
scoreContainer.y = 250; // Position lower to accommodate timer ring
game.addChild(scoreContainer);
// Function to create timer ring
function createTimerRing() {
// Clear existing timer particles
timerParticles.forEach(function (particle) {
particle.destroy();
});
timerParticles = [];
// Create particles in a circle
var particleCount = 60; // Number of particles in the ring
for (var i = 0; i < particleCount; i++) {
// Start from top (-PI/2) and go clockwise
var angle = -Math.PI / 2 + i / particleCount * Math.PI * 2;
var particle = scoreContainer.addChild(new Particle());
// Position in circle around score
particle.x = Math.cos(angle) * timerRadius;
particle.y = Math.sin(angle) * timerRadius;
particle.scale.set(0.2, 0.2);
particle.tint = 0x00FF00; // Start with green
particle.timerIndex = i;
particle.baseAngle = angle;
timerParticles.push(particle);
}
}
// Initialize score display
updateScoreDisplay(0);
// Initialize timer ring
createTimerRing();
for (var i = 0; i < 500; i++) {
var particle = game.addChild(new Particle());
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * 300;
particle.x = 1024 + Math.cos(angle) * radius;
particle.y = 1366 + Math.sin(angle) * radius;
particle.scale.set(4, 4);
// Initialize cloud movement parameters
particle.cloudAngle = angle;
particle.cloudRadius = radius;
particle.cloudSpeed = 0.01 + Math.random() * 0.02;
particle.driftSpeed = 0.5 + Math.random() * 1;
}
// Create letter positions for directional words - centered on screen
var letterPositions = {
UP: [
// U
{
x: 724,
y: 1200
}, {
x: 724,
y: 1300
}, {
x: 724,
y: 1400
}, {
x: 724,
y: 1500
}, {
x: 824,
y: 1500
}, {
x: 924,
y: 1500
}, {
x: 1024,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 1024,
y: 1400
}, {
x: 1024,
y: 1500
},
// P
{
x: 1224,
y: 1200
}, {
x: 1224,
y: 1300
}, {
x: 1224,
y: 1400
}, {
x: 1224,
y: 1500
}, {
x: 1324,
y: 1200
}, {
x: 1424,
y: 1200
}, {
x: 1424,
y: 1300
}, {
x: 1324,
y: 1350
}, {
x: 1424,
y: 1350
}],
DOWN: [
// D
{
x: 324,
y: 1200
}, {
x: 324,
y: 1300
}, {
x: 324,
y: 1400
}, {
x: 324,
y: 1500
}, {
x: 424,
y: 1200
}, {
x: 524,
y: 1250
}, {
x: 524,
y: 1450
}, {
x: 424,
y: 1500
},
// O
{
x: 724,
y: 1250
}, {
x: 724,
y: 1450
}, {
x: 774,
y: 1200
}, {
x: 874,
y: 1200
}, {
x: 924,
y: 1250
}, {
x: 924,
y: 1450
}, {
x: 774,
y: 1500
}, {
x: 874,
y: 1500
},
// W
{
x: 1124,
y: 1200
}, {
x: 1144,
y: 1300
}, {
x: 1164,
y: 1400
}, {
x: 1184,
y: 1500
}, {
x: 1274,
y: 1400
}, {
x: 1364,
y: 1400
}, {
x: 1384,
y: 1500
}, {
x: 1404,
y: 1400
}, {
x: 1424,
y: 1300
}, {
x: 1444,
y: 1200
},
// N
{
x: 1574,
y: 1200
}, {
x: 1574,
y: 1300
}, {
x: 1574,
y: 1400
}, {
x: 1574,
y: 1500
}, {
x: 1644,
y: 1280
}, {
x: 1714,
y: 1360
}, {
x: 1784,
y: 1440
}, {
x: 1854,
y: 1200
}, {
x: 1854,
y: 1300
}, {
x: 1854,
y: 1400
}, {
x: 1854,
y: 1500
}],
LEFT: [
// L
{
x: 424,
y: 1200
}, {
x: 424,
y: 1300
}, {
x: 424,
y: 1400
}, {
x: 424,
y: 1500
}, {
x: 524,
y: 1500
}, {
x: 624,
y: 1500
},
// E
{
x: 824,
y: 1200
}, {
x: 824,
y: 1300
}, {
x: 824,
y: 1400
}, {
x: 824,
y: 1500
}, {
x: 924,
y: 1200
}, {
x: 1024,
y: 1200
}, {
x: 924,
y: 1350
}, {
x: 924,
y: 1500
}, {
x: 1024,
y: 1500
},
// F
{
x: 1224,
y: 1200
}, {
x: 1224,
y: 1300
}, {
x: 1224,
y: 1400
}, {
x: 1224,
y: 1500
}, {
x: 1324,
y: 1200
}, {
x: 1424,
y: 1200
}, {
x: 1324,
y: 1350
},
// T
{
x: 1624,
y: 1200
}, {
x: 1724,
y: 1200
}, {
x: 1824,
y: 1200
}, {
x: 1724,
y: 1300
}, {
x: 1724,
y: 1400
}, {
x: 1724,
y: 1500
}],
RIGHT: [
// Shifted left by 225px to fit on screen
// R
{
x: 49,
// 274 - 225
y: 1200
}, {
x: 49,
// 274 - 225
y: 1300
}, {
x: 49,
// 274 - 225
y: 1400
}, {
x: 49,
// 274 - 225
y: 1500
}, {
x: 149,
// 374 - 225
y: 1200
}, {
x: 249,
// 474 - 225
y: 1200
}, {
x: 249,
// 474 - 225
y: 1300
}, {
x: 149,
// 374 - 225
y: 1350
}, {
x: 249,
// 474 - 225
y: 1400
}, {
x: 349,
// 574 - 225
y: 1500
},
// I
{
x: 549,
// 774 - 225
y: 1200
}, {
x: 649,
// 874 - 225
y: 1200
}, {
x: 749,
// 974 - 225
y: 1200
}, {
x: 649,
// 874 - 225
y: 1300
}, {
x: 649,
// 874 - 225
y: 1400
}, {
x: 549,
// 774 - 225
y: 1500
}, {
x: 649,
// 874 - 225
y: 1500
}, {
x: 749,
// 974 - 225
y: 1500
},
// G
{
x: 949,
// 1174 - 225
y: 1250
}, {
x: 999,
// 1224 - 225
y: 1200
}, {
x: 1099,
// 1324 - 225
y: 1200
}, {
x: 1149,
// 1374 - 225
y: 1200
}, {
x: 949,
// 1174 - 225
y: 1350
}, {
x: 949,
// 1174 - 225
y: 1450
}, {
x: 999,
// 1224 - 225
y: 1500
}, {
x: 1099,
// 1324 - 225
y: 1500
}, {
x: 1149,
// 1374 - 225
y: 1450
}, {
x: 1149,
// 1374 - 225
y: 1400
}, {
x: 1099,
// 1324 - 225
y: 1400
},
// H
{
x: 1349,
// 1574 - 225
y: 1200
}, {
x: 1349,
// 1574 - 225
y: 1300
}, {
x: 1349,
// 1574 - 225
y: 1400
}, {
x: 1349,
// 1574 - 225
y: 1500
}, {
x: 1449,
// 1674 - 225
y: 1350
}, {
x: 1549,
// 1774 - 225
y: 1350
}, {
x: 1649,
// 1874 - 225
y: 1200
}, {
x: 1649,
// 1874 - 225
y: 1300
}, {
x: 1649,
// 1874 - 225
y: 1400
}, {
x: 1649,
// 1874 - 225
y: 1500
},
// T
{
x: 1799,
// 2024 - 225
y: 1200
}, {
x: 1899,
// 2124 - 225
y: 1200
}, {
x: 1999,
// 2224 - 225
y: 1200
}, {
x: 1899,
// 2124 - 225
y: 1300
}, {
x: 1899,
// 2124 - 225
y: 1400
}, {
x: 1899,
// 2124 - 225
y: 1500
}]
};
// NOT letter positions (reusable)
var notLetterPositions = {
// N
0: {
x: 574,
y: 1100
},
1: {
x: 574,
y: 1200
},
2: {
x: 574,
y: 1300
},
3: {
x: 574,
y: 1400
},
4: {
x: 644,
y: 1180
},
5: {
x: 714,
y: 1260
},
6: {
x: 784,
y: 1340
},
7: {
x: 854,
y: 1100
},
8: {
x: 854,
y: 1200
},
9: {
x: 854,
y: 1300
},
10: {
x: 854,
y: 1400
},
// O
11: {
x: 1024,
y: 1150
},
12: {
x: 1024,
y: 1350
},
13: {
x: 1074,
y: 1100
},
14: {
x: 1174,
y: 1100
},
15: {
x: 1224,
y: 1150
},
16: {
x: 1224,
y: 1350
},
17: {
x: 1074,
y: 1400
},
18: {
x: 1174,
y: 1400
},
// T
19: {
x: 1324,
y: 1100
},
20: {
x: 1424,
y: 1100
},
21: {
x: 1524,
y: 1100
},
22: {
x: 1424,
y: 1200
},
23: {
x: 1424,
y: 1300
},
24: {
x: 1424,
y: 1400
}
};
// Function to generate NOT direction positions
function getNotDirectionPositions(direction) {
var positions = [];
// Add NOT letters
for (var i = 0; i < 25; i++) {
positions.push(notLetterPositions[i]);
}
// Add direction letters with y offset
var basePositions = letterPositions[direction];
var yOffset = 300; // Move direction word down
for (var j = 0; j < basePositions.length; j++) {
positions.push({
x: basePositions[j].x,
y: basePositions[j].y + yOffset
});
}
return positions;
}
game.move = function (x, y) {
// Not used for swipe detection, but required by engine
};
game.up = function (x, y) {
if (!canSwipe || swipeStartX === null || swipeStartY === null) return;
var swipeDeltaX = x - swipeStartX;
var swipeDeltaY = y - swipeStartY;
var swipeThreshold = 100;
var detectedDirection = null;
if (Math.abs(swipeDeltaX) > Math.abs(swipeDeltaY)) {
if (swipeDeltaX > swipeThreshold) {
detectedDirection = 'RIGHT';
} else if (swipeDeltaX < -swipeThreshold) {
detectedDirection = 'LEFT';
}
} else {
if (swipeDeltaY > swipeThreshold) {
detectedDirection = 'DOWN';
} else if (swipeDeltaY < -swipeThreshold) {
detectedDirection = 'UP';
}
}
var isCorrect = false;
if (currentDirection.indexOf('NOT ') === 0) {
// For NOT directions, any swipe except the forbidden one is correct
var forbiddenDirection = currentDirection.substring(4); // Remove 'NOT ' prefix
if (detectedDirection !== null && detectedDirection !== forbiddenDirection) {
isCorrect = true;
}
} else {
// For regular directions, must match exactly
isCorrect = detectedDirection === currentDirection;
}
if (isCorrect) {
// Correct swipe!
isCorrectSwipe = true;
LK.setScore(LK.getScore() + 1);
updateScoreDisplay(LK.getScore());
// Flash green for correct
LK.effects.flashScreen(0x00FF00, 300);
// Check win condition
if (LK.getScore() >= 20) {
LK.showYouWin();
return;
}
// Start next round
canSwipe = false;
showNextDirection();
} else if (detectedDirection !== null) {
// Wrong swipe - game over
LK.effects.flashScreen(0xFF0000, 300);
LK.showGameOver();
}
swipeStartX = null;
swipeStartY = null;
};
function showNextDirection() {
// Reset timer for new round
roundStartTime = Date.now();
// Reset timer particles to full visibility
timerParticles.forEach(function (particle) {
particle.alpha = 1;
particle.scale.set(0.2, 0.2);
particle.tint = 0x00FF00; // Reset to green
});
// Choose random direction - include NOT directions
var directions = ['UP', 'DOWN', 'LEFT', 'RIGHT', 'NOT UP', 'NOT DOWN', 'NOT LEFT', 'NOT RIGHT'];
currentDirection = directions[Math.floor(Math.random() * directions.length)];
var directionColors = {
UP: 0xFFFF00,
// Bright Yellow
DOWN: 0x00FFFF,
// Bright Cyan
LEFT: 0x00FF00,
// Bright Green
RIGHT: 0xFF00FF,
// Bright Magenta
'NOT UP': 0xFF4500,
// Orange Red
'NOT DOWN': 0x00CED1,
// Dark Turquoise
'NOT LEFT': 0x32CD32,
// Lime Green
'NOT RIGHT': 0xFF1493 // Deep Pink
};
// Get particles
var particles = [];
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] instanceof Particle) {
particles.push(game.children[i]);
}
}
// Animate particles to scatter first
var scatterDuration = 500;
particles.forEach(function (particle, index) {
var angle = Math.random() * Math.PI * 2;
var radius = 400 + Math.random() * 800;
tween(particle, {
x: 1024 + Math.cos(angle) * radius,
y: 1366 + Math.sin(angle) * radius,
scaleX: 0.5,
scaleY: 0.5,
rotation: Math.random() * Math.PI * 2,
tint: particle.originalTint
}, {
duration: scatterDuration,
easing: tween.easeOut
});
});
// After scatter, form the word
LK.setTimeout(function () {
// Get letter positions for the current direction
var positions;
if (currentDirection.indexOf('NOT ') === 0) {
// For NOT directions, generate combined positions
var baseDirection = currentDirection.substring(4); // Remove 'NOT ' prefix
positions = getNotDirectionPositions(baseDirection);
} else {
// For regular directions, use existing positions
positions = letterPositions[currentDirection].slice();
}
// Clone and shuffle the positions
var shuffledPositions = positions.slice();
for (var i = shuffledPositions.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = shuffledPositions[i];
shuffledPositions[i] = shuffledPositions[j];
shuffledPositions[j] = temp;
}
var tweenFunctions = [tween.easeIn, tween.easeOut, tween.elasticOut, tween.bounceOut, tween.easeInOut];
var randomTweenFunction = tweenFunctions[Math.floor(Math.random() * tweenFunctions.length)];
// Use direction color for the word
var wordColor = directionColors[currentDirection];
particles.forEach(function (particle, index) {
if (index < shuffledPositions.length) {
// Form letter
// Clear cloud parameters so particle is identified as word particle
delete particle.cloudAngle;
delete particle.cloudRadius;
delete particle.cloudSpeed;
delete particle.driftSpeed;
tween(particle, {
x: shuffledPositions[index].x,
y: shuffledPositions[index].y,
scaleX: 1.2,
// Increased scale for better readability
scaleY: 1.2,
// Increased scale for better readability
rotation: 0,
tint: wordColor // Same color for all particles in the word
}, {
duration: 800,
easing: randomTweenFunction,
delay: index * 10
});
} else {
// Extra particles float around in cloud-like motion
var angle = Math.random() * Math.PI * 2;
var radius = 300 + Math.random() * 400;
var targetX = 1024 + Math.cos(angle) * radius;
var targetY = 1366 + Math.sin(angle) * radius;
// Store cloud movement parameters on particle
particle.cloudAngle = angle;
particle.cloudRadius = radius;
particle.cloudSpeed = 0.01 + Math.random() * 0.02;
particle.driftSpeed = 0.5 + Math.random() * 1;
tween(particle, {
x: targetX,
y: targetY,
scaleX: 0.2,
scaleY: 0.2,
rotation: Math.random() * Math.PI * 2,
tint: particle.originalTint
}, {
duration: 1000,
easing: tween.linear
});
}
});
// Enable swiping after animation
LK.setTimeout(function () {
canSwipe = true;
}, 900);
}, scatterDuration + 100);
}
// Add continuous movement for background particles
game.update = function () {
// Move particles that are in cloud formation
for (var i = 0; i < game.children.length; i++) {
var particle = game.children[i];
if (particle instanceof Particle) {
// Check if particle is part of the word (not in cloud formation)
if (particle.cloudAngle === undefined) {
// Add small wiggle to word particles
var wiggleX = Math.sin(Date.now() * 0.003 + i) * 0.5;
var wiggleY = Math.cos(Date.now() * 0.003 + i) * 0.5;
particle.x = particle.x + wiggleX;
particle.y = particle.y + wiggleY;
} else {
// Original cloud movement for background particles
// Update cloud angle for circular drift
particle.cloudAngle += particle.cloudSpeed;
// Calculate new position within cloud shape
var centerX = 1024;
var centerY = 1366;
var cloudX = centerX + Math.cos(particle.cloudAngle) * particle.cloudRadius;
var cloudY = centerY + Math.sin(particle.cloudAngle) * particle.cloudRadius;
// Add some drift movement
var driftX = Math.sin(Date.now() * 0.001 * particle.driftSpeed) * 20;
var driftY = Math.cos(Date.now() * 0.001 * particle.driftSpeed) * 15;
// Apply movement
particle.x = cloudX + driftX;
particle.y = cloudY + driftY;
// Gentle rotation
particle.rotation += 0.01;
}
}
}
// Add wiggle effect to score particles
scoreParticles.forEach(function (particle, index) {
var wiggleX = Math.sin(Date.now() * 0.002 + index * 0.1) * 0.3;
var wiggleY = Math.cos(Date.now() * 0.002 + index * 0.1) * 0.3;
particle.x = particle.x + wiggleX;
particle.y = particle.y + wiggleY;
});
// Update timer ring
if (canSwipe && roundStartTime > 0) {
var elapsedTime = Date.now() - roundStartTime;
var timeRemaining = Math.max(0, timerDuration - elapsedTime);
var progress = timeRemaining / timerDuration;
// Update timer particles
timerParticles.forEach(function (particle, index) {
// Calculate threshold for this particle (inverted so it depletes clockwise from top)
var threshold = 1 - index / timerParticles.length;
if (threshold > progress) {
particle.alpha = 0.1; // Fade out depleted particles
particle.scale.set(0.1, 0.1);
} else {
particle.alpha = 1;
particle.scale.set(0.2, 0.2);
// Change color based on time remaining
if (progress < 0.2) {
particle.tint = 0xFF0000; // Red when low on time
} else if (progress < 0.5) {
particle.tint = 0xFFFF00; // Yellow when half time
} else {
particle.tint = 0x00FF00; // Green when plenty of time
}
// Add pulsing effect when time is low
if (progress < 0.2) {
var pulse = Math.sin(Date.now() * 0.01) * 0.1 + 0.2;
particle.scale.set(pulse, pulse);
}
}
// Add gentle orbital movement
var orbitOffset = Math.sin(Date.now() * 0.001 + index * 0.1) * 5;
particle.x = Math.cos(particle.baseAngle) * (timerRadius + orbitOffset);
particle.y = Math.sin(particle.baseAngle) * (timerRadius + orbitOffset);
});
// Check if time ran out
if (timeRemaining === 0 && canSwipe) {
// Time's up - game over
canSwipe = false;
LK.effects.flashScreen(0xFF0000, 500);
LK.showGameOver();
}
}
};
// Start the first round
showNextDirection();
game.down = function (x, y) {
if (!canSwipe) return;
swipeStartX = x;
swipeStartY = y;
isCorrectSwipe = false;
};