I am trying to show that a tile on a chessboard is selected by outlining it whit a green colour.
I have managed to draw the outline when that specific tile area has been clicked, but the outline disappears after a few milliseconds.
So, I thought had something to do with updating the display (a function that I am already calling inside the highlight_tile() method).
here is the main loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# mouse handling
for unit in white_army:
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_position = pygame.mouse.get_pos()
if unit.tile_area.collidepoint(mouse_position):
highlight_tile(unit.tile_area)
else:
pygame.display.update()
and here the complete code
import pygame
import sys
from coordinator import coordinator
# set up the display
pygame.init()
window_size = (800, 800)
game_window = pygame.display.set_mode(size=window_size)
pygame.display.set_caption('My Game')
# defines classes and related methods
class WhiteSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.white_square = pygame.Surface((self.height, self.width))
self.white_square.fill((255, 255, 255))
class BlackSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.black_square = pygame.Surface((self.height, self.width))
self.black_square.fill((0, 0, 0))
class ChessBoard:
def __init__(self):
self.ws = ws
self.bs = bs
self.white_columns = white_columns
self.black_columns = black_columns
def draw(self):
for w_columns in self.white_columns:
game_window.blit(self.ws.white_square, w_columns)
for b_columns in self.black_columns:
game_window.blit(self.bs.black_square, b_columns)
# declare letters and numbers
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
numbers = ['1', '2', '3', '4', '5', '6', '7', '8']
# create coordinates
coordinates = []
for item_letter in letters:
letter = item_letter
for item_number in numbers:
number = item_number
coordinates.append(letter + number)
# create coordinates values components
x_values = []
for number in range(0, 800, 100):
x = number
x_values.append(x)
y_values = []
for number in range(0, 800, 100):
y = number
y_values.append(y)
# create coordinate values
coordinate_values = []
for x in x_values:
for y in y_values:
coordinate_values.append((x, y))
# assign values to coordinates
squares_coordinates = dict(zip(coordinates, coordinate_values))
# Background for units
class CircleSurface:
def __init__(self):
self.circle_surface = pygame.Surface((100, 100), flags=pygame.SRCALPHA)
pygame.draw.circle(self.circle_surface, (255, 0, 0), (50, 50), 45)
# define colours
black = (0, 0, 0)
white = (255, 255, 255)
gold = (153, 153, 0)
green = (0, 255, 0)
dark_green = (0, 200, 0)
class Unit:
def __init__(self, colour, position):
# define Unit colour
self.colour = colour
# define Unit position
self.position = position
class Knight(Unit):
def __init__(self, colour, position):
# draw circle, inline, and outline
super().__init__(colour, position)
self.center_x = position[0]
self.center_y = position[1]
self.colour = colour
self.position = position
# define tile position
self.tile_area = pygame.Rect(position[0] - 50, position[1] - 50, 100, 100)
circle_radius = 40
self.circle = pygame.draw.circle(game_window, colour, self.position, circle_radius)
self.circle_outline = pygame.draw.circle(game_window, gold, self.position, circle_radius, 5)
self.circle_inline = pygame.draw.circle(game_window, gold, self.position, (circle_radius - 7), 2)
# draw letter
pygame.font.init()
my_font_size = 50
my_font = pygame.font.SysFont('Time New Roman', my_font_size)
text_surface = my_font.render('K', 1, gold)
center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
game_window.blit(text_surface, center_text)
class Archer(Unit):
def __init__(self, colour, first_point, second_point, third_point):
self.colour = colour
self.first_point = first_point
self.second_point = second_point
self.third_point = third_point
self.position = [self.first_point, self.second_point, self.third_point]
super().__init__(colour, self.position)
self.center_x = self.second_point[0]
self.center_y = (self.second_point[1] + ((self.first_point[1] - self.second_point[1]) / 2)) + 10
self.inline_position = [(self.first_point[0] + 10, self.first_point[1] - 5),
(self.second_point[0], self.second_point[1] + 10),
(self.third_point[0] - 10, self.third_point[1] - 5)]
# define_tile_centre
self.tile_area = pygame.Rect(self.first_point[0] - 10, self.second_point[1] - 10, 100, 100)
if self.colour == black:
self.first_point = self.first_point[0], self.first_point[1] - 80
self.second_point = self.second_point[0], self.second_point[1] + 80
self.third_point = self.third_point[0], self.third_point[1] - 80
self.position = [self.first_point, self.second_point, self.third_point]
self.center_y = (self.second_point[1] + ((self.first_point[1] - self.second_point[1])
/ 2)) - 10
self.inline_position = [(self.first_point[0] + 10, self.first_point[1] + 5),
(self.second_point[0], self.second_point[1] - 10),
(self.third_point[0] - 10, self.third_point[1] + 5)]
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
self.triangle_inline = pygame.draw.polygon(game_window, gold, self.inline_position, 2)
# draw letter
pygame.font.init()
my_font_size = 50
my_font = pygame.font.SysFont('Time New Roman', my_font_size)
text_surface = my_font.render('A', 1, gold)
center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
game_window.blit(text_surface, center_text)
class Pikeman(Unit):
def __init__(self, colour, position):
# draw circle, inline, and outline
super().__init__(colour, position)
self.dimension = (80, 80)
self.center_x = position[0] + self.dimension[0] / 2
self.center_y = position[1] + self.dimension[1] / 2
self.colour = colour
self.position = position
# define_tile_centre
self.tile_area = pygame.Rect(position[0] - 10, position[1] - 10, 100, 100)
self.position_and_dimension = self.position + self.dimension
self.inline_position_and_dimension = (self.position[0] + 5, self.position[1] + 5),\
(self.dimension[0] - 10, self.dimension[1] - 10)
self.square = pygame.draw.rect(game_window, colour, self.position_and_dimension, )
self.square_outline = pygame.draw.rect(game_window, gold, self.position_and_dimension, 5)
self.square_inline = pygame.draw.rect(game_window, gold, self.inline_position_and_dimension, 2)
# draw letter
pygame.font.init()
my_font_size = 50
my_font = pygame.font.SysFont('Time New Roman', my_font_size)
text_surface = my_font.render('P', 1, gold)
center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
game_window.blit(text_surface, center_text)
def highlight_tile(tile_area):
pygame.draw.rect(game_window, dark_green, tile_area, 5)
pygame.display.update()
# Sets and gets the coordinates for black and white squares
coordinator = coordinator()
black_columns = coordinator[2] + coordinator[3]
white_columns = coordinator[0] + coordinator[1]
# Creates needed objects
ws = WhiteSquare()
bs = BlackSquare()
cb = ChessBoard()
cs = CircleSurface()
# Event loop (outer)
while 1:
# Draws the chessboard
cb.draw()
# set up white units
white_knight_1 = Knight(white, (150, 650))
white_knight_2 = Knight(white, (650, 650))
white_archer_1 = Archer(white, (210, 790), (250, 710), (290, 790))
white_archer_2 = Archer(white, (310, 790), (350, 710), (390, 790))
white_archer_3 = Archer(white, (410, 790), (450, 710), (490, 790))
white_archer_4 = Archer(white, (510, 790), (550, 710), (590, 790))
white_pikeman_1 = Pikeman(white, (210, 610))
white_pikeman_2 = Pikeman(white, (310, 610))
white_pikeman_3 = Pikeman(white, (410, 610))
white_pikeman_4 = Pikeman(white, (510, 610))
white_army = [white_knight_1, white_knight_2,
white_archer_1, white_archer_2, white_archer_3, white_archer_4,
white_pikeman_1, white_pikeman_2, white_pikeman_3, white_pikeman_4]
# set up black units
black_knight_1 = Knight(black, (150, 150))
black_knight_2 = Knight(black, (650, 150))
black_archer_1 = Archer(black, (210, 90), (250, 10), (290, 90))
black_archer_2 = Archer(black, (310, 90), (350, 10), (390, 90))
black_archer_3 = Archer(black, (410, 90), (450, 10), (490, 90))
black_archer_4 = Archer(black, (510, 90), (550, 10), (590, 90))
black_pikeman_1 = Pikeman(black, (210, 110))
black_pikeman_2 = Pikeman(black, (310, 110))
black_pikeman_3 = Pikeman(black, (410, 110))
black_pikeman_4 = Pikeman(black, (510, 110))
# Event loop (inner)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# mouse handling
for unit in white_army:
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_position = pygame.mouse.get_pos()
if unit.tile_area.collidepoint(mouse_position):
highlight_tile(unit.tile_area)
else:
pygame.display.update()
pygame.display.update()
EDIT
I have managed to not make it disappear, but now I want it to disappear when the mouse is being clicked again.
here is the new block of code updated
if event.type == pygame.MOUSEBUTTONDOWN:
for unit in white_army:
mouse_position = pygame.mouse.get_pos()
if unit.tile_area.collidepoint(mouse_position):
print(mouse_position)
highlight_tile(unit.tile_area)
I tried with a while loop but it just makes the game crash, does not look like a good idea.
So, I thought had something to do with updating the display (a function that I am already calling inside the highlight_tile() method)
Of course.
Create a variable (selected_unit) which states the unit which is currently selected. If the mouse button is pressed the clear the state and set the new selection state according to the mouse position.
Once the variable is selected, then highlight the shape in the main application loop rather than in the event loop. e.g.:
selected_unit = None
while 1:
# Draws the chessboard
cb.draw()
# set up white units
# [...]
# set up black units
# [...]
# Event loop (inner)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# mouse handling
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_position = pygame.mouse.get_pos()
if selected_unit:
# reset the selection
selected_unit = None
else:
# select a new unit
for unit in white_army:
if unit.tile_area.collidepoint(mouse_position):
selected_unit = unit
# highlight the selected unit
if selected_unit:
highlight_tile(selected_unit.tile_area)
# update the dispaly
pygame.display.update()
Related
This question already has answers here:
How can I play an mp3 with pygame?
(7 answers)
how to play wav file in python?
(5 answers)
Closed 5 months ago.
I'm not so sure why but my game screen window/pygame window sometimes freezes or is not responding because of the added SFX or music in my game. If I remove the SFX or music the game runs smoothly. Hoping that anyone can help me or at least tell me why it keeps freezing. Thanks very much.
The specific code for music and sounds in class Game can be found in load_data method, run method, and update method.
This is where you can find my music, target SFX when hit, bonus SFX when hit.
Below is from my main.py module
import pygame as py
import sys
from os import kill, path
from Setting import *
from Sprite import *
import random
#BUGs (BULLET DISAPPEAR WHEN PAUSED [PROBABLY FROM get_tick()])
#add highscore later in end screen
class Game():
def __init__(self):
py.mixer.pre_init(44100, -16, 1, 512)
py.init()
self.screen = py.display.set_mode((Width, Height),py.RESIZABLE)
py.display.set_caption("Hit Me!")
self.clock = py.time.Clock()
self.load_data()
self.score_value = 0
self.time_value = 90
self.paused = False
self.channel1 = py.mixer.Channel(1)
self.channel2 = py.mixer.Channel(2)
self.channel3 = py.mixer.Channel(3)
def draw_data(self, text, font_name, size, color, x, y,type=0, align="center", value=""):
font = py.font.Font(font_name, size)
if type == 0:
text_surface = font.render(text + str(value), True, color)
if self.paused == True:
text_surface.set_alpha(125)
else:
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
if align == "nw":
text_rect.topleft = (x, y)
if align == "ne":
text_rect.topright = (x, y)
if align == "sw":
text_rect.bottomleft = (x, y)
if align == "se":
text_rect.bottomright = (x, y)
if align == "n":
text_rect.midtop = (x, y)
if align == "s":
text_rect.midbottom = (x, y)
if align == "e":
text_rect.midright = (x, y)
if align == "w":
text_rect.midleft = (x, y)
if align == "center":
text_rect.center = (x, y)
self.screen.blit(text_surface, text_rect)
def load_data(self):
game_folder = path.dirname(__file__)
self.map_data = []
with open(path.join(game_folder, 'map.txt'), 'rt') as f:
for line in f:
self.map_data.append(line)
image_folder = path.join(game_folder, 'images')
sfx_folder = path.join(game_folder, 'sfx_music')
self.dim_screen = py.Surface(self.screen.get_size()).convert_alpha()
self.dim_screen.fill((0, 0, 0, 150))
self.player_img = py.image.load(
path.join(image_folder, character)).convert_alpha()
self.bullet_img = py.image.load(
path.join(image_folder, bullets)).convert_alpha()
self.target_img = py.image.load(
path.join(image_folder, targets)).convert_alpha()
self.target_img = py.transform.scale(
self.target_img, (TileSize + 20, TileSize + 20))
self.bonus_img = py.image.load(
path.join(image_folder, time)).convert_alpha()
self.bonus_img = py.transform.scale(
self.bonus_img, (TileSize + 30, TileSize + 30))
#sound loading
self.music = py.mixer.Sound(path.join(sfx_folder,background_music))
self.music.set_volume(0.25)
self.gun_sfx = py.mixer.Sound(path.join(sfx_folder,gun_sound))
self.bonus_sfx = py.mixer.Sound(path.join(sfx_folder,bonus_sound))
self.target_sfx = py.mixer.Sound(path.join(sfx_folder,target_sound))
self.gun_sfx.set_volume(0.4)
self.target_sfx.set_volume(0.5)
def new(self):
self.sprites = py.sprite.Group()
self.walls = py.sprite.Group()
self.grass = py.sprite.Group()
self.targets = py.sprite.Group()
self.bullets = py.sprite.Group()
self.bonuss = py.sprite.Group()
for row, tiles in enumerate(self.map_data):
for col, tile in enumerate(tiles):
if tile == 'P':
self.player = Player(self, col, row)
py.time.set_timer(py.USEREVENT, 1000)
def newTarget(self):
self.targets = py.sprite.Group()
for row, tiles in enumerate(self.map_data):
for col, tile in enumerate(tiles):
if tile == '.':
target_chances = random.randint(0, 100)
if target_chances <= 10: # 10% chance
tile = 'T'
if tile == 'M':
bonus_chances = random.randint(0,100)
if bonus_chances <= 5: # 5% chance bonus time (add 2 or 3 seconds to timer) [specified area]
tile = 'B'
if tile == 'T':
Target(self, col, row)
if tile == 'B':
Bonus(self,col,row)
def run(self):
self.playing = True
self.music_played = False
if not self.music_played:
self.channel3.play(self.music, loops = -1)
self.music_played = True
while self.playing:
self.dt = self.clock.tick(FPS) / 1000
self.events()
if not self.paused:
self.update()
self.channel3.unpause()
if self.paused:
self.channel3.pause()
self.draw()
def quit(self):
py.quit()
sys.exit()
def update(self):
self.sprites.update()
hits = py.sprite.groupcollide(
self.targets, self.bullets, True, True, py.sprite.collide_mask)
bonus_hits = py.sprite.groupcollide(
self.bonuss, self.bullets, True, True, py.sprite.collide_mask)
#for bullets & targets
for hit in hits:
hit.kill()
self.score_value += 1
self.target_sfx_played = False
if not self.target_sfx_played:
self.channel1.play(self.target_sfx)
self.target_sfx_played = True
#for bullets & bonus
for hit in bonus_hits:
hit.kill()
self.time_value += 3
self.bonus_sfx_played = False
if not self.bonus_sfx_played:
self.channel2.play(self.bonus_sfx)
self.bonus_sfx_played = True
#if there is no target in screen, it will create a new set
if len(self.targets) == 0:
self.newTarget()
def drawGrid(self):
for x in range(0, Width, TileSize):
py.draw.line(self.screen, Black, (x, 0), (x, Height))
for y in range(0, Height, TileSize):
py.draw.line(self.screen, Black, (0, y), (Width, y))
def draw(self):
py.display.set_caption("{:.2f}".format(self.clock.get_fps()))
self.screen.fill(BGcolor)
self.drawGrid()
self.sprites.draw(self.screen)
py.draw.rect(self.screen, Green, self.player.rect, 1)
if self.paused:
self.screen.blit(self.dim_screen, (0, 0))
self.draw_data("Paused",'freesansbold.ttf', 105, White, Width / 2, Height / 2,1)
self.draw_data("Score: ",'freesansbold.ttf', 40, White, 100, 35,value = self.score_value)
self.draw_data("Time: ",'freesansbold.ttf', 40, White, 450, 35 ,value = self.time_value)
self.draw_data("HighScore: ",'freesansbold.ttf', 40, White, Width - 225, 35) # add data in end game
py.display.flip()
def events(self):
for event in py.event.get():
if event.type == py.QUIT:
self.quit()
if event.type == py.KEYDOWN:
if event.key == py.K_ESCAPE:
self.paused = not self.paused
if event.type == py.MOUSEBUTTONDOWN:
if event.button == 1:
if not self.paused:
self.player.shoot()
if event.type == py.USEREVENT:
if not self.paused:
self.time_value -=1
def show_start_screen(self):
pass
def show_go_screen(self):
pass
# main loop
g = Game()
g.show_start_screen()
while True:
g.new()
g.run()
g.show_go_screen()
In the Sprite.py module, this is where you can find the SFX for gun shooting whenever I press/hold the left mouse button.
Below is from my Sprite.py module
import pygame as py
from Setting import *
from pygame.locals import *
vec = py.math.Vector2
class Player(py.sprite.Sprite):
def __init__(self, game,x,y):
self.groups = game.sprites
py.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.orig_image = game.player_img
self.rect = self.orig_image.get_rect()
self.pos = vec(x,y) * TileSize
self.rect.center = self.pos
self.last_shot = 0
self.gun_sfx = game.gun_sfx
self.channel4 = py.mixer.Channel(4)
def shoot(self):
if py.mouse.get_pressed()[0]:
now = py.time.get_ticks()
if now - self.last_shot > bullet_rate:
self.gun_sfx_played = False
if not self.gun_sfx_played:
self.channel4.play(self.gun_sfx)
self.gun_sfx_played = True
self.last_shot = now
dir = py.mouse.get_pos() - self.pos
radius, angle = dir.as_polar()
direction = vec(1, 0).rotate(angle - 3)
pos = self.pos + Barrel_offset.rotate(angle)
Bullet(self.game, pos, direction, -angle)
def rotate(self):
dir = py.mouse.get_pos() - self.pos
radius, angle = dir.as_polar()
self.image = py.transform.rotate(self.orig_image, -angle)
self.rect = self.image.get_rect(center=self.rect.center)
def update(self):
self.shoot()
self.rotate()
Below is from my Setting.py
# sounds
gun_sound = 'gun_sfx.mp3'
background_music = 'bg_music.mp3'
target_sound = 'target_sfx_broken.mp3'
bonus_sound = 'hourglass_sfx.mp3'
I have no idea how to implement this, but I do know how to explain it. What the code is supposed to do is: While the program is running, stop the object moving around the screen from coming off it's designated area. How do I test for collision and reflect the moving object from that blocked off wall?
In relation to my code, I have a grid that makes up most of my screen and a small amount of the screen that holds text. The output of the code I hope to learn is two barriers: 1) for the grid so the moving object doesn't go under the text and 2) for the text so it doesn't print on other part of the screen.
Here is my current code:
import sys
from random import randrange
import pygame as pg
import timeit
import xlrd
# timer
start = timeit.default_timer()
# define main colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# define trail colors
C1 = (31, 119, 180)
C2 = (174, 199, 232)
C3 = (255, 127, 14)
C4 = (255, 187, 120)
C5 = (44, 160, 44)
C6 = (152, 223, 138)
C7 = (214, 39, 40)
C8 = (255, 152, 150)
C9 = (148, 103, 189)
C10 = (197, 176, 213)
C11 = (140, 86, 75)
C12 = (196, 156, 148)
C13 = (227, 119, 194)
C14 = (247, 182, 210)
C15 = (127, 127, 127)
C16 = (199, 199, 199)
C17 = (188, 189, 34)
C18 = (219, 219, 141)
C19 = (23, 190, 207)
C20 = (158, 218, 229)
# define measurements
WIDTH, HEIGHT, MARGIN = 10, 10, 1
GRIDX, GRIDY = 90, 35
# text
class GridObject(pg.sprite.Sprite):
def __init__(self, pos, grid, *groups):
super().__init__(groups)
# create image from grid
self.grid = grid
self.gridsize = (len(grid[0]), len(grid))
imgsize = self.gridsize[0]*(WIDTH+MARGIN), self.gridsize[1]*(HEIGHT+MARGIN)
self.image = pg.Surface(imgsize, flags=pg.SRCALPHA)
self.image.fill((0, 0, 0, 0))
col = (1, 1, 1)
for c in range(self.gridsize[0]):
for r in range(self.gridsize[1]):
if self.grid[r][c] == 1:
rect = [(MARGIN + WIDTH) * c + MARGIN, (MARGIN + HEIGHT) * r + MARGIN, WIDTH, HEIGHT]
pg.draw.rect(self.image, col, rect)
self.rect = self.image.get_rect(center=pos)
self.vel = pg.math.Vector2(8, 0).rotate(randrange(360))
self.pos = pg.math.Vector2(pos)
def update(self, boundrect, hitGrid, hitList):
self.pos += self.vel
self.rect.center = self.pos
if self.rect.left <= boundrect.left or self.rect.right >= boundrect.right:
self.vel.x *= -1
if self.rect.top <= boundrect.top or self.rect.bottom >= boundrect.bottom:
self.vel.y *= -1
# align rect to grid
gridpos = round(self.rect.x / (WIDTH+MARGIN)), round(self.rect.y / (HEIGHT+MARGIN))
self.rect.topleft = gridpos[0] * (WIDTH+MARGIN), gridpos[1] * (HEIGHT+MARGIN)
# increment touched filed
global max_hit
max_hit = 0
oldHitList = hitList[:]
hitList.clear()
for c in range(self.gridsize[0]):
for r in range(self.gridsize[1]):
p = gridpos[1] + r, gridpos[0] + c
if p in oldHitList:
hitList.append(p)
elif self.grid[r][c] == 1:
if p[0] < len(hitGrid) and p[1] < len(hitGrid[p[0]]):
hitList.append(p)
if p not in oldHitList:
hitGrid[p[0]][p[1]] +=1
max_hit = max(max_hit, hitGrid[p[0]][p[1]])
ballGrid = [[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0]]
def main():
screen = pg.display.set_mode((GRIDX * (WIDTH+MARGIN) + MARGIN, GRIDY * (HEIGHT+MARGIN) + 50))
# Set title of screen
pg.display.set_caption("Ball With Grid")
clock = pg.time.Clock()
sprite_group = pg.sprite.Group()
ball = GridObject((screen.get_width()//2, screen.get_height()//2), ballGrid, sprite_group)
hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)]
hitList = []
done = False
# create timer event
change_delay = 500 # 1/2 second(s)
change_event = pg.USEREVENT + 1
pg.time.set_timer(change_event, change_delay)
angles = [0, 45, 90, 135, 180, 225, 270, 315]
degreeChange = 0
print("REMINDER: Day 0 is the first day of the simulation.")
#text displayed at the bottom of the screen
# get day and temp from excel file
book = xlrd.open_workbook('daysTemp.xlsx')
sheet = book.sheet_by_index(0)
temps = []
days = []
day = 0
for k in range(1,sheet.nrows):
temps.append(int(sheet.row_values(k)[-2]))
days.append(int(sheet.row_values(k)[-1]))
d = ("day: ", str(days[0]))
t = ("temp: ", str(temps[0]))
print("day: ", days[day])
print("temp: ", temps[days[day]])
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# receive timer event
if event.type == change_event:
degreeChange += 1
if degreeChange == 1:
degreeChange = degreeChange - 5
day += 1
print("day: ", days[day])
print("temp: ", temps[days[day]])
d = ("day: ", str(days[day]))
t = ("temp: ", str(temps[day]))
if day >= 365:
pg.quit()
for i in ball.vel:
# change angle by 45°
ball.vel = ball.vel.rotate(angles[randrange(0, len(angles))])
#print("angle: ", i)
if event.type == pg.KEYDOWN and event.key == pg.K_SPACE:
hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)]
screen.fill(BLACK)
# Draw the grid and add values to the cells
for row in range(GRIDY):
for column in range(GRIDX):
rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
colorlist = [WHITE,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20, WHITE]
color = colorlist[min(len(colorlist)-1, hitGrid[row][column])]
pg.draw.rect(screen, color, rect)
# stops program if the max number is reached
sprite_group.update(screen.get_rect(), hitGrid, hitList)
if max_hit >= 21:
print("\n"+"Program terminated.")
done = True
stop = timeit.default_timer()
end = stop-start
print("Time (in seconds):", end)
sprite_group.draw(screen)
# create a font object.
font = pg.font.Font('freesansbold.ttf', 24)
# create a text suface object,
text = font.render("".join(d) + ", " + "".join(t), True, GREEN, BLACK)
# create a rectangular text object
textRect = text.get_rect()
# set the center of the rectangular object.
textRect.center = ((GRIDX * (WIDTH+MARGIN) + 50) // 2, (GRIDY * (HEIGHT+MARGIN) + 50))
screen.blit(text, textRect)
pg.display.update()
clock.tick(60)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
Well it appears that you have almost done it. In update() you have
if self.rect.left <= boundrect.left or self.rect.right >= boundrect.right:
self.vel.x *= -1
if self.rect.top <= boundrect.top or self.rect.bottom >= boundrect.bottom:
self.vel.y *= -1
which is perfect, the only problem is boundrect seems to be the whole screen
sprite_group.update(screen.get_rect(), hitGrid, hitList)
All you need to do is pass a rect that doesnt include the bottom part.
bounding_box = pg.Rect(0,0,(GRIDX * (WIDTH+MARGIN) + MARGIN,GRIDY * (HEIGHT+MARGIN))
#this has same width and height as screen but doesnt have +50 for y
then update with new rect
sprite_group.update(bounding_box, hitGrid, hitList)
As for the text, it looks like it can only be in one place so should be fine
I'm trying to make my own version of OLDTV in Python, but I've run into a problem. I am making an effect where the text is bigger for a moment before going to a regular size. The problem that I am running up against is that the text does not display at all. I am running Anaconda 2.7 (installed in a previous project) with the Spyder editor that comes with, if that helps.
Code:
import pygame
from pygame.transform import scale
from random import randint
def make_font(fonts, size):
available = pygame.font.get_fonts()
# get_fonts() returns a list of lowercase spaceless font names
choices = map(lambda x:x.lower().replace(' ', ''), fonts)
for choice in choices:
if choice in available:
return pygame.font.SysFont(choice, size)
return pygame.font.Font(None, size)
_cached_fonts = {}
def get_font(font_preferences, size):
global _cached_fonts
key = str(font_preferences) + '|' + str(size)
font = _cached_fonts.get(key, None)
if font == None:
font = make_font(font_preferences, size)
_cached_fonts[key] = font
return font
_cached_text = {}
def create_text(text, fonts, size, color):
global _cached_text
key = '|'.join(map(str, (fonts, size, color, text)))
image = _cached_text.get(key, None)
if image == None:
font = get_font(fonts, size)
image = font.render(text, True, color)
_cached_text[key] = image
return image
pygame.init()
screen = pygame.display.set_mode((640, 480))
real = 0
guess = 0
score = 0
i = 0
gameRunning = False
runEnd = False
clock = pygame.time.Clock()
done = False
font_preferences = [
"Arial",
"Times New Roman",
"Papyrus",
"Comic Sans MS"]
def endRun(score):
global gameRunning
global runEnd
global i
screen.fill([255, 255, 255])
text = create_text(str(score), font_preferences, 72, (0, 0, 0))
screen.blit(text,
(320 - text.get_width() // 2, 240 - text.get_height() // 2))
gameRunning = False
runEnd = True
i = 0
def genNext():
screen.fill([255, 255, 255])
global real
gen = randint(1, 2)
if gen == 2:
ref = 0
else:
ref = 1
rand1 = randint(1, 6)
rand2 = randint(1, 6)
words = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple"]
if ref == 1:
if rand1 == rand2:
real = 0
else:
real = 1
displayWord = words[rand1-1]
displayCol = rand2
elif ref == 0:
real = 0
displayWord = words[rand1-1]
displayCol = rand1
return ReturnValue(displayWord, displayCol)
def displayWordCol(word, col):
colVal = [(255, 0, 0), (255, 128, 0), (190, 190, 0), (0, 255, 0), (0, 0, 255), (128, 0, 255)]
for i in range(10, 5):
text = create_text(word, font_preferences, 72, colVal[col-1])
scale(text, (text.get_width() * i/5, text.get_height() * i/5))
screen.blit(text, (320 - text.get_width() // 2, 240 - text.get_height() // 2))
pygame.display.update()
clock.tick(60)
def checkNext(real, guess):
global score
if real == guess:
score = score + 1
e = genNext()
displayWordCol(e.y0, e.y1)
else:
endRun(score)
def homeScreen():
screen.fill(0)
text = create_text("OpenTV", font_preferences, 72, (100, 100, 100))
screen.blit(text,
(320 - text.get_width() // 2, 240 - text.get_height() // 2))
class ReturnValue:
def __init__(self, y0, y1):
self.y0 = y0
self.y1 = y1
homeScreen()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if gameRunning == True:
guess = 0
checkNext(real, guess)
elif event.button == 3:
if gameRunning == True:
guess = 1
checkNext(real, guess)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
if gameRunning == False:
gameRunning = True
score = 0
e = genNext()
displayWordCol(e.y0, e.y1)
if event.key == pygame.K_ESCAPE:
if gameRunning == True:
endRun(score)
elif gameRunning == False:
done = True
if runEnd:
i = i + 1
if i == 120:
homeScreen()
runEnd = False
pygame.display.flip()
clock.tick(60)
The part that is causing trouble is the displayWordCol function. Is there something wrong with my code, or should I switch to IDLE and paste in my code?
I think the main problem is using scale() to scale rendered text. As far as I know, scale() is for images.
Try this as a mere example (you can adapt it to your needs afterwards).
def displayWordCol(word, col):
colVal = [(255, 0, 0), (255, 128, 0), (190, 190, 0), (0, 255, 0), (0, 0, 255), (128, 0, 255)]
for i in range(10):
text = create_text(word, font_preferences, int(72 *i/5), colVal[col-1])
#scale(text, (text.get_width() * i/5, text.get_height() * i/5))
screen.blit(text, (320 - text.get_width() // 2, 240 - text.get_height() // 2))
pygame.display.update()
clock.tick(60)
Another possible problem is that you might need to erase the screen before blitting the word in every loop cycle (not sure which effect you are looking for).
Finally, using pygame is almost always a good thing to use "dirty" rects, erasing and updating only the parts of the screen that have actually changed.
Regards!
EDIT: Try this as well. I added erasing the screen before blitting. I guess this effect is what you were looking for. I also added "dirty" rects management as an example.
def displayWordCol(word, col):
colVal = [(255, 0, 0), (255, 128, 0), (190, 190, 0), (0, 255, 0), (0, 0, 255), (128, 0, 255)]
regular_size = 72
cicles = 20
size_gap = 5
initial_size = regular_size + cicles * size_gap
text = create_text(word, font_preferences, int(initial_size), colVal[col - 1])
pos = (320, 240)
rect = pygame.Rect(pos[0] - text.get_width()/2, pos[1] - text.get_height()/2, text.get_width(), text.get_height())
screen.fill(pygame.Color("white"))
pygame.display.update()
for i in range(cicles):
text = create_text(word, font_preferences, int(initial_size - i*size_gap), colVal[col-1])
screen.fill(pygame.Color("white"), rect)
screen.blit(text, (pos[0] - text.get_width()/2, pos[1] - text.get_height()/2))
pygame.display.update(rect)
clock.tick(60))
I want to draw a triangle from a class, so I call the function
pygame.draw.polygon()
Now, the problem is that I need to pass the points in a manner that will allow me to calculate the centre of the triangle.
I was trying to pass the tuples one by one in this way
self.first_point = (int, int)
self.second_point = (int, int)
self.third_point = (int, int)
so that I can then access the single tuple values.
Then pass the three points like this
self.position = [self.first_point, self.second_point, self.third_point]
But for some reason, it doesn't work.
This is the error I get
File "C:/Users/oricc/PycharmProjects/designAChessboardChallange/display.py", line 178, in <module>
white_archer_3 = Archer(white, [(100, 100), (200, 200), (300, 300)])
[(100, 100), (200, 200), (300, 300)]
File "C:/Users/oricc/PycharmProjects/designAChessboardChallange/display.py", line 132, in __init__
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
TypeError: points must be number pairs
By number of pairs, the Pygame documentation gives as an example
e.g. [(x1, y1), (x2, y2), (x3, y3)]
In fact, when I print the position I pass I get, as you can see from the error above
[(100, 100), (200, 200), (300, 300)]
Anyone can help with this?
Is there another manner to calculate the centre without accessing the xs and ys like that?
Full code here
import pygame
import sys
from coordinator import coordinator
# set up the display
pygame.init()
window_size = (800, 800)
game_window = pygame.display.set_mode(size=window_size)
pygame.display.set_caption('My Game')
# defines classes and related methods
class WhiteSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.white_square = pygame.Surface((self.height, self.width))
self.white_square.fill((255, 255, 255))
class BlackSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.black_square = pygame.Surface((self.height, self.width))
self.black_square.fill((0, 0, 0))
class ChessBoard:
def __init__(self):
self.ws = ws
self.bs = bs
self.white_columns = white_columns
self.black_columns = black_columns
def draw(self):
for w_columns in self.white_columns:
game_window.blit(self.ws.white_square, w_columns)
for b_columns in self.black_columns:
game_window.blit(self.bs.black_square, b_columns)
# declare letters and numbers
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
numbers = ['1', '2', '3', '4', '5', '6', '7', '8']
# create coordinates
coordinates = []
for item_letter in letters:
letter = item_letter
for item_number in numbers:
number = item_number
coordinates.append(letter + number)
# create coordinates values components
x_values = []
for number in range(0, 800, 100):
x = number
x_values.append(x)
y_values = []
for number in range(0, 800, 100):
y = number
y_values.append(y)
# create coordinate values
coordinate_values = []
for x in x_values:
for y in y_values:
coordinate_values.append((x, y))
# assign values to coordinates
squares_coordinates = dict(zip(coordinates, coordinate_values))
# Background for units
class CircleSurface:
def __init__(self):
self.circle_surface = pygame.Surface((100, 100), flags=pygame.SRCALPHA)
pygame.draw.circle(self.circle_surface, (255, 0, 0), (50, 50), 45)
# define colours
black = (0, 0, 0)
white = (255, 255, 255)
gold = (153, 153, 0)
class Unit:
def __init__(self, colour, position):
# define Unit colour
self.colour = colour
# define Unit position
self.position = position
class Knight(Unit):
def __init__(self, colour, position):
# draw circle, inline, and outline
super().__init__(colour, position)
self.center_x = position[0]
self.center_y = position[1]
self.colour = colour
self.position = position
circle_radius = 40
self.circle = pygame.draw.circle(game_window, colour, self.position, circle_radius)
self.circle_outline = pygame.draw.circle(game_window, gold, self.position, circle_radius, 5)
self.circle_inline = pygame.draw.circle(game_window, gold, self.position, (circle_radius - 10), 5)
# draw letter
pygame.font.init()
my_font_size = 50
my_font = pygame.font.SysFont('Time New Roman', my_font_size)
text_surface = my_font.render('K', 1, gold)
center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
game_window.blit(text_surface, center_text)
class Archer(Unit):
def __init__(self, colour, position):
super().__init__(colour, position)
self.first_point = (int, int)
self.second_point = (int, int)
self.third_point = (int, int)
self.position = [self.first_point, self.second_point, self.third_point]
print(position)
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
self.triangle_inline = pygame.draw.polygon(game_window, gold, self.position, 5)
# draw letter
# pygame.font.init()
# my_font_size = 50
# my_font = pygame.font.SysFont('Time New Roman', my_font_size)
# text_surface = my_font.render('A', 1, gold)
# center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
# game_window.blit(text_surface, center_text)
# Sets and gets the coordinates for black and white squares
coordinator = coordinator()
black_columns = coordinator[2] + coordinator[3]
white_columns = coordinator[0] + coordinator[1]
# Creates needed objects
ws = WhiteSquare()
bs = BlackSquare()
cb = ChessBoard()
cs = CircleSurface()
# Event loop (outer)
while 1:
# Event loop (inner)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Draws the chessboard
cb.draw()
# Draws white pieces in their initial position
white_knight_1 = Knight(white, (150, 650))
white_knight_2 = Knight(white, (650, 650))
white_archer_3 = Archer(white, [(100, 100), (200, 200), (300, 300)])
pygame.display.update()
Thank you
OK, I managed to make it work.
You guys are both right, I should know by now that I can't pass placeholders, so I figured out the solution to my problem as follow:
class Archer(Unit):
def __init__(self, colour, first_point, second_point, third_point):
self.first_point = first_point
self.second_point = second_point
self.third_point = third_point
position = [self.first_point, self.second_point, self.third_point]
super().__init__(colour, position)
print(self.position)
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
self.triangle_inline = pygame.draw.polygon(game_window, gold, self.position, 5)
Basically I have to declare the three points self variables, as well as position before the super function so that I can then pass them as 'position' to the parent class initializer. This has been really useful!!
Thanks both
you could also do this: self.first_point = (int(0), int(0)) as int is not a placeholder but to declare that a variable is an integer str('0') will print '0' you could also input this
zero = 0
str(zero) #'0'
int(zero) #0
and you dont need to put rgb tupels because you can store them in a variable like this
black = (0, 0, 0)
Display = pygame.display.set_mode((800, 600))
Display.fill(black)
I have some simple circles (boids) that move in a way that simulates birds; they should avoid getting too close to each other while maintaining the same general heading et cetera.
I'm using pygame but the circles don't move unless I press one of the buttons in the GUI, which seems kind of strange but I can't figure out where I messed up.
The most relevant part of the code is probably the gui function and the draw function inside the Boid class.
import pygame
import numpy as np
import sys
import math
class BoidWorld:
# Boid movement parameters
w_separation = 10
w_alignment = 1
w_cohesion = 1
w_avoidance = 0
w_flee = 50
dim = 0 # dim*dim = Size of world
neighbour_radius = 100
max_velocity = 100
# Objects in world
boids = []
predators = []
obstacles = []
def __init__(self, dim):
self.dim = dim
def update_boid_velocity(self, boid):
# Flee from predators, if any
predator = self.get_predator(boid)
flee_x, flee_y = self.calc_flee_force(boid, predator)
# Avoid obstacles, if any
obstacle = self.get_obstacle(boid)
avoid_x, avoid_y = self.calc_avoidance_force(boid, obstacle)
# Get neighbours within radius r
neighbours = self.get_neighbours(boid)
sep_x, sep_y = self.calc_separation_force(boid, neighbours)
align_x, align_y = self.calc_alignment_force(neighbours)
coh_x, coh_y = self.calc_cohesion_force(neighbours)
boid.velocity_x += self.w_separation * sep_x + self.w_alignment * align_x + self.w_cohesion * coh_x + \
self.w_avoidance * avoid_x + self.w_flee * flee_x
boid.velocity_y += self.w_separation * sep_y + self.w_alignment * align_y + self.w_cohesion * coh_y + \
self.w_avoidance * avoid_y + self.w_flee * flee_y
# Limit velocity by creating unit vectors and multiplying by max velocity
v = math.sqrt(boid.velocity_x**2 + boid.velocity_y**2)
if v > self.max_velocity:
boid.velocity_x = boid.velocity_x*self.max_velocity/v
boid.velocity_y = boid.velocity_y*self.max_velocity/v
boid.position_x += boid.velocity_x
boid.position_y += boid.velocity_y
print(boid.velocity_x, boid.velocity_y)
# Wrap around
if boid.position_x > self.dim or boid.position_x < 0:
boid.position_x %= self.dim
if boid.position_y > self.dim or boid.position_y < 0:
boid.position_y %= self.dim
def update_predator_velocity(self, predator):
pass
def calc_separation_force(self, boid, neighbours):
sep_x = 0.
sep_y = 0.
for b in neighbours:
sep_x = sep_x - (b.position_x - boid.position_x)
sep_y = sep_y - (b.position_y - boid.position_y)
return sep_x, sep_y
def calc_alignment_force(self, neighbours):
if not neighbours: return 0, 0
avg_heading_x = 0.
avg_heading_y = 0.
for b in neighbours:
avg_heading_x += b.velocity_x
avg_heading_y += b.velocity_y
return avg_heading_x/len(neighbours), avg_heading_y/len(neighbours)
def calc_cohesion_force(self, neighbours):
if not neighbours: return 0, 0
avg_pos_x = 0.
avg_pos_y = 0.
for b in neighbours:
avg_pos_x += b.position_x
avg_pos_y += b.position_y
return avg_pos_x/len(neighbours), avg_pos_y/len(neighbours)
# Flee straight away from predators
def calc_flee_force(self, boid, predator):
if not predator: return 0
return boid.position - predator.position
# Avoid obstacles
def calc_avoidance_force(self, boid, obstacle):
if not obstacle: return 0
return 0
# Predators chasing boids
def calc_chasing_force(self, predator, boids):
return 0
def get_predator(self, boid):
for predator in self.predators:
if self.is_neighbour(predator, boid):
return predator
return None
def get_obstacle(self, boid):
for obstacle in self.obstacles:
if self.is_neighbour(obstacle, boid):
return obstacle
return None
def is_neighbour(self, boid1, boid2):
if np.power(boid2.position_x - boid1.position_x, 2) + \
np.power(boid2.position_y - boid1.position_y, 2) \
< np.power(self.neighbour_radius, 2):
return True
return False
def get_neighbours(self, boid):
neighbours = []
for b in self.boids:
if b != boid and self.is_neighbour(b, boid):
neighbours.append(b)
return neighbours
def add_boid(self):
self.boids.append(Boid(
self.rand_position(), self.rand_position(),
self.rand_velocity(), self.rand_velocity()
))
def add_obstacle(self):
self.obstacles.append(Obstacle(
self.rand_position(), self.rand_position()))
def add_predator(self):
self.predators.append(Predator(
self.rand_position(), self.rand_position(),
self.rand_velocity(), self.rand_velocity()
))
def remove_boids(self):
self.boids = []
def remove_obstacles(self):
self.obstacles = []
def remove_predators(self):
self.predators = []
def rand_position(self):
return float(np.random.randint(0, self.dim))
def rand_velocity(self):
return float(np.random.randint(0, self.max_velocity))
class Boid(object):
color_circle = (100, 0, 0)
color_line = (100, 0, 100)
radius = 10
position_x = 0.
position_y = 0.
velocity_x = 0.
velocity_y = 0.
def __init__(self, position_x, position_y, velocity_x, velocity_y):
self.position_x = position_x
self.position_y = position_y
self.velocity_x = velocity_x
self.velocity_y = velocity_y
def draw(self, screen):
pygame.draw.circle(screen, self.color_circle, (int(round(self.position_x)), int(round(self.position_y))),
self.radius, 0)
# Velocity vector
pygame.draw.lines(screen, self.color_line, False, [
(int(round(self.position_x)), int(round(self.position_y))),
(int(round(self.position_x+self.velocity_x)), int(round(self.position_y+self.velocity_y)))
], 2)
class Predator(Boid):
color_circle = (100, 55, 0)
color_line = (100, 0, 100)
radius = 20
class Obstacle:
color = (0, 33, 50)
position_x = 0.
position_y = 0.
radius = 15
def __init__(self, position_x, position_y):
self.position_x = position_x
self.position_y = position_y
def draw(self, screen):
pygame.draw.circle(screen, self.color, (int(round(self.position_x)), int(round(self.position_y))),
self.radius, 0)
def main():
pygame.init()
boid_world = BoidWorld(800)
boid_world.add_boid()
gui(boid_world)
def gui(boid_world):
weight_inc = 0.1
btn_boid_add = Button('Add boid')
btn_boid_rem = Button('Remove boids')
btn_obst_add = Button('Add obstacle')
btn_obst_rem = Button('Remove obstacles')
btn_pred_add = Button('Add predator')
btn_pred_rem = Button('Remove predators')
btn_sep_p = Button('+')
btn_sep_m = Button('-')
btn_ali_p = Button('+')
btn_ali_m = Button('-')
btn_coh_p = Button('+')
btn_coh_m = Button('-')
pygame.font.init()
font = pygame.font.Font(None, 20)
font_color = (255, 255, 255)
screen = pygame.display.set_mode((1200, 800))
screen_half = screen.subsurface((400, 0, 800, 800))
pygame.display.set_caption('Boids')
clock = pygame.time.Clock()
run = True
while run:
screen.fill((0, 0, 0))
mouse = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if btn_boid_add.obj.collidepoint(mouse):
boid_world.add_boid()
elif btn_boid_rem.obj.collidepoint(mouse):
boid_world.remove_boids()
elif btn_obst_add.obj.collidepoint(mouse):
boid_world.add_obstacle()
elif btn_obst_rem.obj.collidepoint(mouse):
boid_world.remove_obstacles()
elif btn_pred_add.obj.collidepoint(mouse):
boid_world.add_predator()
elif btn_pred_rem.obj.collidepoint(mouse):
boid_world.remove_predators()
elif btn_sep_m.obj.collidepoint(mouse):
boid_world.w_separation -= weight_inc
elif btn_sep_p.obj.collidepoint(mouse):
boid_world.w_separation += weight_inc
elif btn_ali_p.obj.collidepoint(mouse):
boid_world.w_alignment -= weight_inc
elif btn_ali_m.obj.collidepoint(mouse):
boid_world.w_alignment += weight_inc
elif btn_coh_m.obj.collidepoint(mouse):
boid_world.w_cohesion -= weight_inc
elif btn_coh_p.obj.collidepoint(mouse):
boid_world.w_cohesion += weight_inc
btn_boid_add.draw(screen, mouse, (10, 10, 100, 20), (15, 15))
btn_boid_rem.draw(screen, mouse, (120, 10, 130, 20), (125, 15))
btn_obst_add.draw(screen, mouse, (10, 40, 100, 20), (15, 45))
btn_obst_rem.draw(screen, mouse, (120, 40, 130, 20), (125, 45))
btn_pred_add.draw(screen, mouse, (10, 70, 100, 20), (15, 75))
btn_pred_rem.draw(screen, mouse, (120, 70, 130, 20), (125, 75))
btn_sep_m.draw(screen, mouse, (120, 100, 20, 20), (125, 105))
btn_sep_p.draw(screen, mouse, (150, 100, 20, 20), (155, 105))
btn_ali_m.draw(screen, mouse, (120, 130, 20, 20), (125, 135))
btn_ali_p.draw(screen, mouse, (150, 130, 20, 20), (155, 135))
btn_coh_m.draw(screen, mouse, (120, 160, 20, 20), (125, 165))
btn_coh_p.draw(screen, mouse, (150, 160, 20, 20), (155, 165))
screen.blit(font.render('Separation', 1, font_color), (15, 105))
screen.blit(font.render('Alignment', 1, font_color), (15, 135))
screen.blit(font.render('Cohesion', 1, font_color), (15, 165))
for boid in boid_world.boids:
boid_world.update_boid_velocity(boid)
boid.draw(screen_half)
for obstacle in boid_world.obstacles:
obstacle.draw(screen_half)
for predator in boid_world.predators:
boid_world.update_predator_velocity(predator)
predator.draw(screen_half)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
class Button:
def __init__(self, text):
self.text = text
self.is_hover = False
self.default_color = (100, 100, 100)
self.hover_color = (255, 255, 255)
self.font_color = (100, 0, 0)
self.obj = None
def label(self):
font = pygame.font.Font(None, 20)
return font.render(self.text, 1, self.font_color)
def color(self):
if self.is_hover:
return self.hover_color
else:
return self.default_color
def draw(self, screen, mouse, rectcoord, labelcoord):
# create rect obj, draw, and change color based on input
self.obj = pygame.draw.rect(screen, self.color(), rectcoord)
screen.blit(self.label(), labelcoord)
# change color if mouse over button
self.check_hover(mouse)
def check_hover(self, mouse):
# adjust is_hover value based on mouse over button - to change hover color
if self.obj.collidepoint(mouse):
self.is_hover = True
else:
self.is_hover = False
if __name__ == "__main__":
main()
It happens because you do all calculation inside
elif event.type == pygame.MOUSEBUTTONDOWN:
MOUSEBUTTONDOWN means that button changes state from UP to DOWN (and it takes very short time). It doesn't means button is holding pressed all the time
If you need to check weather button is holding pressed then use pygame.mouse.get_pressed() but use it outside/after for event loop.
It is similar to key events: