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();