I am trying to figure out how to increase the intensity of my shapes moving when holding the 'up' arrow key. When I hold space bar, I wanted my shapes to rumble based on the intensity, which I've done. What I also would like to do is be able to increase the intensity by pressing the 'up' arrow key once (NOTE: Once. Currently when I press the arrow key once, it loops way too fast and multiplies the intensity by like 5000x. I would like it just to add one number each time.) This is the code that does not work how I'd like.
import pygame
import random
import time
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# Edit the intensity of the shake (Must be one number apart)
# Ex: a = -100, b = 101. A is negative, B is positive
a = -4
b = 5
up = 10
intensity = (a, b)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
done = False
clock = pygame.time.Clock()
class Rectangle():
def __init__(self):
self.x = random.randrange(0, 700)
self.y = random.randrange(0, 500)
self.height = random.randrange(20, 70)
self.width = random.randrange(20, 70)
self.x_change = random.randrange(-3, 3)
self.y_change = random.randrange(-3, 3)
self.color = random.sample(range(250), 4)
def draw(self):
pygame.draw.rect(screen, self.color, [self.x, self.y, self.width, self.height])
def move(self):
self.x += self.x_change
self.y += self.y_change
class Ellipse(Rectangle):
pass
def draw(self):
pygame.draw.ellipse(screen, self.color, [self.x, self.y, self.width, self.height])
def move(self):
self.x += self.x_change
self.y += self.y_change
my_list = []
for number in range(600):
my_object = Rectangle()
my_list.append(my_object)
for number in range(600):
my_object = Ellipse()
my_list.append(my_object)
# -------- Main Program Loop -----------
while not done:
keys = pygame.key.get_pressed()
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
for rect in my_list:
rect.draw()
rect.move()
for rectElli in my_list:
rectElli.draw()
if keys[pygame.K_SPACE]:
rectElli.y_change = random.randrange(a, b)
rectElli.x_change = random.randrange(a, b)
rectElli.move()
print(a)
print(b)
if keys[pygame.K_UP] and up / 10 == 1:
up += 1
a -= 1
b -= -1
print(a)
print(b)
print(up)
if up / 10 != 1:
up += 1
pygame.display.flip()
clock.tick(60)
pygame.quit()
This is the code that worked before I wanted to add the increasing of intensity.
import pygame
import random
import time
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# Edit the intensity of the shake (Must be one number apart)
# Ex: a = -100, b = 101. A is negative, B is positive
a = -4
b = 5
up = 10
intensity = (a, b)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
done = False
clock = pygame.time.Clock()
class Rectangle():
def __init__(self):
self.x = random.randrange(0, 700)
self.y = random.randrange(0, 500)
self.height = random.randrange(20, 70)
self.width = random.randrange(20, 70)
self.x_change = random.randrange(-3, 3)
self.y_change = random.randrange(-3, 3)
self.color = random.sample(range(250), 4)
def draw(self):
pygame.draw.rect(screen, self.color, [self.x, self.y, self.width, self.height])
def move(self):
self.x += self.x_change
self.y += self.y_change
class Ellipse(Rectangle):
pass
def draw(self):
pygame.draw.ellipse(screen, self.color, [self.x, self.y, self.width, self.height])
def move(self):
self.x += self.x_change
self.y += self.y_change
my_list = []
for number in range(600):
my_object = Rectangle()
my_list.append(my_object)
for number in range(600):
my_object = Ellipse()
my_list.append(my_object)
# -------- Main Program Loop -----------
while not done:
keys = pygame.key.get_pressed()
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
for rect in my_list:
rect.draw()
rect.move()
for rectElli in my_list:
rectElli.draw()
if keys[pygame.K_SPACE]:
rectElli.y_change = random.randrange(a, b)
rectElli.x_change = random.randrange(a, b)
rectElli.move()
pygame.display.flip()
clock.tick(60)
pygame.quit()
The first issue is, that you do the increasing of the intensity in the for-loop which traverse the ellipses. So the intensity is not increased once, it is increased once per ellipse.
If you don't want to increase the intensity in every 10th frame, then you've to verify if the increment the frame counter up in every frame, but you've to verify if it is divisible by 10. Verify if the remainder of an integral division by 10 is 0. Use the modulo operator (%) to calculate the remainder:
if up % 10 == 0:
See the example, when UP is pressed, the the intensity increases and when it is released then the intensity returns to normal:
while not done:
keys = pygame.key.get_pressed()
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
for rect in my_list:
rect.draw()
rect.move()
for rectElli in my_list:
rectElli.draw()
if keys[pygame.K_SPACE]:
rectElli.y_change = random.randrange(a, b)
rectElli.x_change = random.randrange(a, b)
rectElli.move()
if keys[pygame.K_UP]:
up += 1
if up % 10 == 0:
a -= 1
b -= -1
else:
a, b = -4, 5
pygame.display.flip()
clock.tick(60)
Related
I've been struggling with this problem for a couple days now. I want to eventually convert my snake game script to an exe, for my friends to play. I want the snake to move at the same speed, no matter the size of the window.
For Example: My window size right now is (400, 400). If I increase the size to (800, 800), the snake will move slower. However, the snake velocity is constant at 20 pixels. It almost seems like my main game loop is looping at a slower pace as the window size increases.
I know that the snake has more pixels to traverse with a bigger window size, but how does that affect the snake velocity at all? I'm thinking the solution lies somewhere in the speed at which I'm drawing the snake to the screen, but can't be sure.
import pygame
import sys
import random
import math
import time
pygame.display.set_caption('Snake')
pygame.font.init()
game_running = True
width = 400
height = 400
size = (width, height)
window = pygame.display.set_mode(size) # our surface type
pygame.display.set_caption("Snake Game by Nick Rinaldi")
class Food:
def __init__(self, block_size, surface, x_loc, y_loc): # pass in color and random_x/random_y. block size is a constant
self.block_size = block_size
self.surface = surface # green
self.x_loc = x_loc
self.y_loc = y_loc
self.mask = pygame.mask.from_surface(self.surface)
def draw(self, window):
window.blit(self.surface, (self.x_loc, self.y_loc))
class Snake:
def __init__(self, block_size, surface, x_loc, y_loc):
self.block_size = block_size
self.surface = surface # red
self.x_loc = x_loc
self.y_loc = y_loc
self.body = []
self.direction = None
self.velocity = 20
self.mask = pygame.mask.from_surface(self.surface)
def draw(self, color, window, block_size):
self.seg = []
self.head = pygame.Rect(self.x_loc, self.y_loc, block_size, block_size)
pygame.draw.rect(window, color, self.head)
if len(self.body) > 0:
for unit in self.body:
segment = pygame.Rect(unit[0], unit[1], block_size, block_size)
pygame.draw.rect(window, color, segment)
self.seg.append(segment)
def add_unit(self):
if len(self.body) != 0:
index = len(self.body) - 1
x = self.body[index][0]
y = self.body[index][1]
self.body.append([x, y])
else:
self.body.append([1000, 1000])
def move(self, step):
for index in range(len(self.body) -1, 0, -1):
x = self.body[index-1][0]
y = self.body[index-1][1]
self.body[index] = [x, y]
if len(self.body) > 0:
self.body[0] = [self.x_loc, self.y_loc]
if self.direction == "right": # if specific constant, keep moving in direction
self.x_loc += self.velocity * step
if self.direction == "left":
self.x_loc -= self.velocity * step
if self.direction == "down":
self.y_loc += self.velocity * step
if self.direction == "up":
self.y_loc -= self.velocity * step
def collision(self, obj):
return collide(food)
def gameOver(snake):
white = pygame.Color(255, 255, 255)
display = True
while display:
window.fill(white)
score_font = pygame.font.SysFont("Courier New", 16)
score_label = score_font.render("Your score was: " + str(len(snake.body) + 1), 1, (0, 0, 0))
replay_label = score_font.render("To replay, click the mouse button", 1, (0, 0, 0))
window.blit(score_label, (50, 100))
window.blit(replay_label, (50, 130))
pygame.display.update()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
sys.exit()
clock = pygame.time.Clock()
def main():
game_over = False
x = 20 # x position
y = 20 # y position
block_snakes = []
pygame.init()
clock = pygame.time.Clock()
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
white = pygame.Color(255, 255, 255)
black = pygame.Color(0, 0, 0)
block_size = 20
randx_green = random.randrange(0, width, 20)
randy_green = random.randrange(0, height, 20)
randx_red = random.randrange(0, width, 20)
randy_red = random.randrange(0, height, 20)
red_square = pygame.Surface((block_size, block_size))
red_square.fill(red)
green_square = pygame.Surface((block_size, block_size))
green_square.fill(green)
snake = Snake(block_size, red_square, 20, 20) # create snake instance
food = Food(block_size, green_square, randx_green, randy_green) # create food instance
def redraw_window():
draw_grid(window, height, width, white)
while game_running:
dt = clock.tick(30) # time passed between each call
step = dt/1000
print(step)
FPS = 60
window.fill(black)
food.draw(window)
snake.draw(red, window, block_size)
redraw_window()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]: # sets direction attribute as a constant
snake.direction = "right"
if keys[pygame.K_LEFT]:
snake.direction = "left"
if keys[pygame.K_DOWN]:
snake.direction = "down"
if keys[pygame.K_UP]:
snake.direction = "up"
snake.move(step)
collision = collide_food(snake.x_loc, snake.y_loc, food.x_loc, food.y_loc)
if collision:
ac_rand_x = random.randrange(0, width, 20) # after collision, random x
ac_rand_y = random.randrange(0, height, 20) # after collision, random y
# check snake.direction.
food = Food(block_size, green_square, ac_rand_x, ac_rand_y)
food.draw(window)
snake.add_unit()
wall_collide = collide_wall(snake.x_loc, snake.y_loc)
if wall_collide:
gameOver(snake)
# break
for block in snake.body:
if snake.x_loc == block[0] and snake.y_loc == block[1]:
gameOver(snake)
pygame.display.update()
# clock.tick(FPS)
def collide_food(snake_x, snake_y, obj_x, obj_y):
distance = math.sqrt((math.pow(snake_x - obj_x, 2)) + (math.pow(snake_y - obj_y, 2)))
if distance < 20:
return True
else:
return False
def collide_wall(snake_x, snake_y):
if snake_x > width:
game_over = True
return game_over
if snake_y > height:
game_over = True
return game_over
if snake_x < 0:
game_over = True
return game_over
if snake_y < 0:
game_over = True
return game_over
def collide_self(snake_x, snake_y, body_x, body_y):
if (snake_x and snake_y) == (body_x and body_y):
return True
else:
return False
def draw_grid(window, height, width, color):
x = 0
y = 0
grid_blocks = 20
for i in range(height):
x += 20
pygame.draw.line(window, color, (x, 0), (x, height), 1)
for j in range(width):
y += 20
pygame.draw.line(window, color, (0, y), (height, y), 1)
# pygame.display.update()
def display_score():
score_font = pygame.font.SysFont()
def main_menu(width, height):
clock = pygame.time.Clock()
FPS = 60
width = width
height = height
run = True
title_font = pygame.font.SysFont("Courier New", 16)
title_font.set_bold(True)
white = pygame.Color(255, 255, 255)
while run:
window.fill(white)
title_label = title_font.render("Snake Game by Nick Rinaldi ", 1, (0, 0, 0))
sponser_label = title_font.render("Sponsored by #goodproblemsnyc", 1, (0, 0, 0))
window.blit(title_label, ((width/4, height/4)))
window.blit(sponser_label, ((width/4, height/4 + 30)))
pygame.display.update()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
main_menu(width, height)```
The bottleneck in your game is the function draw_grid, which draws far too many lines out of the window.
def draw_grid(window, height, width, color):
x = 0
y = 0
grid_blocks = 20
for i in range(height):
x += 20
pygame.draw.line(window, color, (x, 0), (x, height), 1)
for j in range(width):
y += 20
pygame.draw.line(window, color, (0, y), (height, y), 1)
If you draw a line outside the window, the statement does not draw anything, nevertheless the nested for loops still run.
Furthermore, you don't need a nested loops. You don't want to draw 19 horizontal lines for each vertical line. You want to draw 19 vertical and 19 horizontal lines. Hence 1 for-loop is enough.
Use the step argument of range to define the list of positions for the vertical and horizontal lines
def draw_grid(window, height, width, color):
tile_size = 20
for p in range(tile_size, height, tile_size):
pygame.draw.line(window, color, (p, 0), (p, height), 1)
pygame.draw.line(window, color, (0, p), (height, p), 1)
if the size is 400 * 400 pixels, the total pixels 160000 so moving at a 20 pixel rate, because there are less pixels the an 800 * 800 board (320000 pixels) it looks like you are going faster because there are less pixels. Find an equation to calculate the correct speed on differently sized boards.
Sincerely,
Zac
I am trying to make my own version of Snake. I'm trying to set it up so that when a wall is hit, the main while loop stops running by setting run = False. This works when I close the program with the quit button, but for some reason is not working when a collision is detected. Any help?
Note: I did try moving the gameOver() function out of the updateScreen() function and putting it separately at the end of the loop, but that didn't work either.
import pygame
import time
import os
pygame.init()
width, height = (500, 500)
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Snake")
win.fill((0, 0, 0))
# Snake Class
class Snake:
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.len = []
self.xvel = 0
self.yvel = 0
def draw(self, window):
win.fill((0, 0, 0))
pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height))
def move(self):
self.x += self.xvel
self.y += self.yvel
def checkCol(self):
# Check if edge is hit
if self.x <= 0 or self.x + self.width >= width:
return True
elif self.y <= 0 or self.y + self.height >= height:
return True
else:
return False
sn = Snake(100, 100, 15, 15, (0, 255, 0))
# MAIN LOOP
def main():
run = True
FPS = 15
clock = pygame.time.Clock()
fontStyle = pygame.font.SysFont(None, 50)
def updateScreen():
sn.move()
sn.draw(win)
gameOver()
pygame.display.update()
def gameOver():
if sn.checkCol():
run = False
print("check")
def message(msg, color):
m = fontStyle.render(msg, True, color)
win.blit(m, [width / 2, height / 2])
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
sn.yvel = -10
sn.xvel = 0
if keys[pygame.K_s]:
sn.yvel = 10
sn.xvel = 0
if keys[pygame.K_a]:
sn.xvel = -10
sn.yvel = 0
if keys[pygame.K_d]:
sn.xvel = 10
sn.yvel = 0
updateScreen()
message("Game Over!", (255, 0, 0))
main()
use breakwhen your condition is met
if keys[pygame.K_d]:
sn.xvel = 10
sn.yvel = 0
break
I'm starting to work with classes more and I was trying to translate my old classless code to this new format. Before, I defined my lists as global variables and could draw multiple enemies to the screen with no problem. This time, however, something about working with classes causes the enemies to be drawn and instantly disappear from their position.
Some help or workaround would be greatly appreciated. Here's the code:
import pygame
import sys
import random
import math
pygame.init()
class enemies(object):
enemies = []
def __init__(self, enemy_num, diff, enemy_size):
self.enemy_num = enemy_num
self.diff = diff
self.enemy_s = enemy_size
def add_enemies(self):
counter = 0
if len(self.enemies) < self.enemy_num:
for enemy in range(0, self.enemy_num):
if len(self.enemies) < 5:
self.enemies.append([counter * (self.enemy_s * 0.5), 200, (50, 168, 82)])
elif len(self.enemies) > 5 and len(self.enemies) <= 9:
self.enemies.append([counter * (self.enemy_s * 0.5), 250, (168, 160, 50)])
else:
self.enemies.append([counter * (self.enemy_s * 0.5), 300, (50, 52, 168)])
counter += 1
def move(self, surface):
for enemy in self.enemies:
surface.fill((0, 0, 0))
pygame.draw.rect(surface, enemy[2], (enemy[0], enemy[1], self.enemy_s, self.enemy_s))
pygame.display.update()
class ship(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
def draw_all(self, surface, ship_size):
surface.fill((0, 0, 0))
pygame.draw.rect(surface, self.color, (self.x, self.y, ship_size, ship_size))
pygame.display.update()
def move(self):
keys = pygame.key.get_pressed()
for key in keys:
if keys[pygame.K_LEFT]:
self.x -= 0.2
if keys[pygame.K_RIGHT]:
self.x += 0.2
if keys[pygame.K_UP]:
self.y -= 0.2
if keys[pygame.K_DOWN]:
self.y += 0.2
def main():
width = 800
height = 1000
ship_size = 35
difficulty = 0
enemy_number = 12
enemy_size = 35
player = ship(width / 2, height - 100, (255, 0, 0))
aliens = enemies(enemy_number, difficulty, enemy_size)
screen = pygame.display.set_mode((width, height))
enemy_list = 12
run = True
clock = pygame.time.Clock()
aliens.add_enemies()
while run:
player.draw_all(screen, ship_size)
player.move()
aliens.move(screen)
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
main()
You've to do 1 clear display and 1 display update in the main loop of the application.
Remove .fill() respectively .pygame.display.update from the .move() and .draw_all method. Clear the display once, draw all the objects and then update the display:
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
screen.fill((0, 0, 0))
player.draw_all(screen, ship_size)
player.move()
aliens.move(screen)
pygame.display.update()
Note, you didn't see the enemies, because the display is clear before drawing a single enemy in enemies.move() and it is clear again when drawing the ship in ship.draw_all()
First post here. So I am trying to implement a Civilization type of movement game. At the moment, I have one sprite in a cell. I can click it and then if I click another grid, the sprite moves there. What I now want is to spawn 5-6 such sprites, and then do the same thing. Click on a sprite and then click another grid, and that specific sprite moves there without affecting the other sprites. I cannot seem to do that. I can spawn 5-6 random sprites at different grids, but when I click on one of them and then click another grid, all the other sprites are gone. The code is below (not the best as I am learning Pygame). I understand that I have to somehow only update the sprite that was clicked, but I am not sure how to do that.
import pygame
import random
WIDTH = 900
HEIGHT = 700
FPS = 2
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
TURN = "TeamOne"
def main():
# Pygame sprite Example
global x_lines
global y_lines
x_lines = [WIDTH-i*WIDTH/20 for i in range(20,0, -1)]
y_lines = [HEIGHT-j*HEIGHT/20 for j in range(20,0, -1)]
class TeamOne(pygame.sprite.Sprite):
# sprite for the Player
def __init__(self):
# this line is required to properly create the sprite
pygame.sprite.Sprite.__init__(self)
# create a plain rectangle for the sprite image
self.image = pygame.Surface((WIDTH / 20, HEIGHT / 20))
self.image.fill(GREEN)
# find the rectangle that encloses the image
self.rect = self.image.get_rect()
# center the sprite on the screen
self.rect.center = ((random.randint(1,19)*2+1)* WIDTH/ 40, (random.randint(1,19)*2+1)*HEIGHT/40)
def update(self, position):
# any code here will happen every time the game loop updates
(a, b) = position
for index, i in enumerate(x_lines):
if i > a:
self.rect.x = x_lines[index-1]
break
for index, j in enumerate(y_lines):
if j > b:
self.rect.y = y_lines[index-1]
break
# initialize pygame and create window
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A Game")
clock = pygame.time.Clock()
clicked_sprites = pygame.sprite.Group()
teamone_sprites = pygame.sprite.Group()
for i in range(5):
mob1 = TeamOne()
teamone_sprites.add(mob1)
# Game loop
running = True
j=0
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and j == 0:
pos = pygame.mouse.get_pos()
for s in teamone_sprites:
if s.rect.collidepoint(pos):
#teamone_sprites.add(s)
clicked_sprites.add(s)
print (clicked_sprites)
j = 1
elif event.type == pygame.MOUSEBUTTONDOWN and j == 1:
new_pos = pygame.mouse.get_pos()
#teamone_sprites.update(new_pos)
clicked_sprites.update(new_pos)
j = 0
# Update
# Draw / render
## screen.fill(BLACK)
## draw_grid(screen)
##
## teamone_sprites.draw(screen)
##
##
##
## # *after* drawing everything, flip the display
## pygame.display.flip()
# Draw / render
screen.fill(BLACK)
draw_grid(screen)
teamone_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
def draw_grid(screen):
for i in range(1, HEIGHT, int(HEIGHT/20)):
pygame.draw.line(screen, GREEN, (1,i) ,(WIDTH,i), 2)
for j in range(1, WIDTH, int(WIDTH/20)):
pygame.draw.line(screen, GREEN, (j,1) ,(j,HEIGHT), 2)
if __name__ == '__main__':
main()
Some tips for you:
Keep your main loop clean
Put logic where it belongs
Only call pygame.display.flip()/pygame.display.update() once
Don't use variable names like j
Since your game is grid based, you should have a way to translate between grid coordinates and screen coordinates
Here's a simple runnable example I hacked together (see the comments for some explanations):
import pygame
import random
WIDTH = 900
HEIGHT = 700
ROWS = 20
COLUMNS = 20
TILE_SIZE = WIDTH / COLUMNS, HEIGHT / ROWS
TILE_W, TILE_H = TILE_SIZE
FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
TURN = "TeamOne"
# some functions to translate grid <-> screen coordinates
def posToScreen(pos):
column, row = pos
return column * TILE_W, row * TILE_H
def screenToPos(pos):
column, row = pos
return column / TILE_W, row / TILE_H
def draw_grid(screen):
for i in range(1, HEIGHT, TILE_H):
pygame.draw.line(screen, GREEN, (1,i) ,(WIDTH,i), 2)
for j in range(1, WIDTH, TILE_W):
pygame.draw.line(screen, GREEN, (j,1) ,(j,HEIGHT), 2)
# a class that handles selecting units
class Cursor(pygame.sprite.Sprite):
def __init__(self, units, *groups):
pygame.sprite.Sprite.__init__(self, *groups)
# group of the units that can be controlled
self.units = units
# we create two images
# to indicate if we are selecting or moving
self.image = pygame.Surface(TILE_SIZE)
self.image.set_colorkey((43,43,43))
self.image.fill((43,43,43))
self.rect = self.image.get_rect()
self.selected_image = self.image.copy()
pygame.draw.rect(self.image, pygame.Color('red'), self.image.get_rect(), 4)
pygame.draw.rect(self.selected_image, pygame.Color('purple'), self.image.get_rect(), 4)
self.base_image = self.image
self.selected = None
def update(self):
# let's draw the rect on the grid, based on the mouse position
pos = pygame.mouse.get_pos()
self.rect.topleft = posToScreen(screenToPos(pos))
def handle_click(self, pos):
if not self.selected:
# if we have not selected a unit, do it now
for s in pygame.sprite.spritecollide(self, self.units, False):
self.selected = s
self.image = self.selected_image
else:
# if we have a unit selected, just set its target attribute, so it will move on its own
self.selected.target = posToScreen(screenToPos(pos))
self.image = self.base_image
self.selected = None
class TeamOne(pygame.sprite.Sprite):
def __init__(self, *groups):
pygame.sprite.Sprite.__init__(self, *groups)
self.image = pygame.Surface(TILE_SIZE)
self.image.fill(GREEN)
self.pos = random.randint(0, COLUMNS), random.randint(0, ROWS)
self.rect = self.image.get_rect(topleft = posToScreen(self.pos))
self.target = None
def update(self):
# do nothing until target is set
# (maybe unset it if we reached our target)
if self.target:
if self.rect.x < self.target[0]:
self.rect.move_ip(1, 0)
elif self.rect.x > self.target[0]:
self.rect.move_ip(-1, 0)
elif self.rect.y < self.target[1]:
self.rect.move_ip(0, 1)
elif self.rect.y > self.target[1]:
self.rect.move_ip(0, -1)
self.pos = screenToPos(self.rect.topleft)
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A Game")
clock = pygame.time.Clock()
all_sprites = pygame.sprite.LayeredUpdates()
team_ones = pygame.sprite.Group()
for i in range(5):
TeamOne(all_sprites, team_ones)
cursor = Cursor(team_ones, all_sprites)
# a nice, simple, clean main loop
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# we could also pass all events to all sprites
# so we would not need this special clause for the cursor...
if event.type == pygame.MOUSEBUTTONDOWN:
cursor.handle_click(event.pos)
all_sprites.update()
screen.fill(BLACK)
draw_grid(screen)
all_sprites.draw(screen)
pygame.display.flip()
if __name__ == '__main__':
main()
I have pretty much the same Problem i have a healthbar for my enemie but i want all enemys to have one so its a spritegroup now if i want to change an attribute of one object out of my spritegroup i dont know how to properly access it. The Problem lays in the Healthbaranimation function. I tried self.healthbar.sprites() self.healthbar.sprites and spritedict nothing really semms to work. Is there an easy way to fix this? P.s sorry for my bad code It is my first real attempt making a small game
from os import path
import pygame
from elements.ammo import AMMO
from elements.bigenemy import BIGENEMY
from elements.enemy import ENEMY
from elements.player import PLAYER
from .base import BaseState
from elements.healthbar import HEALTHBAR
class Gameplay(BaseState):
def __init__(self):
super(Gameplay, self).__init__()
self.next_state = "GAME_OVER"
self.x, self.y = 100, 1030
self.playersprite = PLAYER((self.x, self.y))
self.bigenemy = pygame.sprite.GroupSingle(BIGENEMY())
self.bottomrect = pygame.Rect((0, 1030), (1920, 50))
self.enemysprite = ENEMY()
self.ammosprite = AMMO()
self.healthbar = pygame.sprite.Group(HEALTHBAR())
self.displayedimage = self.playersprite.image
self.displayedrect = self.playersprite.rect
self.highscore = self.load_data()
self.points = 0
self.scoretext = f"SCORE: {self.points}"
self.scoresurf = self.font.render(self.scoretext, True, "red")
self.nhstext = "NEW HIGHSCORE!"
self.nhssurf = self.font.render(self.nhstext, True, "red")
self.ammotext = f"AMMO:{self.playersprite.ammunition}"
self.ammosurf = self.font.render(self.ammotext, True, "red")
self.bulletgroup = pygame.sprite.Group()
self.time_active = 0
self.bigenemyexisting = True
def get_event(self, event):
if event.type == pygame.QUIT:
self.quit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL:
self.playersprite.crouching = True
elif event.key == pygame.K_SPACE:
self.playersprite.jumping = True
elif event.key == pygame.K_q and self.playersprite.ammunition != 0:
self.playersprite.shooting = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_ESCAPE:
self.done = True
elif event.key == pygame.K_LCTRL:
self.playersprite.crouching = False
elif event.key == pygame.K_q:
self.playersprite.shooting = False
def draw(self, surface):
surface.fill(pygame.Color("black"))
pygame.draw.rect(surface, "red", self.bottomrect)
surface.blit(self.displayedimage, (self.displayedrect))
surface.blit(self.enemysprite.image, (self.enemysprite.rect))
surface.blit(self.ammosprite.image, (self.ammosprite.rect))
self.healthbar.draw(surface)
self.bigenemy.draw(surface)
self.bulletgroup.draw(surface)
surface.blit(self.scoresurf, (0, 0))
surface.blit(self.ammosurf, (0, 1000))
if self.points > self.highscore: surface.blit(self.nhssurf, (1920 / 2 - 100, 1080 / 2))
def lost(self):
self.enemysprite.startposx = 1920
self.enemysprite.startposy = self.enemysprite.gettypeenemy()
self.enemysprite.speed = 10
self.highscorefunc()
self.points = 0
self.playersprite.ammunition = 30
def collidecheck(self):
self.playermask = pygame.mask.from_surface(self.displayedimage)
self.enemymask = pygame.mask.from_surface(self.enemysprite.image)
offsetx = self.enemysprite.rect.left - self.displayedrect.left
offsety = self.enemysprite.rect.top - self.displayedrect.top
if self.displayedrect.colliderect(self.enemysprite.rect):
if self.playermask.overlap(self.enemymask, (offsetx, offsety)):
self.lost()
self.done = True
elif self.enemysprite.rect.x < 0 and self.enemysprite.speed < 25:
self.points += 1
self.enemysprite.speed += 1
elif self.enemysprite.speed > 25:
self.enemysprite.speed += .5
elif self.displayedrect.colliderect(self.ammosprite.rect):
self.ammosprite.startposx = 2300
self.playersprite.ammunition += 30
elif pygame.sprite.groupcollide(self.bigenemy,self.bulletgroup,False,True):
self.bigenemy.sprite.health -= 10
def shooting(self, dt):
if self.playersprite.ammunition != 0:
if self.playersprite.shooting and not self.playersprite.jumping and not self.playersprite.crouching:
self.time_active += dt
if self.time_active >= 100:
self.bulletgroup.add(self.playersprite.createbullet())
self.time_active = 0
self.playersprite.ammunition -= 1
else:
self.playersprite.shooting = False
def highscorefunc(self):
if self.points > self.highscore:
self.highscore = self.points
with open(path.join(self.dir, self.HS_FILE), 'w') as f:
f.write(str(self.highscore))
def animation(self):
if not self.playersprite.shooting and not self.playersprite.jumping and not self.playersprite.crouching:
if self.playersprite.index >= len(self.playersprite.basicanimation):
self.playersprite.index = 0
self.displayedimage = self.playersprite.basicanimation[int(self.playersprite.index)]
self.playersprite.index += .1
elif self.playersprite.shooting and not self.playersprite.jumping:
if self.playersprite.index >= len(self.playersprite.shootanimation):
self.playersprite.index = 0
self.displayedimage = self.playersprite.shootanimation[int(self.playersprite.index)]
self.playersprite.index += .1
elif self.playersprite.jumping:
self.displayedimage = self.playersprite.imagejump
elif self.playersprite.crouching:
self.displayedimage = self.playersprite.slidingimage
def healthbaranimation(self):
if self.bigenemy.sprite.health < 90:
self.healthbar.spritedict.index = 1
if self.bigenemy.sprite.health < 80:
self.healthbar.sprite.index = 2
if self.bigenemy.sprite.health < 70:
self.healthbar.sprite.index = 3
if self.bigenemy.sprite.health < 60:
self.healthbar.sprite.index = 4
if self.bigenemy.sprite.health < 50:
self.healthbar.sprite.index = 5
if self.bigenemy.sprite.health < 40:
self.healthbar.sprite.index = 6
if self.bigenemy.sprite.health < 30:
self.healthbar.sprite.index = 7
if self.bigenemy.sprite.health < 20:
self.healthbar.sprite.index = 8
if self.bigenemy.sprite.health < 10:
self.healthbar.sprite.index = 9
def spawnbigenemies(self):
if self.bigenemyexisting:
if self.bigenemy.sprite.health < 3:
self.bigenemy.add(BIGENEMY())
self.bigenemyexisting = True
def update(self, dt):
try:
self.bigenemy.sprite.update()
except:
pass
self.healthbaranimation()
self.healthbar.update()
self.playersprite.jump()
self.animation()
self.shooting(dt)
self.bulletgroup.update()
self.enemysprite.update()
self.ammosprite.update()
self.collidecheck()
self.spawnbigenemies()
self.scoretext = f"SCORE: {self.points}"
self.scoresurf = self.font.render(self.scoretext, True, "black")
self.ammotext = f"AMMO:{self.playersprite.ammunition}"
self.ammosurf = self.font.render(self.ammotext, True, "red")
I am trying to find a certain sprite in a collision group. In this case, My code checks every platform to see if the player is touching it. If the player is touching the platform, I want the player's bottom y to become the platform's (that the player is touching) top y. I do not know how to grab a certain platform, and edit the attributes of that one. How would I edit my code to make this work?
import pygame
import random
WIDTH = 500
HEIGHT = 400
FPS = 30
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
playerImage = "blockBandit/BlockBandit.png"
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image = pygame.image.load(playerImage).convert()
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.vx = 0
self.vy = 0
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Block Bandit")
clock = pygame.time.Clock()
allPlatforms = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
player = Player()
p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
all_sprites.add(p1)
allPlatforms.add(p1)
all_sprites.add(player)
def moveCharacter(object):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
object.vx += -2
if keys[pygame.K_RIGHT]:
object.vx += 2
if keys[pygame.K_UP]:
object.vy -= 12
pygame.quit()
object.vx = object.vx * 0.9
if abs(object.vx) < 1:
object.vx = 0
if abs(object.vx) > 10:
if object.vx < 0:
object.vx = -10
else:
object.vx = 10
object.vy = object.vy + 1
object.rect.x += object.vx
object.rect.y += object.vy
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
if hits:
# object.rect.y = hits[0].rect.midbottom
object.rect.y -= 1
object.vy = 0
if object.rect.bottom < allPlatforms.top:
object.rect.y = allPlatforms.top
print(object.rect.midbottom)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
moveCharacter(player)
# Update State
all_sprites.update()
# Render
screen.fill(BLACK)
all_sprites.draw(screen)
# screen.blit(player.icon, (20, 40))
pygame.display.flip()
pygame.quit()
hits is a list of the colliding platform sprites, so you can iterate over it with a for loop and set the object.rect.bottom to the platform.rect.top.
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
for platform in hits:
object.vy = 0
object.rect.bottom = platform.rect.top