In my program, when the keys are pressed, the image of the ship is flipped. I decided to bind the direction of the bullets to the flags of the ship's position. But I ran into the problem that all bullets take the direction of the ship when they are already fired. I need to keep the coordinate of the sprite when it is drawn.
import sys
import pygame
from settings import Settings
from rocket import Rocket
from bullet import Bullet
class Cosmos:
"""Главный класс игры Cosmos"""
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
pygame.display.set_caption('Cosmos')
self.fon_image = pygame.image.load('image/Fon.png')
self.fon = self.fon_image.get_rect()
self.settings = Settings()
self.rocket = Rocket(self.screen, self.settings)
self.bullets = pygame.sprite.Group()
def key_event(self):
"""Обрабатывает нажатие клавиш"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
elif event.key == pygame.K_d:
self.rocket.move_RIGHT = True
elif event.key == pygame.K_a:
self.rocket.move_LEFT = True
elif event.key == pygame.K_w:
self.rocket.move_UP = True
elif event.key == pygame.K_s:
self.rocket.move_DOWN = True
elif event.key == pygame.K_SPACE:
self.fire_bullet()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
self.rocket.move_RIGHT = False
elif event.key == pygame.K_a:
self.rocket.move_LEFT = False
elif event.key == pygame.K_w:
self.rocket.move_UP = False
elif event.key == pygame.K_s:
self.rocket.move_DOWN = False
def fire_bullet(self):
"""Создание нового снаряда и включение его в группу"""
new_bullet = Bullet(self.screen, self.settings, self.rocket)
self.bullets.add(new_bullet)
def run_game(self):
"""Обновляет события игры"""
while True:
self.screen.blit(self.fon_image, self.fon)
self.key_event()
self.rocket.update_rocket()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.bullets.update(bullet)
self.rocket.draw_rocket()
pygame.display.flip()
game = Cosmos()
game.run_game()
from pygame.sprite import Sprite
class Bullet(Sprite):
"""Класс для управления снарядами, выпущенными кораблем"""
def __init__(self, screen, settings, rocket):
super().__init__()
self.screen = screen
self.settings = settings
self.rocket = rocket
self.color = self.settings.bullets_color
self.rect = pygame.Rect(0, 0, self.settings.bullets_width, self.settings.bullets_height)
self.rect.midtop = rocket.rect.midtop
self.y = float(self.rect.y)
self.x = float(self.rect.x)
def update(self, bullet):
"""Перемещение снаряда"""
if self.rocket.image == self.rocket.image_right:
bullet.x += 2
if self.rocket.image == self.rocket.image_left:
bullet.x -= 2
if self.rocket.image == self.rocket.image_up:
bullet.y -= 2
if self.rocket.image == self.rocket.image_down:
bullet.y += 2
self.rect.x = self.x
self.rect.y = self.y
def draw_bullet(self):
"""Рисует снаряд"""
pygame.draw.rect(self.screen, self.color, self.rect)
import pygame
class Rocket:
"""Класс для управления кораблём"""
def __init__(self, screen, settings):
self.screen = screen
self.screen_rect = screen.get_rect()
self.settings = settings
self.image = pygame.image.load('image/pixil-frame-0.png')
self.rect = self.image.get_rect()
self.rect.center = self.screen_rect.center
self.x = float(self.rect.x)
self.y = float(self.rect.y)
self.move_RIGHT = False
self.move_LEFT = False
self.move_UP = False
self.move_DOWN = False
self.image_right = pygame.transform.rotate(self.image, -90)
self.image_left = pygame.transform.rotate(self.image, 90)
self.image_up = pygame.transform.rotate(self.image, 0)
self.image_down = pygame.transform.rotate(self.image, 180)
def update_rocket(self):
"""Флаги управления кораблём"""
if self.move_RIGHT and self.rect.right < self.screen_rect.right:
self.image = self.image_right
self.x += self.settings.rocket_speed
if self.move_LEFT and self.rect.left > self.screen_rect.left:
self.image = self.image_left
self.x -= self.settings.rocket_speed
if self.move_UP and self.rect.top > self.screen_rect.top:
self.image = self.image_up
self.y -= self.settings.rocket_speed
if self.move_DOWN and self.rect.bottom < self.screen_rect.bottom:
self.image = self.image_down
self.y += self.settings.rocket_speed
self.rect.x = self.x
self.rect.y = self.y
def draw_rocket(self):
"""Обновляет позицию корабля"""
self.screen.blit(self.image, self.rect)
The problem here is that in Bullet.update, you use the current image of the rocket to determine in which direction the bullet is going. This means that any change of this image results in a change of direction. Instead of doing this, you should save the current direction upon creating a new Bullet instance and then use this saved direction to determine the direction of the rocket.
A possible implementation:
class Bullet(Sprite):
"""Класс для управления снарядами, выпущенными кораблем"""
def __init__(self, screen, settings, rocket):
super().__init__()
self.screen = screen
self.settings = settings
self.rocket = rocket
self.color = self.settings.bullets_color
self.rect = pygame.Rect(0, 0, self.settings.bullets_width, self.settings.bullets_height)
self.rect.midtop = rocket.rect.midtop
self.y = float(self.rect.y)
self.x = float(self.rect.x)
if self.rocket.image == self.rocket.image_right:
self.direction = "right"
elif self.rocket.image == self.rocket.image_left:
self.direction = "left"
elif self.rocket.image == self.rocket.image_up:
self.direction = "up"
elif self.rocket.image == self.rocket.image_down:
self.direction = "down"
def update(self, bullet):
"""Перемещение снаряда"""
if self.direction == "right":
bullet.x += 2
if self.direction == "left":
bullet.x -= 2
if self.direction == "up":
bullet.y -= 2
if self.direction == "down":
bullet.y += 2
self.rect.x = self.x
self.rect.y = self.y
def draw_bullet(self):
"""Рисует снаряд"""
pygame.draw.rect(self.screen, self.color, self.rect)
Related
This question already has answers here:
how to make image/images disappear in pygame?
(1 answer)
How do I delete rect object from screen once player collides with it?
(1 answer)
Closed 23 days ago.
I am new at using objects in python and brand new at Pygame. I am trying to make a game where a player moves around the screen eating objects. However, I am unable to get the consumed objects to disappear, the moving object is smudging and not transparent. The Downward and Rightward movement keys also produce no result.
This is the code for the movement:
def move(self):
if self.dir != '':
if self.dir == 'd' and self.rect.bottom < self.height:
self.rect.top += self.speed
if self.dir == 'u' and self.rect.top > 0:
self.rect.top -= self.speed
if self.dir == 'l' and self.rect.left > 0:
self.rect.left -= self.speed
if self.dir == 'r' and self.rect.right < self.width:
self.rect.right += self.speed
the code for image transparency:
self.surface = pygame.image.load("images/player.png").convert_alpha()
This is how I am drawing the player and the consumable:
def draw(self):
self.screen.blit(self.surface, self.rect)
and the main update code that is inside the game loop:
def update(self):
for f in self.foods[:]:
if self.player.rect.colliderect(f.rect):
self.foods.remove(f)
self.foods.append(Consumable(
self.screen, WIDTH*random.randint(1, 9)//10, HEIGHT*random.randint(1, 9)//10))
self.eaten += 1
for f in self.foods:
f.draw()
if self.eaten == 10:
self.won = True
self.player.move()
self.player.draw()
pygame.display.update()
pygame.display.flip()
This is the full game code:
import pygame
import random
import time
from pygame.locals import *
pwidth = 250
pheight = 250
class Consumable(pygame.sprite.Sprite):
def __init__(self, screen, centerx, centery):
super(Consumable, self).__init__()
self.surface = pygame.image.load("images/food.jpeg")
self.rect = self.surface.get_rect()
self.rect.centerx = centerx
self.rect.centery = centery
self.screen = screen
def draw(self):
self.screen.blit(self.surface, self.rect)
class player(pygame.sprite.Sprite):
def __init__(self, screen, centerx, centery):
super(player, self).__init__()
self.surface = pygame.image.load("images/player.png").convert_alpha()
self.screen = screen
self.speed = 10
self.dir = ''
self.rect = self.surface.get_rect()
self.rect.centerx = centerx
self.rect.centery = centery
self.width = self.rect.width
self.height = self.rect.height
def draw(self):
self.screen.blit(self.surface, self.rect)
def move(self):
if self.dir != '':
if self.dir == 'd' and self.rect.bottom < self.height:
self.rect.top += self.speed
if self.dir == 'u' and self.rect.top > 0:
self.rect.top -= self.speed
if self.dir == 'l' and self.rect.left > 0:
self.rect.left -= self.speed
if self.dir == 'r' and self.rect.right < self.width:
self.rect.right += self.speed
class Game:
def __init__(self, screen):
self.screen = screen
self.screen.fill((0, 0, 0))
self.icon = pygame.image.load("images/icon.jpeg")
pygame.display.set_icon(self.icon)
self.foods = []
self.eaten = 0
for i in range(4):
self.foods.append(Borgar(
self.screen, WIDTH*random.randint(1, 9)//10, HEIGHT*random.randint(1, 9)//10))
for f in self.foods:
f.draw()
self.player = player(screen, WIDTH//2, HEIGHT//2)
self.mainclock = pygame.time.Clock()
self.start_time = time.perf_counter()
self.end_time = -1
self.won = False
def update(self):
pickedUp = False
for f in self.foods[:]:
if self.player.rect.colliderect(f.rect):
self.foods.remove(f)
self.foods.append(Borgar(
self.screen, WIDTH*random.randint(1, 9)//10, HEIGHT*random.randint(1, 9)//10))
pickedUp = True
self.eaten += 1
print(self.eaten)
for f in self.foods:
f.draw()
if self.eaten == 10:
self.won = True
self.end_time = time.perf_counter()
print("You won")
print("time taken: {:.2f}".format(self.end_time-self.start_time))
self.player.move()
self.player.draw()
pygame.display.update()
pygame.display.flip()
def _handle_events(self):
for event in pygame.event.get():
if event.type == QUIT:
raise SystemExit
if event.type == KEYDOWN:
if event.key == K_BACKSPACE or event.key == K_ESCAPE or event.key == ord('q'):
raise SystemExit
if event.key == K_LEFT or event.key == ord('a'):
self.player.dir = 'l'
if event.key == K_RIGHT or event.key == ord('d'):
self.player.dir = 'r'
if event.key == K_UP or event.key == ord('w'):
self.player.dir = 'u'
if event.key == K_DOWN or event.key == ord('s'):
self.player.dir = 'd'
if event.type == KEYUP:
# End repetition.
if event.key == K_LEFT or event.key == ord('a'):
self.player.dir = ''
if event.key == K_RIGHT or event.key == ord('d'):
self.player.dir = ''
if event.key == K_UP or event.key == ord('w'):
self.player.dir = ''
if event.key == K_DOWN or event.key == ord('s'):
self.player.dir = ''
def run(self):
while True:
self.mainclock.tick(60)
self._handle_events()
self.update()
if self.won:
raise SystemExit
pygame.display.flip()
pygame.init()
display = pygame.display.set_mode((800, 600), pygame.RESIZABLE)
WIDTH, HEIGHT = pygame.display.get_window_size()
pygame.display.set_caption("Game")
game = Game(display)
game.run()
Here is what happens when I run the game:
game screenshot
I would really appreciate any help possible.
So, I'm a beginner to Python and Pygame and would like some help. I'm trying to make a game similar to Asteroids and I've made most of this program by looking around at other examples on the internet. However, I'm stuck on this problem: how do I get an enemy sprite to follow the player sprite? I've googled how to do so and tried implementing the same thing on my code but the sprite just stays in one place and doesn't follow the player. I've used the vector stuff to create the player sprite and I still barely understand how that works. I'm sort of on a tight schedule so I don't have time to thoroughly understand this stuff but I intend to later. Sorry if I haven't explained my code properly but I'm still trying to understand how Pygame works and most of this code is basically just copied.
import random, math, pygame, time, sys
from pygame.locals import *
from pygame.math import Vector2
######Setting up Variables
class settings:
fps = 30
windowwidth = 590
windowheight = 332
class ship:
HEALTH = 3
SPEED = 4
SIZE = 25
class colours:
black = (0, 0, 0)
white = (255, 255, 255)
###########################
######################################################################################
class Player(pygame.sprite.Sprite):
def __init__(self,image_file , pos=(0,0)):
super(Player, self).__init__()
self.image = pygame.image.load(image_file)
self.image = pygame.transform.scale(self.image, (25,25))
self.original_image = self.image
self.rect = self.image.get_rect(center=pos)
self.position = Vector2(pos)
self.direction = Vector2(1, 0)
self.speed = 0
self.angle_speed = 0
self.angle = 0
def update(self):
if self.angle_speed != 0:
self.direction.rotate_ip(self.angle_speed)
self.angle += self.angle_speed
self.image = pygame.transform.rotate(self.original_image, -self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.position += self.direction * self.speed
self.rect.center = self.position
class Enemy(pygame.sprite.Sprite):
def __init__(self, image_file, pos=(0,0)):
super(Enemy, self).__init__()
self.image = pygame.image.load(image_file)
self.image = pygame.transform.scale(self.image, (25, 25))
self.original_image = self.image
self.rect = self.image.get_rect(center=pos)
self.speed = 1
def move_towards_player(self, Player):
dx, dy = self.rect.x - Player.rect.x, self.rect.y - Player.rect.y
dist = math.hypot(dx, dy)
dx, dy = dx/dist, dy/dist
self.rect.x += dx * self.speed
self.rect.y += dy * self.speed
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
def main():
pygame.init()
screen = pygame.display.set_mode((settings.windowwidth, settings.windowheight))
pygame.display.set_caption('Final Game')
background = Background('space.jpg',[0,0])
global player, enemy
player = Player('SpaceShip.png',[200,100])
playersprite = pygame.sprite.RenderPlain((player))
enemy = Enemy('Enemy Hexagon.png',[300,150])
enemysprite = pygame.sprite.RenderPlain((enemy))
fpsClock = pygame.time.Clock()
intro = True
while intro == True:
myFont = pygame.font.SysFont('freesansbold.ttf', 75)
otherFont = pygame.font.SysFont('freesansbold.ttf', 30)
SurfaceFont = myFont.render("Space Destroyer", True, (colours.white))
SurfaceFont2 = otherFont.render("Press Space to Start", True, (colours.white))
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_SPACE:
intro= False
screen.blit(SurfaceFont,(50,50))
screen.blit(SurfaceFont2,(125,125))
pygame.display.flip()
screen.blit(background.image, background.rect)
while intro == False:
fpsClock.tick(settings.fps)
for event in pygame.event.get():
enemy.rect.x
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_UP:
player.speed += 4
if event.key == K_LEFT:
player.angle_speed = -4
if event.key == K_RIGHT:
player.angle_speed = 4
if player.position.y < 0:
player.position = (player.position.x ,332)
elif player.position.y > settings.windowheight:
player.position = (player.position.x, 0)
elif player.position.x < 0:
player.position = (590, player.position.y)
elif player.position.x > settings.windowwidth:
player.position = (0, player.position.y)
elif event.type == KEYUP:
if event.key == K_LEFT:
player.angle_speed = 0
if event.key == K_RIGHT:
player.angle_speed = 0
if event.key == K_UP:
player.speed = 0
screen.fill(colours.white)
screen.blit(background.image, background.rect)
enemysprite.draw(screen)
enemysprite.update()
playersprite.draw(screen)
playersprite.update()
pygame.display.update()
playersprite.update()
pygame.display.flip()
if __name__ == '__main__': main()
You never called move_towards_player. Try adding this:
...
enemysprite.draw(screen)
enemysprite.update()
playersprite.draw(screen)
playersprite.update()
enemy.move_towards_player(player)
...
lately I've been working on a little project of mine.
I have a background in which I spawn alot of cars.
I want to have those cars move along a path i define myself. I've gotten to the point where one of my cars moves to the (0,0) position when i call my move method, also, I'm not sure how to have a smooth animation along the path, I don't want the car to suddenly appear at the last waypoint define instantly.
Here is my code:
import assets
import pygame
##this class spawns
class bus(pygame.sprite.Sprite):
def __init__(self):
super(bus,self).__init__()
self.image = pygame.Surface((assets.bus_width,assets.bus_height))
self.rect = self.image.get_rect()
def set_position(self,x,y):
self.rect.x = x
self.rect.y = y
def set_image(self, filename = None):
if filename != None:
self.image = pygame.image.load(filename).convert()
self.rect = self.image.get_rect()
def rotate(self,angle):
self.image = pygame.transform.rotate(self.image,angle)
self.rect = self.image.get_rect()
class car(pygame.sprite.Sprite):
def __init__(self):
super(car,self).__init__()
self.image = pygame.Surface((assets.car_width,assets.car_height))
self.rect = self.image.get_rect()
self.speed = 2
def set_position(self,x,y):
self.rect.x = x
self.rect.y = y
def get_x_position(self):
return self.rect.x
def get_y_position(self):
return self.rect.y
def set_image(self, filename = None):
if filename != None:
self.image = pygame.image.load(filename).convert()
self.rect = self.image.get_rect()
def rotate(self,angle):
self.image = pygame.transform.rotate(self.image,angle)
self.rect = self.image.get_rect()
#not sure what to do here
def move_position(self,x,y):
self.rect.x +=
self.rect.y +=
self.rect = self.image.get_rect()
class WayPoint:
def __init__(self, x, y):
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
class WayPointsList:
def __init__(self):
self.wayPoints = []
def add_wayPoint(self, x, y):
self.wayPoints.append(WayPoint(x,y))
def __len__(self):
return len(self.wayPoints)
def get_wayPoint(self, i):
return [self.wayPoints[i].getX(), self.wayPoints[i].getY()]
if __name__ == '__main__':
pygame.init()
window_size = window_width, window_height = assets.screen_width, assets.screen_height
window = pygame.display.set_mode(window_size, pygame.RESIZABLE)
pygame.display.set_caption(assets.caption)
window.fill(assets.white)
clock = pygame.time.Clock()
car_group = pygame.sprite.Group()
#mainloop
running = True
while running:
#loading background
bkg = pygame.image.load(assets.background)
#event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
car110 = car()
car110.set_image(assets.furore)
car110.rotate(180)
car110.set_position(0,273)
car_group.add(car110)
elif event.key == pygame.K_2:
car109 = car()
car109.set_image(assets.hachura)
car109.rotate(180)
car109.set_position(0,306)
car_group.add(car109)
#i want to move this car along some waypoints I've defined in my head
#like so:
#lane = WayPointsList()
#lane.add_wayPoint(50, 250)
#lane.add_wayPoint(250, 350)
#after this i want to move my image along these waypoints I've defined
elif event.key == pygame.K_3:
car108=car()
car108.set_image(assets.jefferson)
car108.rotate(180)
car108.set_position(0,343)
car_group.add(car108)
elif event.key == pygame.K_4:
car107=car()
car107.set_image(assets.michelli)
car107.rotate(270)
car107.set_position(410,550)
car_group.add(car107)
elif event.key == pygame.K_5:
car106=car()
car106.set_image(assets.traceAM)
car106.rotate(270)
car106.set_position(460,550)
car_group.add(car106)
elif event.key == pygame.K_6:
car105=car()
car105.set_image(assets.traceAM)
car105.set_position(750,300)
car_group.add(car105)
elif event.key == pygame.K_7:
car104=car()
car104.set_image(assets.rumbler)
car104.set_position(750,265)
car_group.add(car104)
elif event.key == pygame.K_8:
car103=car()
car103.set_image(assets.rumbler)
car103.rotate(90)
car103.set_position(294,0)
car_group.add(car103)
elif event.key == pygame.K_9:
car102=car()
car102.set_image(assets.rumbler)
car102.rotate(90)
car102.set_position(337,0)
car_group.add(car102)
elif event.key == pygame.K_0:
car101=car()
car101.set_image(assets.rumbler)
car101.rotate(90)
car101.set_position(380,0)
car_group.add(car101)
elif event.key == pygame.K_b:
car201=bus()
car201.set_image(assets.bus)
car201.set_position(700,229)
car_group.add(car201)
elif event.key ==pygame.K_x:
car_group.remove(car101,car102,car103,car104,car105,car106,car107,car108,car109,car110,car201)
car_group.update()
window.fill(assets.white)
window.blit(bkg,(0,0))
car_group.draw(window)
clock.tick(assets.FPS)
pygame.display.update()
pygame.quit()
If anyone could give me some pointers or tell me what I can do to fix it, I would really appreciate it!
In move_position don't use
self.rect = self.image.get_rect()
because image doesn't keep position and it has always (x,y) == (0,0)
In class create update() and run move_position() inside update() and car_group.update() will execute it in every loop.
I save angle in self.angle so I can use it to move in correct direction
radians_angle = math.radians(self.angle)
self.rect.x -= self.speed * math.cos(radians_angle)
self.rect.y -= self.speed * math.sin(radians_angle)
Example works without images so everyone can run it.
import pygame
import math
WHITE = (0,0,0)
##this class spawns
class bus(pygame.sprite.Sprite):
def __init__(self):
super(bus,self).__init__()
self.image = pygame.Surface((800, 600)).convert_alpha()
self.rect = self.image.get_rect()
self.angle = 0 # <-- default direction
def set_position(self,x,y):
self.rect.x = x
self.rect.y = y
def set_image(self, filename = None):
if filename != None:
self.image = pygame.Surface((20, 20)).convert_alpha()
self.image.fill((255,0,0))
self.rect = self.image.get_rect()
def rotate(self,angle):
self.angle = angle # <-- keep it to move it in correct direction
self.image = pygame.transform.rotate(self.image,angle).convert_alpha() # need alpha to correctly rotate
self.rect = self.image.get_rect()
class car(pygame.sprite.Sprite):
def __init__(self):
super(car,self).__init__()
self.image = pygame.Surface((20,20)).convert_alpha()
self.image.fill((255,0,0))
self.rect = self.image.get_rect()
self.speed = 2
self.angle = 0 # <-- default direction
def set_position(self,x,y):
self.rect.x = x
self.rect.y = y
def get_x_position(self):
return self.rect.x
def get_y_position(self):
return self.rect.y
def set_image(self, filename = None):
if filename != None:
self.image = pygame.Surface((20, 20)).convert_alpha() # need alpha to correctly rotate
self.image.fill((0,255,0))
self.rect = self.image.get_rect()
def rotate(self,angle):
self.angle = angle # <-- keep it to move it in correct direction
self.image = pygame.transform.rotate(self.image, angle).convert_alpha() # need alpha to correctly rotate
self.rect = self.image.get_rect()
#not sure what to do here
def move_position(self,x,y):
# use angle to calculate direction
radius_angle = math.radians(self.angle)
self.rect.x -= self.speed * math.cos(radius_angle)
self.rect.y -= self.speed * math.sin(radius_angle)
#print('move', self.angle, self.rect.x, self.rect.y)
#self.rect = self.image.get_rect() # <-- DON'T DO THIS
def update(self):
self.move_position(0,0)
class WayPoint:
def __init__(self, x, y):
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
class WayPointsList:
def __init__(self):
self.wayPoints = []
def add_wayPoint(self, x, y):
self.wayPoints.append(WayPoint(x,y))
def __len__(self):
return len(self.wayPoints)
def get_wayPoint(self, i):
return [self.wayPoints[i].getX(), self.wayPoints[i].getY()]
if __name__ == '__main__':
pygame.init()
window_size = window_width, window_height = 800, 600
window = pygame.display.set_mode(window_size, pygame.RESIZABLE)
window.fill(WHITE)
clock = pygame.time.Clock()
car_group = pygame.sprite.Group()
#mainloop
running = True
while running:
#loading background
bkg = pygame.Surface((800,600)).convert()
bkg.fill((0,0,255))
#event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
car110 = car()
#car110.set_image(assets.furore)
car110.rotate(180-45)
car110.set_position(0,273)
car_group.add(car110)
elif event.key == pygame.K_2:
car109 = car()
#car109.set_image(assets.hachura)
car109.rotate(180)
car109.set_position(0,306)
car_group.add(car109)
#i want to move this car along some waypoints I've defined in my head
#like so:
#lane = WayPointsList()
#lane.add_wayPoint(50, 250)
#lane.add_wayPoint(250, 350)
#after this i want to move my image along these waypoints I've defined
elif event.key == pygame.K_3:
car108=car()
#car108.set_image(assets.jefferson)
car108.rotate(180)
car108.set_position(0,343)
car_group.add(car108)
elif event.key == pygame.K_4:
car107=car()
#car107.set_image(assets.michelli)
car107.rotate(270)
car107.set_position(410,550)
car_group.add(car107)
elif event.key == pygame.K_5:
car106=car()
#car106.set_image(assets.traceAM)
car106.rotate(270)
car106.set_position(460,550)
car_group.add(car106)
elif event.key == pygame.K_6:
car105=car()
#car105.set_image(assets.traceAM)
car105.set_position(750,300)
car_group.add(car105)
elif event.key == pygame.K_7:
car104=car()
#car104.set_image(assets.rumbler)
car104.set_position(750,265)
car_group.add(car104)
elif event.key == pygame.K_8:
car103=car()
#car103.set_image(assets.rumbler)
car103.rotate(90)
car103.set_position(294,0)
car_group.add(car103)
elif event.key == pygame.K_9:
car102=car()
#car102.set_image(assets.rumbler)
car102.rotate(90)
car102.set_position(337,0)
car_group.add(car102)
elif event.key == pygame.K_0:
car101=car()
#car101.set_image(assets.rumbler)
car101.rotate(90)
car101.set_position(380,0)
car_group.add(car101)
elif event.key == pygame.K_b:
car201=bus()
#car201.set_image(assets.bus)
car201.set_position(700,229)
car_group.add(car201)
elif event.key ==pygame.K_x:
car_group.remove(car101,car102,car103,car104,car105,car106,car107,car108,car109,car110,car201)
car_group.update()
window.fill(WHITE)
window.blit(bkg,(0,0))
car_group.draw(window)
clock.tick(25)
pygame.display.update()
pygame.quit()
In pygame I have a projectile being shot from one character sprite to another which I would like to determine whether there is a collision or not. That is a collision between a shot projectile and another character I will call TRUMP. I have found an equation in a tutorial that is the best example of an arching trajectory that I can accomplish. If that equation could be helped it would be awesome.
def fireshell(self, elapsedTime):
fire = True
FPS = 60 # frames per second setting
fpsClock = pg.time.Clock()
print("fire", self.pos.x, self.pos.y)
fireX = int(self.pos.x)
fireY = int(self.pos.y)
print("fireX", fireX, "fireY", fireY, "elapsed time", elapsedTime)
power = elapsedTime*.0005
x = int(self.pos.x)
y = int(self.pos.y) - 100
while fire:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
pg.draw.circle(self.screen, RED, (x, y), 5)
x -= int(-(elapsedTime*6))
y += int((((x - fireX)*0.015)**2) - ((elapsedTime*2)/(12 - elapsedTime )))
print("X:", x,"Y:", y)
if y > HEIGHT or x > WIDTH:
fire = False
pg.display.update()
self.clock.tick(20)
My character sprite who I would like to check for collisions with the projectile is here:
class TRUMP(pg.sprite.Sprite):
def __init__(self, spritesheet, all_sprites, mudballGroup, jetsGroup):
pg.sprite.Sprite.__init__(self)
self.spritesheet = spritesheet
self.all_sprites = all_sprites
self.mudballGroup = mudballGroup
self.jetsGroup = jetsGroup
self.current_frame2 = 0
self.last_update2 = 0
self.load_images()
self.image = self.TRUMP_fingers_l
self.rect = self.image.get_rect()
self.rect.center = (WIDTH *3/4), (589)
self.rect.centerx = (WIDTH *3/4)
self.rect.centery = 589
self.rect.centerx = (WIDTH*5/6)
self.rect.centery = 589
self.pos = vec((WIDTH/2), (HEIGHT/2))
self.vel = vec(0, 0)
self.acc = vec(0, 0)
self.dir = 0
To get a ballistic trajectory, you can just add a GRAVITY constant to the y-value of the velocity vector each frame.
For the collision detection you can use pygame.sprite.spritecollide again (you already know how that works).
Here's a complete example:
import sys
import pygame as pg
GRAVITY = 3
class Player(pg.sprite.Sprite):
def __init__(self, pos, color):
super().__init__()
self.image = pg.Surface((50, 30))
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
self.pos = pg.math.Vector2(pos)
self.vel = pg.math.Vector2()
def update(self):
self.pos += self.vel
self.rect.center = self.pos
class Projectile(pg.sprite.Sprite):
def __init__(self, pos, color, target):
super().__init__()
self.image = pg.Surface((7, 5))
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
self.pos = pg.math.Vector2(pos)
direction = target - self.pos # Vector to the target.
# Normalize, then scale direction to adjust the speed.
self.vel = direction.normalize() * 33
def update(self):
self.pos += self.vel
self.vel.y += GRAVITY
self.rect.center = self.pos
if self.rect.y > 580:
self.kill()
class Game:
def __init__(self):
self.fps = 30
self.screen = pg.display.set_mode((800, 600))
pg.display.set_caption('Ballistic trajectory')
self.clock = pg.time.Clock()
self.bg_color = pg.Color(90, 120, 100)
self.green = pg.Color('aquamarine2')
self.blue = pg.Color(30, 90, 150)
self.font = pg.font.Font(None, 30)
self.player = Player((100, 300), self.green)
self.player2 = Player((400, 300), self.blue)
self.all_sprites = pg.sprite.Group(self.player, self.player2)
self.projectiles = pg.sprite.Group()
self.collisions = 0
self.done = False
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(self.fps)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
proj = Projectile(
self.player.rect.center, pg.Color('sienna2'), event.pos)
self.projectiles.add(proj)
self.all_sprites.add(proj)
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
self.player.vel.x = -3
if event.key == pg.K_d:
self.player.vel.x = 3
if event.key == pg.K_w:
self.player.vel.y = -3
if event.key == pg.K_s:
self.player.vel.y = 3
if event.type == pg.KEYUP:
if event.key == pg.K_a and self.player.vel.x == -3:
self.player.vel.x = 0
if event.key == pg.K_d and self.player.vel.x == 3:
self.player.vel.x = 0
if event.key == pg.K_w and self.player.vel.y == -3:
self.player.vel.y = 0
if event.key == pg.K_s and self.player.vel.y == 3:
self.player.vel.y = 0
def run_logic(self):
self.all_sprites.update()
hits = pg.sprite.spritecollide(self.player2, self.projectiles, True)
for collided_sprite in hits:
self.collisions += 1
def draw(self):
self.screen.fill(self.bg_color)
self.all_sprites.draw(self.screen)
txt = self.font.render('Collisions {}'.format(self.collisions), True, self.green)
self.screen.blit(txt, (20, 20))
pg.display.flip()
if __name__ == '__main__':
pg.init()
game = Game()
game.run()
pg.quit()
sys.exit()
Hello I am currently making a survival shooter but cannot find any way on how to do my collisions! I am trying to make the player collide with the floors but with no success. Here is an image of the map (I want to collide with moon blocks):
http://i.stack.imgur.com/R2apz.jpg
Here is an image of moon blocks with no Background:
http://i.stack.imgur.com/W9H2m.png
And finally here is my code:
import pygame
import random
gravity = .5
jump_time = 2000
x = 0
y = 0
# Player
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gravity):
# Player dimensions and position
self.gravity = gravity
# Player image and animation
self.images = []
self.images.append(pygame.image.load('images/player.png'))
self.images.append(pygame.image.load('images/player2.png'))
#~ self.images.append(pygame.image.load('ball1.png'))
#~ self.images.append(pygame.image.load('ball2.png'))
self.maxImage = len(self.images)
self.currentImage = 0
#~ self.rect = pygame.Rect(x, y, 80, 80)
self.rect = self.images[0].get_rect()
self.rect.x = x
self.rect.y = y
self.timeTarget = 10
self.timeNum = 1
self.velX = 0
self.velY = 0
# Jump and gravity
self.vSpeed = 3
self.jumpForce = 15
self.maxVspeed = 3
self.isJumping = False
# Jump inputs
def handle_events(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if not self.isJumping:
self.isJumping = True
elif event.key == pygame.K_a:
self.velX = -5
elif event.key == pygame.K_d:
self.velX = +5
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.velX = 0
# PLayer updates
def update(self, ground):
keys = pygame.key.get_pressed()
# Jumping
self.vSpeed += gravity
if self.vSpeed > self.maxVspeed:
self.vSpeed = self.maxVspeed
self.rect.y += self.vSpeed
if self.rect.y >= ground.y:
self.vSpeed = 0
self.rect.y = ground.y
self.isJumping = False
if keys[pygame.K_SPACE]:
if not self.isJumping:
self.isJumping = True
if self.isJumping:
if pygame.time.get_ticks() < jump_time:
self.isJumping == True
else:
self.isJumping = False
self.vSpeed -= self.jumpForce
#print "isJumping:", self.isJumping
# Animations
if self.timeNum == self.timeTarget:
self.currentImage += 1
if self.currentImage >= self.maxImage:
self.currentImage = 0
self.timeNum = 0
self.rect.centerx += self.velX
self.rect.centery += self.velY
# Screen wrap
if self.rect.right > 1280:
self.rect.left = 0
elif self.rect.left < 0:
self.rect.right = 1280
# Player rendering
def render(self, surface):
surface.blit(self.images[self.currentImage], self.rect)
#----------------------------------------------------------------------
class Zombie():
def __init__(self, x, y):
self.image = pygame.image.load('images/zombie.png')
#~ self.image = pygame.image.load('ball2.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.direction_left = True
def update(self, surface_rect):
if self.direction_left:
self.rect.x -= 1
if self.rect.left <= surface_rect.left:
self.direction_left = not self.direction_left
else:
self.rect.x += 1
if self.rect.right >= surface_rect.right:
self.direction_left = not self.direction_left
def render(self, surface):
surface.blit(self.image, self.rect)
#----------------------------------------------------------------------
class Background():
def __init__(self):
self.image = pygame.image.load('images/arena2.jpg')
#~ self.image = pygame.image.load('background.jpg')
self.rect = self.image.get_rect()
def render(self, surface):
surface.blit(self.image, self.rect)
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
# A few variables
self.gravity = .50
self.ground = pygame.Rect(0, 640, 1280, 80)
# Screen
size = (1280, 720)
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Moon Survival!')
# Moon / Background
self.moon = Background()
# Zombies
self.zombies = []
for i in range(10):
self.zombies.append( Zombie(random.randint(0,1280), random.randint(0,720)) )
# Player
self.player = Player(25, 320, self.gravity)
# Font for text
self.font = pygame.font.SysFont(None, 72)
# Pause - center on screen
self.pause_text = self.font.render("PAUSE", -1, (255,0,0))
self.pause_rect = self.pause_text.get_rect(center = self.screen.get_rect().center)
def run(self):
clock = pygame.time.Clock()
# "state machine"
RUNNING = True
PAUSED = False
GAME_OVER = False
# Game loop
while RUNNING:
# (all) Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
elif event.key == pygame.K_p:
PAUSED = not PAUSED
# Player/Zomies events
if not PAUSED and not GAME_OVER:
self.player.handle_events(event)
# (all) Movements / Updates
if not PAUSED and not GAME_OVER:
self.player.update(self.ground)
for z in self.zombies:
z.update(self.screen.get_rect())
# (all) Display updating
self.moon.render(self.screen)
for z in self.zombies:
z.render(self.screen)
self.player.render(self.screen)
if PAUSED:
self.screen.blit(self.pause_text, self.pause_rect)
pygame.display.update()
# FTP
clock.tick(100)
# --- the end ---
pygame.quit()
#---------------------------------------------------------------------
Game().run()
Any help will be greatly appreciated, thank you.
I made a very similar game for PyWeek #17 called "Miner".
Here's a screenshot: http://media.pyweek.org/dl/17/powrtoch/miner_ss.png (you can see the similarity!)
You can find the relevant code on GitHub here: https://github.com/marcusmoller/pyweek17-miner/blob/master/miner/engine.py#L202-L220:
def checkCollision(self, sprite, xVel, yVel):
for x in range(len(level.levelStructure)):
for y in range(len(level.levelStructure[x])):
block = level.levelStructure[x][y]
if block is not None:
if pygame.sprite.collide_rect(sprite, block):
if xVel < 0:
sprite.rect.x = block.rect.x + block.rect.w
if xVel > 0:
sprite.rect.x = block.rect.x - sprite.rect.w
if yVel < 0:
sprite.rect.y = block.rect.y + block.rect.h
if yVel > 0 and not sprite.onGround:
sprite.onGround = True
sprite.rect.y = block.rect.y - sprite.rect.h
You could do something like this using collide_rect:
# See if the Sprite block collides with anything in the Ground block_list
for block in groundBlocks:
if(collide_rect(player, block)):
# do not fall
else:
# fall
where all Block you can walk on are in the groundBlocks list.