My Game attribute is not updating my mesh during play

This is a little complicated so I’ll try and explain what is going on

I have a dynamic digital clock that takes a value from a game property and moves uv vertices around to create the display.

When I hard-code the time into the script that runs the clock, it works great. I have a picture here…


I circled the bit where I hard-coded the attribute and it works

So then the next step is I have a script that updates the game attribute from another location. That works too as shown in my second screenshot.


Here the time is set t 12:00 in the other script and it’s captured and updated when the game starts

However,

When I change the time in the other script, (I update Star.worldOrientation using the “Z” and “X” keys) Everything updates except for the clock in the game.


So why isn’t my clock updating? It should be as as update the UVs after every calculation.

Here is the code for the clock and for the script that sets it.


from bge import logic

uv_size=0.0797
cont = bge.logic.getCurrentController()
clock = cont.owner

mesh = clock.meshes[0] #access the mesh of the clock

clock_disp = clock["time"] 

char_len=len(clock_disp)

print ("Clocky = ", clock_disp)

#if the clock is 5 characters long, there is a "1" in the front
#else it's blank

if char_len==4:
    first_uv=0.92
else:
    first_uv=uv_size

#calculate the offsets on the UV map
fourth_uv = float(clock_disp[-1:])*uv_size
third_uv = float(clock_disp[-2:-1])*uv_size
second_uv = float(clock_disp[-4:-3])*uv_size

#map the UVs
#1st number
vert = mesh.getVertex(0,87)
uv = vert.getUV()
uv[0]=first_uv
vert.setUV(uv)

vert = mesh.getVertex(0,86)
uv = vert.getUV()
uv[0]=first_uv+uv_size
vert.setUV(uv)

vert = mesh.getVertex(0,84)
uv = vert.getUV()
uv[0]=first_uv
vert.setUV(uv)

vert = mesh.getVertex(0,85)
uv = vert.getUV()
uv[0]=first_uv+uv_size
vert.setUV(uv)

#2nd number
vert = mesh.getVertex(0,91)
uv = vert.getUV()
uv[0]=second_uv
vert.setUV(uv)

vert = mesh.getVertex(0,90)
uv = vert.getUV()
uv[0]=second_uv+uv_size
vert.setUV(uv)

vert = mesh.getVertex(0,88)
uv = vert.getUV()
uv[0]=second_uv
vert.setUV(uv)

vert = mesh.getVertex(0,89)
uv = vert.getUV()
uv[0]=second_uv+uv_size
vert.setUV(uv)

#3rd number
vert = mesh.getVertex(0,99)
uv = vert.getUV()
uv[0]=third_uv
vert.setUV(uv)

vert = mesh.getVertex(0,98)
uv = vert.getUV()
uv[0]=third_uv+uv_size
vert.setUV(uv)

vert = mesh.getVertex(0,96)
uv = vert.getUV()
uv[0]=third_uv
vert.setUV(uv)

vert = mesh.getVertex(0,97)
uv = vert.getUV()
uv[0]=third_uv+uv_size
vert.setUV(uv)

#4th number
vert = mesh.getVertex(0,31)
uv = vert.getUV()
uv[0]=fourth_uv
vert.setUV(uv)

vert = mesh.getVertex(0,30)
uv = vert.getUV()
uv[0]=fourth_uv+uv_size
vert.setUV(uv)

vert = mesh.getVertex(0,28)
uv = vert.getUV()
uv[0]=fourth_uv
vert.setUV(uv)

vert = mesh.getVertex(0,29)
uv = vert.getUV()
uv[0]=fourth_uv+uv_size
vert.setUV(uv)    


from bge import logic as g
import math
import time

tau=math.pi*2

scene = g.getCurrentScene()
Axis = scene.objects['SunAxis']
SunObj = scene.objects['Sun']
Sunpos = scene.objects['SunPosition']
Star = scene.objects['SunTarget']
BusClock = scene.objects['clock']

SunObj.worldOrientation = Axis.worldOrientation
SunObj.worldPosition = Sunpos.worldPosition
Star.worldOrientation = Axis.worldOrientation

rotation = Star.worldOrientation.to_euler()

seconds =(( rotation.y / tau) * 86400) + 43200

conv_time = time.strftime('%I:%M', time.gmtime(seconds))

if conv_time[:1] == "0":
    gametime=conv_time[-4:]
else:
    gametime=conv_time

BusClock['time'] = gametime


This looks a bit over complicated to me.

Get formatted time
As first step I suggest to have one Python controller calculating the time and placing it in a property. Why your time relies on the rotation of an object is a bit over my head and why you need all this object is not visible to me too.

the basic code can look like this:


def putFormattedTimeIntoProperty():
   formattedTime = retrieveFormattedTime()
   setProperty("time", formattedTime)

retrieveTime() depends on how you want to calculate the current time. A way is to get the system time, but you could calculate your own game time too.

Here is an example with system time:


import datetime
...
def retrieveFormattedTime():
    return datetime.datetime.now().strftime("%H:%M")

Just in case you do not know how to set a property:


import bge
...
def setProperty(property, value):
    bge.logic.getCurrentController().owner[property] = value

Output the time in scene
Moving UV texture is around is possible, but there are much better methods.
A) You can use a font object to output the formatted time. The resulting letters have a single color only.
B) Use a bitmap text to do the same thing. This effect is pretty that what you get with the moving UV as you can have colored textures. To convert a .ttf font to a text image look for FTBlender.

The logic is pretty simple. When the property changes (property sensor) -> change the property “Text”.
Indeed if you place the formatted time into the “Text” property directly, you do not even need this logic.

The example:
clock.py:


import bge
import datetime

def putFormattedTimeIntoProperty():
   formattedTime = retrieveFormattedTime()
   setProperty("time", formattedTime)

def retrieveFormattedTime():
    return datetime.datetime.now().strftime("%H:%M")

def setProperty(property, value):
    bge.logic.getCurrentController().owner[property] = value

sensor -> Python controller Module: clock.putFormattedTimeIntoProperty

The problem is that the game continually updates the rotation on the sun to create the day/night cycle. The clock reads the position of the sun and then calculates the time from that. (It’s not the clock the sets the time. It’s the sun that sets the time. Like reality)

As opposed to correcting the concept with different code, I’m more interested in why the system simply isn’t doing what I’m telling it to do. In my clock code I explicitly read the property set the by the other script. This is verified by both the debug info and the print statements, the vertexes are being properly calculated and in the end, the engine is not updating my new UV vertex locations. (Or it’s only doing it once at initialization)

I’m going to be reusing the concept for the odometer, which requires you to “slide” the UV window to create “half numbers” as the number rolls to it’s new value.

I can verify that the UV verts are being calculated to new values. Maybe the mesh isn’t updating? (Is blender using some kind of initialized instance) Can you force a mesh update to re-read the UV mapping? Can I alter it’s instance?

Also, I know this sounds selfish, but it took me two days to figure out how to create a clock value from blender’s really weird internal angle system. I had to fist figure out why it wasn’t spitting out normal degrees from 0-360 an discovered that it was “wrapping” at values close to pi and negative pi. I barely can do algebra and had to simply to Tau to figure out the whole pi negative/pi thing

as an aside. I tried to do a clock.update() but I got this error:
AttributeError: ‘KX_GameObject’ object has no attribute ‘update’
however, I’m seeing it used when they import the bpy lib so, I’ll experiment with that.

EDIT:
Yay! Tenacity pays off!

You have to update the mesh after you alter it or Blender just uses the instance you feed it.

The fix is to do the BGE equvalant of clock.update()
It’s clock.replaceMesh(mesh)

Congratulations!