Page 1 of 1

Programatically added hotspots on an image map

Posted: Mon Oct 31, 2022 7:44 am
by Thaw87
I am looking forward to a better way to describe and add hotspots to an image map. I have a screen that defines for a basic Point&Click behavior, where I can add a location python object as a parameter. This object defines every aspect of the screen so I can reuse this screen all over my game.

Here is the screen's snippet:

Code: Select all

screen pointnclick_screen(location):
    tag pointnclick
    layer "master"
    zorder 0
    imagemap:
        ground [location.name]
        for i,spot in enumerate(location.spots):
            if spot.is_visible():
                imagebutton:
                    pos spot.position
                    idle spot.sprite
		    focus_mask spot.sprite
                    action Jump(spot.target)
I have python classes for the Location and for the Hotspots:

Code: Select all

class Location:
	def __init__(self, name, spots):
		self.name = name
		self.spots = spots
		
class Hotspot:
	def __init__(self, position, sprite, target = None, visible = None):
		self.position = position
		self.sprite = sprite
		self.target = target
		self.visible = visible
		
	def is_visible(self):
		if self.visible:
			return eval(self.visible)
		else:
			return True		
When I define a scene I do it in python like so:

Code: Select all

define my_scene = Location("bg myscene",
    [
        # Foo
        Hotspot((2918, 1027),
        sprite = "sprite foo",
        target = "ask_foo"),

        # Bar
        Hotspot((6370, 957),
        sprite = "sprite bar",
        target = "goto_bar",
        visible = "not need_to_ask_foo"),
    ]
My problem is that I'm not t satisfied with this framework. Sometimes I need to 'hide" hotspots where the player is not allowed to click yet. Like Bar, I have a visible member, where I write python statements in string format. I evaluate this in the Hotspot's is_visible method: eval(self.visible). It works but eval is slow and I feel like I missing out on some feature of from Ren'Py.
  • I can't write the variable name as is, because - according to the compiler - the variable is not known at that point, and because sometimes I need to add a "not" or make combined/complex conditional statements.
  • I know I can't use lambdas
  • I played with renpy.curry(), but messed it up.
  • Maybe my whole python approach is wrong
  • The pointnclick_screen is more complex (I pasted here only the relevant parts), including frames, keymaps, and control buttons, so I really want to reuse it rather than create one for every scene.

Re: Programatically added hotspots on an image map

Posted: Mon Oct 31, 2022 9:26 am
by Ocelot
A collection of composable function objects?

Code: Select all

class C_Value:
    def __init__(self, val):
        self.val = val
    def __call__(self):
        return self.val

class C_Variable:
    def __init__(self, name):
        self.name = name
    def __call__(self):
        return getattr(store, name)

class C_Negation:
    def __init__(self, fo):
        self.fo = fo
    def __call__(self)
        return not fo()

# You can do classes for any operation you need.

# Change hotspot class:
	def is_visible(self):
		if self.visible is not None:
			return self.visible()
		else:
			return True		

# And pass a combined function object:
visible = C_Negation( C_Variable("need_to_ask_foo") ),

Re: Programatically added hotspots on an image map

Posted: Mon Oct 31, 2022 3:08 pm
by Thaw87
Thank you, the getattr(store, name) looks fancy.

What about currying? Isn't that fit here well?

Also, I'm open to a screen-bases solution too.

Re: Programatically added hotspots on an image map

Posted: Mon Oct 31, 2022 3:50 pm
by Ocelot
Cyrrying is basically packaging some of function arguments withing function object, so it could be called with less arguments. I do not see, how this could be used in this case. Technically, you can pass curried function to the C_Negation and classes that are defined similarly to it, as it just expects function object.