renpy.set_mouse_pos is delayed?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

renpy.set_mouse_pos is delayed?

#1 Post by Milkymalk »

I use this code to change the mouse pointer to the image of a button when it is clicked and right before that move the pointer to a position where it looks like the "item" has been gently picked up. Yet for a split second, the image "jerks" to where the pointer has just been, but should not be any more when the cursor change has taken place.

I know that in theory I'm not supposed to change config variables after init, but this works except for that little detail and I know of no better way to do this. If you can help me do this better, I'm open to suggestions.
What I'm trying to achieve is a kind of "diablo" style inventory. So I want the item image to "become" the mouse pointer as long as it's picked up, and not jump to where the mouse pointer was when the player clicked.

Code: Select all

    def take_invitem(char=None, item=None):
        global hand
        hand = char.inv.items.pop(char.inv.items.index(item))
        for i in range(item[0].inv_ysize):
               for j in range(item[0].inv_xsize):
                   char.inv.slot[ j+item[1][1] ] [ i+item[1][0] ] = 0
        renpy.set_mouse_pos( item[1][0]*50+870, item[1][1]*50+430, duration=0)
        changemouse(m=item[0].id)
        hand = hand[0]
        
    def changemouse(m="default"):
        if m == "default":
            setattr(config, "mouse", None)
        else:
            setattr(config, "mouse", {"default": [(im.Composite(None, (0,0), "images/items/"+m+".png", (0,0), "images/interface/pointer.png"), 0, 0 ) ]})
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: renpy.set_mouse_pos is delayed?

#2 Post by Remix »

Would it not be sensible to just use Ren'py's drag and drop features to handle the dynamics instead? It would certainly integrate easier if you did opt for an Android or ios version at any stage?
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: renpy.set_mouse_pos is delayed?

#3 Post by Milkymalk »

That won't happen because the keyboard is integral to playing the game.
Drag and drop also requires the button to stay pressed (I think), something I don't want because the player has to be able to interact with other screen elements while holding the item.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: renpy.set_mouse_pos is delayed?

#4 Post by Remix »

If you know the exact co-ordinates of the buttons, you could calculate the effective x,y of the click inside the image then (rather than moving the x,y of the mouse) compose a cursor that has offsets reflecting those co-ordinates...

Pseudo code:

Code: Select all

init python:
    def pickup_gently( x, y, m ):
        m_pos = renpy.get_mouse_pos()
        offset = ( m_pos[0] - x, m_pos[1] - y )
        setattr(config, "mouse", {"default": [(im.Composite(None, (0,0), "images/items/"+m+".png", (0,0), "images/interface/pointer.png"), offset[0], offset[1] ) ]})
        
        # 
        # # personally I'd adjust the pointer.png by offset so it does not move
        # 
        # # Also note: I just wrote the offsets there without checking syntax, so adjust as needed

screen some_overlay():
    imagebutton idle "a.png" pos(700,400) action Function( pickup_gently, 700, 400, item )
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: renpy.set_mouse_pos is delayed?

#5 Post by Milkymalk »

Thank you, that is a good idea, but I don't think it helps as this would put the hotspot of the cursor at strange positions.

I will overthink my concept and try something else.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Andredron
Miko-Class Veteran
Posts: 718
Joined: Thu Dec 28, 2017 2:37 pm
Location: Russia
Contact:

Re: renpy.set_mouse_pos is delayed?

#6 Post by Andredron »

Milkymalk wrote: Thu May 24, 2018 10:12 am Thank you, that is a good idea, but I don't think it helps as this would put the hotspot of the cursor at strange positions.

I will overthink my concept and try something else.
Image

Code: Select all

init python:

    import pygame_sdl2 as pygame

    class __VirtualJoystick (renpy.Displayable):

        __author__ = u "Vladya"

        def __init __ (self):
            super (self .__ class__, self) .__ init __ ()

            self .__ stick_is_pressed = False
            self .__ size = None

            self .__ xalign = self .__ yalign = .5

        @property
        def stick (self):
            u "" "
            Take the stick position from here.
            The format of the return is a tuple (x, y).
            Where each value determines the travel speed multiplier
            object from -1 to 1 in inclusive, along the corresponding axis.
            "" "
            return tuple (
                map (
                    lambda a: ((a * 2.) - 1.),
                    (self .__ xalign, self .__ yalign)
                )
            )

        def get_circle (self, radius, color = u "fff"):
            u "" "
            Programmatically draws a circle.

            : radius:
                The radius of the circle.
            : color:
                Color tuple, or in hexadecimal.
            "" "
            radius = int (radius)
            diameter = radius * 2
            canvas = renpy.Render (diameter, diameter) .canvas ()
            canvas.circle (color = color, pos = (radius, radius), radius = radius)
            return (canvas.surf, diameter)

        def event (self, ev, x, y, st):

            if not self .__ size:
                return

            w, h, x, y = map (float, (self .__ size + (x, y)))

            if ev.type == pygame.MOUSEBUTTONDOWN:
                self .__ stick_is_pressed = bool (
                    ((.0 <= x <= w) and (.0 <= y <= h))
                )
            elif ev.type == pygame.MOUSEBUTTONUP:
                self .__ stick_is_pressed = False

            if self .__ stick_is_pressed:
                self .__ xalign, self .__ yalign = map (
                    lambda a: max (min (a, 1.), .0),
                    ((x / w), (y / h))
                )
            else:
                self .__ xalign = self .__ yalign = .5

        def render (self, width, height, st, at):

            circle_radius = min ((width * .1), (height * .1))

            big_circle, bigD = self.get_circle (circle_radius)
            smallMultipler = (.8 if self .__ stick_is_pressed else 1.)
            small_circle, smallD = self.get_circle (
                (circle_radius * .5 * smallMultipler),
                u "000"
            )

            baseRenderObject = renpy.Render (bigD, bigD)

            baseRenderObject.blit (big_circle, (0, 0))
            smallXPos, smallYPos = map (
                lambda align: int (((bigD * align) - (smallD * align))),
                (self .__ xalign, self .__ yalign)
            )
            baseRenderObject.blit (small_circle, (smallXPos, smallYPos))

            self .__ size = (bigD, bigD)
            return baseRenderObject

    class JoystickMove (renpy.Displayable):

        __author__ = u "Vladya"

        joystickAlign = (.05, .95)

        def __init __ (self, child, time_speed = 3.):
            u "" "
            : child:
                The object to move.
            : time_speed:
                Time in seconds, for full movement
                from one end of the screen to the other.
            "" "

            super (self .__ class__, self) .__ init __ ()
            self .__ child = child
            self .__ joystick = __VirtualJoystick ()
            self .__ time_speed = float (time_speed)

            self .__ jxPos = self .__ jyPos = 0

            self .__ last_st = .0

            self .__ childXAlign = self .__ childYAlign = .5

        @property
        def align (self):
            u "" "
            From here take the current relative position on the screen.
            Data type: The tuple of the form (xalign, yalign).
            "" "
            return (self .__ childXAlign, self .__ childYAlign)

        def event (self, ev, x, y, st):
            self .__ joystick.event (
                ev,
                (x is self .__ jxPos),
                (y - self .__ jyPos),
                st
            )

        def render (self, width, height, st, at):

            stickXSpeed, stickYSpeed ​​= self .__ joystick.stick
            increment = (st - self .__ last_st) / self .__ time_speed
            xIncrement = stickXSpeed ​​* increment
            yIncrement = stickYSpeed ​​* increment
            newX, newY = (
                (self .__ childXAlign + xIncrement),
                (self .__ childYAlign + yIncrement)
            )

            self .__ childXAlign, self .__ childYAlign = map (
                lambda a: max (min (a, 1.), .0),
                (newX, newY)
            )

            child = self .__ child.render (width, height, st, at)

            childXSize, childYSize = child.get_size ()

            childXPos = int (
                (
                    (
                        (width * self .__ childXAlign)
                    ) - (
                        (childXSize * self .__ childXAlign)
                    )
                )
            )
            childYPos = int(
                (
                    (
                        (height * self.__childYAlign)
                    ) - (
                        (childYSize * self.__childYAlign)
                    )
                )
            )

            baseRenderObject = renpy.Render(*map(int, (width, height)))
            joystick = self.__joystick.render(width, height, st, at)

            jw, jh = joystick.get_size()
            jxAl, jyAl = self.joystickAlign
            self.__jxPos = int(((width * jxAl) - (jw * jxAl)))
            self.__jyPos = int(((height * jyAl) - (jh * jyAl)))

            baseRenderObject.blit(child, (childXPos, childYPos))
            baseRenderObject.blit(joystick, (self.__jxPos, self.__jyPos))

            self.__last_st = st

            renpy.redraw(self, .0)

            return baseRenderObject


label start:

    # Юзать либо как трансу, либо как обёртку для изображения.
    show expression Text(u"Test 123", size=150) at JoystickMove
    $ ui.interact()
    return

Post Reply

Who is online

Users browsing this forum: No registered users