how to make collision in flappybird? - python

Ok, so I need to make a collision between the two pillars to the bird player. Sorry if the code is complicated, I am new to programming.
In the code, there are two pillars that move left and repeat.
I did xpos2, ypos2, xpos, ypos because there are 2 pillars at one moment.
The gap between them is 670 because the picture of the pillars is very big,
so I drew them very high or low - you can't see all the pillar.
What I need to make a collision between each pillar (top or bottom) to the bird.
I tried with colliderect and another pygame func without success.
Thank you.
code
import pygame
import random
size = [900, 504]
wait = pygame.time.Clock()
red = (255, 0, 0)
pygame.init()
class game:
def __init__(self):
self.screen = pygame.display.set_mode((size[0], size[1]))
pygame.display.set_caption("Flappy Bird #yuv")
self.background = pygame.image.load(r"d:\Users\Student\Desktop\background.png").convert()
self.top_pillar = pygame.image.load(r"d:\Users\Student\Desktop\top.png").convert()
self.bottom_pillar = pygame.image.load(r"d:\Users\Student\Desktop\bottom.png").convert()
self.done = False
self.xpos = 400 # XPOS OF THE PILLARS
self.xpos2 = 800 #
self.ypos_top = random.randint(-400, -200) # ypos of the pillar - top
self.ypos_bottom = self.ypos_top + 670 # ypos of the pillar - bottom
self.ypos2_top = random.randint(-400, -200) # ypos of the pillar - bottom
self.ypos2_bottom = self.ypos2_top + 670 # ypos of the pillar - bottom
self.score = 0
def pillars(self):
for i in range(5):
self.xpos -= 1
self.xpos2 -= 1
if self.xpos <= 0:
self.xpos = 800
self.ypos_top = random.randint(-400, -200) # ypos of the pillar - top
self.ypos_bottom = self.ypos_top + 670 # ypos of the pillar - bottom
if self.xpos2 <= 0:
self.xpos2 = 800
self.ypos2_top = random.randint(-400, -200) # ypos of the pillar - bottom
self.ypos2_bottom = self.ypos2_top + 670 # ypos of the pillar - bottom
# def collide(self):
## how the hell i do it ! ? ?! ?! ?! ?!
def scoregame(self):
if bird().x > self.xpos or bird().x > self.xpos2:
self.score += 1
myfont = pygame.font.SysFont('Comic Sans MS', 30)
textsurface = myfont.render('score : ' + str(int(self.score / 39)), True, red)
self.screen.blit(textsurface, (0, 0))
def gameover(self):
font = pygame.font.SysFont(None, 55)
text = font.render("Game Over!", False, red)
self.screen.blit(text, [100, 250])
self.done = True
class bird:
def __init__(self):
self.x = 200
self.y = 350
self.bird = pygame.image.load(r"d:\Users\Student\Desktop\player.png").convert_alpha()
def move_bird(self):
wait.tick(20)
for i in range(3):
self.y += 2
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
for i in range(50):
self.y -= 1
def check_obstacle(self):
if self.y > 478 or self.y < -10: # check if the player touch the top or the bottom of the screen
print('3')
Game.gameover()
Game = game()
birdfunc = bird()
while Game.done == False:
Game.screen.blit(Game.background, (0, 0))
Game.screen.blit(birdfunc.bird, (birdfunc.x, birdfunc.y))
birdfunc.move_bird()
birdfunc.check_obstacle()
Game.screen.blit(Game.top_pillar, (
Game.xpos, Game.ypos_bottom)) # ypos -500 is the start of the top between -400 to -200 XXXXX gap- 200
Game.screen.blit(Game.bottom_pillar, (Game.xpos, Game.ypos_top)) # ypos 500 is the start of the bottom
Game.screen.blit(Game.top_pillar, (Game.xpos2, Game.ypos2_bottom)) # ypos -500 is the start of the top between -400 to -200 XXXXX gap- 200
Game.screen.blit(Game.bottom_pillar, (Game.xpos2, Game.ypos2_top)) # ypos 500 is the start of the bottom
Game.scoregame()
Game.pillars()
pygame.display.flip()
while Game.done == True:
Game.screen.blit(Game.background, (0, 0))
Game.gameover()

You're already pretty close... I see that you've got code for collisions with the top and bottom of the screen already written. You don't need a library to do simple collision handling between objects either, in this case you can probably write your own algorithm.
def check_obstacle(self):
if self.y > 478 or self.y < -10: # check if the player touch the top or the bottom of the screen
print('3')
Game.gameover()
How might you modify this to make the bird collide with pillars?
Here's my initial thought: The pillar edges could be simplified to different values of self.y, so if the bird is outside the range of valid y values in-between the pillars when the pillar goes by (do you have a pillar.x?), it should call Game.gameover(). Drawing a picture and labeling it with coordinates on paper might help you work out the math.

Related

Trying to get actor to wrap around screen (go from one side to the other at edge of screen) also trying to get animation to work:

import pgzrun
import pygame
WIDTH = 850
HEIGHT = 425
#sprites
title = Actor('title.png') #calling sprites and saying their pos
title.pos = 400, 212
cont = Actor('cont.png')
cont.pos = 470, 300
player = Actor('ship.png')
player.pos = 100, 56
foe = Actor('foe.png')
foe.pos = 200, 112
vel = 5
music.play("temp.mp3")
#controls
def draw():
screen.clear()
screen.fill((0, 0, 0))
title.draw()
cont.draw()
foe.draw()
player.draw()
def update():
keys = pygame.key.get_pressed()
x, y = player.pos
x += (keys[pygame.K_d] - keys[pygame.K_a]) * vel
y += (keys[pygame.K_s] - keys[pygame.K_w]) * vel
player.pos = x, y
if player.left > WIDTH: #if player hits right side of screen it takes the player to the other side of the screen
player.right = 0
def otherimage(): #animation of ship
player.image = 'ship.png'
imagey()
def imagey():
player.image = 'ship1.png'
clock.schedule_unique(otherimage, 1.0)
imagey()
pgzrun.go()
the animation section is the bit commented with "animation of ship". The wrapping bit is the bit labled "if player hits right side of screen it takes the player to the other side of the screen" as you can see i have go it working when the player hits the screen on the right side but every time i have tried getting it to work on the other sides it doesn't work. Please help! Thanks! Im new to coding and i am trying to understand this language. thanks again.

Adding infinite number of obstacles in pygame

i am trying to make a flappy bird game in pygame for school but i am struggling with adding the obstacles. I can add one obstacle but i want to add infinite obstacles and i already have an infinite loop to run my game so when i add an extra infinite, loop my game just crashes. I am using a time.sleep() function when add the obstacle in my infinite loop which makes the game crash.
This is my code so far:
import time
import pygame
pygame.init()
xSpeler = 450
ySpeler = 100
widthSpeler = 40
heightSpeler = 40
vel = 10
vel1 = 10
#obstacle 1
xo1 = 900
yo1 = 0
ho1 = 200
wo1 = 50
xo2 = 900
yo2 = 350
ho2 = 200
wo2 = 50
#obstacle 2
xo3 = 900
yo3 = 0
ho3 = 250
wo3 = 50
xo4 = 900
yo4 = 350
ho4 = 150
wo4 = 50
win = pygame.display.set_mode((1000, 500))
bi = pygame.image.load('bada.png')
pygame.display.flip()
run = True
while run:
win.blit(bi, (0, 0))
pygame.time.delay(1)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
ySpeler += vel
if ySpeler >= 500 - heightSpeler:
ySpeler = 500 - heightSpeler
xo1 -= vel1
xo2 -= vel1
if keys[pygame.K_SPACE] and xSpeler> vel and ySpeler > 0:
ySpeler -= jump
pygame.draw.rect(win, (255, 0, 0), (xSpeler, ySpeler, widthSpeler, heightSpeler))
for x in range(100):
pygame.draw.rect(win, (0, 255, 0), (xo1, yo1, wo1, ho1)) or pygame.draw.rect(win, (0, 255, 0),(xo1, yo1, wo1, ho1))
pygame.draw.rect(win, (0, 255, 0), (xo2, yo2, wo2, ho2)) or pygame.draw.rect(win, (0, 255, 0),(xo2, yo2, wo2, ho2))
time.sleep(7)
pygame.display.update()
im came from netherland so my inglish is not so good and my variables are in dutch so sorry for it
i realy hope someone can help me.
Your screen stays black because of time.sleep(7). It is in a for loop that iterate 100 times so that's your program sleeping 700 seconds every frame. To make an obstacle, make a function that generates and returns 2 obstacles, one for top and the other one for bottom.
def genObstacle():
# generate and return
#1. pygame surface for top and bottom rects
#2. initial position for top rect and bottom rect
topHeight = random.randint(10, 200) # height for bottom obstacle
botHeight = random.randint(10, 200) # height for top obstacle
top = pygame.Surface((10, topHeight)).convert()
bot = pygame.Surface((10, botHeight)).convert()
# return: top rect, bottom rect, top rect's position, bottom rect's position
return [top, bot, [800, 0], [800, 500-botHeight]]
Return the initial positions for both of the obstacles as well, so it is easier to work with. I would really recommend using a class for obstacle, so working with attributes of obstacles like position is easier.
Now that we have a function to generate obstacle, we can make a list to hold those obstacles obstacles = []. Now, we can generate the obstacles every 3 seconds like this:
#other code
start = time.time()
while True:
#other code
now = time.time()
if now - start > 3:
obstacles.append(genObstacle())
start = now
Now that we have obstacles, we can change draw them and change their values like this:
for i in range(len(obstacles)):
# remember, third item in list is position for top and
# fourth item is the position for bottom
# draw the obstacles
win.blit(obstacles[i][0], (obstacles[i][2][0], obstacles[i][3][1]))
win.blit(obstacles[i][1], (obstacles[i][2][0], obstacles[i][3][1]))
# change the x values for it to move to the right
obstacles[i][2][0] -= 1
obstacles[i][2][0] -= 1

PyGame Window not starting

I created this simple snake game a while ago and I wanted to try running it and for some reason the window is not starting on my machine. I am sure the code was working before. I tried debugging for a while but can't seem to figure out why I am stuck on a black screen. It seems to detect a key pressed but nothing is displayed on the screen.
import pygame
from pygame.locals import *
import random
# Global Color Variables
RED = (255, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
CYAN = (0,255, 255)
# Set the speed of the Snake --> lower = faster
timeDelaySpeed = 0
class App:
def __init__(self):
self._running = True
self._display_surf = None
self.size = self.weight, self.height = 600, 700
# create the boarder
self.boarder = self.generateBoard()
# Initial Snake array with 3 Snake Blocks starting at (50, 50) and going left
self.snake = [Snake(WHITE, 10, 10, 150, 260), Snake(WHITE, 10, 10, 140, 260), Snake(WHITE, 10, 10, 130, 260)]
def on_init(self):
pygame.init()
self._display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self._display_surf.fill(BLACK)
self._running = True
# Create Score Board
self.score = 0
self.displayScore(self.score, 45)
# Create Initial Food
self.initFood = Food(RED, 10, 10)
self._display_surf.blit(self.initFood.image, self.initFood.rect)
# display the initial Snake array
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
# display the board
for i in range(len(self.boarder)):
self._display_surf.blit(self.boarder[i].image, self.boarder[i].rect)
pygame.display.update()
"""
Helper Method that will run the events that are clicked on by the user
"""
def on_event(self):
# Checks if Snake crashes with itself - LOSE
for i in range(1, len(self.snake)):
if pygame.sprite.collide_rect(self.snake[0], self.snake[1]):
self.spaceToRestartText(20)
self.gameRestart()
if pygame.sprite.collide_rect(self.snake[0], self.snake[i]):
self.spaceToRestartText(20)
self.gameRestart()
# Check if Snake hits the boarder - LOSE
for i in range(len(self.boarder)):
if pygame.sprite.collide_rect(self.snake[0], self.boarder[i]):
self.spaceToRestartText(20)
self.gameRestart()
# Checks if Snake eats Food
if pygame.sprite.collide_rect(self.snake[0], self.initFood):
self.eatFood()
# set the direction based of key that is pressed
for event in pygame.event.get():
if event.type == pygame.QUIT:
self._running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
# check for self collision before eating any food - weird collision method error fix
if self.move == 'right':
self.spaceToRestartText(20)
self.gameRestart()
break
self.move = 'left'
if event.key == pygame.K_RIGHT:
# check for self collision before eating any food
if self.move == 'left':
self.spaceToRestartText(20)
self.gameRestart()
break
self.move = 'right'
if event.key == pygame.K_UP:
# check for self collision before eating any food
if self.move == 'down':
self.spaceToRestartText(20)
self.gameRestart()
break
self.move = 'up'
if event.key == pygame.K_DOWN:
# check for self collision before eating any food
if self.move == 'up':
self.spaceToRestartText(20)
self.gameRestart()
break
self.move = 'down'
# if stored current direction is right
if self.move == 'right':
print("RIGHT")
# Reset the Board
self.boardReset()
# Store the current head of the snake
snakeHead = self.snake[0]
# remove the last block of the snake
self.snake.pop()
# create a new head for the snake that is shifted toward the right
newHead = snakeHead.moveRight()
# add the newly created head to the front of the list - make head
self.snake.insert(0, newHead)
# displays moved snake
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
pygame.display.update()
pygame.time.delay(timeDelaySpeed)
# if stored current direction is left
if self.move == 'left':
print("LEFT")
# Reset the Board
self.boardReset()
# Store the current head of the snake
snakeHead = self.snake[0]
# remove the last block of the snake
self.snake.pop()
# create a new head for the snake that is shifted toward the right
newHead = snakeHead.moveLeft()
# add the newly created head to the front of the list - make head
self.snake.insert(0, newHead)
# displays moved snake
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
pygame.display.update()
pygame.time.delay(timeDelaySpeed)
# if stored current direction is up
if self.move == 'up':
print("UP")
# Reset the Board
self.boardReset()
# Store the current head of the snake
snakeHead = self.snake[0]
# remove the last block of the snake
self.snake.pop()
# create a new head for the snake that is shifted toward the right
newHead = snakeHead.moveUp()
# add the newly created head to the front of the list - make head
self.snake.insert(0, newHead)
# displays moved snake
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
pygame.display.update()
pygame.time.delay(timeDelaySpeed)
# if stored current direction is down
if self.move == 'down':
print("DOWN")
# Reset the Board
self.boardReset()
# Store the current head of the snake
snakeHead = self.snake[0]
# remove the last block of the snake
self.snake.pop()
# create a new head for the snake that is shifted toward the right
newHead = snakeHead.moveDown()
# add the newly created head to the front of the list - make head
self.snake.insert(0, newHead)
# displays moved snake
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
pygame.display.update()
pygame.time.delay(timeDelaySpeed)
"""
Helper method that displays the current score on the screen.
"""
def displayScore(self, score, size):
font = pygame.font.SysFont("Comic Sans MS", size)
ScoreBoard = font.render("SCORE: {}".format(score), False, (WHITE))
self._display_surf.blit(ScoreBoard, [90, 100])
pygame.display.update()
"""
Helper method that will reset the screen:
Make screen Black
Add the current Food block
Add the current Score
"""
def boardReset(self):
# Erases the current screen
self._display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self._display_surf.fill(BLACK)
# Create Score Board
self.displayScore(self.score, 45)
# Add Food
self._display_surf.blit(self.initFood.image, self.initFood.rect)
# Add Boarder
for i in range(len(self.boarder)):
self._display_surf.blit(self.boarder[i].image, self.boarder[i].rect)
"""
Eating food helper method
"""
def eatFood(self):
# Create a new Food at random location and display it
self.initFood = Food(RED, 10, 10)
self._display_surf.blit(self.initFood.image, self.initFood.rect)
# Create Score Board
self.score += 1
self.displayScore(self.score, 45)
# for i in range(len(self.snake)):
# self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
#
# Store the last and second to last blocks of the snake
lastSnakeBlock = self.snake[-1]
secondToLastBlock = self.snake[-2]
# if the last two blocks are on the same horizontal line and the last block is to the left of the
# second to last block, add a block to the left side of the last block
if lastSnakeBlock.rect.y == secondToLastBlock.rect.y and lastSnakeBlock.rect.x < secondToLastBlock.rect.x:
newX = lastSnakeBlock.rect.x - 10
newSnakeBlock = Snake(lastSnakeBlock.color, lastSnakeBlock.width, lastSnakeBlock.height, newX,
lastSnakeBlock.rect.y)
self.snake.append(newSnakeBlock)
# if the last two blocks are on the same horizontal line and the last block is to the right of the
# second to last block, add a block to the right side of the last block
if lastSnakeBlock.rect.y == secondToLastBlock.rect.y and lastSnakeBlock.rect.x > secondToLastBlock.rect.x:
newX = lastSnakeBlock.rect.x + 10
newSnakeBlock = Snake(lastSnakeBlock.color, lastSnakeBlock.width, lastSnakeBlock.height, newX,
lastSnakeBlock.rect.y)
self.snake.append(newSnakeBlock)
# if the last two blocks are on the same vertical line and the last block is above the
# second to last block, add a block above the last block
if lastSnakeBlock.rect.x == secondToLastBlock.rect.x and lastSnakeBlock.rect.y < secondToLastBlock.rect.y:
newY = lastSnakeBlock.rect.y - 10
newSnakeBlock = Snake(lastSnakeBlock.color, lastSnakeBlock.width, lastSnakeBlock.height,
lastSnakeBlock.rect.x, newY)
self.snake.append(newSnakeBlock)
# if the last two blocks are on the same vertical line and the last block is below the
# second to last block, add a block below the last block
if lastSnakeBlock.rect.x == secondToLastBlock.rect.x and lastSnakeBlock.rect.y > secondToLastBlock.rect.y:
newY = lastSnakeBlock.rect.y + 10
newSnakeBlock = Snake(lastSnakeBlock.color, lastSnakeBlock.width, lastSnakeBlock.height,
lastSnakeBlock.rect.x, newY)
self.snake.append(newSnakeBlock)
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
"""
Takes the player back to initial start state
"""
def gameRestart(self):
# Erase the Board
self._display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self._display_surf.fill(BLACK)
self._running = True
# Recreate the Snake
self.snake = [Snake(WHITE, 10, 10, 150, 260), Snake(WHITE, 10, 10, 140, 260), Snake(WHITE, 10, 10, 130, 260)]
# Create Score Board
self.score = 0
self.displayScore(self.score, 45)
# Create Initial Food
self.initFood = Food(RED, 10, 10)
self._display_surf.blit(self.initFood.image, self.initFood.rect)
# set current move to nothing
self.move = ''
# draw in the boarder
for i in range(len(self.boarder)):
self._display_surf.blit(self.boarder[i].image, self.boarder[i].rect)
# display the initial Snake array
for i in range(len(self.snake)):
self._display_surf.blit(self.snake[i].image, self.snake[i].rect)
pygame.display.update()
"""
Creates a List of Blocks that outline the Boarder of the snake game
"""
def generateBoard(self):
boardCorners = []
boardTop = []
boardSide1 = []
boardSide2 = []
boardBottom = []
# Makes (0,0) of board = (100, 210)
# top left corner
boardCorners.append(Snake(CYAN, 10, 10, 90, 200))
# top right corner
boardCorners.append(Snake(CYAN, 10, 10, 500, 200))
# bottom left corner
boardCorners.append(Snake(CYAN, 10, 10, 90, 610))
# bottom right corner
boardCorners.append(Snake(CYAN, 10, 10, 500, 610))
# top and bottom sides
topCoord = 100
for i in range(40):
boardTop.append(Snake(CYAN, 10, 10, topCoord, 200))
boardBottom.append(Snake(CYAN, 10, 10, topCoord, 610))
topCoord += 10
# sides of board
sideCoord = 210
for i in range(40):
boardSide1.append(Snake(CYAN, 10, 10, 90, sideCoord))
boardSide2.append(Snake(CYAN, 10, 10, 500, sideCoord))
sideCoord += 10
# combine all parts
allBoarder = boardCorners + boardTop + boardSide1 + boardSide2 + boardBottom
# return list of blocks
return allBoarder
"""
Allows player to restart a game by pressing space bar - displays losing screen
"""
def spaceToRestartText(self, size):
self._display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self._display_surf.fill(BLACK)
self.youLoseText(50)
self.yourScoreText(25)
font = pygame.font.SysFont("Comic Sans MS", size)
text_surface = font.render("Press space bar to play again", True, WHITE)
text_rect = text_surface.get_rect(center=(self.weight / 2, self.height / 2))
self._display_surf.blit(text_surface, text_rect)
pygame.display.flip()
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
done = True
"""
Helper function that prints 'YOU LOSE!'
"""
def youLoseText(self, size):
font = pygame.font.SysFont("Comic Sans MS", size)
text_surface = font.render("YOU LOSE!", True, WHITE)
# Shift height up so no collision with space bar text
text_rect = text_surface.get_rect(center=(self.weight / 2, (self.height / 2) - 75))
self._display_surf.blit(text_surface, text_rect)
pygame.display.flip()
"""
Helper function that prints your score at loss
"""
def yourScoreText(self, size):
font = pygame.font.SysFont("Comic Sans MS", size)
text_surface = font.render("Your Score was: " + str(self.score), True, WHITE)
# Shift height up so no collision with space bar text
text_rect = text_surface.get_rect(center=(self.weight / 2, (self.height / 2) - 35))
self._display_surf.blit(text_surface, text_rect)
pygame.display.flip()
def on_loop(self):
pass
def on_render(self):
pass
def on_cleanup(self):
pygame.quit()
"""
Game Loop
"""
def on_execute(self):
if self.on_init() == False:
self._running = False
self.move = ''
while (self._running):
self.on_event()
self.on_loop()
self.on_render()
self.on_cleanup()
"""
Class to create a Food at a random coordinate
"""
class Food(pygame.sprite.Sprite):
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(color)
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
# set the position of the Food
# TODO: change values in randint to use the input width and height
randX = random.randint(10,49) * 10
randY = random.randint(21,60) * 10
self.rect.x = randX
self.rect.y = randY
class Snake(pygame.sprite.Sprite):
# TODO: Make Snake a chain of Blocks
def __init__(self, color, width, height, positionX, positionY):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(color)
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
# set the position of the snake
self.rect.x = positionX
self.rect.y = positionY
# set the inputs the usable variables for later code
self.color = color
self.width = width
self.height = height
"""
Method the will change the direction of the Snake towards the left
"""
def moveLeft(self):
newX = self.rect.x - 10
return Snake(self.color, self.width, self.height, newX, self.rect.y)
"""
Method that will change the direction of the Snake toward the right
"""
def moveRight(self):
newX = self.rect.x + 10
return Snake(self.color, self.width, self.height, newX, self.rect.y)
"""
Method that will change the direction of the Snake to go upward
"""
def moveUp(self):
newY = self.rect.y - 10
return Snake(self.color, self.width, self.height, self.rect.x, newY)
"""
Method that will change the direction of the Snake to go downward
"""
def moveDown(self):
newY = self.rect.y + 10
return Snake(self.color, self.width, self.height, self.rect.x, newY)
if __name__ == "__main__":
theApp = App()
theApp.on_execute()
I can agree with the answers above. The only problem appears to be that you did not set the FPS i.e. clock.tick(fps) and the game is too fast so it is unplayable. 30 and under will do in my opinion. Please provide more details.
Code is okay, worked on my machine.
Can u add a screenshot of your command prompt?

Enemy doesn't follow player (pygame) [duplicate]

This question already has answers here:
How to make smooth movement in pygame
(2 answers)
How can i make a block follow another block in pygame [duplicate]
(2 answers)
Closed 2 years ago.
So I followed the answers in another question asked on StackOverflow but it seems that I have missed something. I went ahead after reading the answer and copied the code and adjusted it to my variables and class names.
The following is the error code that Idle gives me:
Traceback (most recent call last):
File "D:\Programme (x86)\Python\Games\Zombie Game\Zombie Game_Test1.py", line 133, in <module>
Zombie.move_towards_Char(Char)
TypeError: move_towards_Char() missing 1 required positional argument: 'Char'
This is where I looked:
How to make an enemy follow the player in pygame?
import pygame
import turtle
import time
import math
import random
import sys
import os
pygame.init()
WHITE = (255,255,255)
GREEN = (0,255,0)
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
BGColor = (96,128,56)
ZColor = (225,0,0)
PColor = (0,0,255)
MOVE = 2.5
size = (1920, 1080)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Zombie Game")
class Char(pygame.sprite.Sprite):
def __init__(self, color, pos, radius, width):
super().__init__()
self.image = pygame.Surface([radius*2, radius*2])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
pygame.draw.circle(self.image, color, [radius, radius], radius, width)
self.rect = self.image.get_rect()
def moveRightP(self, pixels):
self.rect.x += pixels
pass
def moveLeftP(self, pixels):
self.rect.x -= pixels
pass
def moveUpP(self, pixels):
self.rect.y -= pixels
pass
def moveDownP(self, pixels):
self.rect.y += pixels
pass
class Zombie(pygame.sprite.Sprite):
def __init__(self2, color, pos, radius, width):
super().__init__()
self2.image = pygame.Surface([radius*2, radius*2])
self2.image.fill(WHITE)
self2.image.set_colorkey(WHITE)
pygame.draw.circle(self2.image, color, [radius, radius], radius, width)
self2.rect = self2.image.get_rect()
self2.rect.center = pos
def move_towards_Char(self2, Char):
dx, dy = self2.rect.x - Char.rect.x, self2.rect.y - Char.rect.y
dist = math.hypot(dx, dy)
dx, dy = dx / dist, dy / dist
self2.rect.x += dx * self2.speed
self2.rect.y += dy * self2.speed
def moveRightZ(self2, pixels):
self2.rect.x += pixels
pass
def moveLeftZ(self2, pixels):
self2.rect.x -= pixels
pass
def moveUpZ(self2, pixels):
self2.rect.y -= pixels
pass
def moveDownZ(self2, pixels):
self2.rect.y += pixels
pass
all_sprites_list = pygame.sprite.Group()
playerChar = Char(PColor, [0, 0], 15, 0)
playerChar.rect.x = 960
playerChar.rect.y = 505
all_sprites_list.add(playerChar)
carryOn = True
clock = pygame.time.Clock()
zombie_list = []
zombie_rad = 15
zombie_dist = (200, 900)
next_zombie_time = pygame.time.get_ticks() + 10000
zombie_list = []
zombie_rad = 15
zombie_dist = (200, 900)
next_zombie_time = 10000
while carryOn:
for event in pygame.event.get():
if event.type==pygame.QUIT:
carryOn=False
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_x:
carryOn=False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
playerChar.moveLeftP(MOVE)
if keys[pygame.K_d]:
playerChar.moveRightP(MOVE)
if keys[pygame.K_w]:
playerChar.moveUpP(MOVE)
if keys[pygame.K_s]:
playerChar.moveDownP(MOVE)
current_time = pygame.time.get_ticks()
if current_time > next_zombie_time:
next_zombie_time = current_time + 2000
on_screen_rect = pygame.Rect(zombie_rad, zombie_rad, size[0]-2*zombie_rad, size[1]-2*zombie_rad)
zombie_pos = (-1, -1)
while not on_screen_rect.collidepoint(zombie_pos):
dist = random.randint(*zombie_dist)
angle = random.random() * math.pi * 2
p_pos = (playerChar.rect.centerx, playerChar.rect.centery)
zombie_pos = (p_pos[0] + dist * math.sin(angle), p_pos[1] + dist * math.cos(angle))
new_pos = (random.randrange(0, size[0]), random.randrange(0, size[1]))
new_zombie = Zombie(RED, zombie_pos, zombie_rad, 0)
zombie_list.append(new_zombie)
screen.fill(BGColor)
screen.blit(playerChar.image,playerChar.rect)
for zombie in zombie_list:
screen.blit(zombie.image,zombie.rect)
pygame.display.flip()
clock.tick(60)
pygame.quit()
The major issue is, that you do the zombie movement calculations with integral data types. If the movement of a zombie is 1 pixel and the movement is diagonal, then the x and y component of the movement is < 1. Using an integral data type, this may results in 0 movement, because of truncating to int. Note the members of pygame.Rect are integral values.
You've to switch to floating point values to solve the issue. Use pygame.math.Vector2 to do the calculations.
Add a member pos of type Vector2 to the class Zombie which stores the floating point position of the zombie:
class Zombie(pygame.sprite.Sprite):
def __init__(self2, color, pos, radius, width):
super().__init__()
self2.image = pygame.Surface([radius*2, radius*2])
self2.image.fill(WHITE)
self2.image.set_colorkey(WHITE)
pygame.draw.circle(self2.image, color, [radius, radius], radius, width)
self2.rect = self2.image.get_rect()
self2.speed = 1
self2.pos = pygame.Vector2(pos[0], pos[1])
# [...]
Add a new method draw to the class Zombie, which draws (blit) a zombie at the position pos:
class Zombie(pygame.sprite.Sprite):
# [...]
def draw(self2):
self2.rect.center = (int(round(self2.pos.x)), int(round(self2.pos.y)))
screen.blit(self2.image, self2.rect)
Do the calculation of the movement of the zombie based on Vector2. Ensure that the distance between the player and the zombie is greater than 0 and that the zombie does not step over of the position of the player (min(len, self2.speed)):
class Zombie(pygame.sprite.Sprite):
# [...]
def move_towards_Char(self2, Char):
deltaVec = pygame.Vector2(Char.rect.center) - self2.pos
len = deltaVec.length()
if len > 0:
self2.pos += deltaVec/len * min(len, self2.speed)
Call the methods move_towards_Char and draw for each zombie, in the main loop of the application:
while carryOn:
for event in pygame.event.get():
if event.type==pygame.QUIT:
carryOn=False
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_x:
carryOn=False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
playerChar.moveLeftP(MOVE)
if keys[pygame.K_d]:
playerChar.moveRightP(MOVE)
if keys[pygame.K_w]:
playerChar.moveUpP(MOVE)
if keys[pygame.K_s]:
playerChar.moveDownP(MOVE)
current_time = pygame.time.get_ticks()
if current_time > next_zombie_time:
next_zombie_time = current_time + 2000
on_screen_rect = pygame.Rect(zombie_rad, zombie_rad, size[0]-2*zombie_rad, size[1]-2*zombie_rad)
zombie_pos = (-1, -1)
while not on_screen_rect.collidepoint(zombie_pos):
dist = random.randint(*zombie_dist)
angle = random.random() * math.pi * 2
p_pos = (playerChar.rect.centerx, playerChar.rect.centery)
zombie_pos = (p_pos[0] + dist * math.sin(angle), p_pos[1] + dist * math.cos(angle))
new_pos = (random.randrange(0, size[0]), random.randrange(0, size[1]))
new_zombie = Zombie(RED, zombie_pos, zombie_rad, 0)
zombie_list.append(new_zombie)
# update all the positions of the zombies
for zombie in zombie_list:
zombie.move_towards_Char(playerChar)
screen.fill(BGColor)
screen.blit(playerChar.image,playerChar.rect)
# draw all the zombies
for zombie in zombie_list:
zombie.draw()
pygame.display.flip()
clock.tick(60)
L{Zombie.move_towards_Char} is a self method. You need to create object of Zombie class passing the required args mentioned in L{Zombie.init}.
Something like below:
zm = Zombie(color=<color>, pos=<pos>, radius=<radius>, width=<width>)
zm.move_towards_Char(Char)

Sprites not appearing correctly onscreen - pygame

I'm in a game programming class and I'm supposed to make a game where there are sprites falling down from the top of the screen that you catch or avoid. Right now I'm working on making the objects fall and they were working at first but then I screwed something up because now they appear patchily/randomly disappear while falling down the screen. I've tried changing various things in the code to fix the problem but I've been stuck for a while.
I'm pretty certain that I messed something up either blitting the coal/candy to the screen or adding new ones to fall once others disappear, but I included a large portion of my code just in case something there is messing it up. I'll highlight the likely messed up sections below.
Oh, I also always really appreciate comments on how to make code more concise/efficient, but the teacher expects the code to be similar to how he taught us, so if you do have a specific fix, if it could keep the code similar to how it is right now I'd really appreciate it!
Thank you so much!
#Setting up time/timer
time = 6000
TICKTOCK = 0
pygame.time.set_timer (TICKTOCK+1, 10)
#Class for candy
class Candy:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH - 150)
self.y = random.randint(-1000, 0)
self.image_Candy = pygame.image.load('konpeito.png')
self.height = self.image_Candy.get_height()
self.width = self.image_Candy.get_width()
def collide (self, sprite):
selfRect = pygame.Rect(self.x, self.y, self.width, self.height)
spriteRect = pygame.Rect(sprite.x, sprite.y, sprite.width, sprite.height)
if selfRect.colliderect(spriteRect):
return True
else:
return False
#class for coal
class Coal:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH - 150)
self.y = random.randint(-1000, SCREEN_HEIGHT)
self.image_Coal = pygame.image.load('coal.png')
self.width = self.image_Coal.get_width()
self.height = self.image_Coal.get_height()
def collide (self, sprite):
selfRect = pygame.Rect(self.x, self.y, self.width, self.height)
spriteRect = pygame.Rect(sprite.x, sprite.y, sprite.width, sprite.height)
if selfRect.colliderect(spriteRect):
return True
else:
return False
#class for sootsprite (collects candy and coal)
class Sootsprite:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH)
self.y = random.randint(0, SCREEN_HEIGHT)
self.image_bowl = pygame.image.load('sootsprite.png')
self.height = self.image_bowl.get_height()
self.width = self.image_bowl.get_width()
clock = pygame.time.Clock()
fps = 10
#Creating candies and rocks
bowl = []
for i in range (15):
candyInstance = Candy()
bowl.append(candyInstance)
rocks = []
for i in range (8):
coalInstance = Coal()
rocks.append(coalInstance)
catch = Sootsprite()
playground.fill(cyan)
Game_Over = False
while not Game_Over:
font = pygame.font.SysFont(None, 30)
endfont = pygame.font.SysFont(None, 100)
text = font.render('Points: ' + str(total) + '/15', True, black)
playground.blit(text, (0,0))
timer = font.render('Time remaining: ' + str(time), True, black)
playground.blit(timer, (0, 40))
end = endfont.render("GAME OVER." + str(total) + " POINTS EARNED", True, black)
This is where I blitted things onscreen and potentially screwed up:
playground.blit(catch.image_bowl, (catch.x, catch.y))
playground.blit(candyInstance.image_Candy, (candyInstance.x, candyInstance.y))
playground.blit(coalInstance.image_Coal, (coalInstance.x, coalInstance.y))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game_Over = True
if event.type == TICKTOCK+1:
time -=1
#ends game when time is over
if time < 0:
playground.blit(end, (300, 400))
#moving sootsprite with mouse
if event.type == MOUSEMOTION:
(catch.x, catch.y) = pygame.mouse.get_pos()
#making candy fall
for candyInstance in bowl:
if candyInstance.x <= 0:
candyInstance.x += 0
elif candyInstance.x >= 0 :
candyInstance.x -=0
if candyInstance.y <= (SCREEN_HEIGHT+150):
candyInstance.y += 20
elif candyInstance.y > (SCREEN_HEIGHT + 150) :
candyInstance.y = -100
this is where I'm removing things and adding new ones and might've messed up:
#removing candy when collected
for candyInstance in bowl:
if candyInstance.collide(catch):
bowl.remove(candyInstance)
total += 1
candyInstance = Candy()
bowl.append(candyInstance)
#making coal fall
for coalInstance in rocks:
if coalInstance.x <= 0:
coalInstance.x += 0
elif coalInstance.x >= 0 :
coalInstance.x -=0
if coalInstance.y <= (SCREEN_HEIGHT + 200):
coalInstance.y += 20
elif coalInstance.y > (SCREEN_HEIGHT + 200) :
coalInstance.y = -100
this is also a place where I removed objects and added new ones:
#removing coal when collected
for coalInstance in rocks:
if coalInstance.collide(catch):
rocks.remove(coalInstance)
total -= 1
coalInstance = Coal()
rocks.append(coalInstance)
pygame.display.flip()
playground.fill(cyan)
clock.tick (fps)
pygame.quit()
You blit only one candy. Use for loop to blit all candies.
for candyInstance in bowl:
playground.blit(candyInstance.image_Candy, (candyInstance.x, candyInstance.y))
You have the same problem with rocks
for coalInstance in rocks:
playground.blit(coalInstance.image_Coal, (coalInstance.x, coalInstance.y))

Categories

Resources