Random colored assets. (Random colors, same material?)

Hello, I’m trying to make assets that when created, have slightly different color variations.
(EG, trees)
I can make each object generate a random property, but since they all share the original objects material, they all end up the same color, and every time you spawn a new instance of the object, it just changes the color of them all.
Example blend:
cube_random_color_spawn.blend (668.7 KB)

This project requires that:

The cubes have the texture included in the material.

Each cube is a different color.

The result can’t be achieved by changing the mesh.(Imagine making 10 tree assets, and wanting 10 random shades. You’d need 100 different meshes!)

Objects at the start have to be randomized as well as new instances of the object.

So, as you can see from the blend, I’m animating the color, and using a random property to set the frame of that animation, changing the color. I really want to use this technique, but it there’s a better way, I’m open to learning.

P.S. i’m not using UPBge.

1 Like

something like this?
cube_random_color_spawn_by_cotaks.blend (663.4 KB)

removed your keyframes
removed all your bricks
removed your empty
set the material color to white
ticked the object color in materials options

if you want specific, you can just create an list with colors you like, then .pop() from that list and use that color, so you can just use brownish colors for example.

Cotaks’ way is likely what you’re looking for. But just to add to the topic,

If you want to always generate the exact same sequence of random numbers, you can try numpy. For as long as you feed the same seed to your random state, you’ll get the same numbers.

import numpy as np
seed = 0

prng = np.random.RandomState(seed)
aRed = prng.rand(100); aGreen = prng.rand(100); aBlue = prng.rand(100)
colors = [ False for v in range(100) ]

for i in range(100):
    colors[i] = [aRed[i], aGreen[i], aBlue[i], 1]

Then to get a different sequence of colors, you just change the value of seed.

Thanks for taking the time to put that together!

That’s definitely a step in the right direction. Much simpler.

Two things though.

One, how do I chose the colors that the object can spawn as? I don’t want for example blue trees, and most trees are a very specific range of colors.

Two, I need the pre-existing cubes to randomize color, as they represent objects that interact with other objects in a group via logic-bricks. Inherently, I want for example a group I can create that contains a tree trunk, animated or even rigged leaves/branches (With the random colored leaves). This group needs to be able to be spawned in, and be random each time.

Thanks for your time so far.

example:

import random


def spawn_cube(cont):
    
    own = cont.owner
    
    sensor = cont.sensors['Keyboard']
    
    trunk_colors = [ # rgba (1 = alpha)
                    [0.342 , 0.078, 0.023, 1], #light brown
                    [0.200 , 0.048, 0.015, 1], #darker brown
                    [0.052 , 0.015, 0.006, 1] #dark brown
                    ]
    

    if sensor.positive:
        added_object = own.scene.addObject('particle cube', own,0)
        added_object.color = random.choice(trunk_colors)


    #put a property in the existing cubes
    #put that property name where property stands
    # best to make a separate function for this part,
    #or make a way that this will only be executed once
    for obj in own.scene.objects:
        if 'property' in obj:
            obj.color = random.choice(trunk_colors)

#edit
removed type

depending on the complexity of the shader used, it could be as simple as checking the object color box.

however, a node tree in vanilla bge may be much more complex if you dont have the object info color node that upbge has.

could have sworn i posted a demo file somewhere showing this. ill post another when i get to my pc.

So, I’ve been trying to edit your code to fit my project. I’m still learning python.

Here are my persistent problems. I want to be able to place trees, ect. in the scene, and them have them random when the game runs. If I have say, an object that represents a tree that spawns an actual randomly colored one, it’s logic brick stricture relative to it’s branches and trunk are no longer connected.

Another example is characters. Say, If I want NPCs to have random skin color. Sure I can spawn a rigged skin, but how will I make sure it syncs with the clothes or skeleton, let alone logic bricks.

Is there a way to hook up a property logic brick to a python controller, where the python controller changes the local object’s color, yet not the universal material’s color? This would be much more versatile.

@Ranstone

Why couldn’t you just use Object_Color & use it with a python script to assign different colors to defined characters when they are spawned :thinking:

[ EXAMPLE ]
[1] Spawn Character
[2] If Character is good guy --> Color_Green. If Character bad guy --> Color_Red.

:arrow_up: This should be enough for ALL objects enless your trying to use MULTIPLE materials for 1 mesh.

[ EDIT ]
Object Color is definitely the thing your looking for then.
Will make a script for you in the future (I am a little late on dead-lines right now :slight_smile:)

Exactly. I just can’t figure out the python code to put in the controller.

1 Like

@Ranstone

Here is the blend file :slight_smile:
Controls are explained in-game.

Per-Object_Material.blend (110.8 KB)

Accessing spawned objects technique I learned from @Thatimster
(maybe could have learned it without watching one of his awesome tutorials but who can tell :wink:)

Thanks for taking the time to put that together. It really helps out, as well as helps me understand Python for future projects. Gunna go work on this for a bit.

Thanks!

1 Like

@Ranstone

Did you try demo file or are you just saying thanks before-hand :slight_smile: (?)
(not trying to me mean, just curious) :wink:

[ EDIT ]
If you choose absolute random colors then you might want decimal numbers & the function I used only uses whole numbers.
But there is a number random function that does allow it so feel free to ask me for it if you do.

I would not use @RandomPerson script, way to sloppy and resource intensive.

what do you not get from my script?
It does what you want.

color existing objects random or predefined(trunk_colors list)

here is all the code together

import random

trunk_colors = [ # rgba (1 = alpha)
                [0.342 , 0.078, 0.023, 1], #light brown
                [0.200 , 0.048, 0.015, 1], #darker brown
                [0.052 , 0.015, 0.006, 1] #dark brown
                ]
   
                    
def spawn_cube_with_random_color(cont):
    
    own = cont.owner
    
    sensor = cont.owner.sensors['Keyboard']
    
    if sensor.positive:
        added_object = own.scene.addObject('particle cube', own,0)
        added_object.color = [random.uniform(0.00,1.0) ,random.uniform(0.00,1.0) ,random.uniform(0.0,1.0) ,1]


def spawn_cube_with_random_predefined_color(cont):
    
    own = cont.owner
    
    sensor = cont.sensors['Keyboard']

    if sensor.positive:
        added_object = own.scene.addObject('particle cube', own,0)
        added_object.color = random.choice(trunk_colors)


def change_existing_objects_color(cont):
    
    own = cont.owner
    #put a property in the existing cubes
    #put that property name where property stands
    # best to make a separate function for this part,
    #or make a way that this will only be executed once
    for obj in own.scene.objects:
        if 'property' in obj:
            obj.color = random.choice(trunk_colors)
1 Like

@Cotaks

Ok.
I’m going to try to make this clean & not too bias . . .

Your the one using a sensor :stuck_out_tongue:

Anyway @Ranstone your free to choose any method that suits your needs.
(I won’t be offended like @Cotaks) :wink:

yup because he uses them in his blend.

I’m not offended at all, just curious, your sloppy script does the exact same thing. except for current objects that he also asked for.

making a random number in true pulse changing a property every tic is not the way to go.
you don’t even need true pulse for this.

but anyway i don’t care which one he picks as long as he’s happy with it.

1 Like

Yes @Cotaks
We are on the same team.
Let us rejoice as we are both Python Coders :slight_smile:

[ EDIT ]
This is weird since I look at the bge docs almost per-day but I didn’t know cont.owner had scene() function (nice job)

& also to be fair. I looked like maybe 25% at your script before I posted my blend file :grin:

[ QUESTIONS ]

    • Why are you creating multiple modules (?) You should just be using 1.
    • What do you mean resource intensive (?) The properties are for easy access if you mean that.

50.0% True.
You don’t need true pulse but you also get more random numbers if your on a constant time-stream.

To name the functions by what it does, and so that not all script lines get read/used until used/called.
also to be used multiple times by different objects.

for example 10 objects runs 1st function. some other objects can use the other functions if needed. so 1 script for lots of functions that basically does the same thing. (keeping things together instead of creating 10 scripts)

from bge import *
from random import *

Don’t use * it’s outdated, import bge does the same thing or if you need a sub module use

from bge import logic,render,etc
COLOR_RANDOM = [randint(0,1),randint(0,1),randint(0,1),1]

why use randint here, you could use randint(1,4) instead of your property or random.choice(), or if you use upbge using weighted random like random.choices.

oh wait you use it

cont.owner["COLOR_NUMBER"] = randint(1,4)

and then you do

if cont.owner["COLOR_NUMBER"] == 1:

so the whole property is wasted resources
because with a list you can pick directly from it like i did.

then you get the if statement

        if cont.owner["COLOR_NUMBER"] == 1:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_BLUE
        if cont.owner["COLOR_NUMBER"] == 2:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_RED
        if cont.owner["COLOR_NUMBER"] == 3:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_GREEN
        if cont.owner["COLOR_NUMBER"] == 4:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_YELLOW

repeating code all over while it could be just 3 lines of code
also you check for things that never gets True.

if you make an if statment like that then atleast use elif, like this

        if cont.owner["COLOR_NUMBER"] == 1:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_BLUE
        elif cont.owner["COLOR_NUMBER"] == 2:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_RED
        elif cont.owner["COLOR_NUMBER"] == 3:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_GREEN
        elif cont.owner["COLOR_NUMBER"] == 4:
            OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
            OBJ.color = COLOR_YELLOW

then if you want to define an object you could simply do:

    if SPAWN_DEFINED == 1:
        #Define the selected colors to spawned objects
        OBJ = logic.getCurrentScene().addObject("PROP : CUBE", cont.owner)
        if cont.owner["COLOR_NUMBER"] == 1:            
            OBJ.color = COLOR_BLUE
        elif cont.owner["COLOR_NUMBER"] == 2:
            OBJ.color = COLOR_RED
        elif cont.owner["COLOR_NUMBER"] == 3:
            OBJ.color = COLOR_GREEN
        elif cont.owner["COLOR_NUMBER"] == 4:
            OBJ.color = COLOR_YELLOW
            
    elif SPAWN_RANDOM == 1:
        OBJ.color = COLOR_RANDOM

also the color you could just assign that to a variable as well

    if SPAWN_DEFINED == 1:

        if cont.owner["COLOR_NUMBER"] == 1:            
            color = COLOR_BLUE
        elif cont.owner["COLOR_NUMBER"] == 2:
            color = COLOR_RED
        elif cont.owner["COLOR_NUMBER"] == 3:
            color = COLOR_GREEN
        elif cont.owner["COLOR_NUMBER"] == 4:
            color = COLOR_YELLOW

    elif SPAWN_RANDOM == 1:
        color = COLOR_RANDOM
    
    OBJ.color = color   
    
    #or so color exist set color
#    if color:
#         OBJ.color = color

And so on…

I would just put colors into a list and pick random from that, saves you coding time as well.
it looks better and saves resources.

This answer good enough?

@Cotaks

Haha we all have our ways to code :smiley:

Btw do you have a game on BA (?) Just curious. Haven’t seem really any games from you :slight_smile:

click my name, then scroll all the way down

Uh ok.
Nice DEMO :wink: