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()
Related
This is my first post so please let me know if I should alter anything.
I am attempting to create a simple test 2D platformer, this is the first pygame project I've undertaken without a tutorial. The issue I am encountering is due to this can_jump variable. I am using this variable to stop the player from being able to jump when not on a platform or the bottom of the screen. I had attempted other methods but this is where I have ended up. I feel I've gotten so close.
The issue at the moment appears to be that the variable self.can_jump1 continuously swaps between True and False in the platform loop (at exactly 3 Falses for every True I have noticed) when standing on a platform, I have isolated it to the commented section in collision_check(). I don't know why this happens, and as far as I can tell the rest of the code works as I want it.
I would be happy to provide any extra information/clarification if need be.
Here's my code:
import pygame, sys, random
#---Classes----------------------------------------#
class Block(pygame.sprite.Sprite): #inherited by rest of classes
def __init__(self,path,x_pos,y_pos,size_x,size_y):
super().__init__()
self.image = pygame.transform.scale(pygame.image.load(path).convert_alpha(),(size_x,size_y))
self.rect = self.image.get_rect(center = (x_pos,y_pos))
class PlatformRect(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,size_x,size_y,colour,players):
super().__init__()
self.center_x = x_pos
self.center_y = y_pos
self.size_x = size_x
self.size_y = size_y
self.colour = colour
self.players = players
self.can_jump1 = None
self.image = pygame.Surface((self.size_x,self.size_y))
self.image.fill(self.colour)
self.rect = self.image.get_rect(center = (self.center_x,self.center_y))
def collision_check(self):
if pygame.sprite.spritecollide(self,self.players,False):
collision_paddle = pygame.sprite.spritecollide(self,self.players,False)[0].rect
if abs(self.rect.top - collision_paddle.bottom) < 10:
collision_paddle.bottom = self.rect.top
player.movement_y = 0
self.can_jump1 = True
else: #error isolated to here,consistently fluctuates between True and False, not sure why
self.can_jump1 = False
print(self.can_jump1) #if standing on platform should only produce True, everywhere else produce False
def can_jump_check(self):
return self.can_jump1
def update(self):
self.collision_check()
class Player(Block):
def __init__(self,path,x_pos,y_pos,size_x,size_y,speed_x,acceleration_y):
super().__init__(path,x_pos,y_pos,size_x,size_y)
self.size_x = size_x
self.size_y = size_y
self.speed_x = speed_x
self.acceleration_y = acceleration_y
self.movement_x = 0
self.movement_y = 0
def screen_constrain(self):
if self.rect.bottom >= sresy:
self.rect.bottom = sresy
if self.rect.left <= 0:
self.rect.left = 0
if self.rect.right >= sresx:
self.rect.right = sresx
def update(self):
if abs(self.movement_y) <= 9:
self.movement_y += GRAVITY
self.rect.centery += self.movement_y
self.rect.centerx += self.movement_x
self.screen_constrain()
class GameManager:
def __init__(self,player_group,platform_group):
self.player_group = player_group
self.platform_group = platform_group
self.can_jump = True
def run_game(self):
#---drawing---#
self.player_group.draw(screen)
self.platform_group.draw(screen)
#---updating---#
self.player_group.update()
self.platform_group.update()
def game_checking(self):
#---checking---#
for sprite_platform in self.platform_group.sprites():
if not sprite_platform.can_jump_check() == True:
self.can_jump = False
else:
self.can_jump = True
return self.can_jump
#---Setup------------------------------------------#
#---constants-----#
global GRAVITY
GRAVITY = 0.25
#---Gamevariables-----#
can_jump = True
#---colour---#
bg_colour = (50,50,50)
white_colour = (255,255,255)
black_colour = (0,0,0)
#---res---#
resx = 900
resy = 675
sresx = resx - 50
sresy = resy - 50
#---start window-----#
clock = pygame.time.Clock()
screendisplay = pygame.display.set_mode((resx,resy))
screendisplay.fill(bg_colour)
pygame.display.set_caption("PlatformerGame1 started 09/02/2021")
screen = pygame.Surface((sresx,sresy))
screen.fill(white_colour)
#---startgame-----#
player = Player("assets\\pics\\TestPlayerFigure1_256512.png",100,100,32,64,10,30)
player_group = pygame.sprite.GroupSingle()
player_group.add(player)
platform1 = PlatformRect(100,550,100,10,black_colour,player_group)
platform_group = pygame.sprite.Group()
platform_group.add(platform1)
game_manager = GameManager(player_group,platform_group)
#---Loop--------------------------------------------#
while True:
#---events-----#
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_SPACE:
if can_jump == True:
player.movement_y = 0
player.movement_y -= player.acceleration_y * GRAVITY
if event.key == pygame.K_a:
player.movement_x -= player.speed_x
if event.key == pygame.K_d:
player.movement_x += player.speed_x
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
if player.movement_y < 0:
player.movement_y = 0
if event.key == pygame.K_a:
player.movement_x += player.speed_x
if event.key == pygame.K_d:
player.movement_x -= player.speed_x
#---background---#
screendisplay.blit(screen,(25,25))
screen.fill(white_colour)
#---running---#
game_manager.run_game()
if not game_manager.game_checking() == True and player.rect.bottom < sresy:
can_jump = False
else:
can_jump = True
#print(can_jump)
#---updating-----#
pygame.display.update()
clock.tick(60)
When the player is standing on the platform, the player does not collide with the platform and self.can_jump1 is set False. Test if the player is on the platform when the player does not collide with the platform:
self.can_jump1 = False
self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom
Method collision_check:
class PlatformRect(pygame.sprite.Sprite):
# [...]
def collision_check(self):
collide_list = pygame.sprite.spritecollide(self,self.players,False)
if collide_list:
collision_paddle = collide_list[0].rect
if abs(self.rect.top - collision_paddle.bottom) < 10:
collision_paddle.bottom = self.rect.top
player.movement_y = 0
self.can_jump1 = True
else:
self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom
GameManager.game_checking needs to check if the plyer collides with any platform:
class GameManager:
# [...]
def game_checking(self):
#---checking---#
self.can_jump = False
for sprite_platform in self.platform_group.sprites():
if sprite_platform.can_jump_check() == True:
self.can_jump = True
return self.can_jump
This can be simplified with the any function:
class PlatformRect(pygame.sprite.Sprite):
# [...]
def game_checking(self):
#---checking---#
self.can_jump = any(p.can_jump_check() for p in self.platform_group)
return self.can_jump
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.
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.
For my code, I would like the chickens (enemies) to move 4 different ways:
vertical, horizontal, diagonal and following the player (pig).
Each chicken should have its own movement and move independently. Only two chickens can go in diagonal.
I have only programmed their vertical and horizontal movements but there is a problem with them; sometimes, they all move horizontally, sometimes, vertically. Sometimes they don't move at all.
Here is my code:
def game_loop():
x_change = 0
y_change = 0
foodCounter = 0
Score = 0
list = ["Vertical","Vertical","Horizontal","Horizontal","Follow","Diagonal1","Diagonal2"]
baddies = []
item = 0
x = (display_width * 0.45)
y = (display_height * 0.8)
foodx = random.randrange(48, display_width - 48)
foody = random.randrange(54, display_height - 54)
gameExit = False
while not gameExit:
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:
x_change = -8
if event.key == pygame.K_RIGHT:
x_change = 8
if event.key == pygame.K_UP:
y_change = -8
if event.key == pygame.K_DOWN:
y_change = 8
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
if x > 705:
x_change = 0
x = 705
if x < -10:
x_change = 0
x = -10
if y < -15:
y_change = 0
y = -15
if y > 505:
y_change = 0
y = 505
x += x_change
y += y_change
gameDisplay.fill(white)
gameDisplay.blit(background,(-50,-50))
food = pygame.Rect(foodx, foody,48 , 54)
if foodCounter == 0:
gameDisplay.blit(foodImage, food)
player = pygame.Rect(x, y,108,105)
if player.colliderect(food):
foodCounter += -1
Score += 1
foodx = random.randrange(48, display_width - 48)
foody = random.randrange(54, display_height - 54)
foodCounter += 1
item = random.randint(1, len(list))
print(item)
if item == 1 or item == 2:
newchicken = {'rect':pygame.Rect(random.randint(0,display_width-45),0,45,63),
'surface':pygame.transform.scale(enemyImage,(45,63)),
'vertical': "vertical",
'down': "down"
}
item = 0
baddies.append(newchicken)
if item == 3 or item == 4:
newchicken = {'rect':pygame.Rect(0,random.randint(0,display_height-45),45,63),
'surface': pygame.transform.scale(enemyImage, (45,63)),
'horizontal': "horizontal",
'right': "right"
}
item = 0
baddies.append(newchicken)
if item == 6:
newchicken = {'rect':pygame.Rect(200,0,45,63),
'surface':pygame.transform.scale(enemyImage,(45,63)),
'diagonal1': "diagonal1"
}
if "Diagonal1" in list:
list.remove("Diagonal1")
item = 0
baddies.append(newchicken)
if len(list) == 7:
if item == 7:
newchicken = {'rect':pygame.Rect(100,600,45,63),
'surface':pygame.transform.scale(enemyImage,(45,63)),
'diagonal2': "diagonal2"
}
if "Diagonal2" in list:
list.remove("Diagonal2")
item = 0
baddies.append(newchicken)
if len(list) == 6:
if item == 6:
newchicken = {'rect':pygame.Rect(100,600,45,63),
'surface':pygame.transform.scale(enemyImage,(45,63)),
'diagonal2': "diagonal2"
}
if "Diagonal2" in list:
list.remove("Diagonal2")
item = 0
baddies.append(newchicken)
gameDisplay.blit(pigImage, player)
for b in baddies:
gameDisplay.blit(b['surface'],b['rect'])
for b in baddies:
if "vertical" in newchicken:
if "down" in newchicken:
if not b['rect'].bottom >= 600:
b['rect'].move_ip(0, 2)
if b['rect'].bottom >= 600 :
del newchicken['down']
newchicken["up"] = "up"
if "up" in newchicken:
if not b['rect'].top <= 0:
b['rect'].move_ip(0,-2)
if b['rect'].top <= 0:
del newchicken ['up']
newchicken["down"] = "down"
if "horizontal" in newchicken:
print ("horizontal")
if "right" in newchicken:
if not b['rect'].right >= 800:
b['rect'].move_ip(2,0)
if b['rect'].right >= 800:
del newchicken['right']
newchicken['left'] = "left"
if "left" in newchicken:
if not b['rect'].left <= 0:
b['rect'].move_ip(-2,0)
if b['rect'].left <= 0:
del newchicken ['left']
newchicken['right'] = "right"
pygame.display.update()
clock.tick(60)
game_loop()
Your code does not work because you always check for keys in newchicken when you iterate over baddies, while I guess you should check b instead.
But what you should do instead is to change your code in a way that seperates the different logical concerns of your game. Also, just use a class instead of a dict to group data and behaviour that belongs together.
Let's think a bit:
We have some kind of entity that basically consists of three things: an image, a position, and a behavior. You already know this, because you created these dicts:
newchicken = {'rect':pygame.Rect(100,600,45,63),
'surface':pygame.transform.scale(enemyImage,(45,63)),
'diagonal2': "diagonal2"
}
Let's tweak this a bit and use a Sprite (really, read the docs), which already has these things (more or less). Our class class could look like this (and don't tell me you don't want to use classes. That's stupid IMHO since you already use dozens of classes):
class Animal(pg.sprite.Sprite):
def __init__(self, color, pos, logic, *groups):
super().__init__(*groups)
self.image = pg.surface.Surface((40, 40))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
self.logic = logic
self.direction = pg.Vector2((0, 0))
def update(self):
self.logic(self)
So, we have an image (which is just a plain rect so we have a working game at the end that everybody can copy/paste and run), a rect that stores the position, a mysterious logic argument that's a function (the "AI" of our animal) which will be called every tick, and a direction, which defines in which direction out animal will walk.
So, let's create the actual logic that will move out animals. We create three functions, one for vertical movement, one for horizontal movement, and one that will always walk towards the mouse cursor:
def move_vertical(animal):
if animal.direction.length() == 0:
animal.direction = pg.Vector2(5, 0)
animal.rect.move_ip(*animal.direction)
if not screen_rect.contains(animal.rect):
animal.direction *= -1
animal.rect.move_ip(animal.direction)
def move_horizontal(animal):
if animal.direction.length() == 0:
animal.direction = pg.Vector2(0, 5)
animal.rect.move_ip(*animal.direction)
if not screen_rect.contains(animal.rect):
animal.direction *= -1
animal.rect.move_ip(animal.direction)
def move_to_mouse(animal):
pos = pg.mouse.get_pos()
v = pg.Vector2(pos) - pg.Vector2(animal.rect.center)
if v.length() > 0:
v.normalize_ip()
v *= 5
animal.rect.move_ip(*v)
If we now want to create an Animal, we simply pass one of those functions to the constructor. No need for massive if/else blocks in your main loop (note how clean and simple it is in the end).
So, here's our final example. Note how we create four animals: two that move vertically, one that moves horizontally, and one that follows the mouse.
import pygame as pg
pg.init()
clock = pg.time.Clock()
running = True
screen = pg.display.set_mode((640, 480))
screen.fill((255, 255, 255))
screen_rect = screen.get_rect()
def move_vertical(animal):
if animal.direction.length() == 0:
animal.direction = pg.Vector2(5, 0)
animal.rect.move_ip(*animal.direction)
if not screen_rect.contains(animal.rect):
animal.direction *= -1
animal.rect.move_ip(animal.direction)
def move_horizontal(animal):
if animal.direction.length() == 0:
animal.direction = pg.Vector2(0, 5)
animal.rect.move_ip(*animal.direction)
if not screen_rect.contains(animal.rect):
animal.direction *= -1
animal.rect.move_ip(animal.direction)
def move_to_mouse(animal):
pos = pg.mouse.get_pos()
v = pg.Vector2(pos) - pg.Vector2(animal.rect.center)
if v.length() > 0:
v.normalize_ip()
v *= 5
animal.rect.move_ip(*v)
class Animal(pg.sprite.Sprite):
def __init__(self, color, pos, logic, *groups):
super().__init__(*groups)
self.image = pg.surface.Surface((40, 40))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=pos)
self.logic = logic
self.direction = pg.Vector2((0, 0))
def update(self):
self.logic(self)
sprites = pg.sprite.Group()
Animal(pg.color.Color('yellow'), ( 10, 10), move_vertical, sprites)
Animal(pg.color.Color('red'), (200, 400), move_vertical, sprites)
Animal(pg.color.Color('orange'), (500, 100), move_horizontal, sprites)
Animal(pg.color.Color('brown'), (100, 200), move_to_mouse, sprites)
while running:
for e in pg.event.get():
if e.type == pg.QUIT:
running = False
sprites.update()
screen.fill((255, 255, 255))
sprites.draw(screen)
pg.display.update()
clock.tick(60)
I'm making a version of http://agar.io and i'm trying to make the circle shape for the player. I have been trying to use pygame.draw.circle to draw it, however it keeps showing a square. Thanks for help!
import pygame, sys, random
from pygame.locals import *
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
width = 600
height = 800
screen = pygame.display.set_mode((width, height), 0, 32)
pygame.display.set_caption('Agar.io')
# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
# set up the player and food data structure
foodCounter = 0
NEWFOOD = 0
FOODSIZE = 20
player = pygame.draw.circle(screen, WHITE, (60, 250), 40)
foods = []
for i in range(20):
foods.append(pygame.Rect(random.randint(0, width - FOODSIZE), random.randint(0, height - FOODSIZE), FOODSIZE, FOODSIZE))
# set up movement variables
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
MOVESPEED = 10
# run the game loop
while True:
# check for events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
# change the keyboard variables
if event.key == K_LEFT or event.key == ord('a'):
moveRight = False
moveLeft = True
if event.key == K_RIGHT or event.key == ord('d'):
moveLeft = False
moveRight = True
if event.key == K_UP or event.key == ord('w'):
moveDown = False
moveUp = True
if event.key == K_DOWN or event.key == ord('s'):
moveUp = False
moveDown = True
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == ord('a'):
moveLeft = False
if event.key == K_RIGHT or event.key == ord('d'):
moveRight = False
if event.key == K_UP or event.key == ord('w'):
moveUp = False
if event.key == K_DOWN or event.key == ord('s'):
moveDown = False
if event.key == ord('x'):
player.top = random.randint(0, height - player.height)
player.left = random.randint(0, width - player.width)
if event.type == MOUSEBUTTONUP:
foods.append(pygame.Rect(event.pos[0], event.pos[1], FOODSIZE, FOODSIZE))
foodCounter += 1
if foodCounter >= NEWFOOD:
# add new food
foodCounter = 0
foods.append(pygame.Rect(random.randint(0, width - FOODSIZE), random.randint(0, height - FOODSIZE), FOODSIZE, FOODSIZE))
# draw the black background onto the surface
screen.fill(BLACK)
# move the player
if moveDown and player.bottom < height:
player.top += MOVESPEED
if moveUp and player.top > 0:
player.top -= MOVESPEED
if moveLeft and player.left > 0:
player.left -= MOVESPEED
if moveRight and player.right < width:
player.right += MOVESPEED
# draw the player onto the surface
pygame.draw.rect(screen, WHITE, player)
# check if the player has intersected with any food squares.
for food in foods[:]:
if player.colliderect(food):
foods.remove(food)
player.width+=1
player.height+=1
# draw the food
for i in range(len(foods)):
pygame.draw.rect(screen, GREEN, foods[i])
# draw the window onto the screen
pygame.display.update()
mainClock.tick(40)
Your immediate problem can be solved by using pygame.draw.circle instead of pygame.draw.rect:
# draw the player onto the surface
pygame.draw.circle(screen, WHITE, player.center, 40)
You are creating your player object with:
player = pygame.draw.circle(screen, WHITE, (60, 250), 40)
pygame.draw.circle returns a Rect object (not a circle object, which you might have expected), and you can use its .center attribute as the center of the circle.
here is my agar.io code:
import pygame,random,math
pygame.init()
place_10 = 500
place_9 = random.randint(501, 550)
place_8 = random.randint(551, 600)
place_7 = random.randint(601, 650)
place_6 = random.randint(651, 700)
place_5 = random.randint(701, 750)
place_4 = random.randint(751, 800)
place_3 = random.randint(801, 850)
place_2 = random.randint(851, 900)
place_1 = 950
colors_players = [(37,7,255),(35,183,253),(48,254,241),(19,79,251),(255,7,230),(255,7,23),(6,254,13)]
colors_cells = [(80,252,54),(36,244,255),(243,31,46),(4,39,243),(254,6,178),(255,211,7),(216,6,254),(145,255,7),(7,255,182),(255,6,86),(147,7,255)]
colors_viruses = [(66,254,71)]
screen_width, screen_height = (800,500)
surface = pygame.display.set_mode((screen_width,screen_height))
t_surface = pygame.Surface((95,25),pygame.SRCALPHA) #transparent rect for score
t_lb_surface = pygame.Surface((155,278),pygame.SRCALPHA) #transparent rect for leaderboard
t_surface.fill((50,50,50,80))
t_lb_surface.fill((50,50,50,80))
pygame.display.set_caption("Agar.io")
cell_list = list()
clock = pygame.time.Clock()
try:
font = pygame.font.Font("Ubuntu-B.ttf",20)
big_font = pygame.font.Font("Ubuntu-B.ttf",24)
except:
print("Font file not found: Ubuntu-B.ttf")
font = pygame.font.SysFont('Ubuntu',20,True)
big_font = pygame.font.SysFont('Ubuntu',24,True)
def drawText(message,pos,color=(255,255,255)):
surface.blit(font.render(message,1,color),pos)
def getDistance(pos1,pos2):
px,py = pos1
p2x,p2y = pos2
diffX = math.fabs(px-p2x)
diffY = math.fabs(py-p2y)
return ((diffX**2)+(diffY**2))**(0.5)
class Camera:
def __init__(self):
self.x = 0
self.y = 0
self.width = screen_width
self.height = screen_height
self.zoom = 0.5
def centre(self,blobOrPos):
if(isinstance(blobOrPos,Player)):
p = blobOrPos
self.x = (p.startX-(p.x*self.zoom))-p.startX+((screen_width/2))
self.y = (p.startY-(p.y*self.zoom))-p.startY+((screen_height/2))
elif(type(blobOrPos) == tuple):
self.x,self.y = blobOrPos
class Player:
def __init__(self,surface,name = ""):
self.startX = self.x = random.randint(100,400)
self.startY = self.y = random.randint(100,400)
self.mass = 20
self.surface = surface
self.color = colors_players[random.randint(0,len(colors_players)-1)]
self.name = name
self.pieces = list()
piece = Piece(surface,(self.x,self.y),self.color,self.mass,self.name)
def update(self):
self.move()
self.collisionDetection()
def collisionDetection(self):
for cell in cell_list:
if(getDistance((cell.x,cell.y),(self.x,self.y)) <= self.mass/2):
self.mass+=0.5
cell_list.remove(cell)
cell = Cell(surface)
cell_list.append(cell)
def move(self):
dX,dY = pygame.mouse.get_pos()
rotation = math.atan2(dY-(float(screen_height)/2),dX-(float(screen_width)/2))*180/math.pi
speed = 5-1
vx = speed * (90-math.fabs(rotation))/90
vy = 0
if(rotation < 0):
vy = -speed + math.fabs(vx)
else:
vy = speed - math.fabs(vx)
self.x += vx
self.y += vy
def feed(self):
pass
def split(self):
pass
def draw(self,cam):
col = self.color
zoom = cam.zoom
x = cam.x
y = cam.y
pygame.draw.circle(self.surface,(col[0]-int(col[0]/3),int(col[1]-col[1]/3),int(col[2]-col[2]/3)),(int(self.x*zoom+x),int(self.y*zoom+y)),int((self.mass/2+3)*zoom))
pygame.draw.circle(self.surface,col,(int(self.x*cam.zoom+cam.x),int(self.y*cam.zoom+cam.y)),int(self.mass/2*zoom))
if(len(self.name) > 0):
fw, fh = font.size(self.name)
drawText(self.name, (self.x*cam.zoom+cam.x-int(fw/2),self.y*cam.zoom+cam.y-int(fh/2)),(50,50,50))
class Piece:
def __init__(self,surface,pos,color,mass,name,transition=False):
self.x,self.y = pos
self.mass = mass
self.splitting = transition
self.surface = surface
self.name = name
def draw(self):
pass
def update(self):
if(self.splitting):
pass
class Cell:
def __init__(self,surface):
self.x = random.randint(20,1980)
self.y = random.randint(20,1980)
self.mass = random.randint(6, 8)
self.surface = surface
self.color = colors_cells[random.randint(0,len(colors_cells)-1)]
def draw(self,cam):
pygame.draw.circle(self.surface,self.color,(int((self.x*cam.zoom+cam.x)),int(self.y*cam.zoom+cam.y)),int(self.mass*cam.zoom))
def spawn_cells(numOfCells):
for i in range(numOfCells):
cell = Cell(surface)
cell_list.append(cell)
def draw_grid():
for i in range(0,2001,25):
pygame.draw.line(surface,(230,240,240),(0+camera.x,i*camera.zoom+camera.y),(2001*camera.zoom+camera.x,i*camera.zoom+camera.y),3)
pygame.draw.line(surface,(230,240,240),(i*camera.zoom+camera.x,0+camera.y),(i*camera.zoom+camera.x,2001*camera.zoom+camera.y),3)
camera = Camera()
blob = Player(surface,"person x")
spawn_cells(2000)
def draw_HUD():
w,h = font.size("Score: "+str(int(blob.mass*2))+" ")
surface.blit(pygame.transform.scale(t_surface,(w,h)),(8,screen_height-30))
surface.blit(t_lb_surface,(screen_width-160,15))
drawText("Score: " + str(int(blob.mass*2)),(10,screen_height-30))
surface.blit(big_font.render("Leaderboard",0,(255,255,255)),(screen_width-157,20))
if blob.mass >= place_1:
drawText("1. person x", (screen_width-157,20+25))
else:
drawText("1. team",(screen_width-157,20+25))
if blob.mass >= place_2 and blob.mass < place_1:
drawText("2. person x", (screen_width-157,20+25*2))
else:
drawText("2. help",(screen_width-157,20+25*2))
if blob.mass >= place_3 and blob.mass < place_2:
drawText("3. person x", (screen_width-157,20+25*3))
else:
drawText("3. ISIS",(screen_width-157,20+25*3))
if blob.mass >= place_4 and blob.mass < place_3:
drawText("4. person x", (screen_width-157,20+25*4))
else:
drawText("4. ur mom",(screen_width-157,20+25*4))
if blob.mass >= place_5 and blob.mass < place_4:
drawText("5. person x", (screen_width-157,20+25*5))
else:
drawText("5. w = pro team",(screen_width-157,20+25*5))
if blob.mass >= place_6 and blob.mass < place_5:
drawText("6. person x", (screen_width-157,20+25*6))
else:
drawText("6. jumbo",(screen_width-157,20+25*6))
if blob.mass >= place_7 and blob.mass < place_6:
drawText("7. person x", (screen_width-157,20+25*7))
else:
drawText("7. [cg]team",(screen_width-157,20+25*7))
if blob.mass >= place_8 and blob.mass < place_7:
drawText("8. person x", (screen_width-157,20+25*8))
else:
drawText("8. jack",(screen_width-157,20+25*8))
if blob.mass >= place_9 and blob.mass < place_8:
drawText("9. person x", (screen_width-157,20+25*9))
else:
drawText("9. doge",(screen_width-157,20+25*9))
if blob.mass >= place_10 and blob.mass < place_9:
drawText("10. person x",(screen_width-157,20+25*10))
else:
drawText("10. happy",(screen_width-157,20+25*10),(210,0,0))
while(True):
clock.tick(70)
for e in pygame.event.get():
if(e.type == pygame.KEYDOWN):
if(e.key == pygame.K_ESCAPE):
pygame.quit()
quit()
if(e.key == pygame.K_SPACE):
blob.split()
if(e.key == pygame.K_w):
blob.feed()
if(e.type == pygame.QUIT):
pygame.quit()
quit()
blob.update()
camera.zoom = 100/(blob.mass)+0.3
camera.centre(blob)
surface.fill((242,251,255))
#surface.fill((0,0,0))
draw_grid()
for c in cell_list:
c.draw(camera)
blob.draw(camera)
draw_HUD()
pygame.display.flip()