User prompt
Please fix the bug: 'TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 352 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Daha çok geliştir ufak optimizasyonlardan sonra büyük bir güncelleme planla ve geliştir ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Oyunu geliştir.
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: mazeLeft is not defined' in or related to this line: 'powerup.x = mazeLeft + 100 + Math.random() * (mazeRight - mazeLeft - 200);' Line Number: 685
User prompt
### Temel Hedefler (Yapısal İyileştirme) 1. **Global Değişkenleri Yönetme:** Tüm global değişkenleri (`gameSpeed`, `slowMotionTimer`, `scoreMultiplier`, `mazeLeft`, `mazeRight`, `hazardSpeedBoost` vb.) tek bir **`GameManager`** sınıfı/nesnesi içine taşıyın. Oyuncu (`Player`) ve Tehlike (`Hazard`) sınıflarının, bu değişkenlere **doğrudan global erişim yerine** `GameManager` nesnesini kurucu (constructor) aracılığıyla almasını sağlayarak **kapsüllemeyi (encapsulation)** güçlendirin. 2. **Duvar Performansı İyileştirmesi:** `createMazeWalls` fonksiyonunu `game.update` döngüsünden çıkarın. Duvarları yalnızca bir kez oluşturun. `game.update` içinde, duvarların küçülme (`shrinkSpeed`) efektini uygulamak için sadece **mevcut duvarların konumlarını ve gerekirse ölçeklerini** güncelleyin. Her 30 tikte (tick) duvarların tamamen yıkılıp yeniden oluşturulmasını önleyin. 3. **Tehlike Sınıf Yapısı:** Tüm tehlike sınıfları (`BouncingWall`, `LaserWall`, `SawBlade`, `SpikeTrap`, `Turret`) için ortak bir **`BaseHazard`** sınıfı tanımlayın. Bu temel sınıf, tehlikenin hareket hızını ayarlarken kullanılan `gameSpeed` ve `hazardSpeedBoost` gibi değişkenleri `GameManager`'dan alsın ve **geçici hız artışı** (`tempSpeedBoostTimer`) mantığını merkezi olarak bu sınıfta yönetin. ### Yeni Özellikler (Geliştirme) 1. **Yeni Tehlike: Görünmez Engel (`InvisibleWall`):** * `BaseHazard`'dan türeyen yeni bir sınıf oluşturun. * Bu duvar, dikey veya yatay olarak rastgele bir pozisyonda sabit kalsın. * Duvarın grafiği her **3 saniyede bir** (180 tik) **1 saniyeliğine** (60 tik) tamamen şeffaf (`alpha: 0.0`) olsun, ardından tekrar görünür hale gelsin. * Çarpışma, sadece görünür olduğu zaman değil, **her zaman** gerçekleşmelidir. 2. **Oyun Sonu Arayüzü (Game Over UI):** * `LK.showGameOver()` yerine oyunu kontrol eden sınıfa (`GameManager`) bir `gameOver()` metodu ekleyin. * Bu metodun içinde, `LK.gui` üzerine mevcut skoru, yüksek skoru ve **"Yeniden Başlat (Restart)"** butonu/metnini içeren bir UI oluşturun. * "Yeniden Başlat" butonuna tıklandığında, oyunun tüm değişkenlerini sıfırlayan (`resetGame()` metodu) ve oyunu yeniden başlatan bir mekanizma ekleyin. **Beklenen Çıktı:** * `GameManager` sınıfını/nesnesini içeren güncellenmiş kod yapısı. * `BaseHazard` sınıfını ve bundan türeyen tüm tehlike sınıflarını içeren kod. * `InvisibleWall` ve `Powerup` sınıflarını içeren kod. * `game.update` döngüsünde yeni yapıya (GameManager ve BaseHazard) uygun değişiklikler ve `gameOver()` ile yeniden başlatma mantığı. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Aşağıdaki adımları uygulayarak mevcut kodu güncelleyelim. 1. ⚙️ Kritik Düzeltme: Powerup Negatif Etkisi tempSpeedBoostTimer'ın çarpanını tüm hareketli tehlikelere (Turret mermileri dahil) uygulayın. LaserWall.update ve SawBlade.update metotlarında, hareket hızını hesaplarken mevcut gameSpeed ve hazardSpeedBoost çarpanlarına ek olarak tempSpeedBoostTimer'ı kontrol eden bir çarpan kullanın. Yeni Hız Çarpanı Formülü (tüm hareketli tehlikeler için): JavaScript var tempMultiplier = tempSpeedBoostTimer > 0 ? 1.5 : 1; // Hareketi bu tempMultiplier ile çarpın. // Örneğin SawBlade için: self.x += self.direction.x * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier; 2. 🧱 Yeni Tehlike: Zıplayan Duvar (Bouncing Wall) Zorluk yükseltme amacıyla yeni bir, ölümcül olmayan ancak cezalandırıcı bir tehlike ekleyin. Yeni Asset: Yeni bir şekil tanımlayın: JavaScript LK.init.shape('bouncingWall', {width:100, height:200, color:0x00ffaa, shape:'box'}) BouncingWall Sınıfı: LaserWall'a benzer hareket eden ancak oyuncuyu geri iten bir sınıf oluşturun. moveSpeed ve direction (yatay veya dikey) tanımlayın. Spawn Kuralı: spawnHazard() fonksiyonunda, scoreMultiplier 3 veya daha yüksek olduğunda bu yeni tehlikenin ortaya çıkma şansını (%20) ekleyin. Çarpışma Etkileşimi: game.update içinde, BouncingWall ile oyuncu çarpıştığında: Ölüm Yok: Oyuncu ölmez. İtme: Oyuncunun merkezinden duvarın merkezine doğru bir vektör hesaplayın. Oyuncuya duvardan uzaklaşacak yönde güçlü bir hız uygulayın (örneğin, player.x += forceX * 10; player.y += forceY * 10;). Ceza: Oyuncunun mevcut skorundan 50 puan düşün (LK.setScore(LK.getScore() - 50)). Skorun 0'ın altına düşmemesini sağlayın. Geri Bildirim: Çarpışma sesini çalın ve oyuncu itilirken kısa süreliğine mavi flaş (tint: 0x0000FF) uygulayın. 3. ✨ Görsel Geri Bildirim ve İyileştirme Oyuncunun etkileşimlerini daha belirgin hale getirin. Oyuncu Hareketi İzi (Player Trail): Her player.update döngüsünde, oyuncunun anlık konumunda küçük, şeffaf, ve oyuncunun renginde bir daire oluşturun. Bu iz parçacıklarını hemen oyuna ekleyin. Her iz parçacığı için bir tween kullanarak, parçacığın boyutu küçülsün (scaleX/Y: 0'a) ve şeffaflığı azalsın (alpha: 0'a) ve 30 tick (0.5 saniye) sonra yok olsun. Bu izler, oyun alanını (game objesini) kirletmemek için ayrı bir parçacık listesinde yönetilmelidir. (Yeni bir trails = [] listesi oluşturun.) Patlama Animasyonu (Game Over): LK.showGameOver() çağrılmadan hemen önce, oyuncunun konumunda bir patlama efekti oluşturun. Bu, birkaç (10-15) küçük, kırmızı/sarı renkte parçacığın oyuncunun merkezinden rastgele hızlarla dışa doğru fırlatılması ve birkaç tick içinde yok olması şeklinde olabilir. Bu parçacıklar için de ayrı bir liste kullanın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mevcut kodu, aşağıdaki Asset Optimizasyonlarını, Dinamik Zorluk Yönetimi ve Gelişmiş Etkileşim Mekanikleri ile güncelleyin. 1. Asset ve Ses Tanımlamaları Gerekli Ses: Yeni bir ses asset'i tanımlayın: LK.init.sound('nearmiss'). 2. Dinamik Zorluk ve Ritim Yönetimi Hız Artış Sistemi: game objesine hazardSpeedBoost adında yeni bir değişken ekleyin, başlangıç değeri 1 olsun. Tüm hareketli tehlikelerin (LaserWall, SawBlade, Turret mermileri) hızlarını hesaplarken bu çarpanı kullanın. Ritmik Zorluk (Görünmez Dalga): game.update içinde, her 3600 tick'te (60 saniyede): hazardSpeedBoost değerini 1.2 ile çarpın (hazardSpeedBoost *= 1.2). Tüm aktif LaserWall'lar için 1 saniyeliğine (60 tick) alpha değerini 0.05'e düşürün, ardından tween kullanarak normal pulsasyon aralığına geri döndürün. Powerup Negatif Etkisi: Powerup toplandığında, tüm aktif tehlikelerin (Turret hariç) moveSpeed değerini (veya Turret mermi hızını) 0.5 saniyeliğine geçici olarak %50 artırın (* 1.5), ardından orijinal değerine geri döndürün. Bu etki için bir geçici sayaç kullanın (örn: tempSpeedBoostTimer). 3. Gelişmiş Çarpışma ve Geri Bildirim Kalkan Kırılması/Çarpan Sıfırlama: game.update içindeki (hem normal tehlike hem de mermi) çarpışma kontrollerinde, kalkan kırıldığında (player.shieldActive kontrolü true iken çarpışma gerçekleştiğinde): scoreMultiplier'ı 1'e sıfırla. lastMultiplierIncrease'i o anki zamana sıfırla (Math.floor(LK.ticks / 60)). multiplierTxt'in rengini tween kullanarak anlık olarak kırmızıya (0xFF0000) değiştir ve hemen eski rengine (0xFFAA00) geri döndür. Mermi Bloklama ve Ödül: game.update içinde, aktif SawBlade objeleri ile Turret mermileri (hazard.bullets) arasındaki çarpışmayı kontrol edin. Çarpışma algılandığında, hem SawBlade'i hem de mermiyi yok edin (destroy ve listeden silme). Skora sabit +10 puan ekleyin (LK.setScore(LK.getScore() + 10)). Kıl Payı Kurtuluş (Near Miss) Sistemi: game.update içinde, oyuncu ile her bir tehlike arasındaki mesafeyi kontrol edin. Near Miss Eşiği: İki objenin merkezleri arasındaki mesafe, çarpışma mesafesinden 40 pikselden fazla, 60 pikselden az ise, bu bir Near Miss'tir. Geri Bildirim: Near Miss tetiklendiğinde: nearmiss sesini çalın. Oyuncunun grafik objesine (player.getChildAt(0)) anlık olarak kısa süreli beyaz flaş (tint: 0xFFFFFF) efekti uygulayın, ardından normal rengine geri döndürün. Tekrarlamayı Önleme: Bir tehlike objesi için nearMissCooldown (60 tick) kullanarak aynı objeyle ardışık Near Miss'leri engelleyin. SawBlade, LaserWall ve SpikeTrap sınıflarına nearMissTimer değişkeni ekleyin. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mevcut kodda, oynanışı derinleştirmek, görsel temayı keskinleştirmek ve oyuncu etkileşimini artırmak için kapsamlı bir güncelleme yapın. 1. **Asset Düzeltmeleri ve Yeni Asset:** * `player` rengini daha parlak bir neon yeşili yapın: `0x00FF00`. * `wall` rengini daha koyu ve uyumlu bir griye ayarlayın: `0x333333`. * **YENİ TEHLİKE (Turret):** `turret` adında, `sawBlade` ile aynı boyutta (80x80) ve `0xFF4100` (neon turuncu) renginde, sabit duran, kare şeklinde bir asset tanımlayın. 2. **Mekanik İyileştirme: Kalkan Kırılması/Çarpan Sıfırlama:** * `game.update` içindeki tehlike çarpışma kontrolünde, **kalkan kırıldığında** (`player.shieldActive` kontrolü `true` iken çarpışma gerçekleştiğinde): * `scoreMultiplier`'ı **1**'e sıfırla. * `lastMultiplierIncrease`'i o anki zamana sıfırla. * `multiplierTxt`'in rengini **kırmızıya** (`0xFF0000`) anlık olarak değiştir ve `tween` kullanarak hemen eski rengine (`0xFFAA00`) geri döndür. Bu sıfırlanma hissini vurgular. 3. **Yeni Mekanik: Taret ve Atış (Turret Hazard):** * `Turret` adında, `SawBlade` gibi, ancak **sabit duran** yeni bir Class oluşturun. * `Turret`'in görevi, oyuncuya doğru **yavaşça dönmek** ve düzenli aralıklarla (`120 ticks` - 2 saniye) `LaserWall`'dan daha küçük ve hızlı bir mermi fırlatmaktır. * Mermiler, `LaserWall` asset'ini kullansın, ancak mermi fırlatıldığında `x` veya `y` yönünde hızlıca hareket etmelidir. (Mermi bir süre sonra kaybolmalı/yok edilmelidir). * `spawnHazard` fonksiyonuna, yeni `Turret`'i rastgele yerleştirme seçeneğini ekleyin. 4. **UI İyileştirme: Çarpan Seviyesi Görsel Geri Bildirimi:** * `game.update` içinde çarpan her arttığında (`scoreMultiplier++` olduğunda), `multiplierTxt` üzerindeki sayıyı büyütüp küçülten `tween` animasyonunu koru. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mevcut oyundaki oyuncu etkileşimini ve kalıcılığını artırmak için aşağıdaki iki kritik iyileştirmeyi yap: 1. **Çarpan Görsel Geri Bildirimi (Multiplier Reward):** * Skor çarpanı (`scoreMultiplier`) her arttığında (yani `currentTime - lastMultiplierIncrease >= 30` koşulu sağlandığında), oyuncuya anlık bir görsel ödül ver. * `multiplierTxt` UI öğesini kullanarak, **kısa bir animasyonla** metnin boyutunu anlık olarak büyüt ve hemen normale geri döndür (`tween` kullanarak). Bu, oyuncuya bir "seviye atladı" hissi verecektir. 2. **Başlangıç Denge Ayarı (Ease-in):** * Yeni oyuncuların hemen ölmesini engellemek için, labirentin küçülme hızını (`shrinkSpeed`) başlangıçta biraz azalt. * `shrinkSpeed` değerini **0.5'ten 0.35'e** düşür. Bu, oyunculara mekaniklere alışmaları için biraz daha fazla zaman tanıyacaktır. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mevcut koda son bir cilalama yapmak istiyorum: 1. **Yüksek Skor UI Eklenmesi:** * Mevcut skoru gösteren `scoreTxt`'a benzer şekilde, sol alt köşeye "HS: [En Yüksek Skor]" değerini gösterecek yeni bir **UI etiketi (`highScoreTxt`)** ekle. * Oyun başlangıcında `storage.highScore`'daki değeri bu etikette göster. 2. **Game Over Bilgisi Güncellemesi:** * Oyun bittiğinde (`LK.showGameOver()` çağrılmadan hemen önce), Yüksek Skorun başarıyla kaydedildiğinden emin ol. 3. **Hata Giderme (Optional):** * Oyuncu kalkanı aktifken engellere çarptığında gerçekleşen parlama animasyonunun (`tween`) temiz bir şekilde bittiğinden ve oyuncu renginin doğru bir şekilde geri geldiğinden emin ol. Bu son değişiklikler, oyunun UI'ını tamamlayacak ve oyuncular için yüksek skor hedefini daha görünür kılacaktır. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Mevcut kodu bu iyileştirmelerle güncelle: 1. **Player (Oyuncu) Cilalaması:** * `Player` sınıfına, oyuncu hareket ettiğinde karakteri hafifçe büyütüp küçülten (titreme veya zıplama efekti gibi) basit bir **görsel hareket animasyonu** ekle. 2. **LaserWall Cilalaması:** * `LaserWall` sınıfına, lazer duvarına gerçekçi bir enerji hissi vermek için rengi veya şeffaflığı (`alpha`) sürekli olarak yumuşakça değiştiren bir **parlama (pulsing) efekti** ekle. 3. **Kalkan Geri Bildirimi:** * `game.update` içindeki hazard (engel) çarpışma kontrolüne, oyuncunun kalkanı (`player.shieldActive`) aktifken bir engele çarptığı durumu ele alacak bir mantık ekle. * **Eğer kalkan aktifken çarpışma olursa:** Kalkanı hemen sonlandır (`player.shieldActive = false; playerGraphics.tint = 0xffffff;`). Çarpışmanın absorbe edildiğini göstermek için oyuncu karakterine kısa, parlak bir **beyaz/sarı titreme (blink)** animasyonu uygula (Game Over olmasın). 4. **Game Over Ekranı:** * Oyun bittiğinde (`LK.showGameOver()`), mevcut skora ek olarak oyunun en yüksek skorunu (High Score) da ekranda göster. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Pixel Maze Runner: Fast Escape
Initial prompt
OYUN TÜRÜ: 2D, Yukarıdan Aşağıya (Top-Down), Sonsuz Koşucu (Endless Runner) ve Hayatta Kalma (Survival) öğeleri içeren Yüksek Skorlu Arcade Oyunu. OYUN ADI: Pixel Labirenti: Hızlı Kaçış (Pixel Maze Runner) AMAÇ: Oyuncu karakterinin, sürekli olarak dinamik bir şekilde küçülen ve engellerle dolan pikselli bir labirentte, duvarlara ve engellere çarpmadan mümkün olduğunca uzun süre hayatta kalmasını sağlamak ve en yüksek puanı elde etmek. ANA MEKANİKLER (CORE MECHANICS): 1. **Kontrol:** Oyuncu, basit 4 yönlü (yukarı, aşağı, sol, sağ) hareketle kare bir karakteri kontrol eder. 2. **Dinamik Labirent:** Labirent, oyun başladığı anda görünmeye başlar. Labirent duvarları sürekli olarak **içe doğru** hareket eder ve labirent alanını daraltır. Oyuncu duvarlara çarparsa oyun biter. 3. **Engeller (Hazards):** Labirent içinde rastgele olarak **dönen testere dişlileri, kayan lazer duvarları ve geçici kapanlar** gibi basit, hareketli engeller (Hazards) belirir. Bu engellere çarpmak da oyunu sonlandırır. 4. **Puanlama:** Oyuncu hayatta kaldığı her saniye için puan kazanır. Puan çarpanı her 30 saniyede bir artar. 5. **Güçlendirmeler (Power-ups):** Nadiren labirentte 3 saniyelik **Hız Azaltma** veya 1 saniyelik **Kalkan (Dokunulmazlık)** güçlendirmeleri belirir. Oyuncu bu güçlendirmeleri toplayabilir. VİZYON VE TEMA: * **Görsel Stil:** Retro, 8-bit/16-bit **Piksel Sanatı (Pixel Art)**. Canlı neon renkler ve karanlık bir arka plan ile yüksek kontrast oluşturulmalı (Arcade makinesi görünümü). * **Karakter:** Basit, tek renkli, hareket ederken hafif bir "yürüme" animasyonu olan kare bir blok. * **Labirent Varlıkları:** Duvarlar koyu gri, engeller (testereler/lazerler) parlak neon mavi/kırmızı/sarı renkte olmalı. SES VE MÜZİK: * **Müzik:** Hızlı tempolu, tekrar eden ve gerilimi artıran **Synthwave/Chiptune** tarzı bir müzik döngüsü. * **Ses Efektleri:** * Haraket: Minimal pikselli ayak sesi (isteğe bağlı). * Çarpışma: Yüksek ve keskin "Game Over" sesi. * Güçlendirme Alma: Kısa, tatmin edici "ding" sesi. ÖZEL TALEP (Ava İçin İpucu): Lütfen temel 2D Top-Down karakter kontrol kodunu ve içe doğru sürekli hareket eden dinamik duvar mekaniğini öncelikli olarak oluştur. Engeller için rastgele doğma (random spawn) fonksiyonunu ekle. Görsel ve ses varlıklarını (Pixel Art stilinde labirent duvarı, dönen dişli, Synthwave müziği) oluşturmak için ilgili AI araçlarını kullan.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BouncingWall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('bouncingWall', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveSpeed = 2;
self.isVertical = Math.random() > 0.5;
self.direction = Math.random() > 0.5 ? 1 : -1;
if (!self.isVertical) {
wallGraphics.rotation = Math.PI / 2;
}
self.update = function () {
var tempMultiplier = tempSpeedBoostTimer > 0 ? 1.5 : 1;
if (self.isVertical) {
self.x += self.direction * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
if (self.x <= mazeLeft + 50 || self.x >= mazeRight - 50) {
self.direction *= -1;
}
} else {
self.y += self.direction * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
if (self.y <= mazeTop + 50 || self.y >= mazeBottom - 50) {
self.direction *= -1;
}
}
};
return self;
});
var LaserWall = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laserWall', {
anchorX: 0.5,
anchorY: 0.5
});
self.isVertical = Math.random() > 0.5;
if (!self.isVertical) {
laserGraphics.rotation = Math.PI / 2;
}
self.moveSpeed = 3;
self.direction = Math.random() > 0.5 ? 1 : -1;
self.nearMissTimer = 0;
self.update = function () {
// Update near miss timer
if (self.nearMissTimer > 0) self.nearMissTimer--;
var tempMultiplier = tempSpeedBoostTimer > 0 ? 1.5 : 1;
if (self.isVertical) {
self.x += self.direction * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
if (self.x <= mazeLeft + 10 || self.x >= mazeRight - 10) {
self.direction *= -1;
}
} else {
self.y += self.direction * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
if (self.y <= mazeTop + 10 || self.y >= mazeBottom - 10) {
self.direction *= -1;
}
}
// Pulsing effect
var pulse = Math.sin(LK.ticks * 0.15) * 0.3 + 0.7;
laserGraphics.alpha = pulse;
};
return self;
});
var MagneticOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('magneticOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.magneticRange = 200;
self.pulseTimer = 0;
self.nearMissTimer = 0;
self.update = function () {
// Update near miss timer
if (self.nearMissTimer > 0) self.nearMissTimer--;
// Pulsing magnetic effect
self.pulseTimer++;
var pulse = Math.sin(self.pulseTimer * 0.1) * 0.3 + 1;
orbGraphics.scaleX = pulse;
orbGraphics.scaleY = pulse;
// Electrical arc effect
if (LK.ticks % 20 === 0) {
var electricityTint = Math.random() > 0.5 ? 0xffffff : 0x9966ff;
orbGraphics.tint = electricityTint;
var self_ref = self;
LK.setTimeout(function () {
if (orbGraphics.parent) orbGraphics.tint = 0xffffff;
}, 100);
}
// Apply magnetic force to player if within range
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.magneticRange && distance > 0) {
var force = 0.8 * (1 - distance / self.magneticRange);
var forceX = dx / distance * force;
var forceY = dy / distance * force;
// Pull player toward orb
player.x -= forceX * 2;
player.y -= forceY * 2;
}
};
return self;
});
var MultiplierBoost = Container.expand(function () {
var self = Container.call(this);
var boostGraphics = self.attachAsset('multiplierBoost', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTimer = 250; // 4.2 seconds
self.floatOffset = 0;
self.update = function () {
self.lifeTimer--;
self.floatOffset++;
// Floating motion
boostGraphics.y = Math.sin(self.floatOffset * 0.1) * 5;
// Golden glow effect
var glow = Math.sin(LK.ticks * 0.2) * 0.3 + 1;
boostGraphics.scaleX = glow;
boostGraphics.scaleY = glow;
if (self.lifeTimer <= 0) {
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.moveDirection = {
x: 0,
y: 0
};
self.shieldActive = false;
self.shieldTimer = 0;
self.update = function () {
// Apply movement
self.x += self.moveDirection.x * self.speed * gameSpeed;
self.y += self.moveDirection.y * self.speed * gameSpeed;
// Handle shield timer
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
playerGraphics.tint = 0xffffff;
}
}
// Movement animation - bounce effect when moving
if (self.moveDirection.x !== 0 || self.moveDirection.y !== 0) {
var bounce = Math.sin(LK.ticks * 0.4) * 0.1 + 1;
playerGraphics.scaleX = bounce;
playerGraphics.scaleY = bounce;
} else {
playerGraphics.scaleX = 1;
playerGraphics.scaleY = 1;
}
// Keep player within maze bounds
var padding = 30;
if (self.x < mazeLeft + padding) self.x = mazeLeft + padding;
if (self.x > mazeRight - padding) self.x = mazeRight - padding;
if (self.y < mazeTop + padding) self.y = mazeTop + padding;
if (self.y > mazeBottom - padding) self.y = mazeBottom - padding;
// Create trail effect
if (LK.ticks % 3 === 0) {
// Create trail every 3 ticks
var trail = game.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.5,
tint: 0x00ff00
}));
trails.push(trail);
// Tween trail to fade and shrink
tween(trail, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
trail.destroy();
var index = trails.indexOf(trail);
if (index > -1) trails.splice(index, 1);
}
});
}
};
self.activateShield = function () {
self.shieldActive = true;
self.shieldTimer = 60; // 1 second at 60fps
playerGraphics.tint = 0xffaa00;
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var powerupGraphics = self.attachAsset(type === 'slow' ? 'slowPowerup' : 'shieldPowerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTimer = 300; // 5 seconds at 60fps
self.pulseTimer = 0;
self.update = function () {
self.lifeTimer--;
self.pulseTimer++;
// Pulsing effect
var scale = 1 + Math.sin(self.pulseTimer * 0.2) * 0.2;
powerupGraphics.scaleX = scale;
powerupGraphics.scaleY = scale;
if (self.lifeTimer <= 0) {
self.destroy();
}
};
return self;
});
var SawBlade = Container.expand(function () {
var self = Container.call(this);
var sawGraphics = self.attachAsset('sawBlade', {
anchorX: 0.5,
anchorY: 0.5
});
self.rotationSpeed = 0.2;
self.moveSpeed = 2;
self.nearMissTimer = 0;
self.direction = {
x: Math.random() - 0.5,
y: Math.random() - 0.5
};
var length = Math.sqrt(self.direction.x * self.direction.x + self.direction.y * self.direction.y);
self.direction.x /= length;
self.direction.y /= length;
self.update = function () {
// Update near miss timer
if (self.nearMissTimer > 0) self.nearMissTimer--;
sawGraphics.rotation += self.rotationSpeed;
// Move
var tempMultiplier = tempSpeedBoostTimer > 0 ? 1.5 : 1;
self.x += self.direction.x * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
self.y += self.direction.y * self.moveSpeed * gameSpeed * hazardSpeedBoost * tempMultiplier;
// Bounce off maze walls
if (self.x <= mazeLeft + 40 || self.x >= mazeRight - 40) {
self.direction.x *= -1;
}
if (self.y <= mazeTop + 40 || self.y >= mazeBottom - 40) {
self.direction.y *= -1;
}
// Keep within bounds
self.x = Math.max(mazeLeft + 40, Math.min(mazeRight - 40, self.x));
self.y = Math.max(mazeTop + 40, Math.min(mazeBottom - 40, self.y));
};
return self;
});
var SpikeTrap = Container.expand(function () {
var self = Container.call(this);
var spikeGraphics = self.attachAsset('spikeTrap', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTimer = 180; // 3 seconds at 60fps
self.isActive = true;
self.nearMissTimer = 0;
self.update = function () {
// Update near miss timer
if (self.nearMissTimer > 0) self.nearMissTimer--;
self.lifeTimer--;
// Blink when about to disappear
if (self.lifeTimer < 60) {
spikeGraphics.alpha = Math.sin(self.lifeTimer * 0.3) * 0.5 + 0.5;
}
if (self.lifeTimer <= 0) {
self.isActive = false;
}
};
return self;
});
var TimePowerup = Container.expand(function () {
var self = Container.call(this);
var timeGraphics = self.attachAsset('timePowerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTimer = 400; // 6.7 seconds
self.rotationSpeed = 0.05;
self.update = function () {
self.lifeTimer--;
timeGraphics.rotation += self.rotationSpeed;
// Sparkle effect
if (LK.ticks % 15 === 0) {
var sparkle = Math.random() > 0.5 ? 0xffffff : 0xff66ff;
timeGraphics.tint = sparkle;
var self_ref = self;
LK.setTimeout(function () {
if (timeGraphics.parent) timeGraphics.tint = 0xffffff;
}, 200);
}
if (self.lifeTimer <= 0) {
self.destroy();
}
};
return self;
});
var Turret = Container.expand(function () {
var self = Container.call(this);
var turretGraphics = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireTimer = 0;
self.bullets = [];
self.nearMissTimer = 0;
self.update = function () {
// Update near miss timer
if (self.nearMissTimer > 0) self.nearMissTimer--;
// Slowly rotate toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var targetAngle = Math.atan2(dy, dx);
var currentAngle = turretGraphics.rotation;
var angleDiff = targetAngle - currentAngle;
// Normalize angle difference
while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;
// Slowly rotate toward target
turretGraphics.rotation += angleDiff * 0.05;
// Fire bullets every 120 ticks (2 seconds)
self.fireTimer++;
if (self.fireTimer >= 120) {
self.fireTimer = 0;
var bullet = game.addChild(LK.getAsset('laserWall', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
}));
// Set bullet direction toward player
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.speedX = dx / distance * 6 * hazardSpeedBoost;
bullet.speedY = dy / distance * 6 * hazardSpeedBoost;
bullet.lifeTimer = 180; // 3 seconds
self.bullets.push(bullet);
}
// Update bullets
for (var i = self.bullets.length - 1; i >= 0; i--) {
var bullet = self.bullets[i];
var speedMultiplier = tempSpeedBoostTimer > 0 ? 1.5 : 1;
bullet.x += bullet.speedX * gameSpeed * speedMultiplier;
bullet.y += bullet.speedY * gameSpeed * speedMultiplier;
bullet.lifeTimer--;
if (bullet.lifeTimer <= 0 || bullet.x < mazeLeft - 50 || bullet.x > mazeRight + 50 || bullet.y < mazeTop - 50 || bullet.y > mazeBottom + 50) {
bullet.destroy();
self.bullets.splice(i, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
// Game variables
var player;
var walls = [];
var hazards = [];
var powerups = [];
var gameSpeed = 1;
var slowMotionTimer = 0;
var scoreMultiplier = 1;
var lastMultiplierIncrease = 0;
var hazardSpawnTimer = 0;
var powerupSpawnTimer = 0;
var hazardSpeedBoost = 1;
var tempSpeedBoostTimer = 0;
var trails = [];
var explosionParticles = [];
var timeSlowActive = false;
var timeSlowDuration = 0;
var magneticOrbs = [];
var achievementTimer = 0;
var comboCounter = 0;
var lastComboTime = 0;
// Persistent game statistics
var gameStats = {
totalGamesPlayed: storage.totalGamesPlayed || 0,
totalScore: storage.totalScore || 0,
bestMultiplier: storage.bestMultiplier || 1,
totalHazardsDestroyed: storage.totalHazardsDestroyed || 0,
achievementsUnlocked: storage.achievementsUnlocked || []
};
// Achievement definitions
var achievements = [{
id: 'first_game',
name: 'First Steps',
desc: 'Play your first game',
target: 1,
stat: 'totalGamesPlayed'
}, {
id: 'score_1000',
name: 'Getting Started',
desc: 'Reach 1000 points',
target: 1000,
stat: 'score'
}, {
id: 'score_5000',
name: 'Skilled Player',
desc: 'Reach 5000 points',
target: 5000,
stat: 'score'
}, {
id: 'multiplier_5',
name: 'Combo Master',
desc: 'Reach 5x multiplier',
target: 5,
stat: 'multiplier'
}, {
id: 'survive_180',
name: 'Survivor',
desc: 'Survive 3 minutes',
target: 180,
stat: 'time'
}, {
id: 'destroy_50',
name: 'Destroyer',
desc: 'Destroy 50 hazards total',
target: 50,
stat: 'totalHazardsDestroyed'
}];
function checkAchievements() {
var currentStats = {
totalGamesPlayed: gameStats.totalGamesPlayed,
score: LK.getScore(),
multiplier: scoreMultiplier,
time: Math.floor(LK.ticks / 60),
totalHazardsDestroyed: gameStats.totalHazardsDestroyed
};
for (var i = 0; i < achievements.length; i++) {
var achievement = achievements[i];
if (gameStats.achievementsUnlocked.indexOf(achievement.id) === -1) {
if (currentStats[achievement.stat] >= achievement.target) {
gameStats.achievementsUnlocked.push(achievement.id);
storage.achievementsUnlocked = gameStats.achievementsUnlocked;
// Achievement notification
LK.getSound('achievement').play();
showAchievementPopup(achievement.name, achievement.desc);
}
}
}
}
function showAchievementPopup(name, desc) {
var popup = game.addChild(LK.getAsset('shieldPowerup', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 200,
scaleX: 2,
scaleY: 2,
tint: 0xFFD700
}));
tween(popup, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 3000,
onFinish: function onFinish() {
popup.destroy();
}
});
}
// Maze boundaries
var mazeLeft = 200;
var mazeRight = 1848;
var mazeTop = 200;
var mazeBottom = 2532;
var shrinkSpeed = 0.35;
// UI
var scoreTxt = new Text2('0', {
size: 80,
fill: 0x00FF41
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var multiplierTxt = new Text2('x1', {
size: 60,
fill: 0xFFAA00
});
multiplierTxt.anchor.set(1, 0);
multiplierTxt.y = 100;
LK.gui.topRight.addChild(multiplierTxt);
// High score display
var highScoreTxt = new Text2('HS: 0', {
size: 60,
fill: 0xFFFFFF
});
highScoreTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(highScoreTxt);
// Initialize high score display
highScoreTxt.setText('HS: ' + (storage.highScore || 0));
// Create player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Create initial maze walls
function createMazeWalls() {
// Clear existing walls
for (var i = 0; i < walls.length; i++) {
walls[i].destroy();
}
walls = [];
// Top wall
for (var x = mazeLeft - 50; x <= mazeRight + 50; x += 100) {
var wall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: mazeTop - 50
}));
walls.push(wall);
}
// Bottom wall
for (var x = mazeLeft - 50; x <= mazeRight + 50; x += 100) {
var wall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: mazeBottom + 50
}));
walls.push(wall);
}
// Left wall
for (var y = mazeTop - 50; y <= mazeBottom + 50; y += 100) {
var wall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: mazeLeft - 50,
y: y
}));
walls.push(wall);
}
// Right wall
for (var y = mazeTop - 50; y <= mazeBottom + 50; y += 100) {
var wall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: mazeRight + 50,
y: y
}));
walls.push(wall);
}
}
// Initial wall creation
createMazeWalls();
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
isDragging = true;
};
game.move = function (x, y, obj) {
if (!isDragging) return;
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var threshold = 30;
player.moveDirection.x = 0;
player.moveDirection.y = 0;
if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
player.moveDirection.x = deltaX > 0 ? 1 : -1;
} else {
player.moveDirection.y = deltaY > 0 ? 1 : -1;
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
player.moveDirection.x = 0;
player.moveDirection.y = 0;
};
// Spawn hazards
function spawnHazard() {
var hazardType;
// Advanced hazard spawning logic based on multiplier
if (scoreMultiplier >= 5 && Math.random() < 0.15) {
hazardType = 5; // MagneticOrb
} else if (scoreMultiplier >= 3 && Math.random() < 0.2) {
hazardType = 4; // BouncingWall
} else {
hazardType = Math.floor(Math.random() * 4);
}
var hazard;
if (hazardType === 0) {
// Saw blade
hazard = new SawBlade();
hazard.x = mazeLeft + Math.random() * (mazeRight - mazeLeft);
hazard.y = mazeTop + Math.random() * (mazeBottom - mazeTop);
} else if (hazardType === 1) {
// Laser wall
hazard = new LaserWall();
if (hazard.isVertical) {
hazard.x = mazeLeft + Math.random() * (mazeRight - mazeLeft);
hazard.y = (mazeTop + mazeBottom) / 2;
} else {
hazard.x = (mazeLeft + mazeRight) / 2;
hazard.y = mazeTop + Math.random() * (mazeBottom - mazeTop);
}
} else if (hazardType === 2) {
// Spike trap
hazard = new SpikeTrap();
hazard.x = mazeLeft + 100 + Math.random() * (mazeRight - mazeLeft - 200);
hazard.y = mazeTop + 100 + Math.random() * (mazeBottom - mazeTop - 200);
} else if (hazardType === 3) {
// Turret
hazard = new Turret();
hazard.x = mazeLeft + 100 + Math.random() * (mazeRight - mazeLeft - 200);
hazard.y = mazeTop + 100 + Math.random() * (mazeBottom - mazeTop - 200);
} else if (hazardType === 4) {
// Bouncing wall
hazard = new BouncingWall();
if (hazard.isVertical) {
hazard.x = mazeLeft + Math.random() * (mazeRight - mazeLeft);
hazard.y = (mazeTop + mazeBottom) / 2;
} else {
hazard.x = (mazeLeft + mazeRight) / 2;
hazard.y = mazeTop + Math.random() * (mazeBottom - mazeTop);
}
} else if (hazardType === 5) {
// Magnetic Orb
hazard = new MagneticOrb();
hazard.x = mazeLeft + 120 + Math.random() * (mazeRight - mazeLeft - 240);
hazard.y = mazeTop + 120 + Math.random() * (mazeBottom - mazeTop - 240);
magneticOrbs.push(hazard);
}
hazards.push(hazard);
game.addChild(hazard);
}
// Spawn powerup
function spawnPowerup() {
var rand = Math.random();
var powerup;
if (rand < 0.4) {
powerup = new Powerup('slow');
} else if (rand < 0.7) {
powerup = new Powerup('shield');
} else if (rand < 0.85) {
powerup = new TimePowerup();
} else {
powerup = new MultiplierBoost();
}
powerup.x = mazeLeft + 100 + Math.random() * (mazeRight - mazeLeft - 200);
powerup.y = mazeTop + 100 + Math.random() * (mazeBottom - mazeTop - 200);
powerups.push(powerup);
game.addChild(powerup);
}
// Play background music
LK.playMusic('bgmusic');
// Main game loop
game.update = function () {
// Handle slow motion
if (slowMotionTimer > 0) {
slowMotionTimer--;
gameSpeed = 0.3;
if (slowMotionTimer <= 0) {
gameSpeed = 1;
}
}
// Handle time slow effect
if (timeSlowDuration > 0) {
timeSlowDuration--;
gameSpeed = 0.1; // Much slower than regular slow motion
hazardSpeedBoost *= 0.5; // Reduce hazard speed as well
if (timeSlowDuration <= 0) {
timeSlowActive = false;
gameSpeed = 1;
hazardSpeedBoost = Math.max(1, hazardSpeedBoost * 2); // Restore hazard speed
}
}
// Emergency teleportation (double tap detection simulation)
if (LK.ticks % 180 === 0 && Math.random() < 0.03) {
// Rare random teleportation for demo
// Find safe teleportation spot
var attempts = 0;
var newX, newY, safe;
do {
newX = mazeLeft + 100 + Math.random() * (mazeRight - mazeLeft - 200);
newY = mazeTop + 100 + Math.random() * (mazeBottom - mazeTop - 200);
safe = true;
// Check if position is safe from hazards
for (var h = 0; h < hazards.length; h++) {
var dx = newX - hazards[h].x;
var dy = newY - hazards[h].y;
if (Math.sqrt(dx * dx + dy * dy) < 120) {
safe = false;
break;
}
}
attempts++;
} while (!safe && attempts < 10);
if (safe) {
LK.getSound('teleport').play();
// Teleportation effect
var oldX = player.x,
oldY = player.y;
tween(player, {
alpha: 0
}, {
duration: 100,
onFinish: function onFinish() {
player.x = newX;
player.y = newY;
tween(player, {
alpha: 1
}, {
duration: 100
});
}
});
}
}
// Achievement checking
achievementTimer++;
if (achievementTimer >= 60) {
// Check every second
checkAchievements();
achievementTimer = 0;
}
// Handle temp speed boost timer
if (tempSpeedBoostTimer > 0) {
tempSpeedBoostTimer--;
}
// Rhythmic difficulty every 60 seconds (3600 ticks)
if (LK.ticks > 0 && LK.ticks % 3600 === 0) {
hazardSpeedBoost *= 1.2;
// Make all laser walls nearly invisible for 1 second
for (var i = 0; i < hazards.length; i++) {
var hazard = hazards[i];
if (hazard.constructor === LaserWall) {
var laserGraphics = hazard.getChildAt(0);
tween(laserGraphics, {
alpha: 0.05
}, {
duration: 1000,
onFinish: function onFinish() {
// Resume normal pulsing after 1 second
}
});
}
}
}
// Shrink maze
mazeLeft += shrinkSpeed * gameSpeed;
mazeRight -= shrinkSpeed * gameSpeed;
mazeTop += shrinkSpeed * gameSpeed;
mazeBottom -= shrinkSpeed * gameSpeed;
// Recreate walls periodically
if (LK.ticks % 30 === 0) {
createMazeWalls();
}
// Check if maze is too small (game over condition)
if (mazeRight - mazeLeft < 200 || mazeBottom - mazeTop < 200) {
// Update all persistent statistics
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
// Update game statistics
gameStats.totalGamesPlayed++;
gameStats.totalScore += currentScore;
gameStats.bestMultiplier = Math.max(gameStats.bestMultiplier, scoreMultiplier);
// Save to storage
storage.totalGamesPlayed = gameStats.totalGamesPlayed;
storage.totalScore = gameStats.totalScore;
storage.bestMultiplier = gameStats.bestMultiplier;
storage.totalHazardsDestroyed = gameStats.totalHazardsDestroyed;
// Final achievement check
checkAchievements();
LK.showGameOver();
return;
}
// Update score
LK.setScore(Math.floor(LK.ticks / 60 * scoreMultiplier));
scoreTxt.setText(LK.getScore().toString());
// Increase multiplier every 30 seconds
var currentTime = Math.floor(LK.ticks / 60);
if (currentTime - lastMultiplierIncrease >= 30) {
scoreMultiplier++;
lastMultiplierIncrease = currentTime;
multiplierTxt.setText('x' + scoreMultiplier);
// Multiplier reward animation
tween(multiplierTxt, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(multiplierTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
// Spawn hazards
hazardSpawnTimer++;
var spawnRate = Math.max(60, 180 - scoreMultiplier * 20);
if (hazardSpawnTimer >= spawnRate) {
spawnHazard();
hazardSpawnTimer = 0;
}
// Spawn powerups (rare)
powerupSpawnTimer++;
if (powerupSpawnTimer >= 600 && Math.random() < 0.3) {
// Every 10 seconds, 30% chance
spawnPowerup();
powerupSpawnTimer = 0;
}
// Check collision with walls
if (!player.shieldActive) {
if (player.x <= mazeLeft + 30 || player.x >= mazeRight - 30 || player.y <= mazeTop + 30 || player.y >= mazeBottom - 30) {
// Update high score
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
LK.getSound('collision').play();
LK.showGameOver();
return;
}
}
// Update and check hazard collisions
for (var i = hazards.length - 1; i >= 0; i--) {
var hazard = hazards[i];
if (hazard.isActive === false) {
hazard.destroy();
hazards.splice(i, 1);
continue;
}
// Check collision with turret bullets
if (hazard.bullets) {
for (var j = hazard.bullets.length - 1; j >= 0; j--) {
var bullet = hazard.bullets[j];
if (player.intersects(bullet)) {
if (player.shieldActive) {
// Shield absorbs the hit
player.shieldActive = false;
// Reset multiplier and timer
scoreMultiplier = 1;
lastMultiplierIncrease = Math.floor(LK.ticks / 60);
multiplierTxt.setText('x' + scoreMultiplier);
// Flash multiplier text red then back to orange
tween(multiplierTxt, {
tint: 0xFF0000
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(multiplierTxt, {
tint: 0xFFAA00
}, {
duration: 100,
easing: tween.linear
});
}
});
// Stop any existing tweens on player graphics
tween.stop(player.getChildAt(0), {
tint: true
});
// Create sequential white/yellow blink animation
tween(player.getChildAt(0), {
tint: 0xffffff
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(player.getChildAt(0), {
tint: 0xffff00
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(player.getChildAt(0), {
tint: 0xffffff
}, {
duration: 50,
easing: tween.linear
});
}
});
}
});
bullet.destroy();
hazard.bullets.splice(j, 1);
} else {
// Update high score before game over
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
LK.getSound('collision').play();
LK.showGameOver();
return;
}
}
}
}
// Special handling for BouncingWall
if (hazard.constructor === BouncingWall && player.intersects(hazard)) {
// Calculate push force
var dx = player.x - hazard.x;
var dy = player.y - hazard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var forceX = dx / distance * 150;
var forceY = dy / distance * 150;
player.x += forceX;
player.y += forceY;
}
// Score penalty
var newScore = Math.max(0, LK.getScore() - 50);
LK.setScore(newScore);
scoreTxt.setText(LK.getScore().toString());
// Blue flash effect
LK.getSound('collision').play();
var playerGraphics = player.getChildAt(0);
tween(playerGraphics, {
tint: 0x0000FF
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerGraphics, {
tint: 0xFFFFFF
}, {
duration: 100
});
}
});
} else if (player.intersects(hazard)) {
if (player.shieldActive) {
// Shield absorbs the hit
player.shieldActive = false;
// Reset multiplier and timer
scoreMultiplier = 1;
lastMultiplierIncrease = Math.floor(LK.ticks / 60);
multiplierTxt.setText('x' + scoreMultiplier);
// Flash multiplier text red then back to orange
tween(multiplierTxt, {
tint: 0xFF0000
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(multiplierTxt, {
tint: 0xFFAA00
}, {
duration: 100,
easing: tween.linear
});
}
});
// Stop any existing tweens on player graphics
tween.stop(player.getChildAt(0), {
tint: true
});
// Create sequential white/yellow blink animation
tween(player.getChildAt(0), {
tint: 0xffffff
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(player.getChildAt(0), {
tint: 0xffff00
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(player.getChildAt(0), {
tint: 0xffffff
}, {
duration: 50,
easing: tween.linear
});
}
});
}
});
} else {
// Create explosion effect before game over
for (var p = 0; p < 12; p++) {
var particle = game.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x,
y: player.y,
scaleX: 0.2,
scaleY: 0.2,
tint: Math.random() > 0.5 ? 0xFF0000 : 0xFFFF00
}));
var speedX = (Math.random() - 0.5) * 20;
var speedY = (Math.random() - 0.5) * 20;
explosionParticles.push(particle);
tween(particle, {
x: particle.x + speedX,
y: particle.y + speedY,
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
particle.destroy();
var index = explosionParticles.indexOf(particle);
if (index > -1) explosionParticles.splice(index, 1);
}
});
}
// Update high score before game over
var currentScore = LK.getScore();
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
LK.getSound('collision').play();
LK.showGameOver();
return;
}
}
}
// Update and check powerup collisions
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player.intersects(powerup)) {
LK.getSound('powerup').play();
if (powerup.type === 'slow') {
slowMotionTimer = 180; // 3 seconds
} else if (powerup.type === 'shield') {
player.activateShield();
} else if (powerup.constructor === TimePowerup) {
// Ultra slow motion effect
timeSlowActive = true;
timeSlowDuration = 240; // 4 seconds
} else if (powerup.constructor === MultiplierBoost) {
// Double score multiplier temporarily
scoreMultiplier += 2;
multiplierTxt.setText('x' + scoreMultiplier);
// Bonus score animation
tween(multiplierTxt, {
scaleX: 2,
scaleY: 2,
tint: 0xFFD700
}, {
duration: 300,
onFinish: function onFinish() {
tween(multiplierTxt, {
scaleX: 1,
scaleY: 1,
tint: 0xFFAA00
}, {
duration: 200
});
}
});
}
// Powerup negative effect: temporary speed boost to hazards (except for time powerups)
if (powerup.constructor !== TimePowerup) {
tempSpeedBoostTimer = 30; // 0.5 seconds
}
powerup.destroy();
powerups.splice(i, 1);
}
}
// Near miss detection and saw blade vs bullet collision
for (var i = 0; i < hazards.length; i++) {
var hazard = hazards[i];
// Near miss detection
if (hazard.nearMissTimer !== undefined && hazard.nearMissTimer <= 0) {
var dx = player.x - hazard.x;
var dy = player.y - hazard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var collisionDistance = 50; // Approximate collision distance
if (distance > collisionDistance + 40 && distance < collisionDistance + 60) {
// Near miss detected
LK.getSound('nearmiss').play();
hazard.nearMissTimer = 60; // Cooldown
// White flash on player
var playerGraphics = player.getChildAt(0);
tween(playerGraphics, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerGraphics, {
tint: 0x00ff00
}, {
duration: 50
});
}
});
}
}
// Saw blade vs bullet collision
if (hazard.constructor === SawBlade) {
for (var j = 0; j < hazards.length; j++) {
var otherHazard = hazards[j];
if (otherHazard.constructor === Turret && otherHazard.bullets) {
for (var k = otherHazard.bullets.length - 1; k >= 0; k--) {
var bullet = otherHazard.bullets[k];
if (hazard.intersects(bullet)) {
// Collision detected - destroy both
var currentTime = Math.floor(LK.ticks / 60);
// Combo system
if (currentTime - lastComboTime <= 2) {
// Within 2 seconds
comboCounter++;
} else {
comboCounter = 1;
}
lastComboTime = currentTime;
// Bonus points for combo
var bonusPoints = 10 * comboCounter;
LK.setScore(LK.getScore() + bonusPoints);
scoreTxt.setText(LK.getScore().toString());
// Update destruction statistics
gameStats.totalHazardsDestroyed++;
// Visual combo feedback
if (comboCounter > 1) {
var comboText = game.addChild(new Text2('x' + comboCounter + '!', {
size: 40,
fill: 0xFFD700
}));
comboText.x = hazard.x;
comboText.y = hazard.y;
comboText.anchor.set(0.5, 0.5);
tween(comboText, {
y: comboText.y - 60,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
comboText.destroy();
}
});
}
hazard.destroy();
hazards.splice(i, 1);
bullet.destroy();
otherHazard.bullets.splice(k, 1);
i--; // Adjust index since we removed an element
break;
}
}
}
}
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -90,9 +90,9 @@
if (LK.ticks % 20 === 0) {
var electricityTint = Math.random() > 0.5 ? 0xffffff : 0x9966ff;
orbGraphics.tint = electricityTint;
var self_ref = self;
- setTimeout(function () {
+ LK.setTimeout(function () {
if (orbGraphics.parent) orbGraphics.tint = 0xffffff;
}, 100);
}
// Apply magnetic force to player if within range
@@ -306,9 +306,9 @@
if (LK.ticks % 15 === 0) {
var sparkle = Math.random() > 0.5 ? 0xffffff : 0xff66ff;
timeGraphics.tint = sparkle;
var self_ref = self;
- setTimeout(function () {
+ LK.setTimeout(function () {
if (timeGraphics.parent) timeGraphics.tint = 0xffffff;
}, 200);
}
if (self.lifeTimer <= 0) {