UDD and the animation.

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
sdx231
Newbie
Posts: 3
Joined: Wed Nov 25, 2020 2:25 am
Contact:

UDD and the animation.

#1 Post by sdx231 » Wed Nov 25, 2020 11:42 am

Is it possible to make an animation with a UDD? The reason why I ask is I can't stop the usuall "transform" operator and get variables from it.
The minigame's idea is that there is a gauge and mark on it that moves back and forth while button isn't pressed. When it's pressed mark stops and check the conditionals. If mark is on scale's center the player win.
I have questions:
1. Does UDD accept other methods besides __init__, render and event?

Code: Select all

    class Displayable(renpy.Displayable):

        def __init__(self, child):
            super(Displayable, self).__init__()
            self.child = renpy.displayable(child)
            self.width = 0
            self.height = 0

        def render(self, width, height, st, at):
            t=Transform(child=self.child)
            child_render = renpy.Render(t,width,height,st,at)
            self.width, self.height = child_render.get_size()
            render = renpy.Render(self.width,self.height)
            render.blit(child_render, (0,0))
            return render
            
    class Mark(Displayable):

        def __init__(self, child):
            super(Displayable, self).__init__()
            self.child = renpy.displayable(child)
            self.width = 0
            self.height = 0
            self.s = [i for i in range(-25,26)]

        def render(self, width, height, st, at):
            t=Transform(child=self.child)
            child_render = renpy.render(t,width,height,st,at)
            self.width, self.height = child_render.get_size()
            render = renpy.Render(self.width,self.height)
            render.blit(child_render, (0,0))
            return render

        def move(self):
            while yalign < 0.5:
                yalign +=0.05
2. If yes, then how can I activate them?

Code: Select all

    add Mark("mark/mark.png"):
        xalign 0.5
        yalign 0.15
I may got smth wrong about position...
P.S. If it's still doable on screens (which I doubt), please, let me know.
Last edited by sdx231 on Wed Nov 25, 2020 10:57 pm, edited 1 time in total.

User avatar
RicharDann
Veteran
Posts: 284
Joined: Thu Aug 31, 2017 11:47 am
Contact:

Re: UDD and the animation.

#2 Post by RicharDann » Wed Nov 25, 2020 1:10 pm

I'm not familiar with creator-defined displayables, as for now they seem too complicated for me, but as it happens I've been experimenting as I need something similar for my game, and so far I think this could be done with variables and screens. There is just one little problem. Here's an example:

Code: Select all

screen gauge_minigame():
    
    default position = 0
    default direction = 'right'
    
    if direction == 'right':
        timer .01 repeat True action [SetScreenVariable('position', position+10),
                                      If(position > 100, true=SetScreenVariable('direction', 'left'))]    
    elif direction == 'left':
        timer .01 repeat True action [SetScreenVariable('position', position-10),
                                      If(position < -100, true=SetScreenVariable('direction', 'right'))]

    text "[position]" align (.5,.4)
    add "mark.png" align (.5, .5) xoffset position
    textbutton "Hit!" align (.5,.6) action Return(position)

label start:
    
    call screen gauge_minigame

    #the returned value from a called screen is stored in _return variable

    if _return in range(-30,30): 
        "You scored [_return]. Your win!"
    else:
        "You scored [_return]. You lose."
    
    return
Now the problem with this method is performance. In my testing, for the mark to move smoothly across the screen I had to set the timer to 0.01 seconds, but this causes the hover effect on buttons to stop working correctly (buttons are clickable, but sometimes it doesn't change color when hovered). Maybe because the screen is being refreshed too quickly. Setting it higher doesn't affect hovering but causes the mark's movement to become jarred or lag depending on the range of the min and max values (those where the direction changes) and the increment of the position variable.

I'll keep looking into this.
The most important step is always the next one.

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Projects: The Button Man
Organization: NILA
Github: hell-oh-world
Location: Philippines
Contact:

Re: UDD and the animation.

#3 Post by hell_oh_world » Wed Nov 25, 2020 3:31 pm

Not really fully an expert at CDD but you can try this.

Code: Select all

init python:
  class Mark(renpy.Displayable):
    def __init__(self, d, duration=3.0, range=(0.25, 0.75)):
      renpy.Displayable.__init__(self)
      
      self.d = renpy.displayable(d)
      self.st = 0 # the current time
      self.dir = 1 # the direction of the slide 1 is right, -1 is left
      self.xalign = 0 # the xalign to use for the transform
      self.dur = duration # the duration of the slide
      self.range = range # the range that spans from the middle that needed to be timed right.
      
    def render(self, w, h, st, at):
        r = renpy.Render(w, h) # our render

        if not self.st:
            self.st = st

        td = st - self.st # the timedelta
        f = td / float(self.dur) # the xalign factor
        self.xalign = f if self.dir == 1 else 1.0 - f # we do a reverse xalign if dir == -1

        if self.xalign > 1.0: # reset the time and set dir to -1 when the right most edge is reached
            self.st = 0
            self.dir = -1

        elif self.xalign < 0.0: # reset the time and set dir to -1 when the left most edge is reached
            self.st = 0
            self.dir = 1
    
        t = Transform(self.d, xalign=self.xalign)
        s1 = Solid("#0f03", xysize=(10, 1.0), xalign=self.range[0])
        s2 = Solid("#0f03", xysize=(10, 1.0), xalign=self.range[1])
        
        # we place our child as well as some guidelines for the target range
        r.place(t)
        r.place(s1)
        r.place(s2)
        
        renpy.redraw(self, 0) # make sure that were drawing constantly to see the slide movement
        return r
        
    def event(self, e, x, y, st):
      if renpy.map_event(e, "mouseup_1"): # if left mousebutton is released then check if the xalign is within the range
        if self.range[0] <= self.xalign <= self.range[1]:
          return True # wins
          
        else:
          return False
          
screen test():
  add Mark(Solid("#f00", xysize=(50, 50)), duration=2.0)
  
label start:
  call screen test
  if _return:
    "Winner!"
  else:
    "Loser!"
Havent tested as I am on the phone when I typed this, so might not work at all.
Update: Working so far, just corrected some calculations and added more comments.
Last edited by hell_oh_world on Wed Nov 25, 2020 6:36 pm, edited 6 times in total.

User avatar
Alex
Lemma-Class Veteran
Posts: 2981
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: UDD and the animation.

#4 Post by Alex » Wed Nov 25, 2020 4:29 pm

Yet another approach you could try...

Code: Select all

image blue:
    Solid("#00c")
    size(100, 100)
    
# some variables that describe the game state
default x_speed = 0.05
default obj_x_pos = 0.5
default game_speed = 0.05
default game_run = False

init python:
    def move_obj(st, at):
        '''
        Function that updated every ("game_speed" variable) seconds.
        It returns an object - "rv"
        '''

        # some global variables that describe the game state
        global obj_x_pos, x_speed, game_speed, game_run
        
        # some changes will occure only if "game_run"
        if game_run:
            
            # if object doesn't reach the side it should move
            if (x_speed > 0 and obj_x_pos < 1.0) or (x_speed < 0 and obj_x_pos > 0.0):
                obj_x_pos += x_speed
                    
            # if object reach the side, let's change its speed to opposite
            # and correct its position to not let it move out of boundaries
            elif (x_speed > 0 and obj_x_pos >= 1.0) or (x_speed < 0 and obj_x_pos <= 0.0):
                x_speed *= -1
                if obj_x_pos >= 1.0:
                    obj_x_pos = 1.0
                else:
                    obj_x_pos = 0.0
            
            # this shouldn't happence
            else:
                renpy.notify("???")
            
        # object to return
        rv = Transform("blue", align=(obj_x_pos, 0.5))
        
        return rv, game_speed

transform strange_tr():
    rotate -30 zoom 1.0
    block:
        linear 1.0 zoom 1.1
        linear 1.0 zoom 1.0
        repeat


screen my_game_scr():
    
    textbutton "ClickMe!" action ToggleVariable("game_run", True, False) align (0.05, 0.05)
    
    # the container that has an object in it
    frame:
        align (0.5, 0.3)
        xysize(600, 150)
        at strange_tr # we can apply transform to it
        
        add DynamicDisplayable(move_obj) rotate 45 # an object, returned by function 'move_obj'

label start:
    "..."
    show screen my_game_scr
    "?!"
    
https://www.renpy.org/doc/html/displaya ... isplayable

User avatar
Imperf3kt
Lemma-Class Veteran
Posts: 3636
Joined: Mon Dec 14, 2015 5:05 am
Location: Your monitor
Contact:

Re: UDD and the animation.

#5 Post by Imperf3kt » Wed Nov 25, 2020 4:41 pm

I'd try a simpler approach first.

Make the bar an animation using ATL, taking note of exactly how long it takes to reach halfway, and place it in its own screen with a timer.
Modify the keymap so it waits for a space bar press which grabs the timer time and places it in the _return variable via Return()

Then, simply call the screen and wait for a keypress. Check the _return variable is within an acceptable range (pressing something with millisecond accuracy is hard)


Note that this will be rather limited in use, but it might achieve what you're after.
Warning: May contain trace amounts of gratuitous plot.
pro·gram·mer (noun) An organism capable of converting caffeine into code.

Current project: GGD Mentor
Free Android GUI - Updated occasionally
Twitter
Imperf3kt Blackjack - a WIP blackjack game for Android made using Ren'Py

Post Reply

Who is online

Users browsing this forum: Bing [Bot]