User prompt
1) Re-anchor your gun sprites at the butt In your asset init (or per-attach), make the gun’s anchorX sit at the butt end of the texture: js Kopyala Düzenle // ↓ in your init section, override the old anchorX/Y LK.init.image('playerGun', { width: 60, height: 15, id: '...', anchorX: 0, // 0 = left edge of the sprite (the butt) anchorY: 0.5, // vertically centered }); LK.init.image('enemyGun', { width: 60, height: 18, id: '...', anchorX: 0, // again: butt at left edge anchorY: 0.5, }); If you prefer to override it only when you attach: js Kopyala Düzenle // Player class var gun = self.attachAsset('playerGun',{ anchorX: 0, anchorY: 0.5, x: rarm.x + 5, // tweak as needed y: rarm.y + 3, rotation: 0 }); // Enemy class var gun = self.attachAsset('enemyGun',{ anchorX: 0, anchorY: 0.5, x: rarm.x + 4, y: rarm.y + 2, rotation: 0 }); 2) Keep your recoil tween exactly the same Because the pivot is now at the butt, your existing recoil code... js Kopyala Düzenle // recoil constants var RECOIL_ANGLE = 0.4; // bigger tip var RECOIL_TIME = 200; // 0.2s total // in playerFire (and enemyFire) var baseRot = player.gun.rotation; tween(player.gun, { rotation: baseRot - RECOIL_ANGLE }, { duration: RECOIL_TIME/2, easing: tween.cubicOut, onFinish(){ tween(player.gun, { rotation: baseRot },{ duration: RECOIL_TIME/2, easing: tween.cubicIn }); } });
User prompt
Just bump those two constants at the top of your file: js Kopyala Düzenle // === GUN RECOIL CONSTANTS === // was 0.3 / 500ms var RECOIL_ANGLE = 0.4; // tip the barrel a little farther (≈23° instead of 17°) var RECOIL_TIME = 200; // total recoil lasts 0.2s instead of 0.5s Because all of your recoil tweens are driven off those: js Kopyala Düzenle // e.g. in playerFire: tween(player.gun, { rotation: baseRot - RECOIL_ANGLE }, { duration: RECOIL_TIME/2, // now 100ms ... onFinish() { tween(player.gun, { rotation: baseRot }, { duration: RECOIL_TIME/2 // now 100ms back }); } }); ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
To get rid of the heavy arm “kick” and do a quick little gun-only recoil, you can: Remove the tween on player.rarm (and enemy.rarm) in your fire functions. Only tween the gun’s rotation up by a tiny amount, then back to its original angle over 0.5 s. Here’s how you can change both playerFire and enemyFire: js Kopyala Düzenle // at top of your file, define recoil parameters: const RECOIL_ANGLE = 0.3; // how far the barrel tips up (radians) const RECOIL_TIME = 500; // total time in ms // ... inside playerFire(x,y) just after you play gunshot: { // capture the gun’s base rotation: const baseRot = player.gun.rotation; // tween up half-time: tween(player.gun, { rotation: baseRot - RECOIL_ANGLE }, { duration: RECOIL_TIME / 2, easing: tween.cubicOut, onFinish() { // tween back down the other half: tween(player.gun, { rotation: baseRot }, { duration: RECOIL_TIME / 2, easing: tween.cubicIn }); } }); // ...and remove any tween(player.rarm,...) } js Kopyala Düzenle // ...and in enemyFire(), do the same for enemy.gun: { const baseRotE = enemy.gun.rotation; tween(enemy.gun, { rotation: baseRotE + RECOIL_ANGLE }, { duration: RECOIL_TIME / 2, easing: tween.cubicOut, onFinish() { tween(enemy.gun, { rotation: baseRotE }, { duration: RECOIL_TIME / 2, easing: tween.cubicIn }); } }); // remove any tween(enemy.rarm,...) } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
1) Ragdoll’dan silahı çıkar Düşman ve oyuncu sınıflarında self.bodyParts tanımını şu şekilde güncelle: js Kopyala Düzenle // Enemy class’in en başında // eskisi: // self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; // yenisi: self.bodyParts = [body, head, larm, rarm, lleg, rleg]; // → gun’ı çıkardık // aynı şekilde Player class’te // eskisi: // self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; // yenisi: self.bodyParts = [body, head, larm, rarm, lleg, rleg]; Böylece enemy.ragdoll() veya player.ragdoll() çağrıldığında silah parçaları etkilenmeyecek, sadece “vücut” parçaları uçuşacak. 2) Sonuç durumunda hiçbir şeyi hareket ettirme Özellikle “sonuç” (STATE_RESULT) durumundayken hem update loop’un hem de input handler’ların silahı tekrar pozisyonlandırmasına veya ragdoll’ı tetiklemesine engel ol. game.update, game.down, game.move, game.up ve stopMusicAndDraw fonksiyonlarına başa şu satırı ekle: js Kopyala Düzenle // örneğin game.update’in en başında: game.update = function(dt) { if (duelState === STATE_RESULT) return; // ...geri kalanı... }; // aynı guard’ı input handler’lara da koy: game.down = function(x,y,obj){ if (duelState === STATE_RESULT) return; // ... }; game.move = function(x,y,obj){ if (duelState === STATE_RESULT) return; // ... }; game.up = function(x,y,obj){ if (duelState === STATE_RESULT) return; // ... }; // ve eğer stopMusicAndDraw çağrısı sonuçtan sonra gelebiliyorsa: function stopMusicAndDraw(){ if (duelState !== STATE_WAIT) return; // ...eski stopMusicAndDraw kodu... } Bu sayede: Ragdoll fırlatmaları silaha dokunmaz. STATE_RESULT başladıktan sonra ne tween’lar ne input’lar ne de callback’ler silahı yerinden oynatabilir.
User prompt
Olay şu ki, “sonuç” durumuna (STATE_RESULT) geçtiğimizde hâlâ elimizdeki tüm zamanlayıcılar, animasyonlar ve input handler’lar çalışmaya devam ediyor. Bu yüzden silah bir anda “elle” geliyor, gidiyor veya “stopMusicAndDraw” gibi callback’ler tetikleniyor. En sağlam çözüm: STATE_RESULT sırasında hiçbir input ve animasyonu çalıştırma game.down, game.move, game.up içinde en başa: js Kopyala Düzenle if (duelState === STATE_RESULT) return; pointGunAt ve aimEnemyGunAt fonksiyonlarının başına da aynı guard’ı koyabilirsiniz: js Kopyala Düzenle function pointGunAt(x,y) { if (duelState === STATE_RESULT) return; // ...eski kod... } game.update’in en başına: js Kopyala Düzenle if (duelState === STATE_RESULT) { // İstersen statusTxt vs. burada gösterilmeye devam edebilir, // ama silah/karakter hareketi vb. tamamen dursun: return; } Bekleyen tüm zamanlayıcıları temizle — Sonuç belli olur belli olmaz, holster hold timer’ı (“musicTimeout”), draw timer’ı (“duelTimer”) ve result timer’ı (“resultTimeout”) mutlaka iptal edilmeli: js Kopyala Düzenle function endRound(win) { // ...mevcut kod... // Tam sonuç anında: cancelHold(); // musicTimeout’u iptal eder if (duelTimer) { LK.clearTimeout(duelTimer); duelTimer = null; } if (drawTimeout) { LK.clearTimeout(drawTimeout); drawTimeout = null; } if (resultTimeout) { LK.clearTimeout(resultTimeout); resultTimeout = null; } duelState = STATE_RESULT; // ...sonrası ragdoll/text vs... } “stopMusicAndDraw” callback’i de guard’lamalı Holster’ı tutup bırakınca planlanmış olan “stopMusicAndDraw” callback’i, eğer o sırada zaten sonuç (STATE_RESULT) mapasında isek devreye girmesin: js Kopyala Düzenle function stopMusicAndDraw() { if (duelState !== STATE_WAIT) return; // eğer bekleme aşamasında değilsek LK.stopMusic(); // ...geri kalan draw başlangıcı... }
Code edit (1 edits merged)
Please save this source code
User prompt
1. Gun pivot’unu doğru yere kaydırmak Şu anda silahın anchorX/Y’si 0.5,0.5 (ortada). Bunu, “tetiğin” tam gövdeye yakın ucuna sabitlemeliyiz. Örneğin: js Kopyala Düzenle // Player sınıfında: var gun = self.attachAsset('playerGun', { anchorX: 0.2, // tavsiye edilen değer (tetiğe yakın tarafa kaydır) anchorY: 0.8, // tüfeğin namlu ucundan değil, sapına yakın olsun x: rarm.x, y: rarm.y, rotation: 0 }); Benzer şekilde Enemy sınıfında da: js Kopyala Düzenle var gun = self.attachAsset('enemyGun', { anchorX: 0.2, anchorY: 0.8, x: rarm.x, y: rarm.y, rotation: 0 }); Bu değişiklikten sonra gun.x ve gun.y zaten kol pivot’nuz (rarm.x, rarm.y) ile eşleşiyor; dolayısıyla silah sapı doğrudan elin ortasına yerleşmiş oluyor. 2. Offset’leri ufak tweaks ile ince ayarlamak Pivot’u taşıdığımızda görsel olarak hâlâ biraz kayma olabilir. Bu durumda x ve y başlangıç değerlerinize birkaç piksel ekleyip çıkararak elin tam ucuna denk getirebilirsiniz: js Kopyala Düzenle // Player: var gun = self.attachAsset('playerGun', { anchorX: 0.2, anchorY: 0.8, x: rarm.x + 5, // 5px sağa kaydır y: rarm.y + 3, // 3px alta kaydır rotation: 0 }); // Enemy: var gun = self.attachAsset('enemyGun', { anchorX: 0.2, anchorY: 0.8, x: rarm.x + 4, y: rarm.y + 2, rotation: 0 }); 3. Dinamik yönlendirme fonksiyonunda da offset’i uygulamak Eğer silahı pointGunAt() içinde yeniden konumlandırıyorsanız, orada da aynı 5px/3px gibi offset’i ekleyin: js Kopyala Düzenle function pointGunAt(globalX, globalY) { // ...hesaplar... player.gun.x = player.rarm.x - Math.sin(armRot)*L + 5; // +5 piksel x-offset player.gun.y = player.rarm.y + Math.cos(armRot)*L + 3; // +3 piksel y-offset player.gun.rotation = ang; } Aynı işi aimEnemyGunAt() içinde de yapın.
User prompt
Görünüşe göre resetPose metodu, Round 1’den sonra karakterin pozlarını tam başta olduğu gibi sıfırlamıyor; özellikle kafanın Y konumu eski değerini koruyor ve her round’da giderek yukarı kayıyor. Bunu düzeltmek için resetPose’un içinde kafanın (ve diğer parçaların) başlangıç “offset” değerlerini doğrudan sabit olarak tanımlamalısın. Şöyle yapabiliriz: js Kopyala Düzenle // Player.resetPose içinde... self.resetPose = function() { // ...body reset... body.x = -12; body.y = 10; body.rotation = 0; // HEAD’i mutlaka en son değil ama doğru değerlerle resetle head.x = 0; head.y = -body.height/2 - 45; // ← burayı sabit tut head.rotation = 0; // kol, bacak, silah vb. de aynı şekilde sabit değerler almalı // ... }; js Kopyala Düzenle // Enemy.resetPose içinde... self.resetPose = function() { // ...body reset... body.x = 10; body.y = -15; body.rotation = 0; // HEAD reset head.x = 0; head.y = -body.height/2 - 45; // ← burayı sabit tut head.rotation = 0; // kollar, bacaklar, hipGun vs... // ... };
Code edit (1 edits merged)
Please save this source code
User prompt
move enemy hipgun 10 pixels left further
User prompt
move enemy hipgun location 3 pixels down further aand move it 5 pixels left further
User prompt
move enemy hipgun location 10 pixels down further and move 10 pixels left further
User prompt
move enemy hipgun location 15 pixels down further
User prompt
move enemy pocketed gun 15 pixels down further
User prompt
move enemy's pocketed gun 15 pixels down 10 pixels left
User prompt
player’s holster 20px to the left and 30px down, and moved the enemy’s pocketed gun 5px left and 10px down
User prompt
move player left arm 15 pixels down 3 pixels right
User prompt
move player arm 15 pixels down
User prompt
move player left leg 10 pixels right
User prompt
move it 6 pixels down further and move it 5 pixels left
User prompt
move it 15 pixels down further
User prompt
move it more 30 pixels
User prompt
move it 30 pixels down
User prompt
make bottomthing player a child of player then move it 20 pixels down
User prompt
move bottomthingenemy 10 pixels up
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0; self.dirX = 0; self.dirY = 0; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Attach enemybottomthing as a child of enemy var enemybottomthing = self.attachAsset('bottomthingenemy', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 80 // moved 10px up from previous (90 -> 80) }); // Legs var lleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: -140 / 4 + 5 - 5, // moved 5px left // use width of enemyBody (140) since body not yet defined y: 180 / 2 - 15 - 3 // use height of enemyBody (180) }); var rleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: 140 / 4 + 5 - 5, // moved 5px left y: 180 / 2 - 15 - 3 }); // Left Arm var larm = self.attachAsset('enemyArm', { anchorX: 0.5, anchorY: 0, x: -140 / 2 + 5 + 10, // use width of enemyBody (140) since body not yet defined // 10px right // 5px closer to body, 10px right y: -80 //{t} // 30px up (10px further down) }); // Body var body = self.attachAsset('enemyBody', { anchorX: 0.5, anchorY: 0.5, x: 10, y: -15 //{h} // 5px daha aşağı, 10px sağa taşındı }); // Head var head = self.attachAsset('enemyHead', { anchorX: 0.5, anchorY: 0.5, x: -4 + 5 - 4, // 4px left from previous // 5px right, 4px left y: -body.height / 2 - 45 - 4 - 5 - 4 // 4px up from previous }); // Right Arm (gun hand) var rarm = self.attachAsset('enemyArm', { anchorX: 0.5, anchorY: 0, x: body.width / 2 - 5, // 5px closer to body y: -80 //{z} // 30px up (10px further down) }); // Legs var lleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: -body.width / 4 + 5 - 5 + 3, // moved 5px left, now 3px right y: body.height / 2 - 15 - 3 //{z} // 3px up }); var rleg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: body.width / 4 + 5 - 5 + 3, // moved 5px left, now 3px right y: body.height / 2 - 15 - 3 //{E} // 3px up }); // Gun (in hand) var gun = self.attachAsset('enemyGun', { anchorX: 0.2, // tetiğe yakın pivot anchorY: -0.4, // sapına yakın pivot x: rarm.x + 15, // 4px sağa kaydır y: rarm.y + 15, // 2px alta kaydır rotation: 0 }); // Holster gun (on hip, always visible unless drawn) var hipGun = self.attachAsset('enemyGun', { anchorX: 0.5, anchorY: 0.5, x: body.width / 2 + 8 - 10 - 5 - 10, // 5px further left // 10px further left, 5px more left, 10px more left y: body.height / 2 - 22 + 15 + 10 + 3, // 3px further down // 10px further down, 3px more down rotation: Math.PI / 2 }); // Start with gun in holster, hand empty gun.visible = false; hipGun.visible = true; // Helper methods to switch gun/holster visibility self.toHolster = function () { hipGun.visible = true; gun.visible = false; }; self.toHand = function () { hipGun.visible = false; gun.visible = true; }; self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; self.gun = gun; self.rarm = rarm; self.head = head; self.body = body; self.ragdoll = function (hitX, hitY) { for (var i = 0; i < self.bodyParts.length; i++) { var part = self.bodyParts[i]; tween(part, { rotation: (Math.random() - 0.5) * 2.5, x: part.x + (Math.random() - 0.5) * 200, y: part.y + (Math.random() - 0.5) * 200 }, { duration: 600, delay: i * 30, easing: tween.elasticOut }); } }; self.resetPose = function () { // Body body.x = 10; body.y = -15; body.rotation = 0; // Head (use constant offset, not accumulated) head.x = 0; head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi head.rotation = 0; // Left Arm larm.x = -body.width / 2 + 5 + 10; larm.y = -80; larm.rotation = 0; // Right Arm rarm.x = body.width / 2 - 5; rarm.y = -80; rarm.rotation = 0; // Left Leg lleg.x = -body.width / 4 + 5 - 5 + 3; lleg.y = body.height / 2 - 15 - 3; lleg.rotation = 0; // Right Leg rleg.x = body.width / 4 + 5 - 5 + 3; rleg.y = body.height / 2 - 15 - 3; rleg.rotation = 0; // Gun (in hand) gun.x = rarm.x + 4; // 4px sağa kaydır gun.y = rarm.y + 2; // 2px alta kaydır gun.rotation = 0; // Hip gun (holster) if (typeof hipGun !== "undefined") { hipGun.x = body.width / 2 + 8 - 10 - 5 - 10; hipGun.y = body.height / 2 - 22 + 15 + 10 + 3; hipGun.rotation = Math.PI / 2; } self.toHolster(); // always start with gun in holster }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); // Head var head = self.attachAsset('playerHead', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -160 / 2 - 45 - 20 // use playerBody height (160) since body not yet defined, moved 25px up }); // Body var body = self.attachAsset('playerBody', { anchorX: 0.5, anchorY: 0.5, x: -12, y: 10 //{1U} // moved 15px down, 5px left from previous }); // bottomthingplayer as child of player, 75px down (moved 15px further down) var bottomthingplayer = self.attachAsset('bottomthingplayer', { anchorX: 0.5, anchorY: 0.5, x: -5, //{21} // moved 5px left y: 101 // moved 6px further down (95+6) }); // Left Arm var larm = self.attachAsset('playerArm', { anchorX: 0.5, anchorY: 0, x: -body.width / 2 - 10 - 5 + 5 + 7 + 3, // move 3px right // move 5px right, 7px more right, 3px more right y: -100 + 10 + 10 + 15, // move 15px down // move 10px down, 15px more down zIndex: -1 // ensure arm is behind body (if zIndex is supported) }); // Move left arm behind body in display list if (typeof self.setChildIndex === "function") { self.setChildIndex(larm, 0); } // Right Arm (gun hand) var rarm = self.attachAsset('playerArm', { anchorX: 0.5, anchorY: 0, x: body.width / 2 + 10 - 5 - 20 - 5 - 10, // 10px more left y: -100 + 10 + 15 + 10 //{1Y} // 10px more down, 15px more down, 10px more down }); // Legs var lleg = self.attachAsset('playerLeg', { anchorX: 0.5, anchorY: 0, x: -body.width / 4 - 10 + 3 + 10, // moved 10px right // move 3px right (total 6px closer) // 10px left, 3px right, 10px right y: body.height / 2 - 10 + 10 // 10px down }); var rleg = self.attachAsset('playerLeg', { anchorX: 0.5, anchorY: 0, x: body.width / 4 - 10 - 3, // move 3px left (total 6px closer) // 10px left, 3px left y: body.height / 2 - 10 + 10 // 10px down }); // Gun (in hand) var gun = self.attachAsset('playerGun', { anchorX: 0.3, // tetiğe yakın pivot anchorY: 1.2, // sapına yakın pivot x: rarm.x + 5, // 5px sağa kaydır y: rarm.y + 3, // 3px alta kaydır rotation: 0 }); // Holster gun (on hip, always visible unless drawn) var hipGun = self.attachAsset('playerGun', { anchorX: 0.5, anchorY: 0.5, x: body.width / 2 + -28, y: body.height / 2 - -12, rotation: Math.PI / 2 }); // Start with gun in holster, hand empty gun.visible = false; hipGun.visible = true; // Helper methods to switch gun/holster visibility self.toHolster = function () { hipGun.visible = true; gun.visible = false; }; self.toHand = function () { hipGun.visible = false; gun.visible = true; }; // Used for ragdoll effect self.bodyParts = [body, head, larm, rarm, lleg, rleg, gun]; // Used for aiming self.gun = gun; self.rarm = rarm; // Used for hit detection self.head = head; self.body = body; // Used for ragdoll self.ragdoll = function (hitX, hitY) { // Animate all parts to random positions/rotations for (var i = 0; i < self.bodyParts.length; i++) { var part = self.bodyParts[i]; tween(part, { rotation: (Math.random() - 0.5) * 2.5, x: part.x + (Math.random() - 0.5) * 200, y: part.y + (Math.random() - 0.5) * 200 }, { duration: 600, delay: i * 30, easing: tween.elasticOut }); } }; // Reset pose self.resetPose = function () { // Body body.x = -12; body.y = 10; body.rotation = 0; // Head (use constant offset, not accumulated) head.x = 0; head.y = -body.height / 2 - 45; // SABİT offset, yukarı kayma engellendi head.rotation = 0; // Left Arm larm.x = -body.width / 2 - 10 - 5 + 5 + 7 + 3; larm.y = -100 + 10 + 10 + 15; larm.rotation = 0; // Move left arm behind body in display list if (typeof self.setChildIndex === "function") { self.setChildIndex(larm, 0); } // Right Arm rarm.x = body.width / 2 + 10 - 5 - 20 - 5 - 10; rarm.y = -100 + 10 + 15 + 10; rarm.rotation = 0; // Left Leg lleg.x = -body.width / 4 - 10 + 3 + 10; lleg.y = body.height / 2 - 10 + 10; lleg.rotation = 0; // Right Leg rleg.x = body.width / 4 - 10 - 3; rleg.y = body.height / 2 - 10 + 10; rleg.rotation = 0; // Gun (in hand) gun.x = rarm.x + 5; // 5px sağa kaydır gun.y = rarm.y + 3; // 3px alta kaydır gun.rotation = 0; // Move bottomthingplayer 6px further down and 5px left if (typeof bottomthingplayer !== "undefined") { bottomthingplayer.x = -5; bottomthingplayer.y = 101; } self.toHolster(); // always start with gun in holster }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2e1a09 }); /**** * Game Code ****/ // Player and enemy bodies (torso, head, arms, legs) as simple shapes // Game state var STATE_WAIT = 0; var STATE_DRAW = 1; var STATE_SHOT = 2; var STATE_RESULT = 3; var duelState = STATE_WAIT; var canShoot = false; var playerShot = false; var enemyShot = false; var playerBullet = null; var enemyBullet = null; var duelTimer = null; var drawTimeout = null; var resultTimeout = null; var duelStartTime = 0; var playerShotTime = 0; var enemyShotTime = 0; var aimX = 0; var aimY = 0; var aimRadius = 180; var aimAngle = 0; var aimSpeed = 0.018; // %30 daha yavaş var aimDir = 1; var aimActive = false; var playerScore = 0; var roundNum = 1; var maxRounds = 5; // === GLOBAL SHOT COUNTERS === var playerShotsFiredCnt = 0; var enemyShotsFiredCnt = 0; // === PLAYER SHOT COOLDOWN === var playerShotCooldown = 0; // ms left until next shot allowed var enemyData = [{ name: "Greenhorn", minReact: 3.0, maxReact: 3.4, coneStart: 42, coneEnd: 0 }, { name: "Billy the Kid", minReact: 2.4, maxReact: 2.7, coneStart: 36, coneEnd: 0 }, { name: "Doc Holliday", minReact: 1.6, maxReact: 1.9, coneStart: 30, coneEnd: 0 }, { name: "Calamity Jane", minReact: 1.0, maxReact: 1.3, coneStart: 24, coneEnd: 0 }, { name: "The Undertaker", minReact: 0.6, maxReact: 0.8, coneStart: 18, coneEnd: 0, scale: 1.5 }]; var currentEnemy = null; // ==== FIX #1 : SAHNENİN BAŞINDA ==== var world = new Container(); game.addChild(world); // Add arkaplan background image centered in the screen var arkaplan = LK.getAsset('arkaplan', { anchorX: 0.5, anchorY: 0.5 }); arkaplan.x = 2048 / 2; arkaplan.y = 2732 / 2; world.addChild(arkaplan); // Player and enemy var player = new Player(); var enemy = new Enemy(); world.addChild(player); world.addChild(enemy); // Center positions var centerX = 2048 / 2; var playerY = 2732 * 0.7; var enemyY = 2732 * 0.3; // 6-bullet UI for player and enemy var playerAmmoUI = []; var enemyAmmoUI = []; function setupAmmoUI() { // Remove old UI if any for (var i = 0; i < playerAmmoUI.length; i++) { if (playerAmmoUI[i].parent) { playerAmmoUI[i].parent.removeChild(playerAmmoUI[i]); } } for (var i = 0; i < enemyAmmoUI.length; i++) { if (enemyAmmoUI[i].parent) { enemyAmmoUI[i].parent.removeChild(enemyAmmoUI[i]); } } playerAmmoUI = []; enemyAmmoUI = []; for (var i = 0; i < 6; i++) { var px = player.x - 120 + i * 40; var ex = enemy.x - 120 + i * 40; var bulletP = LK.getAsset('bullet', { scaleX: 0.6, scaleY: 0.6, anchorX: 0.5, anchorY: 0.5 }); var bulletE = LK.getAsset('bullet', { scaleX: 0.6, scaleY: 0.6, anchorX: 0.5, anchorY: 0.5 }); bulletP.y = player.y + 250 + 60; // Düşman: yalnızca 5. raundda 75 px yukarı var enemyExtraY = roundNum === 5 ? -75 : 0; bulletE.y = enemy.y - 250 + enemyExtraY; bulletP.x = px; bulletE.x = ex; // HUD’u world içine koy ki zoom animasyonuyla birlikte büyüsün world.addChild(bulletP); world.addChild(bulletE); playerAmmoUI.push(bulletP); enemyAmmoUI.push(bulletE); } } // Position player and enemy player.x = centerX - 500; player.y = playerY; enemy.x = centerX + 500; enemy.y = enemyY; // Score text var scoreTxt = new Text2('Score: 0', { size: 90, fill: 0xFFF7D6 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Round text var roundTxt = new Text2('', { size: 70, fill: 0xFFE4B5 }); roundTxt.anchor.set(0.5, 0); LK.gui.top.addChild(roundTxt); roundTxt.y = 110; // Duel status text var statusTxt = new Text2('', { size: 110, fill: 0xFFECB3 }); statusTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(statusTxt); // (Aim reticle removed) // Helper: reset all state for a new round function resetDuel() { duelState = STATE_WAIT; canShoot = false; playerShot = false; enemyShot = false; playerBullet = null; enemyBullet = null; duelStartTime = 0; playerShotTime = 0; enemyShotTime = 0; aimAngle = Math.random() * Math.PI * 2; aimDir = Math.random() > 0.5 ? 1 : -1; aimActive = false; // (aimReticle removed) player.resetPose(); enemy.resetPose(); player.toHolster(); enemy.toHolster(); holsterFull.visible = true; holsterEmpty.visible = false; setupAmmoUI(); // === RESET SHOT COUNTERS === playerShotsFiredCnt = 0; enemyShotsFiredCnt = 0; // === RESET HOLSTER FLAGS === playerReady = false; // yeni ← round’a nötr gir holdingHolster = false; // yeni holsterHoldTime = 0; // güvenlik duelStarted = false; // <-- YENİ: her raunda nötr gir cancelHold(); // 1. raunddan kalma musicTimeout varsa temizle zoomFinished = false; // yeni animasyona hazırlan var roundMusic = roundNum === 1 ? 'duelmusic' : roundNum === 2 ? 'round2music' : roundNum === 3 ? 'round3music' : roundNum === 4 ? 'round4music' : 'round5music'; startZoomIn(roundMusic); statusTxt.setText("Wait for the music..."); statusTxt.visible = true; // Set up enemy for this round currentEnemy = enemyData[roundNum - 1]; roundTxt.setText("Round " + roundNum + ": " + currentEnemy.name); // Boss scale (if any) enemy.scaleX = enemy.scaleY = currentEnemy.scale || 1; // Play duel music // (music now only plays during zoom-in, do not play here) // drawTimeout is now set after zoom-in, not here if (drawTimeout) { LK.clearTimeout(drawTimeout); } } // Start the "DRAW!" phase function startDraw() { if (!playerReady) { earlyLose(); return; } duelState = STATE_DRAW; canShoot = true; aimActive = true; // (aimReticle removed) statusTxt.setText("DRAW!"); statusTxt.visible = true; LK.stopMusic(); LK.getSound('draw').play(); player.toHand(); // draw from holster enemy.toHand(); // enemy draws too aimEnemyGunAt(player.x, player.y - 40); // hemen hizala duelStartTime = Date.now(); // Enemy will shoot after their reaction time var reactTime = 1200; // fallback default if (currentEnemy && typeof currentEnemy.minReact === "number" && typeof currentEnemy.maxReact === "number") { reactTime = 1000 * (currentEnemy.minReact + Math.random() * (currentEnemy.maxReact - currentEnemy.minReact)); reactTime *= 0.425; // %57.5 daha hızlı tepki (eski 0.5 ve yeni 0.35 arası) } if (duelTimer) { LK.clearTimeout(duelTimer); } duelTimer = LK.setTimeout(enemyFire, reactTime); } // Player fires function playerFire(x, y) { // 6 mermi limiti if (playerShotsFiredCnt >= 6) { statusTxt.setText("Out of ammo!"); statusTxt.visible = true; return; } if (!canShoot) { return; } // === COOLDOWN: Block if cooldown active === if (playerShotCooldown > 0) { return; } playerShot = true; playerShotsFiredCnt++; // sayaç ↑ playerShotTime = Date.now(); // === COOLDOWN: Set cooldown after shot === playerShotCooldown = 300; // 0.3 seconds in ms // Animate gun tween(player.gun, { rotation: -0.5 }, { duration: 80, easing: tween.cubicOut }); tween(player.rarm, { rotation: -0.3 }, { duration: 80, easing: tween.cubicOut }); LK.getSound('gunshot').play(); // Create bullet playerBullet = new Bullet(); // Muzzle position helper function muzzlePos() { // Use full gun width/height for muzzle (center anchor) var gunW = player.gun.width || 60; var gunH = player.gun.height || 15; return { x: player.x + player.gun.x + Math.cos(player.gun.rotation) * gunW, y: player.y + player.gun.y + Math.sin(player.gun.rotation) * gunH }; } var muzzle = muzzlePos(); playerBullet.x = muzzle.x; playerBullet.y = muzzle.y; // Ateş anındaki imleç (x, y) fonksiyona zaten parametre olarak geliyor var dx = x - muzzle.x; var dy = y - muzzle.y; var dist = Math.sqrt(dx * dx + dy * dy); playerBullet.dirX = dx / dist; playerBullet.dirY = dy / dist; playerBullet.speed = 60; game.addChild(playerBullet); // Decrement player bullet UI for (var i = 0; i < playerAmmoUI.length; i++) { if (playerAmmoUI[i].visible !== false) { playerAmmoUI[i].visible = false; break; } } // If shot before draw, instant loss if (duelState === STATE_WAIT) { duelState = STATE_RESULT; statusTxt.setText("You shot too early!\nYou Lose!"); statusTxt.visible = true; LK.getSound('fail').play(); player.ragdoll(); enemy.ragdoll(); endRound(false); return; } // bir sonraki mermiye izin ver if (duelState === STATE_DRAW && playerShotsFiredCnt < 6) { canShoot = true; aimActive = true; // (aimReticle removed) } // DRAW fazı açık kalsın ki 6 mermi bitene kadar tekrar tekrar ateş edebilelim } // Enemy fires function enemyFire() { var _currentEnemy; if (enemyShotsFiredCnt >= 6 || duelState === STATE_RESULT) { return; } if (!enemyShot) { enemyShot = true; } // ilk mermi için eski bayrak enemyShotsFiredCnt++; enemyShotTime = Date.now(); // Ateşten önce hedefe çevir aimEnemyGunAt(player.x, player.y - 40); // Animate gun tween(enemy.gun, { rotation: 0.5 }, { duration: 80, easing: tween.cubicOut }); tween(enemy.rarm, { rotation: 0.3 }, { duration: 80, easing: tween.cubicOut }); LK.getSound('gunshot').play(); // Create bullet enemyBullet = new Bullet(); var gunW = enemy.gun.width || 60; var gunH = enemy.gun.height || 18; enemyBullet.x = enemy.x + enemy.gun.x + Math.cos(enemy.gun.rotation) * gunW; enemyBullet.y = enemy.y + enemy.gun.y + Math.sin(enemy.gun.rotation) * gunH; // Decrement enemy bullet UI for (var i = 0; i < enemyAmmoUI.length; i++) { if (enemyAmmoUI[i].visible !== false) { enemyAmmoUI[i].visible = false; break; } } // Konik isabet modeliyle hedef seçimi // 1️⃣ hedef vektörü var baseDX = player.x - enemyBullet.x; var baseDY = player.y - 40 - enemyBullet.y; // gövdenin biraz üstü var baseAng = Math.atan2(baseDY, baseDX); // 2️⃣ saçılma açısı (daralan koni) var sIdx = enemyShotsFiredCnt; // 1-6 var sMax = 6; var cStart = currentEnemy && typeof currentEnemy.coneStart === "number" ? currentEnemy.coneStart : 24; // fallback var cEnd = currentEnemy && typeof currentEnemy.coneEnd === "number" ? currentEnemy.coneEnd : 0; var coneDeg = cStart + (cEnd - cStart) * ((sIdx - 1) / (sMax - 1)); var coneRad = coneDeg * Math.PI / 180; var isLast = sIdx === sMax; // son kurşun var spread = isLast ? 0 : Math.random() * coneRad - coneRad / 2; // 3️⃣ hedef noktasını diagramdaki yayı keserek bul var range = 1500; // ekran dışına yeter var targetX = enemyBullet.x + Math.cos(baseAng + spread) * range; var targetY = enemyBullet.y + Math.sin(baseAng + spread) * range; var dx = targetX - enemyBullet.x; var dy = targetY - enemyBullet.y; var dist = Math.sqrt(dx * dx + dy * dy); enemyBullet.dirX = dx / dist; enemyBullet.dirY = dy / dist; enemyBullet.speed = 60; game.addChild(enemyBullet); // sonraki mermi (tak-tak) 0.6 sn sonra if (enemyShotsFiredCnt < 6) { LK.setTimeout(enemyFire, 600); } // Round oyuncu ateş etmediyse ANCAK bütün 6 mermi atıldıktan sonra if (enemyShotsFiredCnt === 6 && !playerShot) { // Son kurşunun ekrandan çıkması için çok kısa bir gecikme bırak LK.setTimeout(function () { if (duelState !== STATE_RESULT) { duelState = STATE_RESULT; statusTxt.setText("You Survived!"); statusTxt.visible = true; endRound(true); } }, 350); } } // End round, win: true/false function endRound(win) { canShoot = false; aimActive = false; // (aimReticle removed) // Clear all timers immediately cancelHold(); // musicTimeout'u iptal eder if (duelTimer) { LK.clearTimeout(duelTimer); duelTimer = null; } if (drawTimeout) { LK.clearTimeout(drawTimeout); drawTimeout = null; } if (resultTimeout) { LK.clearTimeout(resultTimeout); resultTimeout = null; } drawTimeout = null; duelTimer = null; resultTimeout = null; duelState = STATE_RESULT; // Next round or end game resultTimeout = LK.setTimeout(function () { if (win) { playerScore += 1; scoreTxt.setText("Score: " + playerScore); roundNum += 1; if (roundNum > maxRounds) { statusTxt.setText("You Win!\nScore: " + playerScore); statusTxt.visible = true; LK.showYouWin(); } else { resetDuel(); } } else { statusTxt.setText("You Lose!\nScore: " + playerScore); statusTxt.visible = true; LK.showGameOver(); } }, 1600); } // Handle aiming reticle movement (circular motion) function updateAimReticle() { // (aim reticle removed) } // Handle bullet collisions and duel result function checkBullets() { // Player bullet hits enemy if (playerBullet) { // Check if bullet reached enemy var dx = playerBullet.x - enemy.x; var dy = playerBullet.y - enemy.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { // Hit! LK.getSound('hit').play(); enemy.ragdoll(playerBullet.x, playerBullet.y); game.removeChild(playerBullet); playerBullet = null; duelState = STATE_RESULT; statusTxt.setText("You Win the Duel!"); statusTxt.visible = true; endRound(true); } } // Enemy bullet hits player if (enemyBullet) { var dx = enemyBullet.x - player.x; var dy = enemyBullet.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { LK.getSound('hit').play(); player.ragdoll(enemyBullet.x, enemyBullet.y); game.removeChild(enemyBullet); enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("You were shot!"); statusTxt.visible = true; endRound(false); } } // Both bullets exist (simultaneous fire) if (playerBullet && enemyBullet) { // Check which bullet hits first var pdx = playerBullet.x - enemy.x; var pdy = playerBullet.y - enemy.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); var edx = enemyBullet.x - player.x; var edy = enemyBullet.y - player.y; var edist = Math.sqrt(edx * edx + edy * edy); if (pdist < 120 && edist < 120) { // Both hit at same time: draw LK.getSound('hit').play(); player.ragdoll(); enemy.ragdoll(); game.removeChild(playerBullet); game.removeChild(enemyBullet); playerBullet = null; enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("Draw!\nBoth shot!"); statusTxt.visible = true; endRound(false); } else if (pdist < 120) { LK.getSound('hit').play(); enemy.ragdoll(playerBullet.x, playerBullet.y); game.removeChild(playerBullet); playerBullet = null; duelState = STATE_RESULT; statusTxt.setText("You Win the Duel!"); statusTxt.visible = true; endRound(true); } else if (edist < 120) { LK.getSound('hit').play(); player.ragdoll(enemyBullet.x, enemyBullet.y); game.removeChild(enemyBullet); enemyBullet = null; duelState = STATE_RESULT; statusTxt.setText("You were shot!"); statusTxt.visible = true; endRound(false); } } // Remove bullets if off screen if (playerBullet && (playerBullet.x < 0 || playerBullet.x > 2048 || playerBullet.y < 0 || playerBullet.y > 2732)) { game.removeChild(playerBullet); playerBullet = null; // === COOLDOWN: Only allow new shot if cooldown expired === if (playerShotCooldown <= 0) { canShoot = true; } } if (enemyBullet && (enemyBullet.x < 0 || enemyBullet.x > 2048 || enemyBullet.y < 0 || enemyBullet.y > 2732)) { game.removeChild(enemyBullet); enemyBullet = null; enemyShot = false; // yeni atışa izin ver } } // ==== FIX #2 : holster konumu ==== // Use two holster sprites: full and empty, toggle visibility var holsterFull = LK.getAsset('kilif', { width: 300, height: 300, anchorX: -0.2, anchorY: 0 }); var holsterEmpty = LK.getAsset('kilifbos', { width: 300, height: 300, anchorX: -0.2, anchorY: 0 }); holsterFull.visible = true; holsterEmpty.visible = false; var holsterOffset = 250; holsterFull.x = player.x - 200; holsterFull.y = player.y + player.body.height / 2 + holsterOffset; holsterEmpty.x = holsterFull.x; holsterEmpty.y = holsterFull.y; world.addChild(holsterFull); world.addChild(holsterEmpty); // === Place enemygunpocket in the middle of the screen === var enemygunpocket = LK.getAsset('enemygunpocket', { anchorX: 0.5, anchorY: 0.5 }); enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5; enemygunpocket.y = 2732 / 2 - 600 + 150 + 10; world.addChild(enemygunpocket); // Helper: check if global point is inside holsterFull's bounds (always use holsterFull for hit area) function holsterContains(globalX, globalY) { // Global (stage) → world-içi (local) koordinata çevir var localX = (globalX - world.x) / world.scaleX; var localY = (globalY - world.y) / world.scaleY; // kilif sprite’ının local kutusu var b = { x: holsterFull.x, y: holsterFull.y, w: holsterFull.width, h: holsterFull.height }; return localX >= b.x && localX <= b.x + b.w && localY >= b.y && localY <= b.y + b.h; } // Holster hold/zoom/duel state var zoomFinished = false, duelStarted = false, holsterHoldTime = 0; var playerReady = false; var holdingHolster = false; // Track if holster is being held var musicTimeout = null; // Timer for music/draw phase function beginHold() { if (musicTimeout) { LK.clearTimeout(musicTimeout); } var extra = 4000 + Math.random() * 6000; // 4-10 s musicTimeout = LK.setTimeout(stopMusicAndDraw, extra); } function cancelHold() { if (musicTimeout) { LK.clearTimeout(musicTimeout); } musicTimeout = null; } function stopMusicAndDraw() { if (duelState !== STATE_WAIT) return; LK.stopMusic(); // müzik sustu if (enemygunpocket && enemygunpocket.visible !== false) { enemygunpocket.visible = false; } duelStarted = true; // <-- ERKEN KAYIP KONTROLÜ ARTIK PASİF holsterHoldTime = 0; // güvenlik: sayaç sıfırla startDraw(); // DRAW fazına geç } // Touch/click to fire or start holster hold game.down = function (x, y, obj) { if (duelState === STATE_RESULT) return; // No fire until duel actually started if (zoomFinished && !duelStarted && holsterContains(x, y)) { playerReady = true; holdingHolster = true; // holster pressed player.toHand(); // ← kılıftan çek (hemen ele ver) // Play holdsound when gun is drawn to hand LK.getSound('holdsound').play(); // --- holster assetini kilifbos ile değiştir (Çözüm 2: iki sprite, görünürlük) --- holsterFull.visible = false; holsterEmpty.visible = true; pointGunAt(x, y); // artık global ve erişilebilir beginHold(); // HOLD başlatılırken zamanlayıcı kuruluyor return; } if (!duelStarted) { return; } if (duelState === STATE_DRAW && canShoot && aimActive) { playerFire(x, y); } else if (duelState === STATE_WAIT && !playerShot) { playerFire(x, y); } }; // On pointer up, check for early leave from holster // ==== FIX #4c : tetikleyici ===== game.up = function (x, y, obj) { if (duelState === STATE_RESULT) return; // HOLSTER EARLY RELEASE CHECK holdingHolster = false; // holster released cancelHold(); // el çekildi, zamanlayıcı iptal if (!duelStarted && playerReady && duelState === STATE_WAIT) { earlyLose(); return; } if (duelState === STATE_DRAW && canShoot) { playerFire(x, y); return; } }; // Move reticle with finger (optional: drag to aim) game.move = function (x, y, obj) { if (duelState === STATE_RESULT) return; // Holster hold/early leave logic if (zoomFinished && !duelStarted) { if (holsterContains(x, y)) { // handled in update for dt-accurate timing } else if (holdingHolster) { cancelHold(); earlyLose(); } } // (aim reticle removed) // Namlu her zaman fareyi izlesin (DRAW’tan önce holster tutulurken de) pointGunAt(x, y); }; /**** GLOBAL YARDIMCI : Silahı imlece çevir ****/ function pointGunAt(globalX, globalY) { if (duelState === STATE_RESULT) return; // 1) Omuz pivotu – dünya koordinatı var shX = player.x + player.rarm.x; var shY = player.y + player.rarm.y; // 2) Omuz → imleç vektörü ve açı (0 rad = sağ) var dx = globalX - shX; var dy = globalY - shY; var ang = Math.atan2(dy, dx); // 3) Kol sprite’ı AŞAĞI bakıyor → –90° (-π/2) düzelt var armRot = ang - Math.PI / 2; player.rarm.rotation = armRot; // 4) El / silah konumu (player LOCAL) var L = player.rarm.height; // ≈110 px // ❗️ Doğru ofset: (-sin, +cos) player.gun.x = player.rarm.x - Math.sin(armRot) * L + 5; // +5px x-offset player.gun.y = player.rarm.y + Math.cos(armRot) * L + 3; // +3px y-offset // 5) Silah namlu yönü if (!duelStarted && holsterContains(globalX, globalY)) { player.gun.rotation = Math.PI / 2; // kılıfta ⇒ namlu yere } else { player.gun.rotation = ang; // hedefe bak } } /**** GLOBAL : Enemy silahını hedefe çevir ****/ function aimEnemyGunAt(globalX, globalY) { if (duelState === STATE_RESULT) return; // 1) Omuz pivotu (world) var shX = enemy.x + enemy.rarm.x; var shY = enemy.y + enemy.rarm.y; // 2) Omuz→hedef vektörü var dx = globalX - shX; var dy = globalY - shY; var ang = Math.atan2(dy, dx); // 3) Kol sprite’ı AŞAĞI bakıyor → –90° (–π/2) düzeltme var armRot = ang - Math.PI / 2; enemy.rarm.rotation = armRot; // 4) El / silah konumu (enemy LOCAL) **ayna!** var L = enemy.rarm.height; // ≈145 px enemy.gun.x = enemy.rarm.x - Math.sin(armRot) * L + 4; // +4px x-offset enemy.gun.y = enemy.rarm.y + Math.cos(armRot) * L + 2; // +2px y-offset // 5) Namluyu hedefe döndür enemy.gun.rotation = ang; } // Helper to update holster box position under player's feet function updateHolsterBox() { holsterFull.x = player.x - 200; holsterFull.y = player.y + player.body.height / 2 + holsterOffset; holsterEmpty.x = holsterFull.x; holsterEmpty.y = holsterFull.y; } // Main update loop game.update = function (dt) { if (duelState === STATE_RESULT) { // Optionally, statusTxt can still be shown statusTxt.visible = true; return; } // Move enemygun assets in pocket 5px down and 10px left when music is not stopped if (LK.musicPlaying && enemygunpocket) { enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5 - 10; // 10px more left enemygunpocket.y = 2732 / 2 - 600 + 150 + 10 + 5; // 5px more down } // Hide status text during zoom-in if (!zoomFinished) { statusTxt.visible = false; return; } // Always update holster position to follow player updateHolsterBox(); // (aim reticle removed) // Rakip silahı eldeyse oyuncuyu takip etsin if (enemy.gun.visible) { aimEnemyGunAt(player.x, player.y - 40); } // Animate bullets if (playerBullet) { playerBullet.update(); } if (enemyBullet) { enemyBullet.update(); } // === PLAYER SHOT COOLDOWN TIMER === if (playerShotCooldown > 0) { var dtMs = typeof dt === "number" ? dt : 16.7; playerShotCooldown -= dtMs; if (playerShotCooldown < 0) { playerShotCooldown = 0; } } // Check for bullet collisions checkBullets(); // ==== FIX #3 : statusTxt ayarı ==== // Holster hold logic after zoom if (zoomFinished && !duelStarted) { // Use pointerX/Y for current pointer var px = typeof game.pointerX === "number" ? game.pointerX : 0; var py = typeof game.pointerY === "number" ? game.pointerY : 0; var dtMs = typeof dt === "number" ? dt : 16.7; if (holsterContains(px, py) && holdingHolster) { holsterHoldTime += dtMs; } else { if (holsterHoldTime > 0 && holdingHolster) { earlyLose(); } holsterHoldTime = 0; } if (!duelStarted) { if (!playerReady) { statusTxt.setText("Hold holster to start duel"); } else { statusTxt.setText("Wait for music to end…\nthen aim & release"); } } // if (holsterHoldTime >= 4000 && !duelStarted) { // duelStarted = true; // holsterHoldTime = 0; // resetDuel(); // } statusTxt.visible = true; } else { if (duelState === STATE_DRAW) { statusTxt.setText("Aim and SHOOT!"); } statusTxt.visible = true; } }; // Early lose function function earlyLose() { if (duelState === STATE_RESULT) { return; } // only trigger once holdingHolster = false; holsterHoldTime = 0; duelStarted = false; LK.stopMusic(); if (drawTimeout) { LK.clearTimeout(drawTimeout); } statusTxt.setText("Too early!\nYou lose!"); statusTxt.visible = true; LK.getSound('gunshot').play(); // yere ateş LK.getSound('fail').play(); // Optionally, also play gunshot sound: // LK.getSound('gunshot').play(); // Show game over after 1 second LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Camera zoom-in before duel starts function startZoomIn(music) { // ==== FIX #1b : zoom fonksiyonunda ==== var startScale = 0.4; world.scaleX = world.scaleY = startScale; world.x = centerX * (1 - startScale); world.y = 2732 / 2 * (1 - startScale); LK.playMusic(music || 'duelmusic'); tween(world, { scaleX: 1, scaleY: 1, x: 0, y: 0 }, { duration: 4000, easing: tween.quadInOut, onFinish: function onFinish() { zoomFinished = true; } }); } // Start zoom-in and music immediately on boot startZoomIn();
===================================================================
--- original.js
+++ change.js
@@ -100,13 +100,13 @@
// Gun (in hand)
var gun = self.attachAsset('enemyGun', {
anchorX: 0.2,
// tetiğe yakın pivot
- anchorY: 0.8,
+ anchorY: -0.4,
// sapına yakın pivot
- x: rarm.x + 4,
+ x: rarm.x + 15,
// 4px sağa kaydır
- y: rarm.y + -2,
+ y: rarm.y + 15,
// 2px alta kaydır
rotation: 0
});
// Holster gun (on hip, always visible unless drawn)
@@ -259,11 +259,11 @@
y: body.height / 2 - 10 + 10 // 10px down
});
// Gun (in hand)
var gun = self.attachAsset('playerGun', {
- anchorX: 0.2,
+ anchorX: 0.3,
// tetiğe yakın pivot
- anchorY: 0.8,
+ anchorY: 1.2,
// sapına yakın pivot
x: rarm.x + 5,
// 5px sağa kaydır
y: rarm.y + 3,
@@ -367,10 +367,10 @@
/****
* Game Code
****/
-// Game state
// Player and enemy bodies (torso, head, arms, legs) as simple shapes
+// Game state
var STATE_WAIT = 0;
var STATE_DRAW = 1;
var STATE_SHOT = 2;
var STATE_RESULT = 3;
@@ -773,20 +773,26 @@
function endRound(win) {
canShoot = false;
aimActive = false;
// (aimReticle removed)
- if (drawTimeout) {
- LK.clearTimeout(drawTimeout);
- }
+ // Clear all timers immediately
+ cancelHold(); // musicTimeout'u iptal eder
if (duelTimer) {
LK.clearTimeout(duelTimer);
+ duelTimer = null;
}
+ if (drawTimeout) {
+ LK.clearTimeout(drawTimeout);
+ drawTimeout = null;
+ }
if (resultTimeout) {
LK.clearTimeout(resultTimeout);
+ resultTimeout = null;
}
drawTimeout = null;
duelTimer = null;
resultTimeout = null;
+ duelState = STATE_RESULT;
// Next round or end game
resultTimeout = LK.setTimeout(function () {
if (win) {
playerScore += 1;
@@ -968,8 +974,9 @@
}
musicTimeout = null;
}
function stopMusicAndDraw() {
+ if (duelState !== STATE_WAIT) return;
LK.stopMusic(); // müzik sustu
if (enemygunpocket && enemygunpocket.visible !== false) {
enemygunpocket.visible = false;
}
@@ -978,8 +985,9 @@
startDraw(); // DRAW fazına geç
}
// Touch/click to fire or start holster hold
game.down = function (x, y, obj) {
+ if (duelState === STATE_RESULT) return;
// No fire until duel actually started
if (zoomFinished && !duelStarted && holsterContains(x, y)) {
playerReady = true;
holdingHolster = true; // holster pressed
@@ -1004,8 +1012,9 @@
};
// On pointer up, check for early leave from holster
// ==== FIX #4c : tetikleyici =====
game.up = function (x, y, obj) {
+ if (duelState === STATE_RESULT) return;
// HOLSTER EARLY RELEASE CHECK
holdingHolster = false; // holster released
cancelHold(); // el çekildi, zamanlayıcı iptal
if (!duelStarted && playerReady && duelState === STATE_WAIT) {
@@ -1018,8 +1027,9 @@
}
};
// Move reticle with finger (optional: drag to aim)
game.move = function (x, y, obj) {
+ if (duelState === STATE_RESULT) return;
// Holster hold/early leave logic
if (zoomFinished && !duelStarted) {
if (holsterContains(x, y)) {
// handled in update for dt-accurate timing
@@ -1033,8 +1043,9 @@
pointGunAt(x, y);
};
/**** GLOBAL YARDIMCI : Silahı imlece çevir ****/
function pointGunAt(globalX, globalY) {
+ if (duelState === STATE_RESULT) return;
// 1) Omuz pivotu – dünya koordinatı
var shX = player.x + player.rarm.x;
var shY = player.y + player.rarm.y;
// 2) Omuz → imleç vektörü ve açı (0 rad = sağ)
@@ -1057,8 +1068,9 @@
}
}
/**** GLOBAL : Enemy silahını hedefe çevir ****/
function aimEnemyGunAt(globalX, globalY) {
+ if (duelState === STATE_RESULT) return;
// 1) Omuz pivotu (world)
var shX = enemy.x + enemy.rarm.x;
var shY = enemy.y + enemy.rarm.y;
// 2) Omuz→hedef vektörü
@@ -1083,8 +1095,13 @@
holsterEmpty.y = holsterFull.y;
}
// Main update loop
game.update = function (dt) {
+ if (duelState === STATE_RESULT) {
+ // Optionally, statusTxt can still be shown
+ statusTxt.visible = true;
+ return;
+ }
// Move enemygun assets in pocket 5px down and 10px left when music is not stopped
if (LK.musicPlaying && enemygunpocket) {
enemygunpocket.x = 2048 / 2 + 550 + 50 - 30 - 5 - 5 - 10; // 10px more left
enemygunpocket.y = 2732 / 2 - 600 + 150 + 10 + 5; // 5px more down