I wrote simple snake game. Code here:
import pygame
import random
from collections import deque
import time
DISPLAY_WIDTH = 100
DISPLAY_HEIGHT = 100
HEAD_SIZE = 10
FOOD_SIZE = HEAD_SIZE
TAIL_SIZE = 5
BLACK = (0,0,0)
WHITE = (255,255,255)
ONE_MOVE = 5
pygame.init()
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption("Snake")
clock = pygame.time.Clock()
class Snake:
def __init__(self):
self.x = 0
self.y = 0
self.snake_lenght = 0
self.tail = []
def draw_head(self):
pygame.draw.rect(gameDisplay, BLACK, [self.x, self.y, HEAD_SIZE, HEAD_SIZE])
def draw_tail(self):
self.tail.append([self.x, self.y])
for i in self.tail:
pygame.draw.rect(gameDisplay, BLACK, [int(i[0]), int(i[1]), TAIL_SIZE, TAIL_SIZE])
def rise(self):
foodx = random.randrange(ONE_MOVE, DISPLAY_WIDTH - ONE_MOVE, 5) # random food in a distance from the wall
foody = random.randrange(ONE_MOVE, DISPLAY_HEIGHT - ONE_MOVE, 5)
for i in self.tail:
if foodx == i[0] and foody == i[1]: # avoid food in tail
self.rise()
break
self.snake_lenght += 20
return foodx, foody, self.snake_lenght
def direction_of_movement(self, direction):
if direction == "turn_right":
return [ONE_MOVE, 0, 0, 0]
elif direction == "turn_left":
return [0, ONE_MOVE, 0, 0]
elif direction == "turn_down":
return [0, 0, ONE_MOVE, 0]
elif direction == "turn_up":
return [0, 0, 0, ONE_MOVE]
def crash(self): # restart game after failing
time.sleep(2)
self.game_loop()
def game_loop(self):
self.x = (DISPLAY_WIDTH * 0.5)
self.y = (DISPLAY_HEIGHT * 0.5)
start = 0
self.snake_lenght = 10 # reset snake's lenght after calling game_loop again
self.tail = deque([], maxlen=self.snake_lenght)
while True:
if start == 0: # start to move
speed = self.direction_of_movement("turn_right")
foodx, foody, self.snake_lenght = self.rise()
start += 1
for event in pygame.event.get(): # quit if exit pressed
if event.type == pygame.QUIT:
quit()
if event.type == pygame.KEYDOWN: # arrow navigation
if event.key == pygame.K_RIGHT:
speed = self.direction_of_movement("turn_right")
elif event.key == pygame.K_LEFT:
speed = self.direction_of_movement("turn_left")
elif event.key == pygame.K_DOWN:
speed = self.direction_of_movement("turn_down")
elif event.key == pygame.K_UP:
speed = self.direction_of_movement("turn_up")
# game logic
self.x += speed[0] #moving directions
self.x -= speed[1]
self.y += speed[2]
self.y -= speed[3]
if self.x < 0 or self.x + ONE_MOVE > DISPLAY_WIDTH: # hit into wall
self.crash()
elif self.y < 0 or self.y + ONE_MOVE > DISPLAY_HEIGHT:
self.crash()
for i in self.tail: # bite itself
if self.x == i[0]:
if self.y == i[1]:
self.crash()
if self.x == foodx and self.y == foody:
foodx, foody, self.snake_lenght = self.rise()
self.tail = deque(self.tail, maxlen=self.snake_lenght)
# draw
gameDisplay.fill(WHITE)
self.draw_head()
self.draw_tail()
pygame.draw.rect(gameDisplay, BLACK, [foodx, foody, FOOD_SIZE, FOOD_SIZE])
pygame.display.update()
clock.tick(10) # game speed
snake = Snake()
snake.game_loop()
In another file I'm importing whole class, adding constants and run it. In shortcut:
from snake_file import Snake
class Snake_for_AI(Snake):
def __init__(self):
pass
def trying(self):
print("hey")
thing = Snake_for_AI()
thing.trying()
Here is my question. It's never printing "hey". Moreover, it runs game_loop and starts the game when I create class object thing = Snake_for_AI, no need to call thing.game_loop(). Why?
Any code review is very appreciated too.
When importing, you will execute the two lines at the bottom of the file. If that is not the desired behavior, surround them as such:
if __name__ == "__main__":
snake = Snake()
snake.game_loop()
That will cause them to be interpreted only if you actually run that file.
Related
So, I was watching a video from youtube on making the game Snake on Python with the pygame module.. and it was quite confusing.. and now I'm having an issue.. The pygame window opened and closed suddenly and there was no errors in the output.
I ran this pile of code :
import os
os.environ['DISPLAY'] = ': 0.0'
import pygame
pygame.init()
import random
from enum import Enum
from collections import namedtuple
font = pygame.font.Font('PermanentMarker-Regular.ttf', 25)
#font = pygame.font.SysFont('arial', 25)
class Direction(Enum):
RIGHT = 1
LEFT = 2
UP = 3
DOWN = 4
Point = namedtuple('Point', ('x','y'))
WHITE = (255, 255, 255)
RED = (247,33,25)
BLUE = (0,0,255)
CYAN = (255, 255, 1)
BLACK = [0,0,0]
BLOCK_SIZE = 20
SPEED = 40
class SnakeGame:
def __init__(self, w=640, h=480):
self.w = w
self.h = h
# init display
self.display = pygame.display.set_mode((self.w, self.h))
pygame.display.set_caption("Snake")
self.clock = pygame.time.Clock()
# init game state
self.direction = Direction.RIGHT
self.head = Point(self.w/2, self.h/2)
self.snake = [self.head, Point(self.head.x-BLOCK_SIZE, self.head.y), Point(self.head.x-(2*BLOCK_SIZE), self.head.y)]
self.score = 0
self.food = None
self._place_food()
def _place_food(self):
x = random.randint(0, (self.w-BLOCK_SIZE)//BLOCK_SIZE) * BLOCK_SIZE
y = random.randint(0, (self.h-BLOCK_SIZE)//BLOCK_SIZE) * BLOCK_SIZE
self.food = Point(x, y)
if self.food in self.snake:
self._place_food()
self.head = Point(x,y)
def _move(self, direction):
x = self.head.x
y = self.head.y
if direction == Direction.RIGHT:
x += BLOCK_SIZE
elif direction == Direction.LEFT:
x -= BLOCK_SIZE
elif direction == Direction.UP:
y -= BLOCK_SIZE
elif direction == Direction.DOWN:
y += BLOCK_SIZE
def _is_collision(self):
# hits boundary
if self.head.x > self.w - BLOCK_SIZE or self.head.x < 0 or self.head.y > self.h - BLOCK_SIZE or self.head.y < 0:
return True
# hits itself
if self.head in self.snake[1:]:
return True
return False
pygame.display.flip()
def play_step(self):
# collect user input
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.direction = Direction.LEFT
elif event.key == pygame.K_RIGHT:
self.direction = Direction.RIGHT
elif event.key == pygame.K_UP:
self.direction = Direction.UP
elif event.key == pygame.K_DOWN:
self.direction = Direction.DOWN
#2. move
self._move(self.direction)
self.snake.insert(0, self.head)
#3. check if game over
game_over = False
if self._is_collision():
game_over = True
#4. place new food or move snake
if self.head == self.food:
self.score += 1
self._place_food()
else:
self.snake.pop()
#5. update ui and clock
self._update_ui()
self.clock.tick(SPEED)
#6. return game over and score
return game_over, self.score
def _update_ui(self):
self.display.fill(BLACK)
for pt in self.snake:
pygame.draw.rect(self.display, CYAN, pygame.Rect(pt.x, pt.y, BLOCK_SIZE, BLOCK_SIZE))
pygame.draw.rect(self.display, BLUE, pygame.Rect(pt.x+4, pt.y+4, 12, 12))
pygame.draw.rect(self.display, RED, pygame.Rect(self.food.x, self.food.y, BLOCK_SIZE, BLOCK_SIZE))
text = font.render("Score:", str(self.score), True, WHITE)
self.display.blit(text, [0,0])
if __name__ == '__main__':
game = SnakeGame()
# game loop
while True:
game_over, score = game.play_step()
if game_over == True:
break
print("Final score {}".format(score))
# break if game over
pygame.quit()
The issue is probably because I misplaced a method or did something in the script..
There are 4 issues:
Update the head attribute after in the move() method:
class SnakeGame:
# [...]
def _move(self, direction):
x = self.head.x
y = self.head.y
if direction == Direction.RIGHT:
x += BLOCK_SIZE
elif direction == Direction.LEFT:
x -= BLOCK_SIZE
elif direction == Direction.UP:
y -= BLOCK_SIZE
elif direction == Direction.DOWN:
y += BLOCK_SIZE
self.head = Point(x, y) # <--- this is missing
You have to concatenate the strings for the score text (see TypeError: Invalid foreground RGBA argument):
text = font.render("Score:", str(self.score), True, WHITE)
text = font.render("Score:" + str(self.score), True, WHITE)
Update the display after drawing the scene:
def _update_ui(self):
self.display.fill(BLACK)
for pt in self.snake:
pygame.draw.rect(self.display, CYAN, pygame.Rect(pt.x, pt.y, BLOCK_SIZE, BLOCK_SIZE))
pygame.draw.rect(self.display, BLUE, pygame.Rect(pt.x+4, pt.y+4, 12, 12))
pygame.draw.rect(self.display, RED, pygame.Rect(self.food.x, self.food.y, BLOCK_SIZE, BLOCK_SIZE))
text = font.render("Score:" + str(self.score), True, WHITE)
self.display.blit(text, [0,0])
pygame.display.flip() # <--- this is missing
Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
if __name__ == '__main__':
game = SnakeGame()
# game loop
clock = pygame.time.Clock()
while True:
clock.tick(10)
game_over, score = game.play_step()
if game_over == True:
break
print("Final score {}".format(score))
Creating a game where a maze is randomly generated and the player must navigate from the top left to the bottom right of the maze.
I have tried many things to stop my character going off-screen but it still doesn't work.
When already on the boundary of the screen the code works as intended and the character cannot continue moving off screen. However, if already moving then the character continues moving off the screen until the movement key is released where the character is then teleported back on to the screen where it should be. Additionally, I need to add boundaries to the maze walls as well but this is my current problem.
import pygame
import numpy
import sys
import csv
import random
from datetime import date
pygame.init()
done = False
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
cols = 10
rows = 10
width = 600
height = 600
wr = width/cols
hr = height/rows
screen = pygame.display.set_mode([width, height])
screen_rect = screen.get_rect()
pygame.display.set_caption("Maze Generator")
clock = pygame.time.Clock()
class Spot:
def __init__(self, x, y):
self.x = x
self.y = y
self.f = 0
self.g = 0
self.h = 0
self.neighbors = []
self.visited = False
self.walls = [True, True, True, True]
def show(self, color=BLACK):
if self.walls[0]:
pygame.draw.line(screen, color, [self.x*hr, self.y*wr], [self.x*hr+hr, self.y*wr], 2)
if self.walls[1]:
pygame.draw.line(screen, color, [self.x*hr+hr, self.y*wr], [self.x*hr+hr, self.y*wr + wr], 2)
if self.walls[2]:
pygame.draw.line(screen, color, [self.x*hr+hr, self.y*wr+wr], [self.x*hr, self.y*wr+wr], 2)
if self.walls[3]:
pygame.draw.line(screen, color, [self.x*hr, self.y*wr+wr], [self.x*hr, self.y*wr], 2)
def show_block(self, color):
if self.visited:
pygame.draw.rect(screen, color, [self.x*hr+2, self.y*wr+2, hr-2, wr-2])
def add_neighbors(self):
if self.x > 0:
self.neighbors.append(grid[self.x - 1][self.y])
if self.y > 0:
self.neighbors.append(grid[self.x][self.y - 1])
if self.x < rows - 1:
self.neighbors.append(grid[self.x + 1][self.y])
if self.y < cols - 1:
self.neighbors.append(grid[self.x][self.y + 1])
grid = [[Spot(i, j) for j in range(cols)] for i in range(rows)]
for i in range(rows):
for j in range(cols):
grid[i][j].add_neighbors()
current = grid[0][0]
visited = [current]
completed = False
def breakwalls(a, b):
if a.y == b.y and a.x > b.x:
grid[b.x][b.y].walls[1] = False
grid[a.x][a.y].walls[3] = False
if a.y == b.y and a.x < b.x:
grid[a.x][a.y].walls[1] = False
grid[b.x][b.y].walls[3] = False
if a.x == b.x and a.y < b.y:
grid[b.x][b.y].walls[0] = False
grid[a.x][a.y].walls[2] = False
if a.x == b.x and a.y > b.y:
grid[a.x][a.y].walls[0] = False
grid[b.x][b.y].walls[2] = False
class Player:
def __init__(self, x, y):
self.rect = pygame.Rect(x, y, hr-2, wr-2)
self.x = int(x)
self.y = int(y)
self.colour = (255, 0, 0)
self.velX = 0
self.velY = 0
self.left_pressed = False
self.right_pressed = False
self.up_pressed = False
self.down_pressed = False
self.speed = 5
def draw(self, win):
pygame.draw.rect(win, self.colour, self.rect)
def update(self):
self.velX = 0
self.velY = 0
if self.left_pressed and not self.right_pressed:
self.velX = -self.speed
if self.right_pressed and not self.left_pressed:
self.velX = self.speed
if self.up_pressed and not self.down_pressed:
self.velY = -self.speed
if self.down_pressed and not self.up_pressed:
self.velY = self.speed
self.x += self.velX
self.y += self.velY
self.rect = pygame.Rect(self.x, self.y, hr-2, wr-2)
def readMyFiles():
questionsAndAnswers = []
correctAnswers = []
with open('questions.txt', newline='') as f:
reader = csv.reader(f, delimiter='\t')
for row in reader:
questionsAndAnswers.append(row)
return questionsAndAnswers
def game(questions, answers, correctAnswers):
score = 0
counter = 0
numberOfQuestions = len(questions)
while not counter == numberOfQuestions:
print(questions[counter])
print(answers[counter])
userAnswer = input('\nWhat is the correct answer?\n')
if userAnswer == correctAnswers[counter]:
print('Well done! That is correct.')
score += 1
else:
print('Better luck next time, that is not correct.')
counter += 1
return score
def shuffleSplit(qna):
random.shuffle(qna)
questions = []
answers = []
correctAnswers = []
for q in qna:
questions.append(q[0])
correctAnswers.append(q[1])
del q[0]
random.shuffle(q)
answers.append(q)
return (questions, answers, correctAnswers)
def exportScores(score, ):
with open('scores.txt', mode='a') as scores:
scores = csv.writer(scores, delimiter='\t')
today = date.today()
dateFormat = today.strftime("%d/%m/%Y")
scores.writerow([dateFormat, score])
player = Player(2, 2)
while not done:
clock.tick(60)
screen.fill(BLACK)
if not completed:
grid[current.x][current.y].visited = True
got_new = False
temp = 10
while not got_new and not completed:
r = random.randint(0, len(current.neighbors)-1)
Tempcurrent = current.neighbors[r]
if not Tempcurrent.visited:
visited.append(current)
current = Tempcurrent
got_new = True
if temp == 0:
temp = 10
if len(visited) == 0:
completed = True
break
else:
current = visited.pop()
temp = temp - 1
if not completed:
breakwalls(current, visited[len(visited)-1])
current.visited = True
current.show_block(WHITE)
for i in range(rows):
for j in range(cols):
grid[i][j].show(WHITE)
# grid[i][j].show_block(BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
questionsAndAnswers = readMyFiles()
questions, answers, correctAnswers = shuffleSplit(questionsAndAnswers)
score = game(questions, answers, correctAnswers)
exportScores(score)
print('\nYour score is', str(score))
sys.exit()
if event.type == pygame.KEYDOWN and completed:
if event.key == pygame.K_LEFT:
player.left_pressed = True
if event.key == pygame.K_RIGHT:
player.right_pressed = True
if event.key == pygame.K_UP:
player.up_pressed = True
if event.key == pygame.K_DOWN:
player.down_pressed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.left_pressed = False
if event.key == pygame.K_RIGHT:
player.right_pressed = False
if event.key == pygame.K_UP:
player.up_pressed = False
if event.key == pygame.K_DOWN:
player.down_pressed = False
player.rect.clamp_ip(screen_rect)
if player.x <= 2:
player.left_pressed = False
player.x = 2
if player.y <= 2:
player.up_pressed = False
player.y = 2
if player.x >= width-(wr-2):
player.right_pressed = False
player.x = width-(wr-2)
if player.y >= height-(wr-2):
player.down_pressed = False
player.y = height-(wr-2)
player.draw(screen)
player.update()
pygame.display.flip()
I have tried using player.clamp_ip(screen_rect) and creating a screen rectangle but this also doesn't work. I have tried checking for going off-screen using player.rect.x rather than player.x but still doesn't work.
Please help.
It is a matter of Indentation. The player moves even if the key is held down, but the keyboard events only occur once when a key is pressed or released. You need to do the collision test in the application loop and not in the event loop:
while not done:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
# [...]
#<--| INDENTATION
player.rect.clamp_ip(screen_rect)
if player.x <= 2:
player.left_pressed = False
player.x = 2
if player.y <= 2:
player.up_pressed = False
player.y = 2
if player.x >= width-(wr-2):
player.right_pressed = False
player.x = width-(wr-2)
if player.y >= height-(wr-2):
player.down_pressed = False
player.y = height-(wr-2)
player.draw(screen)
player.update()
pygame.display.flip()
How would I get the enemy to avoid the characters line at all costs while still trying to eliminate him? The code I have as far makes the enemy run straight to the player and die pretty much straight away.
Does anyone have any idea how to keep the enemy from touching the players line?
Here is the code:
import random
import pygame, sys
from pygame.locals import *
import time
GREEN=(0,125,0)
BLUE=(0,0,125)
Yplayer = 225/2
Xplayer = 350
playerlinesavedata = []
playercurrent = []
Xplayerchange=0
Yplayerchange=0
Yenemy = 450
Xenemy = 300
enemylinesavedata = []
enemycurrent = []
Xenemychange=0
Yenemychange=0
windowX = 900
windowY = 600
pygame.init()
DISPLAY=pygame.display.set_mode((windowX,windowY),0,32)
def enemymovement():
global Xplayer,Yplayer,Xenemy,Yenemy
enemy1 = True
enemydirection = random.randint(1,4)
# enemy moves toward player
if Xenemy > Xplayer: enemydirection = 1
elif Xenemy < Xplayer: enemydirection = 2
elif Yenemy > Yplayer: enemydirection = 3
elif Yenemy < Yplayer: enemydirection = 4
while enemy1 == True:
if enemydirection == 1:
Xenemychange= -random.randint(1,4)
Xenemy+=Xenemychange
if enemydirection == 2:
Xenemychange= random.randint(1,4)
Xenemy+=Xenemychange
if enemydirection == 3:
Yenemychange= -random.randint(1,4)
Yenemy+=Yenemychange
if enemydirection == 4:
Yenemychange= random.randint(1,4)
Yenemy+=Yenemychange
enemylinesavedata.append([Xenemy,Yenemy])
enemy()
break
def enemy():
for XnY in enemylinesavedata:
pygame.draw.rect(DISPLAY,BLUE, [XnY[0],XnY[1],5,5])
def player():
for XnY in playerlinesavedata:
pygame.draw.rect(DISPLAY,GREEN,[XnY[0],XnY[1],5,5])
def main():
global playerlinesavedata, enemylinesavedata
global Xplayer, Yplayer, Xenemy, Yenemy
WHITE = (255,255,255)
size = 5
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
Xplayer += (keys[pygame.K_d] - keys[pygame.K_a]) * size
Yplayer += (keys[pygame.K_s] - keys[pygame.K_w]) * size
playerlinesavedata.append((Xplayer, Yplayer))
enemymovement()
player_rectlist = [pygame.Rect(x, y, size, size) for x, y in playerlinesavedata]
enemy_rectlist = [pygame.Rect(x, y, size, size) for x, y in enemylinesavedata]
if player_rectlist[-1].collidelist(enemy_rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy_rectlist[-1].collidelist(player_rectlist) >= 0:
playerlinesavedata = []
Yplayer = 225//2
Xplayer = 350
enemylinesavedata = []
Yenemy = 450
Xenemy = 300
DISPLAY.fill(WHITE)
player()
enemy()
pygame.display.update()
main()
It is a bad practice to use globalize variables. It is much better to use python classes as the pygame objects.
Here is a cleaned up version of your code so that you or other users on Stack Overflow can help you with your problem more easily:
import random
import pygame, sys
from pygame.locals import *
import time
pygame.init()
GREEN = (0, 125, 0)
BLUE = (0, 0, 125)
WHITE = (255,255,255)
windowX = 900
windowY = 600
wn = pygame.display.set_mode((windowX, windowY), 0, 32)
class Object:
def __init__(self, X, Y, enemy=False, color=GREEN):
self.enemy = enemy
self.X = X
self.Y = Y
self.current = []
self.Xchange = 0
self.Ychange = 0
self.direction = 0
self.rectlist = []
self.color = color
self.size = 5
def movement(self):
for rect in self.rectlist:
pygame.draw.rect(wn, self.color, rect)
if self.enemy:
if self.X > player.X:
self.direction = 1
elif self.X < player.X:
self.direction = 2
elif self.Y > player.Y:
self.direction = 3
elif self.Y < player.Y:
self.direction = 4
if self.direction == 1:
self.Xchange = -random.randint(1,4)
self.X += self.Xchange
if self.direction == 2:
self.Xchange = random.randint(1,4)
self.X += self.Xchange
if self.direction == 3:
self.Ychange = -random.randint(1,4)
self.Y += self.Ychange
if self.direction == 4:
self.Ychange = random.randint(1,4)
self.Y += self.Ychange
else:
keys = pygame.key.get_pressed()
player.X += (keys[pygame.K_d] - keys[pygame.K_a]) * player.size
player.Y += (keys[pygame.K_s] - keys[pygame.K_w]) * player.size
self.rectlist.append(pygame.Rect(self.X, self.Y, self.size, self.size))
player = Object(350, 225 / 2)
enemy = Object(450, 300, enemy=True, color=BLUE)
def main():
clock = pygame.time.Clock()
size = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
player.movement()
enemy.movement()
if player.rectlist[-1].collidelist(enemy.rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
player.rectlist = []
player.X = 350
player.Y = 225 // 2
enemy.rectlist = []
enemy.X = 450
enemy.Y = 300
pygame.display.update()
wn.fill(WHITE)
main()
Here is my implementation of how to let the enemy avoid the player, though it is very buggy, as in, it will go through the player's line
most of the time:
import random
import pygame, sys
from pygame.locals import *
import time
pygame.init()
GREEN = (0, 125, 0)
BLUE = (0, 0, 125)
WHITE = (255,255,255)
windowX = 900
windowY = 600
wn = pygame.display.set_mode((windowX, windowY), 0, 32)
class Object:
def __init__(self, X, Y, enemy=False, color=GREEN):
self.enemy = enemy
self.X = X
self.Y = Y
self.current = []
self.Xchange = 0
self.Ychange = 0
self.direction = 0
self.rectlist = []
self.color = color
self.size = 5
self.bounce = 0
def movement(self):
for rect in self.rectlist:
pygame.draw.rect(wn, self.color, rect)
if self.enemy:
enemydirection = random.randint(1,4)
if not self.bounce:
if self.X > player.X:
self.direction = 1
elif self.X < player.X:
self.direction = 2
elif self.Y > player.Y:
self.direction = 3
elif self.Y < player.Y:
self.direction = 4
else:
self.bounce -= 1
if self.direction == 1:
self.Xchange = -random.randint(1,4)
self.X += self.Xchange
if self.direction == 2:
self.Xchange = random.randint(1,4)
self.X += self.Xchange
if self.direction == 3:
self.Ychange = -random.randint(1,4)
self.Y += self.Ychange
if self.direction == 4:
self.Ychange = random.randint(1,4)
self.Y += self.Ychange
else:
keys = pygame.key.get_pressed()
player.X += (keys[pygame.K_d] - keys[pygame.K_a]) * player.size
player.Y += (keys[pygame.K_s] - keys[pygame.K_w]) * player.size
self.rectlist.append(pygame.Rect(self.X, self.Y, self.size, self.size))
player = Object(350, 225 / 2)
enemy = Object(450, 300, enemy=True, color=BLUE)
def main():
clock = pygame.time.Clock()
size = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
player.movement()
enemy.movement()
if player.rectlist[-1].collidelist(enemy.rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
if not enemy.bounce:
while enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
enemy.rectlist.pop()
enemy.rectlist.pop()
enemy.rectlist.pop()
enemy.X, enemy.Y = enemy.rectlist[-1].x, enemy.rectlist[-1].y
enemy.direction = enemy.direction - 2 if enemy.direction - 2 else enemy.direction + 2
enemy.bounce = 40
pygame.display.update()
wn.fill(WHITE)
main()
Output:
Commands screen.fill() or screen.blit(), doesnt refresh my object on the screen. My player's object or biedronka's objects stays in the same position even then my program reset the whole screen. My game runs perfectly and i have only problem with this refreshing screen. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
…
import os
import random
import pygame
pygame.init()
pygame.display.set_caption('Biedronkaaa')
screen = pygame.display.set_mode((500, 500))
background_menu = pygame.image.load("tlo-menu.png")
background_game = pygame.image.load("tlo-gra.png")
def write(text, x, y, size):
cz = pygame.font.SysFont("Arial", size)
text = cz.render(text, 1, (204, 0, 0))
screen.blit(text, (x, y))
class Biedronki():
def __init__(self):
self.x = random.randint(10, 100)
self.y = random.randint(10, 100)
self.vx = random.randint(-4, 4)
self.vy = random.randint(-4, 4)
self.graphic = pygame.image.load(os.path.join('biedrona.png'))
self.size = 24
def draw(self):
screen.blit(self.graphic, (self.x, self.y))
def moves(self):
self.x += self.vx
self.y += self.vy
if self.x <= 0 or self.x >= 500 - self.size:
self.vx = self.vx * -1
if self.y <= 0 or self.y >= 500 - self.size:
self.vy = self.vy * -1
def collision(self, player):
x_srodek = self.x + self.size / 2
y_srodek = self.y + self.size / 2
if player.collidepoint(x_srodek, y_srodek):
return True
else:
return False
enemies = []
for i in range(20):
enemies.append(Biedronki())
# player cords
x_player = 450
y_player = 450
v = 20
player = pygame.Rect(x_player, y_player, 32, 32)
graphic_player = pygame.image.load(os.path.join('gracz.png'))
game = "menu"
points = 0
# mainloop
while True:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
if y_player - v > 0:
y_player -= v
if event.key == pygame.K_DOWN:
if y_player + v < 500 - 32:
y_player += v
if event.key == pygame.K_RIGHT:
if x_player + v < 500 - 32:
x_player += v
if event.key == pygame.K_LEFT:
if x_player - v > 0:
x_player -= v
if event.key == pygame.K_SPACE:
if game != "contest":
screen.blit(graphic_player, (x_player, y_player))
game = 'contest'
points = 0
player = pygame.Rect(x_player, y_player, 32, 32)
if game == "menu":
screen.blit(background_menu, (0, 0))
write("Press space to run", 140, 250, 20)
elif game == "contest":
points += 1
screen.blit(background_game, (0, 0))
for biedroneczka in enemies:
biedroneczka.moves()
biedroneczka.draw()
if biedroneczka.collision(player):
game = "end"
screen.blit(graphic_player, (x_player, y_player))
write(str(points), 30, 30, 20)
pygame.time.wait(15)
elif game == "end":
write("Niestety przegrywasz", 50, 290, 20)
write("Nacisnij spację, aby zagrać jeszcze raz", 50, 350, 20)
write("Twój wynik to: " + str(points), 50, 320, 20)
pygame.display.update()
Finally fixed it by added to the space key reseting objects and player position
if event.key == pygame.K_SPACE:
if game != "contest":
screen.blit(graphic_player, (x_player, y_player))
game = 'contest'
points = 0
x_player = 450
y_player = 450
for _ in range(20):
enemies.pop(0)
for _ in range(20):
enemies.append(Biedronki())
You need to do pygame.display.update() at the end of the main loop.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I'm making a platform game with pygame, and I would like to add gravity to it.
Right now I only have a picture which moves when I press the arrow keys, and my next step would be gravity. Here's my code:
import pygame, sys
from pygame.locals import *
pygame.init()
FPS = 30
fpsClock = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption("Jadatja")
WHITE = (255, 255, 255)
catImg = pygame.image.load("images/cat.png")
catx = 10
caty = 10
movingRight = False
movingDown = False
movingLeft = False
movingUp = False
while True: #main game loop
#update
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_RIGHT:
#catx += 5
movingRight = True
movingLeft = False
elif event.key == K_DOWN:
#caty += 5
movingDown = True
movingUp = False
elif event.key == K_LEFT:
#catx -= 5
movingLeft = True
movingRight = False
elif event.key == K_UP:
#caty -= 5
movingUp = True
movingDown = False
if event.type == KEYUP:
if event.key == K_RIGHT:
movingRight = False
if event.key == K_DOWN:
movingDown = False
if event.key == K_LEFT:
movingLeft = False
if event.key == K_UP:
movingUp = False
#actually make the player move
if movingRight == True:
catx += 5
if movingDown == True:
caty += 5
if movingLeft == True:
catx -= 5
if movingUp == True:
caty -= 5
#exit
for event in pygame.event.get():
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == QUIT:
pygame.quit()
sys.exit()
#draw
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(catImg, (catx, caty))
pygame.display.update()
fpsClock.tick(FPS)
I'm not 100% sure if this code is as smooth as I think it is, but I hope you guys can make something of it.
Thanks
There is a tutorial for creating a bouncing ball which I think might be helpful to you.
Now, to add gravity to that simulation, you'd simply add some extra speed in the y-direction every time through the loop:
speed[1] += gravity
What you end up with is kind of goofy however, since the image quickly descends below the bottom of the window never to be seen again :)
The next step is therefore to clip the position of the ball so it must remain in the window:
import os
import sys, pygame
pygame.init()
size = width, height = 320, 240
speed = [1, 1]
black = 0, 0, 0
gravity = 0.1
screen = pygame.display.set_mode(size)
image_file = os.path.expanduser("~/pybin/pygame_examples/data/ball.png")
ball = pygame.image.load(image_file)
ballrect = ball.get_rect()
def clip(val, minval, maxval):
return min(max(val, minval), maxval)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
speed[1] += gravity
ballrect = ballrect.move(speed)
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
if ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
# clip the position to remain in the window
ballrect.left = clip(ballrect.left, 0, width)
ballrect.right = clip(ballrect.right, 0, width)
ballrect.top = clip(ballrect.top, 0, height)
ballrect.bottom = clip(ballrect.bottom, 0, height)
screen.fill(black)
screen.blit(ball, ballrect)
pygame.display.flip()
Okay, now you can incorporate that in your current code and you'll be off and running. However, there are some things you can do to make your code more organized and less repetitive.
For example, consider the massive if...then blocks that follow
for event in pygame.event.get():
You could rewrite it as something like:
delta = {
pygame.K_LEFT: (-20, 0),
pygame.K_RIGHT: (+20, 0),
pygame.K_UP: (0, -20),
pygame.K_DOWN: (0, +20),
}
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
deltax, deltay = delta.get(event.key, (0, 0))
ball.speed[0] += deltax
ball.speed[1] += deltay
You could also benefit from putting all the logic associated with the movement of your image into a class:
class Ball(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.speed = [0, 0]
area = pygame.display.get_surface().get_rect()
self.width, self.height = area.width, area.height
def update(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > self.width:
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.bottom > self.height:
self.speed[1] = -self.speed[1]
self.rect.left = clip(self.rect.left, 0, self.width)
self.rect.right = clip(self.rect.right, 0, self.width)
self.rect.top = clip(self.rect.top, 0, self.height)
self.rect.bottom = clip(self.rect.bottom, 0, self.height)
Notice the update method is very similar to the code presented by the tutorial. One of the nice things about creating a Ball class is that the rest of your program does not need to know much about how a Ball moves. All the logic is in Ball.update. Moreover, it makes it easy to instantiate many balls. And you could create other classes (airplanes, birds, paddles, etc.) that move differently too and add them to your simulation relatively painlessly.
So, putting it all together, you would end up with something like this:
"""
http://stackoverflow.com/a/15459868/190597 (unutbu)
Based on http://www.pygame.org/docs/tut/intro/intro.html
Draws a red ball bouncing around in the window.
Pressing the arrow keys moves the ball
"""
import sys
import pygame
import os
image_file = os.path.expanduser("~/pybin/pygame_examples/data/ball.png")
delta = {
pygame.K_LEFT: (-20, 0),
pygame.K_RIGHT: (+20, 0),
pygame.K_UP: (0, -20),
pygame.K_DOWN: (0, +20),
}
gravity = +1
class Ball(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.speed = [0, 0]
area = pygame.display.get_surface().get_rect()
self.width, self.height = area.width, area.height
def update(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > self.width:
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.bottom > self.height:
self.speed[1] = -self.speed[1]
self.rect.left = clip(self.rect.left, 0, self.width)
self.rect.right = clip(self.rect.right, 0, self.width)
self.rect.top = clip(self.rect.top, 0, self.height)
self.rect.bottom = clip(self.rect.bottom, 0, self.height)
def clip(val, minval, maxval):
return min(max(val, minval), maxval)
class Main(object):
def __init__(self):
self.setup()
def setup(self):
pygame.init()
size = (self.width, self.height) = (640,360)
self.screen = pygame.display.set_mode(size, 0, 32)
self.ball = Ball()
self.setup_background()
def setup_background(self):
self.background = pygame.Surface(self.screen.get_size())
self.background = self.background.convert()
self.background.fill((0, 0, 0))
self.screen.blit(self.background, (0, 0))
pygame.display.flip()
def draw(self):
self.screen.blit(self.background, (0, 0))
self.screen.blit(self.ball.image, self.ball.rect)
pygame.display.flip()
def event_loop(self):
ball = self.ball
friction = 1
while True:
for event in pygame.event.get():
if ((event.type == pygame.QUIT) or
(event.type == pygame.KEYDOWN and
event.key == pygame.K_ESCAPE)):
sys.exit()
elif event.type == pygame.KEYDOWN:
deltax, deltay = delta.get(event.key, (0, 0))
ball.speed[0] += deltax
ball.speed[1] += deltay
friction = 1
elif event.type == pygame.KEYUP:
friction = 0.99
ball.speed = [friction*s for s in ball.speed]
ball.speed[1] += gravity
ball.update()
self.draw()
pygame.time.delay(10)
if __name__ == '__main__':
app = Main()
app.event_loop()