Posts: 419
Threads: 34
Joined: May 2019
I have this sprite here. The controls are dreadful, and my tinkering is fruitless. I copied it from an Asteroids game, and took out the friction, but I broke it.
Sometimes the "thrust" will cause it to slow/break.
How fast you go is effected strongly by your angle.
Here is the sprite and the event handling. I haven't success yet with this type of controls yet. Any advice would be appreciated.
ship_max_speed = 2
ship_max_rtspd = 3
class Ship(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.ship_img = pygame.Surface((15,10), pygame.SRCALPHA)
self.ship_img.fill(red)
self.image = self.ship_img
self.rect = self.image.get_rect()
self.hit_rect = ship_HIT_RECT
self.hit_rect.center = self.rect.center
self.rect.centerx = x
self.rect.centery = y
self.hspeed = 0
self.vspeed = 0
self.dir = 0
self.rtspd = 0
self.thrust = False
def update(self):
speed = math.sqrt(self.hspeed**2 + self.vspeed**2)
if self.thrust:
if speed < ship_max_speed:
self.hspeed += math.cos(self.dir * math.pi / 180)
self.vspeed += math.sin(self.dir * math.pi / 180)
else:
self.hspeed = ship_max_speed * math.cos(self.dir * math.pi / 180)
self.vspeed = ship_max_speed * math.sin(self.dir * math.pi / 180)
self.rect.centerx += self.hspeed
self.rect.centery += self.vspeed
self.dir = (self.dir + self.rtspd) % 360
self.image = pygame.transform.rotate(self.ship_img, -self.dir)
self.rect = self.image.get_rect(center=self.rect.center)
####################################################################################
def get_event(self, event):
self.ship.rtspd = 0
if event.type == pygame.QUIT:
gameState = "Exit"
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.ship.thrust = True
if event.key == pygame.K_LEFT:
self.ship.rtspd = -ship_max_rtspd
if event.key == pygame.K_RIGHT:
self.ship.rtspd = ship_max_rtspd
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
self.ship.thrust = False
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
self.ship.rtspd = 0
Posts: 544
Threads: 15
Joined: Oct 2016
Example.
import os
import math
import pygame
from pygame.sprite import Sprite
class Scene:
def on_draw(self, surface): pass
def on_event(self, event): pass
def on_update(self, delta): pass
class Manager:
def __init__(self, caption, width, height, center=True):
if center:
os.environ['SDL_VIDEO_CENTERED'] = '1'
# Basic pygame setup
pygame.display.set_caption(caption)
self.surface = pygame.display.set_mode((width, height))
self.rect = self.surface.get_rect()
self.clock = pygame.time.Clock()
self.running = False
self.delta = 0
self.fps = 60
# Scene Interface
self.scene = Scene()
def mainloop(self):
self.running = True
while self.running:
for event in pygame.event.get():
self.scene.on_event(event)
self.scene.on_update(self.delta)
self.scene.on_draw(self.surface)
pygame.display.flip()
self.delta = self.clock.tick(self.fps)
def quit(self):
self.running = False
class Ship(Sprite):
def __init__(self, image, position, anchor="center"):
self.image = image
self.original_image = image
self.rect = image.get_rect(**{anchor: position})
self.position = pygame.Vector2(self.rect.center)
self.angle = 0
self.speed = 0
self.max_speed = 0.1
self.thrust = 0.00005
self.rotate_speed = 0.08
self.friction = 0.99
self.drift = 0.01
self.calculate_direction()
def calculate_direction(self):
rads = math.radians(self.angle)
self.direction = pygame.Vector2(math.sin(rads), math.cos(rads))
def draw(self, surface):
surface.blit(self.image, self.rect)
def movement(self, keys, delta):
if keys[pygame.K_UP]:
self.speed += self.thrust * delta
if self.speed > self.max_speed:
self.speed = self.max_speed
elif keys[pygame.K_DOWN]:
self.speed -= self.thrust * delta / 2
if self.speed < -self.max_speed / 2:
self.speed = -self.max_speed / 2
else:
self.speed = self.speed * self.friction
if -self.drift < self.speed < self.drift:
self.speed = 0
if keys[pygame.K_LEFT]:
self.angle = (self.angle + self.rotate_speed * delta) % 360
self.update_rotation()
elif keys[pygame.K_RIGHT]:
self.angle = (self.angle - self.rotate_speed * delta) % 360
self.update_rotation()
self.position += self.direction * self.speed * delta
self.rect.center = self.position
def update_rotation(self):
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.calculate_direction()
class ShipScene(Scene):
def __init__(self, manager):
self.manager = manager
self.create_ship()
def create_ship(self):
image = pygame.Surface((15, 10), pygame.SRCALPHA)
image.fill(pygame.Color('red'))
self.ship = Ship(image, self.manager.rect.center)
def on_draw(self, surface):
surface.fill(pygame.Color('black'))
self.ship.draw(surface)
def on_event(self, event):
if event.type == pygame.QUIT:
self.manager.quit()
def on_update(self, delta):
keys = pygame.key.get_pressed()
self.ship.movement(keys, delta)
def main():
pygame.init()
manager = Manager("Ship Thrust Example", 800, 600)
manager.scene = ShipScene(manager)
manager.mainloop()
if __name__ == "__main__":
main()
99 percent of computer problems exists between chair and keyboard.
Posts: 419
Threads: 34
Joined: May 2019
In your example the sprite drives like a car. I'm looking for it to drift in a straight line unless the thruster is engaged. Much like the original "Asteroids" game.
Posts: 544
Threads: 15
Joined: Oct 2016
So you want it more like this.
class Ship(Sprite):
def __init__(self, image, position, anchor="center"):
self.image = image
self.original_image = image
self.rect = image.get_rect(**{anchor: position})
self.position = pygame.Vector2(self.rect.center)
self.start_position = pygame.Vector2(position)
self.angle_change = False
self.angle = 180
self.speed = 0
self.max_speed = 0.1
self.thrust = 0.00005
self.rotate_speed = 0.06
self.friction = 0.999
self.drift = 0.01
self.direction = self.calculate_direction()
def calculate_direction(self):
rads = math.radians(self.angle)
return pygame.Vector2(math.sin(rads), math.cos(rads))
def draw(self, surface):
surface.blit(self.image, self.rect)
def movement(self, keys, delta):
if keys[pygame.K_r]:
self.reset()
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
if self.angle_change:
self.angle_change = False
self.direction = self.calculate_direction()
self.speed += self.thrust * delta
if self.speed > self.max_speed:
self.speed = self.max_speed
else:
self.speed = self.speed * self.friction
if -self.drift < self.speed < self.drift:
self.speed = 0
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.angle = (self.angle + self.rotate_speed * delta) % 360
self.update_rotation()
elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.angle = (self.angle - self.rotate_speed * delta) % 360
self.update_rotation()
self.position += self.direction * self.speed * delta
self.rect.center = self.position
def reset(self):
self.angle = 180
self.direction = self.calculate_direction()
self.update_rotation()
self.rect.center = self.start_position
self.position = pygame.Vector2(self.start_position)
self.angle_change = False
self.speed = 0
def update_rotation(self):
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.angle_change = True
99 percent of computer problems exists between chair and keyboard.
Posts: 419
Threads: 34
Joined: May 2019
Dec-15-2019, 05:00 PM
(This post was last modified: Dec-15-2019, 05:01 PM by michael1789.)
I get this error. I suspect that I'm not giving the right argument to "ship = Ship()"
Error: Warning (from warnings module):
File "C:/Users/owner/Desktop/Python3/Projects/Asteroids/Asteroids controles.py", line 64
self.rect.center = self.position
DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
import pygame
import math
pygame.init()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
class Ship(pygame.sprite.Sprite):
def __init__(self, position, anchor="center"):
self.original_image = pygame.Surface((10, 20))
self.original_image.fill((100, 200, 200))
self.image = self.original_image
self.rect = self.image.get_rect(**{anchor: position})
self.position = pygame.Vector2(self.rect.center)
self.start_position = pygame.Vector2(position)
self.angle_change = False
self.angle = 180
self.speed = 0
self.max_speed = 0.1
self.thrust = 0.00005
self.rotate_speed = 0.06
self.friction = 0.999
self.drift = 0.01
self.direction = self.calculate_direction()
def calculate_direction(self):
rads = math.radians(self.angle)
return pygame.Vector2(math.sin(rads), math.cos(rads))
def draw(self, surface):
surface.blit(self.image, self.rect)
def movement(self, keys, delta):
if keys[pygame.K_r]:
self.reset()
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
if self.angle_change:
self.angle_change = False
self.direction = self.calculate_direction()
self.speed += self.thrust * delta
if self.speed > self.max_speed:
self.speed = self.max_speed
else:
self.speed = self.speed * self.friction
if -self.drift < self.speed < self.drift:
self.speed = 0
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.angle = (self.angle + self.rotate_speed * delta) % 360
self.update_rotation()
elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.angle = (self.angle - self.rotate_speed * delta) % 360
self.update_rotation()
self.position += self.direction * self.speed * delta
self.rect.center = self.position
def reset(self):
self.angle = 180
self.direction = self.calculate_direction()
self.update_rotation()
self.rect.center = self.start_position
self.position = pygame.Vector2(self.start_position)
self.angle_change = False
self.speed = 0
def update_rotation(self):
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.angle_change = True
def update(self, keys, delta):
self.movement(keys, delta)
self.draw(window)
ship = Ship((400, 400))
run = True
while run:
delta = clock.tick(60) / 1000.0
keys = pygame.key.get_pressed()
ship.update(keys, delta)
pygame.display.flip()
Posts: 544
Threads: 15
Joined: Oct 2016
Dec-15-2019, 08:45 PM
(This post was last modified: Dec-15-2019, 08:51 PM by Windspar.)
I get no error when I run your code. What yours python and pygame version.
My python version 3.7.3, pygame version 1.9.6.
All my math is base on delta not being divide by 1000.
delta = clock.tick(60) You also going to want to change original surface. To alpha state and copy original image not assign.
self.original_image = pygame.Surface((10, 20), pygame.SRCALPHA)
self.original_image.fill((100, 200, 200))
self.image = self.original_image.copy()
Could try: On line 65.
self.rect.center = tuple(map(int, self.position))
99 percent of computer problems exists between chair and keyboard.
Posts: 419
Threads: 34
Joined: May 2019
I did all your changes and it runs, but nothing happens and game window freezes. It keeps running even after the window freezes, but I don't think it's taking input.
import pygame
import math
pygame.init()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
black = (0, 0, 0)
class Ship(pygame.sprite.Sprite):
def __init__(self, position, anchor="center"):
self.original_image = pygame.Surface((10, 20), pygame.SRCALPHA)
self.original_image.fill((100, 200, 200))
self.original_image.set_colorkey(black)
self.image = self.original_image.copy()
self.rect = self.image.get_rect(**{anchor: position})
self.position = pygame.Vector2(self.rect.center)
self.start_position = pygame.Vector2(position)
self.angle_change = False
self.angle = 180
self.speed = 0
self.max_speed = 0.1
self.thrust = 0.00005
self.rotate_speed = 0.06
self.friction = 0.999
self.drift = 0.01
self.direction = self.calculate_direction()
def calculate_direction(self):
rads = math.radians(self.angle)
return pygame.Vector2(math.sin(rads), math.cos(rads))
def draw(self, surface):
surface.blit(self.image, self.rect)
def movement(self, keys, delta):
if keys[pygame.K_r]:
self.reset()
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
if self.angle_change:
self.angle_change = False
self.direction = self.calculate_direction()
self.speed += self.thrust * delta
if self.speed > self.max_speed:
self.speed = self.max_speed
else:
self.speed = self.speed * self.friction
if -self.drift < self.speed < self.drift:
self.speed = 0
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.angle = (self.angle + self.rotate_speed * delta) % 360
self.update_rotation()
elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.angle = (self.angle - self.rotate_speed * delta) % 360
self.update_rotation()
self.position += self.direction * self.speed * delta
self.rect.center = tuple(map(int, self.position))
def reset(self):
self.angle = 180
self.direction = self.calculate_direction()
self.update_rotation()
self.rect.center = self.start_position
self.position = pygame.Vector2(self.start_position)
self.angle_change = False
self.speed = 0
def update_rotation(self):
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.angle_change = True
def update(self, keys, delta):
self.movement(keys, delta)
self.draw(window)
ship = Ship((400, 400))
run = True
while run:
delta = clock.tick(60)
keys = pygame.key.get_pressed()
ship.update(keys, delta)
pygame.display.flip()
Posts: 544
Threads: 15
Joined: Oct 2016
I added event loop when I tested it.
import pygame
import math
pygame.init()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
class Ship(pygame.sprite.Sprite):
def __init__(self, position, anchor="center"):
self.original_image = pygame.Surface((10, 20), pygame.SRCALPHA)
self.original_image.fill((100, 200, 200))
self.image = self.original_image.copy()
self.rect = self.image.get_rect(**{anchor: position})
self.position = pygame.Vector2(self.rect.center)
self.start_position = pygame.Vector2(position)
self.angle_change = False
self.angle = 180
self.speed = 0
self.max_speed = 0.1
self.thrust = 0.00005
self.rotate_speed = 0.06
self.friction = 0.999
self.drift = 0.01
self.direction = self.calculate_direction()
def calculate_direction(self):
rads = math.radians(self.angle)
return pygame.Vector2(math.sin(rads), math.cos(rads))
def draw(self, surface):
surface.blit(self.image, self.rect)
def movement(self, keys, delta):
if keys[pygame.K_r]:
self.reset()
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
if self.angle_change:
self.angle_change = False
self.direction = self.calculate_direction()
self.speed += self.thrust * delta
if self.speed > self.max_speed:
self.speed = self.max_speed
else:
self.speed = self.speed * self.friction
if -self.drift < self.speed < self.drift:
self.speed = 0
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.angle = (self.angle + self.rotate_speed * delta) % 360
self.update_rotation()
elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.angle = (self.angle - self.rotate_speed * delta) % 360
self.update_rotation()
self.position += self.direction * self.speed * delta
self.rect.center = self.position
def reset(self):
self.angle = 180
self.direction = self.calculate_direction()
self.update_rotation()
self.rect.center = self.start_position
self.position = pygame.Vector2(self.start_position)
self.angle_change = False
self.speed = 0
def update_rotation(self):
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.angle_change = True
def update(self, keys, delta):
self.movement(keys, delta)
self.draw(window)
ship = Ship((400, 400))
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
delta = clock.tick(60)
keys = pygame.key.get_pressed()
window.fill(pygame.Color('black'))
ship.update(keys, delta)
pygame.display.flip()
99 percent of computer problems exists between chair and keyboard.
Posts: 419
Threads: 34
Joined: May 2019
It runs well, but something is wonky with the speed. If you thrust and then you rotate 180 deg and thrust again your speed stays the same but your direction is reversed. I think it applies your current speed to the direction you are facing, even if it's directly opposite to your previous thrust. There is no way to do a "reverse burn" in order to slow or stop.
Posts: 544
Threads: 15
Joined: Oct 2016
You should always handle events. If you ignore it. The queue will fill up.
You also need to call events.get, events.poll, or event.pump to update pygame.key.get_pressed.
99 percent of computer problems exists between chair and keyboard.
|