Sniper Minigame animation - possible?

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
mcoirad
Newbie
Posts: 5
Joined: Thu Apr 04, 2019 9:12 pm
Github: mcoirad
Contact:

Sniper Minigame animation - possible?

#1 Post by mcoirad » Sat Nov 09, 2019 3:33 pm

I've been working on creating a sniper minigame within Renpy, sort of inspired by the "Sniper Assassin" series of Flash games, just to see what is possible with the renpy engine. (They are worth checking out for 5 min for a laugh). So far I've got most of it working, using a mix of AlphaBlend and Creator Defined Displayables. You can see the full test demo here: https://github.com/mcoirad/renpy-sniper-assassin-test

Code: Select all

init python:

    import math
    import pygame

    class Revealer(renpy.Displayable):

        def __init__(self, child, child2, child3, **kwargs):

            # Pass additional properties on to the renpy.Displayable
            # constructor.
            super(Revealer, self).__init__(**kwargs)

            # The children
            # Child1 is the image of the flashlight/scope
            # Child2 is the overall darkness, in this case all-black
            # Child3 is the background to be revealed, in this case all-transparent
            # (The real background is the imagemap)
            self.child = renpy.displayable(child)
            self.child2 = renpy.displayable(child2)
            self.child3 = renpy.displayable(child3)

            # The width and height of us, and our children.
            self.width = 0
            self.height = 0

            x, y = pygame.mouse.get_pos()
            self.xpos = x
            self.ypos = y


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

            # Create transforms for the children.
            # The only image we expect to move around is the flashlight/scope
            t1 = Transform(child=self.child, xpos = self.xpos, ypos = self.ypos)
            t2 = Transform(child=self.child2, xpos = 0, ypos = 0)
            t3 = Transform(child=self.child3, xalign = 0, yalign = 0)

            # AlphaBlend the transforms
            scope_view = AlphaBlend(t1,  t2, t3, alpha=True)

            # Create a render from the Alphablend.
            child_render = renpy.render(scope_view, width, height, st, at)

            # Create the render we will return.
            render = renpy.Render(self.width, self.height)

            # Blit (draw) the result to our render.
            render.blit(child_render, (0, 0))

            # Return the render.
            return render


        def event(self, ev, x, y, st, scope_dimensions = 400):

            # Offset the scope by half its height/width so the cursor is at the middle
            cursor_offset = scope_dimensions / 2

            # Logic to ensure the flashlight/scope stays put when cursor leaves the screen
            # After movement, updates the scopes position and redraws render
            if (x != self.xpos - cursor_offset or y != self.ypos - cursor_offset) and (x > 0 or y > 0):

                self.xpos = x - cursor_offset
                self.ypos = y - cursor_offset

                renpy.redraw(self, 0)

            # Pass the event to our child.
            return self.child.event(ev, x, y, st)

        def visit(self):
            return [ self.child ]

image animated_scope: # Not currently used
    "scope"
    linear 1.0 yoffset -100
    pause 0.01
    linear 1.0 yoffset 100


screen sniper_minigame:

    modal True
    imagemap:

        # Instantiate flashlight/scope effect
        # Note: for clicking actions to take effect, the middle of scope image file needs to be black
        ground Revealer("scope", "black.png", "blank.png")

        # Example hotspots to show how actions might be taken
        hotspot (0,0,1920,1080) action (Hide("sniper_minigame"), Jump("did_not_break_window"))
        hotspot (1200,570,100,75) action (Hide("sniper_minigame"), Jump("broke_window"))



# Function for hiding the cursor during these scenes
init 1 python:
    def change_cursor(type="default"):
        persistent.mouse = type
        if type == "default":
            setattr(config, "mouse", None)
        elif type == "1":
            setattr(config, "mouse", {"default": [("images/empty_mouse.png", 0, 0)]})

    if not hasattr(persistent, "mouse"):
        change_cursor(1)
    else:
        change_cursor(persistent.mouse)


label start:

    # Hide Cursor
    $ change_cursor("1")
    $ is_shooting = False

    scene poor_neighborhood:
        xalign 0.5
        yalign 0.5
    "Break the car window!"
    show screen sniper_minigame
    "Shoot out the back right window of the car!"

    return

label broke_window:

    # Show broken window on top of background
    image window = "broken_window.png"
    show window:
        xpos 1200
        ypos 570

    # Reveal cursor
    $ change_cursor()
    "Broke the window."
    return

label did_not_break_window:
    "You missed."
    # Reveal cursor
    $ change_cursor()
    return

However, there is one conceptual piece that I haven't been able to figure out, which is the animation of the crosshairs going upwards from the gun recoil when the player clicks to fire. I've explored two strategies, neither of which has been successful:

1. Handling the animation of the recoil 100% programatically. This requires re-rendering the displayable every frame during a set duration for the recoil time (while incrementing and de-incrementing the ypos). However, I'm unsure how to trigger the render() method once a frame for a set duration. Is that possible to do?

2. Switching from the static crosshairs image to an ATL image animation and then switching back. I also couldn't get this to work but this may just be a matter of lack of knowledge regarding how to use ATL within python.

I guess my main question here is am I going too far with the Renpy engine? The docs do mention that at a certain point you'll just be fighting Renpy itself. I'm not sure I've reached that point (I think the goal of a 2D sniper-like minigame is possible) but I'm wondering if someone with more experience has a better idea.

User avatar
Per K Grok
Miko-Class Veteran
Posts: 562
Joined: Fri May 18, 2018 1:02 am
Completed: the Ghost Pilot, Sea of Lost Ships, Bubbles and the Pterodactyls, Defenders of Adacan Part 1
Projects: Defenders of Adacan Part 2
Deviantart: pekj
itch: per-k-grok
Location: Sverige
Contact:

Re: Sniper Minigame animation - possible?

#2 Post by Per K Grok » Sun Nov 10, 2019 2:18 am

mcoirad wrote:
Sat Nov 09, 2019 3:33 pm
I've been working on creating a sniper minigame within Renpy, sort of inspired by the "Sniper Assassin" series of Flash games, just to see what is possible with the renpy engine. (They are worth checking out for 5 min for a laugh). So far I've got most of it working, using a mix of AlphaBlend and Creator Defined Displayables.

----

However, there is one conceptual piece that I haven't been able to figure out, which is the animation of the crosshairs going upwards from the gun recoil when the player clicks to fire. I've explored two strategies, neither of which has been successful:

----

Just a shot in the dark (pun intended)

You could try if an animated image might be useful.

Code: Select all


image recoil:
	"recoil1.png"
	0.2
	"recoil2.png"
	0.2
	"recoil3.png"
	0.2
	"recoil2.png"
	0.2
	"recoil1.png"
	0.2
Image Visual Story Telling, DeviantArt Group for animations, comics, games and illustrations https://www.deviantart.com/acgi

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

Re: Sniper Minigame animation - possible?

#3 Post by Alex » Sun Nov 10, 2019 5:38 am

Yet another 'shot'...))

Code: Select all

label start:
    "Ready?"
    $ x, y = renpy.get_mouse_pos()
    $ renpy.set_mouse_pos(x, y-20, duration=0.25)
    $ renpy.pause(0.25, hard=True)
    $ renpy.set_mouse_pos(x, y, duration=0.25)
    $ renpy.pause(0.25, hard=True)
    "?"
https://www.renpy.org/doc/html/other.ht ... _mouse_pos
https://www.renpy.org/doc/html/other.ht ... _mouse_pos
https://www.renpy.org/doc/html/other.html#renpy.pause

Post Reply

Who is online

Users browsing this forum: No registered users