1

I am a fifth-grader and I'm making a platformer. I'm trying to keep my player from penetrating through the screen when I use gravity. I also need help jumping once with one click and jumping twice as high with 2 clicks. I also used some pieces of code that I found online. So this is my code:

import pygame

canvas_width = 1000
canvas_height = 500
pygame.init()
screen = pygame.display.set_mode([canvas_width,canvas_height])
screen_rect = screen.get_rect()
clock = pygame.time.Clock()

red = (255,0,0)
blue = (0,0,255)
green = (0,255,0)
white = (255,255,255)
black = (0,0,0)


class Ground:
    def __init__ (self,position,size,color):
        self.xPos = position[0]
        self.yPos = position[1]
        self.width = size[0]
        self.height = size[1]
        self.color = color
        self.rect = pygame.rect.Rect(position,size)

#class Enemyline:
#    def __init__ (self,position,size,color):
#        self.xPos = position[0]
#        self.yPos = position[1]
#        self.width = size[0]
#        self.height = size[1]
#        self.color = color
#        self.rect = pygame.rect.Rect(position,size)
#        #self.rect[(xPos,yPos),(width,height)]
        
#     def __init__(self, xsize, ysize,  color):
#         self.color = color
#         self.xsize = xsize
#         self.ysize = ysize
#         self.pos = [0, 10]
#         self.rect = pygame.rect.Rect(self.pos, (xsize, ysize))

class Ball:
    
    def __init__(self,position,size,color):
        self.xPos = position[0]
        self.yPos = position[1]
        self.width = size[0]
        self.height = size[1]
        self.color = color
        #self.size = size
        #self.pos = [10, 450]
        self.speed = [0.001, 0.001]
        #speed [xSpeed,ySpeed]
        self.rect = pygame.rect.Rect(position,size)
        #self.rect = pygame.rect.Rect(self.pos,(size,size))

    def move (self):
        self.keymove()
        #self.hitRect(Enemyline)
        self.gravity()
        #self.edge()
        self.rect.move_ip(self.speed)
        #self.pos = self.rect[0:2]
        pygame.draw.rect(screen, self.color,self.rect)
        
    def touchRect(self,Enemyline, Ground):
        #if self.rect.colliderect(Enemyline):
            #self.speed[1] = self.speed[1] * -1
            
        if self.rect.colliderect(Ground):
            self.speed[1] = self.speed[1] * 0
    
    
    def gravity(self):
        self.speed[1] = self.speed[1] + 0.5
        
#     def edge(self):
#         spot = self.rect[0:2]
#         xPos = spot[0]
#         yPos = spot[1]
#         if xPos <= 0 or xPos >= (canvas_width - self.size):
#             self.speed[0] = self.speed[0] + 0
#         
#         if yPos <= 0 or yPos >= (canvas_height - self.size):
#             self.speed[1] = self.speed[1] + 0
    
    def keymove(self):
        spot = self.rect[0:2]
        xPos = spot[0]
        yPos = spot[1]
        
        
        key = pygame.key.get_pressed()
        
        if key[pygame.K_LEFT]:
            self.speed[0] = self.speed[0] - 0.5

        
        #RIGHT
        if key[pygame.K_RIGHT]:
            self.speed[0] = self.speed[0] + 0.5
        
        #UP
        if key[pygame.K_UP]:
            self.speed[1] = self.speed[1] - 0.5
        #DOWN
        if key[pygame.K_DOWN]:
            self.speed[1] = self.speed[1] + 0.5
                    
        if xPos <= 0 or xPos >= (canvas_width - (self.width + self.height)):
            self.speed[0] = self.speed[0] * -1
        
        if yPos <= 0 or yPos >= (canvas_height - (self.width + self.height)):
            self.speed[1] = self.speed[1] * -1
            
    
#     def stop(self):
#         self.speed[0] = 0
#         self.speed[1] = 0
#         
#     def key_up(self):
#         if [pygame.K_LEFT] == pygame.KEYUP:
#             stop()


        

        
ball = Ball ([500,250],[30,30],blue)
ground = Ground ([0,470],[1000,10],green)
#L1enemy1 = Enemyline ([0,10], [1000,10],red)

Game = True

while Game:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Game = False
    
    
    ball.move()
#     if (ball.hitRect(L1enemy1) == True):
#         self.speed = [0.001, 0.001]
#         self.speed[1] = self.speed[1] * -1
    screen.fill(black)
    pygame.draw.rect(screen, ball.color, ball.rect)
    pygame.draw.rect(screen, ground.color, ground.rect)
#    pygame.draw.rect(screen, L2enemy2.color, L2enemy2.rect)
    
    pygame.display.update()
    clock.tick(60)

pygame.quit()```

Is there anything you could do?

Thank you.
Kayaan
  • 11
  • 1
  • Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. – Community Jun 25 '22 at 04:02

2 Answers2

0

I played around with your game and got the same behavior. After testing out various blocks of code, I determined that during the collisions with the ground, the "ball" position would often times be below the ground position when the switch from "plus" speed to "minus" speed would occur. So before the ball got moving back up, its position would be checked. And, since its position was still below the ground level which would again reverse the speed to a positive value. Thus it was displaying that "sinking in quicksand" effect. Once the position was below the ground level, it would just keep sinking.

You might want to explore other options, but the way I got it to quit oscillating between positive and negative speed values while the object appeared to be at or under the ground level was to change the following line of code from:

if yPos <= 0 or yPos >= (canvas_height - (self.width + self.height)):

to:

if yPos <= 0 or yPos >= (canvas_height - (self.width + self.height)) and self.speed[1] > 0:

Only doing the speed switch from positive to negative when the noted speed was positive seemed to provide a "shock absorber" effect to counter any lag between the positioning of the ball and the tests for hitting the ground.

Try that out and see if that helps you out.

Regards.

NoDakker
  • 3,390
  • 1
  • 10
  • 11
  • What is the reason for `(self.width + self.height)`? What's the point of adding height and width? – Rabbid76 Jun 24 '22 at 20:34
  • I guess we will need to let Kayann answer that. That was the way the program was coded. – NoDakker Jun 24 '22 at 20:40
  • You should answer that. `self.width + self.height` makes no sense at all and seems to be one of the problems with his algortihm. – Rabbid76 Jun 24 '22 at 20:54
  • To @Rabbid76 and @NoDakker, I had a `self.size` but in my code, some of the stuff, that's commented out, is for an enemy in my game. I gave it a different code compared to the ball object in my game, but then I thought, why not keep it the same as the ball? So I changed it and now I have a `self.width + self.height` instead of a `self.size`. – Kayaan Jun 25 '22 at 04:24
  • @NoDakker, thanks so much for helping XD! It helped me figure out where the actual problem was. I also found out that when the ball touched the ground, it got stuck. All I did was I increased the jump power. This is what I did: `def keymove(self): [. . .] if key[pygame.K_UP]: self.speed[1] = self.speed[1] - 3 #--------this is my change` – Kayaan Jun 25 '22 at 04:36
  • @NoDakker I think you do not get my point. There is absolutely no meaning of adding width and height. The width is a size along the x-axis and the height is a size along the y-axis. – Rabbid76 Jun 25 '22 at 07:22
0

The condition

if yPos <= 0 or yPos >= (canvas_height - (self.width + self.height)):

makes no sense. There is absolutely no point in adding width and height together. The width is a size along the x-axis and the height is a size along the y-axis. Your code works by chance, because self.width is the same as distacnce from the bottom of the window to the top of the green line. What you actually wanted to do is:

if yPos <= 0 or yPos >= ground.rect.top - self.height:

Anyway, that doesn't solve your problem. The problem is similar to the problem described here: Sometimes the ball doesn't bounce off the paddle in pong game. The real problem is that the speed decreases. If the object goes below the line and the upward speed is insufficient to lift the object above the line, the object will get stuck.

You have 2 Option to solve the problem

  1. Make sure the movement is up as long as the object is beneath the ground. You can achieve that with self.speed[1] = -abs(self.speed[1]) instead of self.speed[1] = self.speed[1] * -1
if yPos <= 0:
    self.speed[1] = abs(self.speed[1])

elif yPos >= ground.rect.top - self.height:
    self.speed[1] = -abs(self.speed[1])
  1. Limit the bottom of the object to the top of the ground when the object hits the ground (self.rect[1] = ground.rect.top - self.height):
if yPos <= 0:
    self.speed[1] = self.speed[1] * -1

elif yPos >= ground.rect.top - self.height:
    self.speed[1] = self.speed[1] * -1
    yPos = ground.rect.top - self.height
    self.rect[1] = yPos
Rabbid76
  • 202,892
  • 27
  • 131
  • 174