so,
I have 3 blocks of buildings. The player can move up/down left/right but not forwards/backwards.
What i want is the building blocks to randomly spawn at the spawn point and move towards the player.
(i was successful till here)
but i also want the blocks to be snapped together, having no gaps between so it would look like an endless randomly generated level.
So how to snap the blocks together?
I hope i gave all the details. If any questions please ask.
Of course, you could set the frequency by changing the delay between repeated pulses, but this will only work if the block size and speed are matching. SpawnSnap01.blend (83.1 KB)
Or, you could calculate the frequency and set the sensors frequency (delay between repeated pulses) when starting the script. SpawnSnap02.blend (83.3 KB)
Edit: To get the same random sequence each time you start the game engine you could do this by changing the default seed() to seed(value). Add this two lines to the code:
You’re welcome. But in fact I have to apologize. Today I realized that all my coding is not optimal. With modules that run continuously it’s not necessary to get the owner and the scene each time. Also it isn’t necessary to initialize variables, save to property, and get the property… Also in my last example blend there is no tickRate used in the code, so this line is redundant. Here’s the code to illustrate what I consider now to be better coding:
blockName = 'Block'
blockSize = 1.0
blockSpeed = 0.1
from bge import logic
from random import randrange, seed
seed(0)
cont = logic.getCurrentController()
spawner = cont.owner
scene = spawner.scene
blocks = []
for object in scene.objectsInactive:
if blockName in object.name:
blocks.append(object)
numBlocks = len(blocks)
sensor = spawner.sensors[0]
sensor.frequency = int(blockSize / blockSpeed) - 1
def spawnBlocks(cont):
block = blocks[randrange(numBlocks)]
scene.addObject(block, spawner, 100)
You can see the difference in the Profiler (logic: ms), even with this small script.
Edit: maybe the difference isn’t so great Edit2: please read below, this code is not so good after all!
Remarks:
Keeping the controller and scene as module variable is pretty dangerous. You will get hard to discover errors when calling functions from within other objects or scenes. Getting the actual scene and the actual controller does not cost you any performance. Therefore avoid to cache it in the module.
Using the sensors on module level is even more dangerous. This will definitive not work if any other controller is using a function of this module. That is something you never can exclude. To configure the sensor I recommend a separate bge callable function with a meaningful name e.g. setFrequencyFromBlocks(currentController). Call it from first python controller within first frame.
Indeed the list of blocks is different. Looping through the list of objects is a performance eater. It is a good idea to cache the list as you do. But… You should update the cache when new objects are added or existing objects are removed. Ifyou can guaranty it does not happen it is fine to skip that part. To support this I recommend to create a separate function for list update e.g. updateBlocks(). Optional you can store the list in a property rather then in module.
Thanks, Monster, you are a lifesaver. I forgot about this. :no: @R_Jay: I hope you read this. Please ignore what I said about the controller and scene. So I give it another try:
from random import randrange, seed
seed(0)
blockName = 'Block'
blockSize = 1.0
blockSpeed = 0.1
def spawnBlocks(cont):
spawner = cont.owner
scene = spawner.scene
if 'blocks' not in spawner:
spawner['blocks'] = getBlocks(scene, blockName)
setFrequency(spawner, blockSize, blockSpeed)
blocks = spawner['blocks']
block = blocks[randrange(len(blocks))]
scene.addObject(block, spawner, 100)
def getBlocks(scene, blockName):
blocks = []
for object in scene.objectsInactive:
if blockName in object.name:
blocks.append(object)
return blocks
def setFrequency(spawner, blockSize, blockSpeed):
sensor = spawner.sensors[0]
sensor.frequency = int(blockSize / blockSpeed) - 1
Edit: Here’s the corrected code for the SpawnSnap00.blend:
from bge import logic
from random import randrange, seed
seed(0)
blockName = 'Block'
blockSize = 1.0
blockSpeed = 0.1
frequency = int(blockSize / blockSpeed)
ticRate = logic.getLogicTicRate()
def spawnBlocks(cont):
spawner = cont.owner
scene = spawner.scene
if 'blocks' not in spawner:
spawner['blocks'] = getBlocks(scene, blockName)
blocks = spawner['blocks']
time = int(spawner['timer'] * ticRate)
if time == frequency:
block = blocks[randrange(len(blocks))]
scene.addObject(block, spawner, 100)
spawner['timer'] = 0
def getBlocks(scene, blockName):
blocks = []
for object in scene.objectsInactive:
if blockName in object.name:
blocks.append(object)
return blocks
Hmm i really don’t have much knowledge of code-performance relationship so I am relying on you all for that.
I am going to use this code to spawn chunks of terrain which would have quite high polycount. So will it cause performance drop if i spawn such big geometry? (But then they are actually present in another layer so could it be that they are already in the memory?)
A little off topic question. When the game engine is running, does it simulate all the layers? If so, the three original blocks will always be in motion… since they have an always actuator attached…
Correct me if I’m wrong. A little new to the engine.:rolleyes:
Use the first script of my previous post. This one costs the least of computation time on the logic part, because this script will not run every frame.
Yes, performance will drop at a certain point, when the polycount is too high. After you tested this and you see a performance drop, you may consider to work with levels of detail to decrease the polycount. Also by breaking into separate (smaller) objects you might save some calculation, because even though the geometry of an object is partially in the camera’s frustum, the whole geometry will be calculated. Someone correct me if I’m wrong about this.
Maybe someone can explain to you the technicalities behind this, but no, if you are talking about Video Memory.
You mean, activate all layers? No, all selected layers will be active in the BGE. Objects that are on an inactive layer will also be inactive in the BGE.