Code edit (1 edits merged)
Please save this source code
User prompt
snake be very fast ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let the snake's body turn smoothly in one piece, not in multiple pieces. And let the snake's speed increase. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the snake hits itself, the screen will display the message "You bit yourself" and the restart screen will appear.
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addEventListener')' in or related to this line: 'document.addEventListener('DOMContentLoaded', function () {' Line Number: 12
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (1 edits merged)
Please save this source code
User prompt
restore the game to its previous state
User prompt
Please fix the bug: 'ReferenceError: appleWidth is not defined' in or related to this line: 'return Math.sqrt(dx * dx + dy * dy);' Line Number: 40
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
Code edit (2 edits merged)
Please save this source code
User prompt
The snake's head is not visible
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'getElementById')' in or related to this line: 'var cnv = document.getElementById('gameCanvas'),' Line Number: 11
/**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ document.addEventListener('DOMContentLoaded', function () { // Canvas elementini ve konteksini dinamik olarak oluştur var cnv = document.createElement('canvas'); cnv.id = 'gameCanvas'; document.body.appendChild(cnv); // Canvas'ı body'ye ekle // Skorbord elementini dinamik olarak oluştur var scoreBoard = document.createElement('div'); scoreBoard.id = 'scoreBoard'; // ScoreBoard'a ID ata document.body.appendChild(scoreBoard); var ctx = cnv.getContext('2d'); // Canvas boyutlarını belirle (oyunun original kodundaki gibi, responsive'i sen ekleyebilirsin) cnv.width = 600; // Örnek bir genişlik cnv.height = 600; // Örnek bir yükseklik // Dinamik olarak CSS stilleri oluşturulup sayfaya ekleniyor var style = document.createElement('style'); style.textContent = "\n body {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background-color: #333;\n overflow: hidden;\n font-family: monospace; /* Oyun koduna yak\u0131n bir font */\n color: #eee;\n }\n canvas {\n border: 2px solid #eee;\n background-color: #000;\n margin-bottom: 20px; /* Skorbord ile aras\u0131na bo\u015Fluk */\n }\n #scoreBoard {\n font-size: 1.5em;\n text-align: center;\n padding: 10px 20px;\n background-color: rgba(0, 0, 0, 0.7);\n border-radius: 5px;\n color: #fff;\n }\n "; document.head.appendChild(style); // --- Oyun Değişkenleri ve Sabitleri --- var segmentLength = 10, startingSegments = 20, spawn = { x: 0, y: cnv.height / 2 }, snakeSpeed = 5, maxApples = 5, appleLife = 500, segmentsPerApple = 3, snakeWidth = 5, appleWidth = 5, cursorSize = 10, snakeColor = [100, 255, 100, 1], appleColor = [0, 255, 0, 1], cursorColor = [255, 255, 255, 1], cursorColorMod = [0, -255, -255, 0], // Kırmızıya doğru geçiş (beyazdan yeşile) targetColor = [0, 0, 255, 1], targetColorMod = [255, 0, -255, 0], // Maviden kırmızıya doğru geçiş scoreColor = [255, 255, 255, 1], // Beyaz cursorSpin = 0.075, snake, cursor, target, apples, score, gameState, deathMeans; // --- Yardımcı Fonksiyonlar --- function distance(p1, p2) { var dx = p2.x - p1.x; var dy = p2.y - p1.y; return Math.sqrt(dx * dx + dy * dy); } function lineIntersect(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) { var s1_x = p1_x - p0_x, s1_y = p1_y - p0_y, s2_x = p3_x - p2_x, s2_y = p3_y - p2_y, s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y), t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { return true; } return false; } // --- Segment Sınıfı (SGM) --- function SGM(angle, x, y) { this.x = x || 0; this.y = y || 0; this.angle = angle || 0; this.parent = null; } SGM.prototype.endX = function () { return this.x + Math.cos(this.angle) * segmentLength; }; SGM.prototype.endY = function () { return this.y + Math.sin(this.angle) * segmentLength; }; SGM.prototype.pointAt = function (x, y) { var dx = x - this.x, dy = y - this.y; this.angle = Math.atan2(dy, dx); }; SGM.prototype.target = function (x, y) { this.targetX = x; this.targetY = y; this.arrived = false; this.totalDist = distance({ x: this.endX(), y: this.endY() }, { x: this.targetX, y: this.targetY }); this.currentDist = parseInt(this.totalDist); }; SGM.prototype.gotoTarget = function () { if (!this.arrived) { // Hedefe ulaşıp ulaşmadığını kontrol ederken segmentLength değil, daha küçük bir tolerans kullan if (distance({ x: this.endX(), y: this.endY() }, { x: this.targetX, y: this.targetY }) > 1) { // 1 piksel tolerans this.pointAt(this.targetX, this.targetY); } else { this.arrived = true; } this.currentDist = distance({ x: this.endX(), y: this.endY() }, { x: this.targetX, y: this.targetY }); } // Hareketi daha yumuşak hale getirmek için mevcut pozisyona göre adım at this.x += (this.endX() - this.x) / snakeSpeed; this.y += (this.endY() - this.y) / snakeSpeed; // Parent segmentini sürükle if (this.parent) { this.parent.drag(this.x, this.y); } }; SGM.prototype.drag = function (x, y) { this.pointAt(x, y); this.x = x - Math.cos(this.angle) * segmentLength; this.y = y - Math.sin(this.angle) * segmentLength; if (this.parent) { this.parent.drag(this.x, this.y); } }; SGM.prototype.render = function (context) { context.lineTo(this.endX(), this.endY()); }; // --- Inverse Kinematics Rig Sınıfı (IKR) --- function IKR(x, y) { this.ix = x || 0; this.iy = y || 0; this.sgms = []; this.lastArm = null; } IKR.prototype.addSeg = function (angle) { var arm = new SGM(angle); if (this.lastArm !== null) { arm.x = this.lastArm.endX(); arm.y = this.lastArm.endY(); arm.parent = this.lastArm; } else { arm.x = this.ix; arm.y = this.iy; } this.sgms.push(arm); this.lastArm = arm; }; IKR.prototype.grow = function () { var tail = this.sgms[0], arm = new SGM(tail.angle); arm.x = tail.x - Math.cos(tail.angle) * segmentLength; arm.y = tail.y - Math.sin(tail.angle) * segmentLength; tail.parent = arm; // Yeni segmenti kuyruğun parent'ı yap this.sgms.unshift(arm); // Yeni segmenti dizinin başına ekle }; IKR.prototype.drag = function (x, y) { this.lastArm.drag(x, y); }; // --- Cursor Sınıfı (CUR) --- function CUR(x, y) { this.x = x; this.y = y; this.rotation = 0; } CUR.prototype.render = function (context) { context.save(); context.translate(this.x, this.y); context.rotate(this.rotation); context.beginPath(); context.moveTo(0, -cursorSize); context.lineTo(0, -cursorSize / 2); context.moveTo(0, cursorSize / 2); context.lineTo(0, cursorSize); context.moveTo(-cursorSize, 0); context.lineTo(-cursorSize / 2, 0); context.moveTo(cursorSize / 2, 0); context.lineTo(cursorSize, 0); context.stroke(); context.restore(); this.rotation = (this.rotation + cursorSpin) % (2 * Math.PI); // Açıları radyan cinsinden tut }; // --- Apple Sınıfı --- function Apple(x, y) { this.x = x; this.y = y; this.life = appleLife; this.rotation = 0; // Cursor'dan devralmak için ekledim } Apple.prototype.update = function () { this.life--; }; Apple.prototype.render = function (context) { context.beginPath(); context.arc(this.x, this.y, appleWidth, 0, Math.PI * 2); context.fill(); if (gameState !== 'dead') { context.save(); context.fillStyle = 'white'; context.font = '8px sans-serif'; context.fillText(this.life, this.x + 10, this.y + 10); context.restore(); CUR.prototype.render.call(this, context); // Elmanın etrafına imleç çiz } }; // --- Oyun Başlatma Fonksiyonu --- function init() { // Spawn noktasını canvas genişliğine göre güncelle spawn.x = 0; // Sol kenardan başlasın spawn.y = cnv.height / 2; // Ortadan başlasın snake = new IKR(spawn.x, spawn.y); cursor = new CUR(-20, -20); // Ekran dışına başla target = new CUR(spawn.x + segmentLength * (startingSegments + 5), spawn.y); // Yılanın biraz ilerisinde başla apples = []; score = 0; updateScoreBoard(); // Skorbordu sıfırla ve güncelle for (var i = 0; i < startingSegments; i++) { snake.addSeg(); } snake.lastArm.target(target.x, target.y); gameState = 'play'; } // --- Etkinlik Dinleyicileri --- cnv.addEventListener('mousemove', function (e) { if (gameState === 'play') { cursor.x = e.offsetX; cursor.y = e.offsetY; } }); cnv.addEventListener('mousedown', function (e) { switch (gameState) { case 'play': target.x = e.offsetX; target.y = e.offsetY; snake.lastArm.target(target.x, target.y); break; case 'dead': init(); // Oyunu yeniden başlat break; } }); // Dokunmatik olaylar için: var touchStartX = 0; var touchStartY = 0; cnv.addEventListener('touchstart', function (e) { e.preventDefault(); // Varsayılan kaydırma vb. engelle if (gameState === 'play' && e.touches.length > 0) { touchStartX = e.touches[0].clientX; touchStartY = e.touches[0].clientY; // Cursor'ı dokunulan yere ayarla (isteğe bağlı) cursor.x = e.touches[0].clientX - cnv.getBoundingClientRect().left; cursor.y = e.touches[0].clientY - cnv.getBoundingClientRect().top; } }); cnv.addEventListener('touchend', function (e) { e.preventDefault(); if (gameState === 'play' && e.changedTouches.length > 0) { var touchEndX = e.changedTouches[0].clientX; var touchEndY = e.changedTouches[0].clientY; // Canvas'ın pozisyonunu dikkate alarak hedefi ayarla var rect = cnv.getBoundingClientRect(); target.x = touchEndX - rect.left; target.y = touchEndY - rect.top; snake.lastArm.target(target.x, target.y); } else if (gameState === 'dead') { init(); // Dokunmayla yeniden başlat } }); // --- Oyun Mantığı Fonksiyonları --- function badPlacement(apple) { for (var s = 0; s < snake.sgms.length; s++) { var seg = snake.sgms[s]; if (distance(apple, { x: seg.endX(), y: seg.endY() }) < appleWidth * 2 || distance(apple, { x: seg.x, y: seg.y }) < appleWidth * 2) { return true; } } return false; } function addScoreSegments() { for (var i = 0; i < segmentsPerApple; i++) { snake.grow(); } } function updateScoreBoard() { scoreBoard.textContent = 'Puan: ' + score; } function update() { if (gameState !== 'dead') { snake.lastArm.gotoTarget(); // Duvar çarpışması if (snake.lastArm.endX() > cnv.width - snakeWidth / 2 || snake.lastArm.endX() < snakeWidth / 2 || snake.lastArm.endY() > cnv.height - snakeWidth / 2 || snake.lastArm.endY() < snakeWidth / 2) { gameState = 'dead'; deathMeans = 'Duvara çarptın!'; return; } // Kendini ısırma (son birkaç segmenti kontrol etme) for (var s = 0; s < snake.sgms.length - 4; s++) { // Son 4 segmenti kontrol dışında bırak var seg = snake.sgms[s]; if (lineIntersect(snake.lastArm.x, snake.lastArm.y, snake.lastArm.endX(), snake.lastArm.endY(), seg.x, seg.y, seg.endX(), seg.endY())) { gameState = 'dead'; deathMeans = 'Kendini ısırdın!'; return; } } // Elma kontrolü for (var i = apples.length - 1; i >= 0; i--) { // Ters döngü ile silme işlemi güvenli olur var apple = apples[i]; apple.update(); if (apple.life <= 0) { apples.splice(i, 1); continue; } // Yılanın başı elmayı yedi mi? if (distance(apple, { x: snake.lastArm.endX(), y: snake.lastArm.endY() }) < appleWidth + snakeWidth / 2) { score += apple.life; // Kalan ömrüne göre skor ver apples.splice(i, 1); addScoreSegments(); updateScoreBoard(); } else { // Yılanın kuyruğu veya gövdesi elmayı absorbe etti mi? for (var s = 0; s < snake.sgms.length; s++) { var seg = snake.sgms[s]; if (distance(apple, { x: seg.endX(), y: seg.endY() }) < appleWidth + snakeWidth / 2) { score += Math.round(apple.life / 2); // Yarım skor ver apples.splice(i, 1); addScoreSegments(); updateScoreBoard(); break; // Elma yendiği için bu elma için kontrolü bitir } } } } // Yeni elma oluşturma if (apples.length < maxApples && Math.random() < .05) { // Olasılığı biraz düşürdüm var offset = appleWidth * 10, apple = new Apple(offset / 2 + Math.floor(Math.random() * (cnv.width - offset)), offset / 2 + Math.floor(Math.random() * (cnv.height - offset))); while (badPlacement(apple)) { apple.x = offset / 2 + Math.floor(Math.random() * (cnv.width - offset)); apple.y = offset / 2 + Math.floor(Math.random() * (cnv.height - offset)); } apples.push(apple); } } } // --- Çizim Fonksiyonları --- function drawTarget(targetModFactor) { if (!snake.lastArm.arrived) { ctx.strokeStyle = 'rgba(' + (targetColor[0] + targetColorMod[0] * targetModFactor).toFixed(0) + ',' + (targetColor[1] + targetColorMod[1] * targetModFactor).toFixed(0) + ',' + (targetColor[2] + targetColorMod[2] * targetModFactor).toFixed(0) + ',' + (targetColor[3] + targetColorMod[3] * targetModFactor).toFixed(0) + ')'; ctx.lineWidth = 1; target.render(ctx); } } function drawSnake() { ctx.beginPath(); ctx.strokeStyle = ctx.fillStyle = 'rgba(' + snakeColor[0] + ',' + snakeColor[1] + ',' + snakeColor[2] + ',' + snakeColor[3] + ')'; ctx.lineWidth = snakeWidth; ctx.moveTo(snake.sgms[0].x, snake.sgms[0].y); for (var s in snake.sgms) { snake.sgms[s].render(ctx); } ctx.stroke(); ctx.beginPath(); ctx.arc(snake.lastArm.endX(), snake.lastArm.endY(), appleWidth * .75, 0, Math.PI * 2); ctx.fill(); } function drawCursor(targetModFactor) { ctx.strokeStyle = 'rgba(' + (cursorColor[0] + cursorColorMod[0] * targetModFactor).toFixed(0) + ',' + (cursorColor[1] + cursorColorMod[1] * targetModFactor).toFixed(0) + ',' + (cursorColor[2] + cursorColorMod[2] * targetModFactor).toFixed(0) + ',' + (cursorColor[3] + cursorColorMod[3] * targetModFactor).toFixed(0) + ')'; ctx.lineWidth = 1; cursor.render(ctx); } function drawApples() { ctx.fillStyle = 'rgba(' + appleColor[0] + ',' + appleColor[1] + ',' + appleColor[2] + ',' + appleColor[3] + ')'; for (var a in apples) { var apple = apples[a], appleTargetMod = 1 - apple.life / appleLife; ctx.strokeStyle = 'rgba(' + (cursorColor[0] + cursorColorMod[0] * appleTargetMod).toFixed(0) + ',' + (cursorColor[1] + cursorColorMod[1] * appleTargetMod).toFixed(0) + ',' + (cursorColor[2] + cursorColorMod[2] * appleTargetMod).toFixed(0) + ',' + (cursorColor[3] + cursorColorMod[3] * appleTargetMod).toFixed(0) + ')'; ctx.lineWidth = 1; apple.render(ctx); } } function render() { // snake.lastArm.totalDist henüz atanmamış olabilir, hata vermemesi için kontrol et var targetModFactor = snake.lastArm && snake.lastArm.totalDist ? 1 - snake.lastArm.currentDist / snake.lastArm.totalDist : 0; switch (gameState) { case 'play': ctx.clearRect(0, 0, cnv.width, cnv.height); drawTarget(targetModFactor); drawSnake(); drawApples(); drawCursor(targetModFactor); // Skor metni doğrudan canvas'a çizildiğinde, skorbord div'ini de güncel tutmak için // updateScoreBoard() çağrısı yapılabilir veya skorbord div'ini kaldırabiliriz. // Bu örnekte skorbord div'i zaten mevcut olduğu için onu kullandık. // ctx.fillStyle = 'rgba('+ // scoreColor[0] +','+ scoreColor[1] +','+ scoreColor[2] +','+ scoreColor[3] // +')'; // ctx.textAlign = 'left'; // ctx.textBaseline = 'top'; // ctx.fillText('Puan: '+score, 10, 10); break; case 'dead': ctx.clearRect(0, 0, cnv.width, cnv.height); drawSnake(); drawApples(); ctx.fillStyle = 'rgba(255,0,0,0.5)'; ctx.fillRect(100, 100, cnv.width - 200, cnv.height - 200); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = ctx.strokeStyle = 'white'; ctx.font = 'bold 30px sans-serif'; ctx.fillText('Öldün', cnv.width / 2, cnv.height / 2 - 70); ctx.font = 'bold 25px sans-serif'; ctx.fillText(deathMeans, cnv.width / 2, cnv.height / 2 - 30); ctx.font = '20px sans-serif'; ctx.fillText('Puan:', cnv.width / 2, cnv.height / 2 + 15); ctx.font = 'bold 60px sans-serif'; ctx.fillText(score, cnv.width / 2, cnv.height / 2 + 60); ctx.font = 'lighter 10px sans-serif'; ctx.lineWidth = 1; ctx.strokeRect(103, 103, cnv.width - 206, cnv.height - 206); break; } } // --- Animasyon Döngüsü --- function animate() { update(); render(); requestAnimationFrame(animate); } // Oyunu başlat init(); // Animasyonu başlat animate(); });
===================================================================
--- original.js
+++ change.js
@@ -1,215 +1,471 @@
/****
-* Classes
-****/
-// Bullet class
-var Bullet = Container.expand(function () {
- var self = Container.call(this);
- var bulletGraphics = self.attachAsset('bullet', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- self.speed = -12;
- self.update = function () {
- self.y += self.speed;
- };
- return self;
-});
-// Enemy class
-var Enemy = Container.expand(function () {
- var self = Container.call(this);
- var enemyGraphics = self.attachAsset('enemy', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- self.speed = 3;
- self.lastIntersecting = false;
- self.update = function () {
- self.y += self.speed;
- };
- return self;
-});
-// Powerup class
-var Powerup = Container.expand(function () {
- var self = Container.call(this);
- var powerupGraphics = self.attachAsset('powerup', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- self.speed = 2;
- self.rotationSpeed = 0.05;
- self.lastIntersecting = false;
- self.update = function () {
- self.y += self.speed;
- self.rotation += self.rotationSpeed;
- };
- return self;
-});
-
-/****
* Initialize Game
****/
-// Set background color
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Game variables
-// Initialize space shooter assets
-var spaceship;
-var dragNode = null;
-var bullets = [];
-var enemies = [];
-var powerups = [];
-var scoreTxt;
-// Set background color
-game.setBackgroundColor(0x001122);
-// Create spaceship
-spaceship = game.addChild(LK.getAsset('spaceship', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-spaceship.x = 2048 / 2;
-spaceship.y = 2732 - 200;
-// Create score display
-scoreTxt = new Text2('Score: 0', {
- size: 80,
- fill: 0xFFFFFF
-});
-scoreTxt.anchor.set(0.5, 0);
-LK.gui.top.addChild(scoreTxt);
-// Move handler
-function handleMove(x, y, obj) {
- if (dragNode) {
- dragNode.x = x;
- dragNode.y = y;
- // Keep spaceship within screen bounds
- if (dragNode.x < 40) dragNode.x = 40;
- if (dragNode.x > 2048 - 40) dragNode.x = 2048 - 40;
- if (dragNode.y < 40) dragNode.y = 40;
- if (dragNode.y > 2732 - 40) dragNode.y = 2732 - 40;
+document.addEventListener('DOMContentLoaded', function () {
+ // Canvas elementini ve konteksini dinamik olarak oluştur
+ var cnv = document.createElement('canvas');
+ cnv.id = 'gameCanvas';
+ document.body.appendChild(cnv); // Canvas'ı body'ye ekle
+ // Skorbord elementini dinamik olarak oluştur
+ var scoreBoard = document.createElement('div');
+ scoreBoard.id = 'scoreBoard'; // ScoreBoard'a ID ata
+ document.body.appendChild(scoreBoard);
+ var ctx = cnv.getContext('2d');
+ // Canvas boyutlarını belirle (oyunun original kodundaki gibi, responsive'i sen ekleyebilirsin)
+ cnv.width = 600; // Örnek bir genişlik
+ cnv.height = 600; // Örnek bir yükseklik
+ // Dinamik olarak CSS stilleri oluşturulup sayfaya ekleniyor
+ var style = document.createElement('style');
+ style.textContent = "\n body {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background-color: #333;\n overflow: hidden;\n font-family: monospace; /* Oyun koduna yak\u0131n bir font */\n color: #eee;\n }\n canvas {\n border: 2px solid #eee;\n background-color: #000;\n margin-bottom: 20px; /* Skorbord ile aras\u0131na bo\u015Fluk */\n }\n #scoreBoard {\n font-size: 1.5em;\n text-align: center;\n padding: 10px 20px;\n background-color: rgba(0, 0, 0, 0.7);\n border-radius: 5px;\n color: #fff;\n }\n ";
+ document.head.appendChild(style);
+ // --- Oyun Değişkenleri ve Sabitleri ---
+ var segmentLength = 10,
+ startingSegments = 20,
+ spawn = {
+ x: 0,
+ y: cnv.height / 2
+ },
+ snakeSpeed = 5,
+ maxApples = 5,
+ appleLife = 500,
+ segmentsPerApple = 3,
+ snakeWidth = 5,
+ appleWidth = 5,
+ cursorSize = 10,
+ snakeColor = [100, 255, 100, 1],
+ appleColor = [0, 255, 0, 1],
+ cursorColor = [255, 255, 255, 1],
+ cursorColorMod = [0, -255, -255, 0],
+ // Kırmızıya doğru geçiş (beyazdan yeşile)
+ targetColor = [0, 0, 255, 1],
+ targetColorMod = [255, 0, -255, 0],
+ // Maviden kırmızıya doğru geçiş
+ scoreColor = [255, 255, 255, 1],
+ // Beyaz
+ cursorSpin = 0.075,
+ snake,
+ cursor,
+ target,
+ apples,
+ score,
+ gameState,
+ deathMeans;
+ // --- Yardımcı Fonksiyonlar ---
+ function distance(p1, p2) {
+ var dx = p2.x - p1.x;
+ var dy = p2.y - p1.y;
+ return Math.sqrt(dx * dx + dy * dy);
}
-}
-// Game input handlers
-game.move = handleMove;
-game.down = function (x, y, obj) {
- dragNode = spaceship;
- handleMove(x, y, obj);
-};
-game.up = function (x, y, obj) {
- dragNode = null;
-};
-// Main game update loop
-game.update = function () {
- // Update bullets
- for (var i = bullets.length - 1; i >= 0; i--) {
- var bullet = bullets[i];
- // Track last Y position for off-screen detection
- if (bullet.lastY === undefined) bullet.lastY = bullet.y;
- // Remove bullets that go off screen
- if (bullet.lastY >= -50 && bullet.y < -50) {
- bullet.destroy();
- bullets.splice(i, 1);
- continue;
+ function lineIntersect(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) {
+ var s1_x = p1_x - p0_x,
+ s1_y = p1_y - p0_y,
+ s2_x = p3_x - p2_x,
+ s2_y = p3_y - p2_y,
+ s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y),
+ t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
+ if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
+ return true;
}
- bullet.lastY = bullet.y;
+ return false;
}
- // Update enemies
- for (var i = enemies.length - 1; i >= 0; i--) {
- var enemy = enemies[i];
- // Track last Y position for off-screen detection
- if (enemy.lastY === undefined) enemy.lastY = enemy.y;
- // Remove enemies that go off screen
- if (enemy.lastY <= 2732 + 50 && enemy.y > 2732 + 50) {
- enemy.destroy();
- enemies.splice(i, 1);
- continue;
+ // --- Segment Sınıfı (SGM) ---
+ function SGM(angle, x, y) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.angle = angle || 0;
+ this.parent = null;
+ }
+ SGM.prototype.endX = function () {
+ return this.x + Math.cos(this.angle) * segmentLength;
+ };
+ SGM.prototype.endY = function () {
+ return this.y + Math.sin(this.angle) * segmentLength;
+ };
+ SGM.prototype.pointAt = function (x, y) {
+ var dx = x - this.x,
+ dy = y - this.y;
+ this.angle = Math.atan2(dy, dx);
+ };
+ SGM.prototype.target = function (x, y) {
+ this.targetX = x;
+ this.targetY = y;
+ this.arrived = false;
+ this.totalDist = distance({
+ x: this.endX(),
+ y: this.endY()
+ }, {
+ x: this.targetX,
+ y: this.targetY
+ });
+ this.currentDist = parseInt(this.totalDist);
+ };
+ SGM.prototype.gotoTarget = function () {
+ if (!this.arrived) {
+ // Hedefe ulaşıp ulaşmadığını kontrol ederken segmentLength değil, daha küçük bir tolerans kullan
+ if (distance({
+ x: this.endX(),
+ y: this.endY()
+ }, {
+ x: this.targetX,
+ y: this.targetY
+ }) > 1) {
+ // 1 piksel tolerans
+ this.pointAt(this.targetX, this.targetY);
+ } else {
+ this.arrived = true;
+ }
+ this.currentDist = distance({
+ x: this.endX(),
+ y: this.endY()
+ }, {
+ x: this.targetX,
+ y: this.targetY
+ });
}
- // Check collision with spaceship
- if (enemy.intersects(spaceship)) {
- LK.effects.flashScreen(0xff0000, 1000);
- LK.showGameOver();
- return;
+ // Hareketi daha yumuşak hale getirmek için mevcut pozisyona göre adım at
+ this.x += (this.endX() - this.x) / snakeSpeed;
+ this.y += (this.endY() - this.y) / snakeSpeed;
+ // Parent segmentini sürükle
+ if (this.parent) {
+ this.parent.drag(this.x, this.y);
}
- // Check collision with bullets
- var hit = false;
- for (var j = bullets.length - 1; j >= 0; j--) {
- var bullet = bullets[j];
- if (enemy.intersects(bullet)) {
- // Destroy both enemy and bullet
- enemy.destroy();
- enemies.splice(i, 1);
- bullet.destroy();
- bullets.splice(j, 1);
- // Add score
- LK.setScore(LK.getScore() + 10);
- scoreTxt.setText('Score: ' + LK.getScore());
- // Play explosion sound
- LK.getSound('explosion').play();
- hit = true;
+ };
+ SGM.prototype.drag = function (x, y) {
+ this.pointAt(x, y);
+ this.x = x - Math.cos(this.angle) * segmentLength;
+ this.y = y - Math.sin(this.angle) * segmentLength;
+ if (this.parent) {
+ this.parent.drag(this.x, this.y);
+ }
+ };
+ SGM.prototype.render = function (context) {
+ context.lineTo(this.endX(), this.endY());
+ };
+ // --- Inverse Kinematics Rig Sınıfı (IKR) ---
+ function IKR(x, y) {
+ this.ix = x || 0;
+ this.iy = y || 0;
+ this.sgms = [];
+ this.lastArm = null;
+ }
+ IKR.prototype.addSeg = function (angle) {
+ var arm = new SGM(angle);
+ if (this.lastArm !== null) {
+ arm.x = this.lastArm.endX();
+ arm.y = this.lastArm.endY();
+ arm.parent = this.lastArm;
+ } else {
+ arm.x = this.ix;
+ arm.y = this.iy;
+ }
+ this.sgms.push(arm);
+ this.lastArm = arm;
+ };
+ IKR.prototype.grow = function () {
+ var tail = this.sgms[0],
+ arm = new SGM(tail.angle);
+ arm.x = tail.x - Math.cos(tail.angle) * segmentLength;
+ arm.y = tail.y - Math.sin(tail.angle) * segmentLength;
+ tail.parent = arm; // Yeni segmenti kuyruğun parent'ı yap
+ this.sgms.unshift(arm); // Yeni segmenti dizinin başına ekle
+ };
+ IKR.prototype.drag = function (x, y) {
+ this.lastArm.drag(x, y);
+ };
+ // --- Cursor Sınıfı (CUR) ---
+ function CUR(x, y) {
+ this.x = x;
+ this.y = y;
+ this.rotation = 0;
+ }
+ CUR.prototype.render = function (context) {
+ context.save();
+ context.translate(this.x, this.y);
+ context.rotate(this.rotation);
+ context.beginPath();
+ context.moveTo(0, -cursorSize);
+ context.lineTo(0, -cursorSize / 2);
+ context.moveTo(0, cursorSize / 2);
+ context.lineTo(0, cursorSize);
+ context.moveTo(-cursorSize, 0);
+ context.lineTo(-cursorSize / 2, 0);
+ context.moveTo(cursorSize / 2, 0);
+ context.lineTo(cursorSize, 0);
+ context.stroke();
+ context.restore();
+ this.rotation = (this.rotation + cursorSpin) % (2 * Math.PI); // Açıları radyan cinsinden tut
+ };
+ // --- Apple Sınıfı ---
+ function Apple(x, y) {
+ this.x = x;
+ this.y = y;
+ this.life = appleLife;
+ this.rotation = 0; // Cursor'dan devralmak için ekledim
+ }
+ Apple.prototype.update = function () {
+ this.life--;
+ };
+ Apple.prototype.render = function (context) {
+ context.beginPath();
+ context.arc(this.x, this.y, appleWidth, 0, Math.PI * 2);
+ context.fill();
+ if (gameState !== 'dead') {
+ context.save();
+ context.fillStyle = 'white';
+ context.font = '8px sans-serif';
+ context.fillText(this.life, this.x + 10, this.y + 10);
+ context.restore();
+ CUR.prototype.render.call(this, context); // Elmanın etrafına imleç çiz
+ }
+ };
+ // --- Oyun Başlatma Fonksiyonu ---
+ function init() {
+ // Spawn noktasını canvas genişliğine göre güncelle
+ spawn.x = 0; // Sol kenardan başlasın
+ spawn.y = cnv.height / 2; // Ortadan başlasın
+ snake = new IKR(spawn.x, spawn.y);
+ cursor = new CUR(-20, -20); // Ekran dışına başla
+ target = new CUR(spawn.x + segmentLength * (startingSegments + 5), spawn.y); // Yılanın biraz ilerisinde başla
+ apples = [];
+ score = 0;
+ updateScoreBoard(); // Skorbordu sıfırla ve güncelle
+ for (var i = 0; i < startingSegments; i++) {
+ snake.addSeg();
+ }
+ snake.lastArm.target(target.x, target.y);
+ gameState = 'play';
+ }
+ // --- Etkinlik Dinleyicileri ---
+ cnv.addEventListener('mousemove', function (e) {
+ if (gameState === 'play') {
+ cursor.x = e.offsetX;
+ cursor.y = e.offsetY;
+ }
+ });
+ cnv.addEventListener('mousedown', function (e) {
+ switch (gameState) {
+ case 'play':
+ target.x = e.offsetX;
+ target.y = e.offsetY;
+ snake.lastArm.target(target.x, target.y);
break;
+ case 'dead':
+ init(); // Oyunu yeniden başlat
+ break;
+ }
+ });
+ // Dokunmatik olaylar için:
+ var touchStartX = 0;
+ var touchStartY = 0;
+ cnv.addEventListener('touchstart', function (e) {
+ e.preventDefault(); // Varsayılan kaydırma vb. engelle
+ if (gameState === 'play' && e.touches.length > 0) {
+ touchStartX = e.touches[0].clientX;
+ touchStartY = e.touches[0].clientY;
+ // Cursor'ı dokunulan yere ayarla (isteğe bağlı)
+ cursor.x = e.touches[0].clientX - cnv.getBoundingClientRect().left;
+ cursor.y = e.touches[0].clientY - cnv.getBoundingClientRect().top;
+ }
+ });
+ cnv.addEventListener('touchend', function (e) {
+ e.preventDefault();
+ if (gameState === 'play' && e.changedTouches.length > 0) {
+ var touchEndX = e.changedTouches[0].clientX;
+ var touchEndY = e.changedTouches[0].clientY;
+ // Canvas'ın pozisyonunu dikkate alarak hedefi ayarla
+ var rect = cnv.getBoundingClientRect();
+ target.x = touchEndX - rect.left;
+ target.y = touchEndY - rect.top;
+ snake.lastArm.target(target.x, target.y);
+ } else if (gameState === 'dead') {
+ init(); // Dokunmayla yeniden başlat
+ }
+ });
+ // --- Oyun Mantığı Fonksiyonları ---
+ function badPlacement(apple) {
+ for (var s = 0; s < snake.sgms.length; s++) {
+ var seg = snake.sgms[s];
+ if (distance(apple, {
+ x: seg.endX(),
+ y: seg.endY()
+ }) < appleWidth * 2 || distance(apple, {
+ x: seg.x,
+ y: seg.y
+ }) < appleWidth * 2) {
+ return true;
}
}
- if (!hit) {
- enemy.lastY = enemy.y;
+ return false;
+ }
+ function addScoreSegments() {
+ for (var i = 0; i < segmentsPerApple; i++) {
+ snake.grow();
}
}
- // Update powerups
- for (var i = powerups.length - 1; i >= 0; i--) {
- var powerup = powerups[i];
- // Track last Y position for off-screen detection
- if (powerup.lastY === undefined) powerup.lastY = powerup.y;
- // Remove powerups that go off screen
- if (powerup.lastY <= 2732 + 50 && powerup.y > 2732 + 50) {
- powerup.destroy();
- powerups.splice(i, 1);
- continue;
+ function updateScoreBoard() {
+ scoreBoard.textContent = 'Puan: ' + score;
+ }
+ function update() {
+ if (gameState !== 'dead') {
+ snake.lastArm.gotoTarget();
+ // Duvar çarpışması
+ if (snake.lastArm.endX() > cnv.width - snakeWidth / 2 || snake.lastArm.endX() < snakeWidth / 2 || snake.lastArm.endY() > cnv.height - snakeWidth / 2 || snake.lastArm.endY() < snakeWidth / 2) {
+ gameState = 'dead';
+ deathMeans = 'Duvara çarptın!';
+ return;
+ }
+ // Kendini ısırma (son birkaç segmenti kontrol etme)
+ for (var s = 0; s < snake.sgms.length - 4; s++) {
+ // Son 4 segmenti kontrol dışında bırak
+ var seg = snake.sgms[s];
+ if (lineIntersect(snake.lastArm.x, snake.lastArm.y, snake.lastArm.endX(), snake.lastArm.endY(), seg.x, seg.y, seg.endX(), seg.endY())) {
+ gameState = 'dead';
+ deathMeans = 'Kendini ısırdın!';
+ return;
+ }
+ }
+ // Elma kontrolü
+ for (var i = apples.length - 1; i >= 0; i--) {
+ // Ters döngü ile silme işlemi güvenli olur
+ var apple = apples[i];
+ apple.update();
+ if (apple.life <= 0) {
+ apples.splice(i, 1);
+ continue;
+ }
+ // Yılanın başı elmayı yedi mi?
+ if (distance(apple, {
+ x: snake.lastArm.endX(),
+ y: snake.lastArm.endY()
+ }) < appleWidth + snakeWidth / 2) {
+ score += apple.life; // Kalan ömrüne göre skor ver
+ apples.splice(i, 1);
+ addScoreSegments();
+ updateScoreBoard();
+ } else {
+ // Yılanın kuyruğu veya gövdesi elmayı absorbe etti mi?
+ for (var s = 0; s < snake.sgms.length; s++) {
+ var seg = snake.sgms[s];
+ if (distance(apple, {
+ x: seg.endX(),
+ y: seg.endY()
+ }) < appleWidth + snakeWidth / 2) {
+ score += Math.round(apple.life / 2); // Yarım skor ver
+ apples.splice(i, 1);
+ addScoreSegments();
+ updateScoreBoard();
+ break; // Elma yendiği için bu elma için kontrolü bitir
+ }
+ }
+ }
+ }
+ // Yeni elma oluşturma
+ if (apples.length < maxApples && Math.random() < .05) {
+ // Olasılığı biraz düşürdüm
+ var offset = appleWidth * 10,
+ apple = new Apple(offset / 2 + Math.floor(Math.random() * (cnv.width - offset)), offset / 2 + Math.floor(Math.random() * (cnv.height - offset)));
+ while (badPlacement(apple)) {
+ apple.x = offset / 2 + Math.floor(Math.random() * (cnv.width - offset));
+ apple.y = offset / 2 + Math.floor(Math.random() * (cnv.height - offset));
+ }
+ apples.push(apple);
+ }
}
- // Check collision with spaceship
- if (powerup.intersects(spaceship)) {
- powerup.destroy();
- powerups.splice(i, 1);
- // Add bonus score
- LK.setScore(LK.getScore() + 50);
- scoreTxt.setText('Score: ' + LK.getScore());
- // Flash effect
- LK.effects.flashObject(spaceship, 0x00ffff, 500);
- continue;
+ }
+ // --- Çizim Fonksiyonları ---
+ function drawTarget(targetModFactor) {
+ if (!snake.lastArm.arrived) {
+ ctx.strokeStyle = 'rgba(' + (targetColor[0] + targetColorMod[0] * targetModFactor).toFixed(0) + ',' + (targetColor[1] + targetColorMod[1] * targetModFactor).toFixed(0) + ',' + (targetColor[2] + targetColorMod[2] * targetModFactor).toFixed(0) + ',' + (targetColor[3] + targetColorMod[3] * targetModFactor).toFixed(0) + ')';
+ ctx.lineWidth = 1;
+ target.render(ctx);
}
- powerup.lastY = powerup.y;
}
- // Spawn bullets every 15 frames
- if (LK.ticks % 15 === 0) {
- var newBullet = new Bullet();
- newBullet.x = spaceship.x;
- newBullet.y = spaceship.y - 40;
- newBullet.lastY = newBullet.y;
- bullets.push(newBullet);
- game.addChild(newBullet);
- LK.getSound('shoot').play();
+ function drawSnake() {
+ ctx.beginPath();
+ ctx.strokeStyle = ctx.fillStyle = 'rgba(' + snakeColor[0] + ',' + snakeColor[1] + ',' + snakeColor[2] + ',' + snakeColor[3] + ')';
+ ctx.lineWidth = snakeWidth;
+ ctx.moveTo(snake.sgms[0].x, snake.sgms[0].y);
+ for (var s in snake.sgms) {
+ snake.sgms[s].render(ctx);
+ }
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(snake.lastArm.endX(), snake.lastArm.endY(), appleWidth * .75, 0, Math.PI * 2);
+ ctx.fill();
}
- // Spawn enemies every 60 frames
- if (LK.ticks % 60 === 0) {
- var newEnemy = new Enemy();
- newEnemy.x = 60 + Math.random() * (2048 - 120);
- newEnemy.y = -60;
- newEnemy.lastY = newEnemy.y;
- enemies.push(newEnemy);
- game.addChild(newEnemy);
+ function drawCursor(targetModFactor) {
+ ctx.strokeStyle = 'rgba(' + (cursorColor[0] + cursorColorMod[0] * targetModFactor).toFixed(0) + ',' + (cursorColor[1] + cursorColorMod[1] * targetModFactor).toFixed(0) + ',' + (cursorColor[2] + cursorColorMod[2] * targetModFactor).toFixed(0) + ',' + (cursorColor[3] + cursorColorMod[3] * targetModFactor).toFixed(0) + ')';
+ ctx.lineWidth = 1;
+ cursor.render(ctx);
}
- // Spawn powerups every 300 frames
- if (LK.ticks % 300 === 0) {
- var newPowerup = new Powerup();
- newPowerup.x = 60 + Math.random() * (2048 - 120);
- newPowerup.y = -60;
- newPowerup.lastY = newPowerup.y;
- powerups.push(newPowerup);
- game.addChild(newPowerup);
+ function drawApples() {
+ ctx.fillStyle = 'rgba(' + appleColor[0] + ',' + appleColor[1] + ',' + appleColor[2] + ',' + appleColor[3] + ')';
+ for (var a in apples) {
+ var apple = apples[a],
+ appleTargetMod = 1 - apple.life / appleLife;
+ ctx.strokeStyle = 'rgba(' + (cursorColor[0] + cursorColorMod[0] * appleTargetMod).toFixed(0) + ',' + (cursorColor[1] + cursorColorMod[1] * appleTargetMod).toFixed(0) + ',' + (cursorColor[2] + cursorColorMod[2] * appleTargetMod).toFixed(0) + ',' + (cursorColor[3] + cursorColorMod[3] * appleTargetMod).toFixed(0) + ')';
+ ctx.lineWidth = 1;
+ apple.render(ctx);
+ }
}
- // Win condition
- if (LK.getScore() >= 500) {
- LK.showYouWin();
+ function render() {
+ // snake.lastArm.totalDist henüz atanmamış olabilir, hata vermemesi için kontrol et
+ var targetModFactor = snake.lastArm && snake.lastArm.totalDist ? 1 - snake.lastArm.currentDist / snake.lastArm.totalDist : 0;
+ switch (gameState) {
+ case 'play':
+ ctx.clearRect(0, 0, cnv.width, cnv.height);
+ drawTarget(targetModFactor);
+ drawSnake();
+ drawApples();
+ drawCursor(targetModFactor);
+ // Skor metni doğrudan canvas'a çizildiğinde, skorbord div'ini de güncel tutmak için
+ // updateScoreBoard() çağrısı yapılabilir veya skorbord div'ini kaldırabiliriz.
+ // Bu örnekte skorbord div'i zaten mevcut olduğu için onu kullandık.
+ // ctx.fillStyle = 'rgba('+
+ // scoreColor[0] +','+ scoreColor[1] +','+ scoreColor[2] +','+ scoreColor[3]
+ // +')';
+ // ctx.textAlign = 'left';
+ // ctx.textBaseline = 'top';
+ // ctx.fillText('Puan: '+score, 10, 10);
+ break;
+ case 'dead':
+ ctx.clearRect(0, 0, cnv.width, cnv.height);
+ drawSnake();
+ drawApples();
+ ctx.fillStyle = 'rgba(255,0,0,0.5)';
+ ctx.fillRect(100, 100, cnv.width - 200, cnv.height - 200);
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillStyle = ctx.strokeStyle = 'white';
+ ctx.font = 'bold 30px sans-serif';
+ ctx.fillText('Öldün', cnv.width / 2, cnv.height / 2 - 70);
+ ctx.font = 'bold 25px sans-serif';
+ ctx.fillText(deathMeans, cnv.width / 2, cnv.height / 2 - 30);
+ ctx.font = '20px sans-serif';
+ ctx.fillText('Puan:', cnv.width / 2, cnv.height / 2 + 15);
+ ctx.font = 'bold 60px sans-serif';
+ ctx.fillText(score, cnv.width / 2, cnv.height / 2 + 60);
+ ctx.font = 'lighter 10px sans-serif';
+ ctx.lineWidth = 1;
+ ctx.strokeRect(103, 103, cnv.width - 206, cnv.height - 206);
+ break;
+ }
}
-};
\ No newline at end of file
+ // --- Animasyon Döngüsü ---
+ function animate() {
+ update();
+ render();
+ requestAnimationFrame(animate);
+ }
+ // Oyunu başlat
+ init();
+ // Animasyonu başlat
+ animate();
+});
\ No newline at end of file