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)
Related
I want the obstacle sprite, which are asteroids, to fall from the top of the screen to the bottom. I havent added any code to mess with the collisions of the asteroids, gravity, etc. because I can't even get the sprite to appear on the screen. Here is my code below (I tried using sprite classes but for me personally it made it a lot more confusing and difficult, so I chose not to.)
from sys import exit
from random import randint
def animation_state():
global player_surface, player_index, player_rect
player_index += 0.15
if player_index >= len(player_right_walk):
player_index = 0
if LEFT == True:
player_surface = player_left_walk[int(player_index)]
elif RIGHT == True:
player_surface = player_right_walk[int(player_index)]
if LEFT == False and RIGHT == False:
player_surface = pygame.image.load('graphics/dino_idle_right.png').convert_alpha()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player_surface = pygame.image.load('graphics/dino_idle_left.png').convert_alpha()
elif event.key == pygame.K_RIGHT:
player_surface = pygame.image.load('graphics/dino_idle_right.png').convert_alpha()
screen.blit(player_surface,player_rect)
def player_control():
global LEFT, RIGHT
player_velocity = 0
player_gravity = 0
player_gravity += 3
player_rect.y += player_gravity
if player_rect.bottom >= 500:
player_rect.bottom = 500
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_velocity -= 6
LEFT = True
RIGHT = False
if player_rect.x < -50:
player_rect.x = 800
elif keys[pygame.K_RIGHT]:
player_velocity += 6
LEFT = False
RIGHT = True
if player_rect.x > 800:
player_rect.x = -50
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or pygame.K_RIGHT:
player_velocity = 0
player_rect.x += player_velocity
def display_score():
current_time = int(pygame.time.get_ticks() / 1000) - start_time
score_surface = font.render('Score: ' + str(current_time),False,(64,64,64))
score_rect = score_surface.get_rect(center = (375, 30))
screen.blit(score_surface, score_rect)
return current_time
def game_over_screen():
player_stand = pygame.image.load('graphics/dino_stand.png').convert_alpha()
player_stand = pygame.transform.rotozoom(player_stand,0,4).convert_alpha()
player_stand_rect = player_stand.get_rect(center = (375,280))
game_name = font.render('Personal Project Game', False, (111,196,169))
game_name_rect = game_name.get_rect(center = (375,100))
game_message = font.render('Press Space to start',False, 'Black')
game_message_rect = game_message.get_rect(center = (375, 500))
screen.blit(background_surface,(0,0))
screen.blit(player_stand,player_stand_rect)
screen.blit(game_name,game_name_rect)
screen.blit(game_message,game_message_rect)
def asteroid_animation_state():
global asteroid_surface, asteroid_index, asteroid_rect
asteroid_1 = pygame.image.load('graphics/asteroid_1.png').convert_alpha()
asteroid_1 = pygame.transform.rotozoom(asteroid_1,-45,0)
asteroid_2 = pygame.image.load('graphics/asteroid_2.png').convert_alpha()
asteroid_2 = pygame.transform.rotozoom(asteroid_2,-45,0)
asteroid_frames = [asteroid_1,asteroid_2]
asteroid_index = 0
asteroid_surface = asteroid_frames[asteroid_index]
asteroid_rect = asteroid_surface.get_rect(midtop = (randint(0,751),-20))
asteroid_index += 0.1
if asteroid_index >= len(asteroid_frames):
asteroid_index = 0
asteroid_surface = asteroid_frames[int(asteroid_index)]
asteroid_rect.bottom += 10
if asteroid_rect.bottom >=600:
asteroid_rect.bottom = -20
screen.blit(asteroid_surface,asteroid_rect)
pygame.init()
pygame.display.set_caption('Escape Extinction')
screen = pygame.display.set_mode((750,563))
clock = pygame.time.Clock()
LEFT = False
RIGHT = False
start_time = 0
score = 0
font = pygame.font.Font('fonts/atari-font-full-version/atari_full.ttf', 25)
player_right_1 = pygame.image.load('graphics/dino_1_right.png').convert_alpha()
player_right_2 = pygame.image.load('graphics/dino_2_right.png').convert_alpha()
player_right_3 = pygame.image.load('graphics/dino_3_right.png').convert_alpha()
player_right_4 = pygame.image.load('graphics/dino_4_right.png').convert_alpha()
player_left_1 = pygame.image.load('graphics/dino_1_left.png').convert_alpha()
player_left_2 = pygame.image.load('graphics/dino_2_left.png').convert_alpha()
player_left_3 = pygame.image.load('graphics/dino_3_left.png').convert_alpha()
player_left_4 = pygame.image.load('graphics/dino_4_left.png').convert_alpha()
player_right_walk = [player_right_1,player_right_2,player_right_3,player_right_4]
player_left_walk = [player_left_1,player_left_2,player_left_3,player_left_4]
player_index = 0
#player_surface_right = player_right_walk[player_index]
#player_surface_left = player_left_walk[player_index]
player_surface = player_right_walk[player_index]
player_rect = player_surface.get_rect(midbottom = (375,300))
background_surface = pygame.image.load('graphics/jumperbackground.png').convert()
ground_surface = pygame.image.load('graphics/grass.png').convert()
#obstacle_timer = pygame.USEREVENT + 1
#pygame.time.set_timer(obstacle_timer,1400)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
#if event.type == obstacle_timer:
# obstacle.add(Asteroid('asteroid'))
screen.blit(background_surface,(0,0))
screen.blit(ground_surface,(0,480))
player_control()
animation_state()
display_score()
asteroid_animation_state()
pygame.display.update()
clock.tick(60)
Reading the documentation on the pygame.transform.rotozoom() function :
rotozoom(surface, angle, scale) -> Surface
This is a combined scale and rotation transform. The resulting Surface will be a filtered 32-bit Surface. The scale argument is a floating point value that will be multiplied by the current resolution. The angle argument is a floating point value that represents the counterclockwise degrees to rotate. A negative rotation angle will rotate clockwise.
So your image loading code is scaling the images by a factor of 0. So the resultant surface would have a zero size.
Probably you meant this to be 1.0, which would leave them the original size.
asteroid_1 = pygame.image.load('graphics/asteroid_1.png').convert_alpha()
asteroid_1 = pygame.transform.rotozoom( asteroid_1, -45, 1.0 )
asteroid_2 = pygame.image.load('graphics/asteroid_2.png').convert_alpha()
asteroid_2 = pygame.transform.rotozoom( asteroid_2, -45, 1.0 )
This question already has an answer here:
How do I get the snake to grow and chain the movement of the snake's body?
(1 answer)
Closed 1 year ago.
I'm new to python and only now the basics, I'm trying to make a snake game but I can't seem to figure out how to make my snake grow 1 extra square each time it eats an apple. My reasoning is that I keep a list of all the old positions but only show the last one on the screen, and each time the snakes eats another apple it shows 1 extra old positions making the snake 1 square longer.
This is my code:
import pygame
from random import randint
WIDTH = 400
HEIGHT = 300
dis = pygame.display.set_mode((WIDTH,HEIGHT))
white = (255,255,255)
BACKGROUND = white
blue = [0,0,255]
red = [255,0,0]
class Snake:
def __init__(self):
self.image = pygame.image.load("snake.bmp")
self.rect = self.image.get_rect()
self.position = (10,10)
self.direction = [0,0]
self.positionslist = [self.position]
self.length = 1
pygame.display.set_caption('Snake ')
def draw_snake(self,screen):
screen.blit(self.image, self.position)
def update(self):
self.position = (self.position[0] + self.direction[0],self.position[1] + self.direction[1])
self.rect = (self.position[0],self.position[1],5, 5 )
self.positionslist.append(self.position)
if self.position[0]< 0 :
self.position = (WIDTH,self.position[1])
elif self.position[0] > WIDTH:
self.position = (0,self.position[1])
elif self.position[1] > HEIGHT:
self.position = (self.position[0],0)
elif self.position[1] < 0 :
self.position = (self.position[0],HEIGHT)
class Food:
def __init__(self):
self.image = pygame.image.load("appel.png")
self.rect = self.image.get_rect()
apple_width = -self.image.get_width()
apple_height = -self.image.get_height()
self.position = (randint(0,WIDTH+apple_width-50),randint(0,HEIGHT+apple_height-50))
self.rect.x = self.position[0]
self.rect.y = self.position[1]
def draw_appel(self,screen):
screen.blit(self.image, self.position)
def eat_appel (self, snake):
if self.rect.colliderect(snake.rect) == True:
self.position = (randint(0,WIDTH),randint(0,HEIGHT))
self.rect.x = self.position[0]
self.rect.y = self.position[1]
snake.length += 1
def main():
game_over = False
while not game_over:
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
snake = Snake()
food = Food()
while True:
screen.fill(BACKGROUND)
font = pygame.font.Font('freesansbold.ttf', 12)
text = font.render(str(snake.length), True, red, white)
textRect = text.get_rect()
textRect.center = (387, 292)
screen.blit(text,textRect)
snake.update()
#snake.update_list()
snake.draw_snake(screen)
food.draw_appel(screen)
food.eat_appel(snake)
pygame.display.flip()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
snake.direction = [0,1]
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
snake.direction = [1,0]
if event.key == pygame.K_LEFT:
snake.direction = [-1,0]
if event.key == pygame.K_UP:
snake.direction = [0,-1]
if event.key == pygame.K_DOWN:
snake.direction = [0,1]
if __name__ == "__main__":
main()
This can have multiple reasons. Firstly, I saw you tried to increase the length of the snake by typing snake.length += 1, which may work (probably won't because the module pygame allows the snake to hover around, but not like the loop or conditional statements). One of my tips would be, to increase the length of the snake by using the idea of adding the score with your present snake.length every time (because once your score is 1 by eating an apple, your snake.length would be 2. And it increases with the score). This is my code (a few modifications might be needed):
import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
orange = (255, 165, 0)
width, height = 600, 400
game_display = pygame.display.set_mode((width, height))
pygame.display.set_caption("Snake Mania")
clock = pygame.time.Clock()
snake_size = 10
snake_speed = 15
message_font = pygame.font.SysFont('ubuntu', 30)
score_font = pygame.font.SysFont('ubuntu', 25)
def print_score(score):
text = score_font.render("Score: " + str(score), True, orange)
game_display.blit(text, [0,0])
def draw_snake(snake_size, snake_pixels):
for pixel in snake_pixels:
pygame.draw.rect(game_display, white, [pixel[0], pixel[1], snake_size, snake_size])
def run_game():
game_over = False
game_close = False
x = width / 2
y = height / 2
x_speed = 0
y_speed = 0
snake_pixels = []
snake_length = 1
target_x = round(random.randrange(0, width - snake_size) / 10.0) * 10.0
target_y = round(random.randrange(0, height - snake_size) / 10.0) * 10.0
while not game_over:
while game_close:
game_display.fill(black)
game_over_message = message_font.render("Game Over!", True, red)
game_display.blit(game_over_message, [width / 3, height / 3])
print_score(snake_length - 1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
game_over = True
game_close = False
if event.key == pygame.K_2:
run_game()
if event.type == pygame.QUIT:
game_over = True
game_close = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_speed = -snake_size
y_speed = 0
if event.key == pygame.K_RIGHT:
x_speed = snake_size
y_speed = 0
if event.key == pygame.K_UP:
x_speed = 0
y_speed = -snake_size
if event.key == pygame.K_DOWN:
x_speed = 0
y_speed = snake_size
if x >= width or x < 0 or y >= height or y < 0:
game_close = True
x += x_speed
y += y_speed
game_display.fill(black)
pygame.draw.rect(game_display, orange, [target_x, target_y, snake_size, snake_size])
snake_pixels.append([x, y])
if len(snake_pixels) > snake_length:
del snake_pixels[0]
for pixel in snake_pixels[:-1]:
if pixel == [x, y]:
game_close = True
draw_snake(snake_size, snake_pixels)
print_score(snake_length - 1)
pygame.display.update()
if x == target_x and y == target_y:
target_x = round(random.randrange(0, width - snake_size) / 10.0) * 10.0
target_y = round(random.randrange(0, height - snake_size) / 10.0) * 10.0
snake_length += 1
clock.tick(snake_speed)
pygame.quit()
quit()
run_game()
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()
After hours of searching, I still can't figure out why only the most recently spawned circle is affected by the collision detection. I commented out the code in question. I experimented with sprites and that may be the answer but I still got the same results.
import pygame,random
pygame.init()
width,height,radius = 1280,720,20
class Ball():
def __init__(self):
self.x = 0
self.y = 0
self.vx = 0
self.vy = 0
def make_ball():
ball = Ball()
ball.x = random.randrange(radius, width - radius)
ball.y = random.randrange(radius, 100)
ball.vx = random.randint(1,2)
ball.vy = 0
return ball
def main():
rect_x = 60
display = pygame.display.set_mode((width,height))
pygame.display.set_caption("BOUNCE")
running = True
ball_list = []
ball = make_ball()
ball_list.append(ball)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
ball = make_ball()
ball_list.append(ball)
for ball in ball_list:
ball.x += ball.vx
ball.vy += 0.02
ball.y += ball.vy
if ball.y >= height - radius:
ball.vy *= -1
if ball.x >= width - radius or ball.x <= radius:
ball.vx *= -1
display.fill((0,0,0))
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and rect_x > 0:
rect_x -= 2
if event.key == pygame.K_RIGHT and rect_x < width - 60:
rect_x += 2
'''if pygame.Rect(circle).colliderect(rectangle) == True: ###THIS IS THE BAD CODE!
print('Your Score:',pygame.time.get_ticks())
running = False'''
text = pygame.font.Font(None,120).render(str(pygame.time.get_ticks()),True,(255,255,255))
display.blit(text,(50,50))
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Indentation and code organization is the key to this. the offending section is (comments removed):
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and rect_x > 0:
rect_x -= 2
if event.key == pygame.K_RIGHT and rect_x < width - 60:
rect_x += 2
if pygame.Rect(circle).colliderect(rectangle) == True:
print('Your Score:',pygame.time.get_ticks())
running = False
You had all the correct pieces, but the order in which you are doing them is off as well as the indentation:
for ball in ball_list:
random_color = (random.randint(1,255),random.randint(1,255),random.randint(1,255))
circle = pygame.draw.circle(display,random_color,(int(ball.x), int(ball.y)),radius)
rectangle = pygame.draw.rect(display,(255,255,255),(int(rect_x),660,60,60))
if pygame.Rect(circle).colliderect(rectangle):
print('Your Score:',pygame.time.get_ticks())
running = False
This will now run through every ball in the list and check each one for collision. notice the colliderect if statement is indented into the for loop. Also notice i removed the KEYDOWN check from in the middle of it all
Speaking of that I would recommend using:
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT] and rect_x > 0:
rect_x -= 2
if pressed[pygame.K_RIGHT] and rect_x < width - 60:
rect_x += 2
for ball in ball_list:
# for loop from above
instead of what you had. This works best for when you want to allow for holding a key down. pygame.key.get_pressed() gets the state of all the keys all the time, not just when an event happens
the stickman I have is able to move and all, using the arrow keys, and but, when the up arrow key is pressed, I want him to only be able to go about 10 units every time the key is pressed, no matter how long it is pressed for. In other words I want him to jump, and have a limit to how high he can jump. I've tried a couple things but nothing has worked.
import pygame
def drawMan(screen,x,y):
#head
pygame.draw.ellipse(screen,BLACK,[0+x,0+y,10,10], 0)
#body
pygame.draw.line(screen,BLACK,[4+x,17+y],[4+x,7+y], 2)
#legs
pygame.draw.line(screen,BLACK,[4+x,17+y],[9+x,27+y], 2)
pygame.draw.line(screen,BLACK,[4+x,17+y],[-1+x,27+y], 2)
#arms
pygame.draw.line(screen,BLACK,[4+x,7+y],[8+x,17+y], 2)
pygame.draw.line(screen,BLACK,[4+x,7+y],[0+x,17+y], 2)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BORDER = (100,100,100)
pygame.init()
size = (800, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Jump")
done = False
clock = pygame.time.Clock()
pygame.mouse.set_visible(1)
xCoord = 11
yCoord = 463
xSpeed = 0
ySpeed = 0
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xSpeed = -3
if event.key == pygame.K_RIGHT:
xSpeed = 3
if event.key == pygame.K_UP:
ySpeed = -3
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
xSpeed = 0
if event.key == pygame.K_RIGHT:
xSpeed = 0
if event.key == pygame.K_UP:
ySpeed = 3
if xCoord >= 780:
xSpeed = 0
xCoord -= 1
elif xCoord <= 13:
xSpeed = 0
xCoord += 1
elif yCoord > 465:
ySpeed = 0
yCoord -= 1
elif yCoord <= 13:
ySpeed = 0
yCoord += 1
else:
xCoord += xSpeed
yCoord += ySpeed
screen.fill(WHITE)
pygame.draw.line(screen, BORDER, [0,0],[800,0], 20)
pygame.draw.line(screen, BORDER, [0,0],[0,500], 20)
pygame.draw.line(screen, BORDER, [0,500],[800,500], 20)
pygame.draw.line(screen, BORDER, [800,500],[800,0], 20)
drawMan(screen,xCoord,yCoord)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Set a variable that allows him to jump. If the variable isn't True, then the jump key does nothing.
When he jumps, switch the variable to False. Don't reset it until he hits the ground again.
Pseudocode:
IF INPUT = "jump" AND can_jump == True THEN
can_jump = False
player.jump()
END IF
IF player.y == 0 and can_jump == False THEN
can_jump = True
END IF
dudee i know it is so late but i found out the answer for this and it is a simple thing
import pygame as game
import keyboard
game.init()
dis=game.display.set_mode((1280,720))
state=0
simpclr=(24,24,24)
white=(255,255,255)
posx=5
posy=5
a=0
jcd=1
clock=game.time.Clock()
while not state:
for event in game.event.get():
if event.type==game.QUIT:
state=1
dis.fill(white)
pl=game.Rect(posx,posy,20,20)
game.draw.rect(dis,simpclr,pl)
game.display.flip()
posy+=2
if keyboard.is_pressed('d'):
posx+=5
if jcd<10:
if keyboard.is_pressed(" "):
posy-=10
jcd+=1
if jcd<50 and jcd>=10:
jcd+=1
if jcd==50:
jcd=1
if posx==1230:
posx-=5
if posy==100:
posy-=5
game.display.flip()
clock.tick(60)
game.quit()