User prompt
Estas cometiendo un error con el piso
User prompt
Haz que el piso tenga sombreado si el personaje está serca es más claro pero si se alega se oscurece recuerda que tenemos separación de piso, medio y arriba crea el sombreado en el área de piso ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Haz que el piso tenga el mismo sombreado que las paredes
User prompt
Haz que el piso tenga el efecto de sombra si el jugador está cerca este se ve más claro pero si esta lejos se oscurece ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Has que el movimiento de la cámara sea de juego de terror ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Crea una cruceta para el movimiento
User prompt
Has que las paredes no se salga de lo ancho de la pantalla visible
User prompt
Has que ya no se carguen las cosas que se salgan de la longitud horizontal
User prompt
Has que el juego sea horizontal de ves de vertical
User prompt
Vamos a cambiar al sistema Raycasting 2D
User prompt
Crea una versión propia de paredes para que no use tanta texturas de fotos
User prompt
Haz un contador de fps
User prompt
Reducir la cantidad de imágenes de las paredes para optimizar
User prompt
Tienes que las paredes miren un punto fijo por ejemplo que este esté mirando el punto de medio como textura ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Corrige eso por favor ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'worldGrid.walls[gridX][gridY]')' in or related to this line: 'if (worldGrid.walls[gridX][gridY]) {' Line Number: 562
User prompt
Has las paredes cuadrados
User prompt
Mejora todos eso ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Optimízalo para dispositivos móviles
User prompt
Optimiza las paredes
User prompt
Please fix the bug: 'wallRenderer.generateWalls is not a function. (In 'wallRenderer.generateWalls()', 'wallRenderer.generateWalls' is undefined)' in or related to this line: 'wallRenderer.generateWalls();' Line Number: 733
User prompt
Pues usar este método? Raycasting falso + sprites en plano 3D (pseudo-3D)
User prompt
Migra todo a este método
User prompt
Vamos a probar el método Scaling y distorsión por sprites
User prompt
Las paredes todavía tienen pedazos en blanco soluciónalo
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var CeilingTileRenderer = Container.expand(function () { var self = Container.call(this); self.tiles = []; // Generate ceiling tiles in safe positions (away from corners and walls) self.generateTiles = function () { for (var x = 2; x < worldGrid.width - 2; x++) { for (var y = 2; y < worldGrid.height - 2; y++) { // Only place tiles in open areas (not near walls or corners) if (!worldGrid.hasWallAt(x * worldGrid.cellSize, y * worldGrid.cellSize) && !self.isNearCorner(x, y) && self.isSafePosition(x, y)) { var tile = { worldX: x * worldGrid.cellSize + worldGrid.cellSize / 2, worldY: y * worldGrid.cellSize + worldGrid.cellSize / 2, sprite: null }; self.tiles.push(tile); } } } }; // Check if position is near a corner self.isNearCorner = function (gridX, gridY) { // Check 3x3 area around position for wall density var wallCount = 0; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { var checkX = gridX + dx; var checkY = gridY + dy; if (checkX >= 0 && checkX < worldGrid.width && checkY >= 0 && checkY < worldGrid.height) { if (worldGrid.walls && worldGrid.walls[checkX] && worldGrid.walls[checkX][checkY]) { wallCount++; } } } } return wallCount >= 3; // Near corner if 3+ walls nearby }; // Check if position is safe (center of open areas) self.isSafePosition = function (gridX, gridY) { // Ensure there's open space in all 4 cardinal directions var directions = [{ x: 0, y: -1 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 0 }]; for (var i = 0; i < directions.length; i++) { var checkX = gridX + directions[i].x; var checkY = gridY + directions[i].y; if (checkX >= 0 && checkX < worldGrid.width && checkY >= 0 && checkY < worldGrid.height) { if (worldGrid.walls && worldGrid.walls[checkX] && worldGrid.walls[checkX][checkY]) { return false; } } } return true; }; self.render = function (player) { // Clear existing sprites for (var i = 0; i < self.tiles.length; i++) { if (self.tiles[i].sprite) { self.tiles[i].sprite.visible = false; } } var visibleTiles = []; // Calculate which tiles are visible and their screen positions for (var i = 0; i < self.tiles.length; i++) { var tile = self.tiles[i]; var dx = tile.worldX - player.x; var dy = tile.worldY - player.y; var distance = Math.sqrt(dx * dx + dy * dy); // Only render tiles within reasonable distance if (distance < 800) { // Calculate angle relative to player's view direction var tileAngle = Math.atan2(dy, dx); var angleDiff = tileAngle - player.angle; // Normalize angle difference while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI; while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI; // Check if tile is within field of view var fov = Math.PI / 3; if (Math.abs(angleDiff) < fov / 2) { // Calculate screen X position var screenX = 1366 + angleDiff / (fov / 2) * 1366; // Only add tiles that are within horizontal screen bounds with margin if (screenX >= -50 && screenX <= 2782) { // Apply pitch offset to ceiling tiles var pitchOffset = player.pitch * 400; visibleTiles.push({ tile: tile, distance: distance, screenX: screenX, screenY: 400 - 200 * (1000 / (distance + 100)) + pitchOffset // Project to ceiling with pitch }); } } } } // Sort by distance (farthest first) visibleTiles.sort(function (a, b) { return b.distance - a.distance; }); // Render visible tiles for (var i = 0; i < visibleTiles.length; i++) { var visibleTile = visibleTiles[i]; var tile = visibleTile.tile; if (!tile.sprite) { tile.sprite = self.addChild(LK.getAsset('ceilingTile', { anchorX: 0.5, anchorY: 0.5 })); } tile.sprite.x = visibleTile.screenX; tile.sprite.y = visibleTile.screenY; tile.sprite.visible = true; // Scale based on distance var scale = Math.max(0.1, 20 / (visibleTile.distance + 20)); tile.sprite.scaleX = scale; tile.sprite.scaleY = scale; } }; return self; }); var GeometricWallRenderer = Container.expand(function () { var self = Container.call(this); // Simplified wall rendering with geometric shapes self.wallStrips = []; self.numStrips = 64; // Further reduced for better performance self.maxWalls = 32; // Maximum number of wall strips to render // Initialize wall strips pool self.initWallStrips = function () { for (var i = 0; i < self.maxWalls; i++) { var wallStrip = self.addChild(LK.getAsset('wallSegment', { anchorX: 0.5, anchorY: 0.5 })); wallStrip.visible = false; self.wallStrips.push(wallStrip); } }; // Get available wall strip from pool self.getWallStrip = function () { for (var i = 0; i < self.wallStrips.length; i++) { if (!self.wallStrips[i].visible) { return self.wallStrips[i]; } } return null; }; // Render walls using simplified column-based approach self.render = function (player) { // Initialize strips if not done if (self.wallStrips.length === 0) { self.initWallStrips(); } // Hide all wall strips for (var j = 0; j < self.wallStrips.length; j++) { self.wallStrips[j].visible = false; } var fov = Math.PI / 3; // 60 degrees field of view var halfFov = fov / 2; var screenCenter = 1024; // Y center of screen var pitchOffset = player.pitch * 300; // Apply pitch for vertical look var stripWidth = 2732 / self.numStrips; var wallsRendered = 0; // Cast rays and render wall strips for (var i = 0; i < self.numStrips && wallsRendered < self.maxWalls; i++) { var rayAngle = player.angle - halfFov + i / self.numStrips * fov; var rayData = self.castSimpleRay(player.x, player.y, rayAngle); if (rayData.hit) { var distance = rayData.distance; // Apply fish-eye correction var correctedDistance = distance * Math.cos(rayAngle - player.angle); // Calculate screen X position for horizontal bounds checking var screenX = i * stripWidth + stripWidth / 2; // Only render if within horizontal screen bounds if (screenX >= 0 && screenX <= 2732) { // Get wall strip from pool var wallStrip = self.getWallStrip(); if (wallStrip) { // Calculate wall height based on distance var baseWallSize = worldGrid.cellSize; var wallHeight = Math.max(60, baseWallSize * (500 / (correctedDistance + 50))); // Position wall strip wallStrip.width = stripWidth + 2; // Add small overlap wallStrip.height = wallHeight; wallStrip.x = screenX; wallStrip.y = screenCenter + pitchOffset; wallStrip.visible = true; // Apply distance-based shading var shadingFactor = Math.max(0.2, 1.0 - correctedDistance / 600); var tintValue = Math.floor(shadingFactor * 255); wallStrip.tint = tintValue << 16 | tintValue << 8 | tintValue; // Add slight variation based on position for texture effect var positionVariation = (rayData.hitX + rayData.hitY) % 40; if (positionVariation < 20) { tintValue = Math.floor(tintValue * 0.9); // Slightly darker wallStrip.tint = tintValue << 16 | tintValue << 8 | tintValue; } wallsRendered++; } } } } }; // Simplified raycasting for geometric walls self.castSimpleRay = function (startX, startY, angle) { var rayX = startX; var rayY = startY; var deltaX = Math.cos(angle) * 8; // Larger steps for performance var deltaY = Math.sin(angle) * 8; var distance = 0; var maxDistance = 600; var stepSize = 8; // Raycast until wall hit or max distance while (distance < maxDistance) { rayX += deltaX; rayY += deltaY; distance += stepSize; // Check for wall collision if (worldGrid.hasWallAt(rayX, rayY)) { return { hit: true, distance: distance, hitX: rayX, hitY: rayY }; } } return { hit: false, distance: maxDistance, hitX: rayX, hitY: rayY }; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); self.x = 1366; self.y = 1024; self.angle = 0; self.pitch = 0; // Vertical look angle (up/down) self.speed = 3; self.rotSpeed = 0.1; // Smooth interpolation properties self.targetX = 1366; self.targetY = 1024; self.targetAngle = 0; self.targetPitch = 0; self.smoothingFactor = 0.15; // Player visual for debugging (will be hidden in first person) var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); playerGraphics.visible = false; // Hide for first person view self.moveForward = function () { var newX = self.targetX + Math.cos(self.targetAngle) * self.speed; var newY = self.targetY + Math.sin(self.targetAngle) * self.speed; // Constrain Y coordinate to not go below 0 if (newY < 0) { newY = 0; } // Check collision with world grid using improved collision detection if (!worldGrid.checkCollision(newX, newY)) { self.targetX = newX; self.targetY = newY; } }; self.moveBackward = function () { var newX = self.targetX - Math.cos(self.targetAngle) * self.speed; var newY = self.targetY - Math.sin(self.targetAngle) * self.speed; // Constrain Y coordinate to not go below 0 if (newY < 0) { newY = 0; } // Check collision with world grid using improved collision detection if (!worldGrid.checkCollision(newX, newY)) { self.targetX = newX; self.targetY = newY; } }; self.turnLeft = function () { self.targetAngle -= self.rotSpeed; }; self.turnRight = function () { self.targetAngle += self.rotSpeed; }; self.lookUp = function () { self.targetPitch = Math.max(-Math.PI / 3, self.targetPitch - self.rotSpeed); // Limit to -60 degrees }; self.lookDown = function () { self.targetPitch = Math.min(Math.PI / 3, self.targetPitch + self.rotSpeed); // Limit to +60 degrees }; self.updateSmooth = function () { // Smooth interpolation for position self.x += (self.targetX - self.x) * self.smoothingFactor; self.y += (self.targetY - self.y) * self.smoothingFactor; // Smooth interpolation for rotation with angle wrapping var angleDiff = self.targetAngle - self.angle; // Handle angle wrapping (ensure shortest rotation path) if (angleDiff > Math.PI) angleDiff -= 2 * Math.PI; if (angleDiff < -Math.PI) angleDiff += 2 * Math.PI; self.angle += angleDiff * self.smoothingFactor; // Smooth interpolation for pitch var pitchDiff = self.targetPitch - self.pitch; self.pitch += pitchDiff * self.smoothingFactor; }; return self; }); var RaycastRenderer = Container.expand(function () { var self = Container.call(this); self.screenWidth = 2732; self.screenHeight = 2048; self.numRays = 128; // Number of rays to cast self.wallColumns = []; self.floorColumns = []; self.ceilingColumns = []; // Initialize rendering columns for (var i = 0; i < self.numRays; i++) { var stripWidth = self.screenWidth / self.numRays; // Wall column var wallCol = self.addChild(LK.getAsset('wallSegment', { anchorX: 0.5, anchorY: 0.5 })); wallCol.x = i * stripWidth + stripWidth / 2; wallCol.y = self.screenHeight / 2; wallCol.width = stripWidth + 1; // Small overlap to prevent gaps wallCol.visible = false; self.wallColumns.push(wallCol); // Floor column var floorCol = self.addChild(LK.getAsset('floorStrip', { anchorX: 0.5, anchorY: 0 })); floorCol.x = i * stripWidth + stripWidth / 2; floorCol.width = stripWidth + 1; floorCol.visible = false; self.floorColumns.push(floorCol); // Ceiling column var ceilCol = self.addChild(LK.getAsset('ceilingStrip', { anchorX: 0.5, anchorY: 1 })); ceilCol.x = i * stripWidth + stripWidth / 2; ceilCol.width = stripWidth + 1; ceilCol.visible = false; self.ceilingColumns.push(ceilCol); } self.render = function (player) { var fov = Math.PI / 2; // 90 degrees field of view for classic raycasting var halfFov = fov / 2; var stripWidth = self.screenWidth / self.numRays; var screenCenter = self.screenHeight / 2; var pitchOffset = player.pitch * 300; // Cast rays across the field of view for (var i = 0; i < self.numRays; i++) { var rayAngle = player.angle - halfFov + i / self.numRays * fov; var rayData = self.castRay(player.x, player.y, rayAngle); var distance = rayData.distance; var wallHeight = 0; var wallCol = self.wallColumns[i]; var floorCol = self.floorColumns[i]; var ceilCol = self.ceilingColumns[i]; // Check if column is within horizontal bounds var columnX = wallCol.x; var withinBounds = columnX >= -stripWidth && columnX <= self.screenWidth + stripWidth; if (rayData.hit && withinBounds) { // Fish-eye correction var correctedDistance = distance * Math.cos(rayAngle - player.angle); // Calculate wall height based on distance wallHeight = Math.max(50, worldGrid.cellSize * 800 / (correctedDistance + 1)); // Wall rendering wallCol.height = wallHeight; wallCol.y = screenCenter + pitchOffset; wallCol.visible = true; // Distance-based shading var shadingFactor = Math.max(0.15, 1.0 - correctedDistance / 800); var tintValue = Math.floor(shadingFactor * 255); wallCol.tint = tintValue << 16 | tintValue << 8 | tintValue; // Floor rendering var floorTop = screenCenter + wallHeight / 2 + pitchOffset; var floorHeight = self.screenHeight - floorTop; floorCol.y = floorTop; floorCol.height = Math.max(1, floorHeight); floorCol.visible = true; floorCol.tint = 0x666666; // Ceiling rendering var ceilHeight = screenCenter - wallHeight / 2 + pitchOffset; ceilCol.y = ceilHeight; ceilCol.height = Math.max(1, ceilHeight); ceilCol.visible = true; ceilCol.tint = 0x333333; } else { // No wall hit or outside bounds - hide columns wallCol.visible = false; floorCol.visible = false; ceilCol.visible = false; } } }; // DDA (Digital Differential Analyzer) raycasting algorithm self.castRay = function (startX, startY, angle) { var rayX = startX; var rayY = startY; var rayDirX = Math.cos(angle); var rayDirY = Math.sin(angle); // Which grid cell we're in var mapX = Math.floor(rayX / worldGrid.cellSize); var mapY = Math.floor(rayY / worldGrid.cellSize); // Length of ray from current position to x or y side var deltaDistX = Math.abs(1 / rayDirX); var deltaDistY = Math.abs(1 / rayDirY); // Calculate step and initial sideDist var stepX, sideDistX; var stepY, sideDistY; if (rayDirX < 0) { stepX = -1; sideDistX = (rayX / worldGrid.cellSize - mapX) * deltaDistX; } else { stepX = 1; sideDistX = (mapX + 1.0 - rayX / worldGrid.cellSize) * deltaDistX; } if (rayDirY < 0) { stepY = -1; sideDistY = (rayY / worldGrid.cellSize - mapY) * deltaDistY; } else { stepY = 1; sideDistY = (mapY + 1.0 - rayY / worldGrid.cellSize) * deltaDistY; } // Perform DDA var hit = false; var side = 0; // 0 if x-side, 1 if y-side var maxSteps = 100; var steps = 0; while (!hit && steps < maxSteps) { steps++; // Jump to next map square, either in x-direction, or in y-direction if (sideDistX < sideDistY) { sideDistX += deltaDistX; mapX += stepX; side = 0; } else { sideDistY += deltaDistY; mapY += stepY; side = 1; } // Check if ray has hit a wall if (worldGrid.hasWallAt(mapX * worldGrid.cellSize, mapY * worldGrid.cellSize)) { hit = true; } } var distance = 0; if (hit) { // Calculate distance if (side === 0) { distance = (mapX - rayX / worldGrid.cellSize + (1 - stepX) / 2) / rayDirX; } else { distance = (mapY - rayY / worldGrid.cellSize + (1 - stepY) / 2) / rayDirY; } distance = Math.abs(distance * worldGrid.cellSize); } return { hit: hit, distance: distance, side: side, mapX: mapX, mapY: mapY }; }; return self; }); var SensitivityConfig = Container.expand(function () { var self = Container.call(this); // Load saved sensitivity or default to 50 self.sensitivity = storage.sensitivity || 50; self.isVisible = false; // Create background panel var background = self.addChild(LK.getAsset('untexturedArea', { anchorX: 0, anchorY: 0, width: 300, height: 200, alpha: 0.8 })); background.tint = 0x222222; // Create title text var titleText = new Text2('Sensitivity', { size: 40, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 150; titleText.y = 20; self.addChild(titleText); // Create sensitivity value text var valueText = new Text2(self.sensitivity.toString(), { size: 35, fill: 0xFFFFFF }); valueText.anchor.set(0.5, 0); valueText.x = 150; valueText.y = 70; self.addChild(valueText); // Create decrease button (larger for mobile) var decreaseBtn = self.addChild(LK.getAsset('untexturedArea', { anchorX: 0.5, anchorY: 0.5, width: 70, height: 60 })); decreaseBtn.x = 80; decreaseBtn.y = 130; decreaseBtn.tint = 0x666666; var decreaseText = new Text2('-', { size: 40, fill: 0xFFFFFF }); decreaseText.anchor.set(0.5, 0.5); decreaseText.x = 80; decreaseText.y = 130; self.addChild(decreaseText); // Create increase button (larger for mobile) var increaseBtn = self.addChild(LK.getAsset('untexturedArea', { anchorX: 0.5, anchorY: 0.5, width: 70, height: 60 })); increaseBtn.x = 220; increaseBtn.y = 130; increaseBtn.tint = 0x666666; var increaseText = new Text2('+', { size: 40, fill: 0xFFFFFF }); increaseText.anchor.set(0.5, 0.5); increaseText.x = 220; increaseText.y = 130; self.addChild(increaseText); // Update sensitivity display self.updateDisplay = function () { valueText.setText(self.sensitivity.toString()); // Save to storage storage.sensitivity = self.sensitivity; }; // Toggle visibility self.toggle = function () { self.isVisible = !self.isVisible; self.visible = self.isVisible; }; // Handle decrease button with visual feedback decreaseBtn.down = function (x, y, obj) { decreaseBtn.tint = 0x888888; // Lighten on press if (self.sensitivity > 0) { self.sensitivity = Math.max(0, self.sensitivity - 5); self.updateDisplay(); } }; decreaseBtn.up = function (x, y, obj) { decreaseBtn.tint = 0x666666; // Reset color on release }; // Handle increase button with visual feedback increaseBtn.down = function (x, y, obj) { increaseBtn.tint = 0x888888; // Lighten on press if (self.sensitivity < 100) { self.sensitivity = Math.min(100, self.sensitivity + 5); self.updateDisplay(); } }; increaseBtn.up = function (x, y, obj) { increaseBtn.tint = 0x666666; // Reset color on release }; // Add background click handler to prevent game interactions background.down = function (x, y, obj) { // Prevent event from bubbling to game return true; }; background.up = function (x, y, obj) { // Prevent event from bubbling to game return true; }; background.move = function (x, y, obj) { // Prevent event from bubbling to game return true; }; // Initially hidden self.visible = false; return self; }); /**** * Initialize Game ****/ // Create player var game = new LK.Game({ backgroundColor: 0x000000, orientation: 'landscape' }); /**** * Game Code ****/ // World coordinate system - grid-based layout var worldGrid = { cellSize: 200, width: 20, // 20x20 grid height: 20, walls: [], // Will store wall positions // Initialize world grid with walls initializeGrid: function initializeGrid() { // Initialize walls array first this.walls = []; for (var x = 0; x < this.width; x++) { this.walls[x] = []; for (var y = 0; y < this.height; y++) { // Create backrooms-style layout var isWall = false; // Outer boundaries are always walls if (x === 0 || x === this.width - 1 || y === 0 || y === this.height - 1) { isWall = true; } // Create maze-like structure typical of backrooms else if (x % 3 === 0 && y % 3 === 0 || x % 4 === 0 && y % 2 === 0 || y % 4 === 0 && x % 2 === 0) { isWall = true; } this.walls[x][y] = isWall; } } }, // Check if a world position has a wall hasWallAt: function hasWallAt(worldX, worldY) { var gridX = Math.floor(worldX / this.cellSize); var gridY = Math.floor(worldY / this.cellSize); if (gridX < 0 || gridX >= this.width || gridY < 0 || gridY >= this.height) { return true; // Outside bounds = wall } return this.walls[gridX][gridY]; }, // Check collision with wall boundaries (with player radius) - optimized checkCollision: function checkCollision(worldX, worldY, radius) { radius = radius || 20; // Default player radius var gridX = Math.floor(worldX / this.cellSize); var gridY = Math.floor(worldY / this.cellSize); // Quick bounds check first if (gridX < 1 || gridX >= this.width - 1 || gridY < 1 || gridY >= this.height - 1) { return true; // Near or outside bounds = collision } // Optimized collision check - only check center and edges that matter for movement var checkPoints = [ // Center point { x: worldX, y: worldY }, // Movement-relevant edges { x: worldX - radius, y: worldY }, // Left edge { x: worldX + radius, y: worldY }, // Right edge { x: worldX, y: worldY - radius }, // Top edge { x: worldX, y: worldY + radius } // Bottom edge ]; for (var i = 0; i < checkPoints.length; i++) { var point = checkPoints[i]; var pointGridX = Math.floor(point.x / this.cellSize); var pointGridY = Math.floor(point.y / this.cellSize); // Quick bounds check if (pointGridX < 0 || pointGridX >= this.width || pointGridY < 0 || pointGridY >= this.height) { return true; } // Check wall collision with early exit if (this.walls[pointGridX][pointGridY]) { return true; } } return false; }, // Convert screen coordinates to world coordinates screenToWorld: function screenToWorld(screenX, screenY) { return { x: screenX, y: screenY }; }, // Convert world coordinates to screen coordinates worldToScreen: function worldToScreen(worldX, worldY) { return { x: worldX, y: worldY }; } }; // Initialize the world grid worldGrid.initializeGrid(); // Add wall line completion system worldGrid.completeWallLines = function () { // Trace horizontal lines and complete them for (var y = 0; y < this.height; y++) { var wallStart = -1; var wallEnd = -1; // Find wall segments in this row for (var x = 0; x < this.width; x++) { if (this.walls[x][y]) { if (wallStart === -1) { wallStart = x; // Start of wall segment } wallEnd = x; // Update end of wall segment } else { // If we found a wall segment, complete the line between start and end if (wallStart !== -1 && wallEnd !== -1 && wallEnd > wallStart) { for (var fillX = wallStart; fillX <= wallEnd; fillX++) { this.walls[fillX][y] = true; // Fill the gap } } wallStart = -1; // Reset for next segment wallEnd = -1; } } // Complete any remaining segment at end of row if (wallStart !== -1 && wallEnd !== -1 && wallEnd > wallStart) { for (var fillX = wallStart; fillX <= wallEnd; fillX++) { this.walls[fillX][y] = true; } } } // Trace vertical lines and complete them for (var x = 0; x < this.width; x++) { var wallStart = -1; var wallEnd = -1; // Find wall segments in this column for (var y = 0; y < this.height; y++) { if (this.walls[x][y]) { if (wallStart === -1) { wallStart = y; // Start of wall segment } wallEnd = y; // Update end of wall segment } else { // If we found a wall segment, complete the line between start and end if (wallStart !== -1 && wallEnd !== -1 && wallEnd > wallStart) { for (var fillY = wallStart; fillY <= wallEnd; fillY++) { this.walls[x][fillY] = true; // Fill the gap } } wallStart = -1; // Reset for next segment wallEnd = -1; } } // Complete any remaining segment at end of column if (wallStart !== -1 && wallEnd !== -1 && wallEnd > wallStart) { for (var fillY = wallStart; fillY <= wallEnd; fillY++) { this.walls[x][fillY] = true; } } } }; // Apply wall line completion after initial generation worldGrid.completeWallLines(); // Create geometric wall renderer var wallRenderer = new GeometricWallRenderer(); game.addChild(wallRenderer); // Create ceiling tile renderer var ceilingTileRenderer = new CeilingTileRenderer(); game.addChild(ceilingTileRenderer); ceilingTileRenderer.generateTiles(); // Create player var player = new Player(); // Position player at a valid starting location in the world grid player.x = worldGrid.cellSize * 1.5; // Start in cell (1,1) player.y = worldGrid.cellSize * 1.5; game.addChild(player); // Create raycasting renderer var raycastRenderer = new RaycastRenderer(); game.addChild(raycastRenderer); // FPS counter variables var fpsCounter = 0; var fpsDisplay = 0; var lastFpsTime = Date.now(); // Create coordinate display text var coordXText = new Text2('X: 0', { size: 60, fill: 0xFFFFFF }); coordXText.anchor.set(0, 0); coordXText.x = 120; // Avoid top-left 100x100 area coordXText.y = 120; LK.gui.addChild(coordXText); var coordZText = new Text2('Z: 0', { size: 60, fill: 0xFFFFFF }); coordZText.anchor.set(0, 0); coordZText.x = 120; // Avoid top-left 100x100 area coordZText.y = 200; LK.gui.addChild(coordZText); // Create FPS display text var fpsText = new Text2('FPS: 60', { size: 60, fill: 0x00FF00 }); fpsText.anchor.set(0, 0); fpsText.x = 120; // Avoid top-left 100x100 area fpsText.y = 280; LK.gui.addChild(fpsText); // Create settings button in top-right corner (larger for mobile) var settingsButton = LK.getAsset('untexturedArea', { anchorX: 1, anchorY: 0, width: 120, height: 120 }); settingsButton.tint = 0x444444; settingsButton.alpha = 0.7; LK.gui.topRight.addChild(settingsButton); var settingsText = new Text2('⚙', { size: 60, fill: 0xFFFFFF }); settingsText.anchor.set(0.5, 0.5); settingsText.x = -60; settingsText.y = 60; LK.gui.topRight.addChild(settingsText); // Create sensitivity configuration panel var sensitivityConfig = new SensitivityConfig(); sensitivityConfig.x = 2732 - 320; sensitivityConfig.y = 100; LK.gui.addChild(sensitivityConfig); // Movement flags var moveForward = false; var moveBackward = false; var turnLeft = false; var turnRight = false; var lookUp = false; var lookDown = false; // Touch controls for movement var touchStartX = 0; var touchStartY = 0; var touchActive = false; // Settings button click handler settingsButton.down = function (x, y, obj) { sensitivityConfig.toggle(); }; game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; touchActive = true; // Forward movement on touch moveForward = true; }; game.up = function (x, y, obj) { touchActive = false; moveForward = false; moveBackward = false; turnLeft = false; turnRight = false; lookUp = false; lookDown = false; }; game.move = function (x, y, obj) { if (!touchActive) return; var deltaX = x - touchStartX; var deltaY = y - touchStartY; // Horizontal movement for turning if (Math.abs(deltaX) > 50) { if (deltaX > 0) { turnRight = true; turnLeft = false; } else { turnLeft = true; turnRight = false; } } else { turnLeft = false; turnRight = false; } // Vertical movement - split between forward/backward and look up/down if (Math.abs(deltaY) > 50) { // If touch is in upper part of screen, use for looking up/down if (y < 1024) { // Upper half of screen for vertical look if (deltaY < 0) { lookUp = true; lookDown = false; } else { lookDown = true; lookUp = false; } moveForward = false; moveBackward = false; } else { // Lower half of screen for movement if (deltaY < 0) { moveForward = true; moveBackward = false; } else { moveBackward = true; moveForward = false; } lookUp = false; lookDown = false; } } else { lookUp = false; lookDown = false; } }; game.update = function () { // Update player rotation speed based on sensitivity (0-100 maps to 0.05-0.2) var sensitivityValue = sensitivityConfig.sensitivity; player.rotSpeed = 0.05 + sensitivityValue / 100 * 0.15; // Handle movement if (moveForward) { player.moveForward(); } if (moveBackward) { player.moveBackward(); } if (turnLeft) { player.turnLeft(); } if (turnRight) { player.turnRight(); } if (lookUp) { player.lookUp(); } if (lookDown) { player.lookDown(); } // Apply smooth interpolation player.updateSmooth(); // Render the raycasted view raycastRenderer.render(player); // Render walls wallRenderer.render(player); // Render ceiling tiles ceilingTileRenderer.render(player); // Update FPS counter fpsCounter++; var currentTime = Date.now(); if (currentTime - lastFpsTime >= 1000) { // Update every second fpsDisplay = fpsCounter; fpsCounter = 0; lastFpsTime = currentTime; // Color code FPS display based on performance var fpsColor = 0x00FF00; // Green for good FPS (60+) if (fpsDisplay < 30) { fpsColor = 0xFF0000; // Red for poor FPS } else if (fpsDisplay < 50) { fpsColor = 0xFFFF00; // Yellow for moderate FPS } fpsText.fill = fpsColor; fpsText.setText('FPS: ' + fpsDisplay); } // Update coordinate display var gridX = Math.floor(player.x / worldGrid.cellSize); var gridZ = Math.floor(player.y / worldGrid.cellSize); coordXText.setText('X: ' + gridX); coordZText.setText('Z: ' + gridZ); };
===================================================================
--- original.js
+++ change.js
@@ -96,9 +96,10 @@
var fov = Math.PI / 3;
if (Math.abs(angleDiff) < fov / 2) {
// Calculate screen X position
var screenX = 1366 + angleDiff / (fov / 2) * 1366;
- if (screenX >= 0 && screenX <= 2732) {
+ // Only add tiles that are within horizontal screen bounds with margin
+ if (screenX >= -50 && screenX <= 2782) {
// Apply pitch offset to ceiling tiles
var pitchOffset = player.pitch * 400;
visibleTiles.push({
tile: tile,
@@ -184,31 +185,36 @@
if (rayData.hit) {
var distance = rayData.distance;
// Apply fish-eye correction
var correctedDistance = distance * Math.cos(rayAngle - player.angle);
- // Get wall strip from pool
- var wallStrip = self.getWallStrip();
- if (wallStrip) {
- // Calculate wall height based on distance
- var baseWallSize = worldGrid.cellSize;
- var wallHeight = Math.max(60, baseWallSize * (500 / (correctedDistance + 50)));
- // Position wall strip
- wallStrip.width = stripWidth + 2; // Add small overlap
- wallStrip.height = wallHeight;
- wallStrip.x = i * stripWidth + stripWidth / 2;
- wallStrip.y = screenCenter + pitchOffset;
- wallStrip.visible = true;
- // Apply distance-based shading
- var shadingFactor = Math.max(0.2, 1.0 - correctedDistance / 600);
- var tintValue = Math.floor(shadingFactor * 255);
- wallStrip.tint = tintValue << 16 | tintValue << 8 | tintValue;
- // Add slight variation based on position for texture effect
- var positionVariation = (rayData.hitX + rayData.hitY) % 40;
- if (positionVariation < 20) {
- tintValue = Math.floor(tintValue * 0.9); // Slightly darker
+ // Calculate screen X position for horizontal bounds checking
+ var screenX = i * stripWidth + stripWidth / 2;
+ // Only render if within horizontal screen bounds
+ if (screenX >= 0 && screenX <= 2732) {
+ // Get wall strip from pool
+ var wallStrip = self.getWallStrip();
+ if (wallStrip) {
+ // Calculate wall height based on distance
+ var baseWallSize = worldGrid.cellSize;
+ var wallHeight = Math.max(60, baseWallSize * (500 / (correctedDistance + 50)));
+ // Position wall strip
+ wallStrip.width = stripWidth + 2; // Add small overlap
+ wallStrip.height = wallHeight;
+ wallStrip.x = screenX;
+ wallStrip.y = screenCenter + pitchOffset;
+ wallStrip.visible = true;
+ // Apply distance-based shading
+ var shadingFactor = Math.max(0.2, 1.0 - correctedDistance / 600);
+ var tintValue = Math.floor(shadingFactor * 255);
wallStrip.tint = tintValue << 16 | tintValue << 8 | tintValue;
+ // Add slight variation based on position for texture effect
+ var positionVariation = (rayData.hitX + rayData.hitY) % 40;
+ if (positionVariation < 20) {
+ tintValue = Math.floor(tintValue * 0.9); // Slightly darker
+ wallStrip.tint = tintValue << 16 | tintValue << 8 | tintValue;
+ }
+ wallsRendered++;
}
- wallsRendered++;
}
}
}
};
@@ -373,9 +379,12 @@
var wallHeight = 0;
var wallCol = self.wallColumns[i];
var floorCol = self.floorColumns[i];
var ceilCol = self.ceilingColumns[i];
- if (rayData.hit) {
+ // Check if column is within horizontal bounds
+ var columnX = wallCol.x;
+ var withinBounds = columnX >= -stripWidth && columnX <= self.screenWidth + stripWidth;
+ if (rayData.hit && withinBounds) {
// Fish-eye correction
var correctedDistance = distance * Math.cos(rayAngle - player.angle);
// Calculate wall height based on distance
wallHeight = Math.max(50, worldGrid.cellSize * 800 / (correctedDistance + 1));
@@ -393,16 +402,16 @@
floorCol.y = floorTop;
floorCol.height = Math.max(1, floorHeight);
floorCol.visible = true;
floorCol.tint = 0x666666;
- // Ceiling rendering
+ // Ceiling rendering
var ceilHeight = screenCenter - wallHeight / 2 + pitchOffset;
ceilCol.y = ceilHeight;
ceilCol.height = Math.max(1, ceilHeight);
ceilCol.visible = true;
ceilCol.tint = 0x333333;
} else {
- // No wall hit - render sky/void
+ // No wall hit or outside bounds - hide columns
wallCol.visible = false;
floorCol.visible = false;
ceilCol.visible = false;
}