Random assets placer (v3)

Hello,

Added v3,
- removed the property align

  • added align to the script (still select able for each object)
  • added max_spawn to the script (global max, and per object max)
  • set the right physics for objects
  • reduced the amount polygons of the stone

I have created a random assets placer.
What it does? it spawns objects that you have defined on random locations(with random orientation) on the terrain. It does an 8 directions ray check for each object before it gets placed, so you should not find objects placed in each other.

Here is a video to see it in action: (video showing v1)

What you see is what you get (including objects/textures).


spherical update
After recieving a question, if this will work on sphere instead of a plane, ill post the solution here.

Ok, create a sphere, now give this sphere a rotating animation/motion, now adjust the script and add the following line on line 126.

new_obj.setParent(terrain_object)

, done! it will now place assets on the sphere and parent them to it (so it stays in place when you rotate the sphere to fill up empty spaces).

I hope you like- and can use it, if so leave a reply. Thanks!
random assets placement v3.blend (2.82 MB)
(stones and trunks align to floor)

1 Like

Wow! at first it didnā€™t seem too interesting but once I tried I changed my mind, this is very helpfull. I was thinking about if there was some possibility to keep the objects on scene once I stop the BGE, but then I realize that maybe this is the beauty of this script, the randomness so every time is started is like a brand new scene :slight_smile:

https://gifyu.com/images/2017-06-22_10-36-54.gif

Oh and it was a bit difficult to walk among the flowers so I had to disable the collisions on those objects. And would be great if maybe the rocks and some trunks have some normal align placement to make it more natural.

Thanks for sharing :slight_smile:

I kinda thought you were working on something like thisā€¦looks goodā€¦matai has a good point or twoā€¦aligning some objecs(some check if they have a ā€˜alignā€™ property or something) and maybe a button to save it out as a list or somethingā€¦then you can recreate the same scene, just by creating the objects indexed from the listā€¦I am going to download it and check it outā€¦I am still very early in the dev of my game and not really concerned with anything too flashy yetā€¦still working out ai and mechanics of the gameā€¦but you can bet when I am deep in level design(I have the world, just not much else :))I will be picking through your script for ideasā€¦thanks a lotā€¦

on a related note can bge read pixel color?..for like seed mapsā€¦that is another route I may takeā€¦??? possibly.

Wow! at first it didnā€™t seem too interesting but once I tried I changed my mind, this is very helpfull

It can be verry helpfull indeed, for 3d games or for rts games, etc.

I was thinking about if there was some possibility to keep the objects on scene once I stop the BGE

I was thinking about: to build in a save and load, but i thought why would i? grab the save and load from my signature, or use all the assets in my signature combine then and build a game of your dreams :wink:

Oh and it was a bit difficult to walk among the flowers so I had to disable the collisions on those objects

Yes you should do that indeed, i did not take care of the collisions, i just made a demo setup so you guys could use it.
so if you use my assets from this .blend be sure to check/set the right physics.

 And would be great if maybe the rocks and some trunks have some normal align placement to make it more natural.

that would indeed be a nice option, and i thought about adding it, but this will cause some problems, like 1 tree standing up, 1 tree placed next to it on an angle, that tree will intersect the other tree and in turn look bad.

if i find i good solution, i will add it to the blend, if not then you can try to do it on your own.

glad you like it as much as i do :slight_smile:

on a related note can bge read pixel color?..for like seed mapsā€¦that is another route I may takeā€¦??? possibly.

i have no idea about pixel color, but vertex color is an alternative that does work in bge.

I kinda thought you were working on something like thisā€¦looks good

you thought correct :), just came in to trouble to calculate the vectors the way i wanted (as you already know), the old school manual calculation that you suggested worked perfectly.

this line did it for me ā€œhave you thought about using worldOrientation but on all 3 axis and incrementing the orientations from -1 to 1?..ā€ this let me thinkā€¦ok lets do it manual then.

Yes! thatā€™s for sure! IĀ“m currently working on some game levels and some tasks like prop placement some times are quite tedious when doing manual, so this would help maybe :slight_smile:

This is my game level:

And I also agree with JustinBarret and your possible solution about vertex paint to define certain areas to place objects :slight_smile:

Thanks!

And I also agree with JustinBarret and your possible solution about vertex paint to define certain areas to place objects

Did you look at the whole 7 minutes of my video? i guess not :stuck_out_tongue:

you can just block areas with an invisible plane, so for example place a plane above a city and there will nothing be placed there.
not as fancy but for me that was enough.

This is my game level:

looks good, keep up the work!, this would work, but objects wont be placed indoors so you need to place them manually

Yes I did! :yes: thatā€™s why I placed that white cubes on the ground, just to make a test.

And yes you are rigth, that should work :slight_smile:

Would this work with endless runner videogames?It would be better if it did.

if you use 1 plane as the ground, then yes, put the script on that plane, single pulse. set spawn_amout to 5 or so.

now if you spawn that plane the script gets called and will instantly spawn 5 of the objects each.

Yes, It will work. You still may need to tweak it though.

added v2, put a property called align on an object and it will align to the floor.

Testing, working great :yes: Thanks!

https://gifyu.com/images/2017-06-22_17-33-09.gif

What about looking at vertex color,

So
1 green = higher forest spawn chance,
1 red = higher chance of rocks
1 blue = higher chance of grass and flowers

?

I will be doing this myself, but on terrain I manipulate after generation and store.

So random world, edit and place game objects and paint terrain, and paint vertex color, generate forrest/ grass / rock features, maybe even use alpha to do some water material.

So much option to extend it, but this is up to the user. iā€™m not in need of something fancy like that.

Updated the script to V3

It does not work with my endless runner videogame.

Attachments

my game.zip (14.1 MB)

tried it and it works on my pc:


It maybe does not work how you want it, but that has nothing to do with me or the script.
i told you it will only work with 1 plane as ground object (you got like 8?).
it will spawn objects on the object called Ground (look at your console fix errors first) :wink:

so at this point it does exactly what you ask it to do.

I put it on one.The others do not have it.

you did not put anything on the plane, the spawner has the script.
you did not even change the dimensions. (as said before it does exactly what you asked it to do)

Here this one will work, tested it.
(if you where thinking about taking this code, its not the latest version, this one is adapted for lostscience)


#
# RANDOM ASSETES PLACER - BY COTAKS
# (for endless runner)


from bge import logic, render
from random import uniform
from mathutils import Vector




def generator(cont):
    
    #show mouse cursor (debugging)
    render.showMouse(True)
    
    own     = cont.owner
    scene   = own.scene
    spawner = scene.objects['Empty']
    
    #how much to spawn at once
    #WITH TRUE pulse, set amount at 1 or 2, it will spawn objects till spawn_max is reached 
    #WITHOUT TRUE pulse, it will (try to)spawn every object equal to the spawn_amount 
    #best setting = True pulse, spawn_amount = 1 
    spawn_amount    = 200 # lower is slower but more accurate, higher causes objects to spawn in each other.
    spawn_max = 3000 # +- max amount to spawn
    
    if spawner['objects_spawned']+ spawn_amount <= spawn_max:
    
        #the bigger the distance, the less objects of it will be spawn.
        #objects to be spawn and their distance check
        #place a property on the empty for every object you add (same name) to the dict below (for debugging)
        objects = {
                    'tree': 7.50,
                    'stone': 7.50,
                    'flower': 0.50,
                    'flower2': 0.50,
                    'tree_trunk': 10.50,
                    'grass': 3.50                
                    }
        
        for obj in objects:
            
            name = obj
            distance = objects[obj]
            
            random_placement(cont,name,distance,spawn_amount,spawn_max)




def random_placement(cont,name,distance,spawn_amount,spawn_max):
    
    own     = cont.owner
    scene   = own.scene


    #DIMENSIONS of the landscape (N key in 3dview, scroll the quick menu to the top)
    #for optimal results make sure that you have the origin(orange dot) of the terrain object on the lowest point(bottom) and centered on x/y axis.
    landscape_z   = 160  # defines the (max)spawn height (if it bugs out in single pulse mode then be sure this is at the right dimension or higher)
    landscape_x   = 1000 # defines the spawn area size (no use to set this bigger then the terrain)
    landscape_y   = 1000 # defines the spawn area size (no use to set this bigger then the terrain)
    
    # z dimension of the tallest object that you spawn (in this case the tree)
    spawn_height_offset = 11
    
    #define objects
    terrain_object  = own
    spawner         = scene.objects['Empty']
    
    
    #
    # DONT CHANGE ANYTHING BELOW THIS LINE
    #
    
    z = terrain_object.worldPosition.z + (landscape_z + spawn_height_offset)
    
    terrain_x       = terrain_object.worldPosition.x + landscape_x / 2
    terrain_y       = terrain_object.worldPosition.y + landscape_y / 2
    terrain_minx    = terrain_object.worldPosition.x - landscape_x / 2
    terrain_miny    = terrain_object.worldPosition.y - landscape_y / 2   


    for i in range(spawn_amount): 


        spawner.worldPosition = [uniform(terrain_x, terrain_minx), uniform(terrain_y, terrain_miny), z]
        
        z_vector    = spawner.worldPosition + spawner.worldOrientation.col[2]
        ray         = spawner.rayCast(spawner, z_vector, (landscape_z + spawn_height_offset)*2)


        if ray[0] == terrain_object:
            
            #debug (can be removed)
            render.drawLine(spawner.worldPosition, ray[1], [1,0,0])
            
            check_range = distance
            check_count = 0
            
            direction_vectors = {
                                'vec_north'       : ray[1] + Vector([0,check_range,0]),
                                'vec_north_east'  : ray[1] + Vector([check_range,check_range,0]),
                                'vec_east'        : ray[1] + Vector([check_range,0,0]),
                                'vec_south_east'  : ray[1] + Vector([check_range,-check_range,0]),
                                'vec_south'       : ray[1] + Vector([0,-check_range,0]),
                                'vec_south_west'  : ray[1] + Vector([-check_range,-check_range,0]),
                                'vec_west'        : ray[1] + Vector([-check_range,0,0]),
                                'vec_north_west'  : ray[1] + Vector([-check_range,check_range,0])
                                }


            for direction in direction_vectors:
                
                #debug (can be removed)
                render.drawLine(direction_vectors[direction], ray[1], [0,1,0])
                
                check       = spawner.rayCast(direction_vectors[direction], ray[1], check_range)
                
                if not check[0]:
                    check_count +=1
  
            if check_count == len(direction_vectors):
                
                object_to_add               = name
                new_obj                     = scene.addObject(object_to_add, spawner, 0) 
                new_obj.worldPosition       = ray[1]


                face_direction(new_obj, [uniform(terrain_x, terrain_minx), uniform(terrain_y, terrain_miny), ray[1][2]])
               
                spawner['objects_spawned'] += 1
                
                #debug option (remove this, and object properties on the empty are not needed anymore)
                #spawner[name] += 1
                
            else:
                spawner['spawns_skipped'] += 1    




def face_direction(obj, vector):
    
    track_axis = 1 # x,y,z = 0,1,2
    turn_speed = 1.0 # 0.0 - 1.0
    
    # face direction
    obj.alignAxisToVect(vector, track_axis, turn_speed)
    # head up
    obj.alignAxisToVect([0.0,0.0,1.0], 2, 1.0)          

put this script on the GROUND plane where you want to spawn assets.
always(single pulse)-python

it will spawn 200 assets instantly on the plane, if new one spawns it will instantly spawn 200 on that plane as well up to a max of 3000, you can change it in the script. This is not a neat way because you freeze the engine on a frame till everything is spawned. but none the less it works.

okay i will try it.