/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Character (the slingshot ball)
var SlingshotCharacter = Container.expand(function () {
var self = Container.call(this);
// Attach a circle asset for the character
var charAsset = self.attachAsset('slingshotChar', {
anchorX: 0.5,
anchorY: 0.5
});
// For visual feedback when dragging
self.setDragging = function (isDragging) {
charAsset.alpha = isDragging ? 0.7 : 1;
charAsset.scaleX = charAsset.scaleY = isDragging ? 1.15 : 1;
};
// For visual feedback when shot
self.flash = function () {
LK.effects.flashObject(self, 0xffe066, 200);
};
return self;
});
// Target class
var Target = Container.expand(function () {
var self = Container.call(this);
// Attach a target asset (circle)
var targetAsset = self.attachAsset('targetCircle', {
anchorX: 0.5,
anchorY: 0.5
});
// For hit animation
self.hit = function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- CONFIGURABLES ---
LK.playMusic('M');
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SLING_RADIUS = 350; // Max drag distance
var SLING_CENTER_X = GAME_WIDTH / 2;
var SLING_CENTER_Y = GAME_HEIGHT / 2;
var CHARACTER_RADIUS = 80;
var TARGET_RADIUS = 70;
var NUM_TARGETS = 6;
var MAX_SHOTS = NUM_TARGETS;
var GAME_TIME = 20 * 1000; // 20 seconds
// --- ASSETS ---
// --- STATE ---
var character;
var targets = [];
var shotsLeft = NUM_TARGETS;
var misses = 0;
var score = 0;
var isDragging = false;
var dragStart = null;
var dragLine = null;
var velocity = {
x: 0,
y: 0
};
var isFlying = false;
var timerText, shotsText, missesText;
var timeLeft = GAME_TIME;
var timerInterval = null;
var gameEnded = false;
// --- GUI ---
timerText = new Text2('20.0', {
size: 100,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
shotsText = new Text2('Atış: ' + NUM_TARGETS, {
size: 80,
fill: 0xFFFFFF
});
shotsText.anchor.set(0.5, 0);
LK.gui.top.addChild(shotsText);
shotsText.y = 110;
missesText = new Text2('Iska: 0', {
size: 80,
fill: 0xFFFFFF
});
missesText.anchor.set(0.5, 0);
LK.gui.top.addChild(missesText);
missesText.y = 200;
// --- SHOTS BAR REMOVED (bottom of scene) ---
// --- INIT CHARACTER ---
character = new SlingshotCharacter();
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
game.addChild(character);
// --- INIT TARGETS ---
function randomTargetPos() {
// Place targets randomly, but not too close to center or each other
var minDistFromCenter = 400;
var minDistFromOthers = 300;
var tries = 0;
while (tries < 100) {
var x = 200 + Math.random() * (GAME_WIDTH - 400);
var y = 300 + Math.random() * (GAME_HEIGHT - 600);
var distToCenter = Math.sqrt((x - SLING_CENTER_X) * (x - SLING_CENTER_X) + (y - SLING_CENTER_Y) * (y - SLING_CENTER_Y));
if (distToCenter < minDistFromCenter) {
tries++;
continue;
}
var tooClose = false;
for (var i = 0; i < targets.length; i++) {
var t = targets[i];
var dx = t.x - x,
dy = t.y - y;
if (Math.sqrt(dx * dx + dy * dy) < minDistFromOthers) {
tooClose = true;
break;
}
}
if (!tooClose) return {
x: x,
y: y
};
tries++;
}
// fallback
return {
x: 200 + Math.random() * (GAME_WIDTH - 400),
y: 300 + Math.random() * (GAME_HEIGHT - 600)
};
}
// Arrange targets in a circle around the character
var circleRadius = 600;
var angleStep = 2 * Math.PI / NUM_TARGETS;
for (var i = 0; i < NUM_TARGETS; i++) {
var t = new Target();
var angle = i * angleStep;
t.x = SLING_CENTER_X + Math.cos(angle) * circleRadius;
t.y = SLING_CENTER_Y + Math.sin(angle) * circleRadius;
targets.push(t);
game.addChild(t);
}
// --- DRAGGING & SLINGSHOT ---
function drawDragLine(fromX, fromY, toX, toY) {
if (!dragLine) {
dragLine = LK.getAsset('dragLine', {
width: 10,
height: 10,
color: 0xffffff,
shape: 'box',
anchorX: 0,
anchorY: 0
});
dragLine.alpha = 0.5;
game.addChild(dragLine);
}
var dx = toX - fromX,
dy = toY - fromY;
var len = Math.sqrt(dx * dx + dy * dy);
dragLine.width = len;
dragLine.height = 12;
dragLine.x = fromX;
dragLine.y = fromY - 6;
dragLine.rotation = Math.atan2(dy, dx);
dragLine.visible = true;
}
function hideDragLine() {
if (dragLine) dragLine.visible = false;
}
// --- GAME EVENTS ---
game.down = function (x, y, obj) {
if (gameEnded || isFlying || shotsLeft <= 0) return;
// Only allow drag if touch is on character
var dx = x - character.x,
dy = y - character.y;
if (dx * dx + dy * dy <= CHARACTER_RADIUS * CHARACTER_RADIUS * 1.2) {
isDragging = true;
dragStart = {
x: x,
y: y
};
character.setDragging(true);
drawDragLine(character.x, character.y, x, y);
}
};
game.move = function (x, y, obj) {
if (isDragging && !isFlying && !gameEnded) {
// Limit drag distance
var dx = x - SLING_CENTER_X,
dy = y - SLING_CENTER_Y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > SLING_RADIUS) {
var scale = SLING_RADIUS / dist;
x = SLING_CENTER_X + dx * scale;
y = SLING_CENTER_Y + dy * scale;
}
character.x = x;
character.y = y;
drawDragLine(SLING_CENTER_X, SLING_CENTER_Y, x, y);
}
};
game.up = function (x, y, obj) {
if (isDragging && !isFlying && !gameEnded) {
isDragging = false;
character.setDragging(false);
hideDragLine();
// Calculate velocity (opposite direction of drag)
var dx = SLING_CENTER_X - character.x;
var dy = SLING_CENTER_Y - character.y;
var power = Math.sqrt(dx * dx + dy * dy);
if (power < 40) {
// Not enough drag, reset
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
return;
}
// Normalize and scale velocity
var maxSpeed = 60;
velocity.x = dx / power * Math.min(power, SLING_RADIUS) * 0.25;
velocity.y = dy / power * Math.min(power, SLING_RADIUS) * 0.25;
if (velocity.x > maxSpeed) velocity.x = maxSpeed;
if (velocity.y > maxSpeed) velocity.y = maxSpeed;
isFlying = true;
shotsLeft--;
shotsText.setText('Atış: ' + shotsLeft);
// Shots bar update removed
character.flash();
}
};
// --- TIMER ---
function updateTimerText() {
var sec = Math.max(0, Math.ceil(timeLeft / 100) / 10);
timerText.setText(sec.toFixed(1));
}
function endGame(lost) {
if (gameEnded) return;
gameEnded = true;
LK.setScore(score);
if (lost) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
} else {
// Win only if all targets are hit, no misses, and shots used equals targets, and within 20 seconds
if (score === NUM_TARGETS && misses === 0 && shotsLeft === 0 && timeLeft > 0) {
// Show 'Kazandın' text in the center
var winText = new Text2('Kazandın!', {
size: 220,
fill: 0xffe066,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
winText.anchor.set(0.5, 0.5);
winText.x = GAME_WIDTH / 2;
winText.y = GAME_HEIGHT / 2;
game.addChild(winText);
// Celebration effect: flash screen green, then confetti (simulate with multiple flashes)
LK.effects.flashScreen(0x00ff00, 800);
// Simulate confetti with multiple color flashes
LK.setTimeout(function () {
LK.effects.flashScreen(0xffe066, 200);
}, 900);
LK.setTimeout(function () {
LK.effects.flashScreen(0x66ccff, 200);
}, 1150);
LK.setTimeout(function () {
LK.effects.flashScreen(0xff66cc, 200);
}, 1400);
LK.setTimeout(function () {
LK.effects.flashScreen(0xffffff, 120);
}, 1650);
// ShowYouWin after a short delay so player sees the celebration
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
} else {
// Not a perfect win, show game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}
}
timerInterval = LK.setInterval(function () {
if (gameEnded) return;
timeLeft -= 100;
updateTimerText();
if (timeLeft <= 0) {
endGame(true);
}
}, 100);
// --- GAME UPDATE LOOP ---
game.update = function () {
if (gameEnded) return;
// End game if out of shots or any miss occurs
if (shotsLeft <= 0 || misses > 0) {
endGame(true);
return;
}
// Flying logic
if (isFlying) {
character.x += velocity.x;
character.y += velocity.y;
// Friction
velocity.x *= 0.985;
velocity.y *= 0.985;
// Check collision with targets
for (var i = targets.length - 1; i >= 0; i--) {
var t = targets[i];
var dx = t.x - character.x,
dy = t.y - character.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < CHARACTER_RADIUS + TARGET_RADIUS - 10) {
// Hit!
t.hit();
targets.splice(i, 1);
score++;
LK.setScore(score);
// Animate character a bit
tween(character, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(character, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Reset character to center after short delay
isFlying = false;
LK.setTimeout(function () {
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
}, 180);
// Win condition
if (targets.length === 0) {
endGame(false);
}
return;
}
}
// Out of bounds or stopped
if (character.x < -CHARACTER_RADIUS || character.x > GAME_WIDTH + CHARACTER_RADIUS || character.y < -CHARACTER_RADIUS || character.y > GAME_HEIGHT + CHARACTER_RADIUS || Math.abs(velocity.x) < 1 && Math.abs(velocity.y) < 1) {
isFlying = false;
misses++;
missesText.setText('Iska: ' + misses);
// Animate character back to center
tween(character, {
x: SLING_CENTER_X,
y: SLING_CENTER_Y
}, {
duration: 300,
easing: tween.easeOut
});
if (misses > MAX_MISSES) {
endGame(true);
}
}
}
// If not flying and not dragging, always reset to center
if (!isFlying && !isDragging) {
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
}
};
// --- CLEANUP ON GAME END ---
game.destroy = function () {
LK.clearInterval(timerInterval);
};
// --- GUI POSITIONING ---
// Place timer bar at the far right (en sağda)
timerText.x = LK.gui.top.width - timerText.width / 2 - 20;
shotsText.x = LK.gui.top.width / 2;
missesText.x = 120 + missesText.width / 2; // Place misses bar at top left, leaving 120px margin for menu
;
; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Character (the slingshot ball)
var SlingshotCharacter = Container.expand(function () {
var self = Container.call(this);
// Attach a circle asset for the character
var charAsset = self.attachAsset('slingshotChar', {
anchorX: 0.5,
anchorY: 0.5
});
// For visual feedback when dragging
self.setDragging = function (isDragging) {
charAsset.alpha = isDragging ? 0.7 : 1;
charAsset.scaleX = charAsset.scaleY = isDragging ? 1.15 : 1;
};
// For visual feedback when shot
self.flash = function () {
LK.effects.flashObject(self, 0xffe066, 200);
};
return self;
});
// Target class
var Target = Container.expand(function () {
var self = Container.call(this);
// Attach a target asset (circle)
var targetAsset = self.attachAsset('targetCircle', {
anchorX: 0.5,
anchorY: 0.5
});
// For hit animation
self.hit = function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- CONFIGURABLES ---
LK.playMusic('M');
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SLING_RADIUS = 350; // Max drag distance
var SLING_CENTER_X = GAME_WIDTH / 2;
var SLING_CENTER_Y = GAME_HEIGHT / 2;
var CHARACTER_RADIUS = 80;
var TARGET_RADIUS = 70;
var NUM_TARGETS = 6;
var MAX_SHOTS = NUM_TARGETS;
var GAME_TIME = 20 * 1000; // 20 seconds
// --- ASSETS ---
// --- STATE ---
var character;
var targets = [];
var shotsLeft = NUM_TARGETS;
var misses = 0;
var score = 0;
var isDragging = false;
var dragStart = null;
var dragLine = null;
var velocity = {
x: 0,
y: 0
};
var isFlying = false;
var timerText, shotsText, missesText;
var timeLeft = GAME_TIME;
var timerInterval = null;
var gameEnded = false;
// --- GUI ---
timerText = new Text2('20.0', {
size: 100,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
shotsText = new Text2('Atış: ' + NUM_TARGETS, {
size: 80,
fill: 0xFFFFFF
});
shotsText.anchor.set(0.5, 0);
LK.gui.top.addChild(shotsText);
shotsText.y = 110;
missesText = new Text2('Iska: 0', {
size: 80,
fill: 0xFFFFFF
});
missesText.anchor.set(0.5, 0);
LK.gui.top.addChild(missesText);
missesText.y = 200;
// --- SHOTS BAR REMOVED (bottom of scene) ---
// --- INIT CHARACTER ---
character = new SlingshotCharacter();
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
game.addChild(character);
// --- INIT TARGETS ---
function randomTargetPos() {
// Place targets randomly, but not too close to center or each other
var minDistFromCenter = 400;
var minDistFromOthers = 300;
var tries = 0;
while (tries < 100) {
var x = 200 + Math.random() * (GAME_WIDTH - 400);
var y = 300 + Math.random() * (GAME_HEIGHT - 600);
var distToCenter = Math.sqrt((x - SLING_CENTER_X) * (x - SLING_CENTER_X) + (y - SLING_CENTER_Y) * (y - SLING_CENTER_Y));
if (distToCenter < minDistFromCenter) {
tries++;
continue;
}
var tooClose = false;
for (var i = 0; i < targets.length; i++) {
var t = targets[i];
var dx = t.x - x,
dy = t.y - y;
if (Math.sqrt(dx * dx + dy * dy) < minDistFromOthers) {
tooClose = true;
break;
}
}
if (!tooClose) return {
x: x,
y: y
};
tries++;
}
// fallback
return {
x: 200 + Math.random() * (GAME_WIDTH - 400),
y: 300 + Math.random() * (GAME_HEIGHT - 600)
};
}
// Arrange targets in a circle around the character
var circleRadius = 600;
var angleStep = 2 * Math.PI / NUM_TARGETS;
for (var i = 0; i < NUM_TARGETS; i++) {
var t = new Target();
var angle = i * angleStep;
t.x = SLING_CENTER_X + Math.cos(angle) * circleRadius;
t.y = SLING_CENTER_Y + Math.sin(angle) * circleRadius;
targets.push(t);
game.addChild(t);
}
// --- DRAGGING & SLINGSHOT ---
function drawDragLine(fromX, fromY, toX, toY) {
if (!dragLine) {
dragLine = LK.getAsset('dragLine', {
width: 10,
height: 10,
color: 0xffffff,
shape: 'box',
anchorX: 0,
anchorY: 0
});
dragLine.alpha = 0.5;
game.addChild(dragLine);
}
var dx = toX - fromX,
dy = toY - fromY;
var len = Math.sqrt(dx * dx + dy * dy);
dragLine.width = len;
dragLine.height = 12;
dragLine.x = fromX;
dragLine.y = fromY - 6;
dragLine.rotation = Math.atan2(dy, dx);
dragLine.visible = true;
}
function hideDragLine() {
if (dragLine) dragLine.visible = false;
}
// --- GAME EVENTS ---
game.down = function (x, y, obj) {
if (gameEnded || isFlying || shotsLeft <= 0) return;
// Only allow drag if touch is on character
var dx = x - character.x,
dy = y - character.y;
if (dx * dx + dy * dy <= CHARACTER_RADIUS * CHARACTER_RADIUS * 1.2) {
isDragging = true;
dragStart = {
x: x,
y: y
};
character.setDragging(true);
drawDragLine(character.x, character.y, x, y);
}
};
game.move = function (x, y, obj) {
if (isDragging && !isFlying && !gameEnded) {
// Limit drag distance
var dx = x - SLING_CENTER_X,
dy = y - SLING_CENTER_Y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > SLING_RADIUS) {
var scale = SLING_RADIUS / dist;
x = SLING_CENTER_X + dx * scale;
y = SLING_CENTER_Y + dy * scale;
}
character.x = x;
character.y = y;
drawDragLine(SLING_CENTER_X, SLING_CENTER_Y, x, y);
}
};
game.up = function (x, y, obj) {
if (isDragging && !isFlying && !gameEnded) {
isDragging = false;
character.setDragging(false);
hideDragLine();
// Calculate velocity (opposite direction of drag)
var dx = SLING_CENTER_X - character.x;
var dy = SLING_CENTER_Y - character.y;
var power = Math.sqrt(dx * dx + dy * dy);
if (power < 40) {
// Not enough drag, reset
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
return;
}
// Normalize and scale velocity
var maxSpeed = 60;
velocity.x = dx / power * Math.min(power, SLING_RADIUS) * 0.25;
velocity.y = dy / power * Math.min(power, SLING_RADIUS) * 0.25;
if (velocity.x > maxSpeed) velocity.x = maxSpeed;
if (velocity.y > maxSpeed) velocity.y = maxSpeed;
isFlying = true;
shotsLeft--;
shotsText.setText('Atış: ' + shotsLeft);
// Shots bar update removed
character.flash();
}
};
// --- TIMER ---
function updateTimerText() {
var sec = Math.max(0, Math.ceil(timeLeft / 100) / 10);
timerText.setText(sec.toFixed(1));
}
function endGame(lost) {
if (gameEnded) return;
gameEnded = true;
LK.setScore(score);
if (lost) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
} else {
// Win only if all targets are hit, no misses, and shots used equals targets, and within 20 seconds
if (score === NUM_TARGETS && misses === 0 && shotsLeft === 0 && timeLeft > 0) {
// Show 'Kazandın' text in the center
var winText = new Text2('Kazandın!', {
size: 220,
fill: 0xffe066,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
winText.anchor.set(0.5, 0.5);
winText.x = GAME_WIDTH / 2;
winText.y = GAME_HEIGHT / 2;
game.addChild(winText);
// Celebration effect: flash screen green, then confetti (simulate with multiple flashes)
LK.effects.flashScreen(0x00ff00, 800);
// Simulate confetti with multiple color flashes
LK.setTimeout(function () {
LK.effects.flashScreen(0xffe066, 200);
}, 900);
LK.setTimeout(function () {
LK.effects.flashScreen(0x66ccff, 200);
}, 1150);
LK.setTimeout(function () {
LK.effects.flashScreen(0xff66cc, 200);
}, 1400);
LK.setTimeout(function () {
LK.effects.flashScreen(0xffffff, 120);
}, 1650);
// ShowYouWin after a short delay so player sees the celebration
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
} else {
// Not a perfect win, show game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}
}
timerInterval = LK.setInterval(function () {
if (gameEnded) return;
timeLeft -= 100;
updateTimerText();
if (timeLeft <= 0) {
endGame(true);
}
}, 100);
// --- GAME UPDATE LOOP ---
game.update = function () {
if (gameEnded) return;
// End game if out of shots or any miss occurs
if (shotsLeft <= 0 || misses > 0) {
endGame(true);
return;
}
// Flying logic
if (isFlying) {
character.x += velocity.x;
character.y += velocity.y;
// Friction
velocity.x *= 0.985;
velocity.y *= 0.985;
// Check collision with targets
for (var i = targets.length - 1; i >= 0; i--) {
var t = targets[i];
var dx = t.x - character.x,
dy = t.y - character.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < CHARACTER_RADIUS + TARGET_RADIUS - 10) {
// Hit!
t.hit();
targets.splice(i, 1);
score++;
LK.setScore(score);
// Animate character a bit
tween(character, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(character, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Reset character to center after short delay
isFlying = false;
LK.setTimeout(function () {
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
}, 180);
// Win condition
if (targets.length === 0) {
endGame(false);
}
return;
}
}
// Out of bounds or stopped
if (character.x < -CHARACTER_RADIUS || character.x > GAME_WIDTH + CHARACTER_RADIUS || character.y < -CHARACTER_RADIUS || character.y > GAME_HEIGHT + CHARACTER_RADIUS || Math.abs(velocity.x) < 1 && Math.abs(velocity.y) < 1) {
isFlying = false;
misses++;
missesText.setText('Iska: ' + misses);
// Animate character back to center
tween(character, {
x: SLING_CENTER_X,
y: SLING_CENTER_Y
}, {
duration: 300,
easing: tween.easeOut
});
if (misses > MAX_MISSES) {
endGame(true);
}
}
}
// If not flying and not dragging, always reset to center
if (!isFlying && !isDragging) {
character.x = SLING_CENTER_X;
character.y = SLING_CENTER_Y;
}
};
// --- CLEANUP ON GAME END ---
game.destroy = function () {
LK.clearInterval(timerInterval);
};
// --- GUI POSITIONING ---
// Place timer bar at the far right (en sağda)
timerText.x = LK.gui.top.width - timerText.width / 2 - 20;
shotsText.x = LK.gui.top.width / 2;
missesText.x = 120 + missesText.width / 2; // Place misses bar at top left, leaving 120px margin for menu
;
;