Change texture with python ingame

Hello folks, I reall need your help.
I’m working on an Animal Crossing clone in the BGE for about 1/2 years now and am pretty far now.
As you maybe know, Animal Crossing is a life simulator, so also with different seasons.
My solution for this problem always was to duplicate every acre (the town is made of acres) and change the texture of every single acre, and if it’s summer for example I always used the “Replace Mesh” function to replace the “winter mesh” with a “summer mesh”…
But as you know this is not really a solution because I’m always adding new acres and it’s pretty annoying to always have multiple acres form the same type with different textures, it also wastes unnesessary memory.
So my question is, can I simply have a pyhton script where I can change the texture of every single acre?
So if it’s summer, the textures changes to a summer texture, when it’s winter, to a winter texture?
Every acre has the same season texture, so maybe you can help me. I’m absolutely no coder so I don’t really know how
to make such script, therefore I’m looking for experts here on blenderartist.org
Thank you for reading, I hope you can help :slight_smile:

Well changing the mesh of every acre object is possible as well, just duplicate the mesh give it another material that matches up with the season, then rename that duplicated objects mesh, “acre(insert season here)”. Put it in another layer, and just access it’s mesh whenever the season changes.

Sorta like I show here, it even works with new acre objects being added.

I have the .blend file below, if anything confuses you about the code just let me know. :slight_smile:

Season_Mesh_Change.blend (778 KB)

I really really really appreciate your answer, really! But replacing the mesh is what I try to avoid…
For example if I want to change the shape of an acre I have to do this with every other copied acres too, you know? Therefore I search for a simple “texture change” script, so the textures of every acre can be changed with one single script, I hope you know what I mean.
And again, a big thanks for your reply, I really appreciate your answer :slight_smile:

It is not that simple. The BGE is not designed to manipulate the materials at that level.

You can do it with video-texture. Be aware this needs quite some python code.
You can manipulate the UV_coordinates too (look for UV-scroll).

Btw. what is bad at replacing meshes? Typically objects like trees look completely different in winter and in summer. They do not just change color.

It is super easy to change the textures. Have all the textures in a folder and use this code:


from bge import logic

cont = logic.getCurrentController()
own = cont.owner

path = own["path"]

try:
    del logic.video
except:
    pass
        
if not hasattr(logic, 'video'):
    matID = texture.materialID(own, "MA"+own["material"])
    logic.video = texture.Texture(own, matID)
    logic.video.source = texture.VideoFFmpeg(path)
    logic.video.source.scale = True
    logic.video.source.play()
    logic.video.refresh(True)

path variable is the path to the texture you want. I set it to own[“path”] so you can simply set the string variable on the object to the path.

The snippet from the BGE API is not good sample. The code lacks on flexibility as it restricts itself to a single texture by using bge.logic as storage.

A better desging is to

  • store the texture at the mesh owner (so you can have one video texture source per object)
  • store the texture at a texture managing object (so each texture manager manages one texture source)
  • store the texture in a storage by a key (so you can have as many texture sources as you like)

(keep in mind several objects can share the same mesh).

The core code is:


import bge 


materialID = ...
path = ...

imageSource = texture.ImageFFmpeg(path)
imageSource.refresh(True)

texture = bge.texture.Texture(own, matID)
texture.source = imageSource
texture.refresh(True)

#store texture somewhere e.g. at the managing object (this one)
owner["texture"] = texture

Another possibility is lib load.
Make two blends, each with different textures, then libload the blend you want.
Less coding, but takes up more space on disk.

You can use the texture module to change textures, but I’ve not found it that flexible or reliable. There are times when the texture fails to load for no apparent reason. If that happens to a customer playing your game they won’t be happy.

Thank you for all your great support! I will definitely use one of your methods! Thanks :slight_smile:

actually It can have multiple textures because I added lines 8-11

Do you mean this?


try:
    del logic.video
except:
    pass

Well, be careful because lots of objects can share the same material and the same texture. Storing the textures in bge.logic as a dictionary can be useful since it forces you to remember which ones you have switched, and allows you to get a dict item from a central location for testing and hunting down problems.

if we libload in a mesh, and it’s materials, and edit it, can we then libLoad in the same object with unique materials again?

As far as I remember you can load these data just once. You an create an independent instance of mesh via LibNew but I’m not sure if the materials become independent copies too.

Yes I did. What it does is deletes the current video texture before adding a new one.

The intention is good, but it does not do that. It removes a reference to the texture that was stored at the module bge.logic.

It is not necessary. The storage gets overwritten some lines later (logic.video =…). There is no benefit in removing it first.
It is not even necessary to store the texture at that storage. It is used locally only. It is sufficient enough to keep the texture object in a variable (which will die after existing the code block).

The storage is necessary when you want to do something with the object at a later stage (usually at a later time). E.g. refreshing from video, refreshing from a camera … .

There is no explicit method to remove the texture. I guess the implementation relies on the implicit garbage collector.

This makes the above code not incorrect. It does more than necessary.

Only if you use the data mode on LibLoad, otherwise you’re only making a new instance. And though this could be a fine solution in other scenarios, duplicating all object data peer instant doesn’t seem a very approachable option when talking about something like a forest.

The UVs do so I assume the materials too, or at least you should be able to change the whole material instead of just the texture within. I have not testes it though.