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
});
self.width = monsterSprite.width;
self.height = monsterSprite.height;
// Movement direction
self.vx = 0;
self.vy = 0;
self.speed = 3 + Math.random() * 2;
// 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) {
// 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
@@ -441,14 +441,27 @@
var walkToActive = false;
var walkToX = 0;
var walkToY = 0;
var walkToSpeed = 22;
-// Double-tap detection for hero
-var lastHeroTapTime = 0;
-var heroTapTimeout = 350; // ms, max interval for double tap
-var lastHeroTapX = 0;
-var lastHeroTapY = 0;
-var heroDoubleTapRadius = 120; // px, max distance between taps
+// 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
@@ -466,38 +479,33 @@
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) {
- // Double-tap detection
- var now = Date.now();
- var tapDist = Math.sqrt((x - lastHeroTapX) * (x - lastHeroTapX) + (y - lastHeroTapY) * (y - lastHeroTapY));
- if (now - lastHeroTapTime < heroTapTimeout && tapDist < heroDoubleTapRadius) {
- // Double-tap detected on hero!
- // 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);
- }
+ // 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) {
+ // 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);
}
- // Reset tap time to avoid triple tap
- lastHeroTapTime = 0;
- } else {
- // Not a double-tap, store tap info
- lastHeroTapTime = now;
- lastHeroTapX = x;
- lastHeroTapY = y;
}
+ 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;
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