User prompt
bşala diyince seviyr 10 çıkıyor 1 çıkması gerekiyor
User prompt
oyuna menüde yap
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(piece, {' Line Number: 523
User prompt
Please fix the bug: 'TypeError: Cannot set properties of null (setting 'isPlaced')' in or related to this line: 'piece.isPlaced = true;' Line Number: 517
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(draggingPiece, {' Line Number: 613
User prompt
Please fix the bug: 'LK.hasAsset is not a function' in or related to this line: 'if (!LK.hasAsset(id)) {}' Line Number: 393
Code edit (1 edits merged)
Please save this source code
User prompt
Zenge: Sakin Bulmaca Yolculuğu
Initial prompt
Zenge Hikayeli, çok basit bulmaca oyunu. Sadece sürükle-bırak. Grafikler sakin. ⏱️ ~30-40 dakika ama leveli olsun 10 level olsun
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { level: 1 }); /**** * Classes ****/ // PuzzlePiece: Draggable puzzle piece var PuzzlePiece = Container.expand(function () { var self = Container.call(this); // Properties to be set after creation: // self.pieceId: index of this piece in the level // self.targetX, self.targetY: where this piece should be placed // self.isPlaced: whether the piece is already placed self.isPlaced = false; // Attach the shape asset (box or ellipse, color, size) // These are set after creation via self.setShape self.shape = null; self.setShape = function (shapeId, options) { if (self.shape) { self.shape.destroy(); } self.shape = self.attachAsset(shapeId, { anchorX: 0.5, anchorY: 0.5 }); if (options && options.alpha !== undefined) { self.shape.alpha = options.alpha; } }; // Animate piece to its target position self.animateToTarget = function (onFinish) { tween(self, { x: self.targetX, y: self.targetY }, { duration: 400, easing: tween.cubicOut, onFinish: onFinish }); }; // Animate piece back to its original position self.animateToOrigin = function (onFinish) { tween(self, { x: self.originX, y: self.originY }, { duration: 350, easing: tween.easeOut, onFinish: onFinish }); }; return self; }); // TargetSlot: Where a piece should be placed var TargetSlot = Container.expand(function () { var self = Container.call(this); // Attach the shape asset (box or ellipse, color, size) self.shape = null; self.setShape = function (shapeId, options) { if (self.shape) { self.shape.destroy(); } self.shape = self.attachAsset(shapeId, { anchorX: 0.5, anchorY: 0.5 }); if (options && options.alpha !== undefined) { self.shape.alpha = options.alpha; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ /* We use only simple shapes for puzzle pieces and targets. Each level will use a different color for its pieces and targets for visual variety. Assets are initialized dynamically as needed. */ // --- Level Data --- // Each level defines: pieces: [{shape, color, width, height, targetX, targetY, startX, startY}], and optionally a levelText var levels = [ // Level 1: Simple square { levelText: "Bir kareyi tamamla.", pieces: [{ shape: 'box', color: 0x6ec6ff, width: 320, height: 320, targetX: 1024, targetY: 900, startX: 600, startY: 1800 }, { shape: 'box', color: 0x6ec6ff, width: 320, height: 320, targetX: 1344, targetY: 900, startX: 1440, startY: 1800 }] }, // Level 2: Two ellipses { levelText: "İki daireyi birleştir.", pieces: [{ shape: 'ellipse', color: 0xffb74d, width: 280, height: 280, targetX: 900, targetY: 1100, startX: 400, startY: 2000 }, { shape: 'ellipse', color: 0xffb74d, width: 280, height: 280, targetX: 1148, targetY: 1100, startX: 1600, startY: 2000 }] }, // Level 3: L-shape { levelText: "L şeklini oluştur.", pieces: [{ shape: 'box', color: 0x81c784, width: 200, height: 400, targetX: 900, targetY: 900, startX: 400, startY: 1800 }, { shape: 'box', color: 0x81c784, width: 400, height: 200, targetX: 1100, targetY: 1100, startX: 1600, startY: 1800 }] }, // Level 4: T-shape { levelText: "T harfini tamamla.", pieces: [{ shape: 'box', color: 0xe57373, width: 400, height: 120, targetX: 1024, targetY: 900, startX: 600, startY: 1800 }, { shape: 'box', color: 0xe57373, width: 120, height: 320, targetX: 1024, targetY: 1060, startX: 1440, startY: 1800 }] }, // Level 5: Triangle (approximate with boxes) { levelText: "Bir üçgen oluştur.", pieces: [{ shape: 'box', color: 0xba68c8, width: 320, height: 80, targetX: 1024, targetY: 900, startX: 600, startY: 1800 }, { shape: 'box', color: 0xba68c8, width: 80, height: 320, targetX: 864, targetY: 1060, startX: 1440, startY: 1800 }, { shape: 'box', color: 0xba68c8, width: 80, height: 320, targetX: 1184, targetY: 1060, startX: 900, startY: 2000 }] }, // Level 6: Overlapping ellipses (Venn) { levelText: "Kesişen iki daireyi yerleştir.", pieces: [{ shape: 'ellipse', color: 0x4db6ac, width: 260, height: 260, targetX: 950, targetY: 1000, startX: 400, startY: 2000 }, { shape: 'ellipse', color: 0x4db6ac, width: 260, height: 260, targetX: 1100, targetY: 1000, startX: 1600, startY: 2000 }] }, // Level 7: Barbell (two circles, one rectangle) { levelText: "Bir halter oluştur.", pieces: [{ shape: 'ellipse', color: 0xff8a65, width: 180, height: 180, targetX: 900, targetY: 1000, startX: 400, startY: 2000 }, { shape: 'ellipse', color: 0xff8a65, width: 180, height: 180, targetX: 1148, targetY: 1000, startX: 1600, startY: 2000 }, { shape: 'box', color: 0xff8a65, width: 248, height: 60, targetX: 1024, targetY: 1000, startX: 1024, startY: 1800 }] }, // Level 8: Cross { levelText: "Bir artı işareti yap.", pieces: [{ shape: 'box', color: 0xa1887f, width: 80, height: 320, targetX: 1024, targetY: 900, startX: 600, startY: 1800 }, { shape: 'box', color: 0xa1887f, width: 320, height: 80, targetX: 1024, targetY: 900, startX: 1440, startY: 1800 }] }, // Level 9: Rectangle with a hole (two boxes) { levelText: "Bir çerçeve oluştur.", pieces: [{ shape: 'box', color: 0x90caf9, width: 400, height: 80, targetX: 1024, targetY: 900, startX: 600, startY: 1800 }, { shape: 'box', color: 0x90caf9, width: 80, height: 400, targetX: 824, targetY: 1100, startX: 1440, startY: 1800 }, { shape: 'box', color: 0x90caf9, width: 80, height: 400, targetX: 1224, targetY: 1100, startX: 900, startY: 2000 }, { shape: 'box', color: 0x90caf9, width: 400, height: 80, targetX: 1024, targetY: 1300, startX: 1200, startY: 2200 }] }, // Level 10: Heart (approximate with ellipses and box) { levelText: "Bir kalp oluştur.", pieces: [{ shape: 'ellipse', color: 0xf06292, width: 180, height: 180, targetX: 980, targetY: 1000, startX: 400, startY: 2000 }, { shape: 'ellipse', color: 0xf06292, width: 180, height: 180, targetX: 1068, targetY: 1000, startX: 1600, startY: 2000 }, { shape: 'box', color: 0xf06292, width: 180, height: 220, targetX: 1024, targetY: 1120, startX: 1024, startY: 1800 }] }]; // --- State --- var currentLevel = storage.level || 1; if (currentLevel < 1) currentLevel = 1; if (currentLevel > levels.length) currentLevel = 1; var pieces = []; // PuzzlePiece instances var slots = []; // TargetSlot instances var draggingPiece = null; var dragOffsetX = 0; var dragOffsetY = 0; var placedCount = 0; var levelTextObj = null; var levelNumTextObj = null; var youWinTextObj = null; // --- Helper: Create asset for a shape --- function getShapeAssetId(shape, color, width, height) { var id = shape + '_' + color.toString(16) + '_' + width + '_' + height; // Only initialize if not already done // Defensive workaround: check if asset exists by trying to get it, and if not, initialize it var assetExists = false; try { var asset = LK.getAsset(id, {}); if (asset) assetExists = true; } catch (e) { assetExists = false; } if (!assetExists) {} return id; } // --- Helper: Remove all pieces and slots from game --- function clearLevel() { for (var i = 0; i < pieces.length; i++) { pieces[i].destroy(); } for (var j = 0; j < slots.length; j++) { slots[j].destroy(); } pieces = []; slots = []; placedCount = 0; if (levelTextObj) { levelTextObj.destroy(); levelTextObj = null; } if (levelNumTextObj) { levelNumTextObj.destroy(); levelNumTextObj = null; } if (youWinTextObj) { youWinTextObj.destroy(); youWinTextObj = null; } } // --- Helper: Show level text --- function showLevelText(levelIdx) { var level = levels[levelIdx]; // Level number levelNumTextObj = new Text2("Seviye " + (levelIdx + 1), { size: 90, fill: 0xFFFFFF }); levelNumTextObj.anchor.set(0.5, 0); LK.gui.top.addChild(levelNumTextObj); // Level description levelTextObj = new Text2(level.levelText, { size: 70, fill: 0xBDBDBD }); levelTextObj.anchor.set(0.5, 0); LK.gui.top.addChild(levelTextObj); // Position: levelNum at top center, levelText below it levelNumTextObj.x = LK.gui.top.width / 2; levelNumTextObj.y = 120; levelTextObj.x = LK.gui.top.width / 2; levelTextObj.y = 220; } // --- Helper: Show "Tebrikler" at the end --- function showYouWinText() { youWinTextObj = new Text2("Tebrikler!\nTüm seviyeleri tamamladın.", { size: 120, fill: 0xFFF176, align: "center" }); youWinTextObj.anchor.set(0.5, 0.5); LK.gui.center.addChild(youWinTextObj); youWinTextObj.x = LK.gui.center.width / 2; youWinTextObj.y = LK.gui.center.height / 2; } // --- Load a level --- function loadLevel(levelIdx) { clearLevel(); showLevelText(levelIdx); var level = levels[levelIdx]; var pieceData = level.pieces; placedCount = 0; // Create slots (targets) for (var i = 0; i < pieceData.length; i++) { var p = pieceData[i]; var slot = new TargetSlot(); var slotAssetId = getShapeAssetId(p.shape, p.color, p.width, p.height); slot.setShape(slotAssetId, { alpha: 0.18 }); slot.x = p.targetX; slot.y = p.targetY; slot.pieceId = i; game.addChild(slot); slots.push(slot); } // Create pieces for (var j = 0; j < pieceData.length; j++) { var p2 = pieceData[j]; var piece = new PuzzlePiece(); var pieceAssetId = getShapeAssetId(p2.shape, p2.color, p2.width, p2.height); piece.setShape(pieceAssetId, { alpha: 1 }); piece.x = p2.startX; piece.y = p2.startY; piece.originX = p2.startX; piece.originY = p2.startY; piece.targetX = p2.targetX; piece.targetY = p2.targetY; piece.pieceId = j; piece.isPlaced = false; game.addChild(piece); pieces.push(piece); } } // --- Check if a piece is close enough to its slot --- function isPieceOnSlot(piece, slot) { // Use distance between centers, allow some tolerance var dx = piece.x - slot.x; var dy = piece.y - slot.y; var dist = Math.sqrt(dx * dx + dy * dy); var tolerance = 80; return dist < tolerance; } // --- Place a piece to its slot --- function placePiece(piece, slot) { if (piece) { piece.isPlaced = true; piece.x = slot.x; piece.y = slot.y; } // Animate a little scale effect if (piece && 'scaleX' in piece && 'scaleY' in piece) { tween(piece, { scaleX: 1.12, scaleY: 1.12 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { if (piece && 'scaleX' in piece && 'scaleY' in piece) { tween(piece, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } } }); } placedCount++; } // --- Handle drag and drop logic --- function findPieceAt(x, y) { // Return topmost piece under (x, y) that is not placed for (var i = pieces.length - 1; i >= 0; i--) { var piece = pieces[i]; if (piece.isPlaced) continue; var px = piece.x, py = piece.y; var w = piece.shape.width, h = piece.shape.height; if (x >= px - w / 2 && x <= px + w / 2 && y >= py - h / 2 && y <= py + h / 2) { return piece; } } return null; } // --- Game event handlers --- // Drag start game.down = function (x, y, obj) { if (draggingPiece) return; var piece = findPieceAt(x, y); if (piece && !piece.isPlaced) { draggingPiece = piece; dragOffsetX = x - piece.x; dragOffsetY = y - piece.y; // Bring to front game.removeChild(piece); game.addChild(piece); // Animate scale up tween(piece, { scaleX: 1.08, scaleY: 1.08 }, { duration: 100 }); } }; // Drag move game.move = function (x, y, obj) { if (draggingPiece && !draggingPiece.isPlaced) { draggingPiece.x = x - dragOffsetX; draggingPiece.y = y - dragOffsetY; } }; // Drag end game.up = function (x, y, obj) { if (draggingPiece && !draggingPiece.isPlaced) { // Check if over correct slot var slot = slots[draggingPiece.pieceId]; if (isPieceOnSlot(draggingPiece, slot)) { // Snap to slot draggingPiece.animateToTarget(function () { placePiece(draggingPiece, slot); // Check if level complete if (placedCount === pieces.length) { // Next level or win LK.setTimeout(function () { if (currentLevel < levels.length) { currentLevel++; storage.level = currentLevel; loadLevel(currentLevel - 1); } else { showYouWinText(); LK.showYouWin(); } }, 600); } }); } else { // Animate back to origin draggingPiece.animateToOrigin(function () { // Defensive: Only tween if draggingPiece is still valid and not destroyed if (draggingPiece && 'scaleX' in draggingPiece && 'scaleY' in draggingPiece) { tween(draggingPiece, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } } draggingPiece = null; }; // --- Game update (not used for logic here) --- game.update = function () { // No per-frame logic needed }; // --- Menu State --- var menuContainer = null; function showMenu() { // Defensive: clear menu if already exists if (menuContainer) { menuContainer.destroy(); menuContainer = null; } clearLevel(); menuContainer = new Container(); // Title var title = new Text2("Zenge", { size: 180, fill: 0x6ec6ff, align: "center" }); title.anchor.set(0.5, 0); menuContainer.addChild(title); title.x = 2048 / 2; title.y = 320; // Subtitle var subtitle = new Text2("Sakin Bulmaca Yolculuğu", { size: 80, fill: 0xBDBDBD, align: "center" }); subtitle.anchor.set(0.5, 0); menuContainer.addChild(subtitle); subtitle.x = 2048 / 2; subtitle.y = 520; // Start Button var startBtnW = 600, startBtnH = 180; var startBtn = LK.getAsset('menu_start_btn', { width: startBtnW, height: startBtnH, color: 0x81c784, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); menuContainer.addChild(startBtn); startBtn.x = 2048 / 2; startBtn.y = 900; // Start Button Text var startText = new Text2("Başla", { size: 100, fill: 0xffffff, align: "center" }); startText.anchor.set(0.5, 0.5); menuContainer.addChild(startText); startText.x = startBtn.x; startText.y = startBtn.y; // Instructions var info = new Text2("Parçaları sürükleyip bırak. 10 seviye boyunca rahatla ve bulmacaları tamamla.", { size: 60, fill: 0xBDBDBD, align: "center" }); info.anchor.set(0.5, 0); menuContainer.addChild(info); info.x = 2048 / 2; info.y = 1200; // Add to game game.addChild(menuContainer); // Button interaction startBtn.interactive = true; startBtn.down = function (x, y, obj) { // Remove menu, start game if (menuContainer) { menuContainer.destroy(); menuContainer = null; } currentLevel = 1; storage.level = 1; loadLevel(0); }; // Also allow clicking the text startText.interactive = true; startText.down = startBtn.down; } // Show menu at game start showMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
level: 1
});
/****
* Classes
****/
// PuzzlePiece: Draggable puzzle piece
var PuzzlePiece = Container.expand(function () {
var self = Container.call(this);
// Properties to be set after creation:
// self.pieceId: index of this piece in the level
// self.targetX, self.targetY: where this piece should be placed
// self.isPlaced: whether the piece is already placed
self.isPlaced = false;
// Attach the shape asset (box or ellipse, color, size)
// These are set after creation via self.setShape
self.shape = null;
self.setShape = function (shapeId, options) {
if (self.shape) {
self.shape.destroy();
}
self.shape = self.attachAsset(shapeId, {
anchorX: 0.5,
anchorY: 0.5
});
if (options && options.alpha !== undefined) {
self.shape.alpha = options.alpha;
}
};
// Animate piece to its target position
self.animateToTarget = function (onFinish) {
tween(self, {
x: self.targetX,
y: self.targetY
}, {
duration: 400,
easing: tween.cubicOut,
onFinish: onFinish
});
};
// Animate piece back to its original position
self.animateToOrigin = function (onFinish) {
tween(self, {
x: self.originX,
y: self.originY
}, {
duration: 350,
easing: tween.easeOut,
onFinish: onFinish
});
};
return self;
});
// TargetSlot: Where a piece should be placed
var TargetSlot = Container.expand(function () {
var self = Container.call(this);
// Attach the shape asset (box or ellipse, color, size)
self.shape = null;
self.setShape = function (shapeId, options) {
if (self.shape) {
self.shape.destroy();
}
self.shape = self.attachAsset(shapeId, {
anchorX: 0.5,
anchorY: 0.5
});
if (options && options.alpha !== undefined) {
self.shape.alpha = options.alpha;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
/*
We use only simple shapes for puzzle pieces and targets.
Each level will use a different color for its pieces and targets for visual variety.
Assets are initialized dynamically as needed.
*/
// --- Level Data ---
// Each level defines: pieces: [{shape, color, width, height, targetX, targetY, startX, startY}], and optionally a levelText
var levels = [
// Level 1: Simple square
{
levelText: "Bir kareyi tamamla.",
pieces: [{
shape: 'box',
color: 0x6ec6ff,
width: 320,
height: 320,
targetX: 1024,
targetY: 900,
startX: 600,
startY: 1800
}, {
shape: 'box',
color: 0x6ec6ff,
width: 320,
height: 320,
targetX: 1344,
targetY: 900,
startX: 1440,
startY: 1800
}]
},
// Level 2: Two ellipses
{
levelText: "İki daireyi birleştir.",
pieces: [{
shape: 'ellipse',
color: 0xffb74d,
width: 280,
height: 280,
targetX: 900,
targetY: 1100,
startX: 400,
startY: 2000
}, {
shape: 'ellipse',
color: 0xffb74d,
width: 280,
height: 280,
targetX: 1148,
targetY: 1100,
startX: 1600,
startY: 2000
}]
},
// Level 3: L-shape
{
levelText: "L şeklini oluştur.",
pieces: [{
shape: 'box',
color: 0x81c784,
width: 200,
height: 400,
targetX: 900,
targetY: 900,
startX: 400,
startY: 1800
}, {
shape: 'box',
color: 0x81c784,
width: 400,
height: 200,
targetX: 1100,
targetY: 1100,
startX: 1600,
startY: 1800
}]
},
// Level 4: T-shape
{
levelText: "T harfini tamamla.",
pieces: [{
shape: 'box',
color: 0xe57373,
width: 400,
height: 120,
targetX: 1024,
targetY: 900,
startX: 600,
startY: 1800
}, {
shape: 'box',
color: 0xe57373,
width: 120,
height: 320,
targetX: 1024,
targetY: 1060,
startX: 1440,
startY: 1800
}]
},
// Level 5: Triangle (approximate with boxes)
{
levelText: "Bir üçgen oluştur.",
pieces: [{
shape: 'box',
color: 0xba68c8,
width: 320,
height: 80,
targetX: 1024,
targetY: 900,
startX: 600,
startY: 1800
}, {
shape: 'box',
color: 0xba68c8,
width: 80,
height: 320,
targetX: 864,
targetY: 1060,
startX: 1440,
startY: 1800
}, {
shape: 'box',
color: 0xba68c8,
width: 80,
height: 320,
targetX: 1184,
targetY: 1060,
startX: 900,
startY: 2000
}]
},
// Level 6: Overlapping ellipses (Venn)
{
levelText: "Kesişen iki daireyi yerleştir.",
pieces: [{
shape: 'ellipse',
color: 0x4db6ac,
width: 260,
height: 260,
targetX: 950,
targetY: 1000,
startX: 400,
startY: 2000
}, {
shape: 'ellipse',
color: 0x4db6ac,
width: 260,
height: 260,
targetX: 1100,
targetY: 1000,
startX: 1600,
startY: 2000
}]
},
// Level 7: Barbell (two circles, one rectangle)
{
levelText: "Bir halter oluştur.",
pieces: [{
shape: 'ellipse',
color: 0xff8a65,
width: 180,
height: 180,
targetX: 900,
targetY: 1000,
startX: 400,
startY: 2000
}, {
shape: 'ellipse',
color: 0xff8a65,
width: 180,
height: 180,
targetX: 1148,
targetY: 1000,
startX: 1600,
startY: 2000
}, {
shape: 'box',
color: 0xff8a65,
width: 248,
height: 60,
targetX: 1024,
targetY: 1000,
startX: 1024,
startY: 1800
}]
},
// Level 8: Cross
{
levelText: "Bir artı işareti yap.",
pieces: [{
shape: 'box',
color: 0xa1887f,
width: 80,
height: 320,
targetX: 1024,
targetY: 900,
startX: 600,
startY: 1800
}, {
shape: 'box',
color: 0xa1887f,
width: 320,
height: 80,
targetX: 1024,
targetY: 900,
startX: 1440,
startY: 1800
}]
},
// Level 9: Rectangle with a hole (two boxes)
{
levelText: "Bir çerçeve oluştur.",
pieces: [{
shape: 'box',
color: 0x90caf9,
width: 400,
height: 80,
targetX: 1024,
targetY: 900,
startX: 600,
startY: 1800
}, {
shape: 'box',
color: 0x90caf9,
width: 80,
height: 400,
targetX: 824,
targetY: 1100,
startX: 1440,
startY: 1800
}, {
shape: 'box',
color: 0x90caf9,
width: 80,
height: 400,
targetX: 1224,
targetY: 1100,
startX: 900,
startY: 2000
}, {
shape: 'box',
color: 0x90caf9,
width: 400,
height: 80,
targetX: 1024,
targetY: 1300,
startX: 1200,
startY: 2200
}]
},
// Level 10: Heart (approximate with ellipses and box)
{
levelText: "Bir kalp oluştur.",
pieces: [{
shape: 'ellipse',
color: 0xf06292,
width: 180,
height: 180,
targetX: 980,
targetY: 1000,
startX: 400,
startY: 2000
}, {
shape: 'ellipse',
color: 0xf06292,
width: 180,
height: 180,
targetX: 1068,
targetY: 1000,
startX: 1600,
startY: 2000
}, {
shape: 'box',
color: 0xf06292,
width: 180,
height: 220,
targetX: 1024,
targetY: 1120,
startX: 1024,
startY: 1800
}]
}];
// --- State ---
var currentLevel = storage.level || 1;
if (currentLevel < 1) currentLevel = 1;
if (currentLevel > levels.length) currentLevel = 1;
var pieces = []; // PuzzlePiece instances
var slots = []; // TargetSlot instances
var draggingPiece = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var placedCount = 0;
var levelTextObj = null;
var levelNumTextObj = null;
var youWinTextObj = null;
// --- Helper: Create asset for a shape ---
function getShapeAssetId(shape, color, width, height) {
var id = shape + '_' + color.toString(16) + '_' + width + '_' + height;
// Only initialize if not already done
// Defensive workaround: check if asset exists by trying to get it, and if not, initialize it
var assetExists = false;
try {
var asset = LK.getAsset(id, {});
if (asset) assetExists = true;
} catch (e) {
assetExists = false;
}
if (!assetExists) {}
return id;
}
// --- Helper: Remove all pieces and slots from game ---
function clearLevel() {
for (var i = 0; i < pieces.length; i++) {
pieces[i].destroy();
}
for (var j = 0; j < slots.length; j++) {
slots[j].destroy();
}
pieces = [];
slots = [];
placedCount = 0;
if (levelTextObj) {
levelTextObj.destroy();
levelTextObj = null;
}
if (levelNumTextObj) {
levelNumTextObj.destroy();
levelNumTextObj = null;
}
if (youWinTextObj) {
youWinTextObj.destroy();
youWinTextObj = null;
}
}
// --- Helper: Show level text ---
function showLevelText(levelIdx) {
var level = levels[levelIdx];
// Level number
levelNumTextObj = new Text2("Seviye " + (levelIdx + 1), {
size: 90,
fill: 0xFFFFFF
});
levelNumTextObj.anchor.set(0.5, 0);
LK.gui.top.addChild(levelNumTextObj);
// Level description
levelTextObj = new Text2(level.levelText, {
size: 70,
fill: 0xBDBDBD
});
levelTextObj.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTextObj);
// Position: levelNum at top center, levelText below it
levelNumTextObj.x = LK.gui.top.width / 2;
levelNumTextObj.y = 120;
levelTextObj.x = LK.gui.top.width / 2;
levelTextObj.y = 220;
}
// --- Helper: Show "Tebrikler" at the end ---
function showYouWinText() {
youWinTextObj = new Text2("Tebrikler!\nTüm seviyeleri tamamladın.", {
size: 120,
fill: 0xFFF176,
align: "center"
});
youWinTextObj.anchor.set(0.5, 0.5);
LK.gui.center.addChild(youWinTextObj);
youWinTextObj.x = LK.gui.center.width / 2;
youWinTextObj.y = LK.gui.center.height / 2;
}
// --- Load a level ---
function loadLevel(levelIdx) {
clearLevel();
showLevelText(levelIdx);
var level = levels[levelIdx];
var pieceData = level.pieces;
placedCount = 0;
// Create slots (targets)
for (var i = 0; i < pieceData.length; i++) {
var p = pieceData[i];
var slot = new TargetSlot();
var slotAssetId = getShapeAssetId(p.shape, p.color, p.width, p.height);
slot.setShape(slotAssetId, {
alpha: 0.18
});
slot.x = p.targetX;
slot.y = p.targetY;
slot.pieceId = i;
game.addChild(slot);
slots.push(slot);
}
// Create pieces
for (var j = 0; j < pieceData.length; j++) {
var p2 = pieceData[j];
var piece = new PuzzlePiece();
var pieceAssetId = getShapeAssetId(p2.shape, p2.color, p2.width, p2.height);
piece.setShape(pieceAssetId, {
alpha: 1
});
piece.x = p2.startX;
piece.y = p2.startY;
piece.originX = p2.startX;
piece.originY = p2.startY;
piece.targetX = p2.targetX;
piece.targetY = p2.targetY;
piece.pieceId = j;
piece.isPlaced = false;
game.addChild(piece);
pieces.push(piece);
}
}
// --- Check if a piece is close enough to its slot ---
function isPieceOnSlot(piece, slot) {
// Use distance between centers, allow some tolerance
var dx = piece.x - slot.x;
var dy = piece.y - slot.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var tolerance = 80;
return dist < tolerance;
}
// --- Place a piece to its slot ---
function placePiece(piece, slot) {
if (piece) {
piece.isPlaced = true;
piece.x = slot.x;
piece.y = slot.y;
}
// Animate a little scale effect
if (piece && 'scaleX' in piece && 'scaleY' in piece) {
tween(piece, {
scaleX: 1.12,
scaleY: 1.12
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
if (piece && 'scaleX' in piece && 'scaleY' in piece) {
tween(piece, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
}
});
}
placedCount++;
}
// --- Handle drag and drop logic ---
function findPieceAt(x, y) {
// Return topmost piece under (x, y) that is not placed
for (var i = pieces.length - 1; i >= 0; i--) {
var piece = pieces[i];
if (piece.isPlaced) continue;
var px = piece.x,
py = piece.y;
var w = piece.shape.width,
h = piece.shape.height;
if (x >= px - w / 2 && x <= px + w / 2 && y >= py - h / 2 && y <= py + h / 2) {
return piece;
}
}
return null;
}
// --- Game event handlers ---
// Drag start
game.down = function (x, y, obj) {
if (draggingPiece) return;
var piece = findPieceAt(x, y);
if (piece && !piece.isPlaced) {
draggingPiece = piece;
dragOffsetX = x - piece.x;
dragOffsetY = y - piece.y;
// Bring to front
game.removeChild(piece);
game.addChild(piece);
// Animate scale up
tween(piece, {
scaleX: 1.08,
scaleY: 1.08
}, {
duration: 100
});
}
};
// Drag move
game.move = function (x, y, obj) {
if (draggingPiece && !draggingPiece.isPlaced) {
draggingPiece.x = x - dragOffsetX;
draggingPiece.y = y - dragOffsetY;
}
};
// Drag end
game.up = function (x, y, obj) {
if (draggingPiece && !draggingPiece.isPlaced) {
// Check if over correct slot
var slot = slots[draggingPiece.pieceId];
if (isPieceOnSlot(draggingPiece, slot)) {
// Snap to slot
draggingPiece.animateToTarget(function () {
placePiece(draggingPiece, slot);
// Check if level complete
if (placedCount === pieces.length) {
// Next level or win
LK.setTimeout(function () {
if (currentLevel < levels.length) {
currentLevel++;
storage.level = currentLevel;
loadLevel(currentLevel - 1);
} else {
showYouWinText();
LK.showYouWin();
}
}, 600);
}
});
} else {
// Animate back to origin
draggingPiece.animateToOrigin(function () {
// Defensive: Only tween if draggingPiece is still valid and not destroyed
if (draggingPiece && 'scaleX' in draggingPiece && 'scaleY' in draggingPiece) {
tween(draggingPiece, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
}
draggingPiece = null;
};
// --- Game update (not used for logic here) ---
game.update = function () {
// No per-frame logic needed
};
// --- Menu State ---
var menuContainer = null;
function showMenu() {
// Defensive: clear menu if already exists
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
clearLevel();
menuContainer = new Container();
// Title
var title = new Text2("Zenge", {
size: 180,
fill: 0x6ec6ff,
align: "center"
});
title.anchor.set(0.5, 0);
menuContainer.addChild(title);
title.x = 2048 / 2;
title.y = 320;
// Subtitle
var subtitle = new Text2("Sakin Bulmaca Yolculuğu", {
size: 80,
fill: 0xBDBDBD,
align: "center"
});
subtitle.anchor.set(0.5, 0);
menuContainer.addChild(subtitle);
subtitle.x = 2048 / 2;
subtitle.y = 520;
// Start Button
var startBtnW = 600,
startBtnH = 180;
var startBtn = LK.getAsset('menu_start_btn', {
width: startBtnW,
height: startBtnH,
color: 0x81c784,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
menuContainer.addChild(startBtn);
startBtn.x = 2048 / 2;
startBtn.y = 900;
// Start Button Text
var startText = new Text2("Başla", {
size: 100,
fill: 0xffffff,
align: "center"
});
startText.anchor.set(0.5, 0.5);
menuContainer.addChild(startText);
startText.x = startBtn.x;
startText.y = startBtn.y;
// Instructions
var info = new Text2("Parçaları sürükleyip bırak. 10 seviye boyunca rahatla ve bulmacaları tamamla.", {
size: 60,
fill: 0xBDBDBD,
align: "center"
});
info.anchor.set(0.5, 0);
menuContainer.addChild(info);
info.x = 2048 / 2;
info.y = 1200;
// Add to game
game.addChild(menuContainer);
// Button interaction
startBtn.interactive = true;
startBtn.down = function (x, y, obj) {
// Remove menu, start game
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
currentLevel = 1;
storage.level = 1;
loadLevel(0);
};
// Also allow clicking the text
startText.interactive = true;
startText.down = startBtn.down;
}
// Show menu at game start
showMenu();