[PyGame] Terrible Sprite controls, need help. - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: [PyGame] Terrible Sprite controls, need help. (/thread-23168.html) Pages:
1
2
|
Terrible Sprite controls, need help. - michael1789 - Dec-14-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 RE: Terrible Sprite controls, need help. - Windspar - Dec-14-2019 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() RE: Terrible Sprite controls, need help. - michael1789 - Dec-14-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. RE: Terrible Sprite controls, need help. - Windspar - Dec-14-2019 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 RE: Terrible Sprite controls, need help. - michael1789 - Dec-15-2019 I get this error. I suspect that I'm not giving the right argument to "ship = Ship()"
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() RE: Terrible Sprite controls, need help. - Windspar - Dec-15-2019 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)) RE: Terrible Sprite controls, need help. - michael1789 - Dec-15-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() RE: Terrible Sprite controls, need help. - Windspar - Dec-16-2019 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() RE: Terrible Sprite controls, need help. - michael1789 - Dec-16-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. RE: Terrible Sprite controls, need help. - Windspar - Dec-16-2019 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. |