How do I rotate the object in PyGame - python

Ok. So i have so far found a code for a snake game on python. So far the game is working but now I have started changing the BNP's from squares to circular objects and what I want to know is how to rotate the body and head at the input of lets say the arrow keys making the body parts change. I don't know if this is possible, well it is, but not in the way I want it.
Ill post the code below.
import pygame
import sys
from pygame.locals import *
import random
import time
left = -20
right = 20
up = 10
down = -10
size = width, height = 640, 480
block_size = 20
class Food:
def __init__(self, screen, snake):
self.snake = snake
self.screen = screen
self.image = pygame.image.load('food.bmp').convert()
self.spawn()
def spawn(self):
collision = True
while collision:
random_x = random.randrange(0, width, block_size)
random_y = random.randrange(0, height, block_size)
collision = False
for each in snake.parts:
if each.position.x == random_x and each.position.y == random_y:
collision = True
break
self.position = self.image.get_rect().move(random_x, random_y)
self.blit()
def blit(self):
self.screen.blit(self.image, self.position)
class Part:
def __init__(self, x=0, y=0, direction=right):
self.direction = direction
self.image = pygame.image.load('part.bmp').convert()
self.position = self.image.get_rect().move(x, y)
self.speed = block_size
def change_direction(self, direction):
if self.direction + direction == 0:
return
self.direction = direction
def move(self):
if self.position.x >= width - block_size and self.direction == right:
return False
if self.position.y >= height - block_size and self.direction == down:
return False
if self.position.x <= 0 and self.direction == left:
return False
if self.position.y <= 0 and self.direction == up:
return False
if self.direction == up:
self.position = self.position.move(0, -self.speed)
elif self.direction == down:
self.position = self.position.move(0, self.speed)
elif self.direction == right:
self.position = self.position.move(self.speed, 0)
elif self.direction == left:
self.position = self.position.move(-self.speed, 0)
return True
class Parthead:
def __init__(self, x=0, y=0, direction=right):
self.direction = direction
self.image = pygame.image.load('parthead.bmp').convert()
self.position = self.image.get_rect().move(x, y)
self.speed = block_size
def change_direction(self, direction):
if self.direction + direction == 0:
return
self.direction = direction
def move(self):
if self.position.x >= width - block_size and self.direction == right:
return False
if self.position.y >= height - block_size and self.direction == down:
return False
if self.position.x <= 0 and self.direction == left:
return False
if self.position.y <= 0 and self.direction == up:
return False
if self.direction == up:
self.position = self.position.move(0, -self.speed)
elif self.direction == down:
self.position = self.position.move(0, self.speed)
elif self.direction == right:
self.position = self.position.move(self.speed, 0)
elif self.direction == left:
self.position = self.position.move(-self.speed, 0)
return True
class Snake:
def __init__(self, screen, x=0, y=0):
self.screen = screen
self.head = Parthead(x, y)
self.direction = right
self.length = 1
self.parts = []
self.parts.append(self.head)
self.extend_flag = False
def change_direction(self, direction):
self.direction = direction
def move(self, food):
new_direction = self.direction
old_direction = None
new_part = None
if self.extend_flag:
last_part = self.parts[-1]
new_part = Part(last_part.position.x, last_part.position.y, last_part.direction)
for each in self.parts:
old_direction = each.direction
each.change_direction(new_direction)
if not each.move():
return False
new_direction = old_direction
if self.extend_flag:
self.extend(new_part)
for each in self.parts[1:]:
if each.position.x == self.head.position.x and each.position.y == self.head.position.y:
return False
if food.position.x == self.head.position.x and food.position.y == self.head.position.y:
food.spawn()
self.extend_flag = True
return True
def extend(self, part):
self.parts.append(part)
self.length += 1
self.extend_flag = False
def blit(self):
for each in self.parts:
self.screen.blit(each.image, each.position)
black = 0, 0, 0
pygame.init()
pygame.display.set_caption('Snake by Jonathan Dring')
screen = pygame.display.set_mode(size)
game = True
while True:
snake = Snake(screen)
food = Food(screen, snake)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == KEYDOWN:
if (event.key == K_RIGHT):
snake.change_direction(right)
elif (event.key == K_LEFT):
snake.change_direction(left)
elif (event.key == K_UP):
snake.change_direction(up)
elif (event.key == K_DOWN):
snake.change_direction(down)
elif (event.key == K_SPACE):
snake.extend_flag = True
if not snake.move(food):
game = False
break
screen.fill(black)
print ("Snake - The Game")
snake.blit()
food.blit()
pygame.display.update()
pygame.time.delay(100)
while not game:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == KEYDOWN:
if (event.key == K_SPACE):
game = True
elif (event.key == K_RETURN):
game = True
elif event.key == K_ESCAPE:
pygame.quit()
background = pygame.image.load('gameover.bmp').convert()
screen.blit(background, (0, 0))
pygame.display.flip()
pygame.time.delay(100)
If you know how to do it please reply!

Seeing as there is still no answer, here is how to rotate a sprite. Naturally, you can only rotate the rect of the sprite. This function, when added to a sprite, will make it rotate when you send it an angle to point in:
def rotate(self,angle):
self.rect = pygame.transform.rotate(self.rect, angle)
This should work.

Related

Why does rotated image move by itself?

I rotate an image and I adjust the rect to the rotated image. When I start the program, the image starts moving, without any order by the program. There are, for testing, some pictures needed. I hope, as more experienced users, can take some standards.
import pygame
import sys
from pygame.constants import KEYUP
from pygame.constants import KEYDOWN
import math
import random
pygame.init()
cell_size = 40
cell_number = 20
breite = int(cell_size * cell_number )
hoehe = int( cell_size * cell_number )
screen = pygame.display.set_mode((breite,hoehe))
clock = pygame.time.Clock()
anzahl_gegenstaende = 10 # gehört zu landschaft
class MeinAuto(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(auto_img,(30,66)).convert_alpha()
self.rect = self.image.get_rect(center=(x,y))
self.rect.x = x
self.rect.y = y
self.mask = pygame.mask.from_surface(self.image )
self.wagen_winkel = 0
self.speed = 5
self.links = False
self.rechts = False
self.vor = False
self.zurueck = False
self.lenk_winkel = 0
self.block_vor = False
self.block_zurueck = False
def update(self):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if self.vor or self.zurueck:
self.links = True
if event.key == pygame.K_RIGHT:
if self.vor or self.zurueck:
self.rechts = True
if event.key == pygame.K_UP:
self.vor = True
if event.key == pygame.K_DOWN:
self.zurueck = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
self.links = False
if event.key == pygame.K_RIGHT:
self.rechts = False
if event.key == pygame.K_UP:
self.vor = False
if event.key == pygame.K_DOWN:
self.zurueck = False
self.winkel_berechnung(1)
dx = math.cos(math.radians(self.wagen_winkel))
dy = math.sin(math.radians(self.wagen_winkel))
if self.vor and self.block_vor == False:
self.rect.y -= int(self.speed * dx)
self.rect.x -= int(self.speed * dy)
self.block_zurueck = False
elif self.zurueck and self.block_zurueck == False:
self.rect.y += int(self.speed * dx)
self.rect.x += int(self.speed * dy)
self.block_vor = False
if self.links:
self.lenk_winkel +=5
self.lenk_winkel=min(self.lenk_winkel,120)
elif self.rechts:
self.lenk_winkel -=1
self.lenk_winkel=max(self.lenk_winkel,-120)
if not self.links and not self.rechts: self.lenk_winkel = 0
def winkel_berechnung(self,dt):
if self.rechts:
self.wagen_winkel += self.lenk_winkel
while self.wagen_winkel < 0:
self.wagen_winkel += 360
elif self.links:
self.wagen_winkel += self.lenk_winkel
while self.wagen_winkel > 359:
self.wagen_winkel -= 360
class Lenkung(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(lenkrad_img,(120,120)).convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.wagen_winkel = 0
class Landschaft(pygame.sprite.Sprite):
def __init__(self,image):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.mask = pygame.mask.from_surface(self.image )
x=random.randrange(60, breite -60)
y=random.randrange(200, hoehe - 200)
self.rect = self.image.get_rect(center =(x,y))
def zeichne_hintergrund():
background = pygame.image.load("Bilder/background_gelb.jpg")
screen.blit(background,(0,0))
def blitRotateCenter(image, left, top, angle):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(center = (left, top)).center)
screen.blit(rotated_image, new_rect)
return new_rect
########## Bilder laden
auto_img = pygame.image.load("Bilder/car.png")
lenkrad_img = pygame.image.load("bilder/lenkrad.png")
######### Gruppen bilden
auto = MeinAuto(breite/2,hoehe-100)
auto_sprite = pygame.sprite.Group()
auto_sprite.add(auto)
lenkung = Lenkung(breite/2,60)
lenkung_sprite = pygame.sprite.Group()
lenkung_sprite.add(lenkung)
land = pygame.sprite.Group()
while len(land) < anzahl_gegenstaende:
ii = len(land)
img = pygame.image.load(f"Bilder/Gegenstaende/geg{ii}.png")
img = pygame.transform.scale(img,(100,100))
m = Landschaft(img)
if not pygame.sprite.spritecollide(m, land, False):
land.add(m)
while True:
clock.tick(6)
zeichne_hintergrund()
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
hits = pygame.sprite.spritecollide( auto, land, False, pygame.sprite.collide_mask)
for hit in hits:
pass
auto_sprite.update()
land.draw(screen)
new_auto_rect =blitRotateCenter(auto.image, auto.rect.x, auto.rect.y, auto.wagen_winkel)
auto.rect=new_auto_rect
new_auto_rect = new_auto_rect.inflate(-80,-50)
blitRotateCenter(lenkung.image, lenkung.rect.x, lenkung.rect.y, auto.lenk_winkel)
pygame.draw.rect(screen,(0,250,0),auto.rect,4)
pygame.draw.rect(screen,(250,250,0),new_auto_rect,1)
pygame.display.flip()
Instead of the upper left corner of the image, you have to pass the center of the image to the blitRotateCenter function:
new_auto_rect = blitRotateCenter(auto.image, auto.rect.x, auto.rect.y, auto.wagen_winkel)
new_auto_rect = blitRotateCenter(auto.image, auto.rect.centerx, auto.rect.centery, auto.wagen_winkel)
Simplify the code using the asterisk(*) operator:
new_auto_rect = blitRotateCenter(auto.image, *auto.rect.center, auto.wagen_winkel)

How to use groupcollide?

So I've been wondering how to use the pygame groupcollide. And I'm utterly stumped right now. As I am using collide_rect and it is fine. But for groupcollide I can't seem to figure out how to call the properties of the item inside of that group. And I can't do collide rect because there's going to be a lot of bullets.
def check_blast_collisions(player,bullet):
hits = pg.sprite.groupcollide(player,bullet,False,True)
for hit in hits:
print (hits)
if hit.vx == 20:
player.vx += 40
elif hit.vx == -20:
player.vx += -40
Here is a snippet of where I'm trying to use groupcollide.
After I made this function, the bullets don't even show up. (The bullets are supposed to be called blasts but I forgot about it in this function.)
import pygame as pg
#settings
CAPTION = "Knockback Arena"
resolution = 1600,900
WIDTH = resolution[0]
HEIGHT = resolution[1]
FPS = 60
player_jump_height = 30
player_max_fall_speed = 30
player_fall_speed_increase = 2
player_lives = 5
shoot_cooldown = 500
#initialize pygame
pg.init()
pg.mixer.init()
pg.font.init
screen = pg.display.set_mode(resolution)
pg.display.set_caption(CAPTION)
clock = pg.time.Clock()
#sprites
class Platform(pg.sprite.Sprite):
def __init__(self,x,y,width,height,r,g,b):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((width,height))
self.image.fill((r,g,b))
self.rect = self.image.get_rect()
self.rect.center = (x,y)
class Player(pg.sprite.Sprite):
def __init__(self,r,g,b,x,y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((40, 100))
self.image.fill((r,g,b))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.startx = x
self.starty = y
self.vx = 0
self.vy = 5
self.vy_max = player_max_fall_speed
self.vy_increase = player_fall_speed_increase
self.lives = player_lives
self.last_shot = 0
self.facing_right = False
self.facing_left = False
def update(self):
self.rect.x += self.vx
self.rect.y += self.vy
if self.vy >= self.vy_max:
self.vy = self.vy_max
self.vy_increase = 0
if self.vy < self.vy_max:
self.vy_increase = player_fall_speed_increase
if self.rect.bottom < HEIGHT:
self.vy += self.vy_increase
if self.rect.top >= HEIGHT:
self.rect.x = self.startx
self.rect.y = self.starty
self.lives -= 1
if self.lives <= 0:
self.kill()
if self.rect.right >= WIDTH:
self.rect.right = WIDTH
self.vx = 0
if self.rect.left <= 0:
self.rect.left = 0
self.vx = 0
def jump(self):
if self.rect.bottom >= main_platform.rect.top:
self.vy -= player_jump_height
if self.rect.bottom >= HEIGHT:
self.vy -= player_jump_height
def shoot(self):
if pg.time.get_ticks() - self.last_shot >= shoot_cooldown:
if self.facing_left == True:
return "shoot_left"
elif self.facing_right == True:
return "shoot_right"
else:
return "cd_not_done"
class Blast(pg.sprite.Sprite):
def __init__(self,player,direction):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((20,10))
self.image.fill((0,255,255))
self.rect = self.image.get_rect()
self.rect.center = (player.rect.center)
self.direction = direction
if self.direction == 0:
self.vx = -20
elif self.direction == 1:
self.vx = 20
def update(self):
self.rect.x += self.vx
if self.rect.right < 0:
self.kill()
if self.rect.left > WIDTH:
self.kill()
#functions
def check_for_collisions(player,platform):
hits = pg.sprite.collide_rect(player,platform)
if hits:
if hits and player.vy > 0:
player.rect.bottom = platform.rect.top
player.vy = 0
def check_blast_collisions(player,bullet):
hits = pg.sprite.groupcollide(player,bullet,False,True)
for hit in hits:
print (hits)
if hit.vx == 20:
player.vx += 40
elif hit.vx == -20:
player.vx += -40
font = pg.font.Font('font/Roboto-Light.ttf', 30)
all_sprites = pg.sprite.Group()
players = pg.sprite.Group()
platforms = pg.sprite.Group()
blasts = pg.sprite.Group()
main_platform = Platform(WIDTH/2,650,1000,100,0,200,0)
player_1 = Player(0,0,255,WIDTH/2 + -100,200)
player_2 = Player(255,0,0,WIDTH/2 + 100,200)
platforms.add(main_platform)
players.add(player_1)
players.add(player_2)
all_sprites.add(player_1)
all_sprites.add(player_2)
all_sprites.add(main_platform)
menu = True
run = True
while run:
#check for closing window
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_1.jump()
if event.key == pg.K_a:
player_1.vx = -10
player_1.facing_left = True
player_1.facing_right = False
elif event.key == pg.K_d:
player_1.vx = 10
player_1.facing_right = True
player_1.facing_left = False
if event.key == pg.K_UP:
player_2.jump()
if event.key == pg.K_LEFT:
player_2.vx = -10
player_2.facing_left = True
player_2.facing_right = False
elif event.key == pg.K_RIGHT:
player_2.vx = 10
player_2.facing_right = True
player_2.facing_left = False
if event.key == pg.K_j:
if player_1.shoot() == "shoot_left":
b = Blast(player_1,0)
all_sprites.add(b)
blasts.add(b)
elif player_1.shoot() == "shoot_right":
b = Blast(player_1,1)
all_sprites.add(b)
blasts.add(b)
if event.key == pg.K_KP1:
if player_2.shoot() == "shoot_left":
b = Blast(player_2,0)
all_sprites.add(b)
blasts.add(b)
elif player_2.shoot() == "shoot_right":
b = Blast(player_2,1)
all_sprites.add(b)
blasts.add(b)
elif event.type == pg.KEYUP:
if event.key == pg.K_a:
player_1.vx = 0
if event.key == pg.K_d:
player_1.vx = 0
if event.key == pg.K_LEFT:
player_2.vx = 0
if event.key == pg.K_RIGHT:
player_2.vx = 0
if event.type == pg.QUIT:
pg.quit()
exit()
#update all sprites
all_sprites.update()
check_for_collisions(player_1,main_platform)
check_for_collisions(player_2,main_platform)
check_blast_collisions(players,blasts)
#draw sprites
screen.fill((255,255,255))
all_sprites.draw(screen)
#draw other stuff
p1lives = font.render(str(player_1.lives), False, (0,0,255))
screen.blit(p1lives,(20,50))
p2lives = font.render(str(player_2.lives), False, (255,0,0))
screen.blit(p2lives,(1580,50))
clock.tick(FPS)
pg.display.flip()
Here is the entire code.
Any help is much appreciated. Thanks.
You cannot use pygame.sprite.groupcollide() here, because the bullets collide with the player that shoots the bullets.
You have to use pygame.sprite.spritecollide(), with one player and the bullets of the opponent. Call it once for each player.

Is there an easy and effecient way to code jumping and gravity logic in python using pygame for a platformer?

Im making a platformer in python using pygame, but i am stuck on the collision, jumping and gravity logic, i figured out the collision logic but not the gravity and jumping. So im asking someone to make a example for my code, because im stuck on this for about 3 weeks now.
Project File: https://github.com/1NilusNilus/Pygame-Platformer
Code:
import pygame
import os
import sys
class Level(object):
def __init__(self, path):
self.path = path
def get(self):
with open(self.path, "r") as file:
data = file.read()
data = data.split("\n")
return data
class Tile(object):
def __init__(self, screen, level):
self.screen = screen
self.level = level
self.sprites = {
"dirt": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/dirt.png"),
"grass": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/grass.png"),
"brick": pygame.image.load("C:/Users/entit/Desktop/Python/Platformer/img/brick.png")
}
self.pos = [0,0]
self.size = [30,30]
self.rect = pygame.rect.Rect(self.pos, self.size)
self.tiles = []
def testCollision(self, player_rect):
hitlist = []
for tile in self.tiles:
if player_rect.colliderect(tile):
hitlist.append(tile)
return hitlist
def draw(self):
self.pos[0] = 0
self.pos[1] = 0
for tiles in self.level:
self.pos[0] = 0
for tile in tiles:
if tile == "1":
self.screen.blit(self.sprites["dirt"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
if tile == "2":
self.screen.blit(self.sprites["grass"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
if tile == "3":
self.screen.blit(self.sprites["brick"], self.pos)
self.tiles.append(pygame.Rect(self.pos, self.size))
self.pos[0] += self.size[0]
self.pos[1] += self.size[1]
class Player(object):
def __init__(self, screen, tile, sprite):
self.screen = screen
self.sprite = sprite
self.tile = tile
self.vel = [0, 0]
self.acc = [0.1, 0.1]
self.pos = [180, 390]
self.size = self.sprite.get_size()
self.player_rect = pygame.rect.Rect(self.pos, self.size)
self.dir = {"right":False, "left":False}
def draw(self):
self.screen.blit(self.sprite, self.pos)
def move(self):
self.collision_types = {"left":False, "right":False, "top":False, "bottom":False}
self.player_rect.x = self.pos[0]
self.player_rect.y = self.pos[1]
self.pos[0] += self.vel[0]
for tile in self.tile.testCollision(self.player_rect):
if self.vel[0] > 0:
self.vel[0] = 0
self.pos[0] = tile.left - self.size[0]
self.collision_types["right"] = True
if self.vel[0] < 0:
self.vel[0] = 0
self.pos[0] = tile.right
self.collision_types["left"] = True
self.pos[1] += self.vel[1]
for tile in self.tile.testCollision(self.player_rect):
if self.vel[1] > 0:
self.pos[1] = tile.top - self.size[1]
self.collision_types["bottom"] = True
self.vel[1] = 0
if self.vel[1] < 0:
self.pos[1] = tile.bottom
self.collision_types["top"] = True
if self.dir["left"]:
self.vel[0] = -2
elif self.dir["right"]:
self.vel[0] = 2
else:
self.vel[0] = 0
class Game:
def __init__(self, screen):
self.screen = screen
self.clock = pygame.time.Clock()
self.FPS = 60
self.running = True
self.bgcolor = (66,135,245)
self.level = Level("C:/UserS/entit/Desktop/Python/Platformer/level.txt").get()
self.tile = Tile(self.screen, self.level)
self.player = Player(self.screen, self.tile, pygame.image.load("C:/UserS/entit/Desktop/Python/Platformer/img/player.png"))
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
self.player.dir["left"] = True
if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
self.player.dir["left"] = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
self.player.dir["right"] = True
if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
self.player.dir["right"] = False
def update(self):
self.player.move()
def draw(self):
self.screen.fill(self.bgcolor)
self.tile.draw()
self.player.draw()
pygame.display.update()
def run(self):
while self.running:
self.events()
self.update()
self.draw()
self.clock.tick(self.FPS)
pygame.quit()
sys.exit()
def main():
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
screen_size = [720,480]
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("platformer")
game = Game(screen)
game.run()
if __name__ == "__main__":
main()
Adding the gravity logic is straight forward. Gravity is acceleration so it increases the vertical velocity toward the ground. In a pygame screen, positive Y is down, so gravity increases the Y velocity. For the jump, you just set the Y velocity to a negative number (up) and let gravity do the rest.
Only a few changes are needed:
In the Player class:
def __init__(self, screen, tile, sprite):
self.gravity = .1 # gravity acceleration # add this line
self.screen = screen
self.sprite = sprite
.........
def move(self):
self.vel[1] += self.gravity # adjust vertical velocity # add this line
self.collision_types = {"left":False, "right":False, "top":False, "bottom":False}
.........
In the Game class:
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: # player jump # add this line
self.player.vel[1] = -5 # add this line
........
Note that with the jump added, the player can collide with a platform from the side or bottom while the player X and Y velocities are both non-zero. You will need to update the collision logic for this.

pygame.Rect.colliderect() function is not executing

I'm attempting to add a segment to the player in my snake clone when the food.rect and snake.rect collide. The code inside the function however will not execute.
def add_segment(self,food):
if self.rect.colliderect(food.rect):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
self.body.append(snake_segment)
print('this code works!')
Here is the rest of my code if you need it. I have been struggling with this issue for days, so any help would be much appreciated!
import pygame,sys,random
from pygame.locals import *
pygame.init()
WINDOW_HEIGHT = 500
WINDOW_WIDTH = 500
RECTANGLE_HEIGHT = 20
RECTANGLE_WIDTH = 20
GREEN = (0,255,0)
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
clock = pygame.time.Clock()
SCREEN = pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT))
pygame.display.set_caption("Snake")
class Snake(object):
def __init__(self, color, width, height):
self.body = []
self.image = pygame.Surface((width,height))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.speed = 20
self.direction = 'right'
self.body = []
self.living = True
self.move = (0,0)
def movement(self):
self.rect.move_ip(self.move)
self.rect.clamp_ip(SCREEN.get_rect())
def blit(self):
SCREEN.blit(self.image,self.rect)
def update(self,food):
self.add_segment(food)
self.draw_snake()
self.movement()
print(self.rect.colliderect(food.rect))
print(self.body)
def add_segment(self,food):
if self.rect.colliderect(food.rect):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
self.body.append(snake_segment)
print('this code works!')
def draw_snake(self):
if len(self.body) == 0:
self.blit()
elif len(self.body) >= 1:
for snake_segment in self.body:
snake_segment.blit()
class Food(object):
def __init__(self,color,width,height):
self.image = pygame.Surface((width,height))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(20,500,20)
self.rect.y = random.randrange(20,500,20)
self.state = 'uneaten'
def check_eaten(self,snake):
if snake.rect.colliderect(self.rect):
self.state = 'eaten'
def blit(self):
SCREEN.blit(self.image,self.rect)
def update_state(self,snake):
self.check_eaten(snake)
if self.state == 'uneaten':
self.blit()
elif self.state == 'eaten':
self.rect.x = random.randrange(0,500,20)
self.rect.y = random.randrange(0,500,20)
if self.rect.x == snake.rect.x or self.rect.x == snake.rect.y:
self.rect.x = random.randrange(0,500,20)
self.rect.y = random.randrange(0,500,20)
self.blit()
self.state = 'uneaten'
def update(self,snake):
self.update_state(snake)
print(self.state)
def event_loop(snake,food):
while True:
SCREEN.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_RIGHT:
snake.move = (snake.speed,0)
snake.direction = 'right'
elif event.key == K_LEFT:
snake.move = (-snake.speed,0)
snake.direction = 'left'
elif event.key == K_UP:
snake.move = (0,-snake.speed)
snake.direction = 'up'
elif event.key == K_DOWN:
snake.move = (0,snake.speed)
snake.direction = 'down'
food.update(snake)
snake.update(food)
pygame.display.update()
clock.tick(5)
SNAKE = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
FOOD = Food(RED,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
event_loop(SNAKE,FOOD)
It' all a matter of order.
food.update(snake) tests if the food collides with the shake and place a the food at a new position.
snake.update(food) test is the snake collides with the food and appends a segment to the snake.
So if food.update(snake) is executed before snake.update(food), then the snake will never eat the food, because the food is moved away before:
food.update(snake)
snake.update(food)
snake.update(food)
food.update(snake)
The snake is never at the position where it is drawn, because the snake is drawn self.draw_snake() before it is moved self.movement().
You've to do it in this order:
Move the snake
Test if the snake is on the food
Draw the snake
class Snake(object):
# [...]
def update(self,food):
self.movement()
self.add_segment(food)
self.draw_snake()

Artificial inteligence in python and pygame for Pong clone

I'm making a program that clones pong based off a tutorial and I already have the program to where it is multiplayer with two separate people. I want to add an AI in the program instead of a player 2. I've been stuck on this for quite some time and would appreciate any help! Here is the code currently:
import sys, os, math, random, pygame
from pygame.locals import *
class paddle(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_paddle.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movementspeed = 5
self.velocity = 0
def up(self):
# increases vertical velocity
self.velocity -= self.movementspeed
def down(self):
# decreases vertical velocity
self.velocity += self.movementspeed
def move(self, dy):
# moves the paddle y, doesn't go out of top or bottom
if self.rect.bottom + dy > 400:
self.rect.bottom = 400
elif self.rect.top + dy < 0:
self.rect.top = 0
else:
self.rect.y += dy
def update(self):
# makes the paddle move every frame
self.move(self.velocity)
class aiplayer(object):
def __init__(self):
self.bias = random.random() - 0.5
self.hit_count = 0
def update(self, paddle, game,):
if (paddle.rect.centerx < game.bounds.centerx and game.ball.rect.centerx < game.bounds.centerx) or (paddle.rect.centerx > game.bounds.centerx and game.ball.rect.centerx > game.bounds.centerx):
delta = (paddle.rect.centery + self.bias * paddle.rect.height) - game.ball.rect.centery
if abs(delta) > paddle.velocity:
if delta > 0:
paddle.direction = -1
else:
paddle.direction = 1
else:
paddle.direction = 0
else:
paddle.direction = 0
def hit(self):
self.hit_count += 1
if self.hit_count > 6:
self.bias = random.random() - 0.5
self.hit_count = 0
def lost(self):
self.bias = random.random() - 0.5
def won(self):
pass
def render(self, surface):
x, y = self.location
w, h = self.image.get_size()
surface.blitz(self.image, (x-w/2, y-h/2))
class Ball(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_ball.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.maxspeed = 10
self.servespeed = 5
self.velx = 0
self.vely = 0
def reset(self):
self.rect.centerx, self.rect.centery = 400, 200
self.velx = 0
self.vely = 0
def serve(self):
angle = random.randint(-45, 45)
if abs(angle) < 5 or abs(angle-180) < 5:
angle = random.randint(10, 20)
if random.random() > .5:
angle += 180
# this gets the velocity for the x and y coords
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.velx = self.servespeed * x
self.vely = self.servespeed * y
class Game(object):
def __init__(self):
pygame.init()
# creates the window
self.window = pygame.display.set_mode((800, 400))
# makes a clock
self.clock = pygame.time.Clock()
# window title
pygame.display.set_caption("Pong")
# tells pygame to watch for these certain events so we can close window
pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])
self.background = pygame.Surface((800, 400))
self.background.fill((55, 255, 85))
pygame.draw.line(self.background, (0,0,0), (400, 0), (400, 400), 2)
self.window.blit(self.background, (0,0))
#lets the background show up
pygame.display.flip()
#renders the sprites so that they actually show up
self.sprites = pygame.sprite.RenderUpdates()
# makes the paddles, adds to sprite group
self.leftpaddle = paddle((50, 200))
self.sprites.add(self.leftpaddle)
self.rightpaddle = paddle((750, 200))
self.sprites.add(self.rightpaddle)
# makes the ball
self.ball = Ball((400, 200))
self.sprites.add(self.ball)
def run(self):
# this lets the game run using a loop so its always active and never closes
running = True
while running:
self.clock.tick(60)
# pygame event, if user closes the game, then stop running
running = self.handleEvents()
pygame.display.set_caption("Pong %d fps" % self.clock.get_fps())
self.manageBall()
# updates the sprites(paddles, ball)
for sprite in self.sprites:
sprite.update()
# renders the sprites
self.sprites.clear(self.window, self.background)
dirty = self.sprites.draw(self.window)
pygame.display.update(dirty)
def handleEvents(self):
for event in pygame.event.get():
if event.type == QUIT:
return False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
return False
# controls the right paddle
if event.key == K_w:
self.leftpaddle.up()
if event.key == K_s:
self.leftpaddle.down()
if event.key == K_UP:
self.rightpaddle.up()
if event.key == K_DOWN:
self.rightpaddle.down()
# serves the ball
if event.key == K_SPACE:
if self.ball.velx == 0 and self.ball.vely == 0:
self.ball.serve()
elif event.type == KEYUP:
if event.key == K_w:
self.leftpaddle.down()
if event.key == K_s:
self.leftpaddle.up()
if event.key == K_UP:
self.rightpaddle.down()
if event.key == K_DOWN:
self.rightpaddle.up()
elif event.type ==
return True
def manageBall(self):
# this moves the ball
self.ball.rect.x += self.ball.velx
self.ball.rect.y += self.ball.vely
if self.ball.rect.top < 0:
self.ball.rect.top = 1
# makes the ball bounce
self.ball.vely *= -1
elif self.ball.rect.bottom > 400:
self.ball.rect.bottom = 399
# makes ball bounce off bottom
self.ball.vely *= -1
# resets the ball if it hits the left or right screen
if self.ball.rect.left < 0:
self.ball.reset()
return
elif self.ball.rect.right > 800:
self.ball.reset()
return
collision = pygame.sprite.spritecollide(self.ball, [self.leftpaddle, self.rightpaddle], dokill = False)
if len(collision) > 0:
hitpaddle = collision[0]
# sends the ball back
self.ball.velx *= -1
# makes sure the ball doesn't get stuck in the paddle
self.ball.rect.x += self.ball.velx
# makes the game and runs it
if __name__ == '__main__':
game = Game()
game.run()
Make a function AI in the aiplayer and have it return up or down
int AI(self.position,ball.position):
if self.y>ball.y:
return -1
elif self.y<ball.y:
return 1
then, in the update() code for aiplayer, do something similar to this
self.y += movespeed*AI(self.position,ball.position)
Then, it either moves the paddle up or down depending on where the ball is ( you might need to switch if you add or subtract the movespeed to get the paddle to go the right direction). Also, it might be more effective to use the center of the paddle so that it won't put the top or bottom edge of the paddle at the ball.

Categories