mouse over any + movement problem

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()

to debug that I am going to need it in code tags so its indented.

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()



Attachments

HighLightWithFlickerOut.blend (491 KB)HighLightWithFadeOut.blend (492 KB)

looking at your code I think you may want to look into .copy()

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’ll comment it out and paste it again tonight,

:smiley:

Edit:
http://www.pasteall.org/60990/python


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.

  1. no object detected
  2. the same object detected
  3. 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.