User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'x')' in or related to this line: 'leftLine.skew.x = -0.19; // Angle for trapezoid shape' Line Number: 170
User prompt
field ve oynanabilir alanı çizgiyle ayır
User prompt
arka plan siyah olsun sadece oynanabilir alan yeşil kalsın
User prompt
oyunun alt kenarı tam ekran olacak. yukaruya doğru açılı şekilde daralacak
User prompt
sahanın üst kenarını biraz aşağıya al. oyun alanını kıslat yani. kale üst kenardan yarısı dışarıya taşsın. ayrıca üst iki köşeyi eşit oranda birbirine yaklaştır. yani oyun alanı yamuk şeklinde olmalı.
User prompt
biraz daha soomth hareket etsin top ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
diğer oyuncuları biraz büyüt
User prompt
bottom değil top
User prompt
kenarlara çarpınca top seksin sadece kalenin bulunduğu kenara çarğınca game over olsun
User prompt
sahanın tamamı olsun
User prompt
bu sefer de çok az. rüzgar da fazla etliliyor
User prompt
bu sefer de aşırı fazla
User prompt
topu fırlatma hızımız yeterli değil
User prompt
rüzgar topu doğru şekilde etkilemiyor ayrıca top çok yavaş ve bozuk ilerliyor
User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 224
Code edit (1 edits merged)
Please save this source code
User prompt
Soccer Goal Challenge
Initial prompt
bana bir futbol oyunu yap. olması gerekenler yarım bir saha bir kale birkaç oyuncu top rüzgar oyun nasıl çalışır? kale ve shaa sabittir. her denemede top rastgele bir yerde başlar. oyuncular topun kaleye ulaşmasını bloke etmek için rastgele yerlerde konum alırlar. rüzgar rastgele yönlerden eser. kullancıı rüzgar ve bloke oyuncularına rağmen topu kaleye gönderemeye çalışır. oyannış. topa tıklayıp sürükleyerek yön belirlerin bu sırada bir ok işareti ile gideceği yön gösterilir. rüzgara göre top yönlenerek kaleye gider. eğer bir bloke oyuncusuna çarparsa top duru ve game over olur. eğer kaleye girerse gol olur ve yeni bil el başlar
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AimArrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 1 }); self.visible = false; self.updateArrow = function (startX, startY, endX, endY) { var deltaX = endX - startX; var deltaY = endY - startY; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var angle = Math.atan2(deltaY, deltaX) + Math.PI / 2; self.x = startX; self.y = startY; self.rotation = angle; self.scaleY = Math.min(distance / 40, 5); self.visible = true; }; return self; }); var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.isMoving = false; self.windResistance = 0.98; self.update = function () { // Calculate ball scale based on Y position var fieldTop = 400; var fieldBottom = 2732; var minScale = 1.2; // Smallest scale at top var maxScale = 2.5; // Largest scale at bottom var fieldProgress = (self.y - fieldTop) / (fieldBottom - fieldTop); fieldProgress = Math.max(0, Math.min(1, fieldProgress)); var targetScale = minScale + (maxScale - minScale) * fieldProgress; // Apply smooth scaling with tween if (self.lastScale === undefined) { self.lastScale = targetScale; } if (Math.abs(targetScale - self.lastScale) > 0.05) { tween(self, { scaleX: targetScale, scaleY: targetScale }, { duration: 100 }); self.lastScale = targetScale; } if (self.isMoving) { // Apply wind effect with moderate influence self.velocityX += windX * 0.1; self.velocityY += windY * 0.1; // Apply movement self.x += self.velocityX; self.y += self.velocityY; // Add slow rotation based on movement speed var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY); ballGraphics.rotation += speed * 0.005; // Apply less friction for smoother movement self.velocityX *= 0.995; self.velocityY *= 0.995; // Stop if velocity is very low if (Math.abs(self.velocityX) < 0.3 && Math.abs(self.velocityY) < 0.3) { self.isMoving = false; self.velocityX = 0; self.velocityY = 0; checkRoundEnd(); } // Check boundaries and bounce off walls - trapezoidal field // Calculate field width at current Y position for trapezoid shape var fieldTop = 400; var fieldBottom = 2732; // Full screen height at bottom var fieldTopWidth = 1200; // Narrower at top var fieldBottomWidth = 2048; // Full width at bottom var fieldProgress = (self.y - fieldTop) / (fieldBottom - fieldTop); fieldProgress = Math.max(0, Math.min(1, fieldProgress)); var currentFieldWidth = fieldTopWidth + (fieldBottomWidth - fieldTopWidth) * fieldProgress; var leftBoundary = (2048 - currentFieldWidth) / 2; var rightBoundary = leftBoundary + currentFieldWidth; // Left wall bounce if (self.x < leftBoundary) { self.x = leftBoundary; self.velocityX = -self.velocityX * 0.8; // Bounce with some energy loss } // Right wall bounce if (self.x > rightBoundary) { self.x = rightBoundary; self.velocityX = -self.velocityX * 0.8; // Bounce with some energy loss } // Top wall - game over if (self.y < fieldTop) { LK.getSound('blocked').play(); self.isMoving = false; checkRoundEnd(); } // Banner collision - prevent ball from passing through banner area var bannerTop = 2612; // Banner y position (2672) minus half banner height (60) if (self.y > bannerTop) { self.y = bannerTop; self.velocityY = -self.velocityY * 0.8; // Bounce with some energy loss } // Bottom wall bounce if (self.y > fieldBottom) { self.y = fieldBottom; self.velocityY = -self.velocityY * 0.8; // Bounce with some energy loss } } }; self.shoot = function (targetX, targetY, power) { var deltaX = targetX - self.x; var deltaY = targetY - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance > 0) { self.velocityX = deltaX / distance * power * 1.5; self.velocityY = deltaY / distance * power * 1.5; self.isMoving = true; LK.getSound('kick').play(); } }; return self; }); var Defender = Container.expand(function () { var self = Container.call(this); var defenderGraphics = self.attachAsset('defender', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Array of random celebration messages // Current implementation correctly uses LK.showGameOver() which handles all game over UX // The engine does not provide APIs to customize game over text or add custom links // Game over customization is handled automatically by LK.showGameOver() var celebrationMessages = ["Güzel şuttu. Takımını yönetmeye ne dersin? – volleytics", "Şutunu çektin, şimdi sahayı yönet! – volleytics", "Vaay, antrenman şimdi başlıyor. – volleytics", "Gol senin, yönetim bizim işimiz. – volleytics", "İyi oynuyorsun. Peki takımın geri kalanı? – volleytics", "Spor sahada başlar, volleytics'te tamamlanır.", "Şut çekmesi kolay, ya spor okulu yönetmek? – volleytics", "Topa hükmettin, takıma da hükmedebilirsin. – volleytics", "Skor sende, sistem bizde. – volleytics", "Sahada yıldızsın, yönetimde de olabilirsin. – volleytics", "Bir gol daha! Şimdi yoklama alalım. – volleytics", "Refleksin hızlı, yönetimin de öyle olsun. – volleytics", "Antrenmanlar başlasın, volleytics seni bekliyor!", "Oyunu kazandın, şimdi sistemi kur. – volleytics", "İyi şut! Şimdi antrenmanlarını düzenle. – volleytics"]; var ball; var defenders = []; var goal; var aimArrow; var isDragging = false; var dragStartX = 0; var dragStartY = 0; var windX = 0; var windY = 0; var windIndicator; var roundNumber = 1; var gameState = 'menu'; // 'menu', 'aiming', 'shooting', 'roundEnd' var menuContainer; var startButton; // Create field - full width at bottom, narrowing toward top var field = game.addChild(LK.getAsset('field', { anchorX: 0, anchorY: 0, x: 0, y: 400, width: 2048, height: 2332 })); // Create field boundary lines for trapezoidal shape var fieldLines = []; // Left boundary line - angled using rotation var leftLine = game.addChild(LK.getAsset('fieldLine', { anchorX: 0.5, anchorY: 0, x: 424, // Left edge at top y: 400, width: 4, height: 2332 })); leftLine.rotation = 0.19; // Angle for trapezoid shape fieldLines.push(leftLine); // Right boundary line - angled using rotation var rightLine = game.addChild(LK.getAsset('fieldLine', { anchorX: 0.5, anchorY: 0, x: 1624, // Right edge at top y: 400, width: 4, height: 2332 })); rightLine.rotation = -0.19; // Angle for trapezoid shape fieldLines.push(rightLine); // Top boundary line var topLine = game.addChild(LK.getAsset('fieldLine', { anchorX: 0, anchorY: 0.5, x: 424, y: 400, width: 1200, height: 4 })); fieldLines.push(topLine); // Bottom boundary line var bottomLine = game.addChild(LK.getAsset('fieldLine', { anchorX: 0, anchorY: 0.5, x: 0, y: 2732, width: 2048, height: 4 })); fieldLines.push(bottomLine); // Create goal at top center - half extending above field goal = game.addChild(LK.getAsset('goal', { anchorX: 0.5, anchorY: 0, x: 1024, y: 300 })); // Create UI elements var scoreTxt = new Text2('Gol: 0', { size: 80, fill: 0xFFFFFF, font: "monospace" }); scoreTxt.anchor.set(0.5, 0); scoreTxt.visible = false; // Hide in menu initially LK.gui.top.addChild(scoreTxt); var windTxt = new Text2('Rüzgar Yönü: →', { size: 60, fill: 0x00FFFF, font: "monospace" }); windTxt.anchor.set(0, 0); windTxt.x = 100; windTxt.y = 100; windTxt.visible = false; // Hide in menu initially LK.gui.topLeft.addChild(windTxt); // Create aim arrow aimArrow = game.addChild(new AimArrow()); function spawnBall() { if (ball) { ball.destroy(); } ball = game.addChild(new Ball()); // Spawn ball in bottom half of trapezoidal field, but above banner ball.x = 400 + Math.random() * 1248; ball.y = 2000 + Math.random() * 612; // Reduced from 732 to 612 to stay above banner (2612) // Set initial scale based on spawn position var fieldTop = 400; var fieldBottom = 2732; var minScale = 1.2; var maxScale = 2.5; var fieldProgress = (ball.y - fieldTop) / (fieldBottom - fieldTop); fieldProgress = Math.max(0, Math.min(1, fieldProgress)); var initialScale = minScale + (maxScale - minScale) * fieldProgress; ball.scaleX = initialScale; ball.scaleY = initialScale; ball.lastScale = initialScale; } function spawnDefenders() { // Clear existing defenders for (var i = 0; i < defenders.length; i++) { defenders[i].destroy(); } defenders = []; // Spawn defenders based on round number var defenderCount = Math.min(2 + Math.floor(roundNumber / 2), 6); for (var i = 0; i < defenderCount; i++) { var defender = game.addChild(new Defender()); var validPosition = false; var attempts = 0; var maxAttempts = 100; // Increased attempts for better placement var minDistance = 150; // Increased minimum distance to prevent intersection // Keep trying to find a valid position away from ball and other defenders while (!validPosition && attempts < maxAttempts) { // Spawn defenders within trapezoidal field bounds var spawnY = 500 + Math.random() * 1900; var fieldProgress = (spawnY - 400) / 2332; var fieldWidthAtY = 1200 + 848 * fieldProgress; var leftBound = (2048 - fieldWidthAtY) / 2; var spawnX = leftBound + Math.random() * fieldWidthAtY; validPosition = true; // Assume valid until proven otherwise // Check distance from ball if (ball) { var distanceFromBall = Math.sqrt((spawnX - ball.x) * (spawnX - ball.x) + (spawnY - ball.y) * (spawnY - ball.y)); if (distanceFromBall < minDistance) { validPosition = false; } } // Check distance from other defenders for (var j = 0; j < defenders.length; j++) { var existingDefender = defenders[j]; var distanceFromDefender = Math.sqrt((spawnX - existingDefender.x) * (spawnX - existingDefender.x) + (spawnY - existingDefender.y) * (spawnY - existingDefender.y)); if (distanceFromDefender < 100) { // Minimum distance between defenders validPosition = false; break; } } if (validPosition) { defender.x = spawnX; defender.y = spawnY; } attempts++; } // If we couldn't find a valid position after max attempts, place in upper field area away from ball if (!validPosition) { var safeY = 500 + Math.random() * 800; // Upper portion of field var fieldProgress = (safeY - 400) / 2332; var fieldWidthAtY = 1200 + 848 * fieldProgress; var leftBound = (2048 - fieldWidthAtY) / 2; defender.x = leftBound + Math.random() * fieldWidthAtY; defender.y = safeY; } defenders.push(defender); } } function generateWind() { var windStrength = 0.4 + roundNumber * 0.05; var windAngle = Math.random() * Math.PI * 2; windX = Math.cos(windAngle) * windStrength; windY = Math.sin(windAngle) * windStrength; // Update wind indicator var windDirection = ''; if (Math.abs(windX) > Math.abs(windY)) { windDirection = windX > 0 ? '→' : '←'; } else { windDirection = windY > 0 ? '↓' : '↑'; } windTxt.setText('Rüzgar Yönü: ' + windDirection); } function checkCollisions() { if (!ball || !ball.isMoving) { return; } // Check defender collisions for (var i = 0; i < defenders.length; i++) { if (ball.intersects(defenders[i])) { ball.isMoving = false; LK.getSound('blocked').play(); LK.effects.flashScreen(0xff0000, 500); // Wait for blocked sound to finish before showing retry screen LK.setTimeout(function () { showRetryScreen(); }, 1000); return; } } // Check goal collision if (ball.intersects(goal) && ball.y < goal.y + 200) { ball.isMoving = false; LK.getSound('goal').play(); LK.effects.flashScreen(0x00ff00, 500); // Create animated celebration text only var randomMessage = celebrationMessages[Math.floor(Math.random() * celebrationMessages.length)]; // Split message into parts (main message and volleytics credit) var messageParts = randomMessage.split(' – volleytics'); var mainMessage = messageParts[0]; var hasVolleyticsCredit = messageParts.length > 1; // Split main message into two lines (roughly half the words per line) var words = mainMessage.split(' '); var midPoint = Math.ceil(words.length / 2); var line1 = words.slice(0, midPoint).join(' '); var line2 = words.slice(midPoint).join(' '); // Create container for all text elements var celebrationContainer = new Container(); celebrationContainer.x = -400; // Start off-screen left celebrationContainer.y = 1366; // Center of screen vertically game.addChild(celebrationContainer); // Create text shadow for line 1 var line1Shadow = new Text2(line1, { size: 126, fill: 0x000000, font: "monospace" }); line1Shadow.anchor.set(0.5, 0.5); line1Shadow.x = 2; line1Shadow.y = -42; celebrationContainer.addChild(line1Shadow); // Create line 1 text var line1Text = new Text2(line1, { size: 126, fill: 0xFFFFFF, font: "monospace" }); line1Text.anchor.set(0.5, 0.5); line1Text.x = 0; line1Text.y = -40; celebrationContainer.addChild(line1Text); // Create text shadow for line 2 var line2Shadow = new Text2(line2, { size: 120, fill: 0x000000, font: "monospace" }); line2Shadow.anchor.set(0.5, 0.5); line2Shadow.x = 2; line2Shadow.y = 62; celebrationContainer.addChild(line2Shadow); // Create line 2 text var line2Text = new Text2(line2, { size: 120, fill: 0xFFFFFF, font: "monospace" }); line2Text.anchor.set(0.5, 0.5); line2Text.x = 0; line2Text.y = 60; celebrationContainer.addChild(line2Text); // Create volleytics credit if present if (hasVolleyticsCredit) { // Create shadow for volleytics credit var creditShadow = new Text2('– volleytics', { size: 100, fill: 0x000000, font: "monospace" }); creditShadow.anchor.set(1.0, 0.5); creditShadow.x = 402; creditShadow.y = 151; celebrationContainer.addChild(creditShadow); // Create volleytics credit text (right-aligned) var creditText = new Text2('– volleytics', { size: 100, fill: 0xb63147, font: "monospace" }); creditText.anchor.set(1.0, 0.5); creditText.x = 400; creditText.y = 150; celebrationContainer.addChild(creditText); } // Slide in from left to center tween(celebrationContainer, { x: 1024 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Wait a moment, then slide out to the right LK.setTimeout(function () { tween(celebrationContainer, { x: 2448 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { celebrationContainer.destroy(); } }); }, 1500); } }); // Increment goal count var currentText = scoreTxt.text || 'Gol: 0'; var goalCount = 1; if (currentText && currentText.indexOf(': ') !== -1) { goalCount = parseInt(currentText.split(': ')[1]) + 1; } scoreTxt.setText('Gol: ' + goalCount); // Check win condition if (goalCount >= 10) { LK.showYouWin(); } else { // Next round roundNumber++; // Delay starting new round to allow celebration message to complete LK.setTimeout(function () { startNewRound(); }, 3100); } } } function checkRoundEnd() { if (gameState === 'shooting' && ball && !ball.isMoving) { // Ball stopped without scoring LK.getSound('blocked').play(); LK.setTimeout(function () { showRetryScreen(); }, 1000); } } function startNewRound() { gameState = 'aiming'; spawnBall(); spawnDefenders(); generateWind(); windTxt.visible = true; // Show wind indicator when game starts scoreTxt.visible = true; // Show score when game starts aimArrow.visible = false; } // Event handlers game.down = function (x, y, obj) { if (gameState === 'menu' && startButton) { var buttonPos = game.toLocal(startButton.parent.toGlobal(startButton.position)); var distance = Math.sqrt((x - buttonPos.x) * (x - buttonPos.x) + (y - buttonPos.y) * (y - buttonPos.y)); if (distance < 200) { LK.getSound('kick').play(); gameState = 'aiming'; hideMenu(); startNewRound(); } } else if (gameState === 'aiming' && ball) { var ballPos = game.toLocal(ball.parent.toGlobal(ball.position)); var distance = Math.sqrt((x - ballPos.x) * (x - ballPos.x) + (y - ballPos.y) * (y - ballPos.y)); if (distance < 60) { isDragging = true; dragStartX = x; dragStartY = y; } } }; game.move = function (x, y, obj) { if (gameState === 'aiming' && isDragging && ball) { aimArrow.updateArrow(ball.x, ball.y, x, y); } }; game.up = function (x, y, obj) { if (gameState === 'aiming' && isDragging && ball) { var distance = Math.sqrt((x - ball.x) * (x - ball.x) + (y - ball.y) * (y - ball.y)); var power = Math.min(distance / 3, 20); ball.shoot(x, y, power); gameState = 'shooting'; aimArrow.visible = false; isDragging = false; } }; game.update = function () { checkCollisions(); }; // Create banner at bottom of screen var banner = new Container(); game.addChild(banner); // Position banner at very bottom center banner.x = 1024; banner.y = 2672; // Move to very bottom (2732 - 60 for half banner height) // Create banner background var bannerBg = LK.getAsset('fieldLine', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 120 }); bannerBg.tint = 0x333333; banner.addChild(bannerBg); // Create main text var bannerText1 = new Text2('Gerçek Hayatta spora devam etmek için:', { size: 50, fill: 0xFFFFFF }); bannerText1.anchor.set(0.5, 0.5); bannerText1.y = -25; banner.addChild(bannerText1); // Create link text (no longer clickable) var bannerText2 = new Text2('volleytics.com', { size: 55, fill: 0xb63147 }); bannerText2.anchor.set(0.5, 0.5); bannerText2.y = 30; banner.addChild(bannerText2); function createMenu() { menuContainer = new Container(); game.addChild(menuContainer); // Menu background var menuBg = menuContainer.attachAsset('menuBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Game title image in upper half of menu var titleImage = menuContainer.attachAsset('titleImage', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 800, width: 600, height: 600 }); // Start button startButton = menuContainer.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1500, width: 800, height: 400 }); // Title text shadow var titleShadow = new Text2('Volleytics ile sporun verimli olsun', { size: 120, fill: 0x000000, font: "Kanit" }); titleShadow.anchor.set(0.5, 0.5); titleShadow.x = 1027; titleShadow.y = 2403; menuContainer.addChild(titleShadow); // Title text var titleText = new Text2('Volleytics ile sporun verimli olsun', { size: 120, fill: 0xFFFFFF, font: "Kanit" }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 2400; menuContainer.addChild(titleText); // Link text shadow var linkShadow = new Text2('volleytics.com', { size: 90, fill: 0x000000, font: "Kanit" }); linkShadow.anchor.set(0.5, 0.5); linkShadow.x = 1027; linkShadow.y = 2553; menuContainer.addChild(linkShadow); // Link text var linkText = new Text2('volleytics.com', { size: 90, fill: 0xb63147, font: "Kanit" }); linkText.anchor.set(0.5, 0.5); linkText.x = 1024; linkText.y = 2550; menuContainer.addChild(linkText); } function showRetryScreen() { gameState = 'retry'; // Create retry screen container var retryContainer = new Container(); game.addChild(retryContainer); retryContainer.x = 1024; retryContainer.y = 1366; // Create retry text shadow var retryTextShadow = new Text2('TEKRAR DENE!', { size: 120, fill: 0x000000, font: "monospace" }); retryTextShadow.anchor.set(0.5, 0.5); retryTextShadow.x = 2; retryTextShadow.y = -198; retryContainer.addChild(retryTextShadow); // Create retry text var retryText = new Text2('TEKRAR DENE!', { size: 120, fill: 0xFFFFFF, font: "monospace" }); retryText.anchor.set(0.5, 0.5); retryText.x = 0; retryText.y = -200; retryContainer.addChild(retryText); // Create retry image var retryImage = retryContainer.attachAsset('retryImage', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 100, width: 300, height: 300 }); // Make retry screen clickable retryContainer.down = function (x, y, obj) { // Restart the game without going to menu retryContainer.destroy(); gameState = 'aiming'; roundNumber = 1; // Reset score scoreTxt.setText('Gol: 0'); startNewRound(); }; } function hideMenu() { if (menuContainer) { menuContainer.destroy(); menuContainer = null; startButton = null; } scoreTxt.visible = true; // Show score when leaving menu } // Initialize menu createMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AimArrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1
});
self.visible = false;
self.updateArrow = function (startX, startY, endX, endY) {
var deltaX = endX - startX;
var deltaY = endY - startY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var angle = Math.atan2(deltaY, deltaX) + Math.PI / 2;
self.x = startX;
self.y = startY;
self.rotation = angle;
self.scaleY = Math.min(distance / 40, 5);
self.visible = true;
};
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.isMoving = false;
self.windResistance = 0.98;
self.update = function () {
// Calculate ball scale based on Y position
var fieldTop = 400;
var fieldBottom = 2732;
var minScale = 1.2; // Smallest scale at top
var maxScale = 2.5; // Largest scale at bottom
var fieldProgress = (self.y - fieldTop) / (fieldBottom - fieldTop);
fieldProgress = Math.max(0, Math.min(1, fieldProgress));
var targetScale = minScale + (maxScale - minScale) * fieldProgress;
// Apply smooth scaling with tween
if (self.lastScale === undefined) {
self.lastScale = targetScale;
}
if (Math.abs(targetScale - self.lastScale) > 0.05) {
tween(self, {
scaleX: targetScale,
scaleY: targetScale
}, {
duration: 100
});
self.lastScale = targetScale;
}
if (self.isMoving) {
// Apply wind effect with moderate influence
self.velocityX += windX * 0.1;
self.velocityY += windY * 0.1;
// Apply movement
self.x += self.velocityX;
self.y += self.velocityY;
// Add slow rotation based on movement speed
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
ballGraphics.rotation += speed * 0.005;
// Apply less friction for smoother movement
self.velocityX *= 0.995;
self.velocityY *= 0.995;
// Stop if velocity is very low
if (Math.abs(self.velocityX) < 0.3 && Math.abs(self.velocityY) < 0.3) {
self.isMoving = false;
self.velocityX = 0;
self.velocityY = 0;
checkRoundEnd();
}
// Check boundaries and bounce off walls - trapezoidal field
// Calculate field width at current Y position for trapezoid shape
var fieldTop = 400;
var fieldBottom = 2732; // Full screen height at bottom
var fieldTopWidth = 1200; // Narrower at top
var fieldBottomWidth = 2048; // Full width at bottom
var fieldProgress = (self.y - fieldTop) / (fieldBottom - fieldTop);
fieldProgress = Math.max(0, Math.min(1, fieldProgress));
var currentFieldWidth = fieldTopWidth + (fieldBottomWidth - fieldTopWidth) * fieldProgress;
var leftBoundary = (2048 - currentFieldWidth) / 2;
var rightBoundary = leftBoundary + currentFieldWidth;
// Left wall bounce
if (self.x < leftBoundary) {
self.x = leftBoundary;
self.velocityX = -self.velocityX * 0.8; // Bounce with some energy loss
}
// Right wall bounce
if (self.x > rightBoundary) {
self.x = rightBoundary;
self.velocityX = -self.velocityX * 0.8; // Bounce with some energy loss
}
// Top wall - game over
if (self.y < fieldTop) {
LK.getSound('blocked').play();
self.isMoving = false;
checkRoundEnd();
}
// Banner collision - prevent ball from passing through banner area
var bannerTop = 2612; // Banner y position (2672) minus half banner height (60)
if (self.y > bannerTop) {
self.y = bannerTop;
self.velocityY = -self.velocityY * 0.8; // Bounce with some energy loss
}
// Bottom wall bounce
if (self.y > fieldBottom) {
self.y = fieldBottom;
self.velocityY = -self.velocityY * 0.8; // Bounce with some energy loss
}
}
};
self.shoot = function (targetX, targetY, power) {
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
self.velocityX = deltaX / distance * power * 1.5;
self.velocityY = deltaY / distance * power * 1.5;
self.isMoving = true;
LK.getSound('kick').play();
}
};
return self;
});
var Defender = Container.expand(function () {
var self = Container.call(this);
var defenderGraphics = self.attachAsset('defender', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Array of random celebration messages
// Current implementation correctly uses LK.showGameOver() which handles all game over UX
// The engine does not provide APIs to customize game over text or add custom links
// Game over customization is handled automatically by LK.showGameOver()
var celebrationMessages = ["Güzel şuttu. Takımını yönetmeye ne dersin? – volleytics", "Şutunu çektin, şimdi sahayı yönet! – volleytics", "Vaay, antrenman şimdi başlıyor. – volleytics", "Gol senin, yönetim bizim işimiz. – volleytics", "İyi oynuyorsun. Peki takımın geri kalanı? – volleytics", "Spor sahada başlar, volleytics'te tamamlanır.", "Şut çekmesi kolay, ya spor okulu yönetmek? – volleytics", "Topa hükmettin, takıma da hükmedebilirsin. – volleytics", "Skor sende, sistem bizde. – volleytics", "Sahada yıldızsın, yönetimde de olabilirsin. – volleytics", "Bir gol daha! Şimdi yoklama alalım. – volleytics", "Refleksin hızlı, yönetimin de öyle olsun. – volleytics", "Antrenmanlar başlasın, volleytics seni bekliyor!", "Oyunu kazandın, şimdi sistemi kur. – volleytics", "İyi şut! Şimdi antrenmanlarını düzenle. – volleytics"];
var ball;
var defenders = [];
var goal;
var aimArrow;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var windX = 0;
var windY = 0;
var windIndicator;
var roundNumber = 1;
var gameState = 'menu'; // 'menu', 'aiming', 'shooting', 'roundEnd'
var menuContainer;
var startButton;
// Create field - full width at bottom, narrowing toward top
var field = game.addChild(LK.getAsset('field', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 400,
width: 2048,
height: 2332
}));
// Create field boundary lines for trapezoidal shape
var fieldLines = [];
// Left boundary line - angled using rotation
var leftLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0,
x: 424,
// Left edge at top
y: 400,
width: 4,
height: 2332
}));
leftLine.rotation = 0.19; // Angle for trapezoid shape
fieldLines.push(leftLine);
// Right boundary line - angled using rotation
var rightLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0,
x: 1624,
// Right edge at top
y: 400,
width: 4,
height: 2332
}));
rightLine.rotation = -0.19; // Angle for trapezoid shape
fieldLines.push(rightLine);
// Top boundary line
var topLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0,
anchorY: 0.5,
x: 424,
y: 400,
width: 1200,
height: 4
}));
fieldLines.push(topLine);
// Bottom boundary line
var bottomLine = game.addChild(LK.getAsset('fieldLine', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: 2732,
width: 2048,
height: 4
}));
fieldLines.push(bottomLine);
// Create goal at top center - half extending above field
goal = game.addChild(LK.getAsset('goal', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: 300
}));
// Create UI elements
var scoreTxt = new Text2('Gol: 0', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.visible = false; // Hide in menu initially
LK.gui.top.addChild(scoreTxt);
var windTxt = new Text2('Rüzgar Yönü: →', {
size: 60,
fill: 0x00FFFF,
font: "monospace"
});
windTxt.anchor.set(0, 0);
windTxt.x = 100;
windTxt.y = 100;
windTxt.visible = false; // Hide in menu initially
LK.gui.topLeft.addChild(windTxt);
// Create aim arrow
aimArrow = game.addChild(new AimArrow());
function spawnBall() {
if (ball) {
ball.destroy();
}
ball = game.addChild(new Ball());
// Spawn ball in bottom half of trapezoidal field, but above banner
ball.x = 400 + Math.random() * 1248;
ball.y = 2000 + Math.random() * 612; // Reduced from 732 to 612 to stay above banner (2612)
// Set initial scale based on spawn position
var fieldTop = 400;
var fieldBottom = 2732;
var minScale = 1.2;
var maxScale = 2.5;
var fieldProgress = (ball.y - fieldTop) / (fieldBottom - fieldTop);
fieldProgress = Math.max(0, Math.min(1, fieldProgress));
var initialScale = minScale + (maxScale - minScale) * fieldProgress;
ball.scaleX = initialScale;
ball.scaleY = initialScale;
ball.lastScale = initialScale;
}
function spawnDefenders() {
// Clear existing defenders
for (var i = 0; i < defenders.length; i++) {
defenders[i].destroy();
}
defenders = [];
// Spawn defenders based on round number
var defenderCount = Math.min(2 + Math.floor(roundNumber / 2), 6);
for (var i = 0; i < defenderCount; i++) {
var defender = game.addChild(new Defender());
var validPosition = false;
var attempts = 0;
var maxAttempts = 100; // Increased attempts for better placement
var minDistance = 150; // Increased minimum distance to prevent intersection
// Keep trying to find a valid position away from ball and other defenders
while (!validPosition && attempts < maxAttempts) {
// Spawn defenders within trapezoidal field bounds
var spawnY = 500 + Math.random() * 1900;
var fieldProgress = (spawnY - 400) / 2332;
var fieldWidthAtY = 1200 + 848 * fieldProgress;
var leftBound = (2048 - fieldWidthAtY) / 2;
var spawnX = leftBound + Math.random() * fieldWidthAtY;
validPosition = true; // Assume valid until proven otherwise
// Check distance from ball
if (ball) {
var distanceFromBall = Math.sqrt((spawnX - ball.x) * (spawnX - ball.x) + (spawnY - ball.y) * (spawnY - ball.y));
if (distanceFromBall < minDistance) {
validPosition = false;
}
}
// Check distance from other defenders
for (var j = 0; j < defenders.length; j++) {
var existingDefender = defenders[j];
var distanceFromDefender = Math.sqrt((spawnX - existingDefender.x) * (spawnX - existingDefender.x) + (spawnY - existingDefender.y) * (spawnY - existingDefender.y));
if (distanceFromDefender < 100) {
// Minimum distance between defenders
validPosition = false;
break;
}
}
if (validPosition) {
defender.x = spawnX;
defender.y = spawnY;
}
attempts++;
}
// If we couldn't find a valid position after max attempts, place in upper field area away from ball
if (!validPosition) {
var safeY = 500 + Math.random() * 800; // Upper portion of field
var fieldProgress = (safeY - 400) / 2332;
var fieldWidthAtY = 1200 + 848 * fieldProgress;
var leftBound = (2048 - fieldWidthAtY) / 2;
defender.x = leftBound + Math.random() * fieldWidthAtY;
defender.y = safeY;
}
defenders.push(defender);
}
}
function generateWind() {
var windStrength = 0.4 + roundNumber * 0.05;
var windAngle = Math.random() * Math.PI * 2;
windX = Math.cos(windAngle) * windStrength;
windY = Math.sin(windAngle) * windStrength;
// Update wind indicator
var windDirection = '';
if (Math.abs(windX) > Math.abs(windY)) {
windDirection = windX > 0 ? '→' : '←';
} else {
windDirection = windY > 0 ? '↓' : '↑';
}
windTxt.setText('Rüzgar Yönü: ' + windDirection);
}
function checkCollisions() {
if (!ball || !ball.isMoving) {
return;
}
// Check defender collisions
for (var i = 0; i < defenders.length; i++) {
if (ball.intersects(defenders[i])) {
ball.isMoving = false;
LK.getSound('blocked').play();
LK.effects.flashScreen(0xff0000, 500);
// Wait for blocked sound to finish before showing retry screen
LK.setTimeout(function () {
showRetryScreen();
}, 1000);
return;
}
}
// Check goal collision
if (ball.intersects(goal) && ball.y < goal.y + 200) {
ball.isMoving = false;
LK.getSound('goal').play();
LK.effects.flashScreen(0x00ff00, 500);
// Create animated celebration text only
var randomMessage = celebrationMessages[Math.floor(Math.random() * celebrationMessages.length)];
// Split message into parts (main message and volleytics credit)
var messageParts = randomMessage.split(' – volleytics');
var mainMessage = messageParts[0];
var hasVolleyticsCredit = messageParts.length > 1;
// Split main message into two lines (roughly half the words per line)
var words = mainMessage.split(' ');
var midPoint = Math.ceil(words.length / 2);
var line1 = words.slice(0, midPoint).join(' ');
var line2 = words.slice(midPoint).join(' ');
// Create container for all text elements
var celebrationContainer = new Container();
celebrationContainer.x = -400; // Start off-screen left
celebrationContainer.y = 1366; // Center of screen vertically
game.addChild(celebrationContainer);
// Create text shadow for line 1
var line1Shadow = new Text2(line1, {
size: 126,
fill: 0x000000,
font: "monospace"
});
line1Shadow.anchor.set(0.5, 0.5);
line1Shadow.x = 2;
line1Shadow.y = -42;
celebrationContainer.addChild(line1Shadow);
// Create line 1 text
var line1Text = new Text2(line1, {
size: 126,
fill: 0xFFFFFF,
font: "monospace"
});
line1Text.anchor.set(0.5, 0.5);
line1Text.x = 0;
line1Text.y = -40;
celebrationContainer.addChild(line1Text);
// Create text shadow for line 2
var line2Shadow = new Text2(line2, {
size: 120,
fill: 0x000000,
font: "monospace"
});
line2Shadow.anchor.set(0.5, 0.5);
line2Shadow.x = 2;
line2Shadow.y = 62;
celebrationContainer.addChild(line2Shadow);
// Create line 2 text
var line2Text = new Text2(line2, {
size: 120,
fill: 0xFFFFFF,
font: "monospace"
});
line2Text.anchor.set(0.5, 0.5);
line2Text.x = 0;
line2Text.y = 60;
celebrationContainer.addChild(line2Text);
// Create volleytics credit if present
if (hasVolleyticsCredit) {
// Create shadow for volleytics credit
var creditShadow = new Text2('– volleytics', {
size: 100,
fill: 0x000000,
font: "monospace"
});
creditShadow.anchor.set(1.0, 0.5);
creditShadow.x = 402;
creditShadow.y = 151;
celebrationContainer.addChild(creditShadow);
// Create volleytics credit text (right-aligned)
var creditText = new Text2('– volleytics', {
size: 100,
fill: 0xb63147,
font: "monospace"
});
creditText.anchor.set(1.0, 0.5);
creditText.x = 400;
creditText.y = 150;
celebrationContainer.addChild(creditText);
}
// Slide in from left to center
tween(celebrationContainer, {
x: 1024
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait a moment, then slide out to the right
LK.setTimeout(function () {
tween(celebrationContainer, {
x: 2448
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
celebrationContainer.destroy();
}
});
}, 1500);
}
});
// Increment goal count
var currentText = scoreTxt.text || 'Gol: 0';
var goalCount = 1;
if (currentText && currentText.indexOf(': ') !== -1) {
goalCount = parseInt(currentText.split(': ')[1]) + 1;
}
scoreTxt.setText('Gol: ' + goalCount);
// Check win condition
if (goalCount >= 10) {
LK.showYouWin();
} else {
// Next round
roundNumber++;
// Delay starting new round to allow celebration message to complete
LK.setTimeout(function () {
startNewRound();
}, 3100);
}
}
}
function checkRoundEnd() {
if (gameState === 'shooting' && ball && !ball.isMoving) {
// Ball stopped without scoring
LK.getSound('blocked').play();
LK.setTimeout(function () {
showRetryScreen();
}, 1000);
}
}
function startNewRound() {
gameState = 'aiming';
spawnBall();
spawnDefenders();
generateWind();
windTxt.visible = true; // Show wind indicator when game starts
scoreTxt.visible = true; // Show score when game starts
aimArrow.visible = false;
}
// Event handlers
game.down = function (x, y, obj) {
if (gameState === 'menu' && startButton) {
var buttonPos = game.toLocal(startButton.parent.toGlobal(startButton.position));
var distance = Math.sqrt((x - buttonPos.x) * (x - buttonPos.x) + (y - buttonPos.y) * (y - buttonPos.y));
if (distance < 200) {
LK.getSound('kick').play();
gameState = 'aiming';
hideMenu();
startNewRound();
}
} else if (gameState === 'aiming' && ball) {
var ballPos = game.toLocal(ball.parent.toGlobal(ball.position));
var distance = Math.sqrt((x - ballPos.x) * (x - ballPos.x) + (y - ballPos.y) * (y - ballPos.y));
if (distance < 60) {
isDragging = true;
dragStartX = x;
dragStartY = y;
}
}
};
game.move = function (x, y, obj) {
if (gameState === 'aiming' && isDragging && ball) {
aimArrow.updateArrow(ball.x, ball.y, x, y);
}
};
game.up = function (x, y, obj) {
if (gameState === 'aiming' && isDragging && ball) {
var distance = Math.sqrt((x - ball.x) * (x - ball.x) + (y - ball.y) * (y - ball.y));
var power = Math.min(distance / 3, 20);
ball.shoot(x, y, power);
gameState = 'shooting';
aimArrow.visible = false;
isDragging = false;
}
};
game.update = function () {
checkCollisions();
};
// Create banner at bottom of screen
var banner = new Container();
game.addChild(banner);
// Position banner at very bottom center
banner.x = 1024;
banner.y = 2672; // Move to very bottom (2732 - 60 for half banner height)
// Create banner background
var bannerBg = LK.getAsset('fieldLine', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 120
});
bannerBg.tint = 0x333333;
banner.addChild(bannerBg);
// Create main text
var bannerText1 = new Text2('Gerçek Hayatta spora devam etmek için:', {
size: 50,
fill: 0xFFFFFF
});
bannerText1.anchor.set(0.5, 0.5);
bannerText1.y = -25;
banner.addChild(bannerText1);
// Create link text (no longer clickable)
var bannerText2 = new Text2('volleytics.com', {
size: 55,
fill: 0xb63147
});
bannerText2.anchor.set(0.5, 0.5);
bannerText2.y = 30;
banner.addChild(bannerText2);
function createMenu() {
menuContainer = new Container();
game.addChild(menuContainer);
// Menu background
var menuBg = menuContainer.attachAsset('menuBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Game title image in upper half of menu
var titleImage = menuContainer.attachAsset('titleImage', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 800,
width: 600,
height: 600
});
// Start button
startButton = menuContainer.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1500,
width: 800,
height: 400
});
// Title text shadow
var titleShadow = new Text2('Volleytics ile sporun verimli olsun', {
size: 120,
fill: 0x000000,
font: "Kanit"
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 1027;
titleShadow.y = 2403;
menuContainer.addChild(titleShadow);
// Title text
var titleText = new Text2('Volleytics ile sporun verimli olsun', {
size: 120,
fill: 0xFFFFFF,
font: "Kanit"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 2400;
menuContainer.addChild(titleText);
// Link text shadow
var linkShadow = new Text2('volleytics.com', {
size: 90,
fill: 0x000000,
font: "Kanit"
});
linkShadow.anchor.set(0.5, 0.5);
linkShadow.x = 1027;
linkShadow.y = 2553;
menuContainer.addChild(linkShadow);
// Link text
var linkText = new Text2('volleytics.com', {
size: 90,
fill: 0xb63147,
font: "Kanit"
});
linkText.anchor.set(0.5, 0.5);
linkText.x = 1024;
linkText.y = 2550;
menuContainer.addChild(linkText);
}
function showRetryScreen() {
gameState = 'retry';
// Create retry screen container
var retryContainer = new Container();
game.addChild(retryContainer);
retryContainer.x = 1024;
retryContainer.y = 1366;
// Create retry text shadow
var retryTextShadow = new Text2('TEKRAR DENE!', {
size: 120,
fill: 0x000000,
font: "monospace"
});
retryTextShadow.anchor.set(0.5, 0.5);
retryTextShadow.x = 2;
retryTextShadow.y = -198;
retryContainer.addChild(retryTextShadow);
// Create retry text
var retryText = new Text2('TEKRAR DENE!', {
size: 120,
fill: 0xFFFFFF,
font: "monospace"
});
retryText.anchor.set(0.5, 0.5);
retryText.x = 0;
retryText.y = -200;
retryContainer.addChild(retryText);
// Create retry image
var retryImage = retryContainer.attachAsset('retryImage', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 100,
width: 300,
height: 300
});
// Make retry screen clickable
retryContainer.down = function (x, y, obj) {
// Restart the game without going to menu
retryContainer.destroy();
gameState = 'aiming';
roundNumber = 1;
// Reset score
scoreTxt.setText('Gol: 0');
startNewRound();
};
}
function hideMenu() {
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
startButton = null;
}
scoreTxt.visible = true; // Show score when leaving menu
}
// Initialize menu
createMenu();
pixerlart soccer ball. In-Game asset. 2d. High contrast. No shadows
pixelart soccer goal. In-Game asset. 2d. High contrast. No shadows
pixelart grass texture low quality. have soccer field half center circle at bottom. In-Game asset. 2d. High contrast. No shadows
pixelart arrow up. In-Game asset. 2d. High contrast. No shadows
pixelart football shoot scene cinematic. In-Game asset. 2d. High contrast. No shadows
pixelart button. have text in middle "BAŞLA". In-Game asset. 2d. High contrast. No shadows
fancy pixelart title have shadow and white letters. text is "ŞUT ve GOL". In-Game asset. 2d. High contrast. No shadows
pixelart roling arrow button orange color. In-Game asset. 2d. High contrast. No shadows