How do I make a sprite rotate around another moving sprite? - python

I am currently making a game and I want to add a power up. I am essentially trying to make something similar to the spell book from Castlevania. I found a code to help me get the initial position and rotation. The problem is, the cross doesn't move from it's initial location. It just circles in place while the other one leaves it. I am still new to pygame and the math that goes with game dev. It is still pretty confusing.
import pygame
class Crucifix(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.sprite = pygame.image.load('image'). convert_alpha()
self.image = self.sprite
self.rect = self.image.get_rect()
self.rect.x =500
self.rect.y = 500
self.mask = pygame.mask.from_surface(self.image)
def update(self):
self.rect.x -= 2
if self.rect.x == -100:
self.kill()
class EnemiesStrong(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.image.load('image').convert_alpha()
self.image = self.original_image
self.rect = self.image.get_rect()
self.angle = 0
def initLoc(self, pos, radius):
self.pos = pos
self.radius = radius
def update(self):
center = pygame.math.Vector2(self.pos) + pygame.math.Vector2(0, -self.radius).rotate(-self.angle)
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center = (round(center.x), round(center.y)))
def turnLeft(self):
self.angle = (self.angle + 4) % 360
pygame.init()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
cross1= Crucifix()
enemy_s = EnemiesStrong()
pos = cross1.rect.x, cross1.rect.y
enemy_s.initLoc(cross1.rect.center, 100)
all_sprites = pygame.sprite.Group(enemy_s)
all_sprites.add(cross1)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
enemy_s.turnLeft()
all_sprites.update()
window.fill(0)
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
exit()
I am not exactly sure what to try at this point. Any help would be appreciated.

You have to update the position of enemy_s in every frame depending on the position of cross1. Add a updatePos method to the EnemiesStrong class:
class EnemiesStrong(pygame.sprite.Sprite):
# [...]
def updatePos(self, new_pos):
self.pos = new_pos
Call updatePos in the application loop:
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
enemy_s.turnLeft()
enemy_s.updatePos(cross1.rect.center) # <---
all_sprites.update()
window.fill(0)
all_sprites.draw(window)
pygame.display.flip()
Complete and minimal example based on your original code:
import pygame, math
class Crucifix(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((40, 40), pygame.SRCALPHA)
pygame.draw.circle(self.image, "white", (20, 20), 20)
pygame.draw.line(self.image, "magenta", (20, 0), (20, 40), 5)
pygame.draw.line(self.image, "magenta", (0, 20), (40, 20), 5)
self.rect = self.image.get_rect(center = (400, 400))
self.mask = pygame.mask.from_surface(self.image)
self.px = 400
self.a = 0
def update(self):
offset_x = math.sin(self.a) * 100
self.a += 0.05
self.rect.x = round(self.px + offset_x)
class EnemiesStrong(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.Surface((40, 40), pygame.SRCALPHA)
pygame.draw.circle(self.original_image, "red", (20, 20), 20)
pygame.draw.polygon(self.original_image, "yellow", ((20, 0), (40, 20), (20, 40), (0, 20)))
self.image = self.original_image
self.rect = self.image.get_rect()
self.angle = 0
def initLoc(self, pos, radius):
self.pos = pos
self.radius = radius
def update(self):
center = pygame.math.Vector2(self.pos) + pygame.math.Vector2(0, -self.radius).rotate(-self.angle)
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center = (round(center.x), round(center.y)))
def turnLeft(self):
self.angle = (self.angle + 4) % 360
def updatePos(self, new_pos):
self.pos = new_pos
pygame.init()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
cross1 = Crucifix()
enemy_s = EnemiesStrong()
pos = cross1.rect.x, cross1.rect.y
enemy_s.initLoc(cross1.rect.center, 100)
all_sprites = pygame.sprite.Group(enemy_s)
all_sprites.add(cross1)
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *background.get_size(), (32, 32, 32), (48, 48, 48)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles]
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
enemy_s.turnLeft()
enemy_s.updatePos(cross1.rect.center)
all_sprites.update()
window.blit(background, (0, 0))
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
exit()

Related

How to do a collision detection between line and rectangle in pygame? [duplicate]

This question already has answers here:
Make a line as a sprite with its own collision in Pygame
(1 answer)
Check collision between a image and a line
(1 answer)
Closed 1 year ago.
This program should print "True", only if green rect touches the red line, but it prints True every time green rect got into red lines "area"(touches the lines sprite). Is there a way to make lines sprite?
In this code green is not on line, but still prints true:
class Line(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((200, 200))
self.rect = self.image.get_rect()
self.rect.x = 50
self.rect.y = 0
def update(self):
pygame.draw.line(screen, (255, 0, 0), (self.rect.x, self.rect.y), (200, 200))
class Rectt(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.rect = self.image.get_rect()
self.rect.x = 25
self.rect.y = 100
def update(self):
pygame.draw.rect(screen, (0, 255, 0), self.rect)
pygame.init()
screen = pygame.display.set_mode((300, 300))
screen.fill((0, 0, 0))
running = True
l = Line()
m = Rectt()
while running:
for event in pygame.event.get():
if (event.type == pygame.QUIT):
running = False
if (pygame.sprite.collide_mask(m, l)):
print(True)
else:
print(False)
l.update()
m.update()
pygame.display.flip()
screen.fill((0, 0, 0))
pygame.quit()
See Make a line as a sprite with its own collision in Pygame
You need to create a image (pygame.Surface) in with a per pixel alpha format (pygame.SRCALPHA) or a black color key (pygame.Surface.get_colorkey). Draw the line on the image and blit the image on the screen:
class Line(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((200, 200))
self.image.set_colorkey((0, 0, 0))
pygame.draw.line(self.image, (255, 0, 0), (0, 0), (200, 200))
self.rect = self.image.get_rect()
self.rect.x = 50
self.rect.y = 0
def update(self):
screen.blit(self.image, self.rect)
Do the same for the rectangle:
class Rectt(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.set_colorkey((0, 0, 0))
pygame.draw.rect(self.image, (0, 255, 0), (0, 0, 50, 50))
self.rect = self.image.get_rect()
self.rect.x = 25
self.rect.y = 100
def update(self):
screen.blit(self.image, self.rect)
You do not need the update methods at all if you are using a pygame.sprite.Group and pygame.sprite.Group.draw:
import pygame
class Line(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((200, 200))
self.image.set_colorkey((0, 0, 0))
pygame.draw.line(self.image, (255, 255, 0), (0, 0), (200, 200), 5)
self.rect = self.image.get_rect(topleft = (50, 50))
class Rectt(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.set_colorkey((0, 0, 0))
pygame.draw.rect(self.image, (0, 0, 255), (0, 0, 50, 50))
self.rect = self.image.get_rect(topleft = (25, 100))
pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
running = True
l = Line()
m = Rectt()
group = pygame.sprite.Group([l, m])
while running:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
m.rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3
m.rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3
m.rect.clamp_ip(screen.get_rect())
hit = pygame.sprite.collide_mask(m, l)
screen.fill((0, 0, 0))
group.draw(screen)
if hit:
pygame.draw.rect(screen, (255, 0, 0), m.rect, 5)
pygame.display.flip()
pygame.quit()

Collison and Resetting in PyGame [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
My problem: I am trying to create a vertical ball drop game, and I am testing for collision, which does work. But how would I reset my ball when it hits the hoop? Instead of it detecting and then hitting the bottom of the screen which results in a Game over screen because you lose. Any help is appreciated.
import time, random
from pygame.locals import *
import pygame, sys
pygame.init()
FPS = 60
FramePerSec = pygame.time.Clock()
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 600
SCREEN_BOTTOM = 0
SPEED = 5
SCORE = 0
font = pygame.font.SysFont("Verdana", 60)
font_small = pygame.font.SysFont("Verdana", 20)
game_over = font.render("Game Over", True, BLACK)
background = pygame.image.load("background.jpg")
DISPLAYSURF = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
DISPLAYSURF.fill(WHITE)
pygame.display.set_caption("Ball Drop")
class Ball(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("Ball.png")
self.rect = self.image.get_rect()
self.rect.center = (random.randint(40, SCREEN_WIDTH - 40), 0)
def move(self):
global SCORE
self.rect.move_ip(0, SPEED)
if (self.rect.bottom > 600):
self.rect.top = 0
self.rect.center = (random.randint(30, 380), 0)
# Need to check PNG for hit detection
class Basket(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("Basket.png")
self.rect = self.image.get_rect()
self.rect.center = (160, 520)
def move(self):
pressed_keys = pygame.key.get_pressed()
if(self.rect.x >= (SCREEN_WIDTH - 145)):
self.rect.x -= 5;
elif(self.rect.x <= -5):
self.rect.x += 5;
else:
if pressed_keys[pygame.K_a]:
self.rect.move_ip(-SPEED, 0)
if pressed_keys[pygame.K_d]:
self.rect.move_ip(SPEED, 0)
class Wall(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("wall.png")
self.rect = self.image.get_rect()
self.rect.center = (0, 670)
B2 = Basket()
B1 = Ball()
W1 = Wall()
balls = pygame.sprite.Group()
balls.add(B1)
# Need to fix wall sprite group
walls = pygame.sprite.Group()
walls.add(W1)
all_sprites = pygame.sprite.Group()
all_sprites.add(B2)
all_sprites.add(B1)
INC_SPEED = pygame.USEREVENT + 1
pygame.time.set_timer(INC_SPEED, 1000)
while True:
for event in pygame.event.get():
if event.type == INC_SPEED:
SPEED += 0.3
if event.type == QUIT:
pygame.quit()
sys.exit()
DISPLAYSURF.blit(background, (0, 0))
scores = font_small.render(str(SCORE), True, BLACK)
DISPLAYSURF.blit(scores, (10, 10))
for entity in all_sprites:
DISPLAYSURF.blit(entity.image, entity.rect)
entity.move()
# NEed to fix collison and Counting stats
if pygame.sprite.spritecollideany(W1, balls):
DISPLAYSURF.fill(RED)
DISPLAYSURF.blit(game_over, (30, 250))
pygame.display.update()
for entity in all_sprites:
entity.kill()
time.sleep(2)
pygame.quit()
sys.exit()
if pygame.sprite.spritecollideany(B2, balls):
print("Hit")
SCORE += 1
pygame.display.update()
pygame.display.update()
FramePerSec.tick(FPS)
pygame.sprite.spritecollideany() returns the hit Sprite (ball) object. Change the position of this ball:
while True:
# [...]
ball_hit = pygame.sprite.spritecollideany(B2, balls)
if ball_hit:
ball_hit.rect.center = (random.randint(30, 380), 0)
SCORE += 1
print("Hit")
# [...]

How do you point the barrel towards mouse in pygame?

I have fixed the problem pointed out in this post, but now I am confused on how to point the gray rectangle (barrel) towards my mouse. Could somebody please help? Thanks!
Here is my code:
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((400, 400))
pygame.display.set_caption("diep.io")
screen.fill((255,255,255))
auto_shoot = False
class Bullet:
def __init__(self, x_move, y_move, x_loc, y_loc):
self.image = pygame.image.load("C:\\Users\\ender\\OneDrive\\Documents\\repos\\Bullet.png")
self.x_move = x_move
self.y_move = y_move
self.x_loc = x_loc
self.y_loc = y_loc
self.bullet_rect = self.image.get_rect()
def update(self):
self.x_loc += self.x_move
self.y_loc += self.y_move
self.bullet_rect.center = round(self.x_loc), round(self.y_loc)
rect = screen.blit(self.image, self.bullet_rect)
if not screen.get_rect().contains(rect):
bullets.remove(self)
if self.x_loc > 400 or self.y_loc > 400:
bullets.remove(self)
bullet = None
bullets = []
while True:
screen.fill((255, 255, 255))
pygame.draw.rect(screen, (100, 100, 100), (205, 193, 25, 15)) # This is the rectangle I want to point at my mouse
pygame.draw.circle(screen, (82, 219, 255), (200, 200), 15)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP:
x = pygame.mouse.get_pos()[0] - 200
y = pygame.mouse.get_pos()[1] - 200
pythag = float(math.sqrt(x**2 + y**2))
bullets.append(Bullet(x/pythag, y/pythag, 200, 200))
for bullet in bullets:
bullet.update()
pygame.display.update()
pygame.time.delay(10)
Note: This is different from other problems because I am trying to point a rectangle at my mouse, and other posts are pointing an image at the mouse. That is not what I want to do. Secondly, pygame rectangles are defined by their bottom left corner, so this further complicates things.
For the rotation of the bullets see How to move a sprite according to an angle in Pygame and calculating direction of the player to shoot PyGmae.
Compute the angle of the direction vector grees(math.atan2(-y_move, x_move)) and rotate the bullet image:
class Bullet:
def __init__(self, x_move, y_move, x_loc, y_loc):
self.image = pygame.image.load("C:\\Users\\ender\\OneDrive\\Documents\\repos\\Bullet.png")
self.image = pygame.transform.rotate(self.image, math.degrees(math.atan2(-y_move, x_move)))
Rotating the rectangle is a little trickier. Draw the cannon on a pygame.Surface:
cannon = pygame.Surface((50, 50), pygame.SRCALPHA)
pygame.draw.rect(cannon, (100, 100, 100), (30, 17, 25, 15))
pygame.draw.circle(cannon, (82, 219, 255), (25, 25), 15)
See How do I rotate an image around its center using PyGame?.
Write a function to rotate and blit a Surface:
def blitRotateCenter(surf, image, center, angle):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(center = center).center)
surf.blit(rotated_image, new_rect)
Use the function in the application loop to draw the cannon:
while True:
# [...]
x = pygame.mouse.get_pos()[0] - 200
y = pygame.mouse.get_pos()[1] - 200
angle = math.degrees(math.atan2(-y, x))
blitRotateCenter(screen, cannon, (200, 200), angle)
# [...]
See also How to rotate an image(player) to the mouse direction? and How can you rotate the sprite and shoot the bullets towards the mouse position?.
Complete example:
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((400, 400))
pygame.display.set_caption("diep.io")
screen.fill((255,255,255))
clock = pygame.time.Clock()
class Bullet:
def __init__(self, x_move, y_move, x_loc, y_loc):
#self.image = pygame.image.load("C:\\Users\\ender\\OneDrive\\Documents\\repos\\Bullet.png")
self.image = pygame.Surface((20, 5), pygame.SRCALPHA)
self.image.fill((255, 0, 0))
self.image = pygame.transform.rotate(self.image, math.degrees(math.atan2(-y_move, x_move)))
self.x_move = x_move
self.y_move = y_move
self.x_loc = x_loc
self.y_loc = y_loc
self.bullet_rect = self.image.get_rect()
def update(self):
self.x_loc += self.x_move
self.y_loc += self.y_move
self.bullet_rect.center = round(self.x_loc), round(self.y_loc)
rect = screen.blit(self.image, self.bullet_rect)
if not screen.get_rect().contains(rect):
bullets.remove(self)
if self.x_loc > 400 or self.y_loc > 400:
bullets.remove(self)
cannon = pygame.Surface((50, 50), pygame.SRCALPHA)
pygame.draw.rect(cannon, (100, 100, 100), (30, 17, 25, 15))
pygame.draw.circle(cannon, (82, 219, 255), (25, 25), 15)
def blitRotateCenter(surf, image, center, angle):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(center = center).center)
surf.blit(rotated_image, new_rect)
bullet = None
bullets = []
auto_shoot = False
run = True
while run:
x = pygame.mouse.get_pos()[0] - 200
y = pygame.mouse.get_pos()[1] - 200
angle = math.degrees(math.atan2(-y, x))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONUP:
pythag = float(math.sqrt(x**2 + y**2))
bullets.append(Bullet(x/pythag, y/pythag, 200, 200))
screen.fill((255, 255, 255))
for bullet in bullets:
bullet.update()
blitRotateCenter(screen, cannon, (200, 200), angle)
pygame.display.update()
clock.tick(100)
pygame.quit()
exit()

Pygame mask collision

I'm trying to get proper collision detection with rotating surfaces in pygame. I decided to try using masks. It somewhat works, but it is not as precise as I'd liked/thought. I tried updating the mask at the end of the cycle to get a "fresh" hitbox for the next frame, but it didn't work as expected. What is my mistake?
import pygame
import random
WHITE = [255, 255, 255]
RED = [255, 0, 0]
pygame.init()
FPS = pygame.time.Clock()
fps = 6
winW = 1000
winH = 500
BGCOLOR = WHITE
win = pygame.display.set_mode((winW, winH))
win.fill(WHITE)
pygame.display.set_caption('')
pygame.display.set_icon(win)
class Box(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([w, h], pygame.SRCALPHA)
self.image.fill(random_color())
self.mask = pygame.mask.from_surface(self.image)
self.rect = pygame.Rect(x, y, w, h)
self.angle = 0
def move(self):
self.rect.center = pygame.mouse.get_pos()
def draw(self):
blits = self.rotate()
win.blit(blits[0], blits[1])
self.mask = pygame.mask.from_surface(blits[0])
def rotate(self):
self.angle += 3
new_img = pygame.transform.rotate(self.image, self.angle)
new_rect = new_img.get_rect(center=self.rect.center)
return new_img, new_rect
def update_display():
win.fill(BGCOLOR)
player.draw()
for p in platforms:
p.draw()
pygame.display.update()
def collision():
return pygame.sprite.spritecollide(player, plat_collide, False, pygame.sprite.collide_mask)
def random_color():
return [random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]
player = Box(100, 400, 50, 50)
platforms = [Box(300, 400, 100, 50)]
plat_collide = pygame.sprite.Group(platforms)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
hits = collision()
if hits:
BGCOLOR = RED
else:
BGCOLOR = WHITE
player.move()
update_display()
FPS.tick(fps)
pygame.quit()
Your application works fine. But note, pygame.sprite.collide_mask() use the .rect and .mask attribute of the sprite object for the collision detection.
You have to update self.rect after rotating the image:
class Box(pygame.sprite.Sprite):
# [...]
def rotate(self):
self.angle += 3
new_img = pygame.transform.rotate(self.image, self.angle)
new_rect = new_img.get_rect(center=self.rect.center)
# update .rect attribute
self.rect = new_rect # <------
return new_img, new_rect
See also Sprite mask
Minimal example: repl.it/#Rabbid76/PyGame-SpriteMask
import pygame
class SpriteObject(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, color):
pygame.sprite.Sprite.__init__(self)
self.angle = 0
self.original_image = pygame.Surface([w, h], pygame.SRCALPHA)
self.original_image.fill(color)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.mask = pygame.mask.from_surface(self.image )
def update(self):
self.rotate()
def rotate(self):
self.angle += 0.3
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(center = self.rect.center)
self.mask = pygame.mask.from_surface(self.image )
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode((400, 400))
size = window.get_size()
moving_object = SpriteObject(0, 0, 50, 50, (128, 0, 255))
static_objects = [
SpriteObject(size[0] // 2, size[1] // 3, 100, 50, (128, 128, 128)),
SpriteObject(size[0] // 4, size[1] * 2 // 3, 100, 50, (128, 128, 128)),
SpriteObject(size[0] * 3 // 4, size[1] * 2 // 3, 100, 50, (128, 128, 128))
]
all_sprites = pygame.sprite.Group([moving_object] + static_objects)
static_sprites = pygame.sprite.Group(static_objects)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
moving_object.rect.center = pygame.mouse.get_pos()
all_sprites.update()
collide = pygame.sprite.spritecollide(moving_object, static_sprites, False, pygame.sprite.collide_mask)
window.fill((255, 0, 0) if collide else (255, 255, 255))
all_sprites.draw(window)
pygame.display.update()
pygame.quit()
exit()

How do you divide the screen from the centre (vertically) to make a two player game?

So, I am programming a game which is two-players. I am trying to make it split screen from the center (vertically) where each player has their own screen and their own game is working. This would allow them to be at different stages in the game. For example, if one gets out, the other is not affected.
My game is where a snake has 5 balls initially of different colours and it is automatically moving in an upward direction. The user has to move it right or left to collect the correct colour ball and then collide with the correct colour block. I want this happening in the same screen but two times which will make it a two player game.
First, you have to encapsulte the game state for each sub-game. Then, instead of drawing the scene of the game(s) directly to the screen, draw them to seperate Surfaces, and then draw those to Surfaces to the screen.
Here's a simple, running example:
import pygame
import pygame.freetype
import random
pygame.init()
FONT = pygame.freetype.SysFont(None, 32)
class Player(pygame.sprite.Sprite):
def __init__(self, color, canvas, bindings):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill(color)
self.rect = self.image.get_rect(center=canvas.get_rect().center)
self.canvas = canvas
self.bindings = bindings
self.pos = pygame.Vector2(self.rect.topleft)
def update(self):
pressed = pygame.key.get_pressed()
direction = pygame.Vector2()
for key in self.bindings:
if pressed[key]:
direction += self.bindings[key]
if direction.length() > 0:
direction.normalize_ip()
self.pos += direction*4
self.rect.topleft = self.pos
self.rect.clamp_ip(self.canvas.get_rect())
self.pos = self.rect.topleft
class Game(pygame.sprite.Sprite):
def __init__(self, color, bg_color, bindings, left):
super().__init__()
self.bg_color = bg_color
self.image = pygame.Surface((400, 600))
self.image.fill(self.bg_color)
self.rect = self.image.get_rect(left=0 if left else 400)
self.player = Player(color, self.image, bindings)
self.target = pygame.Vector2(random.randint(100, 300), random.randint(100, 500))
self.stuff = pygame.sprite.Group(self.player)
self.score = 0
def update(self):
self.stuff.update()
self.image.fill(self.bg_color)
self.stuff.draw(self.image)
FONT.render_to(self.image, (190, 50), str(self.score), (200, 200, 200))
pygame.draw.circle(self.image, (210, 210, 210), [int(v) for v in self.target], 5)
if (self.player.rect.center - self.target).length() <= 20:
self.score += 1
self.target = pygame.Vector2(random.randint(100, 300), random.randint(100, 500))
def main():
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
player1_bindings = {
pygame.K_w: pygame.Vector2(0, -1),
pygame.K_a: pygame.Vector2(-1, 0),
pygame.K_s: pygame.Vector2(0, 1),
pygame.K_d: pygame.Vector2(1, 0)
}
player2_bindings = {
pygame.K_UP: pygame.Vector2(0, -1),
pygame.K_LEFT: pygame.Vector2(-1, 0),
pygame.K_DOWN: pygame.Vector2(0, 1),
pygame.K_RIGHT: pygame.Vector2(1, 0)
}
player1 = Game(pygame.Color('dodgerblue'), (30, 30, 30), player1_bindings, True)
player2 = Game(pygame.Color('orange'), (80, 20, 30), player2_bindings, False)
games = pygame.sprite.Group(player1, player2)
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
return
games.update()
screen.fill((30, 30, 30))
games.draw(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()

Categories