This question already has an answer here:
How do I get the snake to grow and chain the movement of the snake's body?
(1 answer)
Closed 2 years ago.
I am creating a snake clone in pygame, and I am currently working on managing the turning mechanisms of the snake and its movement. I create a point at the time of turning in pygame, then store it in snake.pos_at_turn. After that I adjust each snake segments direction the should move until either their x or y coordinate equals that of snake.pos_at_turn then I change their direction again. The problem is that for some reason the snake segment doesn't move at all. Any help would be appreciated!
Code for snake object and event loop:
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.living = True
self.move = (0,0)
self.pos_at_turn = [0,0]
def movement(self):
if self.direction == 'right':
self.move = (self.speed,0)
elif self.direction == 'left':
self.move = (-self.speed,0)
elif self.direction == 'up':
self.move = (0,-self.speed)
elif self.direction == 'down':
self.move = (0,self.speed)
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.movement()
self.add_segment(food)
self.draw_snake()
for snake_segment in self.body:
print(snake_segment.rect)
def add_segment(self,food):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
if len(self.body) == 0:
self.body.append(snake_segment)
if self.rect.colliderect(food.rect):
self.body.append(snake_segment)
def draw_snake(self):
for snake_segment in self.body:
if self.body.index(snake_segment) == 0:
self.blit()
else:
# original movement code:
# if self.direction == 'right':
# snake_segment.rect.x = self.rect.x - RECTANGLE_WIDTH * self.body.index(snake_segment)
# snake_segment.rect.y = self.rect.y
# snake_segment.blit()
# elif self.direction == 'left':
# snake_segment.rect.x = self.rect.x + RECTANGLE_WIDTH * self.body.index(snake_segment)
# snake_segment.rect.y = self.rect.y
# snake_segment.blit()
# elif self.direction == 'up':
# snake_segment.rect.x = self.rect.x
# snake_segment.rect.y = self.rect.y + RECTANGLE_HEIGHT * self.body.index(snake_segment)
# snake_segment.blit()
# elif self.direction == 'down':
# snake_segment.rect.x = self.rect.x
# snake_segment.rect.y = self.rect.y - RECTANGLE_HEIGHT * self.body.index(snake_segment)
# snake_segment.blit()
if self.direction == 'right':
if snake_segment.rect.y >= self.pos_at_turn[1]:
snake_segment.direction = 'down'
elif snake_segment.rect.y <= self.pos_at_turn[1]:
snake_segment.direction = 'up'
if snake_segment.rect.y == self.pos_at_turn[1]:
if snake_segment.rect.x >= self.pos_at_turn[0]:
snake_segment.direction = 'left'
elif snake_segment.rect.x <= self.pos_at_turn[0]:
snake_segment.direction = 'right'
snake_segment.blit()
elif self.direction == 'left':
if snake_segment.rect.y >= self.pos_at_turn[1]:
snake_segment.direction = 'down'
elif snake_segment.rect.y <= self.pos_at_turn[1]:
snake_segment.direction = 'up'
if snake_segment.rect.y == self.pos_at_turn[1]:
if snake_segment.rect.x >= self.pos_at_turn[0]:
snake_segment.direction = 'left'
elif snake_segment.rect.x <= self.pos_at_turn[0]:
snake_segment.direction = 'right'
snake_segment.blit()
elif self.direction == 'up':
if snake_segment.rect.x >= self.pos_at_turn[0]:
snake_segment.direction = 'left'
elif snake_segment.rect.x <= self.pos_at_turn[0]:
snake_segment.direction = 'right'
if snake_segment.rect.x == self.pos_at_turn[0]:
if snake_segment.rect.y >= self.pos_at_turn[1]:
snake_segment.direction = 'down'
elif snake_segment.rect.y <= self.pos_at_turn[1]:
snake_segment.direction = 'up'
snake_segment.blit()
elif self.direction == 'down':
if snake_segment.rect.x >= self.pos_at_turn[0]:
snake_segment.direction = 'left'
elif snake_segment.rect.x <= self.pos_at_turn[0]:
snake_segment.direction = 'right'
if snake_segment.rect.x == self.pos_at_turn[0]:
if snake_segment.rect.y >= self.pos_at_turn[1]:
snake_segment.direction = 'down'
elif snake_segment.rect.y <= self.pos_at_turn[1]:
snake_segment.direction = 'up'
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)
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:
snake.pos_at_turn = [snake.rect.x, snake.rect.y]
if event.key == K_RIGHT:
snake.direction = 'right'
elif event.key == K_LEFT:
snake.direction = 'left'
elif event.key == K_UP:
snake.direction = 'up'
elif event.key == K_DOWN:
snake.direction = 'down'
snake.update(food)
food.update(snake)
pygame.display.update()
clock.tick(5)
SNAKE = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
FOOD = Food(RED,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
event_loop(SNAKE,FOOD)
You've to traverse the snakes body in reverse order in the method movement. For each part of the body, copy the position of the previous part. The head part gets the current position of the snake:
class Snake(object):
# [...]
def movement(self):
if self.direction == 'right':
self.move = (self.speed,0)
elif self.direction == 'left':
self.move = (-self.speed,0)
elif self.direction == 'up':
self.move = (0,-self.speed)
elif self.direction == 'down':
self.move = (0,self.speed)
self.rect.move_ip(self.move)
self.rect.clamp_ip(SCREEN.get_rect())
for i in range(len(self.body)-1, 0, -1):
self.body[i].rect.center = self.body[i-1].rect.center
if self.body:
self.body[0].rect.center = self.rect.center
Init the position of a part, when a new part is add to the body in the method add_segment:
class Snake(object):
# [...]
def add_segment(self,food):
if len(self.body) == 0 or self.rect.colliderect(food.rect):
snake_segment = Snake(GREEN,RECTANGLE_WIDTH,RECTANGLE_HEIGHT)
snake_segment.rect.center = self.rect.center
self.body.append(snake_segment)
In the method draw_snake it is sufficient to traverse the parts of the body and to "blit" each part:
class Snake(object):
# [...]
def draw_snake(self):
for snake_segment in self.body:
snake_segment.blit()
Related
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.
This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
The sprite is just stuck in the top left corner. It moves sligthly when pressing "wasd".
I am trying to make a simple clone of Mayhem/xPilot. A 2 player game where there are 2 rockets that can shoot eachother down.
I am fairly new to coding and python, I would be gratefull if you could ELI5.
Has anyone else had this problem?
import pygame as pg
import sys
x, y = 0, 0
class Rocket(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_w = False
self.pressed_a = False
self.pressed_s = False
self.pressed_d = False
self.speed = 3
self.gravity = False
def update(self):
self.rect.x = 0
self.rect.y = 0
if self.pressed_a and self.rect.left > 0:
self.rect.x = self.speed
if self.pressed_d and self.rect.right < width:
self.rect.x = self.speed
if self.pressed_s and self.rect.bottom < height:
self.rect.y = self.speed
if self.pressed_w and self.rect.top > 0:
self.rect.y = -self.speed
if self.gravity and self.rect.bottom < height:
self.rect.y = self.speed
self.rect.x += x
self.rect.y += y
pg.init()
clock = pg.time.Clock()
width = 1920
height = 1080
screen = pg.display.set_mode((width, height))
background = pg.image.load("bg.jpg")
#rocket
player_rect = Rocket("rocket.png", x, y)
rocket_group = pg.sprite.Group()
rocket_group.add(player_rect)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_rect.pressed_w = True
player_rect.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_s:
player_rect.pressed_s = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player_rect.pressed_d = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
player_rect.pressed_a = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
player_rect.pressed_w = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_s:
player_rect.pressed_s = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_d:
player_rect.pressed_d = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_a:
player_rect.pressed_a = False
player_rect.gravity = True
pg.display.flip()
screen.blit(background, (0, 0))
rocket_group.draw(screen)
rocket_group.update()
clock.tick(120)
The problem is in the update method. The method has to change the coordinates of the rect attribute. However, your method continuously sets self.rect.x = 0 and self.rect.y = 0.
Change update:
class Rocket(pg.sprite.Sprite):
# [...]
def update(self):
if self.pressed_a:
self.rect.x -= self.speed
if self.pressed_d
self.rect.x += self.speed
if self.pressed_w
self.rect.y -= self.speed
if self.pressed_s
self.rect.y += self.speed
if self.gravity
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height
I'm doing a snake game and I got a bug I can't figure out how to solve, I want to make my snake teleport trough walls, when the snake colllides with a wall it teleports to another with the opposite speed and position, like the classic game, but with my code when the snake gets near the wall it duplicates to the opposite wall, but it was supposed to not even detect collision yet
important thing: in the grid the snake is on the side of the wall, like this
SSSS
WWWW
and not like this:
SSSS
NNNN
WWWW
when S represents the snake, W represents the wall and N represents nothing.
edit: whole code
import pygame, random, os, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1020, 585))
pygame.display.set_caption('2snakes!')
#files location
current_path = os.path.dirname(__file__)
data_path = os.path.join(current_path, 'data')
icon = pygame.image.load(os.path.join(data_path, 'icon.png'))
press_any = pygame.image.load(os.path.join(data_path, 'press_any.png'))
pygame.display.set_icon(icon)
#collission
def collision(c1,c2):
return (c1[0] == c2[0]) and (c1[1] == c2[1])
#game over
def gameOverBlue():
print("blue")
main()
def gameOverRed():
print("red")
main()
fps = 15
def main():
#variables
direction = 'RIGHT'
direction2 = 'RIGHT'
change_to = direction
change2_to = direction2
#snake
size = 15
s_posx = 60
s_posy = 60
snake = [(s_posx + size * 2, s_posy),(s_posx + size, s_posy),(s_posx, s_posy)]
s_skin = pygame.Surface((size, size))
s_skin.fill((82,128,208))
#snake2
size2 = 15
s2_posx = 390
s2_posy = 390
snake2 = [(s2_posx + size2 * 2, s2_posy),(s2_posx + size2, s2_posy),(s2_posx, s2_posy)]
s2_skin = pygame.Surface((size2, size2))
s2_skin.fill((208,128,82))
#apple
apple = pygame.Surface((size, size))
apple_pos = ((random.randint(0, 67)) * 15, (random.randint(0, 38)) * 15)
#endregion
while True:
pygame.time.Clock().tick(fps)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
#input
elif event.type == pygame.KEYDOWN:
#snake
if event.key == ord('w'):
change_to = 'UP'
if event.key == ord('s'):
change_to = 'DOWN'
if event.key == ord('a'):
change_to = 'LEFT'
if event.key == ord('d'):
change_to = 'RIGHT'
#snake2
if event.key == pygame.K_UP:
change2_to = 'UP'
if event.key == pygame.K_DOWN:
change2_to = 'DOWN'
if event.key == pygame.K_LEFT:
change2_to = 'LEFT'
if event.key == pygame.K_RIGHT:
change2_to = 'RIGHT'
#quit game
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.quit()
#smoot snake movement
#snake
if change_to == 'UP' and direction != 'DOWN':
direction = 'UP'
if change_to == 'DOWN' and direction != 'UP':
direction = 'DOWN'
if change_to == 'LEFT' and direction != 'RIGHT':
direction = 'LEFT'
if change_to == 'RIGHT' and direction != 'LEFT':
direction = 'RIGHT'
#snake2
if change2_to == 'UP' and direction2 != 'DOWN':
direction2 = 'UP'
if change2_to == 'DOWN' and direction2 != 'UP':
direction2 = 'DOWN'
if change2_to == 'LEFT' and direction2 != 'RIGHT':
direction2 = 'LEFT'
if change2_to == 'RIGHT' and direction2 != 'LEFT':
direction2 = 'RIGHT'
#movement
#snake
new_pos = None
if direction == 'DOWN':
new_pos = (snake[0][0], snake[0][1] + size)
if direction == 'UP':
new_pos = (snake[0][0], snake[0][1] - size)
if direction == 'LEFT':
new_pos = (snake[0][0] - size, snake[0][1])
if direction == 'RIGHT':
new_pos = (snake[0][0] + size, snake[0][1])
if new_pos:
snake = [new_pos] + snake
del snake[-1]
#snake2
new_pos2 = None
if direction2 == 'DOWN':
new_pos2 = (snake2[0][0], snake2[0][1] + size2)
if direction2 == 'UP':
new_pos2 = (snake2[0][0], snake2[0][1] - size2)
if direction2 == 'LEFT':
new_pos2 = (snake2[0][0] - size2, snake2[0][1])
if direction2 == 'RIGHT':
new_pos2 = (snake2[0][0] + size2, snake2[0][1])
if new_pos2:
snake2 = [new_pos2] + snake2
del snake2[-1]
#apple collision
#snake
if collision(snake[0], apple_pos):
snake.append((-20,-20))
size = 15
s_skin = pygame.Surface((size, size))
s_skin.fill((82,128,208))
apple_pos = ((random.randint(0, 32)) * 15, (random.randint(0, 19)) * 15)
#snake2
if collision(snake2[0], apple_pos):
snake2.append((-20,-20))
apple_pos = ((random.randint(0, 67)) * 15, (random.randint(0, 38)) * 15)
#wall collisison
#snake
_pos = None
if snake[0][0] == 15:
_pos = (990, snake[0][1])
elif snake[0][1] == 15:
_pos = (snake[0][0], 555)
elif snake[0][0] == 990:
_pos = (15, snake[0][1])
elif snake[0][1] == 555:
_pos = (snake[0][0], 15)
if _pos:
snake = [_pos] + snake
del snake[-1]
#snake2
_pos2 = None
if snake2[0][0] == 15:
_pos2 = (1005, snake2[0][1])
elif snake2[0][1] == 0:
_pos2 = (snake2[0][0], 570)
elif snake2[0][0] == 1005:
_pos2 = (0, snake2[0][1])
elif snake2[0][1] == 570:
_pos2 = (snake2[0][0], 0)
if _pos2:
snake2 = [_pos2] + snake2
del snake2[-1]
#self collisison
#snake
if snake[0] in snake[1:]:
print("self collision")
gameOverBlue()
#snake2
if snake2[0] in snake2[1:]:
print("self collision")
gameOverRed()
#snakes colliding with each other
if snake2[0] == snake[0]:
print("head to head collisions")
if snake[0] in snake2:
gameOverRed()
if snake2[0] in snake:
gameOverBlue()
#rendering
apple.fill((255,0,0))
screen.fill((10,10,10))
screen.blit(apple,apple_pos)
for pos in snake:
screen.blit(s_skin,pos)
for pos2 in snake2:
screen.blit(s2_skin,pos2)
pygame.display.update()
while True:
pygame.time.Clock().tick(fps)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
#input
elif event.type == pygame.KEYDOWN:
main()
screen.blit(press_any, (0,0))
pygame.display.update()
edit: the red dot is the food/apple
You want to implement a teleporter. Therefore, once the snake is over the edge of the window, you will have to teleport to the other side. The size of your window is 1020x585. The snake is out of the window if x == -15, y == -15, x == 1020 or y == 585 Hence you have to do the following teleportations:
if x = 1020 teleport to x = 0
if x = -15 teleport to x = 1005
if y = 585 teleport to y = 0
if y = -15 teleport to y = 570
_pos = None
if snake[0][0] == -15:
_pos = (1005, snake[0][1])
elif snake[0][1] == -15:
_pos = (snake[0][0], 570)
elif snake[0][0] == 1020:
_pos = (0, snake[0][1])
elif snake[0][1] == 585:
_pos = (snake[0][0], 0)
if _pos:
snake = [_pos] + snake
del snake[-1]
I'm trying to code my first game with Python and Pygame. I'm fairly new to Python and coding in general, so I'm sorry if my code is hard to read.
There are 4 circles, moving from the middle of the screen to the 4 edges.
I'm dropping cubes (enemies) from the 4 edges to the middle. The goal is to stop those cubes from reaching the middle of the screen, by pressing keyboard arrows. I
Now I'm working on the logic of lifes. The player has 5 lifes.
If an enemy reaches the middle of the screen, the player loses a life. I got this part.
The player also loses a life when he misscliks. I'm struggling with this part.
I can see a few scenario. Let's say that the player clicks LEFT:
There are no enemies on the left side --> he loses a life
There is 1 enemy on the left side, but there is no collision --> he loses a life
There are more than 1 enemy on the left side, and he click on one enemy. Right now, the player loses a life per enemy outside the circle even though he clicked right. I can't figure out a way to solve this issue. I solved the 2 scenarios above.
Any idea ?
Here's my code.
# ---------- Packages and Inits ----------
import pygame, random, math
pygame.init()
# ---------- Settings ----------
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
FPS = 60
SPEED = 1
SPEED_ENEMIES = 0.5
CIRCLE_RADIUS = 50
ENEMY_SIZE = 40
red = (255,000,000)
blue = (000,000,255)
yellow = (255,255,000)
green = (000,128,000)
pink = (255,192,203)
black = (000,000,000)
# ---------- Classes ----------
class Enemies:
def __init__(self, x, y, size=ENEMY_SIZE, thick=5, color=blue, speed=SPEED_ENEMIES, position="top"):
self.rect = pygame.Rect(0, 0, size, size)
if ( x == 0 and y == 0 ):
self.randomise()
self.rect.centerx = x
self.rect.centery = y
self.size = size
self.thick = thick
self.color = color
self.speed = speed
self.calcDirection()
self.position = position
def calcDirection( self ):
self.x_float = 1.0 * self.rect.centerx
self.y_float = 1.0 * self.rect.centery
# Determine direction vector from (x,y) to the centre of the screen
self.position_vector = pygame.math.Vector2( self.x_float, self.y_float )
self.velocity_vector = pygame.math.Vector2( SCREEN_WIDTH/2 - self.x_float, SCREEN_HEIGHT/2 - self.y_float )
self.velocity_vector = self.velocity_vector.normalize()
def update( self ):
x_delta = self.speed * self.velocity_vector[0]
y_delta = self.speed * self.velocity_vector[1]
self.x_float += x_delta
self.y_float += y_delta
self.rect.centerx = int( self.x_float )
self.rect.centery = int( self.y_float )
def draw(self, screen):
pygame.draw.rect(screen, self.color, self.rect )
def reachedPoint( self, x, y ):
return self.rect.collidepoint( x, y )
def randomise( self ):
self.rect.centerx = SCREEN_WIDTH//2
self.rect.centery = SCREEN_HEIGHT//2
side = random.randint( 0, 4 )
if ( side == 0 ):
self.rect.centery = SCREEN_HEIGHT
self.color = green
self.position= "bot"
elif ( side == 1 ):
self.rect.centery = 0
self.color = yellow
self.position= "top"
elif ( side == 2 ):
self.rect.centerx = 0
self.color = blue
self.position= "left"
else:
self.rect.centerx = SCREEN_WIDTH
self.color = red
self.position= "right"
self.calcDirection()
class Circle:
def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=blue, speed=SPEED, position="top"):
self.rect = pygame.Rect(0, 0, 2*radius, 2*radius)
self.rect.centerx = x
self.rect.centery = y
self.radius = radius
self.thick = thick
self.color = color
self.speed = speed
self.position = position
if speed >= 0:
self.directionX = 'right'
self.direction = 'up'
else:
self.directionX = 'left'
self.direction = 'down'
def draw(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.radius, self.thick)
def swing(self):
if self.position == "top":
self.rect.y -= self.speed
if self.rect.top <= 0 and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
elif self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
if self.position == "bot":
self.rect.y -= self.speed
if self.rect.top < int(SCREEN_HEIGHT/2) + self.radius and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
elif self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
if self.position == "left":
self.rect.x -= self.speed
if self.rect.right > int(SCREEN_WIDTH/2) - self.radius and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
elif self.rect.left <= 0 and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
if self.position == "right":
self.rect.x -= self.speed
if self.rect.left < int(SCREEN_WIDTH/2) + self.radius and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
elif self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
def isCollision(self, enemyX, enemyY, circleX, circleY):
distance = math.sqrt((math.pow(enemyX-circleX,2))+(math.pow(enemyY-circleY,2)))
if distance < 65:
return True
else:
return False
# ---------- Main ----------
def main():
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
clock = pygame.time.Clock()
game_over = False
lifes = 5
score = 0
myFont = pygame.font.SysFont("monospace", 25)
# Start with 4 enemies
all_enemies = [
Enemies(int(SCREEN_WIDTH/2) , 0 , color = yellow, position = "top"),
Enemies(int(SCREEN_WIDTH/2) , SCREEN_HEIGHT-ENEMY_SIZE, color = green , position = "bot"),
Enemies(0 ,int(SCREEN_HEIGHT/2) , color = blue , position = "left"),
Enemies(SCREEN_WIDTH-ENEMY_SIZE, int(SCREEN_HEIGHT/2) , color = red , position = "right")
]
# Start with 4 circles
all_circles = [
Circle(screen_rect.centerx, screen_rect.centery - 2*CIRCLE_RADIUS, position="top"),
Circle(screen_rect.centerx, screen_rect.centery + 2*CIRCLE_RADIUS, position="bot"),
Circle(screen_rect.centerx + 2*CIRCLE_RADIUS, screen_rect.centery, position="right"),
Circle(screen_rect.centerx - 2*CIRCLE_RADIUS, screen_rect.centery, position="left")
]
while not game_over:
screen.fill(black)
# Reference enemy lists
left_enemies = [x for x in all_enemies if x.position == "left"]
right_enemies = [x for x in all_enemies if x.position == "right"]
top_enemies = [x for x in all_enemies if x.position == "top"]
bot_enemies = [x for x in all_enemies if x.position == "bot"]
# Place and swing 4 circles (the player)
for c in all_circles:
c.draw(screen)
c.swing()
# The enemy reaches the middle
for e in all_enemies:
e.update()
if ( e.reachedPoint( SCREEN_WIDTH//2, SCREEN_HEIGHT//2 ) ):
lifes -=1
e.randomise()
e.draw( screen )
# Score points with keyboard arrow
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
for c in all_circles:
if event.type == pygame.KEYDOWN:
# LEFT
if event.key == pygame.K_LEFT and c.position == "left":
if not left_enemies :
lifes -=1
for e in left_enemies:
collision = c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)
if e.position == "left" and collision == True :
score +=1
e.randomise()
else:
lifes -=1
# RIGHT
if event.key == pygame.K_RIGHT and c.position == "right":
if not right_enemies :
lifes -=1
for e in right_enemies:
collision = c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)
if e.position == "right" and collision == True :
score +=1
e.randomise()
else:
lifes -=1
# TOP
if event.key == pygame.K_UP and c.position == "top":
if not top_enemies :
lifes -=1
for e in top_enemies:
collision = c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)
if e.position == "top" and collision == True :
score +=1
e.randomise()
else:
lifes -=1
# BOT
if event.key == pygame.K_DOWN and c.position == "bot":
if not bot_enemies :
lifes -=1
for e in bot_enemies:
collision = c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)
if e.position == "bot" and collision == True :
score +=1
e.randomise()
else:
lifes -=1
print_lifes = myFont.render("Lifes:" + str(lifes), 1, red)
screen.blit(print_lifes, (10, SCREEN_HEIGHT-50))
print_score = myFont.render("Score:" + str(score), 1, red)
screen.blit(print_score, (10, 10))
pygame.display.update()
clock.tick(FPS)
main()
pygame.quit()
Your rules can be broken down to one simply rule:
If the player presses a key, look if there's an enemy under the circle.
So on KEYDOWN, filter the enemy list for all enemies that collide with the circle and just check if the number is > 0.
Replace your checks/loops:
if not left_enemies:
lifes -=1
for e in left_enemies:
collision = c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)
if e.position == "left" and collision == True :
score +=1
e.randomise()
else:
lifes -=1
with something like this:
hits = [e for e in left_enemies if c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery) and position == "left"]
if not hits:
lifes -=1
for e in hits:
score +=1
e.randomise()
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.