问题
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:
- 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