User prompt
Move the controls closer to the center of the screen, bigger and more spread apart
User prompt
Make the buttons bigger
User prompt
Make the movement even slower
User prompt
Make all of the movement and sensitivity of the controls way slower
User prompt
Make the movement slower
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'map[cellY][cellX]')' in or related to this line: 'if (cellX < 0 || cellX >= MAP_SIZE || cellY < 0 || cellY >= MAP_SIZE) {' Line Number: 763
Code edit (1 edits merged)
Please save this source code
User prompt
RayCaster Dungeon Crawler
Initial prompt
3d ray casting
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ControlButton = Container.expand(function (direction) {
var self = Container.call(this);
var buttonSprite = self.attachAsset('controlButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
var arrowSprite = self.attachAsset('buttonArrow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Set arrow direction based on button type
if (direction === 'up') {
arrowSprite.rotation = 0;
} else if (direction === 'right') {
arrowSprite.rotation = Math.PI / 2;
} else if (direction === 'down') {
arrowSprite.rotation = Math.PI;
} else if (direction === 'left') {
arrowSprite.rotation = Math.PI * 1.5;
} else if (direction === 'attack') {
arrowSprite.visible = false;
buttonSprite = self.attachAsset('attackButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
}
self.direction = direction;
self.pressed = false;
self.down = function (x, y, obj) {
self.pressed = true;
buttonSprite.alpha = 0.7;
};
self.up = function (x, y, obj) {
self.pressed = false;
buttonSprite.alpha = 1;
};
return self;
});
var MapCell = Container.expand(function () {
var self = Container.call(this);
self.type = 0; // 0 = floor, 1 = wall
self.monster = null;
self.treasure = null;
self.setType = function (type) {
self.type = type;
self.updateVisual();
};
self.updateVisual = function () {
self.removeChildren();
if (self.type === 1) {
self.attachAsset('mapWall', {
anchorX: 0,
anchorY: 0
});
} else {
self.attachAsset('mapFloor', {
anchorX: 0,
anchorY: 0
});
}
};
self.addMonster = function () {
if (self.type === 0 && !self.monster && !self.treasure) {
self.monster = true;
return true;
}
return false;
};
self.addTreasure = function () {
if (self.type === 0 && !self.monster && !self.treasure) {
self.treasure = true;
return true;
}
return false;
};
self.removeMonster = function () {
self.monster = null;
};
self.removeTreasure = function () {
self.treasure = null;
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterSprite = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.mapX = 0;
self.mapY = 0;
self.health = 3;
self.takeDamage = function () {
self.health -= 1;
LK.getSound('hit').play();
// Visual feedback for hit
tween(monsterSprite, {
alpha: 0.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(monsterSprite, {
alpha: 1
}, {
duration: 100
});
}
});
return self.health <= 0;
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileSprite = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.dirX = 0;
self.dirY = 0;
self.speed = 0.2;
self.range = 5;
self.distanceTraveled = 0;
self.update = function (deltaTime) {
// Move projectile
var moveX = self.dirX * self.speed * deltaTime;
var moveY = self.dirY * self.speed * deltaTime;
self.x += moveX;
self.y += moveY;
self.distanceTraveled += Math.sqrt(moveX * moveX + moveY * moveY);
return self.distanceTraveled >= self.range;
};
return self;
});
var RaycastStrip = Container.expand(function () {
var self = Container.call(this);
var wall = self.attachAsset('wall', {
anchorX: 0,
anchorY: 0
});
var ceiling = self.attachAsset('ceiling', {
anchorX: 0,
anchorY: 0
});
var floor = self.attachAsset('floor', {
anchorX: 0,
anchorY: 0
});
self.updateStrip = function (stripWidth, wallHeight, stripIdx, wallType, distance) {
// Wall setup
wall.width = stripWidth;
wall.height = wallHeight;
wall.y = (2732 - wallHeight) / 2;
// Ceiling setup
ceiling.width = stripWidth;
ceiling.height = wall.y;
ceiling.y = 0;
// Floor setup
floor.width = stripWidth;
floor.height = ceiling.height;
floor.y = wall.y + wallHeight;
// Adjust positions
self.x = stripIdx * stripWidth;
// Add distance shading effect
var shade = Math.max(0.3, 1 - distance / 10);
wall.alpha = shade;
ceiling.alpha = shade * 0.7;
floor.alpha = shade * 0.8;
};
return self;
});
var Treasure = Container.expand(function () {
var self = Container.call(this);
var treasureSprite = self.attachAsset('treasure', {
anchorX: 0.5,
anchorY: 0.5
});
self.mapX = 0;
self.mapY = 0;
self.value = 1;
// Animate the treasure to make it more appealing
var _animateTreasure = function animateTreasure() {
tween(treasureSprite, {
rotation: Math.PI * 2
}, {
duration: 2000,
onFinish: function onFinish() {
treasureSprite.rotation = 0;
_animateTreasure();
}
});
};
_animateTreasure();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
// Game constants
var MAP_SIZE = 16;
var CELL_SIZE = 20;
var MINI_MAP_SCALE = 1;
var STRIP_WIDTH = 8;
var NUM_RAYS = Math.ceil(2048 / STRIP_WIDTH);
var FOV = Math.PI / 3; // 60 degrees field of view
var HALF_FOV = FOV / 2;
var PLAYER_MOVE_SPEED = 0.005;
var PLAYER_TURN_SPEED = 0.005;
var WALL_HEIGHT_FACTOR = 600;
var MAX_RENDER_DISTANCE = 16;
var MONSTER_COUNT = 5;
var TREASURE_COUNT = 10;
// Game state
var map = [];
var player = {
x: 1.5,
y: 1.5,
dir: 0,
health: 5,
score: 0,
level: storage.level || 1
};
var controls = {
forward: false,
backward: false,
left: false,
right: false,
attack: false
};
var monsters = [];
var treasures = [];
var projectiles = [];
var lastTime = Date.now();
// UI elements
var miniMap;
var rayCastView;
var healthText;
var scoreText;
var levelText;
var controlButtons = {};
var playerMarker;
// Setup game
function setupGame() {
// Create the rayCast view container
rayCastView = new Container();
game.addChild(rayCastView);
// Create raycast strips
for (var i = 0; i < NUM_RAYS; i++) {
var strip = new RaycastStrip();
rayCastView.addChild(strip);
}
// Create minimap container
miniMap = new Container();
miniMap.x = 20;
miniMap.y = 20;
game.addChild(miniMap);
// Generate map
generateMap();
// Create player marker
playerMarker = game.addChild(LK.getAsset('player', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create UI elements
createUI();
// Create control buttons
createControlButtons();
// Start background music
LK.playMusic('dungeon');
}
function generateMap() {
// Clear existing map
miniMap.removeChildren();
map = [];
// Remove existing monsters and treasures
for (var i = 0; i < monsters.length; i++) {
monsters[i].destroy();
}
monsters = [];
for (var i = 0; i < treasures.length; i++) {
treasures[i].destroy();
}
treasures = [];
// Clear projectiles
for (var i = 0; i < projectiles.length; i++) {
projectiles[i].destroy();
}
projectiles = [];
// Generate base map with borders
for (var y = 0; y < MAP_SIZE; y++) {
map[y] = [];
for (var x = 0; x < MAP_SIZE; x++) {
var cell = new MapCell();
cell.x = x * CELL_SIZE * MINI_MAP_SCALE;
cell.y = y * CELL_SIZE * MINI_MAP_SCALE;
// Create outer walls
if (x === 0 || y === 0 || x === MAP_SIZE - 1 || y === MAP_SIZE - 1) {
cell.setType(1); // Wall
} else {
// Random interior walls based on level difficulty
var wallChance = 0.2 + player.level * 0.03;
if (Math.random() < wallChance && !(x === 1 && y === 1)) {
// Ensure starting position is clear
cell.setType(1); // Wall
} else {
cell.setType(0); // Floor
}
}
map[y][x] = cell;
miniMap.addChild(cell);
}
}
// Create monsters
var monstersToPlace = MONSTER_COUNT + Math.floor(player.level * 0.5);
for (var i = 0; i < monstersToPlace; i++) {
placeMonster();
}
// Create treasures
var treasuresToPlace = TREASURE_COUNT;
for (var i = 0; i < treasuresToPlace; i++) {
placeTreasure();
}
// Reset player position
player.x = 1.5;
player.y = 1.5;
player.dir = 0;
}
function placeMonster() {
// Find a random empty cell
var x, y;
var attempts = 0;
do {
x = Math.floor(Math.random() * (MAP_SIZE - 2)) + 1;
y = Math.floor(Math.random() * (MAP_SIZE - 2)) + 1;
attempts++;
// Make sure it's not too close to the player
var distToPlayer = Math.sqrt(Math.pow(x - player.x, 2) + Math.pow(y - player.y, 2));
if (attempts > 100) break; // Prevent infinite loop
} while (map[y][x].type !== 0 || map[y][x].monster || map[y][x].treasure || distToPlayer < 3);
if (attempts <= 100) {
map[y][x].addMonster();
var monster = new Monster();
monster.mapX = x;
monster.mapY = y;
monster.health = 2 + Math.floor(player.level / 3); // Monsters get tougher with level
monsters.push(monster);
game.addChild(monster);
}
}
function placeTreasure() {
// Find a random empty cell
var x, y;
var attempts = 0;
do {
x = Math.floor(Math.random() * (MAP_SIZE - 2)) + 1;
y = Math.floor(Math.random() * (MAP_SIZE - 2)) + 1;
attempts++;
if (attempts > 100) break; // Prevent infinite loop
} while (map[y][x].type !== 0 || map[y][x].monster || map[y][x].treasure);
if (attempts <= 100) {
map[y][x].addTreasure();
var treasure = new Treasure();
treasure.mapX = x;
treasure.mapY = y;
treasure.value = 1 + Math.floor(Math.random() * player.level);
treasures.push(treasure);
game.addChild(treasure);
}
}
function createUI() {
// Health display
healthText = new Text2('Health: ' + player.health, {
size: 40,
fill: 0xFF5555
});
healthText.anchor.set(0, 0);
LK.gui.topRight.addChild(healthText);
healthText.x = -200;
healthText.y = 20;
// Score display
scoreText = new Text2('Score: ' + player.score, {
size: 40,
fill: 0xFFFF55
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
scoreText.x = -200;
scoreText.y = 80;
// Level display
levelText = new Text2('Level: ' + player.level, {
size: 40,
fill: 0x55FF55
});
levelText.anchor.set(0, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -200;
levelText.y = 140;
// Update UI displays
updateUI();
}
function updateUI() {
healthText.setText('Health: ' + player.health);
scoreText.setText('Score: ' + player.score);
levelText.setText('Level: ' + player.level);
// Update score in LK system
LK.setScore(player.score);
}
function createControlButtons() {
// Create directional buttons
controlButtons.up = new ControlButton('up');
controlButtons.up.x = 200;
controlButtons.up.y = 2732 - 350;
game.addChild(controlButtons.up);
controlButtons.right = new ControlButton('right');
controlButtons.right.x = 400;
controlButtons.right.y = 2732 - 200;
game.addChild(controlButtons.right);
controlButtons.down = new ControlButton('down');
controlButtons.down.x = 200;
controlButtons.down.y = 2732 - 200;
game.addChild(controlButtons.down);
controlButtons.left = new ControlButton('left');
controlButtons.left.x = 0;
controlButtons.left.y = 2732 - 200;
game.addChild(controlButtons.left);
// Create attack button on the right side
controlButtons.attack = new ControlButton('attack');
controlButtons.attack.x = 2048 - 200;
controlButtons.attack.y = 2732 - 250;
game.addChild(controlButtons.attack);
}
function rayCasting() {
var rayAngle, distToWall, rayDirX, rayDirY, mapCheckX, mapCheckY;
var distX, distY;
var rayStartX = player.x;
var rayStartY = player.y;
for (var rayIdx = 0; rayIdx < NUM_RAYS; rayIdx++) {
// Calculate ray angle (center ray + offset based on ray index)
rayAngle = player.dir - HALF_FOV + rayIdx / NUM_RAYS * FOV;
// Get direction vector
rayDirX = Math.cos(rayAngle);
rayDirY = Math.sin(rayAngle);
// Distance to wall
distToWall = 0;
hitWall = false;
// Step size for ray casting
var stepSizeX = Math.abs(1 / rayDirX);
var stepSizeY = Math.abs(1 / rayDirY);
// Which block we're checking
mapCheckX = Math.floor(rayStartX);
mapCheckY = Math.floor(rayStartY);
// Length of ray from current position to next x or y-side
var sideDistX, sideDistY;
// Direction to step in x or y direction (either +1 or -1)
var stepX = rayDirX >= 0 ? 1 : -1;
var stepY = rayDirY >= 0 ? 1 : -1;
// Calculate distance to first x and y side
if (rayDirX < 0) {
sideDistX = (rayStartX - mapCheckX) * stepSizeX;
} else {
sideDistX = (mapCheckX + 1.0 - rayStartX) * stepSizeX;
}
if (rayDirY < 0) {
sideDistY = (rayStartY - mapCheckY) * stepSizeY;
} else {
sideDistY = (mapCheckY + 1.0 - rayStartY) * stepSizeY;
}
// Perform DDA (Digital Differential Analysis)
var hit = false;
var side = 0; // 0 for x-side, 1 for y-side
var maxDistance = MAX_RENDER_DISTANCE;
while (!hit && distToWall < maxDistance) {
// Jump to next map square
if (sideDistX < sideDistY) {
sideDistX += stepSizeX;
mapCheckX += stepX;
side = 0;
} else {
sideDistY += stepSizeY;
mapCheckY += stepY;
side = 1;
}
// Check if ray has hit a wall
if (mapCheckX < 0 || mapCheckX >= MAP_SIZE || mapCheckY < 0 || mapCheckY >= MAP_SIZE || !map[mapCheckY] || !map[mapCheckY][mapCheckX]) {
hit = true;
distToWall = maxDistance;
} else if (map[mapCheckY][mapCheckX].type === 1) {
hit = true;
// Calculate exact distance to avoid fisheye effect
if (side === 0) {
distToWall = (mapCheckX - rayStartX + (1 - stepX) / 2) / rayDirX;
} else {
distToWall = (mapCheckY - rayStartY + (1 - stepY) / 2) / rayDirY;
}
}
}
// Calculate height of wall based on distance
var wallHeight = Math.min(2732, WALL_HEIGHT_FACTOR / distToWall);
// Update the strip
var strip = rayCastView.children[rayIdx];
strip.updateStrip(STRIP_WIDTH, wallHeight, rayIdx, 1, distToWall);
}
// Render monsters and treasures
renderEntities();
}
function renderEntities() {
// First, hide all entities
for (var i = 0; i < monsters.length; i++) {
monsters[i].visible = false;
}
for (var i = 0; i < treasures.length; i++) {
treasures[i].visible = false;
}
// Calculate entity positions relative to player
for (var i = 0; i < monsters.length; i++) {
var monster = monsters[i];
// Vector from player to monster
var dx = monster.mapX - player.x;
var dy = monster.mapY - player.y;
// Distance to monster
var dist = Math.sqrt(dx * dx + dy * dy);
// Angle between player's direction and monster
var angle = Math.atan2(dy, dx) - player.dir;
// Normalize angle
while (angle < -Math.PI) angle += Math.PI * 2;
while (angle > Math.PI) angle -= Math.PI * 2;
// Check if monster is in field of view
if (Math.abs(angle) < HALF_FOV && dist < MAX_RENDER_DISTANCE) {
// Check if there's a wall between player and monster
var rayDirX = Math.cos(player.dir + angle);
var rayDirY = Math.sin(player.dir + angle);
var rayHit = castRayToPoint(player.x, player.y, monster.mapX, monster.mapY);
if (!rayHit.hit || rayHit.dist > dist - 0.5) {
// Monster is visible
monster.visible = true;
// Calculate screen position
var screenX = (0.5 + angle / FOV) * 2048;
// Calculate height based on distance
var height = WALL_HEIGHT_FACTOR / dist;
// Position monster
monster.x = screenX;
monster.y = 2732 / 2;
// Scale monster based on distance
var scale = height / 100;
monster.scale.set(scale, scale);
}
}
}
// Render treasures with the same logic
for (var i = 0; i < treasures.length; i++) {
var treasure = treasures[i];
var dx = treasure.mapX - player.x;
var dy = treasure.mapY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx) - player.dir;
while (angle < -Math.PI) angle += Math.PI * 2;
while (angle > Math.PI) angle -= Math.PI * 2;
if (Math.abs(angle) < HALF_FOV && dist < MAX_RENDER_DISTANCE) {
var rayHit = castRayToPoint(player.x, player.y, treasure.mapX, treasure.mapY);
if (!rayHit.hit || rayHit.dist > dist - 0.5) {
treasure.visible = true;
var screenX = (0.5 + angle / FOV) * 2048;
var height = WALL_HEIGHT_FACTOR / dist;
treasure.x = screenX;
treasure.y = 2732 / 2;
var scale = height / 100;
treasure.scale.set(scale, scale);
}
}
}
}
function castRayToPoint(startX, startY, targetX, targetY) {
var rayDirX = targetX - startX;
var rayDirY = targetY - startY;
var distance = Math.sqrt(rayDirX * rayDirX + rayDirY * rayDirY);
rayDirX /= distance;
rayDirY /= distance;
var mapCheckX = Math.floor(startX);
var mapCheckY = Math.floor(startY);
var stepSizeX = Math.abs(1 / rayDirX);
var stepSizeY = Math.abs(1 / rayDirY);
var stepX = rayDirX >= 0 ? 1 : -1;
var stepY = rayDirY >= 0 ? 1 : -1;
var sideDistX, sideDistY;
if (rayDirX < 0) {
sideDistX = (startX - mapCheckX) * stepSizeX;
} else {
sideDistX = (mapCheckX + 1.0 - startX) * stepSizeX;
}
if (rayDirY < 0) {
sideDistY = (startY - mapCheckY) * stepSizeY;
} else {
sideDistY = (mapCheckY + 1.0 - startY) * stepSizeY;
}
var hit = false;
var side = 0;
var distToWall = 0;
while (!hit && distToWall < distance) {
if (sideDistX < sideDistY) {
sideDistX += stepSizeX;
mapCheckX += stepX;
side = 0;
distToWall = sideDistX - stepSizeX;
} else {
sideDistY += stepSizeY;
mapCheckY += stepY;
side = 1;
distToWall = sideDistY - stepSizeY;
}
if (mapCheckX < 0 || mapCheckX >= MAP_SIZE || mapCheckY < 0 || mapCheckY >= MAP_SIZE || !map[mapCheckY] || !map[mapCheckY][mapCheckX]) {
break;
} else if (map[mapCheckY][mapCheckX].type === 1) {
hit = true;
}
}
return {
hit: hit,
dist: distToWall
};
}
function updateControls() {
// Read from control buttons
controls.forward = controlButtons.up.pressed;
controls.backward = controlButtons.down.pressed;
controls.left = controlButtons.left.pressed;
controls.right = controlButtons.right.pressed;
controls.attack = controlButtons.attack.pressed;
}
function updatePlayerMovement(deltaTime) {
var moveSpeed = PLAYER_MOVE_SPEED * deltaTime;
var turnSpeed = PLAYER_TURN_SPEED * deltaTime;
var dx = 0,
dy = 0;
var didMove = false;
// Handle rotation
if (controls.left) {
player.dir -= turnSpeed;
while (player.dir < 0) player.dir += Math.PI * 2;
}
if (controls.right) {
player.dir += turnSpeed;
while (player.dir >= Math.PI * 2) player.dir -= Math.PI * 2;
}
// Handle movement
if (controls.forward) {
dx += Math.cos(player.dir) * moveSpeed;
dy += Math.sin(player.dir) * moveSpeed;
didMove = true;
}
if (controls.backward) {
dx -= Math.cos(player.dir) * moveSpeed;
dy -= Math.sin(player.dir) * moveSpeed;
didMove = true;
}
// Collision detection
var newX = player.x + dx;
var newY = player.y + dy;
var cellX = Math.floor(newX);
var cellY = Math.floor(newY);
// Check if we can move to the new position
if (cellX >= 0 && cellX < MAP_SIZE && cellY >= 0 && cellY < MAP_SIZE && map[cellY] && map[cellY][cellX]) {
if (map[cellY][cellX].type === 0) {
player.x = newX;
player.y = newY;
if (didMove && LK.ticks % 20 === 0) {
LK.getSound('walk').play();
}
}
}
// Attack handling
if (controls.attack && LK.ticks % 15 === 0) {
attackAction();
}
// Check for collisions with monsters
checkMonsterCollisions();
// Check for collisions with treasures
checkTreasureCollisions();
// Update player marker on minimap
updateMiniMap();
}
function attackAction() {
LK.getSound('attack').play();
// Create a projectile
var projectile = new Projectile();
projectile.x = 2048 / 2;
projectile.y = 2732 - 300;
projectile.dirX = Math.cos(player.dir);
projectile.dirY = Math.sin(player.dir);
projectiles.push(projectile);
game.addChild(projectile);
// Projectile visual effect
tween(projectile, {
y: 2732 / 2
}, {
duration: 100,
easing: tween.easeOut
});
}
function updateProjectiles(deltaTime) {
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
// Convert screen projectile to map projectile
var mapX = player.x + projectile.distanceTraveled * Math.cos(player.dir);
var mapY = player.y + projectile.distanceTraveled * Math.sin(player.dir);
// Check if projectile hits a wall
var cellX = Math.floor(mapX);
var cellY = Math.floor(mapY);
var hitWall = false;
if (cellX < 0 || cellX >= MAP_SIZE || cellY < 0 || cellY >= MAP_SIZE || !map[cellY] || !map[cellY][cellX]) {
hitWall = true;
} else if (map[cellY][cellX].type === 1) {
hitWall = true;
}
// Check if projectile hits a monster
var hitMonster = false;
var hitMonsterIndex = -1;
for (var j = 0; j < monsters.length; j++) {
var monster = monsters[j];
var dx = monster.mapX - mapX;
var dy = monster.mapY - mapY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 0.5) {
hitMonster = true;
hitMonsterIndex = j;
break;
}
}
// Update projectile
var remove = projectile.update(deltaTime);
if (remove || hitWall || hitMonster) {
// Handle monster hit
if (hitMonster && hitMonsterIndex !== -1) {
var monster = monsters[hitMonsterIndex];
var killed = monster.takeDamage();
if (killed) {
// Remove monster
map[Math.floor(monster.mapY)][Math.floor(monster.mapX)].removeMonster();
monster.destroy();
monsters.splice(hitMonsterIndex, 1);
// Increase score
player.score += 10;
updateUI();
// Check for level completion
checkLevelCompletion();
}
}
// Remove projectile
projectile.destroy();
projectiles.splice(i, 1);
}
}
}
function checkMonsterCollisions() {
for (var i = 0; i < monsters.length; i++) {
var monster = monsters[i];
var dx = monster.mapX - player.x;
var dy = monster.mapY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 0.5) {
// Player hit by monster
player.health--;
updateUI();
// Visual feedback
LK.effects.flashScreen(0xff0000, 300);
// Play sound
LK.getSound('hit').play();
// Push player back slightly
player.x -= dx * 0.3;
player.y -= dy * 0.3;
// Check game over
if (player.health <= 0) {
LK.showGameOver();
}
break;
}
}
}
function checkTreasureCollisions() {
for (var i = treasures.length - 1; i >= 0; i--) {
var treasure = treasures[i];
var dx = treasure.mapX - player.x;
var dy = treasure.mapY - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 0.5) {
// Collect treasure
player.score += treasure.value * 5;
updateUI();
// Play sound
LK.getSound('collect').play();
// Remove treasure
map[Math.floor(treasure.mapY)][Math.floor(treasure.mapX)].removeTreasure();
treasure.destroy();
treasures.splice(i, 1);
// Check level completion
checkLevelCompletion();
}
}
}
function checkLevelCompletion() {
// Level is complete if all monsters are defeated and all treasures collected
if (monsters.length === 0 && treasures.length === 0) {
// Level up
player.level++;
storage.level = player.level;
// Restore some health
player.health = Math.min(player.health + 2, 5);
// Update UI
updateUI();
// Show level complete
var levelCompleteText = new Text2('Level ' + (player.level - 1) + ' Complete!', {
size: 80,
fill: 0x55FF55
});
levelCompleteText.anchor.set(0.5, 0.5);
levelCompleteText.x = 2048 / 2;
levelCompleteText.y = 2732 / 2;
game.addChild(levelCompleteText);
// Generate new level after a delay
LK.setTimeout(function () {
levelCompleteText.destroy();
generateMap();
}, 2000);
}
}
function updateMiniMap() {
// Update player marker position on minimap
playerMarker.x = miniMap.x + player.x * CELL_SIZE * MINI_MAP_SCALE;
playerMarker.y = miniMap.y + player.y * CELL_SIZE * MINI_MAP_SCALE;
// Draw player direction indicator
var dirX = Math.cos(player.dir) * 15;
var dirY = Math.sin(player.dir) * 15;
}
// Game update method
game.update = function () {
var currentTime = Date.now();
var deltaTime = currentTime - lastTime;
lastTime = currentTime;
// Update controls
updateControls();
// Update player
updatePlayerMovement(deltaTime);
// Update projectiles
updateProjectiles(deltaTime);
// Update raycast view
rayCasting();
};
// Game initialization
setupGame();
// Event handlers
game.down = function (x, y, obj) {
// Handle general screen press
};
game.up = function (x, y, obj) {
// Handle general screen release
};
game.move = function (x, y, obj) {
// Handle general screen move
}; ===================================================================
--- original.js
+++ change.js
@@ -10,13 +10,17 @@
var ControlButton = Container.expand(function (direction) {
var self = Container.call(this);
var buttonSprite = self.attachAsset('controlButton', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ scaleX: 1.5,
+ scaleY: 1.5
});
var arrowSprite = self.attachAsset('buttonArrow', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ scaleX: 1.5,
+ scaleY: 1.5
});
// Set arrow direction based on button type
if (direction === 'up') {
arrowSprite.rotation = 0;
@@ -29,9 +33,11 @@
} else if (direction === 'attack') {
arrowSprite.visible = false;
buttonSprite = self.attachAsset('attackButton', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ scaleX: 1.5,
+ scaleY: 1.5
});
}
self.direction = direction;
self.pressed = false;
@@ -425,26 +431,26 @@
function createControlButtons() {
// Create directional buttons
controlButtons.up = new ControlButton('up');
controlButtons.up.x = 200;
- controlButtons.up.y = 2732 - 300;
+ controlButtons.up.y = 2732 - 350;
game.addChild(controlButtons.up);
controlButtons.right = new ControlButton('right');
- controlButtons.right.x = 350;
- controlButtons.right.y = 2732 - 150;
+ controlButtons.right.x = 400;
+ controlButtons.right.y = 2732 - 200;
game.addChild(controlButtons.right);
controlButtons.down = new ControlButton('down');
controlButtons.down.x = 200;
- controlButtons.down.y = 2732 - 150;
+ controlButtons.down.y = 2732 - 200;
game.addChild(controlButtons.down);
controlButtons.left = new ControlButton('left');
- controlButtons.left.x = 50;
- controlButtons.left.y = 2732 - 150;
+ controlButtons.left.x = 0;
+ controlButtons.left.y = 2732 - 200;
game.addChild(controlButtons.left);
// Create attack button on the right side
controlButtons.attack = new ControlButton('attack');
controlButtons.attack.x = 2048 - 200;
- controlButtons.attack.y = 2732 - 200;
+ controlButtons.attack.y = 2732 - 250;
game.addChild(controlButtons.attack);
}
function rayCasting() {
var rayAngle, distToWall, rayDirX, rayDirY, mapCheckX, mapCheckY;
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "RayCaster Dungeon Crawler" and with the description "A first-person dungeon crawler using ray casting technology to create a pseudo-3D experience. Navigate maze-like dungeons, defeat monsters, and collect treasures as you explore increasingly challenging levels with authentic retro visuals.". No text on banner!
Sword. In-Game asset. 2d. High contrast. No shadows
Tan wall. In-Game asset. 2d. High contrast. No shadows
Make a bunch of empty space above it.