Hello! I have created infinite terrain, it is plain white but it works. It is supposed to generate the tiles in chunks as the player moves.
here is the launch, and here is the editor.
I need help reducing lag, and better/smoother movements when a chunk is generated.
basically, I added a bounding box for the player, but I can’t seem to find out how to make the chunks delete when not inside of the “Distance” entity. If anyone can help please let me know.
Here is the current code.
var TerrainGenerator = pc.createScript('terrainGenerator');
TerrainGenerator.attributes.add('chunkSize', { type: 'number', default: 10 });
TerrainGenerator.attributes.add('numChunksAhead', { type: 'number', default: 5 });
TerrainGenerator.attributes.add('maxDistance', { type: 'number', default: 20 });
TerrainGenerator.prototype.initialize = function () {
this.generatedChunks = {};
this.lastPlayerPosition = new pc.Vec3();
this.lastPlayerChunk = { x: -1, z: -1 };
this.tileEntity = this.app.root.findByName('Tile');
this.tilePool = [];
this.generateTerrain();
};
TerrainGenerator.prototype.generateTerrain = function () {
this.app.on('update', this.updateTerrain.bind(this));
};
TerrainGenerator.prototype.updateTerrain = function () {
var playerPosition = this.app.root.findByName('Player').getPosition();
// Check if the player has moved
if (this.lastPlayerPosition.equals(playerPosition)) {
return;
}
var chunkX = Math.floor(playerPosition.x / this.chunkSize);
var chunkZ = Math.floor(playerPosition.z / this.chunkSize);
// Generate tiles only if the player has moved to a new chunk
if (this.lastPlayerChunk.x !== chunkX || this.lastPlayerChunk.z !== chunkZ) {
// Generate tiles in the direction of player movement along both X and Z axes
for (var i = -this.numChunksAhead; i <= this.numChunksAhead; i++) {
for (var j = -this.numChunksAhead; j <= this.numChunksAhead; j++) {
var newChunkX = chunkX + i;
var newChunkZ = chunkZ + j;
var distance = Math.sqrt(Math.pow(i, 2) + Math.pow(j, 2));
if (distance <= this.numChunksAhead && !this.generatedChunks[`${newChunkX}_${newChunkZ}`]) {
var newTile = this.getTileFromPool();
newTile.setPosition(newChunkX * this.chunkSize, 0, newChunkZ * this.chunkSize);
this.app.root.addChild(newTile);
this.markChunkAsGenerated(newChunkX, newChunkZ);
}
}
}
// Update the last generated chunk
this.lastPlayerChunk.x = chunkX;
this.lastPlayerChunk.z = chunkZ;
}
// Update the last player position
this.lastPlayerPosition.copy(playerPosition);
// Delete chunks outside the max distance
this.deleteChunksOutsideMaxDistance(playerPosition);
};
TerrainGenerator.prototype.getTileFromPool = function () {
if (this.tilePool.length > 0) {
return this.tilePool.pop();
} else {
return this.tileEntity.clone();
}
};
TerrainGenerator.prototype.returnTileToPool = function (tile) {
tile.enabled = false; // Disable the tile
this.tilePool.push(tile);
};
TerrainGenerator.prototype.markChunkAsGenerated = function (chunkX, chunkZ) {
this.generatedChunks[`${chunkX}_${chunkZ}`] = true;
};
TerrainGenerator.prototype.deleteChunksOutsideMaxDistance = function (playerPosition) {
var self = this;
Object.keys(this.generatedChunks).forEach(function (key) {
var chunkPos = key.split('_');
var chunkX = parseInt(chunkPos[0]);
var chunkZ = parseInt(chunkPos[1]);
var distance = Math.sqrt(Math.pow(playerPosition.x - chunkX * self.chunkSize, 2) + Math.pow(playerPosition.z - chunkZ * self.chunkSize, 2));
if (distance > self.maxDistance) {
self.deleteChunk(chunkX, chunkZ);
}
});
};
TerrainGenerator.prototype.deleteChunk = function (chunkX, chunkZ) {
var chunkKey = `${chunkX}_${chunkZ}`;
if (this.generatedChunks[chunkKey]) {
this.generatedChunks[chunkKey] = false;
// Delete the chunk entity
var chunkEntity = this.app.root.findByName('Tile' + chunkX + '_' + chunkZ);
if (chunkEntity) {
this.returnTileToPool(chunkEntity);
chunkEntity.destroy();
}
}
};