/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
var greetingBubble = self.attachAsset('greeting', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -70
});
var greetingText = new Text2('¡Hola!', {
size: 30,
fill: '#000000'
});
greetingText.anchor.set(0.5, 0.5);
greetingText.x = 0;
greetingText.y = -70;
self.addChild(greetingText);
greetingBubble.visible = false;
greetingText.visible = false;
self.showGreeting = function () {
greetingBubble.visible = true;
greetingText.visible = true;
greetingBubble.alpha = 1;
greetingText.alpha = 1;
tween(greetingBubble, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
greetingBubble.visible = false;
}
});
tween(greetingText, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
greetingText.visible = false;
}
});
};
self.isGreeting = false;
self.greetingCooldown = 0;
self.update = function () {
if (self.greetingCooldown > 0) {
self.greetingCooldown--;
}
};
self.greet = function () {
if (self.greetingCooldown <= 0) {
self.isGreeting = true;
self.showGreeting();
self.greetingCooldown = 15; // Short cooldown to prevent spam
LK.setTimeout(function () {
self.isGreeting = false;
}, 250);
return true;
}
return false;
};
return self;
});
var Townsperson = Container.expand(function (isSpecial) {
var self = Container.call(this);
self.isSpecial = isSpecial || false;
var assetId = self.isSpecial ? 'specialPerson' : 'townsperson';
var personGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.greeted = false;
self.speed = 1 + Math.random() * 2;
self.direction = Math.random() * Math.PI * 2;
self.targetX = null;
self.targetY = null;
self.moveTimeout = 0;
self.setRandomDirection = function () {
self.direction = Math.random() * Math.PI * 2;
};
self.setRandomTarget = function () {
self.targetX = 100 + Math.random() * (2048 - 200);
self.targetY = 100 + Math.random() * (2732 - 200);
// Calculate direction to target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
self.direction = Math.atan2(dy, dx);
// Reset timeout
self.moveTimeout = 60 + Math.floor(Math.random() * 120); // 1-3 seconds
};
self.update = function () {
if (self.moveTimeout <= 0) {
self.setRandomTarget();
} else {
self.moveTimeout--;
}
if (self.targetX !== null && self.targetY !== null) {
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 5) {
// Close enough, get new target
self.setRandomTarget();
} else {
var moveX = Math.cos(self.direction) * self.speed;
var moveY = Math.sin(self.direction) * self.speed;
self.x += moveX;
self.y += moveY;
// Boundary check
if (self.x < 50) {
self.x = 50;
}
if (self.x > 2048 - 50) {
self.x = 2048 - 50;
}
if (self.y < 50) {
self.y = 50;
}
if (self.y > 2732 - 50) {
self.y = 2732 - 50;
}
}
} else {
self.setRandomTarget();
}
};
self.greet = function () {
if (!self.greeted) {
self.greeted = true;
// Flash effect
LK.effects.flashObject(self, 0x00FF00, 300);
// Slight movement bounce
var currentX = self.x;
var currentY = self.y;
tween(self, {
x: currentX + Math.cos(self.direction) * 20,
y: currentY + Math.sin(self.direction) * 20
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
x: currentX,
y: currentY
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x88CC99
});
/****
* Game Code
****/
// Define gameplay variables
var player = null;
var townspeople = [];
var score = 0;
var combo = 0;
var maxCombo = 0;
var level = 1;
var spawnTimer = 0;
var dragNode = null;
var gameTime = 0;
var gameActive = true;
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 40,
fill: 0xFFFFFF
});
comboTxt.anchor.set(1, 0);
comboTxt.y = 70;
LK.gui.topRight.addChild(comboTxt);
var levelTxt = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120; // Leave space for platform menu icon
LK.gui.topLeft.addChild(levelTxt);
var timeTxt = new Text2('Time: 60', {
size: 40,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
// Start the game
function initGame() {
// Reset game state
townspeople.forEach(function (person) {
person.destroy();
});
townspeople = [];
score = 0;
combo = 0;
maxCombo = 0;
level = 1;
gameTime = 60; // 60 second game
gameActive = true;
// Reset UI
updateUI();
// Create player
if (player) {
player.destroy();
}
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initial townspeople
spawnTownspeople(5);
// Play music
LK.playMusic('fiestaMusic');
}
function spawnTownspeople(count) {
for (var i = 0; i < count; i++) {
spawnTownsperson();
}
}
function spawnTownsperson() {
var isSpecial = Math.random() < 0.2; // 20% chance for special person
var person = new Townsperson(isSpecial);
// Position on the edge of the screen
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
person.x = Math.random() * 2048;
person.y = 50;
break;
case 1:
// Right
person.x = 2048 - 50;
person.y = Math.random() * 2732;
break;
case 2:
// Bottom
person.x = Math.random() * 2048;
person.y = 2732 - 50;
break;
case 3:
// Left
person.x = 50;
person.y = Math.random() * 2732;
break;
}
// Make sure it's not too close to the player
var dx = person.x - player.x;
var dy = person.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
person.x = Math.random() * 2048;
person.y = Math.random() * 2732;
}
game.addChild(person);
townspeople.push(person);
return person;
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: x' + combo);
levelTxt.setText('Level: ' + level);
timeTxt.setText('Time: ' + Math.ceil(gameTime));
}
function updateLevel() {
var previousLevel = level;
// Calculate level based on score
level = Math.floor(score / 500) + 1;
// Cap at level 10
if (level > 10) {
level = 10;
}
// If level increased
if (level > previousLevel) {
// Spawn more townspeople for each level
spawnTownspeople(level);
// Update UI
levelTxt.setText('Level: ' + level);
// Flash level text
tween(levelTxt, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
tween(levelTxt, {
alpha: 1
}, {
duration: 200
});
}
});
}
}
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep player within bounds
if (dragNode.x < 50) {
dragNode.x = 50;
}
if (dragNode.x > 2048 - 50) {
dragNode.x = 2048 - 50;
}
if (dragNode.y < 50) {
dragNode.y = 50;
}
if (dragNode.y > 2732 - 50) {
dragNode.y = 2732 - 50;
}
// Check for greetings when player moves
if (player.isGreeting) {
checkGreetings();
}
}
}
function checkGreetings() {
var greetedSomeone = false;
for (var i = 0; i < townspeople.length; i++) {
var person = townspeople[i];
// Only check for non-greeted people
if (!person.greeted && player.intersects(person)) {
if (person.greet()) {
greetedSomeone = true;
// Add score
var pointsEarned = 10 * combo * (person.isSpecial ? 3 : 1);
score += pointsEarned;
// Show points gained
var pointsTxt = new Text2("+" + pointsEarned, {
size: 40,
fill: person.isSpecial ? "#FFD700" : "#FFFFFF"
});
pointsTxt.anchor.set(0.5, 0.5);
pointsTxt.x = person.x;
pointsTxt.y = person.y - 60;
game.addChild(pointsTxt);
tween(pointsTxt, {
y: pointsTxt.y - 80,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
pointsTxt.destroy();
}
});
// Update combo
combo++;
if (combo > maxCombo) {
maxCombo = combo;
}
// Play sound
if (person.isSpecial) {
LK.getSound('specialGreet').play();
} else {
LK.getSound('greet').play();
}
// Update level based on score
updateLevel();
}
}
}
if (greetedSomeone) {
// Play combo sound if it's getting high
if (combo > 1 && combo % 5 === 0) {
LK.getSound('combo').play();
// Flash combo text
tween(comboTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
}
// Update UI
updateUI();
}
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
dragNode = player;
handleMove(x, y, obj);
// Greet
if (player.greet()) {
checkGreetings();
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.move = handleMove;
game.update = function () {
if (!gameActive) {
return;
}
// Update game time
gameTime -= 1 / 60; // Assuming 60 FPS
if (gameTime <= 0) {
gameOver();
return;
}
// Update UI
updateUI();
// Spawn new townspeople occasionally
spawnTimer++;
if (spawnTimer >= 180) {
// Every 3 seconds
spawnTimer = 0;
// Chance to spawn increases with level
if (Math.random() < 0.2 + level * 0.05) {
spawnTownsperson();
}
}
// Reset combo if no greets for a while
if (player.greetingCooldown <= 0 && combo > 0) {
var comboDecayRate = 1 / 180; // Lose combo after 3 seconds of inactivity
combo = Math.max(0, combo - comboDecayRate);
if (combo < 1) {
combo = 0;
updateUI();
}
}
// Update all townspeople
for (var i = townspeople.length - 1; i >= 0; i--) {
var person = townspeople[i];
// Remove greeted people after a while
if (person.greeted) {
person.alpha -= 0.01;
if (person.alpha <= 0) {
person.destroy();
townspeople.splice(i, 1);
continue;
}
}
}
};
function gameOver() {
gameActive = false;
// Set final score
LK.setScore(score);
// Show game over
LK.showGameOver();
}
// Initialize the game
initGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
var greetingBubble = self.attachAsset('greeting', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -70
});
var greetingText = new Text2('¡Hola!', {
size: 30,
fill: '#000000'
});
greetingText.anchor.set(0.5, 0.5);
greetingText.x = 0;
greetingText.y = -70;
self.addChild(greetingText);
greetingBubble.visible = false;
greetingText.visible = false;
self.showGreeting = function () {
greetingBubble.visible = true;
greetingText.visible = true;
greetingBubble.alpha = 1;
greetingText.alpha = 1;
tween(greetingBubble, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
greetingBubble.visible = false;
}
});
tween(greetingText, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
greetingText.visible = false;
}
});
};
self.isGreeting = false;
self.greetingCooldown = 0;
self.update = function () {
if (self.greetingCooldown > 0) {
self.greetingCooldown--;
}
};
self.greet = function () {
if (self.greetingCooldown <= 0) {
self.isGreeting = true;
self.showGreeting();
self.greetingCooldown = 15; // Short cooldown to prevent spam
LK.setTimeout(function () {
self.isGreeting = false;
}, 250);
return true;
}
return false;
};
return self;
});
var Townsperson = Container.expand(function (isSpecial) {
var self = Container.call(this);
self.isSpecial = isSpecial || false;
var assetId = self.isSpecial ? 'specialPerson' : 'townsperson';
var personGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.greeted = false;
self.speed = 1 + Math.random() * 2;
self.direction = Math.random() * Math.PI * 2;
self.targetX = null;
self.targetY = null;
self.moveTimeout = 0;
self.setRandomDirection = function () {
self.direction = Math.random() * Math.PI * 2;
};
self.setRandomTarget = function () {
self.targetX = 100 + Math.random() * (2048 - 200);
self.targetY = 100 + Math.random() * (2732 - 200);
// Calculate direction to target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
self.direction = Math.atan2(dy, dx);
// Reset timeout
self.moveTimeout = 60 + Math.floor(Math.random() * 120); // 1-3 seconds
};
self.update = function () {
if (self.moveTimeout <= 0) {
self.setRandomTarget();
} else {
self.moveTimeout--;
}
if (self.targetX !== null && self.targetY !== null) {
// Move toward target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 5) {
// Close enough, get new target
self.setRandomTarget();
} else {
var moveX = Math.cos(self.direction) * self.speed;
var moveY = Math.sin(self.direction) * self.speed;
self.x += moveX;
self.y += moveY;
// Boundary check
if (self.x < 50) {
self.x = 50;
}
if (self.x > 2048 - 50) {
self.x = 2048 - 50;
}
if (self.y < 50) {
self.y = 50;
}
if (self.y > 2732 - 50) {
self.y = 2732 - 50;
}
}
} else {
self.setRandomTarget();
}
};
self.greet = function () {
if (!self.greeted) {
self.greeted = true;
// Flash effect
LK.effects.flashObject(self, 0x00FF00, 300);
// Slight movement bounce
var currentX = self.x;
var currentY = self.y;
tween(self, {
x: currentX + Math.cos(self.direction) * 20,
y: currentY + Math.sin(self.direction) * 20
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
x: currentX,
y: currentY
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x88CC99
});
/****
* Game Code
****/
// Define gameplay variables
var player = null;
var townspeople = [];
var score = 0;
var combo = 0;
var maxCombo = 0;
var level = 1;
var spawnTimer = 0;
var dragNode = null;
var gameTime = 0;
var gameActive = true;
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 40,
fill: 0xFFFFFF
});
comboTxt.anchor.set(1, 0);
comboTxt.y = 70;
LK.gui.topRight.addChild(comboTxt);
var levelTxt = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120; // Leave space for platform menu icon
LK.gui.topLeft.addChild(levelTxt);
var timeTxt = new Text2('Time: 60', {
size: 40,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
// Start the game
function initGame() {
// Reset game state
townspeople.forEach(function (person) {
person.destroy();
});
townspeople = [];
score = 0;
combo = 0;
maxCombo = 0;
level = 1;
gameTime = 60; // 60 second game
gameActive = true;
// Reset UI
updateUI();
// Create player
if (player) {
player.destroy();
}
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initial townspeople
spawnTownspeople(5);
// Play music
LK.playMusic('fiestaMusic');
}
function spawnTownspeople(count) {
for (var i = 0; i < count; i++) {
spawnTownsperson();
}
}
function spawnTownsperson() {
var isSpecial = Math.random() < 0.2; // 20% chance for special person
var person = new Townsperson(isSpecial);
// Position on the edge of the screen
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
person.x = Math.random() * 2048;
person.y = 50;
break;
case 1:
// Right
person.x = 2048 - 50;
person.y = Math.random() * 2732;
break;
case 2:
// Bottom
person.x = Math.random() * 2048;
person.y = 2732 - 50;
break;
case 3:
// Left
person.x = 50;
person.y = Math.random() * 2732;
break;
}
// Make sure it's not too close to the player
var dx = person.x - player.x;
var dy = person.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
person.x = Math.random() * 2048;
person.y = Math.random() * 2732;
}
game.addChild(person);
townspeople.push(person);
return person;
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: x' + combo);
levelTxt.setText('Level: ' + level);
timeTxt.setText('Time: ' + Math.ceil(gameTime));
}
function updateLevel() {
var previousLevel = level;
// Calculate level based on score
level = Math.floor(score / 500) + 1;
// Cap at level 10
if (level > 10) {
level = 10;
}
// If level increased
if (level > previousLevel) {
// Spawn more townspeople for each level
spawnTownspeople(level);
// Update UI
levelTxt.setText('Level: ' + level);
// Flash level text
tween(levelTxt, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
tween(levelTxt, {
alpha: 1
}, {
duration: 200
});
}
});
}
}
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep player within bounds
if (dragNode.x < 50) {
dragNode.x = 50;
}
if (dragNode.x > 2048 - 50) {
dragNode.x = 2048 - 50;
}
if (dragNode.y < 50) {
dragNode.y = 50;
}
if (dragNode.y > 2732 - 50) {
dragNode.y = 2732 - 50;
}
// Check for greetings when player moves
if (player.isGreeting) {
checkGreetings();
}
}
}
function checkGreetings() {
var greetedSomeone = false;
for (var i = 0; i < townspeople.length; i++) {
var person = townspeople[i];
// Only check for non-greeted people
if (!person.greeted && player.intersects(person)) {
if (person.greet()) {
greetedSomeone = true;
// Add score
var pointsEarned = 10 * combo * (person.isSpecial ? 3 : 1);
score += pointsEarned;
// Show points gained
var pointsTxt = new Text2("+" + pointsEarned, {
size: 40,
fill: person.isSpecial ? "#FFD700" : "#FFFFFF"
});
pointsTxt.anchor.set(0.5, 0.5);
pointsTxt.x = person.x;
pointsTxt.y = person.y - 60;
game.addChild(pointsTxt);
tween(pointsTxt, {
y: pointsTxt.y - 80,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
pointsTxt.destroy();
}
});
// Update combo
combo++;
if (combo > maxCombo) {
maxCombo = combo;
}
// Play sound
if (person.isSpecial) {
LK.getSound('specialGreet').play();
} else {
LK.getSound('greet').play();
}
// Update level based on score
updateLevel();
}
}
}
if (greetedSomeone) {
// Play combo sound if it's getting high
if (combo > 1 && combo % 5 === 0) {
LK.getSound('combo').play();
// Flash combo text
tween(comboTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
}
}
// Update UI
updateUI();
}
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
dragNode = player;
handleMove(x, y, obj);
// Greet
if (player.greet()) {
checkGreetings();
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.move = handleMove;
game.update = function () {
if (!gameActive) {
return;
}
// Update game time
gameTime -= 1 / 60; // Assuming 60 FPS
if (gameTime <= 0) {
gameOver();
return;
}
// Update UI
updateUI();
// Spawn new townspeople occasionally
spawnTimer++;
if (spawnTimer >= 180) {
// Every 3 seconds
spawnTimer = 0;
// Chance to spawn increases with level
if (Math.random() < 0.2 + level * 0.05) {
spawnTownsperson();
}
}
// Reset combo if no greets for a while
if (player.greetingCooldown <= 0 && combo > 0) {
var comboDecayRate = 1 / 180; // Lose combo after 3 seconds of inactivity
combo = Math.max(0, combo - comboDecayRate);
if (combo < 1) {
combo = 0;
updateUI();
}
}
// Update all townspeople
for (var i = townspeople.length - 1; i >= 0; i--) {
var person = townspeople[i];
// Remove greeted people after a while
if (person.greeted) {
person.alpha -= 0.01;
if (person.alpha <= 0) {
person.destroy();
townspeople.splice(i, 1);
continue;
}
}
}
};
function gameOver() {
gameActive = false;
// Set final score
LK.setScore(score);
// Show game over
LK.showGameOver();
}
// Initialize the game
initGame();