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[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[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 = 1024 + angleDiff / (fov / 2) * 1024;
if (screenX >= 0 && screenX <= 2048) {
// 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 Player = Container.expand(function () {
var self = Container.call(this);
self.x = 1024;
self.y = 1366;
self.angle = 0;
self.pitch = 0; // Vertical look angle (up/down)
self.speed = 3;
self.rotSpeed = 0.1;
// Smooth interpolation properties
self.targetX = 1024;
self.targetY = 1366;
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 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;
});
var UnifiedSpriteRenderer = Container.expand(function () {
var self = Container.call(this);
// Unified sprite-based rendering system for walls, floors, and ceilings
self.wallSprites = [];
self.floorSprites = [];
self.ceilingSprites = [];
self.maxRenderDistance = 1200;
self.fogStart = 600;
self.wallPool = []; // Pool of reusable wall sprites
self.floorPool = []; // Pool of reusable floor sprites
self.ceilingPool = []; // Pool of reusable ceiling sprites
self.activeWallSprites = []; // Currently active wall sprites
self.activeFloorSprites = []; // Currently active floor sprites
self.activeCeilingSprites = []; // Currently active ceiling sprites
self.poolSize = 200; // Maximum sprites in each pool
// Initialize sprite pools for performance
self.initSpritePools = function () {
// Initialize wall sprite pool
for (var i = 0; i < self.poolSize; i++) {
var wallSprite = self.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 1.0 // Anchor at bottom for ground positioning
}));
wallSprite.visible = false;
self.wallPool.push(wallSprite);
var floorSprite = self.addChild(LK.getAsset('piso', {
anchorX: 0.5,
anchorY: 0.5
}));
floorSprite.visible = false;
self.floorPool.push(floorSprite);
var ceilingSprite = self.addChild(LK.getAsset('ceilingStrip', {
anchorX: 0.5,
anchorY: 0.5
}));
ceilingSprite.visible = false;
self.ceilingPool.push(ceilingSprite);
}
};
// Get sprite from appropriate pool
self.getWallSprite = function () {
if (self.wallPool.length > 0) {
return self.wallPool.pop();
} else {
return self.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 1.0
}));
}
};
self.getFloorSprite = function () {
if (self.floorPool.length > 0) {
return self.floorPool.pop();
} else {
return self.addChild(LK.getAsset('piso', {
anchorX: 0.5,
anchorY: 0.5
}));
}
};
self.getCeilingSprite = function () {
if (self.ceilingPool.length > 0) {
return self.ceilingPool.pop();
} else {
return self.addChild(LK.getAsset('ceilingStrip', {
anchorX: 0.5,
anchorY: 0.5
}));
}
};
// Return sprites to pools
self.returnWallSprite = function (sprite) {
sprite.visible = false;
sprite.scaleX = 1;
sprite.scaleY = 1;
sprite.rotation = 0;
sprite.alpha = 1;
sprite.tint = 0xFFFFFF;
if (self.wallPool.length < self.poolSize) {
self.wallPool.push(sprite);
}
};
self.returnFloorSprite = function (sprite) {
sprite.visible = false;
sprite.scaleX = 1;
sprite.scaleY = 1;
sprite.rotation = 0;
sprite.alpha = 1;
sprite.tint = 0xFFFFFF;
if (self.floorPool.length < self.poolSize) {
self.floorPool.push(sprite);
}
};
self.returnCeilingSprite = function (sprite) {
sprite.visible = false;
sprite.scaleX = 1;
sprite.scaleY = 1;
sprite.rotation = 0;
sprite.alpha = 1;
sprite.tint = 0xFFFFFF;
if (self.ceilingPool.length < self.poolSize) {
self.ceilingPool.push(sprite);
}
};
// Unified sprite-based renderer with distortion effects
self.render = function (player) {
// Return all active sprites to pools
for (var i = 0; i < self.activeWallSprites.length; i++) {
self.returnWallSprite(self.activeWallSprites[i]);
}
for (var i = 0; i < self.activeFloorSprites.length; i++) {
self.returnFloorSprite(self.activeFloorSprites[i]);
}
for (var i = 0; i < self.activeCeilingSprites.length; i++) {
self.returnCeilingSprite(self.activeCeilingSprites[i]);
}
self.activeWallSprites = [];
self.activeFloorSprites = [];
self.activeCeilingSprites = [];
// Scan for visible walls using world grid
var scanRadius = 8; // Grid cells to scan around player
var playerGridX = Math.floor(player.x / worldGrid.cellSize);
var playerGridY = Math.floor(player.y / worldGrid.cellSize);
var fov = Math.PI / 3; // 60 degree field of view
var wallsToRender = [];
// Find all walls within scan radius
for (var dx = -scanRadius; dx <= scanRadius; dx++) {
for (var dy = -scanRadius; dy <= scanRadius; dy++) {
var gridX = playerGridX + dx;
var gridY = playerGridY + dy;
// Check bounds
if (gridX >= 0 && gridX < worldGrid.width && gridY >= 0 && gridY < worldGrid.height) {
if (worldGrid.walls[gridX][gridY]) {
var wallWorldX = gridX * worldGrid.cellSize + worldGrid.cellSize / 2;
var wallWorldY = gridY * worldGrid.cellSize + worldGrid.cellSize / 2;
var deltaX = wallWorldX - player.x;
var deltaY = wallWorldY - player.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Only consider walls within render distance
if (distance < self.maxRenderDistance) {
// Calculate angle to wall
var wallAngle = Math.atan2(deltaY, deltaX);
var angleDiff = wallAngle - player.angle;
// Normalize angle difference
while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;
// Check if wall is within field of view (with some padding)
if (Math.abs(angleDiff) < fov / 2 + 0.5) {
wallsToRender.push({
gridX: gridX,
gridY: gridY,
worldX: wallWorldX,
worldY: wallWorldY,
distance: distance,
angleDiff: angleDiff,
deltaX: deltaX,
deltaY: deltaY
});
}
}
}
}
}
}
// Sort walls by distance (farthest first for proper depth)
wallsToRender.sort(function (a, b) {
return b.distance - a.distance;
});
// Render floors and ceilings first (behind walls)
self.renderFloorAndCeiling(player, wallsToRender);
// Render each visible wall as a scaled sprite
for (var i = 0; i < wallsToRender.length && i < self.poolSize / 3; i++) {
var wall = wallsToRender[i];
var sprite = self.getWallSprite();
self.activeWallSprites.push(sprite);
// Calculate screen position
var screenX = 1024 + wall.angleDiff / (fov / 2) * 1024;
// Calculate sprite scaling based on distance with perspective distortion
var baseScale = 600 / (wall.distance + 100);
var perspectiveScale = Math.max(0.1, Math.min(baseScale, 3.0));
// Apply vertical distortion based on viewing angle
var distortionFactor = 1.0 + Math.abs(wall.angleDiff) * 0.3;
var verticalScale = perspectiveScale * distortionFactor;
var horizontalScale = perspectiveScale;
// Apply pitch-based distortion
var pitchDistortion = 1.0 + Math.abs(player.pitch) * 0.5;
verticalScale *= pitchDistortion;
// Position sprite with pitch offset
var pitchOffset = player.pitch * 400;
var baseY = 1366 - verticalScale * 100 / 2; // Adjust for sprite height
sprite.x = screenX;
sprite.y = baseY + pitchOffset;
// Apply scaling with distortion
sprite.scaleX = horizontalScale * 2; // Make walls wider
sprite.scaleY = verticalScale * 4; // Make walls taller
// Apply perspective rotation distortion
var rotationDistortion = wall.angleDiff * 0.1; // Subtle rotation based on viewing angle
sprite.rotation = rotationDistortion;
// Calculate lighting and fog
var lightIntensity = 1.0;
// Determine wall orientation for lighting
var isVerticalWall = Math.abs(wall.deltaX) > Math.abs(wall.deltaY);
if (!isVerticalWall) {
lightIntensity = 0.7; // Darken horizontal walls
}
// Apply distance-based fog
var fogFactor = Math.max(0.1, 1.0 - (wall.distance - self.fogStart) / (self.maxRenderDistance - self.fogStart));
lightIntensity *= fogFactor;
// Apply lighting with yellow tint
var brightness = Math.floor(255 * lightIntensity);
brightness = Math.max(20, Math.min(255, brightness));
var yellowTint = brightness << 16 | brightness << 8 | 0; // Yellow color
sprite.tint = yellowTint;
sprite.alpha = Math.max(0.3, fogFactor);
// Apply additional distortion effects based on distance
if (wall.distance > 400) {
// Add shimmering effect for distant walls
var shimmer = Math.sin(LK.ticks * 0.1 + wall.gridX + wall.gridY) * 0.1;
sprite.scaleX += shimmer;
sprite.scaleY += shimmer * 0.5;
}
sprite.visible = true;
}
};
// Render floor and ceiling sprites with perspective distortion
self.renderFloorAndCeiling = function (player, wallsToRender) {
var fov = Math.PI / 3;
var screenHeight = 2732;
var screenCenter = screenHeight / 2;
var pitchOffset = player.pitch * 400;
// Create floor and ceiling strips across the screen
for (var x = 0; x < 2048; x += 32) {
// Render every 32 pixels for performance
var screenX = x;
var rayAngle = player.angle - fov / 2 + x / 2048 * fov;
// Cast ray to find distance for floor/ceiling perspective
var rayData = self.castRayWithCoords(player.x, player.y, rayAngle);
var distance = rayData.distance;
// Calculate wall height for floor/ceiling boundaries
var baseWallSize = 400;
var wallHeight = Math.max(100, baseWallSize * (1000 / (distance + 100)));
var halfWallHeight = wallHeight / 2;
var wallTop = screenCenter - halfWallHeight + pitchOffset;
var wallBottom = screenCenter + halfWallHeight + pitchOffset;
// Render floor sprite
var floorSprite = self.getFloorSprite();
self.activeFloorSprites.push(floorSprite);
floorSprite.x = screenX;
floorSprite.y = wallBottom + (screenHeight - wallBottom) / 2;
floorSprite.width = 32;
floorSprite.height = Math.max(2, screenHeight - wallBottom);
var floorFogFactor = Math.max(0.3, 1.0 - distance / self.maxRenderDistance);
floorSprite.alpha = floorFogFactor;
floorSprite.visible = true;
// Render ceiling sprite
var ceilingSprite = self.getCeilingSprite();
self.activeCeilingSprites.push(ceilingSprite);
ceilingSprite.x = screenX;
ceilingSprite.y = wallTop / 2;
ceilingSprite.width = 32;
ceilingSprite.height = Math.max(2, wallTop);
var ceilingFogFactor = Math.max(0.3, 1.0 - distance / self.maxRenderDistance);
ceilingSprite.alpha = ceilingFogFactor;
ceilingSprite.tint = 0x1a1a15; // Darker ceiling
ceilingSprite.visible = true;
}
};
// Raycast helper method
self.castRayWithCoords = function (startX, startY, angle) {
var rayX = startX;
var rayY = startY;
var deltaX = Math.cos(angle) * 2;
var deltaY = Math.sin(angle) * 2;
var distance = 0;
// Raycast using world coordinate system
while (distance < 1000) {
rayX += deltaX;
rayY += deltaY;
distance += 2;
// Check for walls using world grid
if (worldGrid.hasWallAt(rayX, rayY)) {
break;
}
}
// Align hit coordinates to grid boundaries for straight walls
var gridX = Math.floor(rayX / worldGrid.cellSize);
var gridY = Math.floor(rayY / worldGrid.cellSize);
var alignedHitX = gridX * worldGrid.cellSize;
var alignedHitY = gridY * worldGrid.cellSize;
return {
distance: distance,
hitX: alignedHitX,
hitY: alignedHitY
};
};
// Generate method (required by game code)
self.generateWalls = function () {
self.initSpritePools();
};
return self;
});
var WallBackgroundRenderer = Container.expand(function () {
var self = Container.call(this);
self.backgroundColumns = [];
self.columnCount = 512;
// Initialize background columns for Sun texture
self.initBackgroundColumns = function () {
if (self.backgroundColumns.length === 0) {
for (var i = 0; i < self.columnCount; i++) {
var column = self.addChild(LK.getAsset('wallBackground', {
anchorX: 0.5,
anchorY: 0.5
}));
column.x = i * (2048 / self.columnCount);
column.y = 1366; // Center of screen
column.height = 2732; // Full screen height
column.width = 2048 / self.columnCount + 1; // Prevent gaps
column.visible = true;
self.backgroundColumns.push(column);
}
}
};
// Render Sun texture background
self.render = function (player) {
self.initBackgroundColumns();
// Simple parallax effect for Sun texture based on player rotation
var parallaxOffset = player.angle * 100; // Subtle movement with rotation
for (var i = 0; i < self.columnCount; i++) {
var column = self.backgroundColumns[i];
// Apply subtle parallax movement
column.x = i * (2048 / self.columnCount) + parallaxOffset % 2048;
// Ensure column wraps around screen
if (column.x > 2048) {
column.x -= 2048;
}
if (column.x < -column.width) {
column.x += 2048;
}
// Apply subtle brightness variation for atmosphere
var brightness = 0.8 + Math.sin(player.angle + i * 0.1) * 0.2;
brightness = Math.max(0.6, Math.min(1.0, brightness));
var tintValue = Math.floor(255 * brightness);
column.tint = tintValue << 16 | tintValue << 8 | tintValue;
column.visible = true;
}
};
return self;
});
/****
* Initialize Game
****/
// Create player
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* 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() {
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)
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);
// Check the four corners of the player's bounding box
var corners = [{
x: worldX - radius,
y: worldY - radius
}, {
x: worldX + radius,
y: worldY - radius
}, {
x: worldX - radius,
y: worldY + radius
}, {
x: worldX + radius,
y: worldY + radius
}];
for (var i = 0; i < corners.length; i++) {
var corner = corners[i];
var cornerGridX = Math.floor(corner.x / this.cellSize);
var cornerGridY = Math.floor(corner.y / this.cellSize);
// Check bounds
if (cornerGridX < 0 || cornerGridX >= this.width || cornerGridY < 0 || cornerGridY >= this.height) {
return true;
}
// Check wall collision
if (this.walls[cornerGridX][cornerGridY]) {
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 wall background renderer (Sun texture behind walls)
var wallBackgroundRenderer = new WallBackgroundRenderer();
game.addChild(wallBackgroundRenderer);
// Create unified sprite renderer for walls, floors, and ceilings
var unifiedRenderer = new UnifiedSpriteRenderer();
game.addChild(unifiedRenderer);
unifiedRenderer.generateWalls();
// 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 barely visible crosshair in center of screen
var crosshair = LK.getAsset('Sun', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20
});
crosshair.alpha = 0.05; // Almost invisible
crosshair.x = 1024; // Center X of screen
crosshair.y = 1366; // Center Y of screen
LK.gui.addChild(crosshair);
// 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 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 = 2048 - 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 < 1366) {
// 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 in optimal order: Sun background, unified sprite rendering (walls/floors/ceilings), then ceiling details
wallBackgroundRenderer.render(player); // Sun texture background
unifiedRenderer.render(player); // Unified sprite-based rendering for walls, floors, and ceilings
ceilingTileRenderer.render(player); // Ceiling decorations on top
// 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
@@ -208,151 +208,8 @@
self.pitch += pitchDiff * self.smoothingFactor;
};
return self;
});
-var Renderer3D = Container.expand(function () {
- var self = Container.call(this);
- self.wallColumns = [];
- self.floorColumns = [];
- self.ceilingColumns = [];
- self.zBuffer = []; // Track depth for each column
- // Create pseudo-3D rendering columns (walls handled by WallRenderer)
- for (var i = 0; i < 512; i++) {
- var wallCol = self.addChild(LK.getAsset('wall', {
- anchorX: 0.5,
- anchorY: 1.0
- }));
- wallCol.x = i * 4;
- wallCol.y = 1366;
- wallCol.visible = false; // Disable to prevent conflicts
- self.wallColumns.push(wallCol);
- var floorCol = self.addChild(LK.getAsset('piso', {
- anchorX: 0.5,
- anchorY: 0.5
- }));
- floorCol.x = i * 4;
- floorCol.y = 1366;
- self.floorColumns.push(floorCol);
- var ceilCol = self.addChild(LK.getAsset('ceilingStrip', {
- anchorX: 0.5,
- anchorY: 0.5
- }));
- ceilCol.x = i * 4;
- ceilCol.y = 700;
- self.ceilingColumns.push(ceilCol);
- }
- self.render = function (player) {
- var fov = Math.PI / 3; // 60 degrees field of view
- var halfFov = fov / 2;
- var screenHeight = 2732;
- var screenCenter = screenHeight / 2; // Center line at Y = 1366
- // Calculate pitch offset for vertical look
- var pitchOffset = player.pitch * 400; // Scale pitch to screen movement
- // Store column data for depth sorting
- var columnData = [];
- for (var i = 0; i < 512; i++) {
- var rayAngle = player.angle - halfFov + i / 512 * fov;
- var rayData = self.castRayWithCoords(player.x, player.y, rayAngle);
- var distance = rayData.distance;
- var hitX = rayData.hitX;
- var hitY = rayData.hitY;
- // Store column data with distance for sorting
- columnData.push({
- index: i,
- distance: distance,
- hitX: hitX,
- hitY: hitY,
- rayAngle: rayAngle
- });
- }
- // Sort columns by distance (farthest first for proper depth)
- columnData.sort(function (a, b) {
- return b.distance - a.distance;
- });
- // Initialize z-buffer for this frame
- for (var k = 0; k < 512; k++) {
- self.zBuffer[k] = 1000; // Start with maximum distance
- }
- // First pass: Update z-buffer with closest distances
- for (var j = 0; j < columnData.length; j++) {
- var data = columnData[j];
- var i = data.index;
- var distance = data.distance;
- // Only update z-buffer if this is closer
- if (distance < self.zBuffer[i]) {
- self.zBuffer[i] = distance;
- }
- }
- // Second pass: Render only if at closest distance
- for (var j = 0; j < columnData.length; j++) {
- var data = columnData[j];
- var i = data.index;
- var distance = data.distance;
- var hitX = data.hitX;
- var hitY = data.hitY;
- // Only render if this column is at the closest distance
- if (Math.abs(distance - self.zBuffer[i]) < 1) {
- // Calculate wall height to maintain square aspect ratio
- var baseWallSize = 400; // Base size for square walls
- var wallHeight = Math.max(100, baseWallSize * (1000 / (distance + 100)));
- var halfWallHeight = wallHeight / 2;
- // Calculate wall boundaries for floor/ceiling positioning
- var wallTop = screenCenter - halfWallHeight + pitchOffset;
- var wallBottom = screenCenter + halfWallHeight + pitchOffset;
- // Hide wall columns completely - using dedicated RaycastRenderer instead
- self.wallColumns[i].visible = false;
- // FLOOR: Bottom section (from wall bottom to screen bottom) with pitch offset
- var floorTop = wallBottom;
- var floorHeight = screenHeight - floorTop;
- self.floorColumns[i].y = floorTop + floorHeight / 2; // Center floor in bottom section
- self.floorColumns[i].height = Math.max(2, floorHeight);
- self.floorColumns[i].visible = true;
- // CEILING: Top section (from screen top to wall top) with pitch offset
- var ceilingHeight = wallTop;
- self.ceilingColumns[i].y = ceilingHeight / 2; // Center ceiling in top section
- self.ceilingColumns[i].height = Math.max(2, ceilingHeight);
- self.ceilingColumns[i].visible = true;
- } else {
- // Hide columns that are behind walls
- self.wallColumns[i].visible = false;
- self.floorColumns[i].visible = false;
- self.ceilingColumns[i].visible = false;
- }
- }
- };
- self.castRay = function (startX, startY, angle) {
- var rayData = self.castRayWithCoords(startX, startY, angle);
- return rayData.distance;
- };
- self.castRayWithCoords = function (startX, startY, angle) {
- var rayX = startX;
- var rayY = startY;
- var deltaX = Math.cos(angle) * 2;
- var deltaY = Math.sin(angle) * 2;
- var distance = 0;
- // Raycast using world coordinate system
- while (distance < 1000) {
- rayX += deltaX;
- rayY += deltaY;
- distance += 2;
- // Check for walls using world grid
- if (worldGrid.hasWallAt(rayX, rayY)) {
- break;
- }
- }
- // Align hit coordinates to grid boundaries for straight walls
- var gridX = Math.floor(rayX / worldGrid.cellSize);
- var gridY = Math.floor(rayY / worldGrid.cellSize);
- var alignedHitX = gridX * worldGrid.cellSize;
- var alignedHitY = gridY * worldGrid.cellSize;
- return {
- distance: distance,
- hitX: alignedHitX,
- hitY: alignedHitY
- };
- };
- return self;
-});
var SensitivityConfig = Container.expand(function () {
var self = Container.call(this);
// Load saved sensitivity or default to 50
self.sensitivity = storage.sensitivity || 50;
@@ -469,59 +326,127 @@
// Initially hidden
self.visible = false;
return self;
});
-var SpriteScalingRenderer = Container.expand(function () {
+var UnifiedSpriteRenderer = Container.expand(function () {
var self = Container.call(this);
- // Sprite-based scaling and distortion system
+ // Unified sprite-based rendering system for walls, floors, and ceilings
self.wallSprites = [];
+ self.floorSprites = [];
+ self.ceilingSprites = [];
self.maxRenderDistance = 1200;
self.fogStart = 600;
- self.spritePool = []; // Pool of reusable sprites
- self.activeSprites = []; // Currently active sprites
- self.poolSize = 100; // Maximum sprites in pool
- // Initialize sprite pool for performance
- self.initSpritePool = function () {
+ self.wallPool = []; // Pool of reusable wall sprites
+ self.floorPool = []; // Pool of reusable floor sprites
+ self.ceilingPool = []; // Pool of reusable ceiling sprites
+ self.activeWallSprites = []; // Currently active wall sprites
+ self.activeFloorSprites = []; // Currently active floor sprites
+ self.activeCeilingSprites = []; // Currently active ceiling sprites
+ self.poolSize = 200; // Maximum sprites in each pool
+ // Initialize sprite pools for performance
+ self.initSpritePools = function () {
+ // Initialize wall sprite pool
for (var i = 0; i < self.poolSize; i++) {
- var sprite = self.addChild(LK.getAsset('wall', {
+ var wallSprite = self.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 1.0 // Anchor at bottom for ground positioning
}));
- sprite.visible = false;
- self.spritePool.push(sprite);
+ wallSprite.visible = false;
+ self.wallPool.push(wallSprite);
+ var floorSprite = self.addChild(LK.getAsset('piso', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ floorSprite.visible = false;
+ self.floorPool.push(floorSprite);
+ var ceilingSprite = self.addChild(LK.getAsset('ceilingStrip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ ceilingSprite.visible = false;
+ self.ceilingPool.push(ceilingSprite);
}
};
- // Get sprite from pool or create new one
- self.getSprite = function () {
- if (self.spritePool.length > 0) {
- return self.spritePool.pop();
+ // Get sprite from appropriate pool
+ self.getWallSprite = function () {
+ if (self.wallPool.length > 0) {
+ return self.wallPool.pop();
} else {
- var sprite = self.addChild(LK.getAsset('wall', {
+ return self.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 1.0
}));
- return sprite;
}
};
- // Return sprite to pool
- self.returnSprite = function (sprite) {
+ self.getFloorSprite = function () {
+ if (self.floorPool.length > 0) {
+ return self.floorPool.pop();
+ } else {
+ return self.addChild(LK.getAsset('piso', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ }
+ };
+ self.getCeilingSprite = function () {
+ if (self.ceilingPool.length > 0) {
+ return self.ceilingPool.pop();
+ } else {
+ return self.addChild(LK.getAsset('ceilingStrip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ }));
+ }
+ };
+ // Return sprites to pools
+ self.returnWallSprite = function (sprite) {
sprite.visible = false;
sprite.scaleX = 1;
sprite.scaleY = 1;
sprite.rotation = 0;
sprite.alpha = 1;
sprite.tint = 0xFFFFFF;
- if (self.spritePool.length < self.poolSize) {
- self.spritePool.push(sprite);
+ if (self.wallPool.length < self.poolSize) {
+ self.wallPool.push(sprite);
}
};
- // Sprite-based scaling renderer with distortion effects
+ self.returnFloorSprite = function (sprite) {
+ sprite.visible = false;
+ sprite.scaleX = 1;
+ sprite.scaleY = 1;
+ sprite.rotation = 0;
+ sprite.alpha = 1;
+ sprite.tint = 0xFFFFFF;
+ if (self.floorPool.length < self.poolSize) {
+ self.floorPool.push(sprite);
+ }
+ };
+ self.returnCeilingSprite = function (sprite) {
+ sprite.visible = false;
+ sprite.scaleX = 1;
+ sprite.scaleY = 1;
+ sprite.rotation = 0;
+ sprite.alpha = 1;
+ sprite.tint = 0xFFFFFF;
+ if (self.ceilingPool.length < self.poolSize) {
+ self.ceilingPool.push(sprite);
+ }
+ };
+ // Unified sprite-based renderer with distortion effects
self.render = function (player) {
- // Return all active sprites to pool
- for (var i = 0; i < self.activeSprites.length; i++) {
- self.returnSprite(self.activeSprites[i]);
+ // Return all active sprites to pools
+ for (var i = 0; i < self.activeWallSprites.length; i++) {
+ self.returnWallSprite(self.activeWallSprites[i]);
}
- self.activeSprites = [];
+ for (var i = 0; i < self.activeFloorSprites.length; i++) {
+ self.returnFloorSprite(self.activeFloorSprites[i]);
+ }
+ for (var i = 0; i < self.activeCeilingSprites.length; i++) {
+ self.returnCeilingSprite(self.activeCeilingSprites[i]);
+ }
+ self.activeWallSprites = [];
+ self.activeFloorSprites = [];
+ self.activeCeilingSprites = [];
// Scan for visible walls using world grid
var scanRadius = 8; // Grid cells to scan around player
var playerGridX = Math.floor(player.x / worldGrid.cellSize);
var playerGridY = Math.floor(player.y / worldGrid.cellSize);
@@ -569,13 +494,15 @@
// Sort walls by distance (farthest first for proper depth)
wallsToRender.sort(function (a, b) {
return b.distance - a.distance;
});
+ // Render floors and ceilings first (behind walls)
+ self.renderFloorAndCeiling(player, wallsToRender);
// Render each visible wall as a scaled sprite
- for (var i = 0; i < wallsToRender.length && i < self.poolSize; i++) {
+ for (var i = 0; i < wallsToRender.length && i < self.poolSize / 3; i++) {
var wall = wallsToRender[i];
- var sprite = self.getSprite();
- self.activeSprites.push(sprite);
+ var sprite = self.getWallSprite();
+ self.activeWallSprites.push(sprite);
// Calculate screen position
var screenX = 1024 + wall.angleDiff / (fov / 2) * 1024;
// Calculate sprite scaling based on distance with perspective distortion
var baseScale = 600 / (wall.distance + 100);
@@ -623,11 +550,82 @@
}
sprite.visible = true;
}
};
- // Generate walls method (required by game code)
+ // Render floor and ceiling sprites with perspective distortion
+ self.renderFloorAndCeiling = function (player, wallsToRender) {
+ var fov = Math.PI / 3;
+ var screenHeight = 2732;
+ var screenCenter = screenHeight / 2;
+ var pitchOffset = player.pitch * 400;
+ // Create floor and ceiling strips across the screen
+ for (var x = 0; x < 2048; x += 32) {
+ // Render every 32 pixels for performance
+ var screenX = x;
+ var rayAngle = player.angle - fov / 2 + x / 2048 * fov;
+ // Cast ray to find distance for floor/ceiling perspective
+ var rayData = self.castRayWithCoords(player.x, player.y, rayAngle);
+ var distance = rayData.distance;
+ // Calculate wall height for floor/ceiling boundaries
+ var baseWallSize = 400;
+ var wallHeight = Math.max(100, baseWallSize * (1000 / (distance + 100)));
+ var halfWallHeight = wallHeight / 2;
+ var wallTop = screenCenter - halfWallHeight + pitchOffset;
+ var wallBottom = screenCenter + halfWallHeight + pitchOffset;
+ // Render floor sprite
+ var floorSprite = self.getFloorSprite();
+ self.activeFloorSprites.push(floorSprite);
+ floorSprite.x = screenX;
+ floorSprite.y = wallBottom + (screenHeight - wallBottom) / 2;
+ floorSprite.width = 32;
+ floorSprite.height = Math.max(2, screenHeight - wallBottom);
+ var floorFogFactor = Math.max(0.3, 1.0 - distance / self.maxRenderDistance);
+ floorSprite.alpha = floorFogFactor;
+ floorSprite.visible = true;
+ // Render ceiling sprite
+ var ceilingSprite = self.getCeilingSprite();
+ self.activeCeilingSprites.push(ceilingSprite);
+ ceilingSprite.x = screenX;
+ ceilingSprite.y = wallTop / 2;
+ ceilingSprite.width = 32;
+ ceilingSprite.height = Math.max(2, wallTop);
+ var ceilingFogFactor = Math.max(0.3, 1.0 - distance / self.maxRenderDistance);
+ ceilingSprite.alpha = ceilingFogFactor;
+ ceilingSprite.tint = 0x1a1a15; // Darker ceiling
+ ceilingSprite.visible = true;
+ }
+ };
+ // Raycast helper method
+ self.castRayWithCoords = function (startX, startY, angle) {
+ var rayX = startX;
+ var rayY = startY;
+ var deltaX = Math.cos(angle) * 2;
+ var deltaY = Math.sin(angle) * 2;
+ var distance = 0;
+ // Raycast using world coordinate system
+ while (distance < 1000) {
+ rayX += deltaX;
+ rayY += deltaY;
+ distance += 2;
+ // Check for walls using world grid
+ if (worldGrid.hasWallAt(rayX, rayY)) {
+ break;
+ }
+ }
+ // Align hit coordinates to grid boundaries for straight walls
+ var gridX = Math.floor(rayX / worldGrid.cellSize);
+ var gridY = Math.floor(rayY / worldGrid.cellSize);
+ var alignedHitX = gridX * worldGrid.cellSize;
+ var alignedHitY = gridY * worldGrid.cellSize;
+ return {
+ distance: distance,
+ hitX: alignedHitX,
+ hitY: alignedHitY
+ };
+ };
+ // Generate method (required by game code)
self.generateWalls = function () {
- self.initSpritePool();
+ self.initSpritePools();
};
return self;
});
var WallBackgroundRenderer = Container.expand(function () {
@@ -841,12 +839,12 @@
worldGrid.completeWallLines();
// Create wall background renderer (Sun texture behind walls)
var wallBackgroundRenderer = new WallBackgroundRenderer();
game.addChild(wallBackgroundRenderer);
-// Create sprite scaling renderer
-var wallRenderer = new SpriteScalingRenderer();
-game.addChild(wallRenderer);
-wallRenderer.generateWalls();
+// Create unified sprite renderer for walls, floors, and ceilings
+var unifiedRenderer = new UnifiedSpriteRenderer();
+game.addChild(unifiedRenderer);
+unifiedRenderer.generateWalls();
// Create ceiling tile renderer
var ceilingTileRenderer = new CeilingTileRenderer();
game.addChild(ceilingTileRenderer);
ceilingTileRenderer.generateTiles();
@@ -855,11 +853,8 @@
// 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 3D renderer
-var renderer3D = new Renderer3D();
-game.addChild(renderer3D);
// Create barely visible crosshair in center of screen
var crosshair = LK.getAsset('Sun', {
anchorX: 0.5,
anchorY: 0.5,
@@ -1013,12 +1008,11 @@
player.lookDown();
}
// Apply smooth interpolation
player.updateSmooth();
- // Render in optimal order: Sun background, floor/ceiling, then raycasted walls, then ceiling details
+ // Render in optimal order: Sun background, unified sprite rendering (walls/floors/ceilings), then ceiling details
wallBackgroundRenderer.render(player); // Sun texture background
- renderer3D.render(player); // Handles floor and ceiling strips
- wallRenderer.render(player); // True 2D raycasting wall rendering
+ unifiedRenderer.render(player); // Unified sprite-based rendering for walls, floors, and ceilings
ceilingTileRenderer.render(player); // Ceiling decorations on top
// Update coordinate display
var gridX = Math.floor(player.x / worldGrid.cellSize);
var gridZ = Math.floor(player.y / worldGrid.cellSize);