How do you properly implement gravity to a free floating space object and some sort of friction when thrusting in opposite direction

房东的猫 提交于 2021-02-02 03:44:50

问题


I am trying to program movement that is basically like Asteroids where once UP button is pressed you accelerate to a certain speed and then because in space you don't stop and can only slow down by thrusting in opposite direction. On top of that, I would like gravity to be pulling you towards the bottom of the screen. I have this accomplished for the most part but the issue I have is:

  1. When I turn around and thrust opposite direction, it doesn't slow down first going backwards before starting to move forwards again, it just shoots off in opposite direction at full speed

Any suggestions of how to handle this and make movement smoother in general?

import pygame as pg
import os
vec = pg.math.Vector2

TITLE = "GRAVITAR"
WIDTH = 800
HEIGHT = 600
FPS = 60
GREY = (211, 211, 211)

# Player properties
ROCKET_SHIP = 'Images/Rocket_Ship.png' # <a href='https://pngtree.com/so/spaceship-clipart'>spaceship 
                                       # clipart png from pngtree.com</a>
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.00
PLAYER_GRAV = 0.1
PLAYER_ROT_SPEED = 200
PLAYER_SPEED = 5

class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        pg.sprite.Sprite.__init__(self)
        self.game = game
        self.image = game.rocket_ship
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
        self.vel = vec(0, 0)
        self.pos = vec(x, y)
        self.rot = 0

    def get_keys(self):
        self.rot_speed = 0
        self.acc = vec(0, PLAYER_GRAV)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.rot_speed = PLAYER_ROT_SPEED
        if keys[pg.K_RIGHT]:
            self.rot_speed = -PLAYER_ROT_SPEED
        if keys[pg.K_UP]:
            self.vel = vec(PLAYER_SPEED, 0).rotate(-self.rot)
        if keys[pg.K_SPACE]:
            self.shoot()
        self.acc += self.vel * PLAYER_FRICTION
        self.vel += self.acc
        if self.vel[1] >= 2:
            self.vel[1] = 2
        self.pos += self.vel + 0.5 * self.acc

    def shoot(self):
        pass

    def update(self):
        self.get_keys()
        self.rot = (self.rot + self.rot_speed * self.game.dt) % 360
        self.image = pg.transform.rotate(self.game.rocket_ship, self.rot - 90)
        self.rect = self.image.get_rect()
        self.rect.center = self.pos
        self.pos += self.vel * self.game.dt
        if self.pos.x > WIDTH:
            self.pos.x = 0
        if self.pos.x < 0:
            self.pos.x = WIDTH
        if self.pos.y > HEIGHT:
            self.pos.y = 0
        if self.pos.y < 0:
            self.pos.y = HEIGHT

class Game:
    def __init__(self):
        # Initialize pygame and create window
        pg.init()
        pg.mixer.init()
        pg.key.set_repeat(10, 50)
        os.environ['SDL_VIDEO_WINDOW_POS'] = '568, 101'
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        self.running = True
        self.load_data()

    def load_data(self):
        self.rocket_ship = pg.image.load(ROCKET_SHIP).convert_alpha()
        self.rocket_ship = pg.transform.scale(self.rocket_ship, (32, 32))

    def new(self):
        # Start a new game
        self.all_sprites = pg.sprite.Group()
        self.player = Player(self, WIDTH / 2, HEIGHT / 4)
        self.all_sprites.add(self.player)
        self.run()

    def run(self):
        # Game loop
        self.playing = True
        while self.playing:
            self.dt = self.clock.tick(FPS) / 1000.0
            self.events()
            self.update()
            self.draw()

    def update(self):
        # Game loop update
        self.all_sprites.update()

    def events(self):
        # Game loop events
        for event in pg.event.get():
            if event.type == pg.QUIT:
                if self.playing:
                    self.playing = False
                self.running = False

    def draw(self):
        # Game loop draw
        pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
        self.screen.fill(GREY)
        self.all_sprites.draw(self.screen)

        # After drawing everything, flip display
        pg.display.flip()

    def show_start_screen(self):
        pass

    def show_go_screen(self):
        pass

g = Game()
g.show_start_screen()
while g.running:
    g.new()
    g.show_go_screen()

pg.quit()


      

回答1:


When you press UP you don't have to change the speed, but you have to set the acceleration:

self.vel = vec(PLAYER_SPEED, 0).rotate(-self.rot)

self.acc += vec(PLAYER_ACC, 0).rotate(-self.rot)

Add the acceleration to the velocity:

self.vel += self.acc

I recommend limiting the maximum. However, I recommend doing this separately for each direction:

max_vel = 2
self.vel[0] = max(-max_vel, min(max_vel, self.vel[0]))
self.vel[1] = max(-max_vel, min(max_vel, self.vel[1]))

Apply this to the method get_keys:

class Player(pg.sprite.Sprite):
    # [...]

    def get_keys(self):
        self.rot_speed = 0
        self.acc = vec(0, PLAYER_GRAV)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.rot_speed = PLAYER_ROT_SPEED
        if keys[pg.K_RIGHT]:
            self.rot_speed = -PLAYER_ROT_SPEED
        if keys[pg.K_UP]:
            self.acc += vec(PLAYER_ACC, 0).rotate(-self.rot)
        if keys[pg.K_SPACE]:
            self.shoot()
        self.vel += self.acc + self.vel * PLAYER_FRICTION
        max_vel = 2
        self.vel[0] = max(-max_vel, min(max_vel, self.vel[0]))
        self.vel[1] = max(-max_vel, min(max_vel, self.vel[1]))
        self.pos += self.vel


来源:https://stackoverflow.com/questions/65546677/how-do-you-properly-implement-gravity-to-a-free-floating-space-object-and-some-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!