Both sensors, mouse over any and mouse motion, are connected to the same script - owner is camera. Script is below. In the example scene, I have two cubes. When mouse pointer is over an object, the object should turn to red. And when pointer leaves the object, the color should turn back to original. That does not work: the red color remains.
The code below does a bit more: It handles the cases when pointer leaves the object to another object or to no-object (no hit). Also, when pointer moves over the object, the script flashes the color of the object between red and green. Extra problem here is that the color of the object is combination of red and green - like renderer uses weird raster and combines red and green cubes - at least I see some kind of raster.
Code:
import bge
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
# mouse = cont.sensors['Mouse']
# mx = mouse.position[0]
# my = mouse.position[1]
scene = bge.logic.getCurrentScene()
camera = scene.active_camera
mouseover = cont.sensors ["mouseover"]
if mouseover.positive:
target = mouseover.hitObject
if 'savedtarget' not in own:
own['savedtarget'] = target
own['savedcolor'] = target.color
target.color = [1.0,0.0,0.0,1.0]
elif target == own['savedtarget']:
a = target.color[0]
target.color[0] = target.color[1]
target.color[1] = a
else:
savedtarget = own['savedtarget']
savedtarget.color = own['savedcolor']
# del own['savedtarget']
# del own['savedcolor']
own['savedtarget'] = target
own['savedcolor'] = target.color
target.color = [1.0,0.0,0.0,1.0]
else:
if 'savedtarget' not in own:
b = 1
else:
savedtarget = own['savedtarget']
savedtarget.color = own['savedcolor']
del own['savedtarget']
del own['savedcolor']
main()
Now the code is in code segment. Both mouse movement and mouse over any are connected to it. If this does not work, then I use only mouse movement and do a mouse-over-any check in Python - either existing utils or manually using ray casting (hard way).
The final applications are quite simple: (1) image arranger - lay down images to virtual desk, (2) GUI for audio sequencer/editor. I have written such in GTK/C so I know the application side well.
I checked out what you were doing and came up with
import bge
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
MOA = cont.sensors['MouseOverAny']
if type(own['HighLightList']) is not str:
index=0
for objects in own['HighLightList']:
if objects[1]>=1:
objects[1]-=1
objects[0].color=(objects[0]['color'][0]+(bge.logic.getRandomFloat()*.25),objects[0]['color'][1]+(bge.logic.getRandomFloat()*.25),objects[0]['color'][2]+(bge.logic.getRandomFloat()*.25),objects[0]['color'][3])
else:
objects[0].color=objects[0]['color']
own['HighLightList'].pop(index)
index+=1
if MOA.positive:
if 'color' not in MOA.hitObject:
MOA.hitObject['color']=MOA.hitObject.color.copy()
MOA.hitObject.color=(MOA.hitObject['color'][0]+.25,MOA.hitObject['color'][1]+.25,MOA.hitObject['color'][2]+.25,MOA.hitObject['color'][3])
if type(own['HighLightList']) is str:
own['HighLightList']=[[MOA.hitObject,30]]
else:
n=0
for objects in own['HighLightList']:
if objects[0]==MOA.hitObject:
objects[1]=30
n=1
if n==0:
own['HighLightList'].append([MOA.hitObject,30])
main()
The problem was in missing .copy(). I’m not familiar how Blender/Python manages memory. I wished to pre-allocate the color property, and have C-like copy. So, no malloc(), no anything going to garbage collection.
Your codes are too complicated to me. But guess I need them if I select many objects. I have that kind of selection in GTK/C version of the image arranger.
i did this last night but forgot to save so i did it again real quick. not sure if this is exactly the behavior you are looking for but it just took a couple code tweaks to your original code. the flickering was caused by your swapping block of code in the ‘elif’ clause. it was swapping red and green every frame that your mouse was moving over the object. this works fine on multiple targets.
import bge
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
# mouse = cont.sensors['Mouse']
# mx = mouse.position[0]
# my = mouse.position[1]
scene = bge.logic.getCurrentScene()
camera = scene.active_camera
mouseover = cont.sensors ["mouseover"]
if mouseover.positive:
target = mouseover.hitObject
if 'savedtarget' not in own:
own['savedtarget'] = target
own['savedcolor'] = target.color
target.color = [1.0,0.0,0.0,1.0]
elif target == own['savedtarget']:
target.color = [1.0,0.0,0.0,1.0]
else:
# run this if mousing over new target
# from old target without mousing over
# empty space
savedtarget = own['savedtarget']
savedtarget.color = [0.0,1.0,0.0,1.0]
# del own['savedtarget']
# del own['savedcolor']
own['savedtarget'] = target
own['savedcolor'] = target.color
target.color = [1.0,0.0,0.0,1.0]
else:
if 'savedtarget' not in own:
pass # use pass as a placeholder
else:
savedtarget = own['savedtarget']
savedtarget.color = [0.0,1.0,0.0,1.0]
del own['savedtarget']
del own['savedcolor']
main()
if you want all targets to start out green, give them a string property ‘target’ and then set all objects with that ‘target’ property green when you start up
I can’t see why you want a mouse movement sensor. The object can be moved from below the cursor without moving the cursor e.g. by moving the object or the camera.
I suggest to enable the sensors Pulse mode. This forces the sensor to trigger the connected controllers each time it detects a different object.
Following implementation checks three situations.
no object detected
the same object detected
a different object detected
def toggleColor():
hitObject = getHitObject()
storedObject = restoreObject()
if not hitObject:
restoreColor()
storeObject(hitObject)
return
if hitObject is storedObject:
return
if storedObject:
restoreColor()
storeObject(hitObject)
storeColor(hitObject)
setOverrideColor(hitObject)
Now you need some details. Here is an example:
import bge
PROPERTY_COLOR = "color"
#--- bge callable
def toggleColor():
hitObject = getHitObject()
storedObject = restoreObject()
if not hitObject:
restoreColor()
storeObject(hitObject)
return
if hitObject is storedObject:
return
if storedObject:
restoreColor()
storeObject(hitObject)
storeColor(hitObject)
setOverrideColor(hitObject)
#--- internal
INTERNAL_PROPERTY_STORED_COLOR = "_stored.color"
INTERNAL_PROPERTY_STORED_OBJECT = "_stored.object"
def restoreObject():
return getStorage().get(INTERNAL_PROPERTY_STORED_OBJECT)
def storeObject(object):
getStorage()[INTERNAL_PROPERTY_STORED_OBJECT] = object
def restoreColor():
object = getStorage()[INTERNAL_PROPERTY_STORED_OBJECT]
object.color = getStorage()[INTERNAL_PROPERTY_STORED_COLOR]
def storeColor(object):
getStorage()[INTERNAL_PROPERTY_STORED_COLOR] = object.color.copy()
def setOverrideColor(object):
colorDescription = getStorage()[PROPERTY_COLOR]
color = [float(term) for term in colorDescription.split(",")]
object.color = color
def getStorage():
return bge.logic.getCurrentController().owner
def getHitObject():
for sensor in bge.logic.getCurrentController().sensors:
try:
if sensor.hitObject:
return sensor.hitObject
except AttributeError:
pass
Here the owner acts as storage to keep a reference to the sensed object and the original color.
You can provide the override color as string property called “color” e.g. “1, 0, 0, 1”
As usual: The function “main” adds no value and can be removed. As it is now - it increases complexity and adds confusion by a non-descriptive statement.