Гравитация в pygame

Я делаю платформу с pygame, и я хотел бы добавить к ней гравитацию. Прямо сейчас у меня есть только картинка, которая движется, когда я нажимаю клавиши со стрелками, и моим следующим шагом будет гравитация. Вот мой код:

import pygame, sys
from pygame.locals import *

pygame.init()

FPS = 30
fpsClock = pygame.time.Clock()

DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption("Jadatja")

WHITE = (255, 255, 255)
catImg = pygame.image.load("images/cat.png")
catx = 10
caty = 10
movingRight = False
movingDown = False
movingLeft = False
movingUp = False

while True: #main game loop

    #update
    for event in pygame.event.get():
    if event.type == KEYDOWN:
        if event.key == K_RIGHT:
            #catx += 5
            movingRight = True
            movingLeft = False
        elif event.key == K_DOWN:
            #caty += 5
            movingDown = True
            movingUp = False
        elif event.key == K_LEFT:
            #catx -= 5
            movingLeft = True
            movingRight = False
        elif event.key == K_UP:
            #caty -= 5
            movingUp = True
            movingDown = False

    if event.type == KEYUP:
        if event.key == K_RIGHT:
            movingRight = False
        if event.key == K_DOWN:
            movingDown = False
        if event.key == K_LEFT:
            movingLeft = False
        if event.key == K_UP:
            movingUp = False


    #actually make the player move
    if movingRight == True:
        catx += 5
    if movingDown == True:
        caty += 5
    if movingLeft == True:
        catx -= 5
    if movingUp == True:
        caty -= 5


    #exit
    for event in pygame.event.get():
        if event.type == KEYUP:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()

        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    #draw
    DISPLAYSURF.fill(WHITE)
    DISPLAYSURF.blit(catImg, (catx, caty))



    pygame.display.update()
    fpsClock.tick(FPS)

Я не уверен на 100%, что этот код такой же гладкий, как я думаю, но я надеюсь, что вы, ребята, сможете что-то из этого сделать.

Спасибо


person Fashana    schedule 14.05.2013    source источник
comment
Что вы уже пробовали для реализации гравитации? Привет, мир гравитации работает, применяя отрицательную кати каждый раз, когда считается, что спрайт находится в воздухе. Но я повторяю, что вы пробовали до сих пор?   -  person Tadgh    schedule 14.05.2013


Ответы (1)


Существует руководство по созданию прыгающего мяча, которое, я думаю, может быть полезным. тебе.

Теперь, чтобы добавить гравитацию в эту симуляцию, вы просто добавляете некоторую дополнительную скорость в направлении Y каждый раз в цикле:

speed[1] += gravity

Однако то, что вы получите, довольно глупо, поскольку изображение быстро опускается ниже нижней части окна, и его больше никогда не видно :)

Следовательно, следующим шагом будет обрезание положения мяча, чтобы он оставался в окне:

import os
import sys, pygame
pygame.init()

size = width, height = 320, 240
speed = [1, 1]
black = 0, 0, 0
gravity = 0.1

screen = pygame.display.set_mode(size)

image_file = os.path.expanduser("~/pybin/pygame_examples/data/ball.png")
ball = pygame.image.load(image_file)
ballrect = ball.get_rect()

def clip(val, minval, maxval):
    return min(max(val, minval), maxval)

while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

    speed[1] += gravity

    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    # clip the position to remain in the window

    ballrect.left = clip(ballrect.left, 0, width)
    ballrect.right = clip(ballrect.right, 0, width)        
    ballrect.top = clip(ballrect.top, 0, height)
    ballrect.bottom = clip(ballrect.bottom, 0, height) 

    screen.fill(black)
    screen.blit(ball, ballrect)
    pygame.display.flip()

Хорошо, теперь вы можете включить это в свой текущий код, и все будет готово. Однако есть некоторые вещи, которые вы можете сделать, чтобы сделать ваш код более организованным и менее повторяющимся.

Например, рассмотрим массивные блоки if...then, следующие за

for event in pygame.event.get(): 

Вы можете переписать его как-то так:

delta = {
    pygame.K_LEFT: (-20, 0),
    pygame.K_RIGHT: (+20, 0),
    pygame.K_UP: (0, -20),
    pygame.K_DOWN: (0, +20),  
    }
for event in pygame.event.get():
    if event.type == pygame.KEYDOWN:
        deltax, deltay = delta.get(event.key, (0, 0))
        ball.speed[0] += deltax
        ball.speed[1] += deltay

Вы также можете извлечь выгоду из помещения всей логики, связанной с движением вашего изображения, в класс:

class Ball(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) 
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.speed = [0, 0]
        area = pygame.display.get_surface().get_rect()
        self.width, self.height = area.width, area.height

    def update(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > self.width:
            self.speed[0] = -self.speed[0]
        if self.rect.top < 0 or self.rect.bottom > self.height:
            self.speed[1] = -self.speed[1]
        self.rect.left = clip(self.rect.left, 0, self.width)
        self.rect.right = clip(self.rect.right, 0, self.width)        
        self.rect.top = clip(self.rect.top, 0, self.height)
        self.rect.bottom = clip(self.rect.bottom, 0, self.height)                

Обратите внимание, что метод update очень похож на код, представленный в руководстве. Одна из приятных особенностей создания класса Ball заключается в том, что остальной части вашей программы не нужно много знать о том, как движется Ball. Вся логика в Ball.update. Кроме того, это позволяет легко создавать множество мячей. И вы можете создать другие классы (самолеты, птицы, весла и т. д.), которые тоже двигаются по-другому, и относительно безболезненно добавить их в свою симуляцию.

Итак, собрав все это вместе, вы получите что-то вроде этого:


"""
http://stackoverflow.com/a/15459868/190597 (unutbu)
Based on http://www.pygame.org/docs/tut/intro/intro.html
Draws a red ball bouncing around in the window.
Pressing the arrow keys moves the ball
"""

import sys
import pygame
import os


image_file = os.path.expanduser("~/pybin/pygame_examples/data/ball.png")

delta = {
    pygame.K_LEFT: (-20, 0),
    pygame.K_RIGHT: (+20, 0),
    pygame.K_UP: (0, -20),
    pygame.K_DOWN: (0, +20),  
    }

gravity = +1

class Ball(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) 
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.speed = [0, 0]
        area = pygame.display.get_surface().get_rect()
        self.width, self.height = area.width, area.height

    def update(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > self.width:
            self.speed[0] = -self.speed[0]
        if self.rect.top < 0 or self.rect.bottom > self.height:
            self.speed[1] = -self.speed[1]
        self.rect.left = clip(self.rect.left, 0, self.width)
        self.rect.right = clip(self.rect.right, 0, self.width)        
        self.rect.top = clip(self.rect.top, 0, self.height)
        self.rect.bottom = clip(self.rect.bottom, 0, self.height)                

def clip(val, minval, maxval):
    return min(max(val, minval), maxval)

class Main(object):
    def __init__(self):
        self.setup()
    def setup(self):
        pygame.init()
        size = (self.width, self.height) = (640,360)
        self.screen = pygame.display.set_mode(size, 0, 32)
        self.ball = Ball()
        self.setup_background()
    def setup_background(self):
        self.background = pygame.Surface(self.screen.get_size())
        self.background = self.background.convert()
        self.background.fill((0, 0, 0))
        self.screen.blit(self.background, (0, 0))
        pygame.display.flip()
    def draw(self):
        self.screen.blit(self.background, (0, 0))
        self.screen.blit(self.ball.image, self.ball.rect)
        pygame.display.flip()
    def event_loop(self):
        ball = self.ball
        friction = 1
        while True:
            for event in pygame.event.get():
                if ((event.type == pygame.QUIT) or 
                    (event.type == pygame.KEYDOWN and 
                     event.key == pygame.K_ESCAPE)):
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    deltax, deltay = delta.get(event.key, (0, 0))
                    ball.speed[0] += deltax
                    ball.speed[1] += deltay
                    friction = 1
                elif event.type == pygame.KEYUP:
                    friction = 0.99

            ball.speed = [friction*s for s in ball.speed]
            ball.speed[1] += gravity
            ball.update()
            self.draw()
            pygame.time.delay(10)

if __name__ == '__main__':
    app = Main()
    app.event_loop()
person unutbu    schedule 14.05.2013