/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Decoy character class
var DecoyChar = Container.expand(function () {
var self = Container.call(this);
var _char = self.attachAsset('decoyChar', {
anchorX: 0.5,
anchorY: 0.5
});
// Add "X" text centered
var txt = new Text2('X', {
size: 90,
fill: 0xFFFFFF
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
self.addChild(txt);
self.isMerhaba = false;
self.isActive = true;
// Tap handler
self.down = function (x, y, obj) {
if (!self.isActive) return;
self.isActive = false;
handleDecoyTap(self);
};
return self;
});
// Merhaba character class
var MerhabaChar = Container.expand(function () {
var self = Container.call(this);
var _char2 = self.attachAsset('merhabaChar', {
anchorX: 0.5,
anchorY: 0.5
});
// Add "Click" text centered
var txt = new Text2('Click', {
size: 70,
fill: 0xFFFFFF
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
self.addChild(txt);
self.isMerhaba = true;
self.isActive = true;
// Tap handler
self.down = function (x, y, obj) {
if (!self.isActive) return;
self.isActive = false;
handleMerhabaTap(self);
};
return self;
});
// Tap effect class
var TapEffect = Container.expand(function () {
var self = Container.call(this);
var eff = self.attachAsset('tapEffect', {
anchorX: 0.5,
anchorY: 0.5
});
eff.alpha = 0.5;
self.eff = eff;
self.play = function (x, y) {
self.x = x;
self.y = y;
self.visible = true;
eff.scaleX = 1;
eff.scaleY = 1;
eff.alpha = 0.5;
tween(eff, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.visible = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222831
});
/****
* Game Code
****/
// Game variables
// Friendly "Merhaba" character: green ellipse with "Merhaba" text
// Decoy character: red ellipse with "X" text
// Life icon: small yellow ellipse
// Tap effect: white ellipse
// Sound for correct tap
// Sound for wrong tap
// Sound for losing a life
// Sound for new spawn
var score = 0;
var lives = 3;
var maxLives = 3;
var activeChars = [];
var charLifetime = 1200; // ms, will decrease as score increases
var minCharLifetime = 500; // ms
var spawnInterval = 900; // ms, will decrease as score increases
var minSpawnInterval = 350; // ms
var lastSpawnTime = 0;
var isGameOver = false;
var tapEffect;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var lifeIcons = [];
function updateLivesDisplay() {
// Remove old icons
for (var i = 0; i < lifeIcons.length; i++) {
if (lifeIcons[i].parent) lifeIcons[i].parent.removeChild(lifeIcons[i]);
}
lifeIcons = [];
// Place at top right, with margin
var margin = 30;
for (var i = 0; i < lives; i++) {
var icon = LK.getAsset('lifeIcon', {
anchorX: 0.5,
anchorY: 0.5
});
icon.x = -(i * 70) - 60;
icon.y = 60;
LK.gui.topRight.addChild(icon);
lifeIcons.push(icon);
}
}
updateLivesDisplay();
// Tap effect instance
tapEffect = new TapEffect();
game.addChild(tapEffect);
// Helper: get random position for character, avoiding top left 100x100
function getRandomCharPos() {
var margin = 180;
var x = margin + Math.random() * (2048 - 2 * margin);
var y = margin + Math.random() * (2732 - 2 * margin);
// Avoid top left 100x100
if (x < 100 && y < 100) x = 100 + margin;
return {
x: x,
y: y
};
}
// Helper: spawn a character (merhaba or decoy)
function spawnChar() {
if (isGameOver) return;
var isMerhaba = Math.random() < 0.7; // 70% chance merhaba, 30% decoy
var _char3;
if (isMerhaba) {
_char3 = new MerhabaChar();
} else {
_char3 = new DecoyChar();
}
var pos = getRandomCharPos();
_char3.x = pos.x;
_char3.y = pos.y;
_char3.scaleX = 0.7;
_char3.scaleY = 0.7;
_char3.alpha = 0;
// Animate in
tween(_char3, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 180,
easing: tween.easeOut
});
game.addChild(_char3);
activeChars.push({
obj: _char3,
isMerhaba: isMerhaba,
spawnTime: Date.now(),
isActive: true
});
LK.getSound('spawn').play();
}
// Helper: handle tap on Merhaba
function handleMerhabaTap(charObj) {
if (isGameOver) return;
// Find in activeChars
for (var i = 0; i < activeChars.length; i++) {
var c = activeChars[i];
if (c.obj === charObj && c.isActive) {
c.isActive = false;
// Score up
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Tap effect
tapEffect.play(charObj.x, charObj.y);
// Animate out
tween(charObj, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function onFinish() {
charObj.destroy();
}
});
LK.getSound('goodTap').play();
// Remove from activeChars
activeChars.splice(i, 1);
// Speed up game
updateDifficulty();
return;
}
}
}
// Helper: handle tap on Decoy
function handleDecoyTap(charObj) {
if (isGameOver) return;
// Find in activeChars
for (var i = 0; i < activeChars.length; i++) {
var c = activeChars[i];
if (c.obj === charObj && c.isActive) {
c.isActive = false;
// Lose a life
loseLife(charObj.x, charObj.y);
// Animate out
tween(charObj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function onFinish() {
charObj.destroy();
}
});
LK.getSound('badTap').play();
// Remove from activeChars
activeChars.splice(i, 1);
return;
}
}
}
// Helper: lose a life
function loseLife(x, y) {
if (isGameOver) return;
lives -= 1;
updateLivesDisplay();
LK.getSound('loseLife').play();
// Flash screen
LK.effects.flashScreen(0xff0000, 300);
if (lives <= 0) {
endGame();
}
}
// Helper: update difficulty as score increases
function updateDifficulty() {
// Decrease charLifetime and spawnInterval as score increases
var speedup = Math.floor(score / 5);
charLifetime = Math.max(minCharLifetime, 1200 - speedup * 70);
spawnInterval = Math.max(minSpawnInterval, 900 - speedup * 40);
}
// Helper: end game
function endGame() {
isGameOver = true;
// Remove all active chars
for (var i = 0; i < activeChars.length; i++) {
if (activeChars[i].obj && activeChars[i].obj.parent) {
activeChars[i].obj.destroy();
}
}
activeChars = [];
// Show game over
LK.showGameOver();
}
// Game tap handler (for missed taps)
game.down = function (x, y, obj) {
// If tap is not on any character, do nothing
// (Characters handle their own tap events)
};
// Main update loop
game.update = function () {
if (isGameOver) return;
var now = Date.now();
// Spawn new char if enough time has passed
if (activeChars.length < 2 && now - lastSpawnTime > spawnInterval) {
spawnChar();
lastSpawnTime = now;
}
// Remove expired chars
for (var i = activeChars.length - 1; i >= 0; i--) {
var c = activeChars[i];
if (!c || !c.isActive) continue;
if (now - c.spawnTime > charLifetime) {
// If it's a Merhaba, missing it costs a life
if (c.isMerhaba) {
loseLife(c.obj.x, c.obj.y);
// Animate out
tween(c.obj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function (obj) {
if (obj && obj.parent) obj.destroy();
}.bind(null, c.obj)
});
} else {
// Decoy just disappears
tween(c.obj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function (obj) {
if (obj && obj.parent) obj.destroy();
}.bind(null, c.obj)
});
}
c.isActive = false;
activeChars.splice(i, 1);
}
}
};
// Reset game state on new game
LK.on('gameStart', function () {
score = 0;
lives = maxLives;
isGameOver = false;
activeChars = [];
charLifetime = 1200;
spawnInterval = 900;
lastSpawnTime = 0;
scoreTxt.setText(score);
updateLivesDisplay();
// Remove all children except tapEffect
var toRemove = [];
for (var i = 0; i < game.children.length; i++) {
var ch = game.children[i];
if (ch !== tapEffect) toRemove.push(ch);
}
for (var i = 0; i < toRemove.length; i++) {
if (toRemove[i].parent) toRemove[i].parent.removeChild(toRemove[i]);
}
tapEffect.visible = false;
// Play background music
LK.playMusic('1');
}); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Decoy character class
var DecoyChar = Container.expand(function () {
var self = Container.call(this);
var _char = self.attachAsset('decoyChar', {
anchorX: 0.5,
anchorY: 0.5
});
// Add "X" text centered
var txt = new Text2('X', {
size: 90,
fill: 0xFFFFFF
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
self.addChild(txt);
self.isMerhaba = false;
self.isActive = true;
// Tap handler
self.down = function (x, y, obj) {
if (!self.isActive) return;
self.isActive = false;
handleDecoyTap(self);
};
return self;
});
// Merhaba character class
var MerhabaChar = Container.expand(function () {
var self = Container.call(this);
var _char2 = self.attachAsset('merhabaChar', {
anchorX: 0.5,
anchorY: 0.5
});
// Add "Click" text centered
var txt = new Text2('Click', {
size: 70,
fill: 0xFFFFFF
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
self.addChild(txt);
self.isMerhaba = true;
self.isActive = true;
// Tap handler
self.down = function (x, y, obj) {
if (!self.isActive) return;
self.isActive = false;
handleMerhabaTap(self);
};
return self;
});
// Tap effect class
var TapEffect = Container.expand(function () {
var self = Container.call(this);
var eff = self.attachAsset('tapEffect', {
anchorX: 0.5,
anchorY: 0.5
});
eff.alpha = 0.5;
self.eff = eff;
self.play = function (x, y) {
self.x = x;
self.y = y;
self.visible = true;
eff.scaleX = 1;
eff.scaleY = 1;
eff.alpha = 0.5;
tween(eff, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.visible = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222831
});
/****
* Game Code
****/
// Game variables
// Friendly "Merhaba" character: green ellipse with "Merhaba" text
// Decoy character: red ellipse with "X" text
// Life icon: small yellow ellipse
// Tap effect: white ellipse
// Sound for correct tap
// Sound for wrong tap
// Sound for losing a life
// Sound for new spawn
var score = 0;
var lives = 3;
var maxLives = 3;
var activeChars = [];
var charLifetime = 1200; // ms, will decrease as score increases
var minCharLifetime = 500; // ms
var spawnInterval = 900; // ms, will decrease as score increases
var minSpawnInterval = 350; // ms
var lastSpawnTime = 0;
var isGameOver = false;
var tapEffect;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var lifeIcons = [];
function updateLivesDisplay() {
// Remove old icons
for (var i = 0; i < lifeIcons.length; i++) {
if (lifeIcons[i].parent) lifeIcons[i].parent.removeChild(lifeIcons[i]);
}
lifeIcons = [];
// Place at top right, with margin
var margin = 30;
for (var i = 0; i < lives; i++) {
var icon = LK.getAsset('lifeIcon', {
anchorX: 0.5,
anchorY: 0.5
});
icon.x = -(i * 70) - 60;
icon.y = 60;
LK.gui.topRight.addChild(icon);
lifeIcons.push(icon);
}
}
updateLivesDisplay();
// Tap effect instance
tapEffect = new TapEffect();
game.addChild(tapEffect);
// Helper: get random position for character, avoiding top left 100x100
function getRandomCharPos() {
var margin = 180;
var x = margin + Math.random() * (2048 - 2 * margin);
var y = margin + Math.random() * (2732 - 2 * margin);
// Avoid top left 100x100
if (x < 100 && y < 100) x = 100 + margin;
return {
x: x,
y: y
};
}
// Helper: spawn a character (merhaba or decoy)
function spawnChar() {
if (isGameOver) return;
var isMerhaba = Math.random() < 0.7; // 70% chance merhaba, 30% decoy
var _char3;
if (isMerhaba) {
_char3 = new MerhabaChar();
} else {
_char3 = new DecoyChar();
}
var pos = getRandomCharPos();
_char3.x = pos.x;
_char3.y = pos.y;
_char3.scaleX = 0.7;
_char3.scaleY = 0.7;
_char3.alpha = 0;
// Animate in
tween(_char3, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 180,
easing: tween.easeOut
});
game.addChild(_char3);
activeChars.push({
obj: _char3,
isMerhaba: isMerhaba,
spawnTime: Date.now(),
isActive: true
});
LK.getSound('spawn').play();
}
// Helper: handle tap on Merhaba
function handleMerhabaTap(charObj) {
if (isGameOver) return;
// Find in activeChars
for (var i = 0; i < activeChars.length; i++) {
var c = activeChars[i];
if (c.obj === charObj && c.isActive) {
c.isActive = false;
// Score up
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Tap effect
tapEffect.play(charObj.x, charObj.y);
// Animate out
tween(charObj, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function onFinish() {
charObj.destroy();
}
});
LK.getSound('goodTap').play();
// Remove from activeChars
activeChars.splice(i, 1);
// Speed up game
updateDifficulty();
return;
}
}
}
// Helper: handle tap on Decoy
function handleDecoyTap(charObj) {
if (isGameOver) return;
// Find in activeChars
for (var i = 0; i < activeChars.length; i++) {
var c = activeChars[i];
if (c.obj === charObj && c.isActive) {
c.isActive = false;
// Lose a life
loseLife(charObj.x, charObj.y);
// Animate out
tween(charObj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function onFinish() {
charObj.destroy();
}
});
LK.getSound('badTap').play();
// Remove from activeChars
activeChars.splice(i, 1);
return;
}
}
}
// Helper: lose a life
function loseLife(x, y) {
if (isGameOver) return;
lives -= 1;
updateLivesDisplay();
LK.getSound('loseLife').play();
// Flash screen
LK.effects.flashScreen(0xff0000, 300);
if (lives <= 0) {
endGame();
}
}
// Helper: update difficulty as score increases
function updateDifficulty() {
// Decrease charLifetime and spawnInterval as score increases
var speedup = Math.floor(score / 5);
charLifetime = Math.max(minCharLifetime, 1200 - speedup * 70);
spawnInterval = Math.max(minSpawnInterval, 900 - speedup * 40);
}
// Helper: end game
function endGame() {
isGameOver = true;
// Remove all active chars
for (var i = 0; i < activeChars.length; i++) {
if (activeChars[i].obj && activeChars[i].obj.parent) {
activeChars[i].obj.destroy();
}
}
activeChars = [];
// Show game over
LK.showGameOver();
}
// Game tap handler (for missed taps)
game.down = function (x, y, obj) {
// If tap is not on any character, do nothing
// (Characters handle their own tap events)
};
// Main update loop
game.update = function () {
if (isGameOver) return;
var now = Date.now();
// Spawn new char if enough time has passed
if (activeChars.length < 2 && now - lastSpawnTime > spawnInterval) {
spawnChar();
lastSpawnTime = now;
}
// Remove expired chars
for (var i = activeChars.length - 1; i >= 0; i--) {
var c = activeChars[i];
if (!c || !c.isActive) continue;
if (now - c.spawnTime > charLifetime) {
// If it's a Merhaba, missing it costs a life
if (c.isMerhaba) {
loseLife(c.obj.x, c.obj.y);
// Animate out
tween(c.obj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function (obj) {
if (obj && obj.parent) obj.destroy();
}.bind(null, c.obj)
});
} else {
// Decoy just disappears
tween(c.obj, {
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function (obj) {
if (obj && obj.parent) obj.destroy();
}.bind(null, c.obj)
});
}
c.isActive = false;
activeChars.splice(i, 1);
}
}
};
// Reset game state on new game
LK.on('gameStart', function () {
score = 0;
lives = maxLives;
isGameOver = false;
activeChars = [];
charLifetime = 1200;
spawnInterval = 900;
lastSpawnTime = 0;
scoreTxt.setText(score);
updateLivesDisplay();
// Remove all children except tapEffect
var toRemove = [];
for (var i = 0; i < game.children.length; i++) {
var ch = game.children[i];
if (ch !== tapEffect) toRemove.push(ch);
}
for (var i = 0; i < toRemove.length; i++) {
if (toRemove[i].parent) toRemove[i].parent.removeChild(toRemove[i]);
}
tapEffect.visible = false;
// Play background music
LK.playMusic('1');
});
goat. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
evil heart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
goat's hand. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat