One approach to a non-looping Movie

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
rames44
Veteran
Posts: 233
Joined: Sun May 29, 2016 4:38 pm
Contact:

One approach to a non-looping Movie

#1 Post by rames44 »

This may already have been covered here, but I remember a question about it and ran into the need myself, so...

Here's an approach for using a Movie object, but having it play through once without looping. renpy.movie_cutscene, of course, will play through just once, but it plays full screen. Using the Movie Displayable this way gives you options that renpy.movie_cutscene doesn't - like having the video only occupy a portion of the screen, be used as a character image, etc., etc.

First, Movie takes a play_callback parameter. (See https://www.renpy.org/doc/html/movie.html#Movie). The Ren'py docs say:
Generally, this will want to use renpy.music.play() to start the movie playing on the given channel, with synchro_start=True. A minimal implementation is:

Code: Select all

def play_callback(old, new):

    renpy.music.play(new._play, channel=new.channel, loop=True, synchro_start=True)

    if new.mask:
        renpy.music.play(new.mask, channel=new.mask_channel, loop=True, synchro_start=True)
This is part 1 of the trick - note the loop=True. If you substitute loop=False, lo and behold, the Movie doesn't loop!

Part 2 of the trick relates to what happens when the Movie finishes playing. The Ren'py docs say:
This displayable will be transparent when the movie is not playing.
Thus, when the video reaches the end, it will disappear off the screen. Well, technically, the Movie Displayable is still there - it's just transparent. If that's what you want, then all well and good. But maybe you want to give the illusion of "play through and stop with the last frame showing." In this case, have a normal image that is the last frame of the video, and display it once the video ends. You can do this easily by setting up a compound image using ATL, with it starting with the Movie, delaying for the length of the movie (or maybe just a scrinch less) and then replacing the movie with the last frame.

Here's a sample script that shows this off. The video in question is the "rocket lifting off" video from the Ren'py Tutorial project. So if you use this as the "script.rpy" and copy the movie in, you'll have a full working demo.

Code: Select all

init python:
    # play_callback function for Movie() that starts the movie _without_ looping
    # It's just the reference implementation from https://www.renpy.org/doc/html/movie.html#Movie
    # but with "loop=True" changed to "loop=False"
    def play_movie_only_once_callback(old,new):
        renpy.music.play(new._play, channel=new.channel, loop=False, synchro_start=True)
        if new.mask:
            renpy.music.play(new.mask, channel=new.mask_channel, loop=False, synchro_start=True)

# Just a grey background to show things against
image grey = "#888"

# The movie we want to play through once
image the_movie = Movie(play='oa4_launch.webm', play_callback=play_movie_only_once_callback)

# This should contain the last frame from the movie, but I'm too lazy to extract
# it, so I'm just using a black rectangle of the same size as the movie.
image the_movie_last_frame = Crop((0,0,640,360), "#000")

# The movie image we actually "show"
image one_time_movie:
    "the_movie"             # The movie
    pause 7.99              # A delay to get to the end of the movie
    "the_movie_last_frame"  # The last frame of the movie, now displayed as an image

label start:

    scene grey

    "Ready"

    show one_time_movie:
        align(0.5,0.5)

    "Playing through once, and stopping at the (faked) final frame"

    hide one_time_movie

    "Done"

    return
Of course, this implementation doesn't prevent the player from clicking past before the video has finished playing. If you need that, you can obviously put in a hard pause.

Hope that (a) someone finds this useful and (b) I didn't just re-create the wheel that someone else had already posted here...

Post Reply

Who is online

Users browsing this forum: No registered users