Drawing a flashlight with a creator-defined displayable

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
apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Drawing a flashlight with a creator-defined displayable

#1 Post by apricotorange »

This is an example of a creator-defined displayable. It hides everything on the screen except a small area around the cursor, like using a flashlight in a dark room. This was inspired by http://lemmasoft.renai.us/forums/viewto ... =8&t=17599. The implementation is sort of similar to the example at http://www.renpy.org/doc/html/udd.html, at a high level, but the details are different. The code follows:

Code: Select all

init python:
    
    class Flashlight(renpy.Displayable):
        def __init__(self):
            super(Flashlight, self).__init__()
            
            # This image should be twice the width and twice the height
            # of the screen.
            self.child = Image("flashlight.png")

            # (-1, -1) is the way the event system represents
            # "outside the game window".
            self.pos = (-1, -1)

        def render(self, width, height, st, at):
            render = renpy.Render(config.screen_width, config.screen_height)
            
            if self.pos == (-1, -1):
                # If we don't know where the cursor is, render pure black.
                render.canvas().rect("#000", (0, 0, config.screen_width, config.screen_height))
                return render

            # Render the flashlight image.
            child_render = renpy.render(self.child, width, height, st, at)

            # Draw the image centered on the cursor.
            flashlight_width, flashlight_height = child_render.get_size()
            x, y = self.pos
            x -= flashlight_width / 2
            y -= flashlight_height / 2
            render.blit(child_render, (x, y))
            return render

        def event(self, ev, x, y, st):
            # Re-render if the position changed.
            if self.pos != (x, y):
                renpy.redraw(self, 0)

            # Update stored position
            self.pos = (x, y)

        def visit(self):
            return [ self.child ]
This code expects to be able to find "flashlight.png"; this image should have width and height twice that of the screen, and it should be black with a transparent hole in the center. (Making it twice the size of the screen is a little inefficient, but it makes the code a lot simpler.) I've attached the one I used; I drew it in Paint.NET using the gradient tool (radial mode, primary color transparent, secondary color black). There are probably better ways to draw a flashlight image if you want it to look like a real flashlight.

In terms of understanding the code, I think the trickiest bit is handling the cases where we don't actually want to render the flashlight (the transparent hole) at all. One case is before the event() callback is called; note that it does not get called before the first render() call. If you comment out the call to render.canvas().rect(), you will see that the screen flashes briefly before the flashlight appears. The other case is where the cursor is moved outside the game window. The event() callback represents this with the coordinates (-1, -1).

If there's anything else that's unclear, please ask.

Simple example of how to use it:

Code: Select all

screen flashlight_demo:
    textbutton "continue" xpos 300 ypos 300 action Return()
    add Flashlight()

label start:
    $ mouse_visible = False
    call screen flashlight_demo
Attachments
flashlight.png

User avatar
Hellboy
Regular
Posts: 86
Joined: Mon Dec 24, 2012 9:37 pm
Location: Heredia. Costa Rica.
Contact:

Re: Drawing a flashlight with a creator-defined displayable

#2 Post by Hellboy »

Thank you very much! It works great and the continue button is a nice touch!

After seeing it, I wonder if it would be too difficult to have an image map instead of it. Would be cool to find stuff in the dark, like a light switch maybe. :o

But its perfect like this.
Thanks!! :D
Image
FREE and easy 3D customization, posing, and animation software with pre-made people and environments:
DAZ Studio Pro 4.9

apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Re: Drawing a flashlight with a creator-defined displayable

#3 Post by apricotorange »

Using an imagemap is easy; just replace the textbutton with an imagemap statement (http://www.renpy.org/doc/html/screens.h ... statements).

User avatar
Hellboy
Regular
Posts: 86
Joined: Mon Dec 24, 2012 9:37 pm
Location: Heredia. Costa Rica.
Contact:

Re: Drawing a flashlight with a creator-defined displayable

#4 Post by Hellboy »

I'll try that. Thanks! :D
Image
FREE and easy 3D customization, posing, and animation software with pre-made people and environments:
DAZ Studio Pro 4.9

KimiYoriBaka
Miko-Class Veteran
Posts: 636
Joined: Thu May 14, 2009 8:15 pm
Projects: Castle of Arhannia
Contact:

Re: Drawing a flashlight with a creator-defined displayable

#5 Post by KimiYoriBaka »

I'll go ahead and add that it should work fine with any of the normal renpy screen language stuff (based on the fact mine does). I didn't mention it on the thread I posted with something like this included., but the reason I embedded the flashlight into the other code is cause it wouldn't show up when they were separate. my guess is that having two fullscreen custom displayables doesn't work.

also, this is just my opinion, but having that much of screen be pitch-black would be rather annoying. if you're going to use opaque black, it might be better to use a larger circle in the center, possibly with a bit in that center that is clear, rather than a full gradation.

Post Reply

Who is online

Users browsing this forum: No registered users