Ren'Py Creator-Defined Displayables and Minigames

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,923
I'm trying to do a relatively simple Breakout mini-game in ren'py using the tutorial's pong game as a basis.

However, for starters, I can't even get the initial parameters to read as an x position instead of a y position.
Code:
            self.SHIELD_WIDTH = 95
            self.SHIELD_HEIGHT = 12
            self.SHIELD_X = 240
            self.SHIELD_TOSS_WIDTH = 15
            self.SHIELD_TOSS_HEIGHT = 15
            self.ARENA_TOP = 30
            self.ARENA_BOTTOM = 1020
            self.ARENA_LEFT = 600
            self.ARENA_RIGHT = 1300
The lines self.ARENA_LEFT = 600 and self.ARENA_RIGHT = 1300 are supposed to be x positions to mark the left and right borders of the "arena" for the breakout style game, since, unlike pong, it's a vertical display and not horizontal. That also means that the "ball" don't really have anywhere to bounce off of the sides, only top/bottom, which is read as left/right in this instance.

Can I get some help and guidance on how to make video games? So far I've been working with only simple scripts, and I see that things like pygame code can be relatively complicated. I know how to build in python, and this is similar, but I'm also trying to do other things like, for example, make the "paddle" move freely in the bottom part of the screen, and have the mouse left and right clicks send the balls towards different directions.

Here's the code so far:
Shield: Paddle
Shield_toss: The ball
Arena: the boundaries
Steven: The Player.
You don't have permission to view the spoiler content. Log in or register now.

Here's how the arena should look in a 1080p display.
You don't have permission to view the spoiler content. Log in or register now.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,964
16,210
However, for starters, I can't even get the initial parameters to read as an x position instead of a y position.
Well, you need to invert all the references to x and to y present in the code you use as base.

By example here :
Code:
            # The positions of the two shields.
            self.steven = (self.ARENA_LEFT - self.ARENA_RIGHT) / 2

            # The position, delta-position, and the speed of the
            # shield_toss.
            self.bx = self.SHIELD_X + self.SHIELD_WIDTH + 10
            self.by = self.steven
self.ARENA_LEFT{/icode] and [icode]self.ARENA_RIGHT are clearly used to define something related to the height, while you want them to now refer to the width.
 

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,923
I don't see any reference to x or y in the code. As in, by the default, the code values seem to only be y, and I can't find a way to define those specifically to be x, which is, as you say, what I need. Ideally, I do need both x and y axis to define the whole arena so the ball bounce around all edges.

Dunno if the definition comes directly from pygame.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,964
16,210
I don't see any reference to x or y in the code.
Not all are relevant and/or have to be updated, but personally I see 30 references to x and y :
Code:
            self.shield = Solid("#ffffff", xsize=self.SHIELD_WIDTH, ysize=self.SHIELD_HEIGHT)
            self.shield_toss = Solid("#ffffff", xsize=self.SHIELD_TOSS_WIDTH, ysize=self.SHIELD_TOSS_HEIGHT)
[...]
            self.bx = self.SHIELD_X + self.SHIELD_WIDTH + 10
            self.by = self.steven
            self.bdx = .5
            self.bdy = .5
[...]
                self.by = self.steven
[...]
                self.bx += self.bdx * speed
                self.by += self.bdy * speed
[...]
            if self.by < shield_toss_left:
                self.by = shield_toss_left + (shield_toss_left - self.by)
                self.bdy = -self.bdy
[...]
            if self.by > shield_toss_right:
                self.by = shield_toss_right - (self.by - shield_toss_right)
                self.bdy = -self.bdy
[...]
            def shield(px, py, hotside):
[...]
                if py - self.SHIELD_HEIGHT / 2 <= self.by <= py + self.SHIELD_HEIGHT / 2:
[...]
                    if oldbx >= hotside >= self.bx:
                        self.bx = hotside + (hotside - self.bx)
                        self.bdx = -self.bdx
[...]
                    elif oldbx <= hotside <= self.bx:
                        self.bx = hotside - (self.bx - hotside)
                        self.bdx = -self.bdx
[...]
            r.blit(shield_toss, (int(self.bx - self.SHIELD_TOSS_WIDTH / 2),
                          int(self.by - self.SHIELD_TOSS_HEIGHT / 2)))
[...]
            if self.bx < -50:
[...]
            elif self.bx > width + 50:
[...]
            y = max(y, self.ARENA_LEFT)
            y = min(y, self.ARENA_RIGHT)
            self.steven = y
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
Pong is probably the right place to start, but I do wonder if you've perhaps bitten off more than you can chew.

Firstly, as Anne points out, you need to rotate the whole gaming area. Anywhere in the code that deals with an "x" coordinate probably needs re-coding as "y" and visa-versa. But not every occurrence of x and y, just most of them. You need to visualize what each of those variables are being used for and adjust their code (and probably their names) accordingly.

So, for example, the original pong code included in the tutorial project has a line self.PADDLE_X = 240. That's the left hand edge of the player's paddle. So 240 points/pixels in from the left side of the screen. Except that makes no sense when the play area is organized vertically like a breakout game. At the very least, it should probably be changed to self.PADDLE_Y = 240 and then go search for any places where PADDLE_X is used and alter the code to adjust to the rotated play area. And that isn't always going to be as simple as swapping the variable either. A line that used to reference PADDLE_X probably needs PADDLE_X removing completely and PADDLE_Y adding to the line(s) below it (assuming the programmer deals with x positions before y positions).

Beyond that, breakout games usually have the player's paddle at the bottom of the screen, yet a simple rewrite of the code to rotate things is probably going to result with the player's paddle being at the top. So the code will need to be adjusted to reflect that.

Something else to watch out for is the hotside positioning/checks. The original pong code has a location calculated as being the side of the paddle that can interact with the ball. In the case of the player, that's the right hand edge of the player paddle and in the case of the computer... it's the left edge. Again... that doesn't work for a breakout style game, where the interaction locations will be on the top and bottom of the paddles. So all those checks need to be re-worked.

And all of that is before you get into storing details about lots of individual "bricks", like where in the breakout wall they are positioned and which have already been removed. Then there's the added complexity of keeping track of each collision point for each of those bricks - since in breakout, the ball could in theory hit any edge of the brick, not just the bottom.

I don't see any reference to x or y in the code. [...]

[...] Dunno if the definition comes directly from pygame.

... and it's comments like these that is pretty much why I'm wondering if you've bitten off more than you can chew.

x and y are all over the place, as Anne has listed.

From what I can see in the code, pygame is only being used to check if the left mouse button has been pressed in order to initially release the ball. Everything else is just drawing shapes on the screen and accessing the cursor position, neither of which use pygame. (I tested it by commenting out the import pygame and having the ball start moving without needing to click the mouse button).

I started to see if I could get a simple pong game working with everything going top/bottom instead of left/right. I had some problems because the original pong tutorial code is written for 1280x720 and my test project was 1920x1080. Beyond that, I've made some mistakes defining the "hotside" detection zones (which was why I mentioned it specifically). Plus the ball start position is wrong (since it's not in the middle of the paddle). My initial sizes were just guesses, so those are probably wrong too. By the time I reached this point, I realized it was taking more time than I planned for... so I abandoned it in this state...

You're welcome to try it though, even in it's broken state...

You don't have permission to view the spoiler content. Log in or register now.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,964
16,210
Pong is probably the right place to start, [...]
But just to start.

The code for a Pong game will provide the physics in case of collision, and the move of the paddle, but that's all.
The only collisions handled by the code will be with the wall and the paddle, the main addition to do will be to add all the part for the brick pattern. The displayable must draw them, as well as test if the ball collide with a brick.

Which make me wonder if the custom displayable shouldn't be used only to deal with the ball movement, the update of the brick pattern, and the paddle movements, getting rid of the whole display part.

Then it would looks more or less like :
Code:
# Each line is a row of the pattern
# 0 is an empty space.
# 1 -> x represent a brick, each value being a different kind or color.
default brickPattern = [ [ 0, 1, 0, 1, 2, 2, 1, 0, 1, 0 ],
                                    [ 0, 1, 0, 1, 1, 1, 1, 0, 1 ,0 ], 
                                    [...] ]
# Position of the paddle, updated by the displayable.
default paddlePos = (500, 1070)
# Position of the ball, updated by the displayable.
default ballPos = (550, 1065)

screen breakout():

    # The ball need to move first
    add GemCrushDisplayable()

    grid rows 1:
        for row in brickPattern:
            grid 1 columns:
                for atom in row:
                    add ( "images/breakout/brick{}.jpg".format( atom ) )

   add "images/breakout/paddle.jpg" pos paddlePos

   add "images/breakout/ball.jpg" pos ballPos
It would be faster to do the display in the custom displayable, but it's way easier to let Ren'py deal with it since you don't have to rewrite all the computation parts to find the position of everything.
 

AmazonessKing

Amazoness Entrepreneur
Aug 13, 2019
1,898
2,923
Necroing this thread trying to figure out how to add collision to images. Hopefully, in these 2 years there's more understanding of this, but well, let's see.

I started doing something I'm already familiar with, which is mouse tracking:
You don't have permission to view the spoiler content. Log in or register now.

It's still very early in development, I need to add things like a win/lose state, but that's already planned. What I'm mostly struggling with is adding collision to the images. I will try to reverse-engineer the pong demo once again to figure out a way to implement bullets based on the displayable size. If possible, I will just have to program how each pattern works, probably as it's own class altogether, but as long as there's collision between the bullets and the player/enemy bullets, that should work.

So, I'd like to ask for advice on how to start adding collision to these displayable.

Additionally, also trying to figure out how this space invaders game work, although it's far more complex: