User prompt
ฤฑ want to add two more dog to play the game. Should have select screen. after a mod selected, player should see 3 options a default dog and two more dog . default dog's name is dodo.other two dogs are kaiser and maki. for kaiser use dog_dalmatian and laugh_d assets. for maki use dog_labrador and laugh_l assets. when player select a dog, dog must be shown in the game. selected dog must be shoot the ducks . for example if kaiser is selected dog_dalmatian asset must used. if maki is selected dog_labrador asset must used. if dodo is selected dog asset must used.
User prompt
Implement a character selection system triggered by a "Select Mode" button. 1. Add a "Select Mode" button to the main menu. - When clicked, it should open a character selection screen. 2. Character Selection Screen: - Display three characters: Dodo (default), Kaiser, and Maki. - Show visual previews using these assets: - Dodo: "dog" - Kaiser: "dog_labrador" - Maki: "dog_dalmatian" - Each character should have a name label and preview animation or idle pose. - Allow the player to click on a character to select it. 3. When the player confirms the selection: - Store the selected character. - During gameplay, load the correct model and laugh sound: - Dodo: model = "dog", laugh = "laugh" - Kaiser: model = "dog_labrador", laugh = "laugh_l" - Maki: model = "dog_dalmatian", laugh = "laugh_d" - Ensure this character is used visually and audibly throughout the game (e.g. when shooting ducks). 4. The system should remember the selected character until the game is closed or another selection is made. 5. If no selection is made, default to Dodo. This will allow players to enter a dedicated selection mode, choose their preferred character, and see that character in action throughout the entire game session.
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'undefined')' in or related to this line: 'var _char2 = CHARACTERS[selectedCharacterIndex];' Line Number: 757
User prompt
Add two new characters to the game: Kaiser and Maki. - Kaiser: - Use the asset "dog_labrador" for the dog model. - Use the laugh sound "laugh_l". - Name: Kaiser - Maki: - Use the asset "dog_dalmatian" for the dog model. - Use the laugh sound "laugh_d". - Name: Maki The existing default dog character (Dodo) uses: - Asset: "dog" - Laugh sound: "laugh" Ensure that Kaiser and Maki appear as selectable characters alongside Dodo, each with their respective assets and unique laugh sounds. Make sure their models and sounds are linked correctly.
User prompt
use this information to fix problem that why selected dog cant show in the game. dog assets shooting and dog_laugh asset is laughing for dodo. dog_dalmatian asset shooting and laugh_d asset laughing for kaiser. dog_labrador asset shooting and laugh_l asset lauhing for maki.
User prompt
fix to dog.show only to select chosen dog. do not change dog.laugh
User prompt
// โ Fix for Dog Selection Bug in WhatTheDuck // Ensures the selected dog (dodo, kaiser, maki) shows up correctly in gameplay // Step 1: Ensure selectedDog is defined globally let selectedDog = "dodo"; // default value // Step 2: Show dog select screen and then main menu function startGame() { showDogSelectScreen(function () { showMainMenu(); // ๐ก Re-create dog after selection to ensure correct sprite if (dog && dog.parent) { dog.parent.removeChild(dog); } dog = new Dog(); game.addChild(dog); }); } // Step 3: Update Dog class to use selected sprite class Dog extends GameObject { constructor() { super(); // ๐ฏ Use correct asset based on selectedDog let dogSprite = { "dodo": "dog", "kaiser": "dog_dalmatian", "maki": "dog_labrador" }[selectedDog] || "dog"; this.sprite = new Sprite(dogSprite); this.addChild(this.sprite); // Optional: initial hidden state this.visible = false; } show() { this.visible = true; this.sprite.play("celebrate"); // Auto-hide after delay setTimeout(() => { this.visible = false; }, 1500); } } // Step 4: When a duck is hit, show the dog function onDuckHit() { if (dog) { dog.show(); } // Additional scoring logic here } // Call startGame() somewhere in your initialization code startGame();
User prompt
// โ Fix for Dog Selection Bug in WhatTheDuck // Ensures the selected dog (dodo, kaiser, maki) shows up correctly in gameplay // Step 1: Ensure selectedDog is defined globally let selectedDog = "dodo"; // default value // Step 2: Show dog select screen and then main menu function startGame() { showDogSelectScreen(function () { showMainMenu(); // ๐ก Re-create dog after selection to ensure correct sprite if (dog && dog.parent) { dog.parent.removeChild(dog); } dog = new Dog(); game.addChild(dog); }); } // Step 3: Update Dog class to use selected sprite class Dog extends GameObject { constructor() { super(); // ๐ฏ Use correct asset based on selectedDog let dogSprite = { "dodo": "dog", "kaiser": "dog_dalmatian", "maki": "dog_labrador" }[selectedDog] || "dog"; this.sprite = new Sprite(dogSprite); this.addChild(this.sprite); // Optional: initial hidden state this.visible = false; } show() { this.visible = true; this.sprite.play("celebrate"); // Auto-hide after delay setTimeout(() => { this.visible = false; }, 1500); } } // Step 4: When a duck is hit, show the dog function onDuckHit() { if (dog) { dog.show(); } // Additional scoring logic here } // Call startGame() somewhere in your initialization code startGame();
User prompt
Implement a proper dog selection and appearance system in the game: ๐ฎ Selection System: - On the start screen, allow the player to select one of these dogs: 1. "dodo" 2. "kaiser" 3. "maki" - Internally store the selected dog as a string in a global variable called `selectedDog`. ๐ถ Dog Sprite Mapping: - Map each dog name to its asset name as follows: - "dodo" โ use asset: `dog` - "kaiser" โ use asset: `dog_dalmatian` - "maki" โ use asset: `dog_labrador` ๐ฆ Duck Hit Detection & Dog Appearance: - Track the number of ducks hit using a variable like `duckHitCount`. - On every update frame: - Store previous frameโs duck count in `lastDuckHitCount`. - If `duckHitCount > lastDuckHitCount`, it means a duck was hit this frame. - When a duck is hit, show the correct dog sprite according to `selectedDog` for celebration. ๐พ Dog Appearance Rules: - Dog should appear on the screen near the player for 1โ2 seconds after hitting a duck. - Animate the correct sprite (based on selection) using retro pixel art style. - Do not default to the Dodo dog unless the player actually chose it. ๐ Technical Notes: - Make sure `selectedDog` persists between the menu and gameplay. - Test the transition for all dog choices. - Update all functions that show the dog sprite to use a lookup like: ```js let dogSprite = { "dodo": "dog", "kaiser": "dog_dalmatian", "maki": "dog_labrador" }[selectedDog];
User prompt
fix the code to use if player choose kaiser dog_dalmatian asset play if maki selected dog_labrador asset plays,if dodo selected dog asset plays
User prompt
fix to dog informations in the code
User prompt
Fix the dog selection system so that the correct dog sprite is used during gameplay based on the player's selection. ๐ ๏ธ Dog options and corresponding asset names: - If the player selects **dodo**, use the asset named: `dog` - If the player selects **kaiser**, use the asset named: `dog_dalmatian` - If the player selects **maki**, use the asset named: `dog_labrador` โ What to fix: 1. On the dog selection screen, store the selected dog name (e.g., "dodo", "kaiser", "maki") in a global variable such as `selectedDog`. 2. During gameplay, load and use the correct dog sprite based on that variable: - If `selectedDog == "dodo"`, use the sprite from asset `dog`. - If `selectedDog == "kaiser"`, use the sprite from asset `dog_dalmatian`. - If `selectedDog == "maki"`, use the sprite from asset `dog_labrador`. 3. Make sure the chosen dog appears in all relevant animations (e.g. celebration after hitting ducks). 4. Do not default to `dog` unless the player actually selected "dodo".
User prompt
Fix the bug where the selected dog from the start screen (dog_dalmatian, dog_labrador, or dodo) does not appear in the actual game. No matter which dog the player selects, only dodo appears during gameplay. This is incorrect. ๐ง Fix Requirements: 1. When the player selects a dog on the character select screen, store that choice in a global variable or persistent state (e.g., selectedDog). 2. Pass this selectedDog value into the gameplay scene or main game loop. 3. In the game scene, use a conditional check: - If selectedDog is "dog_dalmatian", use the dalmatian sprite and animations. - If selectedDog is "dog_labrador", use the labrador sprite. - If "dodo", use dodoโs sprite. 4. Do NOT default to dodo unless the player has not selected any dog. 5. Verify that the correct dog is shown every time based on player choice โ not hardcoded. ๐งช Test Cases: - Select dog_dalmatian โ dalmatian appears during gameplay. - Select dog_labrador โ labrador appears in gameplay. - Select dodo โ dodo appears as expected. Make sure the selection works across restarts and between levels. Keep all dog sprites in retro pixel-art style.
User prompt
use kaiser and maki in the game too
User prompt
when ฤฑ select kaiser and makis dodo plays fix this
User prompt
you didnt fix this try again
User prompt
Fix the bug where the selected dog from the start screen (Kaiser, Maki, or Dodo) does not appear in the actual game. No matter which dog the player selects, only Dodo appears during gameplay. This is incorrect. ๐ง Fix Requirements: 1. When the player selects a dog on the character select screen, store that choice in a global variable or persistent state. 2. Pass this selected dog value into the gameplay scene or main game loop. 3. In the game scene, use a conditional check: - If selectedDog is "Kaiser", use Kaiserโs sprite and animations. - If "Maki", use Makiโs sprite. - If "Dodo", use Dodo. 4. Do NOT default to Dodo unless the player has not selected any dog. 5. Verify that the correct dog is shown every time based on player choice โ not hardcoded.
User prompt
Fix the bug where the selected dog from the start screen is not used in the actual game. Currently, no matter which dog is selected (Kaiser, Maki, or Dodo), only the default dog appears during gameplay. What to fix: 1. When the player selects a dog on the start screen, store the selected dog correctly. 2. Use the stored dog as the active dog during gameplay. 3. Ensure the right sprite and animation (Kaiser, Maki, or Dodo) is shown at the appropriate times (like when a duck is hit). 4. Do not default to Dodo unless the player specifically selects Dodo. Test that all 3 dogs appear properly when selected. Keep the dog sprite style consistent with retro pixel art.
User prompt
when ฤฑ select kaiser dog_dalmatian should shoot duck ,when ฤฑ select maki, maki should shoot ducks
User prompt
kaiser is dog_dalmatian , maki is dog_labrador fix this problem. problem is selection screen , all dogs are look like dodo(default dog) change kaiser to dog_dalmatian maki to dog_labrador
User prompt
use dog_dalmatian and dog_labrador assets for the change kaiser andn makis look
User prompt
make differnt assets for maki and kaiser
User prompt
Add a dog selection system with 3 dog characters the player can choose from before the game starts. 1. Dodo โ the original dog (default) 2. Kaiser โ a Dalmatian with black and white spots 3. Maki โ a playful orange Labrador Show a dog selection screen before the game starts with a retro-style layout: - Display all 3 dogs with their names. - The player taps one to select before starting. Make sure the selected dog is remembered during the game session and shown during gameplay. Keep everything in retro pixel art style.
User prompt
+10 bullet to every level except level 1
User prompt
every mode must have their own high score
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ // Achievement popup class var AchievementPopup = Container.expand(function () { var self = Container.call(this); var txt = new Text2('', { size: 120, fill: 0xFFD700 }); txt.anchor.set(0.5, 0.5); self.addChild(txt); self.visible = false; self.show = function (message, color) { txt.setText(message); if (txt && txt.style) { txt.style.fill = color || 0xFFD700; } self.x = 2048 / 2; self.y = 2732 / 2 - 300; self.visible = true; self.alpha = 1; tween(self, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { self.visible = false; } }); }; return self; }); // Dog class var Dog = Container.expand(function () { var self = Container.call(this); self.dogAsset = null; self.laughAsset = null; self.currentDogId = null; // Helper to set dog asset based on selectedDogId self.setDogAssets = function () { // Remove old assets if any if (self.dogAsset && self.dogAsset.parent) self.removeChild(self.dogAsset); if (self.laughAsset && self.laughAsset.parent) self.removeChild(self.laughAsset); self.dogAsset = null; self.laughAsset = null; var dogOpt = null; for (var i = 0; i < DOG_OPTIONS.length; i++) { if (DOG_OPTIONS[i].id === selectedDogId) { dogOpt = DOG_OPTIONS[i]; break; } } if (!dogOpt) dogOpt = DOG_OPTIONS[0]; self.currentDogId = dogOpt.id; self.dogAsset = self.attachAsset(dogOpt.asset, { anchorX: 0.5, anchorY: 1 }); self.dogAsset.visible = false; // Laugh asset will be created on demand in laugh() }; self.setDogAssets(); self.visible = false; // Show dog at (x, y) self.show = function (x, y) { // If dog changed, update assets if (self.currentDogId !== selectedDogId) { self.setDogAssets(); } self.x = x; self.y = y; self.visible = true; if (self.dogAsset) self.dogAsset.visible = true; if (self.laughAsset) self.laughAsset.visible = false; // Optionally, you could add a little "pop up" animation here // For example, tween the dog from below the screen to y var startY = 2732 + (self.dogAsset ? self.dogAsset.height : 180); self.y = startY; tween(self, { y: y }, { duration: 350, easing: tween.cubicOut }); }; // Hide dog self.hide = function () { var endY = 2732 + (self.dogAsset ? self.dogAsset.height : 180); tween(self, { y: endY }, { duration: 350, easing: tween.cubicIn, onFinish: function onFinish() { self.visible = false; if (self.dogAsset) self.dogAsset.visible = false; } }); }; // Show laugh animation self.laugh = function (x, y) { // If dog changed, update assets if (self.currentDogId !== selectedDogId) { self.setDogAssets(); } self.x = x; self.y = y; self.visible = true; if (self.dogAsset) self.dogAsset.visible = false; // Find laugh asset id for this dog var dogOpt = null; for (var i = 0; i < DOG_OPTIONS.length; i++) { if (DOG_OPTIONS[i].id === selectedDogId) { dogOpt = DOG_OPTIONS[i]; break; } } if (!dogOpt) dogOpt = DOG_OPTIONS[0]; var laughId = dogOpt.laugh || "dog_laugh"; if (!self.laughAsset || self.laughAsset._assetId !== laughId) { if (self.laughAsset && self.laughAsset.parent) self.removeChild(self.laughAsset); self.laughAsset = self.attachAsset(laughId, { anchorX: 0.5, anchorY: 1 }); self.laughAsset._assetId = laughId; } self.laughAsset.visible = true; // Play laugh sound (use default for all) LK.getSound('dog_laugh').play(); // Hide after 1.2s LK.setTimeout(function () { self.laughAsset.visible = false; self.hide(); }, 1200); }; return self; }); // Duck class var Duck = Container.expand(function () { var self = Container.call(this); // Determine duck type based on level and DUCK_TYPE_CONFIG var duckType = 'normal'; var levelIdx = Math.max(0, Math.min(level - 1, DUCK_TYPE_CONFIG.length - 1)); var config = DUCK_TYPE_CONFIG[levelIdx]; var r = Math.random(); if (r < config.golden) { duckType = 'golden'; } else if (r < config.golden + config.armored) { duckType = 'armored'; } else if (r < config.golden + config.armored + config.mini) { duckType = 'mini'; } else if (Math.random() < 0.25) { duckType = 'fast'; } self.type = duckType; // Asset selection var duckAsset = null; if (duckType === 'golden') { duckAsset = self.attachAsset('duck_golden', { anchorX: 0.5, anchorY: 0.5 }); duckAsset.tint = 0xFFD700; } else if (duckType === 'armored') { duckAsset = self.attachAsset('duck_armored', { anchorX: 0.5, anchorY: 0.5 }); duckAsset.tint = 0x888888; } else if (duckType === 'mini') { duckAsset = self.attachAsset('duck_mini', { anchorX: 0.5, anchorY: 0.5 }); } else { // normal or fast var duckColors = ['duck_green', 'duck_blue', 'duck_red']; var colorIdx = Math.floor(Math.random() * duckColors.length); duckAsset = self.attachAsset(duckColors[colorIdx], { anchorX: 0.5, anchorY: 0.5 }); } // Set initial position and movement self.speed = 6 + Math.random() * 4; // Will be set by level self.angle = 0; // radians, will be set by level self.alive = true; self.hit = false; self.escaped = false; self.armor = duckType === 'armored' ? 2 : 1; // 2 hits for armored self.flashTween = null; // For animation self.flyTween = null; // --- Hitbox properties for all ducks (mini ducks are smaller, fast/golden slightly larger) --- self.getHitboxRadius = function () { var baseRadius = Math.max(duckAsset.width, duckAsset.height) * 0.5; if (self.type === 'mini') { return baseRadius * 0.55; } if (self.type === 'fast' || self.type === 'golden' || self.speed >= 6) { return baseRadius * 0.7; } return baseRadius * 0.55; }; // Head hitbox (top 1/3 of duck) self.isHeadshot = function (x, y) { var dx = self.x - x; var dy = self.y - y; var dist = Math.sqrt(dx * dx + dy * dy); var headRadius = duckAsset.height * 0.18; var headCenterY = self.y - duckAsset.height * 0.22; var headDist = Math.sqrt((self.x - x) * (self.x - x) + (headCenterY - y) * (headCenterY - y)); return headDist < headRadius; }; // Called every tick self.update = function () { if (!self.alive || self.hit) return; self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) { self.escaped = true; self.alive = false; } }; // Animate duck falling when hit self.fall = function (_onFinish) { self.alive = false; tween(self, { rotation: Math.PI * 1.5, y: self.y + 400 }, { duration: 700, easing: tween.cubicIn, onFinish: function onFinish() { if (_onFinish) _onFinish(); } }); }; // Armored duck: flash red on first hit self.flashRed = function () { if (self.flashTween) { self.flashTween.cancel(); } var origTint = duckAsset.tint; duckAsset.tint = 0xff2222; self.flashTween = tween(duckAsset, {}, { duration: 200, onFinish: function onFinish() { duckAsset.tint = 0x888888; self.flashTween = null; } }); }; return self; }); // Power-up collectible class var PowerupCollectible = Container.expand(function () { var self = Container.call(this); self.type = null; self.icon = null; self.radius = 60; self.speedY = -2 - Math.random() * 2; self.lifetime = 0; self.maxLifetime = 400; // ~6 seconds self.init = function (ptype, x, y) { self.type = ptype; var iconId = ptype === 'doubleBarrel' ? 'powerup_double' : ptype === 'slowTime' ? 'powerup_slow' : 'powerup_auto'; self.icon = self.attachAsset(iconId, { anchorX: 0.5, anchorY: 0.5 }); self.x = x; self.y = y; self.icon.scaleX = self.icon.scaleY = 1.1; self.visible = true; self.alpha = 0.92; }; self.update = function () { self.y += self.speedY; self.lifetime++; // Fade out near end of life if (self.lifetime > self.maxLifetime - 60) { self.alpha = Math.max(0, (self.maxLifetime - self.lifetime) / 60); } // Remove if out of bounds or expired if (self.y < 100 || self.lifetime > self.maxLifetime) { if (self.parent) self.parent.removeChild(self); if (typeof powerupCollectibles !== "undefined") { var idx = powerupCollectibles.indexOf(self); if (idx >= 0) powerupCollectibles.splice(idx, 1); } } }; // Check if tap is within radius self.isHit = function (x, y) { var dx = self.x - x; var dy = self.y - y; return dx * dx + dy * dy < self.radius * self.radius; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // sky blue }); /**** * Game Code ****/ // Use red as base, smaller // Use blue as base, gray tint // Use red as base, gold tint // --- Duck type probabilities and point values --- var DUCK_TYPE_CONFIG = [ // Level 1 { golden: 0.04, // 4% armored: 0.0, mini: 0.0 }, // Level 2 { golden: 0.06, armored: 0.08, mini: 0.04 }, // Level 3 { golden: 0.08, armored: 0.13, mini: 0.08 }, // Level 4 { golden: 0.10, armored: 0.18, mini: 0.13 }, // Level 5+ { golden: 0.13, armored: 0.22, mini: 0.18 }]; var DUCK_TYPE_POINTS = { normal: 10, golden: 50, armored: 20, mini: 25 }; // --- Power-up collectibles array --- // Ducks: 3 colors, 1 dog, 1 bullet, 1 background, 1 crosshair, 1 "laugh" dog // sky blue // Sounds // Music // Power-up icons and retro overlay var powerupCollectibles = []; // Spawn a power-up collectible at a random position function spawnPowerupCollectible(ptype) { var px = 200 + Math.random() * (2048 - 400); var py = 2732 - 200 - Math.random() * 800; var p = new PowerupCollectible(); p.init(ptype, px, py); powerupCollectibles.push(p); game.addChild(p); } // Activate a power-up function activatePowerup(ptype) { if (powerupActive[ptype]) return; powerupActive[ptype] = true; var duration = 0; if (ptype === 'doubleBarrel') duration = 7; if (ptype === 'slowTime') duration = 5; if (ptype === 'autoAim') duration = 3; powerupTimers[ptype] = duration; showPowerupIcon(ptype, duration); // Apply effect if (ptype === 'slowTime') { // Slow all ducks for (var i = 0; i < ducks.length; i++) { ducks[i].speed = ducks[i].speed * 0.35; } // Add retro overlay if (!slowTimeEffectOverlay) { slowTimeEffectOverlay = LK.getAsset('retro_overlay', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); slowTimeEffectOverlay.alpha = 0.22; game.addChild(slowTimeEffectOverlay); } } if (ptype === 'autoAim') { // No immediate effect, handled in shooting logic } if (ptype === 'doubleBarrel') { // No immediate effect, handled in shooting logic } // Set timeout to deactivate if (powerupTimeouts[ptype]) LK.clearTimeout(powerupTimeouts[ptype]); powerupTimeouts[ptype] = LK.setTimeout(function () { powerupActive[ptype] = false; powerupTimers[ptype] = 0; hidePowerupIcon(ptype); if (ptype === 'slowTime') { // Restore duck speed for (var i = 0; i < ducks.length; i++) { ducks[i].speed = ducks[i].speed / 0.35; } // Remove overlay if (slowTimeEffectOverlay && slowTimeEffectOverlay.parent) { slowTimeEffectOverlay.parent.removeChild(slowTimeEffectOverlay); slowTimeEffectOverlay = null; } } }, duration * 1000); } // Show power-up icon in GUI function showPowerupIcon(ptype, duration) { var iconId = ptype === 'doubleBarrel' ? 'powerup_double' : ptype === 'slowTime' ? 'powerup_slow' : 'powerup_auto'; var icon = LK.getAsset(iconId, { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); icon.scaleX = icon.scaleY = 1.1; var timerTxt = new Text2(duration + "s", { size: 60, fill: 0xffffff }); timerTxt.anchor.set(0.5, 0.5); icon.addChild(timerTxt); powerupIcons[ptype] = icon; // Place icons in top left, but not in 0-100px (menu area) var idx = ptype === 'doubleBarrel' ? 0 : ptype === 'slowTime' ? 1 : 2; icon.x = 120 + idx * 120; icon.y = 120; LK.gui.top.addChild(icon); icon._timerTxt = timerTxt; } // Hide power-up icon function hidePowerupIcon(ptype) { if (powerupIcons[ptype] && powerupIcons[ptype].parent) { powerupIcons[ptype].parent.removeChild(powerupIcons[ptype]); powerupIcons[ptype] = null; } } // Game state variables var ducks = []; var bullets = []; var level = 1; var ducksPerLevel = 5; var ducksToHit = 0; var ducksHit = 0; var ducksEscaped = 0; var maxBullets = 3; var bulletsLeft = 3; var timeLimit = 15; // seconds var timeLeft = 15; var gameActive = false; var waveActive = false; // Per-mode high score storage var highScoreClassic = storage.highScoreClassic || 0; var highScoreTimeAttack = storage.highScoreTimeAttack || 0; var highScoreEndless = storage.highScoreEndless || 0; var highScore = 0; // Will be set per mode in showMainMenu/startLevel var score = 0; var dog = null; var crosshair = null; var timerInterval = null; var levelText = null; var scoreText = null; var timerText = null; var bulletIcons = []; var waveResultTimeout = null; // Track missed shots for warning var missedShots = 0; var missedWarningShown = false; // --- Power-up State --- var powerupActive = { doubleBarrel: false, slowTime: false, autoAim: false }; var powerupTimers = { doubleBarrel: 0, slowTime: 0, autoAim: 0 }; var powerupIcons = { doubleBarrel: null, slowTime: null, autoAim: null }; var powerupTimeouts = { doubleBarrel: null, slowTime: null, autoAim: null }; // For slow time effect var slowTimeEffectOverlay = null; // --- Game Mode State --- var GAME_MODE_CLASSIC = "classic"; var GAME_MODE_TIMEATTACK = "timeattack"; var GAME_MODE_ENDLESS = "endless"; var gameMode = null; // Set by menu var mainMenuContainer = null; var endlessMissStreak = 0; var endlessGameOver = false; // --- Dog Selection State --- var DOG_OPTIONS = [{ id: "dodo", name: "Dodo", asset: "dog", laugh: "dog_laugh" }, { id: "kaiser", name: "Kaiser", asset: "dog_dalmatian", laugh: "laugh_d" }, { id: "maki", name: "Maki", asset: "dog_labrador", laugh: "laugh_l" }]; var selectedDogId = "dodo"; // default dog // Background var bg = LK.getAsset('bg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(bg); // --- Main Menu UI --- function showMainMenu() { // Remove previous menu if present if (mainMenuContainer && mainMenuContainer.parent) { mainMenuContainer.parent.removeChild(mainMenuContainer); } mainMenuContainer = new Container(); // Dim background var menuBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 16, scaleY: 16, x: 2048 / 2, y: 2732 / 2 }); menuBg.alpha = 0.85; mainMenuContainer.addChild(menuBg); // Title var title = new Text2("What The Duck", { size: 220, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); title.anchor.set(0.5, 0); title.x = 2048 / 2; title.y = 400; mainMenuContainer.addChild(title); // Classic Mode Button var btnClassic = new Text2("Classic Mode", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnClassic.anchor.set(0.5, 0.5); btnClassic.x = 2048 / 2; btnClassic.y = 900; mainMenuContainer.addChild(btnClassic); // Time Attack Button var btnTime = new Text2("Time Attack", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnTime.anchor.set(0.5, 0.5); btnTime.x = 2048 / 2; btnTime.y = 1100; mainMenuContainer.addChild(btnTime); // Endless Mode Button var btnEndless = new Text2("Endless Mode", { size: 120, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnEndless.anchor.set(0.5, 0.5); btnEndless.x = 2048 / 2; btnEndless.y = 1300; mainMenuContainer.addChild(btnEndless); // Rules Button var btnRules = new Text2("Rules", { size: 100, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnRules.anchor.set(0.5, 0.5); btnRules.x = 2048 / 2; btnRules.y = 1450; mainMenuContainer.addChild(btnRules); // Instructions var info = new Text2("Choose a mode to start!", { size: 80, fill: 0xFFFFFF, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); info.anchor.set(0.5, 0.5); info.x = 2048 / 2; info.y = 1550; mainMenuContainer.addChild(info); // --- Rules Popup --- var rulesPopup = null; function showRulesPopup() { if (rulesPopup && rulesPopup.parent) rulesPopup.parent.removeChild(rulesPopup); rulesPopup = new Container(); var popupBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10, x: 2048 / 2, y: 2732 / 2 }); popupBg.alpha = 0.96; rulesPopup.addChild(popupBg); var rulesTitle = new Text2("Game Rules", { size: 120, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); rulesTitle.anchor.set(0.5, 0); rulesTitle.x = 2048 / 2; rulesTitle.y = 400; rulesPopup.addChild(rulesTitle); var rulesText = new Text2("Classic Mode:\n" + "- Hit enough ducks with limited bullets to advance.\n" + "- Each level has more ducks and bullets.\n\n" + "Time Attack:\n" + "- 30 seconds to hit as many ducks as possible.\n" + "- Unlimited bullets.\n\n" + "Endless Mode:\n" + "- Ducks spawn forever, unlimited bullets.\n" + "- Game ends if you miss 3 times in a row.\n\n" + "Duck Types:\n" + "- Golden Duck: Fast, +50 points.\n" + "- Armored Duck: Needs 2 hits.\n" + "- Mini Fast Duck: Small, fast, +25 points.\n\n" + "Power-ups:\n" + "- Double Barrel: Hit 2 ducks at once.\n" + "- Slow Time: Ducks move slowly for 5s.\n" + "- Auto-Aim: Instantly hit nearest duck for 3s.\n\n" + "Tap power-up icons to collect. Good luck!", { size: 60, fill: 0xFF2222, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma", wordWrap: true, wordWrapWidth: 1600, align: "left" }); rulesText.anchor.set(0.5, 0); rulesText.x = 2048 / 2; rulesText.y = 550; rulesPopup.addChild(rulesText); var btnClose = new Text2("Close", { size: 100, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnClose.anchor.set(0.5, 0.5); btnClose.x = 2048 / 2; btnClose.y = 2300; btnClose.interactive = true; btnClose.down = function () { if (rulesPopup.parent) rulesPopup.parent.removeChild(rulesPopup); }; rulesPopup.addChild(btnClose); game.addChild(rulesPopup); } // Button handlers // --- Dog Select Screen --- function showDogSelectScreen() { // Remove previous menu if present if (mainMenuContainer && mainMenuContainer.parent) { mainMenuContainer.parent.removeChild(mainMenuContainer); } mainMenuContainer = new Container(); // Dim background var menuBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 16, scaleY: 16, x: 2048 / 2, y: 2732 / 2 }); menuBg.alpha = 0.85; mainMenuContainer.addChild(menuBg); // Title var title = new Text2("Select Your Dog", { size: 180, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); title.anchor.set(0.5, 0); title.x = 2048 / 2; title.y = 400; mainMenuContainer.addChild(title); // Dog options var spacing = 600; var startX = 2048 / 2 - spacing; var y = 1100; for (var i = 0; i < DOG_OPTIONS.length; i++) { (function (i) { var dogOpt = DOG_OPTIONS[i]; var asset = LK.getAsset(dogOpt.asset, { anchorX: 0.5, anchorY: 1, x: startX + i * spacing, y: y }); asset.scaleX = asset.scaleY = 1.1; mainMenuContainer.addChild(asset); var nameTxt = new Text2(dogOpt.name, { size: 100, fill: 0xFFFFFF, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); nameTxt.anchor.set(0.5, 0); nameTxt.x = asset.x; nameTxt.y = y + 30; mainMenuContainer.addChild(nameTxt); // Make asset interactive asset.interactive = true; asset.down = function () { selectedDogId = dogOpt.id; if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer); startLevel(); }; nameTxt.interactive = true; nameTxt.down = asset.down; })(i); } // Back button var btnBack = new Text2("Back", { size: 90, fill: 0xFFD700, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); btnBack.anchor.set(0.5, 0.5); btnBack.x = 2048 / 2; btnBack.y = 2100; btnBack.interactive = true; btnBack.down = function () { if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer); showMainMenu(); }; mainMenuContainer.addChild(btnBack); game.addChild(mainMenuContainer); } // Mode buttons now show dog select screen btnClassic.interactive = true; btnClassic.down = function () { gameMode = GAME_MODE_CLASSIC; showDogSelectScreen(); }; btnTime.interactive = true; btnTime.down = function () { gameMode = GAME_MODE_TIMEATTACK; showDogSelectScreen(); }; btnEndless.interactive = true; btnEndless.down = function () { gameMode = GAME_MODE_ENDLESS; showDogSelectScreen(); }; btnRules.interactive = true; btnRules.down = function () { showRulesPopup(); }; // Add to game game.addChild(mainMenuContainer); } // Show menu on load showMainMenu(); // Dog dog = new Dog(); game.addChild(dog); // Achievement popup (always on top) var achievementPopup = new AchievementPopup(); game.addChild(achievementPopup); // Crosshair crosshair = LK.getAsset('crosshair', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); crosshair.visible = false; game.addChild(crosshair); // GUI: Level, Score, Timer, Bullets levelText = new Text2('Level 1', { size: 90, fill: 0xFFF000 }); levelText.anchor.set(1, 0); // right align to match high score scoreText = new Text2('Score: 0', { size: 90, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); timerText = new Text2('Time: 15', { size: 90, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // High Score UI // Set highScore based on mode (default to classic) if (gameMode === GAME_MODE_TIMEATTACK) { highScore = highScoreTimeAttack; } else if (gameMode === GAME_MODE_ENDLESS) { highScore = highScoreEndless; } else { highScore = highScoreClassic; } var highScoreText = new Text2('High: ' + highScore, { size: 70, fill: 0xFFD700 }); highScoreText.anchor.set(1, 0); // Place high score in top right LK.gui.topRight.addChild(highScoreText); // Place level text directly under high score text in top right LK.gui.topRight.addChild(levelText); // Position GUI // Position GUI scoreText.x = 2048 / 2; timerText.x = 2048 * 3 / 4; highScoreText.x = 0; highScoreText.y = 0; levelText.x = 0; levelText.y = highScoreText.height + 10; // 10px gap below high score // Responsive UI: adjust font size and icon size for mobile function resizeUI() { var w = LK.width || 2048; var h = LK.height || 2732; var scale = Math.min(w / 2048, h / 2732); if (scoreText && scoreText.style) scoreText.style.size = 90 * scale; if (timerText && timerText.style) timerText.style.size = 90 * scale; if (highScoreText && highScoreText.style) highScoreText.style.size = 70 * scale; if (levelText && levelText.style) levelText.style.size = 90 * scale; for (var i = 0; i < bulletIcons.length; i++) { bulletIcons[i].scaleX = bulletIcons[i].scaleY = scale; } } LK.on('resize', resizeUI); resizeUI(); // Bullets GUI (now under the level text in the top right) // Show both bullet icons (bottom) and a text counter (top right under level) var bulletCountText = null; var bulletLabelText = null; function updateBulletIcons() { // Remove old icons for (var i = 0; i < bulletIcons.length; i++) { if (bulletIcons[i].parent) bulletIcons[i].parent.removeChild(bulletIcons[i]); } bulletIcons = []; // Draw new icons (up to 10 for visual clarity, then show text) var maxIcons = Math.min(10, bulletsLeft); // Center the icons under the screen var iconSpacing = 60; var totalWidth = (maxIcons - 1) * iconSpacing; var startX = 2048 / 2 - totalWidth / 2; for (var i = 0; i < maxIcons; i++) { var icon = LK.getAsset('bullet_icon', { anchorX: 0.5, anchorY: 0.5, x: startX + i * iconSpacing, y: 2732 - 120 }); LK.gui.bottom.addChild(icon); bulletIcons.push(icon); } // Remove old text if present if (bulletCountText && bulletCountText.parent) { bulletCountText.parent.removeChild(bulletCountText); } if (bulletLabelText && bulletLabelText.parent) { bulletLabelText.parent.removeChild(bulletLabelText); } // Add "Bullets" label above the count, now in top right under level bulletLabelText = new Text2("Bullets", { size: 60, fill: 0xFFF000, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); bulletLabelText.anchor.set(1, 0); // right align, top anchor bulletLabelText.x = 0; bulletLabelText.y = levelText.y + levelText.height + 10; LK.gui.topRight.addChild(bulletLabelText); // Show bullet count as text (always, for clarity) bulletCountText = new Text2("" + bulletsLeft, { size: 90, fill: 0xFFF000, font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma" }); bulletCountText.anchor.set(1, 0); // right align, top anchor bulletCountText.x = 0; bulletCountText.y = bulletLabelText.y + bulletLabelText.height + 2; LK.gui.topRight.addChild(bulletCountText); } // Start a new level function startLevel() { ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; missedShots = 0; missedWarningShown = false; endlessMissStreak = 0; endlessGameOver = false; // --- Mode-specific setup --- if (gameMode === GAME_MODE_CLASSIC || !gameMode) { // Set ducksPerLevel and ducksToHit per level as per requirements if (level === 1) { ducksPerLevel = 6; ducksToHit = 3; } else if (level === 2) { ducksPerLevel = 12; ducksToHit = 6; } else if (level === 3) { ducksPerLevel = 20; ducksToHit = 12; } else if (level === 4) { ducksPerLevel = 30; ducksToHit = 18; } else if (level === 5) { ducksPerLevel = 40; ducksToHit = 20; } else { ducksPerLevel = Math.min(25, 15 + (level - 5) * 2); ducksToHit = Math.ceil(ducksPerLevel * 0.7); } // Set bulletsLeft per level: 10 for level 1, +10 bullets for every other level if (level === 1) { bulletsLeft = 10; } else if (level === 2) { bulletsLeft = 15 + 10; } else if (level === 3) { bulletsLeft = 20 + 10; } else if (level === 4) { bulletsLeft = 30 + 10; } else if (level === 5) { bulletsLeft = 32 + 10; } else { bulletsLeft = 32 + 2 * (level - 5) + 10; } maxBullets = bulletsLeft; timeLimit = Math.max(8, 15 - (level - 1)); timeLeft = timeLimit; levelText.setText('Level ' + level); } else if (gameMode === GAME_MODE_TIMEATTACK) { // 30 seconds, infinite ducks, infinite bullets, score = ducks hit ducksPerLevel = 99999; ducksToHit = 0; bulletsLeft = 99999; maxBullets = bulletsLeft; timeLimit = 30; timeLeft = 30; levelText.setText('Time Attack'); } else if (gameMode === GAME_MODE_ENDLESS) { // Infinite ducks, infinite bullets, game ends on 3 misses in a row ducksPerLevel = 99999; ducksToHit = 0; bulletsLeft = 99999; maxBullets = bulletsLeft; timeLimit = 99999; timeLeft = 99999; levelText.setText('Endless'); } // Set highScore for current mode if (gameMode === GAME_MODE_TIMEATTACK) { highScore = highScoreTimeAttack; } else if (gameMode === GAME_MODE_ENDLESS) { highScore = highScoreEndless; } else { highScore = highScoreClassic; } highScoreText.setText('High: ' + highScore); gameActive = true; waveActive = true; updateBulletIcons(); scoreText.setText('Score: ' + score); timerText.setText('Time: ' + timeLeft); // Duck spawn schedule and speed per level/mode var duckSpawnTimer = null; var ducksSpawned = 0; var ducksAtOnce = 1; var duckSpawnInterval = 3000; var duckSpeedMin = 2; var duckSpeedMax = 3.5; if (gameMode === GAME_MODE_CLASSIC || !gameMode) { if (level === 1) { ducksAtOnce = 1; duckSpawnInterval = 3000; duckSpeedMin = 2; duckSpeedMax = 3.5; } else if (level === 2) { ducksAtOnce = 1; duckSpawnInterval = 2000; duckSpeedMin = 3.5; duckSpeedMax = 5; } else if (level === 3) { ducksAtOnce = 2; duckSpawnInterval = 1800; duckSpeedMin = 4.2; duckSpeedMax = 5.8; } else if (level === 4) { ducksAtOnce = 3; duckSpawnInterval = 1500; duckSpeedMin = 5.5; duckSpeedMax = 7.2; } else if (level === 5) { ducksAtOnce = 4; duckSpawnInterval = 1200; duckSpeedMin = 6.5; duckSpeedMax = 8.5; } else { ducksAtOnce = 5; duckSpawnInterval = 1000; duckSpeedMin = 7.5 + (level - 5) * 0.5; duckSpeedMax = 9.5 + (level - 5) * 0.7; } } else if (gameMode === GAME_MODE_TIMEATTACK) { ducksAtOnce = 2; duckSpawnInterval = 900; duckSpeedMin = 4.5; duckSpeedMax = 7.5; } else if (gameMode === GAME_MODE_ENDLESS) { ducksAtOnce = 2; duckSpawnInterval = 900; duckSpeedMin = 4.5; duckSpeedMax = 7.5; } // Clear any previous duck spawn timer if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } ducksSpawned = 0; // Function to spawn ducks and power-ups function spawnDucks() { if (!gameActive || !waveActive) return; if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && ducksSpawned >= ducksPerLevel) { if (duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } return; } var ducksThisWave = gameMode === GAME_MODE_CLASSIC || !gameMode ? Math.min(ducksAtOnce, ducksPerLevel - ducksSpawned) : ducksAtOnce; for (var d = 0; d < ducksThisWave; d++) { var duck = new Duck(); // Randomize start edge: 0=left, 1=right, 2=bottom var edge = Math.floor(Math.random() * 3); var startX, startY, angle; if (edge === 0) { // left startX = -60; startY = 400 + Math.random() * (2732 - 800); angle = Math.random() * Math.PI / 3 - Math.PI / 6; // -30 to +30 deg } else if (edge === 1) { // right startX = 2048 + 60; startY = 400 + Math.random() * (2732 - 800); angle = Math.PI + (Math.random() * Math.PI / 3 - Math.PI / 6); // 150 to 210 deg } else { // bottom startX = 200 + Math.random() * (2048 - 400); startY = 2732 + 60; angle = -Math.PI / 2 + (Math.random() * Math.PI / 4 - Math.PI / 8); // -67 to -23 deg } duck.x = startX; duck.y = startY; duck.angle = angle; // Set duck speed and size based on type if (duck.type === 'golden') { duck.speed = duckSpeedMax + 2 + Math.random() * 1.5; } else if (duck.type === 'armored') { duck.speed = duckSpeedMin + Math.random() * (duckSpeedMax - duckSpeedMin) * 0.7; } else if (duck.type === 'mini') { duck.speed = duckSpeedMax + 1 + Math.random() * 1.2; duck.scaleX = duck.scaleY = 0.6 + Math.random() * 0.2; } else if (duck.type === 'fast') { duck.speed = duckSpeedMax + 0.7 + Math.random() * 0.7; } else { duck.speed = duckSpeedMin + Math.random() * (duckSpeedMax - duckSpeedMin); } ducks.push(duck); // Always add ducks above background and below crosshair/dog/UI game.addChild(duck); // Move dog and crosshair to top of display list if present if (dog && dog.parent) { dog.parent.removeChild(dog); game.addChild(dog); } if (crosshair && crosshair.parent) { crosshair.parent.removeChild(crosshair); game.addChild(crosshair); } LK.getSound('duck_fly').play(); ducksSpawned++; } // --- Power-up spawn logic --- // Power-ups can appear randomly (1 in 7 chance per spawn, but not if already active) if (Math.random() < 1 / 7) { var availablePowerups = []; if (!powerupActive.doubleBarrel) availablePowerups.push('doubleBarrel'); if (!powerupActive.slowTime) availablePowerups.push('slowTime'); if (!powerupActive.autoAim) availablePowerups.push('autoAim'); if (availablePowerups.length > 0) { var which = availablePowerups[Math.floor(Math.random() * availablePowerups.length)]; spawnPowerupCollectible(which); } } } spawnDucks(); // Spawn first batch immediately if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && ducksPerLevel > ducksAtOnce) { duckSpawnTimer = LK.setInterval(spawnDucks, duckSpawnInterval); } else if (gameMode === GAME_MODE_TIMEATTACK || gameMode === GAME_MODE_ENDLESS) { duckSpawnTimer = LK.setInterval(spawnDucks, duckSpawnInterval); } // Start timer if (timerInterval) LK.clearInterval(timerInterval); timerInterval = LK.setInterval(function () { if (!gameActive) return; if (gameMode === GAME_MODE_TIMEATTACK) { timeLeft--; timerText.setText('Time: ' + timeLeft); if (timeLeft <= 0) { endWave(); } } else if (gameMode === GAME_MODE_CLASSIC || !gameMode) { timeLeft--; timerText.setText('Time: ' + timeLeft); if (timeLeft <= 0) { endWave(); } } else if (gameMode === GAME_MODE_ENDLESS) { // No timer, but show "โ" or running time timerText.setText('Endless'); } }, 1000); } // End wave: check results, show dog if needed, advance or game over function endWave() { if (!waveActive) return; waveActive = false; gameActive = false; if (timerInterval) LK.clearInterval(timerInterval); // Remove remaining ducks for (var i = 0; i < ducks.length; i++) { if (ducks[i].parent) ducks[i].parent.removeChild(ducks[i]); } ducks = []; // --- Classic Mode --- if (gameMode === GAME_MODE_CLASSIC || !gameMode) { // Show dog if not enough ducks hit if (ducksHit < ducksToHit) { dog.laugh(2048 / 2, 2732 - 100); LK.effects.flashScreen(0xff0000, 800); // Show final score on Game Over LK.setTimeout(function () { var finalScoreText = new Text2('Final Score: ' + score, { size: 120, fill: 0xFFFF00 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); LK.showGameOver(); }, 900); }, 400); // Game over after laugh waveResultTimeout = LK.setTimeout(function () { // handled above }, 1300); } else { // Advance to next level after short pause LK.effects.flashObject(levelText, 0x00ff00, 700); LK.setTimeout(function () { var finalScoreText = new Text2('Score: ' + score, { size: 120, fill: 0x00FF00 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); level++; startLevel(); }, 700); }, 200); } } // --- Time Attack Mode --- else if (gameMode === GAME_MODE_TIMEATTACK) { // Show final score and return to menu LK.effects.flashScreen(0x00ffcc, 800); LK.setTimeout(function () { var finalScoreText = new Text2('Ducks Hit: ' + ducksHit, { size: 120, fill: 0x00FFCC }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); showMainMenu(); }, 1400); }, 400); } // --- Endless Mode --- else if (gameMode === GAME_MODE_ENDLESS) { endlessGameOver = true; LK.effects.flashScreen(0xff2222, 800); LK.setTimeout(function () { var finalScoreText = new Text2('Ducks Hit: ' + ducksHit, { size: 120, fill: 0xFF2222 }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2; finalScoreText.y = 2732 / 2; game.addChild(finalScoreText); LK.setTimeout(function () { if (finalScoreText.parent) finalScoreText.parent.removeChild(finalScoreText); showMainMenu(); }, 1400); }, 400); } } // Handle tap/click to shoot game.down = function (x, y, obj) { if (!gameActive || !waveActive) return; // --- Power-up collectible check --- for (var i = powerupCollectibles.length - 1; i >= 0; i--) { var p = powerupCollectibles[i]; if (p.isHit(x, y)) { activatePowerup(p.type); if (p.parent) p.parent.removeChild(p); powerupCollectibles.splice(i, 1); LK.effects.flashObject(p, 0xffffff, 300); LK.getSound('hit').play(); return; } } // --- Bullets check --- if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && bulletsLeft <= 0) { LK.getSound('miss').play(); LK.effects.flashScreen(0x888888, 200); // Show reload animation (flash bullet icons red) for (var i = 0; i < bulletIcons.length; i++) { LK.effects.flashObject(bulletIcons[i], 0xff2222, 300); } // Optionally play reload sound if available // LK.getSound('reload').play(); return; } // Only decrement bullets and allow shooting if bulletsLeft > 0 (classic) if (gameMode === GAME_MODE_CLASSIC || !gameMode) { bulletsLeft--; updateBulletIcons(); if (bulletCountText && bulletCountText.setText) { bulletCountText.setText("Bullets: " + bulletsLeft); } // If bullets reach zero after this shot, trigger game over immediately if (bulletsLeft === 0) { LK.setTimeout(function () { LK.showGameOver(); }, 400); // short delay to allow last shot/crosshair to animate return; } } LK.getSound('shoot').play(); // Show crosshair at tap crosshair.x = x; crosshair.y = y; crosshair.visible = true; tween(crosshair, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { crosshair.visible = false; crosshair.alpha = 1; } }); // --- Power-up shooting logic --- // Auto-Aim: instantly hit nearest duck if (powerupActive.autoAim) { var nearestDuck = null; var minDist = 99999; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; nearestDuck = duck; } } if (nearestDuck) { // Hit the duck nearestDuck.hit = true; nearestDuck.fall(function () { if (nearestDuck.parent) nearestDuck.parent.removeChild(nearestDuck); if (dog) { dog.show(nearestDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; var duckScore = 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (typeof nearestDuck.type !== "undefined" && nearestDuck.type === 'golden') { duckScore = 50; achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(nearestDuck, 0xffe066, 400); } else { LK.effects.flashObject(nearestDuck, 0xffff00, 300); } // Headshot bonus (auto-aim never headshots) score += duckScore; LK.getSound('hit').play(); if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } // End wave check var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } return; } } // Double Barrel: shoot a wide spread, hit up to 2 ducks if close if (powerupActive.doubleBarrel) { var hitDucks = []; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var dist = Math.sqrt(dx * dx + dy * dy); var hitRadius = typeof duck.getHitboxRadius === "function" ? duck.getHitboxRadius() * 1.5 : 120; if (dist < hitRadius) { hitDucks.push({ duck: duck, dist: dist }); } } // Sort by distance, hit up to 2 closest hitDucks.sort(function (a, b) { return a.dist - b.dist; }); hitDucks = hitDucks.slice(0, 2); if (hitDucks.length > 0) { for (var h = 0; h < hitDucks.length; h++) { var hitDuck = hitDucks[h].duck; hitDuck.hit = true; hitDuck.fall(function () { if (hitDuck.parent) hitDuck.parent.removeChild(hitDuck); if (dog) { dog.show(hitDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; var duckScore = 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (typeof hitDuck.type !== "undefined" && hitDuck.type === 'golden') { duckScore = 50; achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(hitDuck, 0xffe066, 400); } else { LK.effects.flashObject(hitDuck, 0xffff00, 300); } // Headshot bonus var isHeadshot = typeof hitDuck.isHeadshot === "function" && hitDuck.isHeadshot(x, y); if (isHeadshot) { duckScore += 5; achievementMsg = 'Headshot! +' + duckScore; achievementColor = 0xFF2222; LK.effects.flashObject(hitDuck, 0xff2222, 400); } score += duckScore; LK.getSound('hit').play(); if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } } // End wave check var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } return; } } // --- Normal shooting logic --- // Check if a duck is hit (closest duck under tap, not already hit) var hitDuck = null; var minDist = 99999; for (var i = 0; i < ducks.length; i++) { var duck = ducks[i]; // Only allow hitting ducks that are alive and not hit yet if (!duck.alive || duck.hit) continue; var dx = duck.x - x; var dy = duck.y - y; var hitRadius = typeof duck.getHitboxRadius === "function" ? duck.getHitboxRadius() : 80; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < hitRadius && dist < minDist) { minDist = dist; hitDuck = duck; } } if (hitDuck) { // Armored duck: needs 2 hits if (hitDuck.type === 'armored' && hitDuck.armor > 1) { hitDuck.armor--; hitDuck.flashRed(); LK.effects.flashObject(hitDuck, 0xff2222, 200); LK.getSound('hit').play(); // No score yet, must hit again return; } // Mark duck as hit and start fall animation hitDuck.hit = true; hitDuck.fall(function () { if (hitDuck.parent) hitDuck.parent.removeChild(hitDuck); if (dog) { dog.show(hitDuck.x, 2732 - 100); LK.getSound('dog_laugh').play(); LK.setTimeout(function () { dog.hide(); }, 2000); } }); ducksHit++; // Score system: use DUCK_TYPE_POINTS if (typeof score === "undefined") score = 0; var duckScore = DUCK_TYPE_POINTS[hitDuck.type] || 10; var achievementMsg = ''; var achievementColor = 0xFFD700; if (hitDuck.type === 'golden') { achievementMsg = 'Golden Duck! +50'; achievementColor = 0xFFD700; LK.effects.flashObject(hitDuck, 0xffe066, 400); } else if (hitDuck.type === 'armored') { achievementMsg = 'Armored Duck! +20'; achievementColor = 0x888888; LK.effects.flashObject(hitDuck, 0xcccccc, 400); } else if (hitDuck.type === 'mini') { achievementMsg = 'Mini Fast Duck! +25'; achievementColor = 0x00e6ff; LK.effects.flashObject(hitDuck, 0x00e6ff, 350); } else { LK.effects.flashObject(hitDuck, 0xffff00, 300); } // Headshot bonus var isHeadshot = typeof hitDuck.isHeadshot === "function" && hitDuck.isHeadshot(x, y); if (isHeadshot) { duckScore += 5; achievementMsg = 'Headshot! +' + duckScore; achievementColor = 0xFF2222; LK.effects.flashObject(hitDuck, 0xff2222, 400); } score += duckScore; LK.getSound('hit').play(); // Show achievement popup if any if (typeof achievementPopup !== "undefined" && achievementMsg) { achievementPopup.show(achievementMsg, achievementColor); } // Triple hit achievement (3 ducks in 1 level) if (ducksHit === 3 && typeof achievementPopup !== "undefined") { achievementPopup.show('Triple Hit!', 0x00FFCC); } // Sharp shooter (all ducks hit) if (ducksHit === ducksToHit && typeof achievementPopup !== "undefined") { achievementPopup.show('Sharp Shooter!', 0x00FF00); } // Update high score if needed if (score > highScore) { highScore = score; if (gameMode === GAME_MODE_TIMEATTACK) { highScoreTimeAttack = highScore; storage.highScoreTimeAttack = highScore; } else if (gameMode === GAME_MODE_ENDLESS) { highScoreEndless = highScore; storage.highScoreEndless = highScore; } else { highScoreClassic = highScore; storage.highScoreClassic = highScore; } if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } scoreText.setText('Score: ' + score); if (score > highScore) { highScore = score; storage.highScore = highScore; if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } } // Endless mode: reset miss streak if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak = 0; } } else { // Miss: do nothing to ducks, just play miss sound and flash LK.getSound('miss').play(); LK.effects.flashScreen(0x888888, 120); // Track missed shots and show warning after 20 misses missedShots++; if (missedShots >= 20 && !missedWarningShown) { missedWarningShown = true; if (typeof achievementPopup !== "undefined") { achievementPopup.show("Careful! 20 missed shots!", 0xFF2222); } } // Endless mode: increment miss streak, end game if 3 in a row if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak++; if (endlessMissStreak >= 3) { endWave(); return; } } } // If all ducks are gone or out of bullets, end wave (classic only) var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } // Only end wave if all ducks are gone AND no more ducks will spawn, or if out of bullets if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && (aliveDucks === 0 && bulletsLeft === 0 || aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0))) { endWave(); } }; // Move handler for crosshair (optional, for desktop) game.move = function (x, y, obj) { // Optionally show crosshair following finger/mouse // crosshair.x = x; // crosshair.y = y; }; // Main update loop game.update = function () { if (!gameActive || !waveActive) return; // Update ducks for (var i = ducks.length - 1; i >= 0; i--) { var duck = ducks[i]; duck.update(); if (duck.escaped && !duck.hit) { ducksEscaped++; if (duck.parent) duck.parent.removeChild(duck); ducks.splice(i, 1); // Endless mode: treat escaped duck as a miss if (gameMode === GAME_MODE_ENDLESS) { endlessMissStreak++; if (endlessMissStreak >= 3) { endWave(); return; } } } } // --- Power-up collectibles update --- for (var i = powerupCollectibles.length - 1; i >= 0; i--) { powerupCollectibles[i].update(); } // --- Power-up timers/icons update --- for (var ptype in powerupActive) { if (powerupActive[ptype] && powerupTimers[ptype] > 0) { // Decrement timer (per second, but update is 60fps) if (LK.ticks % 60 === 0) { powerupTimers[ptype]--; if (powerupIcons[ptype] && powerupIcons[ptype]._timerTxt) { powerupIcons[ptype]._timerTxt.setText(powerupTimers[ptype] + "s"); } } } } // If all ducks gone, end wave (classic only) var aliveDucks = 0; for (var i = 0; i < ducks.length; i++) { if (ducks[i].alive) aliveDucks++; } if ((gameMode === GAME_MODE_CLASSIC || !gameMode) && aliveDucks === 0 && typeof duckSpawnTimer !== "undefined" && (!duckSpawnTimer || ducks.length === 0)) { endWave(); } }; // On game over, reset everything LK.on('gameover', function () { if (timerInterval) LK.clearInterval(timerInterval); if (waveResultTimeout) LK.clearTimeout(waveResultTimeout); if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } gameActive = false; waveActive = false; level = 1; ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; // Reset bullets to 10 on gameover for level 1 bulletsLeft = 10; score = 0; updateBulletIcons(); levelText.setText('Level 1'); scoreText.setText('Score: ' + score); // Reset highScore to current mode's high score on gameover if (gameMode === GAME_MODE_TIMEATTACK) { highScore = highScoreTimeAttack; } else if (gameMode === GAME_MODE_ENDLESS) { highScore = highScoreEndless; } else { highScore = highScoreClassic; } if (typeof highScoreText !== "undefined") { highScoreText.setText('High: ' + highScore); } timerText.setText('Time: 15'); if (dog) dog.hide(); // Show main menu after short delay LK.setTimeout(function () { showMainMenu(); }, 1200); }); // On you win (if you want to add a win condition, e.g. after level 10) LK.on('youwin', function () { if (timerInterval) LK.clearInterval(timerInterval); if (waveResultTimeout) LK.clearTimeout(waveResultTimeout); if (typeof duckSpawnTimer !== "undefined" && duckSpawnTimer) { LK.clearInterval(duckSpawnTimer); duckSpawnTimer = null; } gameActive = false; waveActive = false; // Show win, then reset LK.setTimeout(function () { level = 1; ducks = []; bullets = []; ducksHit = 0; ducksEscaped = 0; bulletsLeft = 10; score = 0; updateBulletIcons(); levelText.setText('Level 1'); scoreText.setText('Score: ' + score); // Reset highScore to current mode's high score on youwin if (gameMode === GAME_MODE_TIMEATTACK) { highScore = highScoreTimeAttack; } else if (gameMode === GAME_MODE_ENDLESS) { highScore = highScoreEndless; } else { highScore = highScoreClassic; } timerText.setText('Time: 15'); if (dog) dog.hide(); showMainMenu(); }, 1800); }); // Start music LK.playMusic('bgm', { fade: { start: 0, end: 0.5, duration: 1200 } }); // Start first level // (Removed: now handled by showMainMenu)
===================================================================
--- original.js
+++ change.js
@@ -41,38 +41,50 @@
});
// Dog class
var Dog = Container.expand(function () {
var self = Container.call(this);
- // Helper to get current character info
- function getChar() {
- for (var i = 0; i < CHARACTER_LIST.length; i++) {
- if (CHARACTER_LIST[i].key === selectedCharacterKey) return CHARACTER_LIST[i];
+ self.dogAsset = null;
+ self.laughAsset = null;
+ self.currentDogId = null;
+ // Helper to set dog asset based on selectedDogId
+ self.setDogAssets = function () {
+ // Remove old assets if any
+ if (self.dogAsset && self.dogAsset.parent) self.removeChild(self.dogAsset);
+ if (self.laughAsset && self.laughAsset.parent) self.removeChild(self.laughAsset);
+ self.dogAsset = null;
+ self.laughAsset = null;
+ var dogOpt = null;
+ for (var i = 0; i < DOG_OPTIONS.length; i++) {
+ if (DOG_OPTIONS[i].id === selectedDogId) {
+ dogOpt = DOG_OPTIONS[i];
+ break;
+ }
}
- return CHARACTER_LIST[0];
- }
- var _char = getChar();
- var dogAsset = self.attachAsset(_char.asset, {
- anchorX: 0.5,
- anchorY: 1
- });
- self.visible = false;
- // Show dog at (x, y)
- self.show = function (x, y) {
- // Update asset if character changed
- var _char2 = getChar();
- if (dogAsset && dogAsset.parent) self.removeChild(dogAsset);
- dogAsset = self.attachAsset(_char2.asset, {
+ if (!dogOpt) dogOpt = DOG_OPTIONS[0];
+ self.currentDogId = dogOpt.id;
+ self.dogAsset = self.attachAsset(dogOpt.asset, {
anchorX: 0.5,
anchorY: 1
});
+ self.dogAsset.visible = false;
+ // Laugh asset will be created on demand in laugh()
+ };
+ self.setDogAssets();
+ self.visible = false;
+ // Show dog at (x, y)
+ self.show = function (x, y) {
+ // If dog changed, update assets
+ if (self.currentDogId !== selectedDogId) {
+ self.setDogAssets();
+ }
self.x = x;
self.y = y;
self.visible = true;
- dogAsset.visible = true;
+ if (self.dogAsset) self.dogAsset.visible = true;
if (self.laughAsset) self.laughAsset.visible = false;
// Optionally, you could add a little "pop up" animation here
// For example, tween the dog from below the screen to y
- var startY = 2732 + dogAsset.height;
+ var startY = 2732 + (self.dogAsset ? self.dogAsset.height : 180);
self.y = startY;
tween(self, {
y: y
}, {
@@ -81,35 +93,51 @@
});
};
// Hide dog
self.hide = function () {
- // Animate dog going down before hiding
- var endY = 2732 + (dogAsset.height || 180);
+ var endY = 2732 + (self.dogAsset ? self.dogAsset.height : 180);
tween(self, {
y: endY
}, {
duration: 350,
easing: tween.cubicIn,
onFinish: function onFinish() {
self.visible = false;
- dogAsset.visible = false;
+ if (self.dogAsset) self.dogAsset.visible = false;
}
});
};
// Show laugh animation
self.laugh = function (x, y) {
- var _char3 = getChar();
+ // If dog changed, update assets
+ if (self.currentDogId !== selectedDogId) {
+ self.setDogAssets();
+ }
self.x = x;
self.y = y;
self.visible = true;
- dogAsset.visible = false;
- if (self.laughAsset && self.laughAsset.parent) self.removeChild(self.laughAsset);
- self.laughAsset = self.attachAsset(_char3.laugh, {
- anchorX: 0.5,
- anchorY: 1
- });
+ if (self.dogAsset) self.dogAsset.visible = false;
+ // Find laugh asset id for this dog
+ var dogOpt = null;
+ for (var i = 0; i < DOG_OPTIONS.length; i++) {
+ if (DOG_OPTIONS[i].id === selectedDogId) {
+ dogOpt = DOG_OPTIONS[i];
+ break;
+ }
+ }
+ if (!dogOpt) dogOpt = DOG_OPTIONS[0];
+ var laughId = dogOpt.laugh || "dog_laugh";
+ if (!self.laughAsset || self.laughAsset._assetId !== laughId) {
+ if (self.laughAsset && self.laughAsset.parent) self.removeChild(self.laughAsset);
+ self.laughAsset = self.attachAsset(laughId, {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.laughAsset._assetId = laughId;
+ }
self.laughAsset.visible = true;
- LK.getSound(_char3.laughSound).play();
+ // Play laugh sound (use default for all)
+ LK.getSound('dog_laugh').play();
// Hide after 1.2s
LK.setTimeout(function () {
self.laughAsset.visible = false;
self.hide();
@@ -487,44 +515,34 @@
autoAim: null
};
// For slow time effect
var slowTimeEffectOverlay = null;
-// --- Character Selection State ---
-var CHARACTER_LIST = [{
- key: "dodo",
- name: "Dodo",
- asset: "dog",
- laugh: "dog_laugh",
- laughSound: "laugh"
-}, {
- key: "kaiser",
- name: "Kaiser",
- asset: "dog_labrador",
- laugh: "dog_laugh",
- laughSound: "laugh_l"
-}, {
- key: "maki",
- name: "Maki",
- asset: "dog_dalmatian",
- laugh: "dog_laugh",
- laughSound: "laugh_d"
-}];
-var selectedCharacterKey = storage.selectedCharacterKey || "dodo";
-var selectedCharacter = CHARACTER_LIST[0];
-for (var i = 0; i < CHARACTER_LIST.length; i++) {
- if (CHARACTER_LIST[i].key === selectedCharacterKey) {
- selectedCharacter = CHARACTER_LIST[i];
- break;
- }
-}
// --- Game Mode State ---
var GAME_MODE_CLASSIC = "classic";
var GAME_MODE_TIMEATTACK = "timeattack";
var GAME_MODE_ENDLESS = "endless";
var gameMode = null; // Set by menu
var mainMenuContainer = null;
var endlessMissStreak = 0;
var endlessGameOver = false;
+// --- Dog Selection State ---
+var DOG_OPTIONS = [{
+ id: "dodo",
+ name: "Dodo",
+ asset: "dog",
+ laugh: "dog_laugh"
+}, {
+ id: "kaiser",
+ name: "Kaiser",
+ asset: "dog_dalmatian",
+ laugh: "laugh_d"
+}, {
+ id: "maki",
+ name: "Maki",
+ asset: "dog_labrador",
+ laugh: "laugh_l"
+}];
+var selectedDogId = "dodo"; // default dog
// Background
var bg = LK.getAsset('bg', {
anchorX: 0,
anchorY: 0,
@@ -589,27 +607,17 @@
btnEndless.anchor.set(0.5, 0.5);
btnEndless.x = 2048 / 2;
btnEndless.y = 1300;
mainMenuContainer.addChild(btnEndless);
- // Select Mode Button
- var btnSelectMode = new Text2("Select Mode", {
- size: 100,
- fill: 0xFFD700,
- font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
- });
- btnSelectMode.anchor.set(0.5, 0.5);
- btnSelectMode.x = 2048 / 2;
- btnSelectMode.y = 1450;
- mainMenuContainer.addChild(btnSelectMode);
// Rules Button
var btnRules = new Text2("Rules", {
size: 100,
fill: 0xFFFFFF,
font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
btnRules.anchor.set(0.5, 0.5);
btnRules.x = 2048 / 2;
- btnRules.y = 1550;
+ btnRules.y = 1450;
mainMenuContainer.addChild(btnRules);
// Instructions
var info = new Text2("Choose a mode to start!", {
size: 80,
@@ -671,177 +679,108 @@
rulesPopup.addChild(btnClose);
game.addChild(rulesPopup);
}
// Button handlers
- btnClassic.interactive = true;
- btnClassic.down = function () {
- gameMode = GAME_MODE_CLASSIC;
- if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer);
- startLevel();
- };
- btnTime.interactive = true;
- btnTime.down = function () {
- gameMode = GAME_MODE_TIMEATTACK;
- if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer);
- startLevel();
- };
- btnEndless.interactive = true;
- btnEndless.down = function () {
- gameMode = GAME_MODE_ENDLESS;
- if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer);
- startLevel();
- };
- btnRules.interactive = true;
- btnRules.down = function () {
- showRulesPopup();
- };
- // --- Character Selection Popup ---
- var charSelectPopup = null;
- function showCharacterSelectPopup() {
- if (charSelectPopup && charSelectPopup.parent) charSelectPopup.parent.removeChild(charSelectPopup);
- charSelectPopup = new Container();
- var popupBg = LK.getAsset('centerCircle', {
+ // --- Dog Select Screen ---
+ function showDogSelectScreen() {
+ // Remove previous menu if present
+ if (mainMenuContainer && mainMenuContainer.parent) {
+ mainMenuContainer.parent.removeChild(mainMenuContainer);
+ }
+ mainMenuContainer = new Container();
+ // Dim background
+ var menuBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
- scaleX: 10,
- scaleY: 10,
+ scaleX: 16,
+ scaleY: 16,
x: 2048 / 2,
y: 2732 / 2
});
- popupBg.alpha = 0.96;
- charSelectPopup.addChild(popupBg);
- var title = new Text2("Select Your Character", {
- size: 120,
+ menuBg.alpha = 0.85;
+ mainMenuContainer.addChild(menuBg);
+ // Title
+ var title = new Text2("Select Your Dog", {
+ size: 180,
fill: 0xFFD700,
font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
- title.y = 500;
- charSelectPopup.addChild(title);
- // Character previews
- var charNodes = [];
- var selectedIdx = 0;
- for (var i = 0; i < CHARACTER_LIST.length; i++) {
- var _char4 = CHARACTER_LIST[i];
- var cx = 2048 / 2 + (i - 1) * 420;
- var cy = 1200;
- var charContainer = new Container();
- // Character image
- var charImg = LK.getAsset(_char4.asset, {
- anchorX: 0.5,
- anchorY: 1,
- x: cx,
- y: cy
- });
- charImg.scaleX = charImg.scaleY = 1.2;
- charContainer.addChild(charImg);
- // Name label
- var nameLabel = new Text2(_char4.name, {
- size: 80,
- fill: 0xFFFFFF,
- font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
- });
- nameLabel.anchor.set(0.5, 0);
- nameLabel.x = cx;
- nameLabel.y = cy + 30;
- charContainer.addChild(nameLabel);
- // Highlight if selected
- if (_char4.key === selectedCharacterKey) {
- var highlight = LK.getAsset('centerCircle', {
+ title.y = 400;
+ mainMenuContainer.addChild(title);
+ // Dog options
+ var spacing = 600;
+ var startX = 2048 / 2 - spacing;
+ var y = 1100;
+ for (var i = 0; i < DOG_OPTIONS.length; i++) {
+ (function (i) {
+ var dogOpt = DOG_OPTIONS[i];
+ var asset = LK.getAsset(dogOpt.asset, {
anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 2.2,
- scaleY: 1.2,
- x: cx,
- y: cy - charImg.height / 2
+ anchorY: 1,
+ x: startX + i * spacing,
+ y: y
});
- highlight.alpha = 0.18;
- highlight.tint = 0xFFD700;
- charContainer.addChildAt(highlight, 0);
- selectedIdx = i;
- }
- // Idle animation: gentle up-down
- (function (img) {
- var baseY = img.y;
- tween(img, {
- y: baseY + 30
- }, {
- duration: 900,
- yoyo: true,
- repeat: Infinity,
- easing: tween.sineInOut
+ asset.scaleX = asset.scaleY = 1.1;
+ mainMenuContainer.addChild(asset);
+ var nameTxt = new Text2(dogOpt.name, {
+ size: 100,
+ fill: 0xFFFFFF,
+ font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
- })(charImg);
- // Click to select
- charContainer.interactive = true;
- (function (idx, key) {
- charContainer.down = function () {
- // Remove all highlights
- for (var j = 0; j < charNodes.length; j++) {
- if (charNodes[j].highlight && charNodes[j].highlight.parent) {
- charNodes[j].highlight.parent.removeChild(charNodes[j].highlight);
- }
- }
- // Add highlight to this
- var highlight = LK.getAsset('centerCircle', {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 2.2,
- scaleY: 1.2,
- x: cx,
- y: cy - charImg.height / 2
- });
- highlight.alpha = 0.18;
- highlight.tint = 0xFFD700;
- charContainer.addChildAt(highlight, 0);
- charContainer.highlight = highlight;
- selectedIdx = idx;
+ nameTxt.anchor.set(0.5, 0);
+ nameTxt.x = asset.x;
+ nameTxt.y = y + 30;
+ mainMenuContainer.addChild(nameTxt);
+ // Make asset interactive
+ asset.interactive = true;
+ asset.down = function () {
+ selectedDogId = dogOpt.id;
+ if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer);
+ startLevel();
};
- })(i, _char4.key);
- charContainer.highlight = null;
- charNodes.push(charContainer);
- charSelectPopup.addChild(charContainer);
+ nameTxt.interactive = true;
+ nameTxt.down = asset.down;
+ })(i);
}
- // Confirm button
- var btnConfirm = new Text2("Confirm", {
- size: 100,
+ // Back button
+ var btnBack = new Text2("Back", {
+ size: 90,
fill: 0xFFD700,
font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
- btnConfirm.anchor.set(0.5, 0.5);
- btnConfirm.x = 2048 / 2;
- btnConfirm.y = 2000;
- btnConfirm.interactive = true;
- btnConfirm.down = function () {
- // Save selection
- selectedCharacterKey = CHARACTER_LIST[selectedIdx].key;
- selectedCharacter = CHARACTER_LIST[selectedIdx];
- storage.selectedCharacterKey = selectedCharacterKey;
- if (charSelectPopup.parent) charSelectPopup.parent.removeChild(charSelectPopup);
+ btnBack.anchor.set(0.5, 0.5);
+ btnBack.x = 2048 / 2;
+ btnBack.y = 2100;
+ btnBack.interactive = true;
+ btnBack.down = function () {
+ if (mainMenuContainer.parent) mainMenuContainer.parent.removeChild(mainMenuContainer);
+ showMainMenu();
};
- charSelectPopup.addChild(btnConfirm);
- // Close button
- var btnClose = new Text2("Close", {
- size: 80,
- fill: 0xFFD700,
- font: "'PressStart2P','GillSans-Bold',Impact,'Arial Black',Tahoma"
- });
- btnClose.anchor.set(0.5, 0.5);
- btnClose.x = 2048 / 2;
- btnClose.y = 2200;
- btnClose.interactive = true;
- btnClose.down = function () {
- if (charSelectPopup.parent) charSelectPopup.parent.removeChild(charSelectPopup);
- };
- charSelectPopup.addChild(btnClose);
- game.addChild(charSelectPopup);
+ mainMenuContainer.addChild(btnBack);
+ game.addChild(mainMenuContainer);
}
- // Button handler for Select Mode
- btnSelectMode.interactive = true;
- btnSelectMode.down = function () {
- showCharacterSelectPopup();
+ // Mode buttons now show dog select screen
+ btnClassic.interactive = true;
+ btnClassic.down = function () {
+ gameMode = GAME_MODE_CLASSIC;
+ showDogSelectScreen();
};
+ btnTime.interactive = true;
+ btnTime.down = function () {
+ gameMode = GAME_MODE_TIMEATTACK;
+ showDogSelectScreen();
+ };
+ btnEndless.interactive = true;
+ btnEndless.down = function () {
+ gameMode = GAME_MODE_ENDLESS;
+ showDogSelectScreen();
+ };
+ btnRules.interactive = true;
+ btnRules.down = function () {
+ showRulesPopup();
+ };
// Add to game
game.addChild(mainMenuContainer);
}
// Show menu on load
@@ -975,15 +914,8 @@
LK.gui.topRight.addChild(bulletCountText);
}
// Start a new level
function startLevel() {
- // Update selectedCharacter from storage (in case changed)
- for (var i = 0; i < CHARACTER_LIST.length; i++) {
- if (CHARACTER_LIST[i].key === selectedCharacterKey) {
- selectedCharacter = CHARACTER_LIST[i];
- break;
- }
- }
ducks = [];
bullets = [];
ducksHit = 0;
ducksEscaped = 0;
bullet. In-Game asset. 2d. High contrast. No shadows
crosshair. In-Game asset. 2d. High contrast. No shadows
pixart jungle. In-Game asset. 2d. High contrast. No shadows
pixart hunting brown dog with black ears and white mouth holding a gun. In-Game asset. 2d. High contrast. No shadows
pixart brown hunting dog with black ears and white mouth laughing. In-Game asset. 2d. High contrast. No shadows
pixart blue duck flying. In-Game asset. 2d. High contrast. No shadows
pixart green duck flying. In-Game asset. 2d. High contrast. No shadows
pixart red duck flying. In-Game asset. 2d. High contrast. No shadows
pigeon flying. In-Game asset. 2d. High contrast. No shadows
black wall. In-Game asset. 2d. High contrast. No shadows
empty beer glass. In-Game asset. 2d. High contrast. No shadows
pixart sand watch. In-Game asset. 2d. High contrast. No shadows
dalmation dog holding a gun. In-Game asset. 2d. High contrast. No shadows. hunting
labrador dog hold a hunt gun. In-Game asset. 2d. High contrast. No shadows
dalmatian dog laugh. In-Game asset. 2d. High contrast. No shadows
labrador laugh. In-Game asset. 2d. High contrast. No shadows