User prompt
ghost moves 10% faster
User prompt
ghost moves in random directions
User prompt
each puzzle opens a door
User prompt
add one puzzle to each level
User prompt
spawn puzzle
User prompt
make four rooms with each different shape and size but combined together
User prompt
set floor5 as level
User prompt
rooms are horizontal
User prompt
add rooms to this level
User prompt
when I get out of the door move me to one floor down
User prompt
show floor in the upper middle
User prompt
name this level as floor 6
User prompt
open door when unlocked
User prompt
unlock door when puzzle solved
User prompt
remove the key asset
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'destroy')' in or related to this line: 'keyObj.destroy();' Line Number: 440
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'destroy')' in or related to this line: 'keyObj.destroy();' Line Number: 438
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'destroy')' in or related to this line: 'keyObj.destroy();' Line Number: 436
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'destroy')' in or related to this line: 'keyObj.destroy();' Line Number: 436
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'destroy')' in or related to this line: 'keyObj.destroy();' Line Number: 434
Code edit (1 edits merged)
Please save this source code
User prompt
Haunted Floors: Escape the House
Initial prompt
ı want to build a horror game that takes place in a house with multiple stories (floors) and we see the rooms from the top
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Door class
var Door = Container.expand(function () {
	var self = Container.call(this);
	self.locked = true;
	self.doorAsset = self.attachAsset('door_locked', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.unlock = function () {
		self.locked = false;
		self.doorAsset.destroy();
		self.doorAsset = self.attachAsset('door_unlocked', {
			anchorX: 0.5,
			anchorY: 0.5
		});
	};
	return self;
});
// Enemy (ghost) class
var Ghost = Container.expand(function () {
	var self = Container.call(this);
	self.attachAsset('ghost', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 4;
	self.direction = 1; // 1: right, -1: left
	self.update = function () {
		self.x += self.speed * self.direction;
		// Bounce off walls (simple horizontal patrol)
		if (self.x < 300) self.direction = 1;
		if (self.x > 2048 - 300) self.direction = -1;
	};
	return self;
});
// Player class
var Player = Container.expand(function () {
	var self = Container.call(this);
	self.asset = self.attachAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.canMove = true;
	self.moveTo = function (x, y) {
		if (!self.canMove) return;
		// Clamp to game area
		var px = Math.max(60, Math.min(2048 - 60, x));
		var py = Math.max(60, Math.min(2732 - 60, y));
		self.x = px;
		self.y = py;
	};
	return self;
});
// Puzzle class
var Puzzle = Container.expand(function () {
	var self = Container.call(this);
	self.solved = false;
	self.attachAsset('puzzle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	return self;
});
// Wall class
var Wall = Container.expand(function () {
	var self = Container.call(this);
	var wallAsset = self.attachAsset('wall', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isSolid = true;
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181818
});
/**** 
* Game Code
****/ 
// Enemy (ghost)
// Puzzle object
// Key
// Door (unlocked)
// Door (locked)
// Wall
// Player
// --- Game State ---
var currentFloor = 0; // 0: ground, 1: upstairs
var floors = [];
var player;
var dragPlayer = false;
var lastPlayerPos = {
	x: 0,
	y: 0
};
var keyObj = null;
var doorObj = null;
var puzzleObj = null;
var ghostObj = null;
var messageTxt = null;
var floorTxt = null;
var puzzleSolved = false;
var gameOver = false;
// --- Room/Floor Layouts ---
function createFloor0() {
	// Floor 6: Two rooms, each with their own walls, connected by a door in the middle
	var floor = {
		walls: [],
		doors: [],
		keys: [],
		puzzles: [],
		enemies: []
	};
	// --- Room 1 (top) ---
	// Left wall (vertical)
	var wallLeft1 = new Wall();
	wallLeft1.x = 300;
	wallLeft1.y = 683; // 2048/3
	wallLeft1.width = 60;
	wallLeft1.height = 800;
	floor.walls.push(wallLeft1);
	// Right wall (vertical, with a gap for the connecting door)
	var wallRight1a = new Wall();
	wallRight1a.x = 1024;
	wallRight1a.y = 400;
	wallRight1a.width = 900;
	wallRight1a.height = 60;
	floor.walls.push(wallRight1a);
	// Top wall (horizontal)
	var wallTop1 = new Wall();
	wallTop1.x = 683; // center of top room
	wallTop1.y = 100;
	wallTop1.width = 1400;
	wallTop1.height = 60;
	floor.walls.push(wallTop1);
	// Bottom wall (horizontal, with a gap for the connecting door)
	var wallBottom1a = new Wall();
	wallBottom1a.x = 683;
	wallBottom1a.y = 950;
	wallBottom1a.width = 900;
	wallBottom1a.height = 60;
	floor.walls.push(wallBottom1a);
	// --- Room 2 (bottom) ---
	// Left wall (vertical, with a gap for the connecting door)
	var wallLeft2a = new Wall();
	wallLeft2a.x = 300;
	wallLeft2a.y = 2048 - 683;
	wallLeft2a.width = 60;
	wallLeft2a.height = 900;
	floor.walls.push(wallLeft2a);
	// Right wall (vertical)
	var wallRight2 = new Wall();
	wallRight2.x = 2048 - 300;
	wallRight2.y = 2048 - 683;
	wallRight2.width = 60;
	wallRight2.height = 800;
	floor.walls.push(wallRight2);
	// Top wall (horizontal, with a gap for the connecting door)
	var wallTop2a = new Wall();
	wallTop2a.x = 1365;
	wallTop2a.y = 1098;
	wallTop2a.width = 900;
	wallTop2a.height = 60;
	floor.walls.push(wallTop2a);
	// Bottom wall (horizontal)
	var wallBottom2 = new Wall();
	wallBottom2.x = 1365;
	wallBottom2.y = 2048 - 100;
	wallBottom2.width = 1400;
	wallBottom2.height = 60;
	floor.walls.push(wallBottom2);
	// --- Connecting Door between rooms (center) ---
	var door = new Door();
	door.x = 1024;
	door.y = 2732 / 2;
	floor.doors.push(door);
	// --- Puzzle in Room 2 (right room, bottom right) ---
	var puzzle = new Puzzle();
	puzzle.x = 2048 - 500;
	puzzle.y = 2732 - 600;
	floor.puzzles.push(puzzle);
	// --- Ghost in Room 1 (left room) ---
	var ghost = new Ghost();
	ghost.x = 524;
	ghost.y = 1200;
	floor.enemies.push(ghost);
	return floor;
}
function createFloor1() {
	// Upstairs: 1 room, exit door (unlocked if puzzle solved), 1 ghost
	var floor = {
		walls: [],
		doors: [],
		keys: [],
		puzzles: [],
		enemies: []
	};
	// Walls (rectangle room)
	var wallTop = new Wall();
	wallTop.x = 2048 / 2;
	wallTop.y = 400;
	wallTop.width = 1600;
	wallTop.height = 60;
	floor.walls.push(wallTop);
	var wallBottom = new Wall();
	wallBottom.x = 2048 / 2;
	wallBottom.y = 2732 - 400;
	wallBottom.width = 1600;
	wallBottom.height = 60;
	floor.walls.push(wallBottom);
	var wallLeft = new Wall();
	wallLeft.x = 300;
	wallLeft.y = 2732 / 2;
	wallLeft.width = 60;
	wallLeft.height = 1800;
	floor.walls.push(wallLeft);
	var wallRight = new Wall();
	wallRight.x = 2048 - 300;
	wallRight.y = 2732 / 2;
	wallRight.width = 60;
	wallRight.height = 1800;
	floor.walls.push(wallRight);
	// Exit Door (top center, unlocked if puzzle solved)
	var door = new Door();
	door.x = 2048 / 2;
	door.y = 400;
	door.locked = false;
	door.doorAsset.destroy();
	door.doorAsset = door.attachAsset('door_unlocked', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	floor.doors.push(door);
	// Ghost (patrols horizontally)
	var ghost = new Ghost();
	ghost.x = 2048 / 2;
	ghost.y = 1200;
	floor.enemies.push(ghost);
	return floor;
}
// --- Helper Functions ---
function clearFloor() {
	// Remove all objects from game
	if (floors[currentFloor]) {
		var f = floors[currentFloor];
		for (var i = 0; i < f.walls.length; ++i) f.walls[i].destroy();
		for (var i = 0; i < f.doors.length; ++i) f.doors[i].destroy();
		for (var i = 0; i < f.keys.length; ++i) f.keys[i].destroy();
		for (var i = 0; i < f.puzzles.length; ++i) f.puzzles[i].destroy();
		for (var i = 0; i < f.enemies.length; ++i) f.enemies[i].destroy();
	}
	if (doorObj) {
		if (typeof doorObj.destroy === "function") {
			doorObj.destroy();
		}
		doorObj = null;
	}
	if (puzzleObj) {
		if (typeof puzzleObj.destroy === "function") {
			puzzleObj.destroy();
		}
		puzzleObj = null;
	}
	if (ghostObj) {
		ghostObj.destroy();
		ghostObj = null;
	}
}
function setupFloor(floorNum) {
	clearFloor();
	var f = floors[floorNum];
	// Add walls
	for (var i = 0; i < f.walls.length; ++i) game.addChild(f.walls[i]);
	// Add doors
	for (var i = 0; i < f.doors.length; ++i) game.addChild(f.doors[i]);
	// Add puzzles
	for (var i = 0; i < f.puzzles.length; ++i) game.addChild(f.puzzles[i]);
	// Add enemies
	for (var i = 0; i < f.enemies.length; ++i) game.addChild(f.enemies[i]);
	// For easy reference
	doorObj = f.doors.length ? f.doors[0] : null;
	keyObj = null;
	puzzleObj = f.puzzles.length ? f.puzzles[0] : null;
	ghostObj = f.enemies.length ? f.enemies[0] : null;
}
// --- GUI ---
messageTxt = new Text2('', {
	size: 90,
	fill: 0xFFCCCC
});
messageTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(messageTxt);
floorTxt = new Text2('Floor 1', {
	size: 70,
	fill: 0xCCCCFF
});
floorTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(floorTxt);
// --- Game Setup ---
floors[0] = createFloor0();
floors[1] = createFloor1();
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 700;
game.addChild(player);
setupFloor(0);
updateFloorText();
function updateFloorText() {
	floorTxt.setText('Floor 5');
}
// --- Movement & Controls ---
function canMoveTo(x, y) {
	// Check collision with walls
	var f = floors[currentFloor];
	for (var i = 0; i < f.walls.length; ++i) {
		var wall = f.walls[i];
		// Simple AABB collision
		var dx = Math.abs(x - wall.x);
		var dy = Math.abs(y - wall.y);
		if (dx < wall.width / 2 + 60 && dy < wall.height / 2 + 60) {
			return false;
		}
	}
	return true;
}
function handleMove(x, y, obj) {
	if (gameOver) return;
	if (!dragPlayer) return;
	// Clamp to game area
	var px = Math.max(60, Math.min(2048 - 60, x));
	var py = Math.max(60, Math.min(2732 - 60, y));
	// Only move if not colliding with wall
	if (canMoveTo(px, py)) {
		player.moveTo(px, py);
	}
}
game.down = function (x, y, obj) {
	if (gameOver) return;
	// Only start drag if touch/click is on player
	var dx = x - player.x;
	var dy = y - player.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist < 100) {
		dragPlayer = true;
		lastPlayerPos.x = player.x;
		lastPlayerPos.y = player.y;
		handleMove(x, y, obj);
	}
};
game.move = function (x, y, obj) {
	handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
	dragPlayer = false;
};
// --- Puzzle Interaction ---
function trySolvePuzzle() {
	if (!puzzleObj || puzzleObj.solved) return;
	// Simple puzzle: tap puzzle to solve
	puzzleObj.solved = true;
	puzzleSolved = true;
	messageTxt.setText("Puzzle solved!\nThe door unlocked.");
	// Unlock door
	if (doorObj && doorObj.locked) {
		doorObj.unlock();
	}
	// Animate puzzle fade out
	tween(puzzleObj, {
		alpha: 0
	}, {
		duration: 800,
		onFinish: function onFinish() {
			puzzleObj.destroy();
		}
	});
	LK.setTimeout(function () {
		messageTxt.setText('');
	}, 1500);
}
// --- Door Interaction ---
function tryOpenDoor() {
	if (!doorObj) return;
	if (doorObj.locked) {
		messageTxt.setText("The door is locked.");
		LK.setTimeout(function () {
			messageTxt.setText('');
		}, 1200);
	} else {
		// Go to next floor or win
		if (currentFloor === 0) {
			// Go upstairs
			currentFloor = 1;
			setupFloor(1);
			player.x = 2048 / 2;
			player.y = 2732 - 700;
			updateFloorText();
			messageTxt.setText("You ascend to the next floor...");
			LK.setTimeout(function () {
				messageTxt.setText('');
			}, 1200);
		} else {
			// Win!
			LK.showYouWin();
		}
	}
}
// --- Enemy (Ghost) Collision ---
function checkGhostCollision() {
	if (!ghostObj) return;
	var dx = player.x - ghostObj.x;
	var dy = player.y - ghostObj.y;
	var dist = Math.sqrt(dx * dx + dy * dy);
	if (dist < 90) {
		// Game over
		gameOver = true;
		player.canMove = false;
		messageTxt.setText("A ghost caught you!");
		LK.effects.flashScreen(0x990000, 1200);
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 1200);
	}
}
// --- Main Game Update ---
game.update = function () {
	if (gameOver) return;
	// Ghost patrol
	if (ghostObj && ghostObj.update) ghostObj.update();
	// Check for puzzle interaction
	if (puzzleObj && !puzzleObj.solved) {
		var dx = player.x - puzzleObj.x;
		var dy = player.y - puzzleObj.y;
		if (Math.sqrt(dx * dx + dy * dy) < 100 && dragPlayer) {
			trySolvePuzzle();
		}
	}
	// Check for door interaction
	if (doorObj) {
		var dx = player.x - doorObj.x;
		var dy = player.y - doorObj.y;
		if (Math.abs(dx) < 80 && Math.abs(dy) < 80 && dragPlayer) {
			if (doorObj.locked) {
				tryOpenDoor();
			} else {
				// Move player through the door (to the other side of the door)
				if (currentFloor === 0) {
					// Go upstairs
					currentFloor = 1;
					setupFloor(1);
					player.x = 2048 / 2;
					player.y = 2732 - 700;
					updateFloorText();
					messageTxt.setText("You ascend to the next floor...");
					LK.setTimeout(function () {
						messageTxt.setText('');
					}, 1200);
				} else {
					// Move player to one floor down (go back to floor 0)
					currentFloor = 0;
					setupFloor(0);
					player.x = 2048 / 2;
					player.y = 2732 - 700;
					updateFloorText();
					messageTxt.setText("You descend to the previous floor...");
					LK.setTimeout(function () {
						messageTxt.setText('');
					}, 1200);
				}
			}
		}
	}
	// Check for ghost collision
	checkGhostCollision();
}; ===================================================================
--- original.js
+++ change.js
@@ -318,9 +318,9 @@
 game.addChild(player);
 setupFloor(0);
 updateFloorText();
 function updateFloorText() {
-	floorTxt.setText('Floor 6');
+	floorTxt.setText('Floor 5');
 }
 // --- Movement & Controls ---
 function canMoveTo(x, y) {
 	// Check collision with walls