Editing and Ending a Rhythm Game Loop...

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
VAPMichaelaLaws
Regular
Posts: 187
Joined: Mon Dec 10, 2012 2:11 am
Completed: Check Signature!
Projects: Check Signature!
Organization: Seraphim Entertainment
Tumblr: thebunnyofevil
Contact:

Editing and Ending a Rhythm Game Loop...

#1 Post by VAPMichaelaLaws » Thu Jun 21, 2018 1:44 pm

Heyo!

I'm trying my darnedest to make a Dance QTE happen in my short VN and my first attempt to make something happen using only screens and timers did not work (ending with a laggy playback and an obnoxious amount of timing issues).

So I took to the interwebs and found this:
viewtopic.php?p=348727#p348727

I wanted to utilize it (giving proper credit of course) but when testing this code, I found that it's an eternal loop. Since the song the mini game is used for is only 63 seconds, this is an issue.

This is my edit to the code, but it's still unfortunately looping forever. My GOAL for it is two conditions:
1. If the player consistently hits the dance button successfully on it's marker during the duration of that 63 seconds, the game ends and the story continues (Label "dance_success")
2. If the player misses THREE times (whether it be misclicking or letting the target run past the marker), the game ends and the story goes to a bad end (Label "dance_failure")

Regardless, the loop needs to break and I have NO clue how to even do that.

Code: Select all

init python:
    config.screen_width=1280
    config.screen_height=800
    import time
    import pygame
    MOUSEBUTTONDOWN=pygame.MOUSEBUTTONDOWN
    
    class RhythmD(object):
        def __init__(self, sprite, speed, delay, ypos=0):
            self.sprite = sprite
            self.speed = speed
            self.delay = delay
            self.show = manager.create(sprite)
            self.show.x = -200
            self.show.y = ypos
            self.moving = False # No point in checking if it isn't.
            
        def update(self):
            if store.t + self.delay < time.time():
                self.moving = True
                self.x = self.x + self.speed
            else:
                pass
            
        @property
        def x(self):
            return self.show.x
        @x.setter
        def x(self, value):
            self.show.x = value
            
        @property
        def y(self):
            return self.show.y
        @y.setter
        def y(self, value):
            self.show.y = value
            
    def sprites_update(st):
        for sprite in sprites[:]:
            sprite.update()
            if sprite.x > config.screen_width:
                sprite.show.destroy()
                sprites.remove(sprite)
        return 0.05
        
    def sprites_event(ev, x, y, st):
        if ev.type == MOUSEBUTTONDOWN:
            if ev.button == 1:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if not hit:
                    store.misses += 1
                renpy.restart_interaction()
                
screen show_vars:
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add "practicebutton.png":
        pos (1000, 100)
        
    timer 63.0 action Jump("omgyayyoudidit") #63 seconds is the length of the song. GAME MUST END AT END OF SONG.
                
label rhythm_qte:
    play music "WALTZ.ogg"
    
    python:
        hits = 0
        misses = 0
        t = time.time()
        manager = SpriteManager(update=sprites_update, event=sprites_event)
        sprite = Image("practicebutton1.png")
        targets = set(1000+i for i in xrange(-200, 200))
        sprites = []
        td = 0
        for i in xrange(100):
            td += renpy.random.choice([0.5, 1, 2]) #TIMED SPACING
            sprites.append(RhythmD(Image("practicebutton.png"), 31, td, 100)) #image, time of distance, time of spawn, ypos
            
        renpy.show_screen("show_vars")
        renpy.show("_", what=manager, zorder=1)
        
    while True:
        $ result = ui.interact()
Image
Voice Actress | Singer | Writer | Producer | Director
http://www.michaelaamandalaws.com/
--------
Completed Projects: My Teacher (NaNoReno2013), Pizz'Amore, My Lady, Our School Love (Otome Audio CD), Our Honeymoon (Otome Audio CD), Seduce Me, Maid With Perfection (NaNoReno2015), Blind Love (ILUjam 2015), Love And Romance: A Study Of Intimacy, Seduce Me 2: The Demon War, Remember, Remember
Projects Still In Production: All For You

kivik
Miko-Class Veteran
Posts: 784
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#2 Post by kivik » Thu Jun 21, 2018 2:00 pm

I'm glance reading as I'm in a rush, but I assume the while True part at the end is the infinite loop. You want to use a variable to determine whether the loop should continue, then change the variable from True to False when it's finished.

What I don't know at a quick glance is whether you have the code to check if the entire sequence has been completed, though given your description and this line, I assume you don't:

Code: Select all

    timer 63.0 action Jump("omgyayyoudidit") #63 seconds is the length of the song. GAME MUST END AT END OF SONG.
But I assume that line doesn't actually jump you to the label (which seems weird), or maybe something else is afoot. So perhaps change it to SetVariable() which alters your while loop variable:

Code: Select all

default qte_loop = True

...

    timer 63.0 action SetVariable("qte_loop", False) #63 seconds is the length of the song. GAME MUST END AT END OF SONG.

...

while qte_loop:
    ui.interact()

# should get to here after 63 seconds
jump dance_success
I don't see code that checks for failure of 3 times though, do you need help to add them as well? I assume you insert them in the if not hit: block to check for 3 misses and do a renpy.jump("dance_failure").

User avatar
VAPMichaelaLaws
Regular
Posts: 187
Joined: Mon Dec 10, 2012 2:11 am
Completed: Check Signature!
Projects: Check Signature!
Organization: Seraphim Entertainment
Tumblr: thebunnyofevil
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#3 Post by VAPMichaelaLaws » Thu Jun 21, 2018 4:26 pm

Hello! Thank you for the assist!

I added a block at the end of the if not hit code and it works!

Code: Select all

    def sprites_event(ev, x, y, st):
        if ev.type == MOUSEBUTTONDOWN:
            if ev.button == 1:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if not hit:
                    store.misses += 1
                    if misses == 3:
                        renpy.hide_screen("show_vars")
                        renpy.hide("_")
                        renpy.jump("dance_failure")
                renpy.restart_interaction(
Now I only need to define that missing the mark also counts as a miss...

---

Otherwise, I added

Code: Select all

default qte_loop = True
to the code and changed my jump to the SetVariable, but it still loops past the timer.

Code: Select all

screen show_vars:
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add "practicebutton.png":
        pos (1000, 100)
        
    timer 63.0 action SetVariable("qte_loop", False) #63 seconds is the length of the song. GAME MUST END AT END OF SONG.
                
label rhythm_qte:
    play music "WALTZ.ogg"
    
    default qte_loop = True
    
    python:
        hits = 0
        misses = 0
        t = time.time()
        manager = SpriteManager(update=sprites_update, event=sprites_event)
        sprite = Image("practicebutton1.png")
        targets = set(1000+i for i in xrange(-200, 200))
        sprites = []
        td = 0
        for i in xrange(100):
            td += renpy.random.choice([0.5, 1, 2]) #TIMED SPACING
            sprites.append(RhythmD(Image("practicebutton.png"), 31, td, 100)) #image, time of distance, time of spawn, ypos
            
        renpy.show_screen("show_vars")
        renpy.show("_", what=manager, zorder=1)
        
    while qte_loop:
        $ result = ui.interact()

# should get to here after 63 seconds
    jump dance_success
Image
Voice Actress | Singer | Writer | Producer | Director
http://www.michaelaamandalaws.com/
--------
Completed Projects: My Teacher (NaNoReno2013), Pizz'Amore, My Lady, Our School Love (Otome Audio CD), Our Honeymoon (Otome Audio CD), Seduce Me, Maid With Perfection (NaNoReno2015), Blind Love (ILUjam 2015), Love And Romance: A Study Of Intimacy, Seduce Me 2: The Demon War, Remember, Remember
Projects Still In Production: All For You

kivik
Miko-Class Veteran
Posts: 784
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#4 Post by kivik » Fri Jun 22, 2018 2:19 am

Sounds like the timer's not firing at all for whatever reason - which was what i was concerned about originally. I can have a look this evening when I'm back home, but meanwhile can you move the timer line to the start of the screen to see if it makes a difference?

User avatar
VAPMichaelaLaws
Regular
Posts: 187
Joined: Mon Dec 10, 2012 2:11 am
Completed: Check Signature!
Projects: Check Signature!
Organization: Seraphim Entertainment
Tumblr: thebunnyofevil
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#5 Post by VAPMichaelaLaws » Fri Jun 22, 2018 12:07 pm

I moved it to the top and there was no change )=

Code: Select all

screen show_vars:
    timer 63.0 action SetVariable("qte_loop", False) #63 seconds is the length of the song. GAME MUST END AT END OF SONG.
    
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add "practicebutton.png":
        pos (1000, 100)
Image
Voice Actress | Singer | Writer | Producer | Director
http://www.michaelaamandalaws.com/
--------
Completed Projects: My Teacher (NaNoReno2013), Pizz'Amore, My Lady, Our School Love (Otome Audio CD), Our Honeymoon (Otome Audio CD), Seduce Me, Maid With Perfection (NaNoReno2015), Blind Love (ILUjam 2015), Love And Romance: A Study Of Intimacy, Seduce Me 2: The Demon War, Remember, Remember
Projects Still In Production: All For You

kivik
Miko-Class Veteran
Posts: 784
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#6 Post by kivik » Sun Jun 24, 2018 12:49 pm

Bummer, seems like something is making the timer not fire on your screen, which is weird. Can you change the timer to 1 seconds and see if it does anything?

I'm not familiar with the ui.interact() to know if it causes problems along side screen timers - if so that's bad.

If a shorter timer of 1 seconds works, you could maybe do something different and use it to check every second if 63 seconds have passed. Your code includes t = time.time() so you just need to compare time.time() with t to see if it's been 63 seconds. Something like this (untested):

Code: Select all

screen show_vars:
    timer 1:
        repeat True:
        action If(time.time()-t >= 63, true=SetVariable("qte_loop", False))
If that doesn't work, maybe change the 63 seconds to shorter time intervals to test if it eventually triggers.

If that doesn't work, I think the current code doesn't have any other way of taking timed events as the ui.interact() will essentially block any renpy code physically...

Maybe see if you can find the creator and see how they end the game?

User avatar
gas
Veteran
Posts: 439
Joined: Mon Jan 26, 2009 7:21 pm
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#7 Post by gas » Thu Jun 28, 2018 11:59 am

That code RESHOWN the screen at each interaction, resetting the timer at 63 each time.
Leave your original code untouched.
Show ANOTHER screen with timer alone just after the label statement.
Tested and it work fine.

Code: Select all

label  rythm_qte:
    show screen timeup()
    # whatever follow

screen timeup():
    timer 63.0 action Jump("completed")
Don't forget on your landing labels to hide screens and del spritemanagers and fuctions
10 ? "RENPY"
20 GOTO 10

RUN

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

Re: Editing and Ending a Rhythm Game Loop...

#8 Post by Alex » Thu Jun 28, 2018 2:17 pm

VAPMichaelaLaws wrote:
Fri Jun 22, 2018 12:07 pm
I moved it to the top and there was no change )=

Code: Select all

screen show_vars:
    timer 63.0 action SetVariable("qte_loop", False) #63 seconds is the length of the song. GAME MUST END AT END OF SONG.
    
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add "practicebutton.png":
        pos (1000, 100)
My two cents...

Code: Select all

    while qte_loop:
        $ result = ui.interact()
this part waits for something to be returned from your rythm game, and if so step to another iteration in loop while condition still true. This can be usefull if your game return anything on players interaction (for now it's not). So here you actually doesn't need the while loop, leave just

Code: Select all

$ result = ui.interact()
$ renpy.hide("_")
"End game ([result])"
and make your timer return some value to cause interaction, like

Code: Select all

timer 3.0 action Return("smth")

User avatar
margaretcatter
Regular
Posts: 32
Joined: Fri May 18, 2018 7:16 pm
Projects: Kathelm Princess X Princess | Hurricane Like Me
itch: margaretcatter
Location: New York/LA
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#9 Post by margaretcatter » Wed Sep 05, 2018 2:00 am

To revive this thread I'm having a bit of a small problem. The first and probably simplist to solve is the images that I'm using as my buttons aren't showing up in color. For whatever reason theyre both showing up as grey and not even the grey that I choose to be one of the buttons. I've attached what I'm getting in game and what theyre supposed to look like.

Code: Select all

define ButtonX  = "images/Buttons/ButtonX.png"
define ButtonA = "images/Buttons/ButtonA.png"
My second problem is when the game is over it doesnt leave the game? It just stays in the loop seemingly forever and I'm not sure why my

Code: Select all

label TheEnd:

    e "something something something"

    return
Isn't working as intended. Any help would be greatly appreciated.
Attachments
ButtonA.png
ButtonA.png (3.39 KiB) Viewed 246 times
ButtonX.png
ButtonX.png (4.2 KiB) Viewed 246 times
Screen Shot 2018-09-05 at 1.56.10 AM.png

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

Re: Editing and Ending a Rhythm Game Loop...

#10 Post by Alex » Wed Sep 05, 2018 12:57 pm

What's the actual code you use?

User avatar
margaretcatter
Regular
Posts: 32
Joined: Fri May 18, 2018 7:16 pm
Projects: Kathelm Princess X Princess | Hurricane Like Me
itch: margaretcatter
Location: New York/LA
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#11 Post by margaretcatter » Wed Sep 05, 2018 1:58 pm

Heres the whole code in question minus the bits I didnt change

Code: Select all

init python:
    config.screen_width=1280
    config.screen_height=800
    import time
    import pygame
    KEYDOWN=pygame.KEYDOWN

    {...}

    def sprites_event(ev, x, y, st):
        if ev.type == KEYDOWN:
            if ev.key == pygame.K_LEFT:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if not hit:
                    store.misses += 1
                renpy.restart_interaction()
                if misses == 3:
                    renpy.hide_screen("show_vars")
                    renpy.hide("_")
                    renpy.jump("TheEnd")
                    renpy.restart_interaction()

# The game starts here.

label start:

e "This is a game"

label FirstSong:

show screen timeup()
screen timeup():
    timer 151.0 action Jump("TheEnd")
screen show_vars:
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add ButtonX:
        pos (1000, 50)

play music ("birth_of_a_band-1st-shot.mp3")
python:
    hits = 0
    misses = 0
    t = time.time()
    manager = SpriteManager(update=sprites_update, event=sprites_event)
    sprite = ("images/Buttons/ButtonA.png")
    targets = set(1000+i for i in xrange(-75, 0)) #area around target to "score" a succesful hit
    sprites = []
    td = -1
    for i in xrange(100): #number of dots that cross the screen
        td += renpy.random.choice([0.5, 1, 2])
        sprites.append(RhythmD(("images/Buttons/ButtonX.png"), 10, td, 50))

    renpy.show_screen("show_vars")
    renpy.show("_", what=manager, zorder=1)

while True:
    $ result = ui.interact()


label TheEnd:
stop music
e "something something something"

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

Re: Editing and Ending a Rhythm Game Loop...

#12 Post by Alex » Wed Sep 05, 2018 3:14 pm

Try to change:

Code: Select all

define ButtonX  = "images/Buttons/ButtonX.png"
define ButtonA = "images/Buttons/ButtonA.png"
to

Code: Select all

image button_a:
    "images/Buttons/ButtonA.png"
image button_x:
    "images/Buttons/ButtonX.png"
/

Code: Select all

sprite = ("images/Buttons/ButtonA.png")
to

Code: Select all

sprite = "button_a"
/

Code: Select all

sprites.append(RhythmD(("images/Buttons/ButtonX.png"), 10, td, 50))
to

Code: Select all

sprites.append(RhythmD(sprite, 10, td, 50))
/

Code: Select all

screen show_vars:
    text "Misses: [misses], Hits: [hits]" xalign 0.5
    add ButtonX:
        pos (1000, 50)
to

Code: Select all

screen show_vars:
    vbox:
        xalign 0.5
        text "Misses: [misses], Hits: [hits]!" xalign 0.5
        bar:
            xsize 500
            value AnimatedValue(old_value=0.0, value=1.0, range=1.0, delay=15.0)
    add "button_x":
        pos (1000, 50)
    timer 15.0 action Return("time's up")

Then change

Code: Select all

def sprites_event(ev, x, y, st):
        if ev.type == KEYDOWN:
            if ev.key == pygame.K_LEFT:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if not hit:
                    store.misses += 1
                renpy.restart_interaction()
                if misses == 3:
                    renpy.hide_screen("show_vars")
                    renpy.hide("_")
                    renpy.jump("TheEnd")
                    renpy.restart_interaction()
to

Code: Select all

    def sprites_event(ev, x, y, st):
        if ev.type == MOUSEBUTTONDOWN:
            if ev.button == 1:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            # We destroy the sprite, making it impossible to it twice :)
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if hits >= 3:
                    return("win")
                    
                if not hit:
                    store.misses += 1
                
                if misses == 3:
                    return("lose") 
                
                renpy.restart_interaction()
And finally

Code: Select all

    while True:
    $ result = ui.interact()


label TheEnd:
    stop music
    e "something something something"
to

Code: Select all

    #while True:
    $ result = ui.interact()
    $ renpy.hide("_")
    hide screen show_vars
        
    $ renpy.pause(0.1, hard=True)
    "End game ([result])"

User avatar
margaretcatter
Regular
Posts: 32
Joined: Fri May 18, 2018 7:16 pm
Projects: Kathelm Princess X Princess | Hurricane Like Me
itch: margaretcatter
Location: New York/LA
Contact:

Re: Editing and Ending a Rhythm Game Loop...

#13 Post by margaretcatter » Wed Sep 05, 2018 3:52 pm

w00t! That mostly worked, everything is now in color and when you finish the song either by winning or losing the game displays the appropriate text. Since Im trying to do it with keyarrows instead of the mouse click I ended up using

Code: Select all

def sprites_event(ev, x, y, st):
        if ev.type == KEYDOWN:
            if ev.key == pygame.K_LEFT:
                hit = False
                for sprite in sprites[:]:
                    if sprite.moving:
                        if int(sprite.x) in store.targets:
                            store.hits += 1
                            hit = True
                            # We destroy the sprite, making it impossible to it twice :)
                            sprite.show.destroy()
                            sprites.remove(sprite)
                            break
                if hits >= 100: #number of hits need to win game
                    enpy.hide_screen("show_vars")
                    renpy.hide("_")
                    renpy.jump("TheEndWin")
                    renpy.restart_interaction()

                if not hit:
                    store.misses += 1

                if misses == 3: #number of misses need to lose game
                    renpy.hide_screen("show_vars")
                    renpy.hide("_")
                    renpy.jump("TheEndLose")
                    renpy.restart_interaction()
Now off to figure out how to count unhit buttons as misses.

Post Reply

Who is online

Users browsing this forum: martingerdes