Code edit (1 edits merged)
Please save this source code
User prompt
Ritim Gezegeni: Neptün Macerası
Initial prompt
dokunmatikdahilyap: 🎮 Oyun Adı: Ritim Gezegeni: Neptün Macerası 🪐 Müziğin ritmiyle çalışan bir gezegende, düzeni sağla! 🌌 KONU (Hikâye): Yıl 3025. Galaksinin kenarındaki mavi gezegen Neptün, sıradan bir yer değil. Tüm sistemi müzikle çalışan bu gezegenin ritmi bozuldu! Müzik Kristalleri çatladı ve ritmik enerji dağılmaya başladı. Eğer ritim toparlanamazsa, Neptün sonsuz bir sessizliğe gömülecek. Sen bir Uzay Ritim Kaşifi olarak, ritimle çalışan uzay geminle Neptün’e iniş yapıyorsun. Görevin: ritim kaynaklarını topla, ritmi bozmadan engelleri aş ve kayıp melodileri bul! 🕹️ OYNANIŞ (Gameplay): 🎵 Ritim Temelli Hareket: Oyuncu, müzik ritmine göre adım atar ve eylem yapar. (Tıpkı bir dans oyunu ama keşif ve bulmaca odaklı!) Düşmanlar, tuzaklar, kapılar ve kristaller müziğe göre hareket eder. Ritmi kaçırırsan enerji kaybedersin. 🧩 Mini Bulmacalar: Her bölümde ritme dayalı bulmacalar bulunur. Örneğin: Ses dalgası sırasını çözmek, Notaları sırayla çalmak, Melodi tamamlamak gibi. 🎛️ Klavye / Oyun Kolu Kontrolleri: Yön Tuşları / Analog Çubuk: Ritme uygun adım at Boşluk / A Tuşu: Ritim Patlaması – Etrafındaki düşmanları saf dışı bırak E Tuşu: Müzikal Kapı Aç – Gizli geçitleri aktif et Shift / B Tuşu: Kalkan – Ritme uygun savunma Q Tuşu: Tempo Değiştir – Daha hızlı veya yavaş ritimle geçiş sağlar 🗺️ BÖLÜMLER (Seviyeler): Başlangıç Kubbesi – Temel ritim hareketlerini öğren Donmuş Senfoni Vadisi – Buzlu zeminler ve kayan platformlar Melodi Fırtınası – Ritmin durduğu an her şey donar, zamanlama şart Echo Mağaraları – Yankılarla gizli melodileri keşfet Neptün'ün Kalbi – Ana kristal seni sınar, tam ritim uyumu gerek (Final boss!) 💡 NELERİYLE FARK YARATIR? Özellik Neden Etkileyici? 🎶 Ritim tabanlı keşif Müzik üzerinden öğrenme ve eğlence bir arada 🎮 Klasik kontrol + ritim uyumu Geniş oyuncu kitlesine uygun ve erişilebilir ❄️ Neptün teması Buzlu-mavi atmosferle benzersiz görsellik 🧠 Müzikli bulmacalar Hem zeka hem zamanlama gerektiriyor 🌠 Hikâye ve evren Bilimkurgu + ritim + macera birleşimi 🏆 Yarışma Uygunluğu: ✅ Müzik merkezde ✔️ ✅ Görsel efektler ✔️ ✅ Keşif ve bulmaca ögeleri ✔️ ✅ Seviyeli, yaratıcı tema ✔️ 🎁 Bonus Fikirler: Özel güçler: Ritim Bombası, Melodi Kalkanı Kendi melodini yarat: Seviye sonlarında oyuncunun ritim kaydedebileceği bir alan Topluluk bölümü: Steam veya özel sunucu üzerinden başkalarının seviyelerini oynayabilme
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Ritim Kaynağı (Collectible)
var Beat = Container.expand(function () {
var self = Container.call(this);
var beatGfx = self.attachAsset('beat', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Boss Kristali
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGfx = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 5;
self.pulse = function () {
tween(bossGfx, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(bossGfx, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
// Düşman (hareketli engel)
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dir = 1; // 1: sağ, -1: sol
self.speed = 6;
self.range = 300; // Hareket aralığı
self.baseX = 0;
self.init = function (x) {
self.baseX = x;
};
self.update = function () {
self.x += self.dir * self.speed;
if (self.x > self.baseX + self.range) self.dir = -1;
if (self.x < self.baseX - self.range) self.dir = 1;
};
return self;
});
// Engeller
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Ritim Efekti (Pulse)
var Pulse = Container.expand(function () {
var self = Container.call(this);
var pulseGfx = self.attachAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.show = function (x, y) {
self.x = x;
self.y = y;
pulseGfx.scaleX = 0.5;
pulseGfx.scaleY = 0.5;
pulseGfx.alpha = 0.3;
tween(pulseGfx, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 350
});
};
return self;
});
// Uzay Gemisi (Player)
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGfx = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.energy = 3; // Can
self.invincible = false; // Hasar sonrası kısa süreli dokunulmazlık
// Enerji kaybı animasyonu
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(shipGfx, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(shipGfx, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
return self;
});
// Teleport hareket eden düşman
var TeleportEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy3', {
anchorX: 0.5,
anchorY: 0.5
});
self.cooldown = 0;
self.teleportInterval = 120; // 2 saniye (60fps)
self.minDist = 200;
self.maxDist = 400;
self.init = function () {};
self.update = function () {
if (typeof self.cooldown !== "number") self.cooldown = 0;
self.cooldown--;
if (self.cooldown <= 0 && typeof ship !== "undefined" && ship) {
// Teleport: player'a yakın bir noktaya ışınlan
var angle = Math.random() * Math.PI * 2;
var dist = self.minDist + Math.random() * (self.maxDist - self.minDist);
var tx = ship.x + Math.cos(angle) * dist;
var ty = ship.y + Math.sin(angle) * dist;
// Sınırları aşmasın
if (tx < 120) tx = 120;
if (tx > GAME_W - 120) tx = GAME_W - 120;
if (ty < 300) ty = 300;
if (ty > GAME_H - 200) ty = GAME_H - 200;
self.x = tx;
self.y = ty;
self.cooldown = self.teleportInterval + Math.floor(Math.random() * 60);
}
};
return self;
});
// Zigzag hareket eden düşman
var ZigzagEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.dir = 1;
self.speed = 5;
self.range = 250;
self.baseX = 0;
self.baseY = 0;
self.angle = 0;
self.init = function (x, y) {
self.baseX = x;
self.baseY = y;
self.angle = 0;
};
self.update = function () {
self.angle += 0.025;
self.x = self.baseX + Math.sin(self.angle) * self.range;
self.y = self.baseY + Math.cos(self.angle) * 60;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0033
});
/****
* Game Code
****/
// 5 yeni background asset (örnek id'ler, gerçek id'ler asset yöneticisinden alınmalı)
// Yeni home tuşu asset'i (sadece home butonu için kullanılacak, dekoratif değil)
// Unique assets for each shop character (no enemy/deco/pulse/beat/boss assets)
// Yeni: Teleport düşman
// Yeni: Zigzag düşman
// Müzik (looping, ritmik)
// Sesler
// Ritim efekti (görsel feedback)
// Boss kristali (finalde)
// Düşman (hareketli engel)
// Engeller
// Ritim kaynağı (collectible)
// Uzay gemisi (player)
// Oyun alanı boyutları
var GAME_W = 2048;
var GAME_H = 2732;
// 5 farklı background asset id'si
var BG_ASSETS = ['bg1', 'bg2', 'bg3', 'bg4', 'bg5'];
var bgImage = null;
// Arka planı güncelleyen fonksiyon
function updateBackgroundForLevel(lvlNum) {
// 1-5: bg1, 6-10: bg2, 11-15: bg3, 16-20: bg4, 21+: bg5
var idx = Math.floor((lvlNum - 1) / 5);
if (idx < 0) idx = 0;
if (idx > 4) idx = 4;
var assetId = BG_ASSETS[idx];
// Arka plan zaten varsa kaldır
if (bgImage && typeof bgImage.destroy === "function") {
bgImage.destroy();
bgImage = null;
}
// Yeni arka planı ekle
bgImage = LK.getAsset(assetId, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 1,
scaleY: 1
});
// Her zaman en arkada olmalı
if (game.children && game.children.length > 0) {
game.addChildAt(bgImage, 0);
} else {
game.addChild(bgImage);
}
}
// Ritim parametreleri
var BPM = 100; // Dakikadaki vuruş
var BEAT_INTERVAL = Math.round(60 * 1000 / BPM); // ms cinsinden
var lastBeatTick = 0;
// Oyun durumu
var score = 0;
// Bölüm tanımları (her biri farklı engel, düşman ve beat dizilimi içerir)
var LEVELS = [
// 1-19: Normal bölümler, 20: Boss
// Her bölüm: {beats, obstacles, enemies}
// beats: [{x, y}, ...], obstacles: [{x, y}], enemies: [{x, y, range, type}]
{
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}],
obstacles: [{
x: 1024,
y: 1400
}],
enemies: [{
x: 1024,
y: 1200,
range: 200
},
// klasik
{
x: 700,
y: 1000,
type: "zigzag"
} // zigzag
]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}],
obstacles: [{
x: 700,
y: 1500
}, {
x: 1350,
y: 1500
}],
enemies: [{
x: 1024,
y: 1300,
range: 300
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1100
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1100
}, {
x: 1024,
y: 1000
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
enemies: [{
x: 700,
y: 1200,
range: 200
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}],
enemies: [{
x: 1024,
y: 1300,
range: 350
}, {
x: 800,
y: 1100,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
enemies: [{
x: 700,
y: 1200,
range: 250
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}],
enemies: [{
x: 700,
y: 1200,
range: 300
}, {
x: 1350,
y: 1200,
type: "zigzag"
}, {
x: 1024,
y: 1000,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}],
enemies: [{
x: 1024,
y: 1300,
range: 400
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 350
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 450
}, {
x: 1240,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 400
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 500
}, {
x: 800,
y: 1200,
type: "teleport"
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 450
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 550
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 500
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 600
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}, {
x: 600,
y: 1700
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 550
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}, {
x: 1024,
y: 1800
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 650
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 600
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}, {
x: 900,
y: 1500,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}, {
x: 1024,
y: 1800
}, {
x: 800,
y: 1900
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 700
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
},
// 20. bölüm: Boss
{
boss: true
}];
var maxScore = 0; // Her bölümde dinamik olarak ayarlanacak
var energy = 3;
var level = 1;
var onBoss = false;
var bossDefeated = false;
// Ana objeler
var ship;
var beats = [];
var obstacles = [];
var enemies = [];
var boss;
var pulseEffect;
// GUI
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var energyTxt = new Text2('♥♥♥', {
size: 90,
fill: 0xFF5252
});
energyTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(energyTxt);
// Home button directly below the hearts (energyTxt)
var homeBtnAbove = LK.getAsset('homeBtn', {
anchorX: 1,
anchorY: 0,
scaleX: 0.7,
scaleY: 0.7,
x: 0,
y: 0
});
homeBtnAbove.x = energyTxt.x;
homeBtnAbove.y = energyTxt.y + energyTxt.height + 24;
homeBtnAbove.visible = true;
homeBtnAbove.down = function () {
// Return to menu
showStartMenu();
};
LK.gui.topRight.addChild(homeBtnAbove);
// Level göstergesi (sol alt)
var levelTxt = new Text2('Level 1', {
size: 90,
fill: "#fff"
});
levelTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(levelTxt);
// Beat indicator
var beatTxt = new Text2('♪', {
size: 100,
fill: 0xFFE066
});
beatTxt.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(beatTxt);
// Home button (in-game, returns to start menu) - now at bottom right, using a new asset (no text)
var homeBtn = LK.getAsset('homeBtn', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.9,
x: 0,
y: 0
});
homeBtn.visible = false;
// Place at bottom right of the GUI (safe area, not overlapping)
homeBtn.x = LK.gui.width - 180;
homeBtn.y = LK.gui.height - 180;
homeBtn.down = function () {
// Hide in-game UI, show start menu
showStartMenu();
// --- Add Richness to Main Menu: Extra Info, Effects, and Decorations ---
// 1. Short description under the game title
var subtitleTxt = new Text2("Move to the rhythm, collect beats!", {
size: 70,
fill: 0xFFE066,
font: "Arial Black"
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = GAME_W / 2;
subtitleTxt.y = GAME_H / 2 - 200;
game.addChild(subtitleTxt);
// 2. Animated effect in main menu (e.g. spinning beat)
// Only visible in menu
var menuAnimBeat = LK.getAsset('beat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 + 420,
y: GAME_H / 2 - 320
});
game.addChild(menuAnimBeat);
menuAnimBeat.visible = true;
menuAnimBeat.menuAnimTick = 0;
menuAnimBeat.update = function () {
this.menuAnimTick++;
this.rotation += 0.04;
this.scaleX = 1.1 + Math.sin(this.menuAnimTick * 0.07) * 0.12;
this.scaleY = 1.1 + Math.cos(this.menuAnimTick * 0.07) * 0.12;
};
// 3. Main menu: total level and boss info
var infoTxt = new Text2("20 levels total (19 normal + 1 boss)", {
size: 60,
fill: "#fff"
});
infoTxt.anchor.set(0.5, 0.5);
infoTxt.x = GAME_W / 2;
infoTxt.y = GAME_H / 2 + 320;
game.addChild(infoTxt);
// 4. Main menu: best score (most beats collected)
var bestScoreTxt = new Text2("", {
size: 60,
fill: 0x00E676
});
bestScoreTxt.anchor.set(0.5, 0.5);
bestScoreTxt.x = GAME_W / 2;
bestScoreTxt.y = GAME_H / 2 + 400;
game.addChild(bestScoreTxt);
function updateBestScoreTxt() {
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
bestScoreTxt.setText("Best score: " + best + " beat");
}
updateBestScoreTxt();
// 5. Main menu: decorative "sword" effect (vertical, next to title)
var swordDeco = LK.getAsset('sword', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2 - 420,
y: GAME_H / 2 - 320,
rotation: Math.PI / 2
});
game.addChild(swordDeco);
// 6. Main menu: "pulse" effect (animated, behind title)
var menuPulse = LK.getAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.18,
x: GAME_W / 2,
y: GAME_H / 2 - 320
});
game.addChild(menuPulse);
menuPulse.menuPulseTick = 0;
menuPulse.update = function () {
this.menuPulseTick++;
this.scaleX = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.scaleY = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.alpha = 0.12 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.12;
};
// (Removed sword_btn decorative assets from menu to ensure no decor on buttons)
// 9. Show/hide extra menu elements only in menu
var menuDecoratives = [subtitleTxt, menuAnimBeat, infoTxt, bestScoreTxt, swordDeco, menuPulse];
// Extend original showStartMenu function
var oldShowStartMenu = showStartMenu;
showStartMenu = function showStartMenu() {
if (typeof oldShowStartMenu === "function") oldShowStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = true;
}
updateBestScoreTxt();
};
// Extend original hideStartMenu function
var oldHideStartMenu = hideStartMenu;
hideStartMenu = function hideStartMenu() {
if (typeof oldHideStartMenu === "function") oldHideStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = false;
}
};
// Update animated menu objects
var oldGameUpdate = game.update;
game.update = function () {
// If in menu, animate
if (startBtn.visible) {
if (menuAnimBeat && typeof menuAnimBeat.update === "function") menuAnimBeat.update();
if (menuPulse && typeof menuPulse.update === "function") menuPulse.update();
}
if (typeof oldGameUpdate === "function") oldGameUpdate();
};
// Update best score at game end
var oldAddCoins = addCoins;
addCoins = function addCoins(n) {
if (typeof oldAddCoins === "function") oldAddCoins(n);
// Update best score
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
if (score > best) {
storage.bestScore = score;
updateBestScoreTxt();
}
};
// --- Ana Menüye Zenginlik Kat: Ekstra Bilgi, Efekt ve Dekorasyonlar ---
// 1. Oyun başlığı altına kısa açıklama
var subtitleTxt = new Text2("Ritme göre hareket et, altınları topla!", {
size: 70,
fill: 0xFFE066,
font: "Arial Black"
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = GAME_W / 2;
subtitleTxt.y = GAME_H / 2 - 200;
game.addChild(subtitleTxt);
// 2. Ana menüde animasyonlu bir efekt (ör: dönen bir beat)
// Sadece menüde görünsün
var menuAnimBeat = LK.getAsset('beat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 + 420,
y: GAME_H / 2 - 320
});
game.addChild(menuAnimBeat);
menuAnimBeat.visible = true;
menuAnimBeat.menuAnimTick = 0;
menuAnimBeat.update = function () {
this.menuAnimTick++;
this.rotation += 0.04;
this.scaleX = 1.1 + Math.sin(this.menuAnimTick * 0.07) * 0.12;
this.scaleY = 1.1 + Math.cos(this.menuAnimTick * 0.07) * 0.12;
};
// 3. Ana menüde toplam bölüm ve boss bölümü bilgisi
var infoTxt = new Text2("Toplam 20 bölüm (19 normal + 1 boss)", {
size: 60,
fill: "#fff"
});
infoTxt.anchor.set(0.5, 0.5);
infoTxt.x = GAME_W / 2;
infoTxt.y = GAME_H / 2 + 320;
game.addChild(infoTxt);
// 4. Ana menüde en iyi skor (en çok toplanan beat)
var bestScoreTxt = new Text2("", {
size: 60,
fill: 0x00E676
});
bestScoreTxt.anchor.set(0.5, 0.5);
bestScoreTxt.x = GAME_W / 2;
bestScoreTxt.y = GAME_H / 2 + 400;
game.addChild(bestScoreTxt);
function updateBestScoreTxt() {
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
bestScoreTxt.setText("En iyi skor: " + best + " beat");
}
updateBestScoreTxt();
// 5. Ana menüde dekoratif bir "sword" efekti (dikey, başlık yanında)
var swordDeco = LK.getAsset('sword', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2 - 420,
y: GAME_H / 2 - 320,
rotation: Math.PI / 2
});
game.addChild(swordDeco);
// 6. Ana menüde bir "pulse" efekti (animasyonlu, başlık arkasında)
var menuPulse = LK.getAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.18,
x: GAME_W / 2,
y: GAME_H / 2 - 320
});
game.addChild(menuPulse);
menuPulse.menuPulseTick = 0;
menuPulse.update = function () {
this.menuPulseTick++;
this.scaleX = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.scaleY = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.alpha = 0.12 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.12;
};
// (Removed sword_btn decorative assets from menu to ensure no decor on buttons)
// 9. Ana menüdeki ekstra elemanları sadece menüde göster/gizle
var menuDecoratives = [subtitleTxt, menuAnimBeat, infoTxt, bestScoreTxt, swordDeco, menuPulse];
// Orijinal showStartMenu fonksiyonunu genişlet
var oldShowStartMenu = showStartMenu;
showStartMenu = function showStartMenu() {
if (typeof oldShowStartMenu === "function") oldShowStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = true;
}
updateBestScoreTxt();
};
// Orijinal hideStartMenu fonksiyonunu genişlet
var oldHideStartMenu = hideStartMenu;
hideStartMenu = function hideStartMenu() {
if (typeof oldHideStartMenu === "function") oldHideStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = false;
}
};
// Ana menüdeki animasyonlu objeleri update et
var oldGameUpdate = game.update;
game.update = function () {
// Menüdeysek animasyonları döndür
if (startBtn.visible) {
if (menuAnimBeat && typeof menuAnimBeat.update === "function") menuAnimBeat.update();
if (menuPulse && typeof menuPulse.update === "function") menuPulse.update();
}
if (typeof oldGameUpdate === "function") oldGameUpdate();
};
// Oyun sonunda en iyi skoru güncelle
var oldAddCoins = addCoins;
addCoins = function addCoins(n) {
if (typeof oldAddCoins === "function") oldAddCoins(n);
// En iyi skor güncelle
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
if (score > best) {
storage.bestScore = score;
updateBestScoreTxt();
}
};
homeBtn.visible = false;
};
// Add to bottom right GUI overlay
LK.gui.bottomRight.addChild(homeBtn);
pulseEffect = new Pulse();
game.addChild(pulseEffect);
// Game starter
function startLevel() {
// Clear
for (var i = 0; i < beats.length; i++) beats[i].destroy();
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
beats = [];
obstacles = [];
enemies = [];
if (boss) {
boss.destroy();
boss = null;
}
onBoss = false;
bossDefeated = false;
score = 0;
energy = 3;
// Level data
levelTxt.setText("Level " + level);
// Arka planı güncelle
updateBackgroundForLevel(level);
// Boss ise boss fonksiyonuna geç
var lvl = LEVELS[(level - 1) % LEVELS.length];
if (lvl && lvl.boss) {
startBoss();
return;
}
// Ship
if (ship) ship.destroy();
ship = new Ship();
ship.x = GAME_W / 2;
ship.y = GAME_H - 400;
game.addChild(ship);
// Beats
maxScore = lvl.beats.length;
scoreTxt.setText(score + "/" + maxScore);
energyTxt.setText("♥".repeat(energy));
for (var i = 0; i < lvl.beats.length; i++) {
var b = new Beat();
b.x = lvl.beats[i].x;
b.y = lvl.beats[i].y;
beats.push(b);
game.addChild(b);
}
// Obstacles
for (var i = 0; i < lvl.obstacles.length; i++) {
var obs = new Obstacle();
obs.x = lvl.obstacles[i].x;
obs.y = lvl.obstacles[i].y;
obstacles.push(obs);
game.addChild(obs);
}
// Enemies
for (var i = 0; i < lvl.enemies.length; i++) {
var enemyData = lvl.enemies[i];
var e;
// Add different enemy types: if type field exists, use it, otherwise classic Enemy
if (enemyData.type === "zigzag") {
e = new ZigzagEnemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init(enemyData.x, enemyData.y);
} else if (enemyData.type === "teleport") {
e = new TeleportEnemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init();
} else {
e = new Enemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init(e.x);
if (typeof enemyData.range === "number") e.range = enemyData.range;
}
enemies.push(e);
game.addChild(e);
}
}
// Start boss level
function startBoss() {
onBoss = true;
// Arka planı güncelle (boss bölümü için de)
updateBackgroundForLevel(level);
for (var i = 0; i < beats.length; i++) beats[i].destroy();
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
beats = [];
obstacles = [];
enemies = [];
score = 0;
maxScore = 5; // Boss bölümünde 5 altın
energy = 5; // Boss bölümünde 5 can
scoreTxt.setText("0/5");
energyTxt.setText("♥♥♥♥♥");
// Boss hareketli: X ekseninde hızlı zigzag + Y ekseninde yavaşça yukarı-aşağı
boss = new Boss();
boss.x = GAME_W / 2;
boss.y = 700;
boss.moveTick = 0;
boss.moveDir = 1;
boss.moveDirY = 1;
boss.update = function () {
// X ekseninde hızlı zigzag
boss.moveTick++;
boss.x += boss.moveDir * 18;
if (boss.x > GAME_W - 220) boss.moveDir = -1;
if (boss.x < 220) boss.moveDir = 1;
// Y ekseninde yavaşça yukarı-aşağı
if (boss.moveTick % 30 === 0) {
boss.y += boss.moveDirY * 40;
if (boss.y > 1100) boss.moveDirY = -1;
if (boss.y < 500) boss.moveDirY = 1;
}
};
// 5 altın (beat) boss etrafında, toplarsak kazanılır
var bossBeatPos = [{
x: boss.x - 180,
y: boss.y + 180
}, {
x: boss.x + 180,
y: boss.y + 180
}, {
x: boss.x - 180,
y: boss.y - 180
}, {
x: boss.x + 180,
y: boss.y - 180
}, {
x: boss.x,
y: boss.y
}];
for (var i = 0; i < 5; i++) {
var b = new Beat();
// Beat'ler boss ile birlikte hareket etsin
b.offsetX = bossBeatPos[i].x - boss.x;
b.offsetY = bossBeatPos[i].y - boss.y;
b.update = function () {
// Her frame boss ile birlikte hareket et
if (boss) {
this.x = boss.x + this.offsetX;
this.y = boss.y + this.offsetY;
}
};
beats.push(b);
game.addChild(b);
}
game.addChild(boss);
LK.getSound('boss').play();
}
// Ritim tick'i
function onBeat() {
// Ritim efekti
if (typeof ship !== "undefined" && ship) {
pulseEffect.show(ship.x, ship.y);
}
// Ritim göstergesi animasyonu
tween(beatTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(beatTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Adım sesi
LK.getSound('step').play();
}
// Ritimle hareket için bekleyen dokunuş
var moveQueued = false;
var queuedMove = {
x: 0,
y: 0
};
// Hareket yönleri
function getMoveDir(x, y) {
if (typeof ship === "undefined" || !ship) {
return {
dx: 0,
dy: 0
};
}
var dx = x - ship.x;
var dy = y - ship.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 80) return {
dx: 0,
dy: 0
};
var angle = Math.atan2(dy, dx);
var step = 220;
return {
dx: Math.round(Math.cos(angle) * step),
dy: Math.round(Math.sin(angle) * step)
};
}
// Hareketi uygula (ritimle)
function doMove() {
if (!moveQueued) return;
if (typeof ship === "undefined" || !ship) {
moveQueued = false;
return;
}
var dx = queuedMove.dx;
var dy = queuedMove.dy;
var newX = ship.x + dx;
var newY = ship.y + dy;
// Sınır kontrolü
if (newX < 120) newX = 120;
if (newX > GAME_W - 120) newX = GAME_W - 120;
if (newY < 300) newY = 300;
if (newY > GAME_H - 200) newY = GAME_H - 200;
// Engel çarpışma kontrolü
var blocked = false;
for (var i = 0; i < obstacles.length; i++) {
if (rectsIntersect(newX, newY, ship, obstacles[i].x, obstacles[i].y, obstacles[i])) {
blocked = true;
break;
}
}
if (!blocked) {
tween(ship, {
x: newX,
y: newY
}, {
duration: 120,
easing: tween.cubicOut
});
}
moveQueued = false;
}
// Dikdörtgen çarpışma (merkezden)
function rectsIntersect(x1, y1, obj1, x2, y2, obj2) {
var w1 = obj1.width || 140,
h1 = obj1.height || 140;
var w2 = obj2.width || 160,
h2 = obj2.height || 60;
return Math.abs(x1 - x2) < (w1 + w2) / 2 - 10 && Math.abs(y1 - y2) < (h1 + h2) / 2 - 10;
}
// Dokunma ile hareket yönü seç
game.down = function (x, y, obj) {
if (onBoss && bossDefeated) return;
var dir = getMoveDir(x, y);
queuedMove.dx = dir.dx;
queuedMove.dy = dir.dy;
moveQueued = true;
};
// Hareketli engeller ve boss için update
game.update = function () {
// Ritim tick'i
if (LK.ticks - lastBeatTick >= Math.round(BEAT_INTERVAL / 16.7)) {
lastBeatTick = LK.ticks;
onBeat();
doMove();
}
// Düşman hareketi
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
// Boss ve boss beatleri hareket ettir
if (onBoss && boss && typeof boss.update === "function") {
boss.update();
for (var i = 0; i < beats.length; i++) {
if (typeof beats[i].update === "function") beats[i].update();
}
}
// Düşman çarpışma
for (var i = 0; i < enemies.length; i++) {
if (ship.intersects(enemies[i]) && !ship.invincible) {
energy--;
energyTxt.setText("♥".repeat(energy));
ship.flash();
LK.getSound('hit').play();
if (energy <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
// Ritim kaynağı toplama
for (var i = beats.length - 1; i >= 0; i--) {
if (ship.intersects(beats[i])) {
LK.getSound('collect').play();
beats[i].destroy();
beats.splice(i, 1);
score++;
scoreTxt.setText(score + "/" + maxScore);
// Her beat toplandığında coin ekle
addCoins(1);
if (score >= maxScore) {
level++;
if (level > LEVELS.length) {
LK.showYouWin();
return;
}
LK.setTimeout(function () {
startLevel();
}, 800);
return;
}
}
}
// Boss bölümü
if (onBoss && boss && !bossDefeated) {
// Boss'a çarpınca enerji kaybı
if (ship.intersects(boss) && !ship.invincible) {
energy--;
energyTxt.setText("♥".repeat(energy));
ship.flash();
LK.getSound('hit').play();
if (energy <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Boss etrafındaki 5 altını (beat) toplarsak kazan
for (var i = beats.length - 1; i >= 0; i--) {
if (ship.intersects(beats[i])) {
LK.getSound('collect').play();
beats[i].destroy();
beats.splice(i, 1);
score++;
scoreTxt.setText(score + "/5");
addCoins(1);
if (score >= 5) {
bossDefeated = true;
LK.effects.flashScreen(0x00e676, 1200);
LK.showYouWin();
return;
}
}
}
}
};
// Müzik başlat
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// Başla ve Mağaza tuşları
// Game title above menu buttons
var gameTitle = new Text2("Rhythm Space", {
size: 160,
fill: "#fff",
font: "Arial Black"
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = GAME_W / 2;
gameTitle.y = GAME_H / 2 - 320;
game.addChild(gameTitle);
// Start button background asset (unique, not boss/enemy)
var startBtnBg = LK.getAsset('startBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2,
y: GAME_H / 2 - 100
});
game.addChild(startBtnBg);
var startBtn = new Text2("Start", {
size: 120,
fill: "#fff",
font: "Arial Black"
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = GAME_W / 2;
startBtn.y = GAME_H / 2 - 100;
game.addChild(startBtn);
// Shop button background asset (unique, not boss/enemy)
var shopBtnBg = LK.getAsset('shopBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2,
y: GAME_H / 2 + 100
});
game.addChild(shopBtnBg);
var shopBtn = new Text2("Shop", {
size: 100,
fill: 0xFFE066,
font: "Arial Black"
});
shopBtn.anchor.set(0.5, 0.5);
shopBtn.x = GAME_W / 2;
shopBtn.y = GAME_H / 2 + 100;
game.addChild(shopBtn);
// Oyun başlatıcı fonksiyonunu sarmala
function showStartMenu() {
startBtn.visible = true;
shopBtn.visible = true;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = true;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = true;
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = true;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = true;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = true;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = true;
scoreTxt.visible = false;
energyTxt.visible = false;
levelTxt.visible = false;
beatTxt.visible = false;
pulseEffect.visible = false;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = true;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = true;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = true;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = true;
// Oyun objelerini gizle
if (ship) ship.visible = false;
for (var i = 0; i < beats.length; i++) beats[i].visible = false;
for (var i = 0; i < obstacles.length; i++) obstacles[i].visible = false;
for (var i = 0; i < enemies.length; i++) enemies[i].visible = false;
if (boss) boss.visible = false;
if (typeof gameTitle !== "undefined") gameTitle.visible = true;
// Hide home button in menu
if (typeof homeBtn !== "undefined") homeBtn.visible = false;
// Hide homeBtnAbove (hearts' home button) in menu
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = false;
}
function hideStartMenu() {
startBtn.visible = false;
shopBtn.visible = false;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = false;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = false;
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = false;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = false;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = false;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = false;
scoreTxt.visible = true;
energyTxt.visible = true;
levelTxt.visible = true;
beatTxt.visible = true;
pulseEffect.visible = true;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = false;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = false;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = false;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = false;
if (typeof decoBlock9 !== "undefined") decoBlock9.visible = false;
if (typeof decoBlock10 !== "undefined") decoBlock10.visible = false;
if (typeof decoBlock12 !== "undefined") decoBlock12.visible = false;
if (typeof decoBlock13 !== "undefined") decoBlock13.visible = false;
if (typeof decoBlock14 !== "undefined") decoBlock14.visible = false;
if (typeof decoBlock15 !== "undefined") decoBlock15.visible = false;
if (typeof decoBlock16 !== "undefined") decoBlock16.visible = false;
if (typeof decoBlock17 !== "undefined") decoBlock17.visible = false;
if (typeof decoBlock18 !== "undefined") decoBlock18.visible = false;
if (typeof decoBlock19 !== "undefined") decoBlock19.visible = false;
if (typeof decoBlock20 !== "undefined") decoBlock20.visible = false;
// Oyun objelerini göster
if (ship) ship.visible = true;
for (var i = 0; i < beats.length; i++) beats[i].visible = true;
for (var i = 0; i < obstacles.length; i++) obstacles[i].visible = true;
for (var i = 0; i < enemies.length; i++) enemies[i].visible = true;
if (boss) boss.visible = true;
if (typeof gameTitle !== "undefined") gameTitle.visible = false;
// Show home button in-game
if (typeof homeBtn !== "undefined") homeBtn.visible = true;
// Show homeBtnAbove (hearts' home button) only in-game
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = true;
}
// Başla butonuna basınca oyunu başlat
startBtn.down = function (x, y, obj) {
LK.getSound('btn').play();
hideStartMenu();
startLevel();
};
// Mağaza butonu (karakter skin mağazası)
shopBtn.down = function (x, y, obj) {
LK.getSound('btn').play();
// Hide all decorative blocks when entering the shop
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = false;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = false;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = false;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = false;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = false;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = false;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = false;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = false;
if (typeof decoBlock9 !== "undefined") decoBlock9.visible = false;
if (typeof decoBlock10 !== "undefined") decoBlock10.visible = false;
if (typeof decoBlock12 !== "undefined") decoBlock12.visible = false;
if (typeof decoBlock13 !== "undefined") decoBlock13.visible = false;
if (typeof decoBlock14 !== "undefined") decoBlock14.visible = false;
if (typeof decoBlock15 !== "undefined") decoBlock15.visible = false;
if (typeof decoBlock16 !== "undefined") decoBlock16.visible = false;
if (typeof decoBlock17 !== "undefined") decoBlock17.visible = false;
if (typeof decoBlock18 !== "undefined") decoBlock18.visible = false;
if (typeof decoBlock19 !== "undefined") decoBlock19.visible = false;
if (typeof decoBlock20 !== "undefined") decoBlock20.visible = false;
// Show shop UI for character skins
showShopMenu();
};
// --- Karakter Skin Mağazası ---
// Skin tanımları (10 farklı skin, 1. skin açık, diğerleri kilitli, hepsi farklı asset)
var SKINS = [{
id: "ship",
name: "Orion",
color: 0x3a9cff,
price: 0,
asset: "ship"
}, {
id: "ship2",
name: "Helios",
color: 0xffd700,
price: 20,
asset: "skin_ship2"
}, {
id: "ship3",
name: "Nebula",
color: 0x8e44ad,
price: 40,
asset: "skin_ship3"
}, {
id: "ship4",
name: "Cosmos",
color: 0x27ae60,
price: 60,
asset: "skin_ship4"
}, {
id: "ship5",
name: "Astera",
color: 0xe67e22,
price: 80,
asset: "skin_ship5"
}, {
id: "ship6",
name: "Vortex",
color: 0xff5252,
price: 100,
asset: "skin_ship6"
}, {
id: "ship7",
name: "Zenith",
color: 0x7cf7ff,
price: 120,
asset: "skin_ship7"
}, {
id: "ship8",
name: "Aurion",
color: 0xf1c40f,
price: 140,
asset: "skin_ship8"
}, {
id: "ship9",
name: "Quasar",
color: 0x00e676,
price: 160,
asset: "skin_ship9"
}, {
id: "ship10",
name: "Pulsar",
color: 0x00bcd4,
price: 200,
asset: "skin_ship10"
}];
// Kalıcı veri için storage plugin
// Oyuncunun sahip olduğu paralar (toplanan beat sayısı)
function getPlayerCoins() {
var coins = storage.coins;
if (typeof coins !== "number" || isNaN(coins)) coins = 0;
return coins;
}
function setPlayerCoins(val) {
storage.coins = val;
}
// Açık skinler (dizi: 1 = açık, 0 = kilitli)
function getUnlockedSkins() {
var arr = storage.unlockedSkins;
if (!Array.isArray(arr)) {
arr = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
storage.unlockedSkins = arr;
}
return arr;
}
function unlockSkin(idx) {
var arr = getUnlockedSkins();
arr[idx] = 1;
storage.unlockedSkins = arr;
}
function isSkinUnlocked(idx) {
var arr = getUnlockedSkins();
return arr[idx] === 1;
}
// Seçili skin
function getSelectedSkin() {
var idx = storage.selectedSkin;
if (typeof idx !== "number" || idx < 0 || idx >= SKINS.length) idx = 0;
return idx;
}
function setSelectedSkin(idx) {
storage.selectedSkin = idx;
}
// Mağaza UI elemanları
var shopBg, shopTitle, shopCloseBtn, shopCoinTxt;
var skinBtns = [];
// Mağaza menüsünü göster
function showShopMenu() {
// Menüdeki diğer butonları gizle
startBtn.visible = false;
shopBtn.visible = false;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = false;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = false;
if (typeof gameTitle !== "undefined") gameTitle.visible = false;
// Arka plan
// Shop arka planı kaldırıldı (yeşil deco2 yok)
if (shopBg) shopBg.visible = false;
// Başlık
if (!shopTitle) {
shopTitle = new Text2("Character Skin Shop", {
size: 120,
fill: "#fff",
font: "Arial Black"
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = GAME_W / 2;
shopTitle.y = GAME_H / 2 - 540; // Moved a bit higher
game.addChild(shopTitle);
}
shopTitle.visible = true;
// Close button
if (!shopCloseBtn) {
shopCloseBtn = new Text2("Close", {
size: 80,
fill: "#fff",
font: "Arial Black"
});
shopCloseBtn.anchor.set(0.5, 0.5);
shopCloseBtn.x = GAME_W / 2;
shopCloseBtn.y = GAME_H / 2 + 820; // Moved a bit lower
shopCloseBtn.down = function () {
hideShopMenu();
showStartMenu();
};
game.addChild(shopCloseBtn);
}
shopCloseBtn.visible = true;
// Coin indicator
if (!shopCoinTxt) {
shopCoinTxt = new Text2("Beat: 0", {
size: 80,
fill: 0xFFE066
});
shopCoinTxt.anchor.set(0.5, 0.5);
shopCoinTxt.x = GAME_W / 2;
shopCoinTxt.y = GAME_H / 2 - 440; // More space from title
game.addChild(shopCoinTxt);
}
shopCoinTxt.visible = true;
shopCoinTxt.setText("Beat: " + getPlayerCoins());
// Hide homeBtnAbove (hearts' home button) in shop
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = false;
// Skin butonları
for (var i = 0; i < skinBtns.length; i++) {
if (skinBtns[i]) skinBtns[i].visible = false;
}
var unlocked = getUnlockedSkins();
var selected = getSelectedSkin();
// Yeni düzen: 2 satır 5 sütun, daha büyük arka plan ve üstte başlık/coin
var btnRows = 2;
var btnCols = 5;
var btnDX = 340; // Yatay aralığı biraz açtık
var btnDY = 300; // Dikey aralığı artırdık
var btnX0 = GAME_W / 2 - (btnCols - 1) * btnDX / 2;
var btnY0 = GAME_H / 2 - 60; // Butonları biraz daha aşağı aldık
var col = 0,
row = 0;
for (var i = 0; i < SKINS.length; i++) {
var btn;
if (!skinBtns[i]) {
btn = new Container();
// Skin görseli (her karakter için farklı asset)
var skinAsset = LK.getAsset(SKINS[i].asset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 0,
y: 0
});
btn.addChild(skinAsset);
// Skin adı
var nameTxt = new Text2(SKINS[i].name, {
size: 60,
fill: "#fff"
});
nameTxt.anchor.set(0.5, 0);
nameTxt.x = 0;
nameTxt.y = 90; // Görselin altına biraz daha mesafe
btn.addChild(nameTxt);
// Fiyat veya kilit
var priceTxt = new Text2("", {
size: 50,
fill: 0xFFE066
});
priceTxt.anchor.set(0.5, 0);
priceTxt.x = 0;
priceTxt.y = 170; // Name ile price arası daha fazla (artırıldı)
btn.addChild(priceTxt);
btn.priceTxt = priceTxt;
btn.skinIdx = i;
btn.down = function (x, y, obj) {
var idx = this.skinIdx;
if (isSkinUnlocked(idx)) {
LK.getSound('select').play();
setSelectedSkin(idx);
updateShopMenu();
} else {
var coins = getPlayerCoins();
var price = SKINS[idx].price;
if (coins >= price) {
LK.getSound('select').play();
setPlayerCoins(coins - price);
unlockSkin(idx);
setSelectedSkin(idx);
updateShopMenu();
}
}
};
skinBtns[i] = btn;
game.addChild(btn);
} else {
btn = skinBtns[i];
}
btn.visible = true;
btn.x = btnX0 + col * btnDX;
btn.y = btnY0 + row * btnDY;
// Price/lock/active
if (unlocked[i]) {
if (selected === i) {
btn.priceTxt.setText("Selected");
btn.priceTxt.fill = "#00e676";
} else {
btn.priceTxt.setText("Unlocked");
btn.priceTxt.fill = "#ffe066";
}
} else {
btn.priceTxt.setText("Locked (" + SKINS[i].price + " beat)");
btn.priceTxt.fill = "#ff5252";
}
col++;
if (col >= btnCols) {
col = 0;
row++;
}
}
}
// Mağaza menüsünü güncelle (skin seçimi/kilit açma sonrası)
function updateShopMenu() {
if (shopCoinTxt) shopCoinTxt.setText("Beat: " + getPlayerCoins());
var unlocked = getUnlockedSkins();
var selected = getSelectedSkin();
for (var i = 0; i < SKINS.length; i++) {
var btn = skinBtns[i];
if (!btn) continue;
// Always ensure priceTxt is at correct y (in case of dynamic changes)
if (btn.priceTxt) btn.priceTxt.y = 170;
if (unlocked[i]) {
if (selected === i) {
btn.priceTxt.setText("Selected");
btn.priceTxt.fill = "#00e676";
} else {
btn.priceTxt.setText("Unlocked");
btn.priceTxt.fill = "#ffe066";
}
} else {
btn.priceTxt.setText("Locked (" + SKINS[i].price + " beat)");
btn.priceTxt.fill = "#ff5252";
}
}
}
// Mağaza menüsünü gizle
function hideShopMenu() {
if (shopBg) shopBg.visible = false;
if (shopTitle) shopTitle.visible = false;
if (shopCloseBtn) shopCloseBtn.visible = false;
if (shopCoinTxt) shopCoinTxt.visible = false;
for (var i = 0; i < skinBtns.length; i++) {
if (skinBtns[i]) skinBtns[i].visible = false;
}
}
// Oyun sonunda veya beat toplandığında coin ekle
function addCoins(n) {
var coins = getPlayerCoins();
setPlayerCoins(coins + n);
if (shopCoinTxt && shopCoinTxt.visible) shopCoinTxt.setText("Beat: " + getPlayerCoins());
}
// --- Ship skinini seçili skine göre oluştur ---
var old_Ship = Ship;
Ship = Container.expand(function () {
var self = Container.call(this);
var idx = getSelectedSkin();
if (typeof idx !== "number" || idx < 0 || idx >= SKINS.length) idx = 0;
var assetId = SKINS[idx].asset;
var color = SKINS[idx].color;
var shipGfx = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Renk uygula (tint)
shipGfx.tint = color;
self.energy = 3;
self.invincible = false;
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(shipGfx, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(shipGfx, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
return self;
});
// Decorative blocks (unique assets) around the menu
// Removed decoBlock1 and decoBlock2 to ensure no shapes are above the game title
var decoBlock3 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 - 500,
y: GAME_H / 2 + 350
});
game.addChild(decoBlock3);
var decoBlock4 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W / 2 + 500,
y: GAME_H / 2 + 350
});
game.addChild(decoBlock4);
// Add more unique decorative blocks, using all available assets, spread out, avoid text/buttons, fill empty areas
// Top left (avoid 0-100,0-100)
var decoBlock5 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 220,
y: 220
});
game.addChild(decoBlock5);
// Top right
var decoBlock6 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 220,
y: 220
});
game.addChild(decoBlock6);
// Bottom left
var decoBlock7 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: 220,
y: GAME_H - 220
});
game.addChild(decoBlock7);
// Bottom right
var decoBlock8 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 220,
y: GAME_H - 220
});
game.addChild(decoBlock8);
// Left center
var decoBlock9 = LK.getAsset('deco1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 180,
y: GAME_H / 2
});
game.addChild(decoBlock9);
// Right center
var decoBlock10 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 180,
y: GAME_H / 2
});
game.addChild(decoBlock10);
// (Removed decoBlock11 to ensure no shape is above the game title)
// Bottom center (below menu)
var decoBlock12 = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W / 2,
y: GAME_H - 120
});
game.addChild(decoBlock12);
// Left mid-top
var decoBlock13 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: 320,
y: 600
});
game.addChild(decoBlock13);
// Right mid-top
var decoBlock14 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 320,
y: 600
});
game.addChild(decoBlock14);
// Left mid-bottom
var decoBlock15 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 320,
y: GAME_H - 600
});
game.addChild(decoBlock15);
// Right mid-bottom
var decoBlock16 = LK.getAsset('deco1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
x: GAME_W - 320,
y: GAME_H - 600
});
game.addChild(decoBlock16);
// Spread a few more in the corners, but not overlapping text/buttons
var decoBlock17 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: 500,
y: 400
});
game.addChild(decoBlock17);
var decoBlock18 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 500,
y: 400
});
game.addChild(decoBlock18);
var decoBlock19 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: 500,
y: GAME_H - 400
});
game.addChild(decoBlock19);
var decoBlock20 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 500,
y: GAME_H - 400
});
game.addChild(decoBlock20);
// Oyunu başlatırken menüyü göster
showStartMenu();
; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Ritim Kaynağı (Collectible)
var Beat = Container.expand(function () {
var self = Container.call(this);
var beatGfx = self.attachAsset('beat', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Boss Kristali
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGfx = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 5;
self.pulse = function () {
tween(bossGfx, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(bossGfx, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
// Düşman (hareketli engel)
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dir = 1; // 1: sağ, -1: sol
self.speed = 6;
self.range = 300; // Hareket aralığı
self.baseX = 0;
self.init = function (x) {
self.baseX = x;
};
self.update = function () {
self.x += self.dir * self.speed;
if (self.x > self.baseX + self.range) self.dir = -1;
if (self.x < self.baseX - self.range) self.dir = 1;
};
return self;
});
// Engeller
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Ritim Efekti (Pulse)
var Pulse = Container.expand(function () {
var self = Container.call(this);
var pulseGfx = self.attachAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.show = function (x, y) {
self.x = x;
self.y = y;
pulseGfx.scaleX = 0.5;
pulseGfx.scaleY = 0.5;
pulseGfx.alpha = 0.3;
tween(pulseGfx, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
}, {
duration: 350
});
};
return self;
});
// Uzay Gemisi (Player)
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGfx = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.energy = 3; // Can
self.invincible = false; // Hasar sonrası kısa süreli dokunulmazlık
// Enerji kaybı animasyonu
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(shipGfx, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(shipGfx, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
return self;
});
// Teleport hareket eden düşman
var TeleportEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy3', {
anchorX: 0.5,
anchorY: 0.5
});
self.cooldown = 0;
self.teleportInterval = 120; // 2 saniye (60fps)
self.minDist = 200;
self.maxDist = 400;
self.init = function () {};
self.update = function () {
if (typeof self.cooldown !== "number") self.cooldown = 0;
self.cooldown--;
if (self.cooldown <= 0 && typeof ship !== "undefined" && ship) {
// Teleport: player'a yakın bir noktaya ışınlan
var angle = Math.random() * Math.PI * 2;
var dist = self.minDist + Math.random() * (self.maxDist - self.minDist);
var tx = ship.x + Math.cos(angle) * dist;
var ty = ship.y + Math.sin(angle) * dist;
// Sınırları aşmasın
if (tx < 120) tx = 120;
if (tx > GAME_W - 120) tx = GAME_W - 120;
if (ty < 300) ty = 300;
if (ty > GAME_H - 200) ty = GAME_H - 200;
self.x = tx;
self.y = ty;
self.cooldown = self.teleportInterval + Math.floor(Math.random() * 60);
}
};
return self;
});
// Zigzag hareket eden düşman
var ZigzagEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.dir = 1;
self.speed = 5;
self.range = 250;
self.baseX = 0;
self.baseY = 0;
self.angle = 0;
self.init = function (x, y) {
self.baseX = x;
self.baseY = y;
self.angle = 0;
};
self.update = function () {
self.angle += 0.025;
self.x = self.baseX + Math.sin(self.angle) * self.range;
self.y = self.baseY + Math.cos(self.angle) * 60;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0033
});
/****
* Game Code
****/
// 5 yeni background asset (örnek id'ler, gerçek id'ler asset yöneticisinden alınmalı)
// Yeni home tuşu asset'i (sadece home butonu için kullanılacak, dekoratif değil)
// Unique assets for each shop character (no enemy/deco/pulse/beat/boss assets)
// Yeni: Teleport düşman
// Yeni: Zigzag düşman
// Müzik (looping, ritmik)
// Sesler
// Ritim efekti (görsel feedback)
// Boss kristali (finalde)
// Düşman (hareketli engel)
// Engeller
// Ritim kaynağı (collectible)
// Uzay gemisi (player)
// Oyun alanı boyutları
var GAME_W = 2048;
var GAME_H = 2732;
// 5 farklı background asset id'si
var BG_ASSETS = ['bg1', 'bg2', 'bg3', 'bg4', 'bg5'];
var bgImage = null;
// Arka planı güncelleyen fonksiyon
function updateBackgroundForLevel(lvlNum) {
// 1-5: bg1, 6-10: bg2, 11-15: bg3, 16-20: bg4, 21+: bg5
var idx = Math.floor((lvlNum - 1) / 5);
if (idx < 0) idx = 0;
if (idx > 4) idx = 4;
var assetId = BG_ASSETS[idx];
// Arka plan zaten varsa kaldır
if (bgImage && typeof bgImage.destroy === "function") {
bgImage.destroy();
bgImage = null;
}
// Yeni arka planı ekle
bgImage = LK.getAsset(assetId, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 1,
scaleY: 1
});
// Her zaman en arkada olmalı
if (game.children && game.children.length > 0) {
game.addChildAt(bgImage, 0);
} else {
game.addChild(bgImage);
}
}
// Ritim parametreleri
var BPM = 100; // Dakikadaki vuruş
var BEAT_INTERVAL = Math.round(60 * 1000 / BPM); // ms cinsinden
var lastBeatTick = 0;
// Oyun durumu
var score = 0;
// Bölüm tanımları (her biri farklı engel, düşman ve beat dizilimi içerir)
var LEVELS = [
// 1-19: Normal bölümler, 20: Boss
// Her bölüm: {beats, obstacles, enemies}
// beats: [{x, y}, ...], obstacles: [{x, y}], enemies: [{x, y, range, type}]
{
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}],
obstacles: [{
x: 1024,
y: 1400
}],
enemies: [{
x: 1024,
y: 1200,
range: 200
},
// klasik
{
x: 700,
y: 1000,
type: "zigzag"
} // zigzag
]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}],
obstacles: [{
x: 700,
y: 1500
}, {
x: 1350,
y: 1500
}],
enemies: [{
x: 1024,
y: 1300,
range: 300
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1100
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1100
}, {
x: 1024,
y: 1000
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
enemies: [{
x: 700,
y: 1200,
range: 200
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}],
enemies: [{
x: 1024,
y: 1300,
range: 350
}, {
x: 800,
y: 1100,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
enemies: [{
x: 700,
y: 1200,
range: 250
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}],
enemies: [{
x: 700,
y: 1200,
range: 300
}, {
x: 1350,
y: 1200,
type: "zigzag"
}, {
x: 1024,
y: 1000,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}],
enemies: [{
x: 1024,
y: 1300,
range: 400
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 350
}, {
x: 1350,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 450
}, {
x: 1240,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 400
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 500
}, {
x: 800,
y: 1200,
type: "teleport"
}, {
x: 1350,
y: 1200,
type: "zigzag"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 450
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 550
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 500
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 600
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}, {
x: 600,
y: 1700
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 550
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}, {
x: 1024,
y: 1800
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 650
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}]
}, {
beats: [{
x: 400,
y: 900
}, {
x: 800,
y: 1000
}, {
x: 1200,
y: 900
}, {
x: 1600,
y: 1000
}, {
x: 1024,
y: 1100
}, {
x: 600,
y: 1200
}, {
x: 1440,
y: 1200
}, {
x: 1024,
y: 1300
}, {
x: 800,
y: 1400
}, {
x: 1240,
y: 1400
}, {
x: 1024,
y: 1600
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 600,
y: 1700
}, {
x: 1440,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 700,
y: 1200,
range: 600
}, {
x: 1350,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}, {
x: 900,
y: 1500,
type: "teleport"
}]
}, {
beats: [{
x: 350,
y: 950
}, {
x: 700,
y: 1100
}, {
x: 1024,
y: 950
}, {
x: 1350,
y: 1100
}, {
x: 1700,
y: 950
}, {
x: 1024,
y: 1200
}, {
x: 800,
y: 1300
}, {
x: 1240,
y: 1300
}, {
x: 1024,
y: 1500
}, {
x: 600,
y: 1600
}, {
x: 1440,
y: 1600
}, {
x: 1024,
y: 1800
}, {
x: 800,
y: 1900
}],
obstacles: [{
x: 1024,
y: 1400
}, {
x: 700,
y: 1700
}, {
x: 1350,
y: 1700
}, {
x: 1024,
y: 2000
}, {
x: 800,
y: 2100
}, {
x: 1240,
y: 2100
}],
enemies: [{
x: 1024,
y: 1300,
range: 700
}, {
x: 1240,
y: 1200,
type: "zigzag"
}, {
x: 800,
y: 1200,
type: "teleport"
}, {
x: 1024,
y: 1000,
type: "zigzag"
}]
},
// 20. bölüm: Boss
{
boss: true
}];
var maxScore = 0; // Her bölümde dinamik olarak ayarlanacak
var energy = 3;
var level = 1;
var onBoss = false;
var bossDefeated = false;
// Ana objeler
var ship;
var beats = [];
var obstacles = [];
var enemies = [];
var boss;
var pulseEffect;
// GUI
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var energyTxt = new Text2('♥♥♥', {
size: 90,
fill: 0xFF5252
});
energyTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(energyTxt);
// Home button directly below the hearts (energyTxt)
var homeBtnAbove = LK.getAsset('homeBtn', {
anchorX: 1,
anchorY: 0,
scaleX: 0.7,
scaleY: 0.7,
x: 0,
y: 0
});
homeBtnAbove.x = energyTxt.x;
homeBtnAbove.y = energyTxt.y + energyTxt.height + 24;
homeBtnAbove.visible = true;
homeBtnAbove.down = function () {
// Return to menu
showStartMenu();
};
LK.gui.topRight.addChild(homeBtnAbove);
// Level göstergesi (sol alt)
var levelTxt = new Text2('Level 1', {
size: 90,
fill: "#fff"
});
levelTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(levelTxt);
// Beat indicator
var beatTxt = new Text2('♪', {
size: 100,
fill: 0xFFE066
});
beatTxt.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(beatTxt);
// Home button (in-game, returns to start menu) - now at bottom right, using a new asset (no text)
var homeBtn = LK.getAsset('homeBtn', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.9,
x: 0,
y: 0
});
homeBtn.visible = false;
// Place at bottom right of the GUI (safe area, not overlapping)
homeBtn.x = LK.gui.width - 180;
homeBtn.y = LK.gui.height - 180;
homeBtn.down = function () {
// Hide in-game UI, show start menu
showStartMenu();
// --- Add Richness to Main Menu: Extra Info, Effects, and Decorations ---
// 1. Short description under the game title
var subtitleTxt = new Text2("Move to the rhythm, collect beats!", {
size: 70,
fill: 0xFFE066,
font: "Arial Black"
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = GAME_W / 2;
subtitleTxt.y = GAME_H / 2 - 200;
game.addChild(subtitleTxt);
// 2. Animated effect in main menu (e.g. spinning beat)
// Only visible in menu
var menuAnimBeat = LK.getAsset('beat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 + 420,
y: GAME_H / 2 - 320
});
game.addChild(menuAnimBeat);
menuAnimBeat.visible = true;
menuAnimBeat.menuAnimTick = 0;
menuAnimBeat.update = function () {
this.menuAnimTick++;
this.rotation += 0.04;
this.scaleX = 1.1 + Math.sin(this.menuAnimTick * 0.07) * 0.12;
this.scaleY = 1.1 + Math.cos(this.menuAnimTick * 0.07) * 0.12;
};
// 3. Main menu: total level and boss info
var infoTxt = new Text2("20 levels total (19 normal + 1 boss)", {
size: 60,
fill: "#fff"
});
infoTxt.anchor.set(0.5, 0.5);
infoTxt.x = GAME_W / 2;
infoTxt.y = GAME_H / 2 + 320;
game.addChild(infoTxt);
// 4. Main menu: best score (most beats collected)
var bestScoreTxt = new Text2("", {
size: 60,
fill: 0x00E676
});
bestScoreTxt.anchor.set(0.5, 0.5);
bestScoreTxt.x = GAME_W / 2;
bestScoreTxt.y = GAME_H / 2 + 400;
game.addChild(bestScoreTxt);
function updateBestScoreTxt() {
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
bestScoreTxt.setText("Best score: " + best + " beat");
}
updateBestScoreTxt();
// 5. Main menu: decorative "sword" effect (vertical, next to title)
var swordDeco = LK.getAsset('sword', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2 - 420,
y: GAME_H / 2 - 320,
rotation: Math.PI / 2
});
game.addChild(swordDeco);
// 6. Main menu: "pulse" effect (animated, behind title)
var menuPulse = LK.getAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.18,
x: GAME_W / 2,
y: GAME_H / 2 - 320
});
game.addChild(menuPulse);
menuPulse.menuPulseTick = 0;
menuPulse.update = function () {
this.menuPulseTick++;
this.scaleX = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.scaleY = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.alpha = 0.12 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.12;
};
// (Removed sword_btn decorative assets from menu to ensure no decor on buttons)
// 9. Show/hide extra menu elements only in menu
var menuDecoratives = [subtitleTxt, menuAnimBeat, infoTxt, bestScoreTxt, swordDeco, menuPulse];
// Extend original showStartMenu function
var oldShowStartMenu = showStartMenu;
showStartMenu = function showStartMenu() {
if (typeof oldShowStartMenu === "function") oldShowStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = true;
}
updateBestScoreTxt();
};
// Extend original hideStartMenu function
var oldHideStartMenu = hideStartMenu;
hideStartMenu = function hideStartMenu() {
if (typeof oldHideStartMenu === "function") oldHideStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = false;
}
};
// Update animated menu objects
var oldGameUpdate = game.update;
game.update = function () {
// If in menu, animate
if (startBtn.visible) {
if (menuAnimBeat && typeof menuAnimBeat.update === "function") menuAnimBeat.update();
if (menuPulse && typeof menuPulse.update === "function") menuPulse.update();
}
if (typeof oldGameUpdate === "function") oldGameUpdate();
};
// Update best score at game end
var oldAddCoins = addCoins;
addCoins = function addCoins(n) {
if (typeof oldAddCoins === "function") oldAddCoins(n);
// Update best score
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
if (score > best) {
storage.bestScore = score;
updateBestScoreTxt();
}
};
// --- Ana Menüye Zenginlik Kat: Ekstra Bilgi, Efekt ve Dekorasyonlar ---
// 1. Oyun başlığı altına kısa açıklama
var subtitleTxt = new Text2("Ritme göre hareket et, altınları topla!", {
size: 70,
fill: 0xFFE066,
font: "Arial Black"
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = GAME_W / 2;
subtitleTxt.y = GAME_H / 2 - 200;
game.addChild(subtitleTxt);
// 2. Ana menüde animasyonlu bir efekt (ör: dönen bir beat)
// Sadece menüde görünsün
var menuAnimBeat = LK.getAsset('beat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 + 420,
y: GAME_H / 2 - 320
});
game.addChild(menuAnimBeat);
menuAnimBeat.visible = true;
menuAnimBeat.menuAnimTick = 0;
menuAnimBeat.update = function () {
this.menuAnimTick++;
this.rotation += 0.04;
this.scaleX = 1.1 + Math.sin(this.menuAnimTick * 0.07) * 0.12;
this.scaleY = 1.1 + Math.cos(this.menuAnimTick * 0.07) * 0.12;
};
// 3. Ana menüde toplam bölüm ve boss bölümü bilgisi
var infoTxt = new Text2("Toplam 20 bölüm (19 normal + 1 boss)", {
size: 60,
fill: "#fff"
});
infoTxt.anchor.set(0.5, 0.5);
infoTxt.x = GAME_W / 2;
infoTxt.y = GAME_H / 2 + 320;
game.addChild(infoTxt);
// 4. Ana menüde en iyi skor (en çok toplanan beat)
var bestScoreTxt = new Text2("", {
size: 60,
fill: 0x00E676
});
bestScoreTxt.anchor.set(0.5, 0.5);
bestScoreTxt.x = GAME_W / 2;
bestScoreTxt.y = GAME_H / 2 + 400;
game.addChild(bestScoreTxt);
function updateBestScoreTxt() {
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
bestScoreTxt.setText("En iyi skor: " + best + " beat");
}
updateBestScoreTxt();
// 5. Ana menüde dekoratif bir "sword" efekti (dikey, başlık yanında)
var swordDeco = LK.getAsset('sword', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2 - 420,
y: GAME_H / 2 - 320,
rotation: Math.PI / 2
});
game.addChild(swordDeco);
// 6. Ana menüde bir "pulse" efekti (animasyonlu, başlık arkasında)
var menuPulse = LK.getAsset('pulse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.18,
x: GAME_W / 2,
y: GAME_H / 2 - 320
});
game.addChild(menuPulse);
menuPulse.menuPulseTick = 0;
menuPulse.update = function () {
this.menuPulseTick++;
this.scaleX = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.scaleY = 0.7 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.25;
this.alpha = 0.12 + Math.abs(Math.sin(this.menuPulseTick * 0.03)) * 0.12;
};
// (Removed sword_btn decorative assets from menu to ensure no decor on buttons)
// 9. Ana menüdeki ekstra elemanları sadece menüde göster/gizle
var menuDecoratives = [subtitleTxt, menuAnimBeat, infoTxt, bestScoreTxt, swordDeco, menuPulse];
// Orijinal showStartMenu fonksiyonunu genişlet
var oldShowStartMenu = showStartMenu;
showStartMenu = function showStartMenu() {
if (typeof oldShowStartMenu === "function") oldShowStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = true;
}
updateBestScoreTxt();
};
// Orijinal hideStartMenu fonksiyonunu genişlet
var oldHideStartMenu = hideStartMenu;
hideStartMenu = function hideStartMenu() {
if (typeof oldHideStartMenu === "function") oldHideStartMenu();
for (var i = 0; i < menuDecoratives.length; i++) {
if (menuDecoratives[i]) menuDecoratives[i].visible = false;
}
};
// Ana menüdeki animasyonlu objeleri update et
var oldGameUpdate = game.update;
game.update = function () {
// Menüdeysek animasyonları döndür
if (startBtn.visible) {
if (menuAnimBeat && typeof menuAnimBeat.update === "function") menuAnimBeat.update();
if (menuPulse && typeof menuPulse.update === "function") menuPulse.update();
}
if (typeof oldGameUpdate === "function") oldGameUpdate();
};
// Oyun sonunda en iyi skoru güncelle
var oldAddCoins = addCoins;
addCoins = function addCoins(n) {
if (typeof oldAddCoins === "function") oldAddCoins(n);
// En iyi skor güncelle
var best = storage.bestScore;
if (typeof best !== "number" || isNaN(best)) best = 0;
if (score > best) {
storage.bestScore = score;
updateBestScoreTxt();
}
};
homeBtn.visible = false;
};
// Add to bottom right GUI overlay
LK.gui.bottomRight.addChild(homeBtn);
pulseEffect = new Pulse();
game.addChild(pulseEffect);
// Game starter
function startLevel() {
// Clear
for (var i = 0; i < beats.length; i++) beats[i].destroy();
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
beats = [];
obstacles = [];
enemies = [];
if (boss) {
boss.destroy();
boss = null;
}
onBoss = false;
bossDefeated = false;
score = 0;
energy = 3;
// Level data
levelTxt.setText("Level " + level);
// Arka planı güncelle
updateBackgroundForLevel(level);
// Boss ise boss fonksiyonuna geç
var lvl = LEVELS[(level - 1) % LEVELS.length];
if (lvl && lvl.boss) {
startBoss();
return;
}
// Ship
if (ship) ship.destroy();
ship = new Ship();
ship.x = GAME_W / 2;
ship.y = GAME_H - 400;
game.addChild(ship);
// Beats
maxScore = lvl.beats.length;
scoreTxt.setText(score + "/" + maxScore);
energyTxt.setText("♥".repeat(energy));
for (var i = 0; i < lvl.beats.length; i++) {
var b = new Beat();
b.x = lvl.beats[i].x;
b.y = lvl.beats[i].y;
beats.push(b);
game.addChild(b);
}
// Obstacles
for (var i = 0; i < lvl.obstacles.length; i++) {
var obs = new Obstacle();
obs.x = lvl.obstacles[i].x;
obs.y = lvl.obstacles[i].y;
obstacles.push(obs);
game.addChild(obs);
}
// Enemies
for (var i = 0; i < lvl.enemies.length; i++) {
var enemyData = lvl.enemies[i];
var e;
// Add different enemy types: if type field exists, use it, otherwise classic Enemy
if (enemyData.type === "zigzag") {
e = new ZigzagEnemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init(enemyData.x, enemyData.y);
} else if (enemyData.type === "teleport") {
e = new TeleportEnemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init();
} else {
e = new Enemy();
e.x = enemyData.x;
e.y = enemyData.y;
e.init(e.x);
if (typeof enemyData.range === "number") e.range = enemyData.range;
}
enemies.push(e);
game.addChild(e);
}
}
// Start boss level
function startBoss() {
onBoss = true;
// Arka planı güncelle (boss bölümü için de)
updateBackgroundForLevel(level);
for (var i = 0; i < beats.length; i++) beats[i].destroy();
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
beats = [];
obstacles = [];
enemies = [];
score = 0;
maxScore = 5; // Boss bölümünde 5 altın
energy = 5; // Boss bölümünde 5 can
scoreTxt.setText("0/5");
energyTxt.setText("♥♥♥♥♥");
// Boss hareketli: X ekseninde hızlı zigzag + Y ekseninde yavaşça yukarı-aşağı
boss = new Boss();
boss.x = GAME_W / 2;
boss.y = 700;
boss.moveTick = 0;
boss.moveDir = 1;
boss.moveDirY = 1;
boss.update = function () {
// X ekseninde hızlı zigzag
boss.moveTick++;
boss.x += boss.moveDir * 18;
if (boss.x > GAME_W - 220) boss.moveDir = -1;
if (boss.x < 220) boss.moveDir = 1;
// Y ekseninde yavaşça yukarı-aşağı
if (boss.moveTick % 30 === 0) {
boss.y += boss.moveDirY * 40;
if (boss.y > 1100) boss.moveDirY = -1;
if (boss.y < 500) boss.moveDirY = 1;
}
};
// 5 altın (beat) boss etrafında, toplarsak kazanılır
var bossBeatPos = [{
x: boss.x - 180,
y: boss.y + 180
}, {
x: boss.x + 180,
y: boss.y + 180
}, {
x: boss.x - 180,
y: boss.y - 180
}, {
x: boss.x + 180,
y: boss.y - 180
}, {
x: boss.x,
y: boss.y
}];
for (var i = 0; i < 5; i++) {
var b = new Beat();
// Beat'ler boss ile birlikte hareket etsin
b.offsetX = bossBeatPos[i].x - boss.x;
b.offsetY = bossBeatPos[i].y - boss.y;
b.update = function () {
// Her frame boss ile birlikte hareket et
if (boss) {
this.x = boss.x + this.offsetX;
this.y = boss.y + this.offsetY;
}
};
beats.push(b);
game.addChild(b);
}
game.addChild(boss);
LK.getSound('boss').play();
}
// Ritim tick'i
function onBeat() {
// Ritim efekti
if (typeof ship !== "undefined" && ship) {
pulseEffect.show(ship.x, ship.y);
}
// Ritim göstergesi animasyonu
tween(beatTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(beatTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Adım sesi
LK.getSound('step').play();
}
// Ritimle hareket için bekleyen dokunuş
var moveQueued = false;
var queuedMove = {
x: 0,
y: 0
};
// Hareket yönleri
function getMoveDir(x, y) {
if (typeof ship === "undefined" || !ship) {
return {
dx: 0,
dy: 0
};
}
var dx = x - ship.x;
var dy = y - ship.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 80) return {
dx: 0,
dy: 0
};
var angle = Math.atan2(dy, dx);
var step = 220;
return {
dx: Math.round(Math.cos(angle) * step),
dy: Math.round(Math.sin(angle) * step)
};
}
// Hareketi uygula (ritimle)
function doMove() {
if (!moveQueued) return;
if (typeof ship === "undefined" || !ship) {
moveQueued = false;
return;
}
var dx = queuedMove.dx;
var dy = queuedMove.dy;
var newX = ship.x + dx;
var newY = ship.y + dy;
// Sınır kontrolü
if (newX < 120) newX = 120;
if (newX > GAME_W - 120) newX = GAME_W - 120;
if (newY < 300) newY = 300;
if (newY > GAME_H - 200) newY = GAME_H - 200;
// Engel çarpışma kontrolü
var blocked = false;
for (var i = 0; i < obstacles.length; i++) {
if (rectsIntersect(newX, newY, ship, obstacles[i].x, obstacles[i].y, obstacles[i])) {
blocked = true;
break;
}
}
if (!blocked) {
tween(ship, {
x: newX,
y: newY
}, {
duration: 120,
easing: tween.cubicOut
});
}
moveQueued = false;
}
// Dikdörtgen çarpışma (merkezden)
function rectsIntersect(x1, y1, obj1, x2, y2, obj2) {
var w1 = obj1.width || 140,
h1 = obj1.height || 140;
var w2 = obj2.width || 160,
h2 = obj2.height || 60;
return Math.abs(x1 - x2) < (w1 + w2) / 2 - 10 && Math.abs(y1 - y2) < (h1 + h2) / 2 - 10;
}
// Dokunma ile hareket yönü seç
game.down = function (x, y, obj) {
if (onBoss && bossDefeated) return;
var dir = getMoveDir(x, y);
queuedMove.dx = dir.dx;
queuedMove.dy = dir.dy;
moveQueued = true;
};
// Hareketli engeller ve boss için update
game.update = function () {
// Ritim tick'i
if (LK.ticks - lastBeatTick >= Math.round(BEAT_INTERVAL / 16.7)) {
lastBeatTick = LK.ticks;
onBeat();
doMove();
}
// Düşman hareketi
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
// Boss ve boss beatleri hareket ettir
if (onBoss && boss && typeof boss.update === "function") {
boss.update();
for (var i = 0; i < beats.length; i++) {
if (typeof beats[i].update === "function") beats[i].update();
}
}
// Düşman çarpışma
for (var i = 0; i < enemies.length; i++) {
if (ship.intersects(enemies[i]) && !ship.invincible) {
energy--;
energyTxt.setText("♥".repeat(energy));
ship.flash();
LK.getSound('hit').play();
if (energy <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
// Ritim kaynağı toplama
for (var i = beats.length - 1; i >= 0; i--) {
if (ship.intersects(beats[i])) {
LK.getSound('collect').play();
beats[i].destroy();
beats.splice(i, 1);
score++;
scoreTxt.setText(score + "/" + maxScore);
// Her beat toplandığında coin ekle
addCoins(1);
if (score >= maxScore) {
level++;
if (level > LEVELS.length) {
LK.showYouWin();
return;
}
LK.setTimeout(function () {
startLevel();
}, 800);
return;
}
}
}
// Boss bölümü
if (onBoss && boss && !bossDefeated) {
// Boss'a çarpınca enerji kaybı
if (ship.intersects(boss) && !ship.invincible) {
energy--;
energyTxt.setText("♥".repeat(energy));
ship.flash();
LK.getSound('hit').play();
if (energy <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Boss etrafındaki 5 altını (beat) toplarsak kazan
for (var i = beats.length - 1; i >= 0; i--) {
if (ship.intersects(beats[i])) {
LK.getSound('collect').play();
beats[i].destroy();
beats.splice(i, 1);
score++;
scoreTxt.setText(score + "/5");
addCoins(1);
if (score >= 5) {
bossDefeated = true;
LK.effects.flashScreen(0x00e676, 1200);
LK.showYouWin();
return;
}
}
}
}
};
// Müzik başlat
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
// Başla ve Mağaza tuşları
// Game title above menu buttons
var gameTitle = new Text2("Rhythm Space", {
size: 160,
fill: "#fff",
font: "Arial Black"
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = GAME_W / 2;
gameTitle.y = GAME_H / 2 - 320;
game.addChild(gameTitle);
// Start button background asset (unique, not boss/enemy)
var startBtnBg = LK.getAsset('startBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
x: GAME_W / 2,
y: GAME_H / 2 - 100
});
game.addChild(startBtnBg);
var startBtn = new Text2("Start", {
size: 120,
fill: "#fff",
font: "Arial Black"
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = GAME_W / 2;
startBtn.y = GAME_H / 2 - 100;
game.addChild(startBtn);
// Shop button background asset (unique, not boss/enemy)
var shopBtnBg = LK.getAsset('shopBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2,
y: GAME_H / 2 + 100
});
game.addChild(shopBtnBg);
var shopBtn = new Text2("Shop", {
size: 100,
fill: 0xFFE066,
font: "Arial Black"
});
shopBtn.anchor.set(0.5, 0.5);
shopBtn.x = GAME_W / 2;
shopBtn.y = GAME_H / 2 + 100;
game.addChild(shopBtn);
// Oyun başlatıcı fonksiyonunu sarmala
function showStartMenu() {
startBtn.visible = true;
shopBtn.visible = true;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = true;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = true;
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = true;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = true;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = true;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = true;
scoreTxt.visible = false;
energyTxt.visible = false;
levelTxt.visible = false;
beatTxt.visible = false;
pulseEffect.visible = false;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = true;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = true;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = true;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = true;
// Oyun objelerini gizle
if (ship) ship.visible = false;
for (var i = 0; i < beats.length; i++) beats[i].visible = false;
for (var i = 0; i < obstacles.length; i++) obstacles[i].visible = false;
for (var i = 0; i < enemies.length; i++) enemies[i].visible = false;
if (boss) boss.visible = false;
if (typeof gameTitle !== "undefined") gameTitle.visible = true;
// Hide home button in menu
if (typeof homeBtn !== "undefined") homeBtn.visible = false;
// Hide homeBtnAbove (hearts' home button) in menu
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = false;
}
function hideStartMenu() {
startBtn.visible = false;
shopBtn.visible = false;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = false;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = false;
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = false;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = false;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = false;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = false;
scoreTxt.visible = true;
energyTxt.visible = true;
levelTxt.visible = true;
beatTxt.visible = true;
pulseEffect.visible = true;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = false;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = false;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = false;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = false;
if (typeof decoBlock9 !== "undefined") decoBlock9.visible = false;
if (typeof decoBlock10 !== "undefined") decoBlock10.visible = false;
if (typeof decoBlock12 !== "undefined") decoBlock12.visible = false;
if (typeof decoBlock13 !== "undefined") decoBlock13.visible = false;
if (typeof decoBlock14 !== "undefined") decoBlock14.visible = false;
if (typeof decoBlock15 !== "undefined") decoBlock15.visible = false;
if (typeof decoBlock16 !== "undefined") decoBlock16.visible = false;
if (typeof decoBlock17 !== "undefined") decoBlock17.visible = false;
if (typeof decoBlock18 !== "undefined") decoBlock18.visible = false;
if (typeof decoBlock19 !== "undefined") decoBlock19.visible = false;
if (typeof decoBlock20 !== "undefined") decoBlock20.visible = false;
// Oyun objelerini göster
if (ship) ship.visible = true;
for (var i = 0; i < beats.length; i++) beats[i].visible = true;
for (var i = 0; i < obstacles.length; i++) obstacles[i].visible = true;
for (var i = 0; i < enemies.length; i++) enemies[i].visible = true;
if (boss) boss.visible = true;
if (typeof gameTitle !== "undefined") gameTitle.visible = false;
// Show home button in-game
if (typeof homeBtn !== "undefined") homeBtn.visible = true;
// Show homeBtnAbove (hearts' home button) only in-game
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = true;
}
// Başla butonuna basınca oyunu başlat
startBtn.down = function (x, y, obj) {
LK.getSound('btn').play();
hideStartMenu();
startLevel();
};
// Mağaza butonu (karakter skin mağazası)
shopBtn.down = function (x, y, obj) {
LK.getSound('btn').play();
// Hide all decorative blocks when entering the shop
if (typeof decoBlock1 !== "undefined") decoBlock1.visible = false;
if (typeof decoBlock2 !== "undefined") decoBlock2.visible = false;
if (typeof decoBlock3 !== "undefined") decoBlock3.visible = false;
if (typeof decoBlock4 !== "undefined") decoBlock4.visible = false;
if (typeof decoBlock5 !== "undefined") decoBlock5.visible = false;
if (typeof decoBlock6 !== "undefined") decoBlock6.visible = false;
if (typeof decoBlock7 !== "undefined") decoBlock7.visible = false;
if (typeof decoBlock8 !== "undefined") decoBlock8.visible = false;
if (typeof decoBlock9 !== "undefined") decoBlock9.visible = false;
if (typeof decoBlock10 !== "undefined") decoBlock10.visible = false;
if (typeof decoBlock12 !== "undefined") decoBlock12.visible = false;
if (typeof decoBlock13 !== "undefined") decoBlock13.visible = false;
if (typeof decoBlock14 !== "undefined") decoBlock14.visible = false;
if (typeof decoBlock15 !== "undefined") decoBlock15.visible = false;
if (typeof decoBlock16 !== "undefined") decoBlock16.visible = false;
if (typeof decoBlock17 !== "undefined") decoBlock17.visible = false;
if (typeof decoBlock18 !== "undefined") decoBlock18.visible = false;
if (typeof decoBlock19 !== "undefined") decoBlock19.visible = false;
if (typeof decoBlock20 !== "undefined") decoBlock20.visible = false;
// Show shop UI for character skins
showShopMenu();
};
// --- Karakter Skin Mağazası ---
// Skin tanımları (10 farklı skin, 1. skin açık, diğerleri kilitli, hepsi farklı asset)
var SKINS = [{
id: "ship",
name: "Orion",
color: 0x3a9cff,
price: 0,
asset: "ship"
}, {
id: "ship2",
name: "Helios",
color: 0xffd700,
price: 20,
asset: "skin_ship2"
}, {
id: "ship3",
name: "Nebula",
color: 0x8e44ad,
price: 40,
asset: "skin_ship3"
}, {
id: "ship4",
name: "Cosmos",
color: 0x27ae60,
price: 60,
asset: "skin_ship4"
}, {
id: "ship5",
name: "Astera",
color: 0xe67e22,
price: 80,
asset: "skin_ship5"
}, {
id: "ship6",
name: "Vortex",
color: 0xff5252,
price: 100,
asset: "skin_ship6"
}, {
id: "ship7",
name: "Zenith",
color: 0x7cf7ff,
price: 120,
asset: "skin_ship7"
}, {
id: "ship8",
name: "Aurion",
color: 0xf1c40f,
price: 140,
asset: "skin_ship8"
}, {
id: "ship9",
name: "Quasar",
color: 0x00e676,
price: 160,
asset: "skin_ship9"
}, {
id: "ship10",
name: "Pulsar",
color: 0x00bcd4,
price: 200,
asset: "skin_ship10"
}];
// Kalıcı veri için storage plugin
// Oyuncunun sahip olduğu paralar (toplanan beat sayısı)
function getPlayerCoins() {
var coins = storage.coins;
if (typeof coins !== "number" || isNaN(coins)) coins = 0;
return coins;
}
function setPlayerCoins(val) {
storage.coins = val;
}
// Açık skinler (dizi: 1 = açık, 0 = kilitli)
function getUnlockedSkins() {
var arr = storage.unlockedSkins;
if (!Array.isArray(arr)) {
arr = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
storage.unlockedSkins = arr;
}
return arr;
}
function unlockSkin(idx) {
var arr = getUnlockedSkins();
arr[idx] = 1;
storage.unlockedSkins = arr;
}
function isSkinUnlocked(idx) {
var arr = getUnlockedSkins();
return arr[idx] === 1;
}
// Seçili skin
function getSelectedSkin() {
var idx = storage.selectedSkin;
if (typeof idx !== "number" || idx < 0 || idx >= SKINS.length) idx = 0;
return idx;
}
function setSelectedSkin(idx) {
storage.selectedSkin = idx;
}
// Mağaza UI elemanları
var shopBg, shopTitle, shopCloseBtn, shopCoinTxt;
var skinBtns = [];
// Mağaza menüsünü göster
function showShopMenu() {
// Menüdeki diğer butonları gizle
startBtn.visible = false;
shopBtn.visible = false;
if (typeof startBtnBg !== "undefined") startBtnBg.visible = false;
if (typeof shopBtnBg !== "undefined") shopBtnBg.visible = false;
if (typeof gameTitle !== "undefined") gameTitle.visible = false;
// Arka plan
// Shop arka planı kaldırıldı (yeşil deco2 yok)
if (shopBg) shopBg.visible = false;
// Başlık
if (!shopTitle) {
shopTitle = new Text2("Character Skin Shop", {
size: 120,
fill: "#fff",
font: "Arial Black"
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = GAME_W / 2;
shopTitle.y = GAME_H / 2 - 540; // Moved a bit higher
game.addChild(shopTitle);
}
shopTitle.visible = true;
// Close button
if (!shopCloseBtn) {
shopCloseBtn = new Text2("Close", {
size: 80,
fill: "#fff",
font: "Arial Black"
});
shopCloseBtn.anchor.set(0.5, 0.5);
shopCloseBtn.x = GAME_W / 2;
shopCloseBtn.y = GAME_H / 2 + 820; // Moved a bit lower
shopCloseBtn.down = function () {
hideShopMenu();
showStartMenu();
};
game.addChild(shopCloseBtn);
}
shopCloseBtn.visible = true;
// Coin indicator
if (!shopCoinTxt) {
shopCoinTxt = new Text2("Beat: 0", {
size: 80,
fill: 0xFFE066
});
shopCoinTxt.anchor.set(0.5, 0.5);
shopCoinTxt.x = GAME_W / 2;
shopCoinTxt.y = GAME_H / 2 - 440; // More space from title
game.addChild(shopCoinTxt);
}
shopCoinTxt.visible = true;
shopCoinTxt.setText("Beat: " + getPlayerCoins());
// Hide homeBtnAbove (hearts' home button) in shop
if (typeof homeBtnAbove !== "undefined") homeBtnAbove.visible = false;
// Skin butonları
for (var i = 0; i < skinBtns.length; i++) {
if (skinBtns[i]) skinBtns[i].visible = false;
}
var unlocked = getUnlockedSkins();
var selected = getSelectedSkin();
// Yeni düzen: 2 satır 5 sütun, daha büyük arka plan ve üstte başlık/coin
var btnRows = 2;
var btnCols = 5;
var btnDX = 340; // Yatay aralığı biraz açtık
var btnDY = 300; // Dikey aralığı artırdık
var btnX0 = GAME_W / 2 - (btnCols - 1) * btnDX / 2;
var btnY0 = GAME_H / 2 - 60; // Butonları biraz daha aşağı aldık
var col = 0,
row = 0;
for (var i = 0; i < SKINS.length; i++) {
var btn;
if (!skinBtns[i]) {
btn = new Container();
// Skin görseli (her karakter için farklı asset)
var skinAsset = LK.getAsset(SKINS[i].asset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 0,
y: 0
});
btn.addChild(skinAsset);
// Skin adı
var nameTxt = new Text2(SKINS[i].name, {
size: 60,
fill: "#fff"
});
nameTxt.anchor.set(0.5, 0);
nameTxt.x = 0;
nameTxt.y = 90; // Görselin altına biraz daha mesafe
btn.addChild(nameTxt);
// Fiyat veya kilit
var priceTxt = new Text2("", {
size: 50,
fill: 0xFFE066
});
priceTxt.anchor.set(0.5, 0);
priceTxt.x = 0;
priceTxt.y = 170; // Name ile price arası daha fazla (artırıldı)
btn.addChild(priceTxt);
btn.priceTxt = priceTxt;
btn.skinIdx = i;
btn.down = function (x, y, obj) {
var idx = this.skinIdx;
if (isSkinUnlocked(idx)) {
LK.getSound('select').play();
setSelectedSkin(idx);
updateShopMenu();
} else {
var coins = getPlayerCoins();
var price = SKINS[idx].price;
if (coins >= price) {
LK.getSound('select').play();
setPlayerCoins(coins - price);
unlockSkin(idx);
setSelectedSkin(idx);
updateShopMenu();
}
}
};
skinBtns[i] = btn;
game.addChild(btn);
} else {
btn = skinBtns[i];
}
btn.visible = true;
btn.x = btnX0 + col * btnDX;
btn.y = btnY0 + row * btnDY;
// Price/lock/active
if (unlocked[i]) {
if (selected === i) {
btn.priceTxt.setText("Selected");
btn.priceTxt.fill = "#00e676";
} else {
btn.priceTxt.setText("Unlocked");
btn.priceTxt.fill = "#ffe066";
}
} else {
btn.priceTxt.setText("Locked (" + SKINS[i].price + " beat)");
btn.priceTxt.fill = "#ff5252";
}
col++;
if (col >= btnCols) {
col = 0;
row++;
}
}
}
// Mağaza menüsünü güncelle (skin seçimi/kilit açma sonrası)
function updateShopMenu() {
if (shopCoinTxt) shopCoinTxt.setText("Beat: " + getPlayerCoins());
var unlocked = getUnlockedSkins();
var selected = getSelectedSkin();
for (var i = 0; i < SKINS.length; i++) {
var btn = skinBtns[i];
if (!btn) continue;
// Always ensure priceTxt is at correct y (in case of dynamic changes)
if (btn.priceTxt) btn.priceTxt.y = 170;
if (unlocked[i]) {
if (selected === i) {
btn.priceTxt.setText("Selected");
btn.priceTxt.fill = "#00e676";
} else {
btn.priceTxt.setText("Unlocked");
btn.priceTxt.fill = "#ffe066";
}
} else {
btn.priceTxt.setText("Locked (" + SKINS[i].price + " beat)");
btn.priceTxt.fill = "#ff5252";
}
}
}
// Mağaza menüsünü gizle
function hideShopMenu() {
if (shopBg) shopBg.visible = false;
if (shopTitle) shopTitle.visible = false;
if (shopCloseBtn) shopCloseBtn.visible = false;
if (shopCoinTxt) shopCoinTxt.visible = false;
for (var i = 0; i < skinBtns.length; i++) {
if (skinBtns[i]) skinBtns[i].visible = false;
}
}
// Oyun sonunda veya beat toplandığında coin ekle
function addCoins(n) {
var coins = getPlayerCoins();
setPlayerCoins(coins + n);
if (shopCoinTxt && shopCoinTxt.visible) shopCoinTxt.setText("Beat: " + getPlayerCoins());
}
// --- Ship skinini seçili skine göre oluştur ---
var old_Ship = Ship;
Ship = Container.expand(function () {
var self = Container.call(this);
var idx = getSelectedSkin();
if (typeof idx !== "number" || idx < 0 || idx >= SKINS.length) idx = 0;
var assetId = SKINS[idx].asset;
var color = SKINS[idx].color;
var shipGfx = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Renk uygula (tint)
shipGfx.tint = color;
self.energy = 3;
self.invincible = false;
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(shipGfx, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(shipGfx, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
return self;
});
// Decorative blocks (unique assets) around the menu
// Removed decoBlock1 and decoBlock2 to ensure no shapes are above the game title
var decoBlock3 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: GAME_W / 2 - 500,
y: GAME_H / 2 + 350
});
game.addChild(decoBlock3);
var decoBlock4 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W / 2 + 500,
y: GAME_H / 2 + 350
});
game.addChild(decoBlock4);
// Add more unique decorative blocks, using all available assets, spread out, avoid text/buttons, fill empty areas
// Top left (avoid 0-100,0-100)
var decoBlock5 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 220,
y: 220
});
game.addChild(decoBlock5);
// Top right
var decoBlock6 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 220,
y: 220
});
game.addChild(decoBlock6);
// Bottom left
var decoBlock7 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: 220,
y: GAME_H - 220
});
game.addChild(decoBlock7);
// Bottom right
var decoBlock8 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 220,
y: GAME_H - 220
});
game.addChild(decoBlock8);
// Left center
var decoBlock9 = LK.getAsset('deco1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 180,
y: GAME_H / 2
});
game.addChild(decoBlock9);
// Right center
var decoBlock10 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: GAME_W - 180,
y: GAME_H / 2
});
game.addChild(decoBlock10);
// (Removed decoBlock11 to ensure no shape is above the game title)
// Bottom center (below menu)
var decoBlock12 = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W / 2,
y: GAME_H - 120
});
game.addChild(decoBlock12);
// Left mid-top
var decoBlock13 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
x: 320,
y: 600
});
game.addChild(decoBlock13);
// Right mid-top
var decoBlock14 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 320,
y: 600
});
game.addChild(decoBlock14);
// Left mid-bottom
var decoBlock15 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: 320,
y: GAME_H - 600
});
game.addChild(decoBlock15);
// Right mid-bottom
var decoBlock16 = LK.getAsset('deco1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
x: GAME_W - 320,
y: GAME_H - 600
});
game.addChild(decoBlock16);
// Spread a few more in the corners, but not overlapping text/buttons
var decoBlock17 = LK.getAsset('deco4', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: 500,
y: 400
});
game.addChild(decoBlock17);
var decoBlock18 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 500,
y: 400
});
game.addChild(decoBlock18);
var decoBlock19 = LK.getAsset('deco2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: 500,
y: GAME_H - 400
});
game.addChild(decoBlock19);
var decoBlock20 = LK.getAsset('deco3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_W - 500,
y: GAME_H - 400
});
game.addChild(decoBlock20);
// Oyunu başlatırken menüyü göster
showStartMenu();
;
MÜZİK NOTASI ŞEKLİNDE BİR COİN TARZI BİR ŞEY. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR BOSS ÇİZ AYAKSIZ. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ BU KARAKTER ETRAFTA DÖNEBLİYOR ONE GÖRE, AYAKSIZ. SİYAH KULLANMA. GÜLMESİN In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR GFEZEGEN ÇİZ. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR ENGEL AMA YATAY OLACAK. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER PLAYER VE İSMİ COSMOS ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER PLAYER VE İSMİ ASTERA ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER PLAYER VE İSMİ VORTEX ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK.. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER PLAYER VE İSMİ zenith ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK.. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER PLAYER VE İSMİ Aurion ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK.. In-Game asset. 2d. High contrast. No shadows
MÜZİK NOTASI ŞEKLİNDE BİR UZAYLI CANAVAR ÇİZ AMA BU KARAKTER VE İSMİ Quasar ONA GÖRE TASARLA. AYAKSIZ. dONT WRİTE TEXT İN TO İMAGE. NO BLACK.. In-Game asset. 2d. High contrast. No shadows
yatay müzik notası şeklinde bir buton. In-Game asset. 2d. High contrast. No shadows
gezegensiz bir uzay temalı bir görsel background. In-Game asset. 2d. High contrast. No shadows
make a main menu button. In-Game asset. 2d. High contrast. No shadows