User prompt
If our character stands in front of a skeleton, let the skeleton stand still.
User prompt
If our character encounters a skeleton, the skeleton should stay where it is.
User prompt
No skeleton spawn where our character is born
User prompt
The kill button should appear when you get close to the skeleton.
User prompt
Sword swinging is currently buggy, when you click once there should be a very short waiting time and the sword should not rotate around itself continuously. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add sword swing effect ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Skeletons have a very large hitbox and move very fast.
User prompt
Adjust skeletons hitbox properly
User prompt
character can kill monster with kill button not with double click
User prompt
If the character can kill all the skeletons he can open the chest
User prompt
add key and chest and door must open with key
User prompt
give the character a sword
User prompt
If the character double clicks, he can damage the skeletons.
User prompt
make a start screen
User prompt
player can walk with mouse
Code edit (1 edits merged)
Please save this source code
User prompt
Dungeon Dash
Initial prompt
make me a dungeon type game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Chest class var Chest = Container.expand(function () { var self = Container.call(this); // Attach chest asset (brown box) var chestSprite = self.attachAsset('chest', { anchorX: 0.5, anchorY: 0.5 }); self.width = chestSprite.width; self.height = chestSprite.height; self.opened = false; return self; }); // Door class (for next room) var Door = Container.expand(function () { var self = Container.call(this); // Attach door asset (purple box) var doorSprite = self.attachAsset('door', { anchorX: 0.5, anchorY: 0.5 }); self.width = doorSprite.width; self.height = doorSprite.height; return self; }); // Hero class var Hero = Container.expand(function () { var self = Container.call(this); // Attach hero asset (red box) var heroSprite = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.width = heroSprite.width; self.height = heroSprite.height; // Attach sword to hero var swordSprite = self.attachAsset('sword', { anchorX: 0.5, anchorY: 0.5 }); swordSprite.x = heroSprite.width * 0.3; // Position sword to the right of hero swordSprite.y = 0; // Center vertically with hero swordSprite.rotation = Math.PI / 4; // Angle the sword slightly // Hero stats self.maxHealth = 3; self.health = self.maxHealth; self.invincible = false; self.invincibleTimer = 0; // Flash when hit self.flash = function () { tween(heroSprite, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { tween(heroSprite, { tint: 0xd83318 }, { duration: 200 }); } }); }; // Take damage self.takeDamage = function () { if (self.invincible) return; self.health -= 1; self.flash(); self.invincible = true; self.invincibleTimer = 60; // 1 second at 60fps LK.effects.flashObject(self, 0xff0000, 300); updateHealthDisplay(); if (self.health <= 0) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } }; // Heal self.heal = function () { if (self.health < self.maxHealth) { self.health += 1; updateHealthDisplay(); LK.effects.flashObject(self, 0x83de44, 300); } }; // Called every tick self.update = function () { if (self.invincible) { self.invincibleTimer--; if (self.invincibleTimer <= 0) { self.invincible = false; } } }; return self; }); /**** * Asset Initialization ****/ // Hero: red box // Monster: green ellipse // Trap: yellow box // Treasure: blue ellipse // Door: purple box // Key class var Key = Container.expand(function () { var self = Container.call(this); // Attach key asset (gold ellipse) var keySprite = self.attachAsset('key', { anchorX: 0.5, anchorY: 0.5 }); self.width = keySprite.width; self.height = keySprite.height; return self; }); // Monster class var Monster = Container.expand(function () { var self = Container.call(this); // Attach monster asset (green ellipse) var monsterSprite = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5 }); // Set much smaller hitbox for more accurate collision detection self.width = monsterSprite.width * 0.3; self.height = monsterSprite.height * 0.3; // Movement direction self.vx = 0; self.vy = 0; self.speed = 1 + Math.random() * 1; // Set random direction self.setRandomDirection = function () { var angle = Math.random() * Math.PI * 2; self.vx = Math.cos(angle) * self.speed; self.vy = Math.sin(angle) * self.speed; }; self.setRandomDirection(); // Called every tick self.update = function () { self.x += self.vx; self.y += self.vy; // Bounce off room walls if (self.x < roomBounds.x + self.width / 2) { self.x = roomBounds.x + self.width / 2; self.vx *= -1; } if (self.x > roomBounds.x + roomBounds.width - self.width / 2) { self.x = roomBounds.x + roomBounds.width - self.width / 2; self.vx *= -1; } if (self.y < roomBounds.y + self.height / 2) { self.y = roomBounds.y + self.height / 2; self.vy *= -1; } if (self.y > roomBounds.y + roomBounds.height - self.height / 2) { self.y = roomBounds.y + roomBounds.height - self.height / 2; self.vy *= -1; } }; return self; }); // Trap class var Trap = Container.expand(function () { var self = Container.call(this); // Attach trap asset (yellow box) var trapSprite = self.attachAsset('trap', { anchorX: 0.5, anchorY: 0.5 }); self.width = trapSprite.width; self.height = trapSprite.height; return self; }); // Treasure class var Treasure = Container.expand(function () { var self = Container.call(this); // Attach treasure asset (blue ellipse) var treasureSprite = self.attachAsset('treasure', { anchorX: 0.5, anchorY: 0.5 }); self.width = treasureSprite.width; self.height = treasureSprite.height; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Tween plugin for animations // --- Start Screen Overlay --- var startScreenOverlay = new Container(); startScreenOverlay.zIndex = 10000; // ensure on top // Title var titleText = new Text2("Dungeon Dash", { size: 180, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 900; startScreenOverlay.addChild(titleText); // Subtitle var subtitleText = new Text2("Drag or tap to move. Collect treasures. Avoid monsters & traps!", { size: 70, fill: 0xB8B031 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 1100; startScreenOverlay.addChild(subtitleText); // Play Button var playBtnWidth = 600; var playBtnHeight = 180; var playBtn = LK.getAsset('door', { width: playBtnWidth, height: playBtnHeight, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1500 }); startScreenOverlay.addChild(playBtn); var playBtnText = new Text2("PLAY", { size: 120, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); playBtnText.anchor.set(0.5, 0.5); playBtnText.x = 2048 / 2; playBtnText.y = 1500; startScreenOverlay.addChild(playBtnText); // Add overlay to game game.addChild(startScreenOverlay); // Block game input until started var gameStarted = false; // Start game handler function startGame() { if (gameStarted) return; gameStarted = true; startScreenOverlay.visible = false; } // Listen for tap/click on play button startScreenOverlay.down = function (x, y, obj) { // Check if tap is inside play button var local = playBtn.toLocal(startScreenOverlay.toGlobal({ x: x, y: y })); if (local.x > -playBtnWidth / 2 && local.x < playBtnWidth / 2 && local.y > -playBtnHeight / 2 && local.y < playBtnHeight / 2) { startGame(); } }; // Intercept all input until game started var oldGameDown = game.down; game.down = function (x, y, obj) { if (!gameStarted) { if (typeof startScreenOverlay.down === "function") startScreenOverlay.down(x, y, obj); return; } if (typeof oldGameDown === "function") oldGameDown(x, y, obj); }; var oldGameMove = game.move; game.move = function (x, y, obj) { if (!gameStarted) return; if (typeof oldGameMove === "function") oldGameMove(x, y, obj); }; var oldGameUp = game.up; game.up = function (x, y, obj) { if (!gameStarted) return; if (typeof oldGameUp === "function") oldGameUp(x, y, obj); }; // Room bounds (centered, with margin) var roomMargin = 120; var roomBounds = { x: roomMargin, y: roomMargin + 100, // leave top 100px for menu width: 2048 - roomMargin * 2, height: 2732 - roomMargin * 2 - 100 }; // Game state var hero; var monsters = []; var traps = []; var treasures = []; var door; var keys = []; var chests = []; var hasKey = false; var draggingHero = false; var lastMoveX = 0, lastMoveY = 0; var currentRoom = 1; var maxRooms = 5; var treasuresCollected = 0; var monstersDefeated = 0; var roomCleared = false; // GUI elements var scoreTxt = new Text2('Score: 0', { size: 90, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var healthTxt = new Text2('♥♥♥', { size: 90, fill: 0xFF4444 }); healthTxt.anchor.set(0.5, 0); LK.gui.top.addChild(healthTxt); healthTxt.y = 100; // Helper to update health display function updateHealthDisplay() { var hearts = ''; for (var i = 0; i < hero.maxHealth; i++) { hearts += i < hero.health ? '♥' : '♡'; } healthTxt.setText(hearts); } // Helper to update score display function updateScoreDisplay() { var score = treasuresCollected * 10 + monstersDefeated * 5; scoreTxt.setText('Score: ' + score); } // Helper to clear room function clearRoom() { for (var i = 0; i < monsters.length; i++) monsters[i].destroy(); for (var i = 0; i < traps.length; i++) traps[i].destroy(); for (var i = 0; i < treasures.length; i++) treasures[i].destroy(); for (var i = 0; i < keys.length; i++) keys[i].destroy(); for (var i = 0; i < chests.length; i++) chests[i].destroy(); monsters = []; traps = []; treasures = []; keys = []; chests = []; if (door) { door.destroy(); door = null; } roomCleared = false; hasKey = false; } // Helper to generate a room function generateRoom(roomNum) { clearRoom(); // Place hero at entrance (bottom center) hero.x = roomBounds.x + roomBounds.width / 2; hero.y = roomBounds.y + roomBounds.height - hero.height; // Place monsters var monsterCount = 2 + roomNum; for (var i = 0; i < monsterCount; i++) { var m = new Monster(); m.x = roomBounds.x + 100 + Math.random() * (roomBounds.width - 200); m.y = roomBounds.y + 200 + Math.random() * (roomBounds.height - 400); monsters.push(m); game.addChild(m); } // Place traps var trapCount = 1 + Math.floor(roomNum / 2); for (var i = 0; i < trapCount; i++) { var t = new Trap(); t.x = roomBounds.x + 100 + Math.random() * (roomBounds.width - 200); t.y = roomBounds.y + 200 + Math.random() * (roomBounds.height - 400); traps.push(t); game.addChild(t); } // Place treasures var treasureCount = 1 + Math.floor(roomNum / 2); for (var i = 0; i < treasureCount; i++) { var tr = new Treasure(); tr.x = roomBounds.x + 100 + Math.random() * (roomBounds.width - 200); tr.y = roomBounds.y + 200 + Math.random() * (roomBounds.height - 400); treasures.push(tr); game.addChild(tr); } // Place key (always one per room) var k = new Key(); k.x = roomBounds.x + 100 + Math.random() * (roomBounds.width - 200); k.y = roomBounds.y + 200 + Math.random() * (roomBounds.height - 400); keys.push(k); game.addChild(k); // Place chest (always one per room) var c = new Chest(); c.x = roomBounds.x + 100 + Math.random() * (roomBounds.width - 200); c.y = roomBounds.y + 200 + Math.random() * (roomBounds.height - 400); chests.push(c); game.addChild(c); // Place door (top center) door = new Door(); door.x = roomBounds.x + roomBounds.width / 2; door.y = roomBounds.y + door.height / 2; game.addChild(door); door.visible = false; // Only show when room is cleared roomCleared = false; } // Create hero hero = new Hero(); game.addChild(hero); updateHealthDisplay(); // Start first room generateRoom(currentRoom); updateScoreDisplay(); // Dragging logic game.down = function (x, y, obj) { // Only start drag if touch is on hero var local = hero.toLocal(game.toGlobal({ x: x, y: y })); if (local.x > -hero.width / 2 && local.x < hero.width / 2 && local.y > -hero.height / 2 && local.y < hero.height / 2) { draggingHero = true; lastMoveX = x; lastMoveY = y; } }; game.up = function (x, y, obj) { draggingHero = false; }; function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Walk-to destination variables var walkToActive = false; var walkToX = 0; var walkToY = 0; var walkToSpeed = 22; // Kill button for attacking monsters var killButton = LK.getAsset('trap', { width: 200, height: 200, anchorX: 0.5, anchorY: 0.5, x: 2048 - 150, y: 2732 - 150 }); game.addChild(killButton); var killButtonText = new Text2("KILL", { size: 60, fill: "#fff", font: "Impact, Arial Black, Tahoma" }); killButtonText.anchor.set(0.5, 0.5); killButtonText.x = 2048 - 150; killButtonText.y = 2732 - 150; game.addChild(killButtonText); // Move handler game.move = function (x, y, obj) { if (draggingHero) { // Clamp hero inside room bounds var hx = clamp(x, roomBounds.x + hero.width / 2, roomBounds.x + roomBounds.width - hero.width / 2); var hy = clamp(y, roomBounds.y + hero.height / 2, roomBounds.y + roomBounds.height - hero.height / 2); hero.x = hx; hero.y = hy; walkToActive = false; // Cancel walk-to if dragging } }; // Tap-to-walk logic: on down, if not on hero, set walk-to destination var oldGameDown = game.down; game.down = function (x, y, obj) { // Only start drag if touch is on hero var local = hero.toLocal(game.toGlobal({ x: x, y: y })); // Check if kill button was tapped var killButtonLocal = killButton.toLocal(game.toGlobal({ x: x, y: y })); if (killButtonLocal.x > -killButton.width / 2 && killButtonLocal.x < killButton.width / 2 && killButtonLocal.y > -killButton.height / 2 && killButtonLocal.y < killButton.height / 2) { // Get sword sprite from hero for animation var swordSprite = hero.children[1]; // Sword is the second child (index 1) // Create sword swing effect var originalRotation = swordSprite.rotation; tween(swordSprite, { rotation: originalRotation + Math.PI / 2 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(swordSprite, { rotation: originalRotation }, { duration: 200, easing: tween.easeIn }); } }); // Kill button tapped - damage all monsters within 350px of hero for (var i = monsters.length - 1; i >= 0; i--) { var m = monsters[i]; var dx = hero.x - m.x; var dy = hero.y - m.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 350) { // Remove monster m.destroy(); monsters.splice(i, 1); monstersDefeated++; updateScoreDisplay(); // Optional: flash monster or hero for feedback LK.effects.flashObject(hero, 0xffffff, 120); } } return; // Don't process other touch logic } if (local.x > -hero.width / 2 && local.x < hero.width / 2 && local.y > -hero.height / 2 && local.y < hero.height / 2) { draggingHero = true; lastMoveX = x; lastMoveY = y; walkToActive = false; } else { // Set walk-to destination if tap is inside room var hx = clamp(x, roomBounds.x + hero.width / 2, roomBounds.x + roomBounds.width - hero.width / 2); var hy = clamp(y, roomBounds.y + hero.height / 2, roomBounds.y + roomBounds.height - hero.height / 2); walkToX = hx; walkToY = hy; walkToActive = true; } if (typeof oldGameDown === "function") oldGameDown(x, y, obj); }; // In update, move hero toward walk-to destination if active var oldGameUpdate = game.update; game.update = function () { // Walk-to logic if (walkToActive && !draggingHero) { var dx = walkToX - hero.x; var dy = walkToY - hero.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > walkToSpeed) { hero.x += dx / dist * walkToSpeed; hero.y += dy / dist * walkToSpeed; } else { hero.x = walkToX; hero.y = walkToY; walkToActive = false; } } if (typeof oldGameUpdate === "function") oldGameUpdate(); }; // Main update loop game.update = function () { if (!gameStarted) return; // Update hero hero.update(); // Update monsters for (var i = 0; i < monsters.length; i++) { monsters[i].update(); } // Check collisions: hero vs monsters for (var i = monsters.length - 1; i >= 0; i--) { var m = monsters[i]; if (hero.intersects(m)) { hero.takeDamage(); // Knockback var dx = hero.x - m.x; var dy = hero.y - m.y; var dist = Math.sqrt(dx * dx + dy * dy) || 1; hero.x += dx / dist * 60; hero.y += dy / dist * 60; // Remove monster m.destroy(); monsters.splice(i, 1); monstersDefeated++; updateScoreDisplay(); } } // Check collisions: hero vs traps for (var i = 0; i < traps.length; i++) { var t = traps[i]; if (hero.intersects(t)) { hero.takeDamage(); // Move hero away from trap var dx = hero.x - t.x; var dy = hero.y - t.y; var dist = Math.sqrt(dx * dx + dy * dy) || 1; hero.x += dx / dist * 40; hero.y += dy / dist * 40; } } // Check collisions: hero vs treasures for (var i = treasures.length - 1; i >= 0; i--) { var tr = treasures[i]; if (hero.intersects(tr)) { tr.destroy(); treasures.splice(i, 1); treasuresCollected++; updateScoreDisplay(); hero.heal(); } } // Check collisions: hero vs keys for (var i = keys.length - 1; i >= 0; i--) { var k = keys[i]; if (hero.intersects(k)) { k.destroy(); keys.splice(i, 1); hasKey = true; LK.effects.flashObject(hero, 0xFFD700, 300); } } // Check collisions: hero vs chests for (var i = 0; i < chests.length; i++) { var c = chests[i]; if (hero.intersects(c) && (hasKey || monsters.length === 0) && !c.opened) { c.opened = true; hasKey = false; LK.effects.flashObject(c, 0x83de44, 600); // Add treasure from chest treasuresCollected += 2; updateScoreDisplay(); } } // Room clear check if (!roomCleared && monsters.length === 0 && chests.length > 0 && chests[0].opened) { roomCleared = true; door.visible = true; LK.effects.flashObject(door, 0x83de44, 600); } // Check hero at door to next room if (roomCleared && door && hero.intersects(door)) { if (currentRoom < maxRooms) { currentRoom++; generateRoom(currentRoom); } else { // Win! LK.setScore(treasuresCollected * 10 + monstersDefeated * 5); LK.showYouWin(); } } };
===================================================================
--- original.js
+++ change.js
@@ -486,8 +486,26 @@
x: x,
y: y
}));
if (killButtonLocal.x > -killButton.width / 2 && killButtonLocal.x < killButton.width / 2 && killButtonLocal.y > -killButton.height / 2 && killButtonLocal.y < killButton.height / 2) {
+ // Get sword sprite from hero for animation
+ var swordSprite = hero.children[1]; // Sword is the second child (index 1)
+ // Create sword swing effect
+ var originalRotation = swordSprite.rotation;
+ tween(swordSprite, {
+ rotation: originalRotation + Math.PI / 2
+ }, {
+ duration: 150,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(swordSprite, {
+ rotation: originalRotation
+ }, {
+ duration: 200,
+ easing: tween.easeIn
+ });
+ }
+ });
// Kill button tapped - damage all monsters within 350px of hero
for (var i = monsters.length - 1; i >= 0; i--) {
var m = monsters[i];
var dx = hero.x - m.x;
dungeon door. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
png
dungeon hero sword. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dungeon key. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dungeon chest. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dungeon demon. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dungeon wizard. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a mage who throws fireballs. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
big dungeon snake. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a spider. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat