ATL vs Motion()

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
Evildumdum
Regular
Posts: 191
Joined: Sun Jan 18, 2015 8:49 am
Projects: ApoclypseZ
Contact:

ATL vs Motion()

#1 Post by Evildumdum »

So i've been looking up ways to generate visual paths that are not pre-defined, but instead generated as needed. Unfortunately ATL blocks insist on being pre defined and do not support generator expressions. I was recommended this thread in the cookbook as an example of a method of generating custom paths.

viewtopic.php?f=51&t=3977

One of the things i picked up in there is a very useful looking function called Motion()

https://www.renpy.org/wiki/renpy/doc/re ... ons/Motion

However it looks like this is a long defunct and "it may interact poorly with ATL code"

Where possible i want to use the most efficient methods, so using something that may mess up ATL code that is alongside it is not ideal. However i can't deny that it has a flexibility that ATL does not.

Is this a flaw of ATL that makes it inferior to the old way of doing things or am i missing something obvious with ATL?
"If at first you don't succeed, try hitting it with a shoe."

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

Re: ATL vs Motion()

#2 Post by Imperf3kt »

I've seen your other thread.
Have you considered trying to make the ATL dynamic?
I am not sure it works, but is it possible to supply the ATL a position argument that is a variable?
So if you need to move 4 blocks right, add 4 blocks worth of position to the variable.


I'm interested to see if this works as I will soon need a similar code. After work I'll put something together to demonstrate what I mean, assuming nobody else gives you an answer in the meantime.
Warning: May contain trace amounts of gratuitous plot.
pro·gram·mer (noun) An organism capable of converting caffeine into code.

Current project: GGD Mentor

Twitter

User avatar
Evildumdum
Regular
Posts: 191
Joined: Sun Jan 18, 2015 8:49 am
Projects: ApoclypseZ
Contact:

Re: ATL vs Motion()

#3 Post by Evildumdum »

I currently work with dynamic ATl blocks as you have described:

Code: Select all

transform path_1(start, finish):
        xpos start.co[1] ypos start.co[0] xanchor 0.0 yanchor 0.0
        linear 0.75 xpos finish.co[1] ypos finish.co[0] xanchor 0.0 yanchor 0.0
    transform path_2(start, finish):
        xpos start.co[1] ypos start.co[0] xanchor 0.0 yanchor 0.0
        linear 0.75 xpos finish.co[1] ypos finish.co[0] xanchor 0.0 yanchor 0.0

Code: Select all

def move(self):    
            global SPRITE_DIRECTION
            renpy.restart_interaction()
            for waypoint in self.final_path[0].waypoints:
                if (waypoint == "N"):
                    SPRITE_DIRECTION = "N"
                    self.m_finish = self.overlay[self.m_start.gy-1][self.m_start.gx]
                    if not (self.move_tick):
                        self.move_tick = True
                        self.view_path = path_1
                    else:
                        self.move_tick = False
                        self.view_path = path_2
                elif (waypoint == "E"):
                    SPRITE_DIRECTION = "E"
                    self.m_finish = self.overlay[self.m_start.gy][self.m_start.gx+1]
                    if not (self.move_tick):
                        self.move_tick = True
                        self.view_path = path_1
                    else:
                        self.move_tick = False
                        self.view_path = path_2
                elif (waypoint == "S"):
                    SPRITE_DIRECTION = "S"
                    self.m_finish = self.overlay[self.m_start.gy+1][self.m_start.gx]
                    if not (self.move_tick):
                        self.move_tick = True
                        self.view_path = path_1
                    else:
                        self.move_tick = False
                        self.view_path = path_2
                elif (waypoint == "W"):
                    SPRITE_DIRECTION = "W"
                    self.m_finish = self.overlay[self.m_start.gy][self.m_start.gx-1]
                    if not (self.move_tick):
                        self.move_tick = True
                        self.view_path = path_1
                    else:
                        self.move_tick = False
                        self.view_path = path_2
                renpy.call_in_new_context("pause_nc", 0.75, self)
                self.m_start= self.m_finish
            self.a_to_b = False
            self.overlay[self.destination[0].gy][self.destination[0].gx].unit = self.move_select[0]
            self.overlay[self.destination[0].gy][self.destination[0].gx].alpha = 1
            self.move_select[0].location = [self.destination[0].gy, self.destination[0].gx]
            self.reset_move()
            renpy.restart_interaction()
It's rather clumsy but it does give the desired effect. If you're wondering why the two identical ATL blocks, it's because the screen doesn't register a fresh movement upon refreshing unless it is fed a new ATL block, so i alternate between the two identical ones to keep it moving. The issue is that while i can feed variables into the ATL block, i can only use them for thier int values or as part of an if statement. For loops are out of the question and a while loop is not appropriate.

The issue is not that ATL won't accept variables, but that is is limited to only what is pre defined. Unless i have pre-programmed a change of direction, i cannot get the variables to generate a change of direction automatically. I can set it up to accept a variable start and end point no problem, but i can't customise the route it takes to get there. It will simply go from A to B in a direct line. If i could set it up to accept unlimited numbers of A to B start and end points that would be fine, but as it has to be predefined and doesn't support loops, back to square one again.

To clarify, the issue that this game involves terrain features. It may be that a sprite has to walk a specific and convoluted path to avoid impassable terrain, other units or simply because it is the easiest path (different terrain costs different amounts of movement, it is set up to select the most efficient path to the destination tile). Simply going from A to B is not good enough, it needs to be able to follow a specific path with specific waypoints that will be unique and generated separately each time, as and when each unit moves. Currently this clumsy method is the only way i can get the visuals to match up with the theoretical path.
"If at first you don't succeed, try hitting it with a shoe."

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: ATL vs Motion()

#4 Post by Remix »

Using Aenakume's Bezier Motion Code you can get the path motion working at a very very very basic ATL level...

Sling the bezier code in a .rpy file and something like the following in script.rpy

Code: Select all

python 2 init:
    def bezier_point(trans, st, at):
        if not isinstance(points, PathInterpolator):
            return None
        elif st > 1.0:
            return None
        else:
            # Zero idea about what 'sizes' means in PathInterpolator...
            # Might be alignment offsets
            # Just using (1,1,1,1) at the moment
            trans.pos = points(st, (1,1,1,1))[0:2]
            return 0
# would be nice to pass everything in
# transform bezier_motion(image='default.png', path_duration=1.0, time_warper=linear):
# and pass the variables through to bezier_point
transform bezier_motion:
    function bezier_point

define forest = Image("images/forest.png")
default points = None
default sine_path = (
    ((100, 300),),
    ((300, 300), (250, 450), 0.25),
    ((600, 300), (550, 150))
  )

default a_points = (
  ((485, 238),),
  ((390, 205), (454, 212), (426, 202)),
  ((336, 289), (353, 207), (326, 247)),
  ((415, 384), (345, 331), (378, 369)),
  ((502, 373), (452, 399), (474, 391)),
  ((531, 305), (530, 355), (534, 333)),
  ((485, 208), (528, 276), (503, 205)),
  ((553, 397), (468, 210), (531, 360))
)

label start:
    "Hi"
    $ points = PathInterpolator(a_points)
    show forest at bezier_motion
    "Again"
    $ points = PathInterpolator(sine_path)
    show forest at bezier_motion
    "Stop"
I might tinker more with it later as there is a LOT that would want improving:

There is no time_warp warper available, so the time moves linearly
There is no movement duration... it just runs on a 'repeat as soon as possible' until done basis
The points have to be assigned to a set variable name rather than passed through the transform

Maybe someone else will sort those problems while I have a nap ;)
Frameworks & Scriptlets:

User avatar
Evildumdum
Regular
Posts: 191
Joined: Sun Jan 18, 2015 8:49 am
Projects: ApoclypseZ
Contact:

Re: ATL vs Motion()

#5 Post by Evildumdum »

That thread you linked me to is super helpful. I'm not 100% sure of the purpose of the bezier_point function that you have defined in your code though.
"If at first you don't succeed, try hitting it with a shoe."

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: ATL vs Motion()

#6 Post by Remix »

Because ATL cannot contain python code, the bezier_point function is just used as an intermediary function call so that the transform bezier_motion can use the path computed by the PathInterpolator class.

It basically gets round using the legacy Motion class.

Another option would be using the Transform class I guess. A bit busy elsewhere at the moment to look further into this.
Frameworks & Scriptlets:

Post Reply

Who is online

Users browsing this forum: bonnie_641, Google [Bot]