User prompt
reset bg2 to beginning of the game when you reset bg2
User prompt
reset to beginning of the game when you reset bg2
User prompt
Flip 180 degree bg2 when score is a multiple of 5
User prompt
skor 5 in katlarına ulaştığında bg2 yi background gibi ters çevir
User prompt
if tube and tree stop stop background and bg2 if tube and tree resets reset background and bg2
User prompt
make them move to left fast as tube
User prompt
add bg2 right of the background and make them move to left of the screen
User prompt
delete mirrored background
User prompt
add bg2 right of backgroundand make it move to left fast as background
User prompt
Sorun, background asset'inin genişliğinin (2807.2) ekran genişliğinden (2048) daha büyük olması nedeniyle oluşuyor. Bu durumda, ilk arka plan görüntüsü (sol kenar referanslı) ekranı tamamen kapladığı için, offset değişse bile ekranda kayma farkı gözlemlenmiyor; diğer kopyalar görünmüyor. Çözüm Önerileri: Scale Ayarı Uygulayın: Arka plan asset'inin, ekran genişliğine (2048) uyacak şekilde ölçeklenmesi gerekir. Örneğin, js Kopyala Düzenle var scaleFactor = 2048 / 2807.2; Bu scaleFactor'ü, background (ve bg2) asset'lerini alırken uygulayabilirsiniz. Böylece, görselin efektif genişliği 2048 piksel olur ve kayma farkı net gözükür. Konumlandırma ve Offset Hesaplaması: Eğer ölçeklendirme uygulanırsa, kopyaları oluştururken kullanılan bgWidth değerini de ölçeklenmiş değere göre ayarlamanız gerekir. Örneğin: js Kopyala Düzenle var origBgWidth = 2807.2; var scaleFactor = 2048 / origBgWidth; var bgWidth = origBgWidth * scaleFactor; Bu şekilde, bgWidth artık 2048 pikselye yakın olacak (tam olarak 2048 ise ideal olur) ve kopyalar yan yana tam oturacaktır. Aşağıda, yukarıdaki düzeltmeleri entegre eden örnek bir ScrollingBackground sınıfı veriyorum: js Kopyala Düzenle /**** Global Tanımlar ****/ function centerX() { return 2048 / 2; } function centerY() { return 2732 / 2; } var groundY = 2732; /**** ScrollingBackground Class (Scale Ayarlı) ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // Orijinal asset genişliği var origBgWidth = 2807.2; // Ekran genişliğine uyacak scale faktörü (istediğiniz değeri verebilirsiniz) var scaleFactor = 2048 / origBgWidth; // Bu örnekte, bg genişliği 2048 olur. // Ölçeklenmiş genişlik: var bgWidth = origBgWidth * scaleFactor; var totalCopies = 3; // Kopya sayısı (ekranı tam kaplamak için) self.offset = 0; self.speed = 3.6; // Tube/Tree ile aynı hız self.bgList = []; for (var i = 0; i < totalCopies; i++) { // bg asset'ini oluşturuyoruz; anchorX=0 (sol kenar referansı) var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: i * bgWidth, y: 0 }); // Uygun scaleFactor'u uygula: bg.scaleX = scaleFactor; bg.scaleY = scaleFactor; // Alternatif mirror: tek index için; bu örnekte eğer i % 2 === 1 ise mirroring yapıyoruz. if (i % 2 === 1) { // Eğer bg2 asset'ini kullanmak istiyorsanız; fakat bu örnekte scaleX değeri -scaleFactor yaparak aynalama yapıyoruz. bg.scaleX = -scaleFactor; } bg.zIndex = 0; self.addChild(bg); self.bgList.push(bg); } self.update = function () { self.offset += self.speed; self.offset = self.offset % bgWidth; for (var i = 0; i < self.bgList.length; i++) { self.bgList[i].x = i * bgWidth - self.offset; } }; return self; }); /**** Initialize Game ****/ var game = new LK.Game({ width: 2048, height: 2732, backgroundColor: 0x000000 }); /**** Arka Planı Ekleyin ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); /**** Örnek Karakter (Test için) ****/ var Character = Container.expand(function () { var self = Container.call(this); self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.x = centerX(); self.y = centerY(); self.update = function () { // Test için update }; return self; }); var character = game.addChild(new Character()); /**** Game Update Fonksiyonu ****/ game.update = function () { game.children.forEach(function (child) { if (child.update) { child.update(); } }); scrollingBackground.update(); game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; /**** Sahneye Ekleyin ****/ LK.stage.addChild(game); Açıklama: Scale Factor: scaleFactor = 2048 / 2807.2 hesaplanarak background asset'in efektif genişliği 2048 pikselye düşürülüyor. bgWidth: Ölçeklenmiş genişlik bgWidth = origBgWidth * scaleFactor, bu durumda 2048 piksel civarında olur. Kopya Oluşturma: Her kopyanın x konumu, i * bgWidth şeklinde belirleniyor. Mirroring: Eğer kopyanın index'i tek ise, bg.scaleX = -scaleFactor olarak ayarlanıyor. Update: Global offset artıyor, ardından her kopyanın x konumu i * bgWidth - offset ile ayarlanıyor. Bu sayede soldan çıkan kopya, sağdan ekranda görünmeye devam ediyor. Bu yapı ile ekran sola kaydıkça, ölçeklenmiş ve dikişsiz bir şekilde yan yana hareket eden arka plan kopyalarını görmelisiniz. Eğer hâlâ sabit görünüyorsa, tarayıcı konsolunda hata olup olmadığını kontrol edin veya kullanılan asset'lerin doğru yüklendiğinden emin olun.
User prompt
spawn bg2 right of the background and move them to left
User prompt
delete everything about background scrolling
User prompt
Aşağıda, yalnızca arka plan sistemine odaklanan ve dikişsiz, mirrored şekilde sola kaydıran minimal bir örnek veriyorum. Bu örnekte, arka plan kopyaları yalnızca ScrollingBackground sınıfı tarafından oluşturuluyor ve global offset yöntemi kullanılarak kaydırılıyor. Diğer tüm arka plan eklemelerini (ör. createInitialBackgrounds) kaldırmanız gerekir, böylece çakışma olmadan tek sistem çalışır. js Kopyala Düzenle /**** Global Fonksiyon ve Değişkenler ****/ function centerX() { return 2048 / 2; } function centerY() { return 2732 / 2; } var groundY = 2732; /**** ScrollingBackground Sınıfı ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); var bgWidth = 2807.2; // Arka plan asset'inizin genişliği var totalCopies = 3; // Ekranı dolduracak kadar kopya (gerekirse artırın) self.offset = 0; self.speed = 3.6; // Tube ve Tree ile aynı hız self.bgList = []; // Her kopyayı oluşturuyoruz; sol kenar referansı için anchorX=0 kullanıyoruz. for (var i = 0; i < totalCopies; i++) { var bg = LK.getAsset('background', { anchorX: 0, // Sol kenar referansı anchorY: 0, x: i * bgWidth, // Sıralı yerleşim: 0, bgWidth, 2*bgWidth y: 0 }); // Alternatif mirror: tek index için scaleX=-1 bg.scaleX = (i % 2 === 1) ? -1 : 1; bg.zIndex = 0; self.addChild(bg); self.bgList.push(bg); } // Update fonksiyonu: offset artıyor ve her kopyanın x konumu yeniden hesaplanıyor. self.update = function () { self.offset += self.speed; self.offset = self.offset % bgWidth; for (var i = 0; i < self.bgList.length; i++) { self.bgList[i].x = i * bgWidth - self.offset; } }; return self; }); /**** Initialize Game ****/ var game = new LK.Game({ width: 2048, height: 2732, backgroundColor: 0x000000 }); /**** Arka Planı Ekleyin ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); /**** Örnek Karakter (Test için) ****/ var Character = Container.expand(function () { var self = Container.call(this); self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.x = centerX(); self.y = centerY(); self.update = function () { // Test amaçlı update (gerektiğinde kendi update fonksiyonunuzu ekleyin) }; return self; }); var character = game.addChild(new Character()); /**** Game Update Fonksiyonu ****/ game.update = function () { // Diğer game.children update işlemleri varsa: game.children.forEach(function (child) { if (child.update) { child.update(); } }); // Arka planın güncellenmesi: scrollingBackground.update(); // Z-index sıralaması (opsiyonel): game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; /**** Sahneye Ekleyin ****/ LK.stage.addChild(game); Açıklamalar Tek Sistem Kullanımı: Kodda yalnızca ScrollingBackground sınıfı kullanılıyor. Eski createInitialBackgrounds veya başka background ekleme yöntemlerini kaldırın. Böylece iki sistemin çakışması önlenir. Anchor Ayarı: Her arka plan kopyası için anchorX: 0 kullanıyoruz. Böylece x değeri, görselin sol kenarını temsil eder; bu, kopyaların yan yana tam yerleşmesini sağlar. Offset Yöntemi: Global offset değeri her update’de artıyor. Her kopyanın x konumu, formül bg.x = (kopya index * bgWidth) - offset ile hesaplanıyor. Offset, bgWidth moduna göre sıfırlanıyor. Böylece soldan çıkan kopya otomatik olarak sağdan görünmeye devam eder. Mirrored Efekt: Kopya oluşturulurken, index tekse bg.scaleX = -1 ayarlanıyor; çift index için bg.scaleX = 1 kalıyor. Böylece, arka planlar normal/mirrored şeklinde sıralanıyor. Bu yapı ile ekran sola doğru kaydıkça, arka plan kopyaları dikişsiz ve sabit hızda (3.6) sola kaymalı, soldan çıkan kopya sağdan yeniden ekranda görünmeli. Eğer hâlâ siyah boşluk görüyorsanız, görselinizin boyutlarını (veya ölçeklemeyi) kontrol edin. Ayrıca, menü veya diğer overlay katmanların arka planı kapatmadığından emin olun.
User prompt
/**** * Assets ****/ LK.init.shape('ground2', {width:2420, height:40, color:0x3e2619, shape:'box'}) LK.init.image('_', {width:100, height:100, id:'67d6c37a228891638f6d628c'}) LK.init.image('background', {width:2807.2, height:2638.77, id:'67ca66de3b19280b799c63f2'}) LK.init.image('button_close', {width:400, height:800, id:'67d4942bd908bd33c0465226'}) LK.init.image('button_credits', {width:847, height:220, id:'67d16188094bc712dffe0bba'}) LK.init.image('button_play', {width:852.5, height:222, id:'67d16188094bc712dffe0bba'}) LK.init.image('button_records', {width:847, height:222, id:'67d16188094bc712dffe0bba'}) LK.init.image('button_volume', {width:854.7, height:222, id:'67d16188094bc712dffe0bba'}) LK.init.image('character', {width:385, height:300, id:'67c8ca443e6157ee028fb76a'}) LK.init.image('ground', {width:3300, height:100, id:'67c8c7553e6157ee028fb720'}) LK.init.image('justX', {width:100, height:100, id:'67d4a59dd908bd33c04652c8'}) LK.init.image('menu_background', {width:2310, height:2800, id:'67cb87b47740c80f1d634b83'}) LK.init.image('menu_background_part', {width:1100, height:2000, id:'67d4fbaf7aa9ff0585703723'}) LK.init.image('second_menu', {width:1850, height:2000, id:'67d17bb7094bc712dffe0d2e', flipX:1}) LK.init.image('sky', {width:2420, height:55, id:'67ca6b423b19280b799c6488'}) LK.init.image('tree', {width:330, height:2200, id:'67d4f6f57aa9ff058570371d', flipY:1}) LK.init.image('tube', {width:330, height:2200, id:'67d4f3547aa9ff058570371a', flipY:1}) LK.init.music('music_1', {volume:0.8, start:0, end:0.383, id:'67c8cc6b3e6157ee028fb79f'}) /**** * Classes ****/ // Character: Dokunulduğunda zıplar. var Character = Container.expand(function () { var self = Container.call(this); self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.zIndex = 4; self.velocityY = 0; self.gravity = 0.3; self.jumpStrength = -12; self.width = 350; self.height = 300; self.update = function () { if (gameStarted && !gameOver) { self.velocityY += self.gravity; self.y += self.velocityY; if (self.y > groundY - 100) { self.y = groundY - 100; self.velocityY = 0; if (!self.intersects(underscoreAsset) && !self.preventDeath) { gameOver = true; endGame(); } } var characterLeft = self.x - self.width / 2; var characterRight = self.x + self.width / 2; var characterTop = self.y - self.height / 2; var characterBottom = self.y + self.height / 2; // Ekran dışına çıkma kontrolü if (characterLeft + self.width / 2 < 0 || characterRight - self.width / 2 > screenRight || characterTop + self.height / 2 < 0 || characterBottom - self.height / 2 > groundY) { gameOver = true; endGame(); } // Çarpışma kontrolü: Tube ve Tree game.children.forEach(function (child) { if (child instanceof Tube) { var tubeLeft = child.x - child.bottomTube.width / 2; var tubeRight = child.x + child.bottomTube.width / 2; var safeGapLowerEdge = child.y - child.bottomTube.height; var safeGapUpperEdge = -gapOffset + child.topTube.height; if (self.x + self.width / 2 > tubeLeft && self.x - self.width / 2 < tubeRight) { if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) { if (!self.intersects(underscoreAsset) && !self.preventDeath) { // Check if not intersecting with underscore asset and preventDeath is not true gameOver = true; endGame(); } else { // If intersecting with underscore asset or preventDeath is true, do not trigger game over return; } } } } else if (child instanceof Tree) { var treeLeft = child.x - child.bottomTree.width / 2; var treeRight = child.x + child.bottomTree.width / 2; var safeGapLowerEdge = child.y - child.bottomTree.height; var safeGapUpperEdge = -gapOffset + child.topTree.height; if (self.x + self.width / 2 > treeLeft && self.x - self.width / 2 < treeRight) { if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) { if (!self.intersects(underscoreAsset) && !self.preventTreeDeath) { // Check if not intersecting with underscore asset and preventTreeDeath is not true gameOver = true; endGame(); } } } } }); } }; self.jump = function () { if (!gameOver) { self.velocityY = self.jumpStrength; } }; return self; }); // GameOverText class var GameOverText = Container.expand(function () { var self = Container.call(this); self.text = new Text2("GAME OVER", { fontFamily: "Arial", fontSize: 2250, fill: 0xFF0000, align: "center", fontWeight: "bold" }); self.text.anchorX = 0.5; self.text.anchorY = 0.5; self.addChild(self.text); self.zIndex = 100; return self; }); var ScrollingBackground = Container.expand(function () { var self = Container.call(this); var bgWidth = 2807.2; // Arka plan asset'inizin orijinal genişliği var totalCopies = 3; // Kaç kopya oluşturulacak (ekranın tamamını kaplayacak kadar) // Global offset, her update'de artacak self.offset = 0; self.speed = 3.6; // Tube/Tree ile aynı hız // Kopyaları saklamak için dizi self.bgList = []; // Her kopyayı oluşturuyoruz for (var i = 0; i < totalCopies; i++) { // anchorX=0: sol kenar referansı var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: i * bgWidth, // Sıralı yerleşim y: 0 }); // Alternatif mirror: tek index için scaleX = -1 if (i % 2 === 1) { bg.scaleX = -1; } else { bg.scaleX = 1; } bg.zIndex = 0; self.addChild(bg); self.bgList.push(bg); } // Update fonksiyonu: offset artar, her kopyanın x konumu offset'e göre ayarlanır. self.update = function () { self.offset += self.speed; // Offset, bgWidth'e göre mod alındığında döngüsel hale gelir self.offset = self.offset % bgWidth; // Her arka plan kopyasının konumunu güncelle for (var i = 0; i < self.bgList.length; i++) { self.bgList[i].x = i * bgWidth - self.offset; } }; return self; }); var Tree = Container.expand(function () { var self = Container.call(this); var bottomUnit = Math.floor(Math.random() * 8) + 1; var topUnit = 9 - bottomUnit; var unitSize = groundY / totalUnits; var bottomHeight = bottomUnit * unitSize; var topHeight = topUnit * unitSize; self.y = groundY; self.bottomTree = self.attachAsset('tree', { anchorX: 0.5, anchorY: 1, width: 300, height: bottomHeight, flipY: false }); self.topTree = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5, width: 300, height: topHeight, flipY: false }); self.topTree.rotation = Math.PI; self.topTree.y = -groundY - gapOffset + topHeight / 2; self.zIndex = 1; self.x = 2048 + 800; self.velocityX = -3.6; self.spawned = false; self.prevX = self.x; self.update = function () { if (gameStarted && !gameOver) { self.x += self.velocityX; // Sırayla ağaç-boru üretimi if (!self.spawned && self.prevX > treeSpawnThreshold && self.x <= treeSpawnThreshold) { self.spawned = true; var newTube = new Tube(); newTube.x = 2048 + 800; game.addChild(newTube); lastSpawner = newTube; } self.prevX = self.x; // Geçme sayacı if (!self.passed && character.x > self.x + self.bottomTree.width / 2) { self.passed = true; updateScore(); } } }; return self; }); // Tube class: Üst ve alt boru oluşturma var Tube = Container.expand(function () { var self = Container.call(this); var bottomUnit = Math.floor(Math.random() * 8) + 1; var topUnit = 9 - bottomUnit; var unitSize = groundY / totalUnits; var bottomHeight = bottomUnit * unitSize; var topHeight = topUnit * unitSize; self.y = groundY; self.bottomTube = self.attachAsset('tube', { anchorX: 0.5, anchorY: 1, width: 300, height: bottomHeight, flipY: false }); self.topTube = self.attachAsset('tube', { anchorX: 0.5, anchorY: 0.5, width: 300, height: topHeight, flipY: false }); self.topTube.rotation = Math.PI; self.topTube.y = -groundY - gapOffset + topHeight / 2; self.zIndex = 1; self.x = 2048 + 800; self.velocityX = -3.6; self.spawned = false; self.prevX = self.x; self.update = function () { if (gameStarted && !gameOver) { self.x += self.velocityX; // Sırayla boru-ağaç üretimi if (!self.spawned && self.prevX > tubeSpawnThreshold && self.x <= tubeSpawnThreshold) { self.spawned = true; var newTree = new Tree(); newTree.x = 2048 + 800; game.addChild(newTree); lastSpawner = newTree; } self.prevX = self.x; // Geçme sayacı if (!self.passed && character.x > self.x + self.bottomTube.width / 2) { self.passed = true; updateScore(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); // Global flag to check if backgrounds have been duplicated var backgroundsDuplicated = false; // Array to store all background copies (both original and duplicated) var allBackgrounds = []; var underscoreAsset = LK.getAsset('_', { anchorX: 0.5, anchorY: 0.5, x: centerX() + 1000, y: centerY() }); underscoreAsset.zIndex = 15000; game.addChild(underscoreAsset); // Add click event to underscore asset underscoreAsset.on('down', function () { // Increment the touch counter underscoreTouchCount++; // Enable preventDeath if touched 5 times if (underscoreTouchCount >= 5) { character.preventDeath = true; character.preventTreeDeath = true; // New flag to prevent death by tree } }); game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); function createCloseButton() { // Close button’un kendi container’ı: var closeButtonContainer = new Container(); closeButtonContainer.zIndex = 9999; // Diğer her şeyin üstünde olsun // Close butonu için ellipse (shape) var closeShape = LK.getAsset('button_close', { anchorX: 0.5, anchorY: 0.5, width: 160 * 0.8, // Adjusted width to 80% of original height: 160 * 1.2 // Adjusted height to 120% of original }); closeButtonContainer.addChild(closeShape); // “X” metni var closeLabel = LK.getAsset('justX', { anchorX: 0.5, anchorY: 0.5, x: -6, // Moved 4 pixels left y: 2 // Moved 4 pixels up }); closeButtonContainer.addChild(closeLabel); return closeButtonContainer; } function zoomEffect() { // Mevcut scale değeri (örneğin orijinal 1) var originalScale = character.scale.x; // Zoom in: %20 artış character.scale.set(originalScale * 1.2); // 300ms sonra zoom out yap, orijinal scale'e dön LK.setTimeout(function () { character.scale.set(originalScale); }, 300); } // Dünyayı ters döndürme (flip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı function flipWorld() { if (flipped) { return; } flipped = true; // 0.3 saniye boyunca karakterin jump ve gravity etkilerini devre dışı bırak character.gravity = 0; character.jumpStrength = 0; zoomEffect(); LK.setTimeout(function () { // Ters dünyada: gravity -0.3, jumpStrength 12 character.gravity = -0.3; character.jumpStrength = 12; }, 300); // Dünya elemanlarını ters çevir (sadece scale yöntemiyle) background.scale.y *= -1; sky.scale.y *= -1; groundAsset.scale.y *= -1; ground2Asset.scale.y *= -1; } // Dünyayı eski hâline döndürme (unflip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı function unflipWorld() { if (!flipped) { return; } flipped = false; character.gravity = 0; character.jumpStrength = 0; zoomEffect(); LK.setTimeout(function () { // Normal dünyada: gravity 0.3, jumpStrength -12 character.gravity = 0.3; character.jumpStrength = -12; }, 300); // Dünya elemanlarını yeniden ters çevirerek orijinal haline döndür background.scale.y *= -1; sky.scale.y *= -1; groundAsset.scale.y *= -1; ground2Asset.scale.y *= -1; } // Skoru güncelleme fonksiyonu – Her 5 skorda flip/unflip toggle function updateScore() { passCounter++; counterText.setText(passCounter); if (passCounter % 5 === 0) { if (!flipped) { flipWorld(); } else { unflipWorld(); } } } /**** * Global Variables & Helper Functions ****/ var groundY = 2732; var menuOpen = true; var volumeOn = true; var records = []; // En iyi 5 skoru saklar var gapOffset = 400; var gameStarted = false; var gameOver = false; var gameWait = false; // Oyun menüden çıkıp da henüz başlamamışken true olacak. var screenRight = 2048; var totalUnits = 10; var tubeSpawnThreshold, treeSpawnThreshold; var lastSpawner = null; var gameOverText = null; var passCounter = 0; var lastScore = 0; // Global lastScore variable var underscoreTouchCount = 0; // Counter for underscore asset touches // Flip durumunu takip eden bayrak var flipped = false; function centerX() { return 2048 / 2; } function centerY() { return groundY / 2; } tubeSpawnThreshold = centerX() + (screenRight - centerX()) / 2; treeSpawnThreshold = centerX() + 3 * (screenRight - centerX()) / 4; /**** * Menu Setup ****/ var menuContainer = new Container(); menuContainer.zIndex = 200; // Menü arka planları var menuBackground = LK.getAsset('menu_background', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: centerY() }); menuBackground.zIndex = 200; menuContainer.addChild(menuBackground); var menuBackgroundPart = LK.getAsset('menu_background_part', { anchorX: 0.5, anchorY: 0.19, x: centerX(), y: centerY() }); menuBackgroundPart.zIndex = menuBackground.zIndex + 1; // 201 menuContainer.addChild(menuBackgroundPart); // Butonlar ve Label’lar // PLAY var playButton = LK.getAsset('button_play', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 20, y: centerY() + 205 }); playButton.visible = false; menuContainer.addChild(playButton); var playLabel = new Text2("PLAY", { fontFamily: "Arial", fontSize: 630.25 * 1.1 * 1.08 * 1.5, fill: 0xffffff }); playLabel.anchorX = 0.5; playLabel.anchorY = 0.5; playLabel.x = playButton.x - 45; playLabel.y = playButton.y - -25; playLabel.visible = true; playLabel.zIndex = 1000; menuContainer.addChild(playLabel); // VOLUME var volumeButton = LK.getAsset('button_volume', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 28, y: centerY() + 310 }); volumeButton.visible = false; menuContainer.addChild(volumeButton); var volumeLabel = new Text2("VOLUME", { fontFamily: "Arial", fontSize: 63.25 * 1.1 * 1.05 * 1.05 * 1.05 * 1.5, fill: 0xffffff }); volumeLabel.anchorX = 0.5; volumeLabel.anchorY = 0.5; volumeLabel.x = volumeButton.x - 58; volumeLabel.y = volumeButton.y + 30; volumeLabel.visible = true; volumeLabel.zIndex = 1000; menuContainer.addChild(volumeLabel); // CREDITS var creditsButton = LK.getAsset('button_credits', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 30, y: centerY() + 429 }); creditsButton.visible = false; menuContainer.addChild(creditsButton); var creditsLabel = new Text2("CREDITS", { fontFamily: "Arial", fontSize: 630.25 * 1.05 * 1.05 * 1.05 * 1.5, fill: 0xffffff }); creditsLabel.anchorX = 0.5; creditsLabel.anchorY = 0.5; creditsLabel.x = creditsButton.x - 60; creditsLabel.y = creditsButton.y + 28; creditsLabel.visible = true; creditsLabel.zIndex = 1000; menuContainer.addChild(creditsLabel); // RECORDS var recordsButton = LK.getAsset('button_records', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 30, y: centerY() + 540 }); recordsButton.visible = false; menuContainer.addChild(recordsButton); var recordsLabel = new Text2("RECORDS", { fontFamily: "Arial", fontSize: 150.25 * 1.05 * 1.05 * 1.03 * 1.05 * 1.5, fill: 0xffffff }); recordsLabel.anchorX = 0.5; recordsLabel.anchorY = 0.5; recordsLabel.x = recordsButton.x - 67; recordsLabel.y = recordsButton.y + 28; recordsLabel.visible = true; recordsLabel.zIndex = 1000; menuContainer.addChild(recordsLabel); // Ekranda sayacımız var counterText = new Text2('0', { size: 124.2, fill: 0xFFFFFF }); counterText.anchor.set(0, 0); counterText.x = 1315; counterText.y = 15; LK.gui.topLeft.addChild(counterText); // Arkaplanlar // Global flag to check if backgrounds have been duplicated var backgroundsDuplicated = false; // Array to store all background copies (both original and duplicated) var allBackgrounds = []; // Function to create the initial set of background copies function createInitialBackgrounds() { var bgWidth = 2807.2; // Arka plan asset'inizin genişliği var totalCopies = 3; // Kaç kopya yan yana dizilecek for (var i = 0; i < totalCopies; i++) { // anchorX=0: sol kenar referansı var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, // Soldan sağa dizilecek x: i * bgWidth, y: 0 }); // i tekse aynalı (scaleX=-1) olsun, çiftse normal (scaleX=1) if (i % 2 === 1) { bg.scaleX = -1; } else { bg.scaleX = 1; } bg.zIndex = 0; allBackgrounds.push(bg); game.addChild(bg); } } // Call this early so you have the initial set on screen. // Call this early so you have the initial set on screen. createInitialBackgrounds(); var sky = LK.getAsset('sky', { anchorX: 0.5, anchorY: 0, x: centerX(), y: 0 }); sky.zIndex = 2; game.addChild(sky); var groundAsset = LK.getAsset('ground', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: groundY - -25 }); groundAsset.zIndex = 4.1; game.addChild(groundAsset); var ground2Asset = LK.getAsset('ground2', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: groundY - 40 }); ground2Asset.zIndex = 0.5; game.addChild(ground2Asset); // Karakteri ekle var character = game.addChild(new Character()); character.x = centerX(); character.y = groundY / 2; // Menü container'ı biraz aşağı kaydırma menuContainer.y += 100; game.addChild(menuContainer); /**** * Helper Functions: Credits, Volume & Records ****/ function createCommonCloseElements(modalWidth, modalHeight) { var closeLabel = LK.getAsset('justX', { anchorX: 0.5, anchorY: 0.5, zIndex: 10000, x: 6, // Moved 4 pixels left y: 16 // Moved 4 pixels up }); var radius = 50; var closeButton = LK.getAsset('button_close', { anchorX: 0.5, anchorY: 0.5, width: radius * 2.3 * 1.2, height: radius * 2.3 * 1.2 }); closeButton.zIndex = 10000; closeButton.x = 0; // Center the button horizontally closeButton.y = 0; // Center the button vertically closeButton.addChild(closeLabel); return { closeLabel: closeLabel, closeButton: closeButton }; } function showCredits() { // Disable menu interaction when modal is opened menuOpen = false; var creditsContainer = new Container(); creditsContainer.zIndex = 300; var modalWidth = 1250, modalHeight = 2000; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); creditsContainer.addChild(bg); var creditsText = new Text2("Game by\nMustafa Talha ŞEN", { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff, align: "center" }); creditsText.anchorX = 0.5; creditsText.anchorY = 0.5; creditsText.x = centerX() - 359; creditsText.y = centerY() - 800 + 40; creditsText.scale.set(3, 3); creditsContainer.addChild(creditsText); // 5) creditsContainer’ı oyuna ekle game.addChild(creditsContainer); // 6) Close butonunu tamamen bağımsız ekle var closeButton = createCloseButton(); // Örneğin, modal’ın sağ üst köşesi olsun closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 160; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175; // Tıklanınca hem creditsContainer’ı hem close butonunu kaldır closeButton.on('down', function () { game.removeChild(creditsContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); // Close butonunu da oyuna ekle game.addChild(closeButton); } function showVolume() { // Disable menu interaction when modal is opened menuOpen = false; var volumeContainer = new Container(); volumeContainer.zIndex = 300; var modalWidth = 1250, modalHeight = 2000; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); volumeContainer.addChild(bg); var volumeText = new Text2("Volume Settings", { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff }); volumeText.scale.set(3, 3); volumeText.anchorX = 0.5; volumeText.anchorY = 0.5; volumeText.x = centerX() - 275; volumeText.y = centerY() - 800 + 85; volumeContainer.addChild(volumeText); // Container’ı oyuna ekle game.addChild(volumeContainer); // Close butonu bağımsız var closeButton = createCloseButton(); closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 159; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175; closeButton.on('down', function () { game.removeChild(volumeContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); game.addChild(closeButton); } function showRecords() { // Disable menu interaction when modal is opened menuOpen = false; var recordsContainer = new Container(); recordsContainer.zIndex = 300; var modalWidth = 1500, modalHeight = 2200; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); recordsContainer.addChild(bg); var recordsTextStr = "Top Scores:\n"; for (var i = 0; i < records.length; i++) { recordsTextStr += i + 1 + ". " + records[i].score + " (Attempt " + records[i].attempt + ")\n"; } if (records.length === 0) { recordsTextStr += "No records yet."; } recordsTextStr += "\nAttempts: " + records.length; recordsTextStr += "\nLast Score: " + lastScore; var recordsText = new Text2(recordsTextStr, { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff, align: "center" }); recordsText.anchorX = 0.5; recordsText.anchorY = 0.5; recordsText.x = centerX() - 280; recordsText.y = centerY() - 850 + 40; recordsText.scale.set(3, 3); recordsContainer.addChild(recordsText); // Container’ı oyuna ekle game.addChild(recordsContainer); // Close butonu bağımsız var closeButton = createCloseButton(); closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 205; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 195; closeButton.on('down', function () { game.removeChild(recordsContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); game.addChild(closeButton); } /**** * End Game & Reset Functions ****/ function endGame() { LK.effects.flashScreen(0xFF0000, 500); character.velocityY = character.jumpStrength; character.update = function () { if (gameOver) { character.velocityY += character.gravity; character.y += character.velocityY; if (character.y > groundY + character.height) { character.y = groundY + character.height; character.velocityY = 0; } } }; game.children.forEach(function (child) { if (child.velocityX) { child.velocityX = 0; } }); game.touchDisabled = true; lastScore = passCounter; records.push({ score: passCounter, attempt: records.length + 1 }); records.sort(function (a, b) { return b.score - a.score; }); if (records.length > 5) { records = records.slice(0, 5); } LK.setTimeout(function () { game.touchDisabled = false; menuOpen = true; menuContainer.visible = true; var startY = groundY + 100; var endY = centerY() - 1270; var animationDuration = 16.5 * 5 / 1.5; var startTime = Date.now(); function animateMenu() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = Math.min(elapsedTime / animationDuration, 1); menuContainer.y = startY + (endY - startY) * progress; if (progress < 1) { LK.setTimeout(animateMenu, 16); } } animateMenu(); }, 1700); LK.setTimeout(function () { resetGame(); }, 1750); } function resetGame() { if (gameOverText) { game.removeChild(gameOverText); gameOverText = null; } // Flip'i eski hâline döndür unflipWorld(); var objectsToRemove = []; game.children.forEach(function (child) { if (child instanceof Tree || child instanceof Tube) { objectsToRemove.push(child); } }); objectsToRemove.forEach(function (obj) { game.removeChild(obj); }); game.removeChild(character); character = game.addChild(new Character()); character.x = centerX(); character.y = groundY / 2; gameStarted = false; gameOver = false; character.preventDeath = false; // Reset preventDeath flag underscoreAsset.preventDeath = false; // Reset preventDeath flag for underscore asset lastSpawner = null; passCounter = 0; underscoreTouchCount = 0; // Reset underscore touch count counterText.setText(passCounter); } /**** * Eliptik hit testi için yardımcı fonksiyon ****/ function checkEllipseHover(button, lx, ly) { var scaleFactorX = 1; var scaleFactorY = 0.53; var offsetY = 40; var dx = lx - button.x; var dy = ly - (button.y + offsetY); var rx = button.width / 2 * scaleFactorX; var ry = button.height / 2 * scaleFactorY; return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1; } /**** * Fare hareketinde hover kontrolü ****/ game.move = function (x, y, obj) { if (!menuOpen) { return; } // Modal açıkken hover efekti çalışmasın. var localX = x - menuContainer.x; var localY = y - menuContainer.y; playButton.visible = checkEllipseHover(playButton, localX, localY); volumeButton.visible = checkEllipseHover(volumeButton, localX, localY); creditsButton.visible = checkEllipseHover(creditsButton, localX, localY); recordsButton.visible = checkEllipseHover(recordsButton, localX, localY); }; /**** * Touch Event ****/ game.down = function (x, y, obj) { if (menuOpen) { var localX = x - menuContainer.x; var localY = y - menuContainer.y; if (checkEllipseHover(playButton, localX, localY)) { var _animateMenu = function animateMenu() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = Math.min(elapsedTime / animationDuration, 1); menuContainer.y = startY + (endY - startY) * progress; if (progress < 1) { LK.setTimeout(_animateMenu, 1); } else { menuOpen = false; menuContainer.visible = false; gameWait = true; } }; var animationDuration = 16.5 * 5 * 2 / 1.5; var startTime = Date.now(); var startY = menuContainer.y; var endY = centerY() + 100; _animateMenu(); return; } else if (checkEllipseHover(volumeButton, localX, localY)) { showVolume(); } else if (checkEllipseHover(creditsButton, localX, localY)) { showCredits(); } else if (checkEllipseHover(recordsButton, localX, localY)) { showRecords(); } return; } else if (gameOver) { if (!game.touchDisabled) { menuOpen = true; menuContainer.visible = true; resetGame(); } } else { if (!menuOpen) {} if (gameWait) { gameWait = false; gameStarted = true; var initialTube = new Tube(); game.addChild(initialTube); lastSpawner = initialTube; character.jump(); } else { character.jump(); character.rotation = 0.1; LK.setTimeout(function () { character.rotation = 0; }, 200); } } }; /**** * Game Loop ****/ game.update = function () { game.children.forEach(function (child) { if (child.update) { child.update(); } }); scrollingBackground.update(); game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); };
User prompt
Aşağıdaki örnekte, sürekli kaydırma için global bir offset değeri kullanıyoruz. Bu yöntemle, arka plan kopyaları (anchorX=0 ile oluşturulmuş) sürekli soldan sağa "dikişsiz" bir şekilde kayar. Her kopyanın x konumunu, global offset üzerinden hesaplıyoruz; böylece soldan kayıp, sağdan yeni kopyaların görünmesi garantilenir ve siyah boşluk oluşmaz. Aşağıdaki kodu deneyin: js Kopyala Düzenle /**** Global Tanımlar ****/ function centerX() { return 2048 / 2; } function centerY() { return 2732 / 2; } var groundY = 2732; /**** ScrollingBackground Class - Offset Yöntemi ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); var bgWidth = 2807.2; // Arka plan asset'inizin orijinal genişliği var totalCopies = 3; // Kaç kopya oluşturulacak (ekranın tamamını kaplayacak kadar) // Global offset, her update'de artacak self.offset = 0; self.speed = 3.6; // Tube/Tree ile aynı hız // Kopyaları saklamak için dizi self.bgList = []; // Her kopyayı oluşturuyoruz for (var i = 0; i < totalCopies; i++) { // anchorX=0: sol kenar referansı var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: i * bgWidth, // Sıralı yerleşim y: 0 }); // Alternatif mirror: tek index için scaleX = -1 if (i % 2 === 1) { bg.scaleX = -1; } else { bg.scaleX = 1; } bg.zIndex = 0; self.addChild(bg); self.bgList.push(bg); } // Update fonksiyonu: offset artar, her kopyanın x konumu offset'e göre ayarlanır. self.update = function () { self.offset += self.speed; // Offset, bgWidth'e göre mod alındığında döngüsel hale gelir self.offset = self.offset % bgWidth; // Her arka plan kopyasının konumunu güncelle for (var i = 0; i < self.bgList.length; i++) { self.bgList[i].x = i * bgWidth - self.offset; } }; return self; }); /**** Initialize Game ****/ var game = new LK.Game({ width: 2048, height: 2732, backgroundColor: 0x000000 }); /**** Arka Planları Ekleyin ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); /**** Örnek Karakter (Basit Test İçin) ****/ var Character = Container.expand(function () { var self = Container.call(this); self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.x = centerX(); self.y = centerY(); self.update = function () { // Test amaçlı boş }; return self; }); var character = game.addChild(new Character()); /**** game.update Fonksiyonu ****/ game.update = function () { // Öncelikle tüm game.children update edilsin (varsa diğer objeler) game.children.forEach(function (child) { if (child.update) { child.update(); } }); // Arka plan kaydırması offset yöntemiyle scrollingBackground.update(); // Diğer update işlemleri (örn. zIndex sıralaması) varsa: game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; /**** Sahneye Ekleyin ****/ LK.stage.addChild(game); Açıklamalar Anchor Ayarı: Arka plan kopyalarını oluştururken anchorX: 0 kullanıyoruz, bu sayede her kopyanın x değeri sol kenarını ifade eder. Offset Yöntemi: Global offset değeri, her update'de speed kadar artar ve bgWidth moduna göre hesaplanır. Her kopyanın x konumu: bg.x = (kopya index * bgWidth) - offset Bu sayede, soldan kayarken ilk kopya kaybolduğunda, son kopya otomatik olarak sağdan görünür hale gelir. Mirrored Etki: Kopya oluşturulurken, tek indexli kopyalara scaleX = -1 verilerek ayna yansıması elde edilir. Entegrasyon: Bu örnek, yalnızca arka plan kopyalarının kaydırılması üzerine odaklanıyor. Diğer oyun objeleri (karakter, menü, vb.) kodunuzda varsa, bu yapıyı karışıklığa yol açmayacak şekilde entegre etmelisiniz. Bu kodu projenize entegre ettikten sonra, ekran sola kaydıkça arka plan kopyaları, dikişsiz ve sürekli bir döngü halinde sağdan yeniden görünmelidir. Eğer hâlâ siyah kısım oluşuyorsa, görselinizin boyutları veya scale ayarlarını gözden geçirip ayarlamak gerekebilir.
User prompt
Aşağıdaki noktaları kontrol ederek “arka plan görünmüyor, ekran siyah” sorununu çözebilirsiniz. Mevcut kodda arka planla ilgili birkaç farklı mekanizma ve asset tanımı bir arada yer alıyor, bu da çakışmalara veya görünüm sorunlarına yol açabiliyor.
1) Eski “ScrollingBackground” Sınıfı ve Tekil “background” Asset’ini Kaldırın
Kodunuzda iki farklı yaklaşım bir arada var:
ScrollingBackground sınıfı (bg1, bg2 şeklinde).
createInitialBackgrounds() fonksiyonu (allBackgrounds dizisi içinde 3 kopya oluşturuyor).
Bu iki yaklaşım birbirini geçersiz kılabilir veya ekranda hangi arka planın görüneceği konusunda çakışma yaratabilir. Eğer siz “createInitialBackgrounds” yaklaşımını kullanacaksanız, ScrollingBackground sınıfını tamamen kaldırın ya da devre dışı bırakın. Aksi takdirde, “ScrollingBackground” da bir arka plan ekliyor ve belki de konumu veya z-index’i diğerini gizliyor.
Aynı şekilde, kodunuzun bir yerinde tekil bir “background” varlığı da (var background = LK.getAsset('background', ...)) ekliyor olabilirsiniz. O da yine çakışma yaratıyor olabilir. “createInitialBackgrounds” dizili yöntemi dışındaki tekil background eklemelerini kaldırın.
Özet:
“ScrollingBackground” sınıfını ya tamamen silin ya da kullanmayın.
Tek seferde, “createInitialBackgrounds()” fonksiyonu ile arka planları oluşturun.
2) Arka Planın Ekrana “Görünür” Şekilde Yerleştirildiğinden Emin Olun
Şu anda createInitialBackgrounds içinde şöyle yapıyorsunuz:
js
Kopyala
Düzenle
var bg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: i * bgWidth,
y: 0
});
Bu, görselin sol üst köşesini (anchorX=0, anchorY=0) ekranın (x=0, y=0) noktasına koyar. Oyununuzun koordinat sistemi (0,0) sol üst köşeye denk geliyorsa, arka planın üst sol köşesi ekranın üst soluna oturur. Eğer oyunun “height” değeri 2732 ve “width” 2048 ise, bu normalde ekranda gözükmesi gerekir.
Ancak bazen:
Başka bir sprite (mesela “sky” ya da “menuBackground”) bunu kapatıyor olabilir.
Arka planın zIndex değeri, menünün veya siyah bir shape’in altında kalıyor olabilir.
Arka planın boyutu çok büyük olduğundan, ekranda tam sığmıyordur. Fakat yine de bir kısmı görünmesi gerek.
“Menu” kapatılmamışsa, menünün koyu alanı arka planı kapatıyor olabilir.
Denetim:
Menüyü gerçekten kapattınız mı? (Play’e bastınız mı?)
zIndex değerlerini kontrol edin. Arka plan 0, menü 200 gibi. Menü varsa, arka planı kapatabilir.
“Sky” isimli asset de ekleniyor. Onun boyutu (2420×55) her ne kadar dar olsa da belki scale edilip tüm ekranı kaplıyordur. ZIndex’i 2 ama arka plan 0’da. Ekranda siyah bir shape varsa, belki o da üstte duruyor olabilir.
Çözüm:
“menuBackground” ve “sky” gibi üst katmanların zIndex değerlerini kontrol edin. Arka planın altına mı üstüne mi geliyorlar?
Menü kapalıyken “arka plan” gözükecektir.
Gerekirse, debug için zIndex=9999 verip “arka plan”ın en önde görünmesini sağlayın; böylece var mı yok mu test edebilirsiniz.
3) Oyuna Bir Başlangıç “Siyah Ekran” Geliyor Olabilir
Eğer menü “open” durumdaysa ve siz henüz “Play” butonuna basmadıysanız, menü katmanı ekranda olabilir. Ayrıca “gameWait = true” durumu da olabilir. Lütfen menünün kapanıp kapanmadığını, “playButton” tıklamasının menüyü gizleyip gizlemediğini doğrulayın.
Basit bir test olarak, menüyü ve sky vb. her şeyi kapatıp sadece arka plan kopyalarını ekleyerek test edin. Örneğin:
js
Kopyala
Düzenle
// Test amaçlı: Menü, sky, ground gibi her şeyi kapatın
// Sadece createInitialBackgrounds() ve game.update kalsın.
// Sonra ekranda background görünüyor mu bakın.
4) Scale Gerekebilir
Arka planınız 2807.2 piksel genişliğinde, oyununuz 2048 piksel genişliğinde. Bu aslında yatayda sığmıyor gibi görünebilir. Normalde “taşsa” da yine bir kısmı görünmelidir. Fakat eğer “ekrana tam sığsın” diyorsanız, bir scale işlemi yapmalısınız:
js
Kopyala
Düzenle
var scaleFactor = 2048 / 2807.2; // Ekrana yatay sığdırmak için
bg.scaleX = scaleFactor;
bg.scaleY = scaleFactor;
Bunu her arka plan kopyası için uygulayabilirsiniz. Böylece arka planlar tam ekrana sığar.
5) Koddan “ScrollingBackground” Nesnesini Kaldırın veya Kullanmayın
Kodunuzda hâlâ:
js
Kopyala
Düzenle
var scrollingBackground = new ScrollingBackground();
game.addChild(scrollingBackground);
gibi bir satır varsa, bu “ScrollingBackground” class’ını sahneye ekler. Orada da bg1 ve bg2 adında arka plan asset’leri ekleniyor. Bu da “createInitialBackgrounds” ile çakışabilir.
En temizi, “ScrollingBackground” class’ını tamamen silip, sadece “createInitialBackgrounds” + “allBackgrounds” ile ilerlemektir.
6) game.update İçinde Kaydırma
Şu an game.update’te şunları yapıyorsunuz:
js
Kopyala
Düzenle
var bgSpeed = 3.6;
var bgWidth = 2807.2;
allBackgrounds.forEach(function (bg) {
bg.x -= bgSpeed;
});
allBackgrounds.forEach(function (bg) {
if (bg.x + bgWidth <= 0) {
var maxX = Math.max(...);
bg.x = maxX + bgWidth;
}
});
Bu kısım doğru çalışıyorsa, arka planlar soldan çıkar çıkmaz en sağa gitmeli. Bu mantık normaldir. Yeter ki “createInitialBackgrounds” ile x: i*bgWidth, anchorX:0 ayarınız tam olsun.
7) Örnek “Temiz” Kod Parçası
Aşağıda menü vb. her şeyi çıkararak sadece arka plan kopyaları ve karakter eklenmiş minimal bir örnek veriyorum. Bunu deneyip çalıştığından emin olduktan sonra, menü ve diğer katmanları yavaş yavaş ekleyebilirsiniz.
js
Kopyala
Düzenle
var game = new LK.Game({ width:2048, height:2732, backgroundColor:0x000000 });
// 1) Basit “createInitialBackgrounds”
var allBackgrounds = [];
function createInitialBackgrounds() {
var bgWidth = 2807.2;
var totalCopies = 3;
for (var i=0; i
User prompt
En büyük sorun, arka planları oluştururken ve konumlandırırken anchorX = 0.5 (merkez referansı) kullanmanız. Bu durumda, her arka planın x değeri görselin merkezini ifade ediyor; ayrıca flipX uygulayınca da görselin kenarları tam üst üste gelmiyor. İstediğiniz “yan yana dikişsiz (solda normal, sağda ayna yansıması) efektini” elde etmek için: anchorX = 0 (veya anchorX = 1) kullanarak görselin sol (veya sağ) kenarını referans alın. Arka planları x = i * bgWidth şeklinde sıralayın. flipX uygulayacaksanız, ölçekte (scaleX = -1) veya flipX: true şeklinde sol/sağ kenar baz alınmalıdır. Güncelleme (scroll) aşamasında, soldan çıkan görseli en sağa koyarken yine aynı anchor ve aynı genişlik hesabını kullanın. Aşağıdaki örnek, anchorX=0 kullanarak, 3 kopya arka planı yan yana dizip, tek satırda ayna yansımasıyla (normal-mirrored-normal) sürekli kaydırır. Bu kodu mevcut projenize adapte ederseniz, “ortadaki çizgi kayması” sorunu ortadan kalkar. 1) Arka Plan Oluşturma (createInitialBackgrounds) js Kopyala Düzenle function createInitialBackgrounds() { var bgWidth = 2807.2; // Arka plan asset'inizin genişliği var totalCopies = 3; // Kaç kopya yan yana dizilecek for (var i = 0; i < totalCopies; i++) { // anchorX=0: sol kenar referansı var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, // Soldan sağa dizilecek x: i * bgWidth, y: 0 }); // i tekse aynalı (scaleX=-1) olsun, çiftse normal (scaleX=1) if (i % 2 === 1) { bg.scaleX = -1; // scaleX=-1 kullanırken, eğer anchorX=0 ise // görselin sağ kenarı x konumunda sabitlenir. // Bu nedenle x'i bir miktar ileri almanız gerekebilir: // bg.x = i * bgWidth + bgWidth; // (Opsiyonel, görselin tam bitişik görünmesi için) } else { bg.scaleX = 1; } bg.zIndex = 0; allBackgrounds.push(bg); game.addChild(bg); } } Önemli Nokta: anchorX=0 iken scaleX=-1 yaptığınızda, görsel “ters çevrilmiş” olarak sol kenardan çizilir. Bazen tam bitişik görünmesi için bg.x = i * bgWidth + bgWidth; gibi 1 birim kaydırmanız gerekebilir. Görselin kendi piksel içeriğine göre 1-2 piksel offset eklemek isteyebilirsiniz. Eğer görselinizin sağ kenarı ile sol kenarı arasında tam “seamless” bir geçiş yoksa, ortada hafif bir çizgi görebilirsiniz; bu görsel tasarımından kaynaklanır. 2) Kaydırma ve Yeniden Konumlandırma (game.update) js Kopyala Düzenle game.update = function () { // Diğer objelerin update fonksiyonları game.children.forEach(function (child) { if (child.update) { child.update(); } }); // Arka planları sola kaydırmak için hız var bgSpeed = 3.6; // Arka plan genişliği var bgWidth = 2807.2; // Tüm kopyaları sola kaydır allBackgrounds.forEach(function (bg) { bg.x -= bgSpeed; }); // Soldan tamamen çıkanları en sağa taşı allBackgrounds.forEach(function (bg) { // Görselin sol kenarı x konumunda. Dolayısıyla (bg.x + bgWidth) < 0 ise ekran dışına çıkmış demektir. if (bg.x + bgWidth <= 0) { // En sağdaki kopyanın x değerini bul var maxX = Math.max.apply(null, allBackgrounds.map(function (b) { return b.x; })); // Bu arka planı en sağın sağına yerleştir bg.x = maxX + bgWidth; // Tekrardan aynalama (flip) değişikliği yapmak isterseniz: // Kaçıncı kopya olduğunu bulup scaleX'i ayarlayabilirsiniz. // Basitçe scaleX'i ters çevirmek de bir pattern oluşturabilir. // bg.scaleX = (bg.scaleX === 1) ? -1 : 1; } }); // Z-index sıralaması (opsiyonel) game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; Bu yaklaşımda: anchorX=0 olduğu için, bg.x görselin sol kenarını ifade eder. Bir görselin bg.x + bgWidth <= 0 olduğu anda, ekranın solundan tamamen çıkmış demektir. O zaman onu en sağdaki kopyanın sağına (maxX + bgWidth) koyarak sonsuz bir döngü yaratırız. Aynalama (mirror) efekti için scaleX=-1 / scaleX=1 dönüşümlü kullanılabilir. “Tam ortada dikiş”in sorunsuz olması, görselin kenarlarının “tile” uyumlu olmasına da bağlıdır. 3) anchorX=0.5 Kullanmamanızın Nedeni Kodunuzda anchorX=0.5 kullandığınızda, x değeri arka planın merkezini ifade ediyor. Yan yana dizmeye çalıştığınızda: Birinci arka planın merkezi centerX() civarında, İkinci arka planın merkezi centerX() + bgWidth civarında, derken görsellerin kenarları tam birleşmeyebiliyor. Özellikle scaleX=-1 devreye girdiğinde, kenarlar üst üste gelmek yerine ya çakışıyor ya da arada boşluk oluşuyor. anchorX=0 ise, her arka planın sol kenarını x ile eşitliyor. Bu da “soldan sağa sıralama” ve “soldan çıkınca sağa atma” mantığını çok basitleştiriyor. 4) Görsel Tasarım (Seamless) Son olarak, eğer görselin sol ve sağ kenarları “seamless” değilse, ortada hafif bir dikiş çizgisi görebilirsiniz. Tam dikişsiz bir sonuç istiyorsanız, arka plan görselinizin kenarları tile uyumlu olmalı. Bazı durumlarda “mirrored” eklemede, görselin sağ kenarı ile sol kenarının kabaca simetrik olması yeterli olabilir. Fakat ormanda dağ resmi gibi bir görselde, kenarlar simetrik değilse “ortada bir dikey çizgi” görebilirsiniz. Bu, kodsal değil, görselin kendisinden kaynaklıdır. Özetle: anchorX=0 yapın, x=i*bgWidth diyerek kopyaları yan yana koyun, scaleX=-1 ile ayna yansıması uygulayın, Kaydırma sırasında soldan çıkanları “bg.x + bgWidth <= 0” koşuluyla en sağa yerleştirin, Dikiş hizası yine bozuksa, 1-2 piksel offset veya görseli “tile/mirror” uyumlu olacak şekilde düzenleyin. Bu değişiklikler sonrasında, “üstteki gibi kaymış” yerine, “alttaki gibi düzgün ortadan ayna yansımalı” bir sonuç elde edersiniz.
User prompt
İki arka planı (biri normal, diğeri yatayda ters çevrilmiş) tam ortada dikişsiz birleştirmek istiyorsanız, en kritik nokta: anchorX değerlerini doğru kullanmak, width (genişlik) hesaplarını doğru yapmak, İki görselin sağ ve sol kenarlarının tam üst üste gelmesini sağlamak. Aşağıdaki adımları takip ederek, üstteki gibi bir boşluk/uyumsuzluk yerine alttaki gibi düzgün birleştirme (seamless) elde edebilirsiniz. 1) Anchor Noktası Seçimi Arka planların birleşme noktası düzgün olsun istiyorsanız, genellikle anchorX=0 (sol kenar referansı) veya anchorX=1 (sağ kenar referansı) kullanılır. anchorX=0 (sol referans) → x koordinatı, görselin sol kenarını ifade eder. anchorX=1 (sağ referans) → x koordinatı, görselin sağ kenarını ifade eder. anchorX=0.5 (merkez referans) kullanırsanız, x değeri görselin ortasını ifade eder; bu da yan yana ekleme yaparken ekstra offset hesaplaması gerektirir. En pratik yol: Birinci arka plan (normal) anchorX=0 İkinci arka plan (mirrored) anchorX=0 (ya da anchorX=1, aşağıdaki örneğe göre karar verin) 2) Birinci Arka Plan (Normal) js Kopyala Düzenle self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); Burada x=0, anchorX=0 olduğu için bg1 tam sol üstten başlar. 3) İkinci Arka Plan (Mirrored) Yöntem A: anchorX=0, scaleX=-1 Eğer ikisini de anchorX=0 yapacaksanız, ikinci arka planın x konumunu birincinin genişliği kadar sağa koymanız gerekir. Çünkü scaleX=-1 demek, görselin sol kenarının (anchorX=0 noktası) sabit kalıp, görselin sağa doğru ayna yansıması almasıdır. Örnek: js Kopyala Düzenle // bg2: mirrored self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // Yatayda ters çevir self.bg2.x = self.bg1.width; // bg1'in sağ kenarına dayıyoruz self.bg2.y = 0; self.addChild(self.bg2); Bu sayede, bg1 solda (normal), bg2 onun hemen sağında (mirrored) durur. Aradaki dikiş çizgisi tam olarak bg1.width noktasına denk gelir. Dikkat: scaleX=-1 kullandığınızda, anchorX=0 görselin sol kenarını sabitler. Dolayısıyla görselin sağ kenarı (mirror sonucu) x koordinatının solunda kalır. Yine de tam bitişik görünmesi için bg2.x = bg1.width; yapmak genellikle yeterli olur. Eğer küçük bir piksel kayması görürseniz, 1-2 piksel ayar yapabilirsiniz. Yöntem B: anchorX=1, scaleX=-1 İkinci bir yaklaşım ise anchorX=1 vererek görselin sağ kenarını referans almak. O zaman bg2.x değerini direkt bg1.width yapınca, bu sefer anchor noktası sağ kenar olduğu için her iki görselin birleşimi yine düzgün olur. js Kopyala Düzenle self.bg2 = LK.getAsset('background', { anchorX: 1, anchorY: 0 }); self.bg2.scaleX = -1; self.bg2.x = self.bg1.width; self.bg2.y = 0; Bu yöntemde, x değeri görselin sağ kenarını ifade eder. scaleX=-1 olduğu için, resim o sağ kenar noktasından sola doğru yansıtılır. Hangisi Kolay? Genelde Yöntem A (ikisini de anchorX=0 yapma) daha az kafa karıştırır. Yöntem B de çalışır ama anchorX=1 kavramı bazen offset’leri karıştırabilir. 4) Ortadaki Dikişin Uyuşmaması Eğer görselin sol kenarı ile sağ kenarı görselin kendisinde tam simetrik değilse (örneğin dağ resmi solda ve sağda farklıysa), tam ortada ayna yansıması “garip” görünebilir. Bu tamamen görselin kendisiyle ilgilidir. “Seamless” (dikişsiz) bir efekt için, görselin sol ve sağ kenarlarının simetrik veya uyumlu olması gerekir. Örneğin, dağ resminin sol kenarında ağaç var ama sağ kenarında yoksa, ortada bariz bir çizgi görebilirsiniz. Tam bir “mirror” illüzyonu istiyorsanız, görselinizin sağ kenarının sol kenarıyla neredeyse aynı dokuda olması veya tam tersi kenarları “fade” ile harmanlanmış olması gerek. Eğer tamamen “dikişsiz” (tiling) bir resim isteniyorsa, resim tasarım aşamasında “wrap around” (soldan sağa tekrarlandığında kesintisiz) olacak şekilde hazırlanmalı. 5) Kod Örneği Aşağıda, “üstteki gibi değil, alttaki gibi” bir sonuç almak için en sade örnek: js Kopyala Düzenle var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // Örnek: arka planın orijinal genişliği var bgWidth = 2807.2; // bg1: normal self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); // bg2: mirrored self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // bg1'in genişliği kadar sağa koy self.bg2.x = bgWidth; self.bg2.y = 0; self.addChild(self.bg2); self.speed = 3.6; self.update = function () { // Her frame sola kaydır self.bg1.x -= self.speed; self.bg2.x -= self.speed; // Soldan çıkanları sağa at if (self.bg1.x + bgWidth <= 0) { self.bg1.x = self.bg2.x + bgWidth; } if (self.bg2.x + bgWidth <= 0) { self.bg2.x = self.bg1.x + bgWidth; } }; return self; }); Bu kodda: Dikiş çizgisi tam bg1.width noktasında. bg2 “mirror” olduğu için sağ kenarı, sol kenarla uyumlu bir biçimde görüntülenir. Eğer görselinizin kenarları simetrik değilse, ortada bariz bir “dikey çizgi” fark edebilirsiniz. Bu görsel kaynaklıdır. Sonuç anchorX=0 + scaleX=-1 + doğru x konumu = alttaki gibi ortadan “mirror” efekti alırsınız. Görselin kenarları uyumlu değilse, tam ortada (veya kenarlarda) boşluk ya da görsel kırılması olabilir. Bu, görselin “seamless” (dikişsiz) tasarlanmadığından kaynaklanır. Kodda yapmanız gereken temel değişiklik: İki arka plan da anchorX=0 olsun. İkinci arka plan scaleX=-1 yapılıp, x=bgWidth değerine konulsun. Kaydırma (scroll) kodunda soldan çıkanları yine + bgWidth kadar sağa atın. Bu şekilde, üstteki resimdeki gibi bir boşluk veya yanlış hizalama yerine, alttaki gibi düzgün, ortadan ayna yansıması elde edersiniz.
User prompt
“FAILURE: Integration failed, target source not found” hatası, kod parçacığını projenize eklerken hedef dosya veya mevcut değişkenler/işlevler bulunamadığında ortaya çıkabilir. Bu genellikle: Kodun eklenmesi gereken yanlış dosyaya ya da yanlış yere yapıştırılması, Kodun referans aldığı değişkenlerin (örneğin allBackgrounds, backgroundsDuplicated, centerX, groundY vb.) tanımlı olmaması, Daha önce tanımlanmış bir fonksiyonu veya değişkeni (örneğin duplicateBackgrounds) yeniden tanımlamaya çalışmak, Veya otomatik bir “kod birleştirme (merge)” aracının projenin mevcut yapısını algılayamaması gibi durumlardan kaynaklanabilir. Aşağıdaki adımları izleyerek, verdiğiniz kod parçacığını (arka planın “dizi” mantığıyla oluşturulması ve hareket ettirilmesi) sorunsuzca entegre edebilirsiniz. Böylece “FAILURE” hatası büyük ihtimalle ortadan kalkacaktır. 1) Gerekli Değişkenleri Tanımlayın Kodunuzda kullandığınız, ancak başka bir yerde tanımlanmamış değişkenleri (örneğin allBackgrounds, backgroundsDuplicated) mutlaka global veya uygun bir scope’ta tanımlamalısınız. Örneğin: js Kopyala Düzenle // Global değişkenler (kodun en üstünde tanımlayın): var allBackgrounds = []; var backgroundsDuplicated = false; Böylece createInitialBackgrounds() fonksiyonu içinde allBackgrounds ve backgroundsDuplicated gibi değişkenlere erişilebilir olur. Ayrıca, centerX() ve centerY() fonksiyonları, groundY, menuOpen, gameWait, gameOver, gameStarted gibi değişken/fonksiyonlar da kodunuzun başka yerlerinde tanımlı olmalıdır. Eğer tanımlı değillerse, bu değerleri ya eklemeli ya da sabit bir sayı kullanmalısınız. Örneğin: js Kopyala Düzenle function centerX() { return 2048 / 2; } function centerY() { return 2732 / 2; } var groundY = 2732; var menuOpen = true; var gameWait = false; var gameOver = false; var gameStarted = false; (Elbette kendi oyununuzun boyutları ve mantığına göre düzenleyin.) 2) “createInitialBackgrounds” Fonksiyonunu Doğru Yere Yerleştirin Verdiğiniz fonksiyon: js Kopyala Düzenle function createInitialBackgrounds() { var bgWidth = 2807.2; // ... var totalCopies = 3; for (var i = 0; i < totalCopies; i++) { var bg = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: centerX() + (i * bgWidth), y: groundY / 2, flipX: i % 2 === 1 // normal, flipped, normal... }); bg.zIndex = 0; allBackgrounds.push(bg); game.addChild(bg); } backgroundsDuplicated = true; } Bu fonksiyonu, oyun kodunuzun (örneğin // Initialize Game gibi bir yorum satırının) üst ya da alt kısmına ekleyin; ancak mutlaka allBackgrounds ve backgroundsDuplicated tanımlarından sonra gelsin. Daha önce duplicateBackgrounds adında bir fonksiyonunuz varsa ve artık kullanmıyorsanız, o fonksiyonu kaldırın veya bu fonksiyonla çakışmayacak şekilde ismini değiştirin. Ardından, oyunun başlangıcında (örneğin resetGame() sonrasında veya Initialize Game aşamasında) şu şekilde çağırın: js Kopyala Düzenle // Oyunun başlangıcında bir kez çalıştırın createInitialBackgrounds(); 3) game.update İçerisinde Arka Planları Kaydırın Kod parçacığında verdiğiniz game.update içeriğini (arka planların sola kayması ve yeniden konumlandırılması) kullanacaksanız, mevcut “scrollingBackground” gibi sınıf tabanlı bir arka plan kodunuz varsa onu kaldırmalısınız veya birbiriyle çakışmayacak şekilde düzenlemelisiniz. Örneğin: js Kopyala Düzenle game.update = function () { // Update all game objects game.children.forEach(function (child) { if (child.update) { child.update(); } }); // Arka planları sadece oyun başladıysa kaydır if (gameStarted && !gameOver) { var bgSpeed = 3.6; var bgWidth = 2807.2; // 1) Tüm background kopyalarını sola hareket ettir allBackgrounds.forEach(function (bg) { bg.x -= bgSpeed; }); // 2) Ekrandan çıkanları en sağa alıp flipX özelliğini değiştir allBackgrounds.forEach(function (bg) { if (bg.x < -bgWidth / 2) { var maxX = Math.max.apply(null, allBackgrounds.map(function (b) { return b.x; })); bg.x = maxX + bgWidth; bg.flipX = !bg.flipX; } }); } // Sıralama (zIndex) game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; Burada “scrollingBackground.update()” gibi başka bir çağrı varsa ve o da background’u kaydırıyorsa, ikisi çakışabilir. Bu nedenle, tek bir arka plan kaydırma mekanizması kullanın. Eğer “ScrollingBackground” sınıfı yerine bu “allBackgrounds” dizili yöntemi kullanacaksanız, “ScrollingBackground” sınıfını ve “scrollingBackground.update()” çağrısını kaldırabilirsiniz. 4) game.down İçindeki “duplicateBackgrounds” Referansını Kaldırın Daha önce duplicateBackgrounds() fonksiyonunu, menü kapandığında veya ekrana ilk tıklamada çağırıyordunuz. Artık createInitialBackgrounds() ile zaten 3 kopya arka plan oluşturduğumuz için, “duplicateBackgrounds” işlevine gerek kalmadı. Kodunuzda şöyle bir satır olabilir: js Kopyala Düzenle if (!menuOpen) { duplicateBackgrounds(); // <-- Bu satırı kaldırın } Bunu silmeniz veya yorum satırına almanız gerekir. Aksi takdirde “target source not found” gibi bir hata oluşabilir. 5) Entegrasyon Sonrası Kontrol Listesi Tanımlanmamış Değişkenler: Konsolda veya derleyicide “allBackgrounds is not defined” gibi bir hata alırsanız, var allBackgrounds = []; eklemeyi unutmuşsunuz demektir. Çift Fonksiyon Tanımı: createInitialBackgrounds fonksiyonunu bir yerde daha tanımlamıyorsanız emin olun. Menü Kapanınca Tekrar Arka Plan Oluşturma: Artık arka plan kopyalarını sadece bir kez (oyun açıldığında) oluşturuyoruz. Eğer menüden dönünce tekrar oluşturmak istiyorsanız, “resetGame” içinde de createInitialBackgrounds çağırabilirsiniz. Ancak, önceki kopyaları temizlemeniz (örneğin allBackgrounds = []; ve game.removeChild(...)) gerekir. Ekran Boyutu: Arka planınız 2807.2 piksel genişliğinde. Oyun ekranınız 2048 piksel ise, normalde soldan sağa yeterince kaplayacaktır. Fakat “y” konumunu (centerY vb.) ve “anchorX” değerlerini doğru ayarlayın ki ekranda boşluk kalmasın. Özet Adım 1: var allBackgrounds = []; var backgroundsDuplicated = false; gibi değişkenleri en üstte tanımlayın. Adım 2: createInitialBackgrounds() fonksiyonunu projeye ekleyip, oyunun başlangıcında bir kez çağırın. Adım 3: “scrollingBackground” vb. önceki arka plan kodlarını kaldırın veya devre dışı bırakın. Adım 4: game.update içinde allBackgrounds dizisindeki arka planları sola kaydırıp, ekran dışına çıkanları sağa yerleştirin. Adım 5: Kodun içinde “duplicateBackgrounds” çağrısı varsa kaldırın. Adım 6: “FAILURE: Integration failed” hâlâ alıyorsanız, büyük ihtimalle proje yapınızda kodu yanlış dosyaya yapıştırıyorsunuz veya otomatik bir “kod birleştirme” aracı, tanımlı olmayan fonksiyon/ değişken referanslarıyla çakışıyor. Kodun tamamını tek bir dosyada veya doğru scope’ta birleştirmeyi deneyin. Bu adımları uyguladıktan sonra, “FAILURE: Integration failed, target source not found” hatası ortadan kalkacak ve arka planınız sorunsuz şekilde oluşturulup, sola doğru kaymaya devam edecektir.
User prompt
ikinci arkaplanı yok et
User prompt
Siyah boşluğun oluşmasının tipik nedenleri şunlar olabilir: Arka planın genişliği ekran genişliğinden küçükse (veya en-boy oranları uyuşmuyorsa), kayma esnasında ekranda boşluk gözükebilir. İki arka planın (normal ve mirrored) birbirinden farklı hızlarda veya farklı offset hesaplarıyla kayması, zamanla senkron bozulmasına ve arada boşluk kalmasına yol açabilir. Arka planın anchorX / anchorY ayarları veya ölçeklendirme (scale) yanlış ayarlanmışsa, ekranda tam hizalanma sağlanamaz. Aşağıdaki adımları kontrol ederek siyah boşluğu engelleyebilirsiniz: 1) Arka Plan Genişliği ve Ekran Genişliği Arka plan görseli (background asset’inin width değeri: 2807.2) oyun ekranının (örneğin 2048 piksel genişliğinde) eninden büyük ya da en azından eşit olmalıdır. Aksi takdirde kaydırma esnasında boşluk kalabilir. Eğer arka plan görselinizin eni, ekran eninden azsa, görseli ölçeklendirebilirsiniz: js Kopyala Düzenle self.bg1.scaleX = self.bg1.scaleY = desiredScaleFactor; self.bg2.scaleX = -desiredScaleFactor; // mirrored self.bg2.scaleY = desiredScaleFactor; Burada desiredScaleFactor, görselin enini ekrana uyacak şekilde hesapladığınız bir orandır (örneğin 2048 / 2807.2 gibi). 2) Tek Bir Offset Değeriyle Kaydırma Her iki arka planı da aynı offset değeri üzerinden sola kaydırın. Böylece hız farklılığı veya senkron kaybı oluşmaz. Örnek kod: js Kopyala Düzenle var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // Arka plan görselinizin orijinal genişliği var bgWidth = 2807.2; // Tek bir offset değeri self.offset = 0; // Kayma hızı (Tube/Tree ile aynı olsun diye 3.6) self.speed = 3.6; // Arka plan 1 (anchorX = 0, anchorY = 0) self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); // Arka plan 2 (mirrored) self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // Arka plan 2’nin sol kenarı, arka plan 1’in sağ kenarına denk gelir self.bg2.x = bgWidth; self.bg2.y = 0; self.addChild(self.bg2); // update fonksiyonu self.update = function () { // offset değerini sola kaydır self.offset += self.speed; // Arka planın genişliğine göre mod alarak sıfırla self.offset = self.offset % bgWidth; // bg1 ve bg2'nin x konumlarını aynı offset üzerinden ayarla self.bg1.x = -self.offset; self.bg2.x = self.bg1.x + bgWidth; }; return self; }); Bu yöntemle: Arka planlar tek bir hız (3.6) ve tek bir offset değeri üzerinden kayar. Bir tanesi diğerinden daha hızlı hareket edemez; çünkü offset herkes için aynıdır. bg1.x = -offset; bg2.x = bg1.x + bgWidth; mantığıyla herhangi bir senkron kaybı önlenir. Not: Eğer hâlâ siyah boşluk görüyorsanız, büyük ihtimalle görselin eni (veya ölçeklendirilmiş eni) ekran eninden küçük kalıyordur. Bu durumda, görseli genişletmek veya ek kopyalar (3, 4, vb.) kullanmak gerekebilir. 3) Ölçeklendirme (Scale) ve Anchor Ayarları Arka planınızın en-boy oranı, ekranınızın en-boy oranından çok farklıysa, üstte veya altta da boşluk oluşabilir. Bu durumda scaleX / scaleY değerlerini dinamik olarak hesaplayıp, ekrana tam sığacak şekilde ayarlamalısınız. Anchor noktalarını (örneğin anchorX: 0, anchorY: 0) tutarak, hesaplamaları offset yöntemiyle yapabilirsiniz. 4) Ekran Boyutu ve Aset Boyutu Son olarak, oyunun kurulduğu boyut (2048x2732) ile background görselinin boyutu (2807.2x2638.77) birbiriyle uyuşuyor mu diye bakın. Arka planın yüksekliği (2638.77) oyunun yüksekliğinden (2732) biraz küçükse veya eninde/ölçekte farklılık varsa, ufak siyah kenarlar oluşabilir. Bu durumda background.scale.set() ile boyutları ayarlayıp, tam ekrana sığdırmak en temiz çözüm olacaktır. Özet Arka planın eni, ekran enine eşit veya daha büyük olmalı (gerekirse ölçekleyin). Tek offset değeriyle her iki arka planın x konumunu hesaplayın. Böylece biri hızlı, diğeri yavaş olmaz. AnchorX/AnchorY = 0,0 ve scaleX = -1 (mirrored) kullanarak hizayı koruyun. En-boy oranlarını kontrol edin, gerekirse scale ile ekrana tam uyum sağlayın. Bu şekilde siyah boşluklar olmadan, arka planlarınız tube/tree ile aynı hızda ve sürekli akış hâlinde ilerleyecektir.
User prompt
Bu tip kaydırma işlemlerinde, her iki arka planı da ayrı ayrı hareket ettirip, yeniden konumlandırmaya çalışmak bazen dengesizliklere yol açabiliyor. Bu sorunu çözmek için tek bir "offset" (kaydırma) değeri kullanarak, arka planların x konumunu hesaplayabilirsiniz. Aşağıdaki kod, her iki arka planın da aynı offset değerine göre konumlanmasını sağlar: js Kopyala Düzenle /**** ScrollingBackground Class - Sabit Hız ve Offset Yöntemi ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // Arka plan genişliği (asset'teki değere göre ayarlayın) self.bgWidth = 2807.2; // Sabit bir offset değeri self.offset = 0; // Hız: Tube/Tree hızıyla aynı (3.6) self.speed = 3.6; // İlk arka plan: normal görüntü, sol üst köşe referansı self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.addChild(self.bg1); // İkinci arka plan: aynalı (mirrored) görüntü self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // yatayda ters çevirme self.addChild(self.bg2); self.update = function () { // Offset'u güncelle: sabit hızla sola doğru kaydır self.offset += self.speed; // Offset, bgWidth kadar arttığında mod alma ile sıfırlanır self.offset = self.offset % self.bgWidth; // bg1'in x konumunu hesapla (sola kaydırılmış offset) self.bg1.x = -self.offset; // bg2, bg1'in hemen sağına gelecek şekilde konumlandırılır self.bg2.x = self.bg1.x + self.bgWidth; }; }); Nasıl Çalışır? Tek Offset Değeri: self.offset tüm arka planların kayma miktarını takip eder. Her update çağrısında bu değer self.speed kadar artar. Mod Alma: Offset, arka plan genişliğine (bgWidth) göre mod alınır, bu sayede offset değeri sürekli artarken hep 0 ile bgWidth arasında kalır. Konum Hesaplama: bg1.x = –offset, ve bg2.x = bg1.x + bgWidth şeklinde hesaplanır. Böylece iki görüntü sabit aralıkla, tam bitişik şekilde hareket eder. Bu yöntemle, hem normal hem de mirrored arka planlar aynı offset değerine göre konumlandığından, hiçbirinin diğerinden farklı hızda hareket etmesi söz konusu olmayacaktır. Kullanım: Arka planı oyuna eklemek ve game.update döngüsünde güncellemek için: js Kopyala Düzenle var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); game.update = function () { scrollingBackground.update(); // Diğer update işlemleri... game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; Bu sayede arka planlar Tube, Tree gibi objelerle aynı hızda (3.6 piksel/saniye) sabit bir şekilde sola kayacaktır.
User prompt
Aşağıdaki tek parça kod, arka planların (normal ve mirrored) Tube ve Tree’lerin hızında (3.6 piksel/saniye) sola doğru kaymasını sağlar: js Kopyala Düzenle /**** ScrollingBackground Class - Mirrored & Fixed Speed ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // İlk arka plan: normal görüntü, sol üst köşe referansı (anchorX: 0, anchorY: 0) self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); // İkinci arka plan: aynalı görüntü self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); // Yatayda ters çevir self.bg2.scaleX = -1; // bg2'nin sol kenarı, bg1'nin sağ kenarı ile hizalanır self.bg2.x = self.bg1.width; self.bg2.y = 0; self.addChild(self.bg2); // Tube ve Tree hızına eşit hale getirmek için hız sabiti 3.6 olarak ayarlandı self.speed = 3.6; self.update = function () { // Her iki arka planı sola kaydır self.bg1.x -= self.speed; self.bg2.x -= self.speed; // Eğer bg1 tamamen soldan çıkmışsa, bg2'nin sağına yeniden yerleştir if (self.bg1.x + self.bg1.width <= 0) { self.bg1.x = self.bg2.x + self.bg2.width; } // Aynı şekilde bg2 için if (self.bg2.x + self.bg2.width <= 0) { self.bg2.x = self.bg1.x + self.bg1.width; } }; }); /**** Initialize Game ****/ var game = new LK.Game({ width: 2048, height: 2732, backgroundColor: 0x000000 }); /**** Create and Add Scrolling Background ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); /**** Example Game Update Loop ****/ game.update = function () { // Arka planı tube/tree hızıyla güncelle scrollingBackground.update(); // Diğer güncelleme işlemleri burada yapılabilir... // Z-index sıralaması (varsa) game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); }; LK.stage.addChild(game); Açıklama: Asset Ayarları: bg1 normal görüntü olarak yükleniyor. bg2 ise scaleX = -1 ile yatayda ters çevrilip, bg1.width kadar sağa konumlandırılıyor. Hız: self.speed = 3.6 olarak ayarlandı; Tube ve Tree sınıflarındaki velocityX değeriyle aynı. Böylece tüm objeler aynı hızda sola kayar. Yeniden Konumlandırma: Bir arka plan tamamen soldan çıkarsa, diğerinin hemen sağına yerleştiriliyor. Bu sayede kesintisiz bir akış elde ediliyor. Bu kodu oyununuzun diğer bölümleriyle birleştirirseniz, arka planlar Tube, Tree ve diğer objelerle aynı hızda sabit şekilde sola hareket edecektir.
User prompt
arkaplanların hepsinin hızı aynı olsun
User prompt
Aşağıdaki kod, arka planın bir kopyasını normal (d) ve diğer kopyasını yatayda ters (b) olarak oluşturup, sürekli sola kaydırarak birbirinin aynalı halini (örneğin "d" ve "b") verecektir: js Kopyala Düzenle /**** ScrollingBackground Class - Mirrored Effect ****/ var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // İlk arka plan: Normal görüntü, sol üst köşe referansı (anchorX: 0) self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); // İkinci arka plan: Aynalı (mirrored) görüntü. // Aynalı olması için scaleX değeri -1, anchorX yine 0 (sol kenar referansı) olarak ayarlanır. self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // bg2'nin sağ kenarı, bg1'nin sağ kenarı ile aynı konumda olacak şekilde yerleştiriyoruz. self.bg2.x = self.bg1.width; self.bg2.y = 0; self.addChild(self.bg2); // Arka planın sola kayma hızı; Tube ve Tree ile aynı hıza ayarlamak için değeri güncelleyebilirsiniz. self.speed = 3.6; self.update = function () { // Her iki arka planı sola kaydır self.bg1.x -= self.speed; self.bg2.x -= self.speed; // Eğer bg1 tamamen soldan çıkmışsa, bg2'nin sağına yeniden yerleştir if (self.bg1.x + self.bg1.width <= 0) { self.bg1.x = self.bg2.x + self.bg2.width; } // Aynı şekilde bg2 için if (self.bg2.x + self.bg2.width <= 0) { self.bg2.x = self.bg1.x + self.bg1.width; } }; }); /**** Initialize Game ****/ var game = new LK.Game({ width: 2048, height: 2732, backgroundColor: 0x000000 }); /**** Create and Add Scrolling Background ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); /**** Game Update Loop ****/ game.update = function () { scrollingBackground.update(); // Buraya diğer oyun güncelleme kodlarınızı ekleyebilirsiniz... }; LK.stage.addChild(game); Açıklama: Anchor Ayarı: İlk arka plan (bg1) sol üst köşe referansı (anchorX: 0) ile oluşturulur. İkinci arka plan (bg2) da aynı anchor değeriyle oluşturulur fakat scaleX değeri -1 yapılarak yatayda ters çevrilir. Böylece bg1 ile bg2 "d" ve "b" şeklinde birbirinin aynısı (ayna yansıması) elde edilir. Konumlandırma: bg2, bg1.width kadar sağa yerleştirilir. Böylece bg1'nin sağ kenarı ile bg2'nin sol kenarı aynı hizada olur. Hareket ve Döngü: Her update çağrısında, her iki arka plan da belirlenen hızla sola kayar. Bir arka plan tamamen ekran dışına çıktığında, diğeriyle bitişik olacak şekilde sağa yeniden konumlandırılır. Bu kod parçası, arka planınızın sürekli akışta, ayna yansıması şeklinde görüntülenmesini sağlayacaktır. İhtiyacınıza göre hız veya konumlandırma değerlerini güncelleyebilirsiniz.
/**** * Classes ****/ // Character: Dokunulduğunda zıplar. var Character = Container.expand(function () { var self = Container.call(this); self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.zIndex = 4; self.velocityY = 0; self.gravity = 0.3; self.jumpStrength = -12; self.width = 350; self.height = 300; self.update = function () { if (gameStarted && !gameOver) { self.velocityY += self.gravity; self.y += self.velocityY; if (self.y > groundY - 100) { self.y = groundY - 100; self.velocityY = 0; if (!self.intersects(underscoreAsset) && !self.preventDeath) { gameOver = true; endGame(); } } var characterLeft = self.x - self.width / 2; var characterRight = self.x + self.width / 2; var characterTop = self.y - self.height / 2; var characterBottom = self.y + self.height / 2; // Ekran dışına çıkma kontrolü if (characterLeft + self.width / 2 < 0 || characterRight - self.width / 2 > screenRight || characterTop + self.height / 2 < 0 || characterBottom - self.height / 2 > groundY) { gameOver = true; endGame(); } // Çarpışma kontrolü: Tube ve Tree game.children.forEach(function (child) { if (child instanceof Tube) { var tubeLeft = child.x - child.bottomTube.width / 2; var tubeRight = child.x + child.bottomTube.width / 2; var safeGapLowerEdge = child.y - child.bottomTube.height; var safeGapUpperEdge = -gapOffset + child.topTube.height; if (self.x + self.width / 2 > tubeLeft && self.x - self.width / 2 < tubeRight) { if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) { if (!self.intersects(underscoreAsset) && !self.preventDeath) { // Check if not intersecting with underscore asset and preventDeath is not true gameOver = true; endGame(); } else { // If intersecting with underscore asset or preventDeath is true, do not trigger game over return; } } } } else if (child instanceof Tree) { var treeLeft = child.x - child.bottomTree.width / 2; var treeRight = child.x + child.bottomTree.width / 2; var safeGapLowerEdge = child.y - child.bottomTree.height; var safeGapUpperEdge = -gapOffset + child.topTree.height; if (self.x + self.width / 2 > treeLeft && self.x - self.width / 2 < treeRight) { if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) { if (!self.intersects(underscoreAsset) && !self.preventTreeDeath) { // Check if not intersecting with underscore asset and preventTreeDeath is not true gameOver = true; endGame(); } } } } }); } }; self.jump = function () { if (!gameOver) { self.velocityY = self.jumpStrength; } }; return self; }); // GameOverText class var GameOverText = Container.expand(function () { var self = Container.call(this); self.text = new Text2("GAME OVER", { fontFamily: "Arial", fontSize: 2250, fill: 0xFF0000, align: "center", fontWeight: "bold" }); self.text.anchorX = 0.5; self.text.anchorY = 0.5; self.addChild(self.text); self.zIndex = 100; return self; }); // ScrollingBackground class - Mirrored Effect var ScrollingBackground = Container.expand(function () { var self = Container.call(this); // İlk arka plan: Normal görüntü, sol üst köşe referansı (anchorX: 0) self.bg1 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg1.x = 0; self.bg1.y = 0; self.addChild(self.bg1); // İkinci arka plan: Aynalı (mirrored) görüntü. // Aynalı olması için scaleX değeri -1, anchorX yine 0 (sol kenar referansı) olarak ayarlanır. self.bg2 = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); self.bg2.scaleX = -1; // bg2'nin sağ kenarı, bg1'nin sağ kenarı ile aynı konumda olacak şekilde yerleştiriyoruz. self.bg2.x = self.bg1.width; self.bg2.y = 0; self.addChild(self.bg2); // Arka planın sola kayma hızı; Tube ve Tree ile aynı hıza ayarlamak için değeri güncelleyebilirsiniz. self.speed = 3.6; self.update = function () { // Her iki arka planı sola kaydır self.bg1.x -= self.speed; self.bg2.x -= self.speed; // Eğer bg1 tamamen soldan çıkmışsa, bg2'nin sağına yeniden yerleştir if (self.bg1.x + self.bg1.width <= 0) { self.bg1.x = self.bg2.x + self.bg2.width; } // Aynı şekilde bg2 için if (self.bg2.x + self.bg2.width <= 0) { self.bg2.x = self.bg1.x + self.bg1.width; } }; }); // Tree class: Üst ve alt ağaç oluşturma var Tree = Container.expand(function () { var self = Container.call(this); var bottomUnit = Math.floor(Math.random() * 8) + 1; var topUnit = 9 - bottomUnit; var unitSize = groundY / totalUnits; var bottomHeight = bottomUnit * unitSize; var topHeight = topUnit * unitSize; self.y = groundY; self.bottomTree = self.attachAsset('tree', { anchorX: 0.5, anchorY: 1, width: 300, height: bottomHeight, flipY: false }); self.topTree = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5, width: 300, height: topHeight, flipY: false }); self.topTree.rotation = Math.PI; self.topTree.y = -groundY - gapOffset + topHeight / 2; self.zIndex = 1; self.x = 2048 + 800; self.velocityX = -3.6; self.spawned = false; self.prevX = self.x; self.update = function () { if (gameStarted && !gameOver) { self.x += self.velocityX; // Sırayla ağaç-boru üretimi if (!self.spawned && self.prevX > treeSpawnThreshold && self.x <= treeSpawnThreshold) { self.spawned = true; var newTube = new Tube(); newTube.x = 2048 + 800; game.addChild(newTube); lastSpawner = newTube; } self.prevX = self.x; // Geçme sayacı if (!self.passed && character.x > self.x + self.bottomTree.width / 2) { self.passed = true; updateScore(); } } }; return self; }); // Tube class: Üst ve alt boru oluşturma var Tube = Container.expand(function () { var self = Container.call(this); var bottomUnit = Math.floor(Math.random() * 8) + 1; var topUnit = 9 - bottomUnit; var unitSize = groundY / totalUnits; var bottomHeight = bottomUnit * unitSize; var topHeight = topUnit * unitSize; self.y = groundY; self.bottomTube = self.attachAsset('tube', { anchorX: 0.5, anchorY: 1, width: 300, height: bottomHeight, flipY: false }); self.topTube = self.attachAsset('tube', { anchorX: 0.5, anchorY: 0.5, width: 300, height: topHeight, flipY: false }); self.topTube.rotation = Math.PI; self.topTube.y = -groundY - gapOffset + topHeight / 2; self.zIndex = 1; self.x = 2048 + 800; self.velocityX = -3.6; self.spawned = false; self.prevX = self.x; self.update = function () { if (gameStarted && !gameOver) { self.x += self.velocityX; // Sırayla boru-ağaç üretimi if (!self.spawned && self.prevX > tubeSpawnThreshold && self.x <= tubeSpawnThreshold) { self.spawned = true; var newTree = new Tree(); newTree.x = 2048 + 800; game.addChild(newTree); lastSpawner = newTree; } self.prevX = self.x; // Geçme sayacı if (!self.passed && character.x > self.x + self.bottomTube.width / 2) { self.passed = true; updateScore(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); var underscoreAsset = LK.getAsset('_', { anchorX: 0.5, anchorY: 0.5, x: centerX() + 1000, y: centerY() }); underscoreAsset.zIndex = 15000; game.addChild(underscoreAsset); // Add click event to underscore asset underscoreAsset.on('down', function () { // Increment the touch counter underscoreTouchCount++; // Enable preventDeath if touched 5 times if (underscoreTouchCount >= 5) { character.preventDeath = true; character.preventTreeDeath = true; // New flag to prevent death by tree } }); game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); function createCloseButton() { // Close button’un kendi container’ı: var closeButtonContainer = new Container(); closeButtonContainer.zIndex = 9999; // Diğer her şeyin üstünde olsun // Close butonu için ellipse (shape) var closeShape = LK.getAsset('button_close', { anchorX: 0.5, anchorY: 0.5, width: 160 * 0.8, // Adjusted width to 80% of original height: 160 * 1.2 // Adjusted height to 120% of original }); closeButtonContainer.addChild(closeShape); // “X” metni var closeLabel = LK.getAsset('justX', { anchorX: 0.5, anchorY: 0.5, x: -6, // Moved 4 pixels left y: 2 // Moved 4 pixels up }); closeButtonContainer.addChild(closeLabel); return closeButtonContainer; } function zoomEffect() { // Mevcut scale değeri (örneğin orijinal 1) var originalScale = character.scale.x; // Zoom in: %20 artış character.scale.set(originalScale * 1.2); // 300ms sonra zoom out yap, orijinal scale'e dön LK.setTimeout(function () { character.scale.set(originalScale); }, 300); } // Dünyayı ters döndürme (flip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı function flipWorld() { if (flipped) { return; } flipped = true; // 0.3 saniye boyunca karakterin jump ve gravity etkilerini devre dışı bırak character.gravity = 0; character.jumpStrength = 0; zoomEffect(); LK.setTimeout(function () { // Ters dünyada: gravity -0.3, jumpStrength 12 character.gravity = -0.3; character.jumpStrength = 12; }, 300); // Dünya elemanlarını ters çevir (sadece scale yöntemiyle) background.scale.y *= -1; sky.scale.y *= -1; groundAsset.scale.y *= -1; ground2Asset.scale.y *= -1; } // Dünyayı eski hâline döndürme (unflip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı function unflipWorld() { if (!flipped) { return; } flipped = false; character.gravity = 0; character.jumpStrength = 0; zoomEffect(); LK.setTimeout(function () { // Normal dünyada: gravity 0.3, jumpStrength -12 character.gravity = 0.3; character.jumpStrength = -12; }, 300); // Dünya elemanlarını yeniden ters çevirerek orijinal haline döndür background.scale.y *= -1; sky.scale.y *= -1; groundAsset.scale.y *= -1; ground2Asset.scale.y *= -1; } // Skoru güncelleme fonksiyonu – Her 5 skorda flip/unflip toggle function updateScore() { passCounter++; counterText.setText(passCounter); if (passCounter % 5 === 0) { if (!flipped) { flipWorld(); } else { unflipWorld(); } } } /**** * Global Variables & Helper Functions ****/ var groundY = 2732; var menuOpen = true; var volumeOn = true; var records = []; // En iyi 5 skoru saklar var gapOffset = 400; var gameStarted = false; var gameOver = false; var gameWait = false; // Oyun menüden çıkıp da henüz başlamamışken true olacak. var screenRight = 2048; var totalUnits = 10; var tubeSpawnThreshold, treeSpawnThreshold; var lastSpawner = null; var gameOverText = null; var passCounter = 0; var lastScore = 0; // Global lastScore variable var underscoreTouchCount = 0; // Counter for underscore asset touches // Flip durumunu takip eden bayrak var flipped = false; function centerX() { return 2048 / 2; } function centerY() { return groundY / 2; } tubeSpawnThreshold = centerX() + (screenRight - centerX()) / 2; treeSpawnThreshold = centerX() + 3 * (screenRight - centerX()) / 4; /**** * Menu Setup ****/ var menuContainer = new Container(); menuContainer.zIndex = 200; // Menü arka planları var menuBackground = LK.getAsset('menu_background', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: centerY() }); menuBackground.zIndex = 200; menuContainer.addChild(menuBackground); var menuBackgroundPart = LK.getAsset('menu_background_part', { anchorX: 0.5, anchorY: 0.19, x: centerX(), y: centerY() }); menuBackgroundPart.zIndex = menuBackground.zIndex + 1; // 201 menuContainer.addChild(menuBackgroundPart); // When the menu is closed and the screen is clicked for the first time, // duplicate the current set of backgrounds to the right. function duplicateBackgrounds() { if (backgroundsDuplicated) { return; } backgroundsDuplicated = true; var bgWidth = 2807.2; // Get the number of copies in our current array var count = allBackgrounds.length; // Duplicate each background and place them to the right. for (var i = 0; i < count; i++) { var original = allBackgrounds[i]; var duplicate = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, // Place it immediately to the right of the rightmost background. x: original.x + count * bgWidth, y: original.y, // Flip it compared to the original. Here, you can simply reverse the flipX value. flipX: original.flipX ? 0 : 1 }); duplicate.zIndex = 0; allBackgrounds.push(duplicate); game.addChild(duplicate); } } var playButton = LK.getAsset('button_play', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 20, y: centerY() + 205 }); playButton.visible = false; menuContainer.addChild(playButton); var playLabel = new Text2("PLAY", { fontFamily: "Arial", fontSize: 630.25 * 1.1 * 1.08 * 1.5, fill: 0xffffff }); playLabel.anchorX = 0.5; playLabel.anchorY = 0.5; playLabel.x = playButton.x - 45; playLabel.y = playButton.y - -25; playLabel.visible = true; playLabel.zIndex = 1000; menuContainer.addChild(playLabel); // VOLUME var volumeButton = LK.getAsset('button_volume', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 28, y: centerY() + 310 }); volumeButton.visible = false; menuContainer.addChild(volumeButton); var volumeLabel = new Text2("VOLUME", { fontFamily: "Arial", fontSize: 63.25 * 1.1 * 1.05 * 1.05 * 1.05 * 1.5, fill: 0xffffff }); volumeLabel.anchorX = 0.5; volumeLabel.anchorY = 0.5; volumeLabel.x = volumeButton.x - 58; volumeLabel.y = volumeButton.y + 30; volumeLabel.visible = true; volumeLabel.zIndex = 1000; menuContainer.addChild(volumeLabel); // CREDITS var creditsButton = LK.getAsset('button_credits', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 30, y: centerY() + 429 }); creditsButton.visible = false; menuContainer.addChild(creditsButton); var creditsLabel = new Text2("CREDITS", { fontFamily: "Arial", fontSize: 630.25 * 1.05 * 1.05 * 1.05 * 1.5, fill: 0xffffff }); creditsLabel.anchorX = 0.5; creditsLabel.anchorY = 0.5; creditsLabel.x = creditsButton.x - 60; creditsLabel.y = creditsButton.y + 28; creditsLabel.visible = true; creditsLabel.zIndex = 1000; menuContainer.addChild(creditsLabel); // RECORDS var recordsButton = LK.getAsset('button_records', { anchorX: 0.5, anchorY: 0.5, x: centerX() - 30, y: centerY() + 540 }); recordsButton.visible = false; menuContainer.addChild(recordsButton); var recordsLabel = new Text2("RECORDS", { fontFamily: "Arial", fontSize: 150.25 * 1.05 * 1.05 * 1.03 * 1.05 * 1.5, fill: 0xffffff }); recordsLabel.anchorX = 0.5; recordsLabel.anchorY = 0.5; recordsLabel.x = recordsButton.x - 67; recordsLabel.y = recordsButton.y + 28; recordsLabel.visible = true; recordsLabel.zIndex = 1000; menuContainer.addChild(recordsLabel); // Ekranda sayacımız var counterText = new Text2('0', { size: 124.2, fill: 0xFFFFFF }); counterText.anchor.set(0, 0); counterText.x = 1315; counterText.y = 15; LK.gui.topLeft.addChild(counterText); // Arkaplanlar var scrollingBackground = new ScrollingBackground(); game.addChild(scrollingBackground); var sky = LK.getAsset('sky', { anchorX: 0.5, anchorY: 0, x: centerX(), y: 0 }); sky.zIndex = 2; game.addChild(sky); var groundAsset = LK.getAsset('ground', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: groundY - -25 }); groundAsset.zIndex = 4.1; game.addChild(groundAsset); var ground2Asset = LK.getAsset('ground2', { anchorX: 0.5, anchorY: 0.5, x: centerX(), y: groundY - 40 }); ground2Asset.zIndex = 0.5; game.addChild(ground2Asset); // Karakteri ekle var character = game.addChild(new Character()); character.x = centerX(); character.y = groundY / 2; // Menü container'ı biraz aşağı kaydırma menuContainer.y += 100; game.addChild(menuContainer); /**** * Helper Functions: Credits, Volume & Records ****/ function createCommonCloseElements(modalWidth, modalHeight) { var closeLabel = LK.getAsset('justX', { anchorX: 0.5, anchorY: 0.5, zIndex: 10000, x: 6, // Moved 4 pixels left y: 16 // Moved 4 pixels up }); var radius = 50; var closeButton = LK.getAsset('button_close', { anchorX: 0.5, anchorY: 0.5, width: radius * 2.3 * 1.2, height: radius * 2.3 * 1.2 }); closeButton.zIndex = 10000; closeButton.x = 0; // Center the button horizontally closeButton.y = 0; // Center the button vertically closeButton.addChild(closeLabel); return { closeLabel: closeLabel, closeButton: closeButton }; } function showCredits() { // Disable menu interaction when modal is opened menuOpen = false; var creditsContainer = new Container(); creditsContainer.zIndex = 300; var modalWidth = 1250, modalHeight = 2000; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); creditsContainer.addChild(bg); var creditsText = new Text2("Game by\nMustafa Talha ŞEN", { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff, align: "center" }); creditsText.anchorX = 0.5; creditsText.anchorY = 0.5; creditsText.x = centerX() - 359; creditsText.y = centerY() - 800 + 40; creditsText.scale.set(3, 3); creditsContainer.addChild(creditsText); // 5) creditsContainer’ı oyuna ekle game.addChild(creditsContainer); // 6) Close butonunu tamamen bağımsız ekle var closeButton = createCloseButton(); // Örneğin, modal’ın sağ üst köşesi olsun closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 160; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175; // Tıklanınca hem creditsContainer’ı hem close butonunu kaldır closeButton.on('down', function () { game.removeChild(creditsContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); // Close butonunu da oyuna ekle game.addChild(closeButton); } function showVolume() { // Disable menu interaction when modal is opened menuOpen = false; var volumeContainer = new Container(); volumeContainer.zIndex = 300; var modalWidth = 1250, modalHeight = 2000; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); volumeContainer.addChild(bg); var volumeText = new Text2("Volume Settings", { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff }); volumeText.scale.set(3, 3); volumeText.anchorX = 0.5; volumeText.anchorY = 0.5; volumeText.x = centerX() - 275; volumeText.y = centerY() - 800 + 85; volumeContainer.addChild(volumeText); // Container’ı oyuna ekle game.addChild(volumeContainer); // Close butonu bağımsız var closeButton = createCloseButton(); closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 159; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175; closeButton.on('down', function () { game.removeChild(volumeContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); game.addChild(closeButton); } function showRecords() { // Disable menu interaction when modal is opened menuOpen = false; var recordsContainer = new Container(); recordsContainer.zIndex = 300; var modalWidth = 1500, modalHeight = 2200; var bg = LK.getAsset('second_menu', { anchorX: 0.5, anchorY: 0.5, width: modalWidth, height: modalHeight, color: 0x000000 }); bg.x = centerX(); bg.y = centerY(); recordsContainer.addChild(bg); var recordsTextStr = "Top Scores:\n"; for (var i = 0; i < records.length; i++) { recordsTextStr += i + 1 + ". " + records[i].score + " (Attempt " + records[i].attempt + ")\n"; } if (records.length === 0) { recordsTextStr += "No records yet."; } recordsTextStr += "\nAttempts: " + records.length; recordsTextStr += "\nLast Score: " + lastScore; var recordsText = new Text2(recordsTextStr, { fontFamily: "Arial", fontSize: 5000 * 1.03, fill: 0xffffff, align: "center" }); recordsText.anchorX = 0.5; recordsText.anchorY = 0.5; recordsText.x = centerX() - 280; recordsText.y = centerY() - 850 + 40; recordsText.scale.set(3, 3); recordsContainer.addChild(recordsText); // Container’ı oyuna ekle game.addChild(recordsContainer); // Close butonu bağımsız var closeButton = createCloseButton(); closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 205; closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 195; closeButton.on('down', function () { game.removeChild(recordsContainer); game.removeChild(closeButton); // Enable menu interaction when modal is closed menuOpen = true; menuContainer.visible = true; }); game.addChild(closeButton); } /**** * End Game & Reset Functions ****/ function endGame() { LK.effects.flashScreen(0xFF0000, 500); character.velocityY = character.jumpStrength; character.update = function () { if (gameOver) { character.velocityY += character.gravity; character.y += character.velocityY; if (character.y > groundY + character.height) { character.y = groundY + character.height; character.velocityY = 0; } } }; game.children.forEach(function (child) { if (child.velocityX) { child.velocityX = 0; } }); game.touchDisabled = true; lastScore = passCounter; records.push({ score: passCounter, attempt: records.length + 1 }); records.sort(function (a, b) { return b.score - a.score; }); if (records.length > 5) { records = records.slice(0, 5); } LK.setTimeout(function () { game.touchDisabled = false; menuOpen = true; menuContainer.visible = true; var startY = groundY + 100; var endY = centerY() - 1270; var animationDuration = 16.5 * 5 / 1.5; var startTime = Date.now(); function animateMenu() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = Math.min(elapsedTime / animationDuration, 1); menuContainer.y = startY + (endY - startY) * progress; if (progress < 1) { LK.setTimeout(animateMenu, 16); } } animateMenu(); }, 1700); LK.setTimeout(function () { resetGame(); }, 1750); } function resetGame() { if (gameOverText) { game.removeChild(gameOverText); gameOverText = null; } // Flip'i eski hâline döndür unflipWorld(); var objectsToRemove = []; game.children.forEach(function (child) { if (child instanceof Tree || child instanceof Tube) { objectsToRemove.push(child); } }); objectsToRemove.forEach(function (obj) { game.removeChild(obj); }); game.removeChild(character); character = game.addChild(new Character()); character.x = centerX(); character.y = groundY / 2; gameStarted = false; gameOver = false; character.preventDeath = false; // Reset preventDeath flag underscoreAsset.preventDeath = false; // Reset preventDeath flag for underscore asset lastSpawner = null; passCounter = 0; underscoreTouchCount = 0; // Reset underscore touch count counterText.setText(passCounter); } /**** * Eliptik hit testi için yardımcı fonksiyon ****/ function checkEllipseHover(button, lx, ly) { var scaleFactorX = 1; var scaleFactorY = 0.53; var offsetY = 40; var dx = lx - button.x; var dy = ly - (button.y + offsetY); var rx = button.width / 2 * scaleFactorX; var ry = button.height / 2 * scaleFactorY; return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1; } /**** * Fare hareketinde hover kontrolü ****/ game.move = function (x, y, obj) { if (!menuOpen) { return; } // Modal açıkken hover efekti çalışmasın. var localX = x - menuContainer.x; var localY = y - menuContainer.y; playButton.visible = checkEllipseHover(playButton, localX, localY); volumeButton.visible = checkEllipseHover(volumeButton, localX, localY); creditsButton.visible = checkEllipseHover(creditsButton, localX, localY); recordsButton.visible = checkEllipseHover(recordsButton, localX, localY); }; /**** * Touch Event ****/ game.down = function (x, y, obj) { if (menuOpen) { var localX = x - menuContainer.x; var localY = y - menuContainer.y; if (checkEllipseHover(playButton, localX, localY)) { var _animateMenu = function animateMenu() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = Math.min(elapsedTime / animationDuration, 1); menuContainer.y = startY + (endY - startY) * progress; if (progress < 1) { LK.setTimeout(_animateMenu, 1); } else { menuOpen = false; menuContainer.visible = false; gameWait = true; } }; var animationDuration = 16.5 * 5 * 2 / 1.5; var startTime = Date.now(); var startY = menuContainer.y; var endY = centerY() + 100; _animateMenu(); return; } else if (checkEllipseHover(volumeButton, localX, localY)) { showVolume(); } else if (checkEllipseHover(creditsButton, localX, localY)) { showCredits(); } else if (checkEllipseHover(recordsButton, localX, localY)) { showRecords(); } return; } else if (gameOver) { if (!game.touchDisabled) { menuOpen = true; menuContainer.visible = true; resetGame(); } } else { if (!menuOpen) { // On the first click after the menu is closed, // duplicate the backgrounds if not done already. duplicateBackgrounds(); } if (gameWait) { gameWait = false; gameStarted = true; var initialTube = new Tube(); game.addChild(initialTube); lastSpawner = initialTube; character.jump(); } else { character.jump(); character.rotation = 0.1; LK.setTimeout(function () { character.rotation = 0; }, 200); } } }; /**** * Game Loop ****/ game.update = function () { game.children.forEach(function (child) { if (child.update) { child.update(); } }); scrollingBackground.update(); game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); };
/****
* Classes
****/
// Character: Dokunulduğunda zıplar.
var Character = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.zIndex = 4;
self.velocityY = 0;
self.gravity = 0.3;
self.jumpStrength = -12;
self.width = 350;
self.height = 300;
self.update = function () {
if (gameStarted && !gameOver) {
self.velocityY += self.gravity;
self.y += self.velocityY;
if (self.y > groundY - 100) {
self.y = groundY - 100;
self.velocityY = 0;
if (!self.intersects(underscoreAsset) && !self.preventDeath) {
gameOver = true;
endGame();
}
}
var characterLeft = self.x - self.width / 2;
var characterRight = self.x + self.width / 2;
var characterTop = self.y - self.height / 2;
var characterBottom = self.y + self.height / 2;
// Ekran dışına çıkma kontrolü
if (characterLeft + self.width / 2 < 0 || characterRight - self.width / 2 > screenRight || characterTop + self.height / 2 < 0 || characterBottom - self.height / 2 > groundY) {
gameOver = true;
endGame();
}
// Çarpışma kontrolü: Tube ve Tree
game.children.forEach(function (child) {
if (child instanceof Tube) {
var tubeLeft = child.x - child.bottomTube.width / 2;
var tubeRight = child.x + child.bottomTube.width / 2;
var safeGapLowerEdge = child.y - child.bottomTube.height;
var safeGapUpperEdge = -gapOffset + child.topTube.height;
if (self.x + self.width / 2 > tubeLeft && self.x - self.width / 2 < tubeRight) {
if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) {
if (!self.intersects(underscoreAsset) && !self.preventDeath) {
// Check if not intersecting with underscore asset and preventDeath is not true
gameOver = true;
endGame();
} else {
// If intersecting with underscore asset or preventDeath is true, do not trigger game over
return;
}
}
}
} else if (child instanceof Tree) {
var treeLeft = child.x - child.bottomTree.width / 2;
var treeRight = child.x + child.bottomTree.width / 2;
var safeGapLowerEdge = child.y - child.bottomTree.height;
var safeGapUpperEdge = -gapOffset + child.topTree.height;
if (self.x + self.width / 2 > treeLeft && self.x - self.width / 2 < treeRight) {
if (self.y < safeGapUpperEdge || self.y > safeGapLowerEdge) {
if (!self.intersects(underscoreAsset) && !self.preventTreeDeath) {
// Check if not intersecting with underscore asset and preventTreeDeath is not true
gameOver = true;
endGame();
}
}
}
}
});
}
};
self.jump = function () {
if (!gameOver) {
self.velocityY = self.jumpStrength;
}
};
return self;
});
// GameOverText class
var GameOverText = Container.expand(function () {
var self = Container.call(this);
self.text = new Text2("GAME OVER", {
fontFamily: "Arial",
fontSize: 2250,
fill: 0xFF0000,
align: "center",
fontWeight: "bold"
});
self.text.anchorX = 0.5;
self.text.anchorY = 0.5;
self.addChild(self.text);
self.zIndex = 100;
return self;
});
// ScrollingBackground class - Mirrored Effect
var ScrollingBackground = Container.expand(function () {
var self = Container.call(this);
// İlk arka plan: Normal görüntü, sol üst köşe referansı (anchorX: 0)
self.bg1 = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
self.bg1.x = 0;
self.bg1.y = 0;
self.addChild(self.bg1);
// İkinci arka plan: Aynalı (mirrored) görüntü.
// Aynalı olması için scaleX değeri -1, anchorX yine 0 (sol kenar referansı) olarak ayarlanır.
self.bg2 = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
self.bg2.scaleX = -1;
// bg2'nin sağ kenarı, bg1'nin sağ kenarı ile aynı konumda olacak şekilde yerleştiriyoruz.
self.bg2.x = self.bg1.width;
self.bg2.y = 0;
self.addChild(self.bg2);
// Arka planın sola kayma hızı; Tube ve Tree ile aynı hıza ayarlamak için değeri güncelleyebilirsiniz.
self.speed = 3.6;
self.update = function () {
// Her iki arka planı sola kaydır
self.bg1.x -= self.speed;
self.bg2.x -= self.speed;
// Eğer bg1 tamamen soldan çıkmışsa, bg2'nin sağına yeniden yerleştir
if (self.bg1.x + self.bg1.width <= 0) {
self.bg1.x = self.bg2.x + self.bg2.width;
}
// Aynı şekilde bg2 için
if (self.bg2.x + self.bg2.width <= 0) {
self.bg2.x = self.bg1.x + self.bg1.width;
}
};
});
// Tree class: Üst ve alt ağaç oluşturma
var Tree = Container.expand(function () {
var self = Container.call(this);
var bottomUnit = Math.floor(Math.random() * 8) + 1;
var topUnit = 9 - bottomUnit;
var unitSize = groundY / totalUnits;
var bottomHeight = bottomUnit * unitSize;
var topHeight = topUnit * unitSize;
self.y = groundY;
self.bottomTree = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1,
width: 300,
height: bottomHeight,
flipY: false
});
self.topTree = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: topHeight,
flipY: false
});
self.topTree.rotation = Math.PI;
self.topTree.y = -groundY - gapOffset + topHeight / 2;
self.zIndex = 1;
self.x = 2048 + 800;
self.velocityX = -3.6;
self.spawned = false;
self.prevX = self.x;
self.update = function () {
if (gameStarted && !gameOver) {
self.x += self.velocityX;
// Sırayla ağaç-boru üretimi
if (!self.spawned && self.prevX > treeSpawnThreshold && self.x <= treeSpawnThreshold) {
self.spawned = true;
var newTube = new Tube();
newTube.x = 2048 + 800;
game.addChild(newTube);
lastSpawner = newTube;
}
self.prevX = self.x;
// Geçme sayacı
if (!self.passed && character.x > self.x + self.bottomTree.width / 2) {
self.passed = true;
updateScore();
}
}
};
return self;
});
// Tube class: Üst ve alt boru oluşturma
var Tube = Container.expand(function () {
var self = Container.call(this);
var bottomUnit = Math.floor(Math.random() * 8) + 1;
var topUnit = 9 - bottomUnit;
var unitSize = groundY / totalUnits;
var bottomHeight = bottomUnit * unitSize;
var topHeight = topUnit * unitSize;
self.y = groundY;
self.bottomTube = self.attachAsset('tube', {
anchorX: 0.5,
anchorY: 1,
width: 300,
height: bottomHeight,
flipY: false
});
self.topTube = self.attachAsset('tube', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: topHeight,
flipY: false
});
self.topTube.rotation = Math.PI;
self.topTube.y = -groundY - gapOffset + topHeight / 2;
self.zIndex = 1;
self.x = 2048 + 800;
self.velocityX = -3.6;
self.spawned = false;
self.prevX = self.x;
self.update = function () {
if (gameStarted && !gameOver) {
self.x += self.velocityX;
// Sırayla boru-ağaç üretimi
if (!self.spawned && self.prevX > tubeSpawnThreshold && self.x <= tubeSpawnThreshold) {
self.spawned = true;
var newTree = new Tree();
newTree.x = 2048 + 800;
game.addChild(newTree);
lastSpawner = newTree;
}
self.prevX = self.x;
// Geçme sayacı
if (!self.passed && character.x > self.x + self.bottomTube.width / 2) {
self.passed = true;
updateScore();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var scrollingBackground = new ScrollingBackground();
game.addChild(scrollingBackground);
var underscoreAsset = LK.getAsset('_', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX() + 1000,
y: centerY()
});
underscoreAsset.zIndex = 15000;
game.addChild(underscoreAsset);
// Add click event to underscore asset
underscoreAsset.on('down', function () {
// Increment the touch counter
underscoreTouchCount++;
// Enable preventDeath if touched 5 times
if (underscoreTouchCount >= 5) {
character.preventDeath = true;
character.preventTreeDeath = true; // New flag to prevent death by tree
}
});
game.children.sort(function (a, b) {
return (a.zIndex || 0) - (b.zIndex || 0);
});
function createCloseButton() {
// Close button’un kendi container’ı:
var closeButtonContainer = new Container();
closeButtonContainer.zIndex = 9999; // Diğer her şeyin üstünde olsun
// Close butonu için ellipse (shape)
var closeShape = LK.getAsset('button_close', {
anchorX: 0.5,
anchorY: 0.5,
width: 160 * 0.8,
// Adjusted width to 80% of original
height: 160 * 1.2 // Adjusted height to 120% of original
});
closeButtonContainer.addChild(closeShape);
// “X” metni
var closeLabel = LK.getAsset('justX', {
anchorX: 0.5,
anchorY: 0.5,
x: -6,
// Moved 4 pixels left
y: 2 // Moved 4 pixels up
});
closeButtonContainer.addChild(closeLabel);
return closeButtonContainer;
}
function zoomEffect() {
// Mevcut scale değeri (örneğin orijinal 1)
var originalScale = character.scale.x;
// Zoom in: %20 artış
character.scale.set(originalScale * 1.2);
// 300ms sonra zoom out yap, orijinal scale'e dön
LK.setTimeout(function () {
character.scale.set(originalScale);
}, 300);
}
// Dünyayı ters döndürme (flip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı
function flipWorld() {
if (flipped) {
return;
}
flipped = true;
// 0.3 saniye boyunca karakterin jump ve gravity etkilerini devre dışı bırak
character.gravity = 0;
character.jumpStrength = 0;
zoomEffect();
LK.setTimeout(function () {
// Ters dünyada: gravity -0.3, jumpStrength 12
character.gravity = -0.3;
character.jumpStrength = 12;
}, 300);
// Dünya elemanlarını ters çevir (sadece scale yöntemiyle)
background.scale.y *= -1;
sky.scale.y *= -1;
groundAsset.scale.y *= -1;
ground2Asset.scale.y *= -1;
}
// Dünyayı eski hâline döndürme (unflip) fonksiyonu – 0.2 saniye boyunca jump/gravity devre dışı
function unflipWorld() {
if (!flipped) {
return;
}
flipped = false;
character.gravity = 0;
character.jumpStrength = 0;
zoomEffect();
LK.setTimeout(function () {
// Normal dünyada: gravity 0.3, jumpStrength -12
character.gravity = 0.3;
character.jumpStrength = -12;
}, 300);
// Dünya elemanlarını yeniden ters çevirerek orijinal haline döndür
background.scale.y *= -1;
sky.scale.y *= -1;
groundAsset.scale.y *= -1;
ground2Asset.scale.y *= -1;
}
// Skoru güncelleme fonksiyonu – Her 5 skorda flip/unflip toggle
function updateScore() {
passCounter++;
counterText.setText(passCounter);
if (passCounter % 5 === 0) {
if (!flipped) {
flipWorld();
} else {
unflipWorld();
}
}
}
/****
* Global Variables & Helper Functions
****/
var groundY = 2732;
var menuOpen = true;
var volumeOn = true;
var records = []; // En iyi 5 skoru saklar
var gapOffset = 400;
var gameStarted = false;
var gameOver = false;
var gameWait = false; // Oyun menüden çıkıp da henüz başlamamışken true olacak.
var screenRight = 2048;
var totalUnits = 10;
var tubeSpawnThreshold, treeSpawnThreshold;
var lastSpawner = null;
var gameOverText = null;
var passCounter = 0;
var lastScore = 0; // Global lastScore variable
var underscoreTouchCount = 0; // Counter for underscore asset touches
// Flip durumunu takip eden bayrak
var flipped = false;
function centerX() {
return 2048 / 2;
}
function centerY() {
return groundY / 2;
}
tubeSpawnThreshold = centerX() + (screenRight - centerX()) / 2;
treeSpawnThreshold = centerX() + 3 * (screenRight - centerX()) / 4;
/****
* Menu Setup
****/
var menuContainer = new Container();
menuContainer.zIndex = 200;
// Menü arka planları
var menuBackground = LK.getAsset('menu_background', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX(),
y: centerY()
});
menuBackground.zIndex = 200;
menuContainer.addChild(menuBackground);
var menuBackgroundPart = LK.getAsset('menu_background_part', {
anchorX: 0.5,
anchorY: 0.19,
x: centerX(),
y: centerY()
});
menuBackgroundPart.zIndex = menuBackground.zIndex + 1; // 201
menuContainer.addChild(menuBackgroundPart);
// When the menu is closed and the screen is clicked for the first time,
// duplicate the current set of backgrounds to the right.
function duplicateBackgrounds() {
if (backgroundsDuplicated) {
return;
}
backgroundsDuplicated = true;
var bgWidth = 2807.2;
// Get the number of copies in our current array
var count = allBackgrounds.length;
// Duplicate each background and place them to the right.
for (var i = 0; i < count; i++) {
var original = allBackgrounds[i];
var duplicate = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
// Place it immediately to the right of the rightmost background.
x: original.x + count * bgWidth,
y: original.y,
// Flip it compared to the original. Here, you can simply reverse the flipX value.
flipX: original.flipX ? 0 : 1
});
duplicate.zIndex = 0;
allBackgrounds.push(duplicate);
game.addChild(duplicate);
}
}
var playButton = LK.getAsset('button_play', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX() - 20,
y: centerY() + 205
});
playButton.visible = false;
menuContainer.addChild(playButton);
var playLabel = new Text2("PLAY", {
fontFamily: "Arial",
fontSize: 630.25 * 1.1 * 1.08 * 1.5,
fill: 0xffffff
});
playLabel.anchorX = 0.5;
playLabel.anchorY = 0.5;
playLabel.x = playButton.x - 45;
playLabel.y = playButton.y - -25;
playLabel.visible = true;
playLabel.zIndex = 1000;
menuContainer.addChild(playLabel);
// VOLUME
var volumeButton = LK.getAsset('button_volume', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX() - 28,
y: centerY() + 310
});
volumeButton.visible = false;
menuContainer.addChild(volumeButton);
var volumeLabel = new Text2("VOLUME", {
fontFamily: "Arial",
fontSize: 63.25 * 1.1 * 1.05 * 1.05 * 1.05 * 1.5,
fill: 0xffffff
});
volumeLabel.anchorX = 0.5;
volumeLabel.anchorY = 0.5;
volumeLabel.x = volumeButton.x - 58;
volumeLabel.y = volumeButton.y + 30;
volumeLabel.visible = true;
volumeLabel.zIndex = 1000;
menuContainer.addChild(volumeLabel);
// CREDITS
var creditsButton = LK.getAsset('button_credits', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX() - 30,
y: centerY() + 429
});
creditsButton.visible = false;
menuContainer.addChild(creditsButton);
var creditsLabel = new Text2("CREDITS", {
fontFamily: "Arial",
fontSize: 630.25 * 1.05 * 1.05 * 1.05 * 1.5,
fill: 0xffffff
});
creditsLabel.anchorX = 0.5;
creditsLabel.anchorY = 0.5;
creditsLabel.x = creditsButton.x - 60;
creditsLabel.y = creditsButton.y + 28;
creditsLabel.visible = true;
creditsLabel.zIndex = 1000;
menuContainer.addChild(creditsLabel);
// RECORDS
var recordsButton = LK.getAsset('button_records', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX() - 30,
y: centerY() + 540
});
recordsButton.visible = false;
menuContainer.addChild(recordsButton);
var recordsLabel = new Text2("RECORDS", {
fontFamily: "Arial",
fontSize: 150.25 * 1.05 * 1.05 * 1.03 * 1.05 * 1.5,
fill: 0xffffff
});
recordsLabel.anchorX = 0.5;
recordsLabel.anchorY = 0.5;
recordsLabel.x = recordsButton.x - 67;
recordsLabel.y = recordsButton.y + 28;
recordsLabel.visible = true;
recordsLabel.zIndex = 1000;
menuContainer.addChild(recordsLabel);
// Ekranda sayacımız
var counterText = new Text2('0', {
size: 124.2,
fill: 0xFFFFFF
});
counterText.anchor.set(0, 0);
counterText.x = 1315;
counterText.y = 15;
LK.gui.topLeft.addChild(counterText);
// Arkaplanlar
var scrollingBackground = new ScrollingBackground();
game.addChild(scrollingBackground);
var sky = LK.getAsset('sky', {
anchorX: 0.5,
anchorY: 0,
x: centerX(),
y: 0
});
sky.zIndex = 2;
game.addChild(sky);
var groundAsset = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX(),
y: groundY - -25
});
groundAsset.zIndex = 4.1;
game.addChild(groundAsset);
var ground2Asset = LK.getAsset('ground2', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX(),
y: groundY - 40
});
ground2Asset.zIndex = 0.5;
game.addChild(ground2Asset);
// Karakteri ekle
var character = game.addChild(new Character());
character.x = centerX();
character.y = groundY / 2;
// Menü container'ı biraz aşağı kaydırma
menuContainer.y += 100;
game.addChild(menuContainer);
/****
* Helper Functions: Credits, Volume & Records
****/
function createCommonCloseElements(modalWidth, modalHeight) {
var closeLabel = LK.getAsset('justX', {
anchorX: 0.5,
anchorY: 0.5,
zIndex: 10000,
x: 6,
// Moved 4 pixels left
y: 16 // Moved 4 pixels up
});
var radius = 50;
var closeButton = LK.getAsset('button_close', {
anchorX: 0.5,
anchorY: 0.5,
width: radius * 2.3 * 1.2,
height: radius * 2.3 * 1.2
});
closeButton.zIndex = 10000;
closeButton.x = 0; // Center the button horizontally
closeButton.y = 0; // Center the button vertically
closeButton.addChild(closeLabel);
return {
closeLabel: closeLabel,
closeButton: closeButton
};
}
function showCredits() {
// Disable menu interaction when modal is opened
menuOpen = false;
var creditsContainer = new Container();
creditsContainer.zIndex = 300;
var modalWidth = 1250,
modalHeight = 2000;
var bg = LK.getAsset('second_menu', {
anchorX: 0.5,
anchorY: 0.5,
width: modalWidth,
height: modalHeight,
color: 0x000000
});
bg.x = centerX();
bg.y = centerY();
creditsContainer.addChild(bg);
var creditsText = new Text2("Game by\nMustafa Talha ŞEN", {
fontFamily: "Arial",
fontSize: 5000 * 1.03,
fill: 0xffffff,
align: "center"
});
creditsText.anchorX = 0.5;
creditsText.anchorY = 0.5;
creditsText.x = centerX() - 359;
creditsText.y = centerY() - 800 + 40;
creditsText.scale.set(3, 3);
creditsContainer.addChild(creditsText);
// 5) creditsContainer’ı oyuna ekle
game.addChild(creditsContainer);
// 6) Close butonunu tamamen bağımsız ekle
var closeButton = createCloseButton();
// Örneğin, modal’ın sağ üst köşesi olsun
closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 160;
closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175;
// Tıklanınca hem creditsContainer’ı hem close butonunu kaldır
closeButton.on('down', function () {
game.removeChild(creditsContainer);
game.removeChild(closeButton);
// Enable menu interaction when modal is closed
menuOpen = true;
menuContainer.visible = true;
});
// Close butonunu da oyuna ekle
game.addChild(closeButton);
}
function showVolume() {
// Disable menu interaction when modal is opened
menuOpen = false;
var volumeContainer = new Container();
volumeContainer.zIndex = 300;
var modalWidth = 1250,
modalHeight = 2000;
var bg = LK.getAsset('second_menu', {
anchorX: 0.5,
anchorY: 0.5,
width: modalWidth,
height: modalHeight,
color: 0x000000
});
bg.x = centerX();
bg.y = centerY();
volumeContainer.addChild(bg);
var volumeText = new Text2("Volume Settings", {
fontFamily: "Arial",
fontSize: 5000 * 1.03,
fill: 0xffffff
});
volumeText.scale.set(3, 3);
volumeText.anchorX = 0.5;
volumeText.anchorY = 0.5;
volumeText.x = centerX() - 275;
volumeText.y = centerY() - 800 + 85;
volumeContainer.addChild(volumeText);
// Container’ı oyuna ekle
game.addChild(volumeContainer);
// Close butonu bağımsız
var closeButton = createCloseButton();
closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 159;
closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 175;
closeButton.on('down', function () {
game.removeChild(volumeContainer);
game.removeChild(closeButton);
// Enable menu interaction when modal is closed
menuOpen = true;
menuContainer.visible = true;
});
game.addChild(closeButton);
}
function showRecords() {
// Disable menu interaction when modal is opened
menuOpen = false;
var recordsContainer = new Container();
recordsContainer.zIndex = 300;
var modalWidth = 1500,
modalHeight = 2200;
var bg = LK.getAsset('second_menu', {
anchorX: 0.5,
anchorY: 0.5,
width: modalWidth,
height: modalHeight,
color: 0x000000
});
bg.x = centerX();
bg.y = centerY();
recordsContainer.addChild(bg);
var recordsTextStr = "Top Scores:\n";
for (var i = 0; i < records.length; i++) {
recordsTextStr += i + 1 + ". " + records[i].score + " (Attempt " + records[i].attempt + ")\n";
}
if (records.length === 0) {
recordsTextStr += "No records yet.";
}
recordsTextStr += "\nAttempts: " + records.length;
recordsTextStr += "\nLast Score: " + lastScore;
var recordsText = new Text2(recordsTextStr, {
fontFamily: "Arial",
fontSize: 5000 * 1.03,
fill: 0xffffff,
align: "center"
});
recordsText.anchorX = 0.5;
recordsText.anchorY = 0.5;
recordsText.x = centerX() - 280;
recordsText.y = centerY() - 850 + 40;
recordsText.scale.set(3, 3);
recordsContainer.addChild(recordsText);
// Container’ı oyuna ekle
game.addChild(recordsContainer);
// Close butonu bağımsız
var closeButton = createCloseButton();
closeButton.x = bg.x + modalWidth / 2 - closeButton.width / 2 - 205;
closeButton.y = bg.y - modalHeight / 2 + closeButton.height / 2 + 195;
closeButton.on('down', function () {
game.removeChild(recordsContainer);
game.removeChild(closeButton);
// Enable menu interaction when modal is closed
menuOpen = true;
menuContainer.visible = true;
});
game.addChild(closeButton);
}
/****
* End Game & Reset Functions
****/
function endGame() {
LK.effects.flashScreen(0xFF0000, 500);
character.velocityY = character.jumpStrength;
character.update = function () {
if (gameOver) {
character.velocityY += character.gravity;
character.y += character.velocityY;
if (character.y > groundY + character.height) {
character.y = groundY + character.height;
character.velocityY = 0;
}
}
};
game.children.forEach(function (child) {
if (child.velocityX) {
child.velocityX = 0;
}
});
game.touchDisabled = true;
lastScore = passCounter;
records.push({
score: passCounter,
attempt: records.length + 1
});
records.sort(function (a, b) {
return b.score - a.score;
});
if (records.length > 5) {
records = records.slice(0, 5);
}
LK.setTimeout(function () {
game.touchDisabled = false;
menuOpen = true;
menuContainer.visible = true;
var startY = groundY + 100;
var endY = centerY() - 1270;
var animationDuration = 16.5 * 5 / 1.5;
var startTime = Date.now();
function animateMenu() {
var currentTime = Date.now();
var elapsedTime = currentTime - startTime;
var progress = Math.min(elapsedTime / animationDuration, 1);
menuContainer.y = startY + (endY - startY) * progress;
if (progress < 1) {
LK.setTimeout(animateMenu, 16);
}
}
animateMenu();
}, 1700);
LK.setTimeout(function () {
resetGame();
}, 1750);
}
function resetGame() {
if (gameOverText) {
game.removeChild(gameOverText);
gameOverText = null;
}
// Flip'i eski hâline döndür
unflipWorld();
var objectsToRemove = [];
game.children.forEach(function (child) {
if (child instanceof Tree || child instanceof Tube) {
objectsToRemove.push(child);
}
});
objectsToRemove.forEach(function (obj) {
game.removeChild(obj);
});
game.removeChild(character);
character = game.addChild(new Character());
character.x = centerX();
character.y = groundY / 2;
gameStarted = false;
gameOver = false;
character.preventDeath = false; // Reset preventDeath flag
underscoreAsset.preventDeath = false; // Reset preventDeath flag for underscore asset
lastSpawner = null;
passCounter = 0;
underscoreTouchCount = 0; // Reset underscore touch count
counterText.setText(passCounter);
}
/****
* Eliptik hit testi için yardımcı fonksiyon
****/
function checkEllipseHover(button, lx, ly) {
var scaleFactorX = 1;
var scaleFactorY = 0.53;
var offsetY = 40;
var dx = lx - button.x;
var dy = ly - (button.y + offsetY);
var rx = button.width / 2 * scaleFactorX;
var ry = button.height / 2 * scaleFactorY;
return dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1;
}
/****
* Fare hareketinde hover kontrolü
****/
game.move = function (x, y, obj) {
if (!menuOpen) {
return;
} // Modal açıkken hover efekti çalışmasın.
var localX = x - menuContainer.x;
var localY = y - menuContainer.y;
playButton.visible = checkEllipseHover(playButton, localX, localY);
volumeButton.visible = checkEllipseHover(volumeButton, localX, localY);
creditsButton.visible = checkEllipseHover(creditsButton, localX, localY);
recordsButton.visible = checkEllipseHover(recordsButton, localX, localY);
};
/****
* Touch Event
****/
game.down = function (x, y, obj) {
if (menuOpen) {
var localX = x - menuContainer.x;
var localY = y - menuContainer.y;
if (checkEllipseHover(playButton, localX, localY)) {
var _animateMenu = function animateMenu() {
var currentTime = Date.now();
var elapsedTime = currentTime - startTime;
var progress = Math.min(elapsedTime / animationDuration, 1);
menuContainer.y = startY + (endY - startY) * progress;
if (progress < 1) {
LK.setTimeout(_animateMenu, 1);
} else {
menuOpen = false;
menuContainer.visible = false;
gameWait = true;
}
};
var animationDuration = 16.5 * 5 * 2 / 1.5;
var startTime = Date.now();
var startY = menuContainer.y;
var endY = centerY() + 100;
_animateMenu();
return;
} else if (checkEllipseHover(volumeButton, localX, localY)) {
showVolume();
} else if (checkEllipseHover(creditsButton, localX, localY)) {
showCredits();
} else if (checkEllipseHover(recordsButton, localX, localY)) {
showRecords();
}
return;
} else if (gameOver) {
if (!game.touchDisabled) {
menuOpen = true;
menuContainer.visible = true;
resetGame();
}
} else {
if (!menuOpen) {
// On the first click after the menu is closed,
// duplicate the backgrounds if not done already.
duplicateBackgrounds();
}
if (gameWait) {
gameWait = false;
gameStarted = true;
var initialTube = new Tube();
game.addChild(initialTube);
lastSpawner = initialTube;
character.jump();
} else {
character.jump();
character.rotation = 0.1;
LK.setTimeout(function () {
character.rotation = 0;
}, 200);
}
}
};
/****
* Game Loop
****/
game.update = function () {
game.children.forEach(function (child) {
if (child.update) {
child.update();
}
});
scrollingBackground.update();
game.children.sort(function (a, b) {
return (a.zIndex || 0) - (b.zIndex || 0);
});
};