Rhythm Game on Renpy

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.
Message
Author
User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Rhythm Game on Renpy

#1 Post by Kaen » Thu Dec 04, 2014 9:40 am

Anyone ever tried to make a rhythm game using renpy? Any code or demo available?

I'd like to make one but I'm pretty clueless on how I'd do it...

Any help is appreciated, thank you!
Last edited by Kaen on Sat Jan 10, 2015 7:24 am, edited 3 times in total.

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#2 Post by Kaen » Sat Dec 06, 2014 1:05 pm

Anyone? Bump.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#3 Post by xela » Sat Dec 06, 2014 1:45 pm

Kaen wrote:Anyone ever tried to make a rhythm game using renpy? Any code or demo available?
I've never seen one, yet there are so many Ren'Py games out there right now that there is no way of knowing for sure...
Kaen wrote:I'd like to make one but I'm pretty clueless on how I'd do it...

Any help is appreciated, thank you!
If your design is simple, you could prolly cheat with Screen language and some timers and/or a python/renpy module functions/classes.

Proper implementation should be a UDD or SpriteManager class, which would also allow you to do a lot of cool stuff (what would prolly get increasingly harder with SL/Timers cheat).

====================================
It's not hard to create but it's definitely a bit more time consuming than your previous requests.
Like what we're doing? Support us at:
Image

User avatar
KomiTsuku
Eileen-Class Veteran
Posts: 1023
Joined: Mon Sep 22, 2008 11:32 pm
Completed: Dreams of the Skies, Anton's Vacation, Luka, The Halberd and The Tiger, Rising Angels, Pyrite Heart, Rising Angels: Reborn, The Halberd and The Fox, VN Tycoon, RA: Hope
Projects: Rising Angels
Organization: IDHAS Studios
IRC Nick: Komi
itch: idhas
Location: Somewhere
Contact:

Re: Rhythm Game on Renpy

#4 Post by KomiTsuku » Sat Dec 06, 2014 1:48 pm

I don't think anyone has done something like that. I've given some thought into it, but it gets pretty complex with either QTE timer event or a mess of if variables and location coordinates. I'm not even sure how some computers would handle the constant shifting graphics in the renpy engine.

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#5 Post by Kaen » Sat Dec 06, 2014 2:21 pm

Thank you guys.

Right now I'm more worried about how to handle the music itself than the graphics. How to make the music react based on the player input for example.

But I also think that maybe this is too much for renpy to handle. So many things moving on the screen at the same time. I made a simple baseball minigame before where only the ball and bg would move for a while and sometimes it caused lag on average computers.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#6 Post by xela » Sat Dec 06, 2014 2:42 pm

KomiTsuku wrote:I don't think anyone has done something like that. I've given some thought into it, but it gets pretty complex with either QTE timer event or a mess of if variables and location coordinates. I'm not even sure how some computers would handle the constant shifting graphics in the renpy engine.
LoL

Way to underestimate Python/Ren'Py :) There will be no issues even on slow machines as long as you know what you're doing.

Timer you need only for the hack. "mess" is a problem of a bad coder, creating a mess here is prolly harder than not creating one.

My approach would be to create a sprite manager class (assuming we'll get a lot of similar/same displayable). Create a simple class holding a speed, coords and picture of the displayable. Then it's a matter of making 4 starting positions, 4 sets of coordinates where player should press/click mouse/keyboard keys and check if there is an object in range of those coordinates whenever a button is clicked. Not in range = -1 point, in range +1 point.

This seems to me a simpler approach than messing with timers but I've messed with something along these lines not so long ago so there is a bias :) Maybe timers will work just as well/better.
Kaen wrote:Right now I'm more worried about how to handle the music itself than the graphics. How to make the music react based on the player input for example.
It's very easy, in UDD or Sprite Manager classes you have an event method. Inside of that method you can play any kind of sounds/change music based on conditions when the button is pressed. It's actually the easiest part. But there is prolly not a hard part to any of this, just a bit of time to get a concept, graphics and code together and work out any possible kinks.
Kaen wrote:But I also think that maybe this is too much for renpy to handle. So many things moving on the screen at the same time. I made a simple baseball minigame before where only the ball and bg would move for a while and sometimes it caused lag on average computers.
I find that hard to believe... but a "bg", that can be huge, especially a complex, large background picture that takes insane amount of memory. What we're talking here, are simple, small objects. I refuse to believe that Ren'Py cannot handle this even on slower machines as I've seen Milky's code launching dozens of ships moving in funny trajectories shooting energy orbs around on my old laptop using SpriteManager without an lag.
Like what we're doing? Support us at:
Image

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#7 Post by xela » Sat Dec 06, 2014 5:26 pm

The problem with the picture you've (very recently) provided in the front is that it will require a good deal of effort just to get the graphics right. Movement trajectories are very simple since it's still just a linear movement between two points (you'd need a simple math formula for coord updates), the problem is to create the graphics and change them as the sprites move towards the player. It's the same code setup as I provide below but you'll have to:

Code: Select all

self.show.destroy()
self.show = self.show_sprite()
where a self.show_sprite method returns the correct picture for the current y position of the every sprite on the screen. You could also use a zoom transform for this (simply changing the size with the distance). But this is something you have to toy with yourself :)

=====================================================
This is a simple and somewhat rushed code setup for a single line of "A" letters. The idea is to click and catch the event (click the left mouse button). Letter will disappear if you click right (it can just as easy be an event changing music or playing a sound or changing music channels and etc). This is very simple to expand to multiple lines or to add graphics.

If you add a background, 4 lines, some music/sounds and simple pngs for graphics, it can do the job nicely and look something like the attached files in the end.

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 = -50
            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
                            # We destroy the sprite, making it impossible to it twice :)
                            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
    text "A":
        pos (1000, 50)
                
label start:
    python:
        hits = 0
        misses = 0
        t = time.time()
        manager = SpriteManager(update=sprites_update, event=sprites_event)
        sprite = Text("A")
        targets = set(1000+i for i in xrange(-20, 20)) # Just checking 1000 would be close to impossible to hit...
        sprites = []
        td = 0
        for i in xrange(100):
            td += renpy.random.random() + 0.5
            sprites.append(RhythmD(Text("A"), 10, td, 50))
            
        renpy.show_screen("show_vars")
        renpy.show("_", what=manager, zorder=1)
        
    while True:
        $ result = ui.interact()
Attachments
1-468x.jpg
pupularcriticalhit530pxheaderimg.jpg
Last edited by xela on Sat Dec 06, 2014 6:20 pm, edited 2 times in total.
Like what we're doing? Support us at:
Image

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#8 Post by Kaen » Sat Dec 06, 2014 5:33 pm

Thank you xela!

Ah, indeed, the bg I talked about was quite big, I gotta admit. I'm glad you're positive this gonna work with renpy! If you say so, I believe haha.

For now the graphics are not that important. I just need to make a working prototype, so I know what to ask for my artist later. We'll probably just use 2D sprites I think, because I have no clues how to work with 3D right now.

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#9 Post by Kaen » Sat Dec 06, 2014 6:13 pm

Wow, the example you provided is really awesome!

I liked your suggestion a lot! The 1st attachment is really cute and seems to be smooth to handle, I'll try to follow this design.

I'm still having a hard time with the music though. I'm not sure if this is a good approach on how to handle it, but what I thought would be something like this:

• Have 2 versions of a song, one is the wrong and the other is the right
• Play both songs at the same time on different channels, but the right one will have 0 volume for now
• Every time the player make a right input, the right song will have it's volume raised for a brief period of time, while the wrong song will be muted
• Also points will be added or removed like in your example

I'm not sure though.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#10 Post by xela » Sat Dec 06, 2014 6:42 pm

Kaen wrote:Wow, the example you provided is really awesome!

I liked your suggestion a lot! The 1st attachment is really cute and seems to be smooth to handle, I'll try to follow this design.

I'm still having a hard time with the music though. I'm not sure if this is a good approach on how to handle it, but what I thought would be something like this:

• Have 2 versions of a song, one is the wrong and the other is the right
• Play both songs at the same time on different channels, but the right one will have 0 volume for now
• Every time the player make a right input, the right song will have it's volume raised for a brief period of time, while the wrong song will be muted
• Also points will be added or removed like in your example

I'm not sure though.
Don't they provide a beat and then add musical instruments throught other channels if for as long as player is hitting the right keys? And silly sounds or just shutting off the channels if you miss?

I have no idea... my approach would be to add cool sounds and points if player hits the right keys. Maybe some combos with graphics on multihits. Music is the last thing I would mess with.

I may have missed your point. If you want to make a pure musical game and this is not a minigame to enrich a sim rpg or vn... renpy may not be a good option for this.

Also, you'll have to analize the track to know when it is sensible to hit for the right instrument or channel. You wkuld not be able to use random in such a case. Seems like a bloody nightmare to me...
Like what we're doing? Support us at:
Image

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#11 Post by Kaen » Sat Jan 10, 2015 7:23 am

Haha yeah I think the way you see how to handle music is a better approach, thank you for the advise xela.

I've been studying and experimenting the code you provided and I could make some changes I wanted. I had never seem something like this before so it was quite complicated in the beginning. There are some things I couldn't figure out yet though.

• If I had more than 1 line, how could I handle the events on Android? For PC we can use multiple keys but I was hoping to release it for Android too and the touch screen simulates mouse right click right?

• Is it possible to add ATL at the sprites on the line? I wanted to have more freedom on what the sprites do while they're not hit but I didn't find a way so far. There are two things that I'd like most: make them increase in size the more closer they are to the hit point and make they move in different directions, not only right/left/up/down. I can easily do this with ATL but I don't know how to apply it.

Thank you!

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#12 Post by xela » Sat Jan 10, 2015 10:20 am

Kaen wrote:• If I had more than 1 line, how could I handle the events on Android? For PC we can use multiple keys but I was hoping to release it for Android too and the touch screen simulates mouse right click right?
Assuming that you know that it simulates mouse click (I never made a game for Android before, my own guess would be left click), I would do this:

Code: Select all

def sprites_event(ev, x, y, st):
x, y should return mouse position (and hopefully, click position in case of android). If your create a set of mouse coordinates that fill the space that you wish to be clickable, you can check if coords in there match coords of x and y. This way you will know where the user have clicked and resolve the loop accordingly.

I also have a vague idea about putting a mouse button or some displayable that can be clicked to return a pygame event but I did the coords thing for a PC game but never messed with this option. But it should be perfectly possible to get done :) It is conceivable that you can even pass arguments to manager or through store namespace (use clicks a simple imagebutton on the screen, it sets a field in manager or a global variable, event is triggered and if the variable is True, you resolve the loop accordingly). Might be a valid hack, like I've said, never tried this before...
Kaen wrote:• Is it possible to add ATL at the sprites on the line? I wanted to have more freedom on what the sprites do while they're not hit but I didn't find a way so far. There are two things that I'd like most: make them increase in size the more closer they are to the hit point and make they move in different directions, not only right/left/up/down. I can easily do this with ATL but I don't know how to apply it.
This code was not written with this in mind. Everything is rendered at the start and moving is likely to be blocked for the transform as well if you're not doing it through the update function or messing with default methods as is done for snowblossom. Basically it's far from simple...

It can be done but it'll prolly be slow as hell and act weird:

to try:

Code: Select all

self.show = manager.create(At(sprite, transform_name(delay))

Code: Select all

transform transform_name(td):
    subpixel True
    td
    # instruction like zoom.

====================================================
There are many ways to get it done exactly like you've described, this is just a poor way to try it...
Like what we're doing? Support us at:
Image

User avatar
Kaen
Regular
Posts: 148
Joined: Tue Oct 16, 2012 10:49 pm
Contact:

Re: Rhythm Game on Renpy

#13 Post by Kaen » Sun Jan 11, 2015 4:25 pm

Thank you again xela.

I could make the zoom work, but for some reason the xy position is not changing at all.

I commented the xy position code on the RhythmD class so it's not really conflicting with that. Any idea why this is happening or how can I fix it?

Code: Select all

transform transform_name(td):
    subpixel True # what this represent exactly?
    td # what this represent exactly? I noticed that only 1 sprite is created if this is not present.
    # instruction like zoom.
    xalign 0.5 ypos 0.14 zoom 0.1
    linear 2.0 xalign 0.0 ypos 0.1 zoom 1.0

class RhythmD(object):
        def __init__(self, sprite, speed, delay, ypos=0):
            self.sprite = sprite
            self.speed = speed
            self.delay = delay
            self.show = manager.create(At(sprite, transform_name(delay)))
            #self.show.x = 640 # If I could set xalign instead of xpos it would help too
            #self.show.y = ypos
            self.moving = False # No point in checking if it isn't.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Rhythm Game on Renpy

#14 Post by xela » Sun Jan 11, 2015 6:32 pm

I didn't really expect position changes to work through a transform, I think that transform positioning is overwritten + you're supposed to control it through manager update method...

Code: Select all

    def ships_update(st):
        """
        Updates ships data (just coords for now) on the screen.
        """
        for ship in ships:
            store.ship = ship
            
            # I don't know the pro trick to get this done :(
            # Shitty codebit follows (but it works):
            x = round(ship.x)
            y = round(ship.y)
            x = list(x+i for i in xrange(-7, 8))
            y = list(y+i for i in xrange(-7, 8))
            if ship.moving or (not (round(ship.target_coords[0]) in x and round(ship.target_coords[1]) in y)):
                if ship.moving:
                    ship.moving += 1
                    if ship.moving == 3:
                        ship.moving = 0
                        
                sprite = ship.sprite
                x = ship.x
                y = ship.y
                
                deltax = ship.speed*math.sin(math.radians(ship.head))
                deltay = ship.speed*math.cos(math.radians(ship.head))
    
                ship.show.destroy()
                ship.show = manager.create(At(sprite, rotate_by(ship.head)))
                ship.x = x + deltax
                ship.y = y - deltay
                renpy.restart_interaction()
                
            if ship.x < -ship.offset:
                ship.x = config.screen_width - ship.offset
            if ship.y < -ship.offset:
                ship.y = config.screen_height - ship.offset
            if ship.x > config.screen_width - ship.offset:
                ship.x = -ship.offset
            if ship.y > config.screen_height - ship.offset:
                ship.y = -ship.offset

        return 0.05
        
    def ships_event(ev, x, y, st):
        if ev.type == MOUSEBUTTONDOWN:
            if ev.button == 1:
                if hasattr(store, "ship") and store.ship is not None:
                    ship = store.ship
                    
                    renpy.music.play("picar.wav", channel="sound")
                    
                    angle = math.atan2((y-ship.offset) - ship.show.y, (x-ship.offset) - ship.show.x)
                    angle = angle * (180/math.pi)
                    ship.head = angle + 90
                    
                    ship.target_coords = (x-ship.offset, y-ship.offset)
                    ship.moving = 1
                    renpy.restart_interaction()
All this does is sending a ship (USS Enterprise) in a straight line to whereever you click with the mouse and saying Engage in Picards voice (+ it turns the ship to the target). This is an example how to handle movement in our setup (I modified this dummy project for the Rythm game), so it's up to you to try figuring out how it works and mess with the movement or leave things as they are and use just the zoom.

subpixel True is the subpixel positioning of transforms child. May not be very useful here but doesn't hurt either.

td is time delay (pause). Transform start executing instructions provided to them on show. We render all of the sprites at once with this particular setup so without delay, spites that start their movement later would have completed their instructions before their movement starts.

# self.show.x = 640 # If I could set xalign instead of xpos it would help too
You are on the right track here but it needs to be done in the managers update method with a code similar to the code above.
======================================================================================================

Other options:
Proper timed transforms and a function that executes and checks if transform is in range when a button is clicked (like a normal button on the screen). I think it may work... but it can be laggy or present some other issues, I never tried that.

UDD but it will require code similar to the above.
Like what we're doing? Support us at:
Image

User avatar
Stelluna
Newbie
Posts: 6
Joined: Wed Sep 19, 2018 11:15 am
Deviantart: stelluna7
Contact:

Re: Rhythm Game on Renpy

#15 Post by Stelluna » Tue Oct 02, 2018 2:16 pm

I know this topic is fairly old, but I was just wondering if someone could show me how to time the notes to music? Also, I'm having trouble changing the keymap and adding more types of notes/buttons. Any help would be appreciated :)

Post Reply

Who is online

Users browsing this forum: Google [Bot], hell_oh_world