shooting game in kivy - python

I am currently making simple shooting game in python kivy. My character is moving but when pressed space bar, the bullet is generated in the same position. So the bullet is not mapped onto the character.
I tried creating bullet as a class but it didn't help.
I will be glad for any help.
Here is my code:
def __init__(self, *args, **kwargs):
super(Auto,self).__init__(*args,**kwargs)
self.rect = Rectangle(size = (150, 150), pos = (0, 0), source = "spriteshd00.png")
self.canvas.add(self.rect)
def pohyb(self, vector):
self.rect.pos = Vector(self.rect.pos) + Vector(vector)
class Hra(BoxLayout):
def __init__(self, *args, **kwargs):
super(Hra,self).__init__(*args,**kwargs)
self.orientation = "vertical"
self.car = Auto(size_hint = (1,.9))
self.bullet = Rectangle(pos=(0,0), size=(20, 5))
Clock.schedule_interval(self.movebullet, .025)
self.add_widget(self.car)
ovladaci_panel_obal = BoxLayout(orientation = "horizontal", size_hint = (1,.1))
self.up_btn = ToggleButton(text = "Up", group = "smer")
self.up_btn.bind(state = self.on_state)
ovladaci_panel_obal.add_widget(self.up_btn)
self.left_btn = ToggleButton(text = "Left", group = "smer")
self.left_btn.bind(state = self.on_state)
ovladaci_panel_obal.add_widget(self.left_btn)
self.down_btn = ToggleButton(text = "Down", group = "smer")
self.down_btn.bind(state = self.on_state)
ovladaci_panel_obal.add_widget(self.down_btn)
self.right_btn = ToggleButton(text = "Right", group = "smer")
self.right_btn.bind(state = self.on_state)
ovladaci_panel_obal.add_widget(self.right_btn)
self.add_widget(ovladaci_panel_obal)
# Připojíme klávesnici k aplikaci
self.Keyboard = Window.request_keyboard(self._keyboard_closed,self,'text')
self.Keyboard.bind(on_key_down = self._on_keyboard_down)
self.Keyboard.bind(on_key_up = self._on_keyboard_up)
self.Keyboard.bind(on_key_up=self.shoot)
def _keyboard_closed(self):
#Funkce už nebude volána při stisku klávesy
self.Keyboard.unbind(on_key_down = self._on_keyboard_down())
self.Keyboard.unbind(on_key_up=self._on_keyboard_down())
self.Keyboard.unbind(on_key_up=self.shoot())
self.Keyboard = None #odstraneni klavesnice
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
if(keycode[1] == "up"):
self.reset_state()#resetovani stavu tlacitek
self.up_btn.state = "down"
elif(keycode[1] == "left"):
self.reset_state()#resetovani stavu tlacitek
self.left_btn.state = "down"
elif(keycode[1] == "right"):
self.reset_state()#resetovani stavu tlacitek
self.right_btn.state = "down"
elif(keycode[1] == "down"):
self.reset_state()#resetovani stavu tlacitek
self.down_btn.state = "down"
if(keycode[1] == "escape"):
keyboard.release()#stisknu escape a aplikace prestane fungovat
return True
def _on_keyboard_up(self,keyboard, keycode):
self.reset_state()
def movebullet(self, *args):
y = self.car.pos[1]*3 + self.car.pos[0]*3
x = self.bullet.pos[0] + 15
#self.bullet.pos = self.car.pos
self.bullet.pos = (x,y) #tahle konfiiguarce umozni jit kulce horizontalne
#blx, bly = self.ball.pos
# Check for hit. Ball size is 15. Bullet size is 5.
#if (x + 5 > blx and x < blx + 15 and y > bly and y < 400):
#self.canvas.remove(self.ball)
#self.newball()
#self.lblRes.text = str(int(self.lblRes.text) + 100)
def shoot(self, keyboard, keycode):
if (keycode[1] == 'spacebar'):
with self.canvas:
Color(0, 0, 0, 1, mode="rgba")
self.bullet = Rectangle(pos= (300, 0), size=(20, 5))
g1 = self.car.pos[0] + 15
g2 = self.car.pos[1] + 15
self.bullet.pos = (g1, g2)
def reset_state(self):
self.up_btn.state = "normal"
self.left_btn.state = "normal"
self.down_btn.state = "normal"
self.right_btn.state = "normal"
def on_state(self, obj, state):
if(obj.text == "Up"):
if(state == "down"):
self.timer = Clock.schedule_interval(lambda dt: self.car.pohyb((0, 1)), 0.01)
#self.auto.rect.source = "up.png" # Změníme obrázek
if(state == "normal"):
#Zastavíme timer
Clock.unschedule(self.timer)
elif(obj.text == "Left"):
if(state == "down"):
self.timer = Clock.schedule_interval(lambda dt: self.car.pohyb((-1, 0)), 0.01)
#self.car.rect.source = "left.png" # Změníme obrázek
if(state == "normal"):
Clock.unschedule(self.timer)
elif(obj.text == "Down"):
if(state == "down"):
self.timer = Clock.schedule_interval(lambda dt: self.car.pohyb((0, -1)), 0.01)
#self.car.rect.source = "down.png" # Změníme obrázek
if(state == "normal"):
Clock.unschedule(self.timer)
elif(obj.text == "Right"):
if(state == "down"):
self.timer = Clock.schedule_interval(lambda dt: self.car.pohyb((1, 0)), 0.01)
#self.car.rect.source = "right.png" # Změníme obrázek
if(state == "normal"):
Clock.unschedule(self.timer)
class MainApp(App):
def build(self):
Window.clearcolor = (1,1,1,1)
return Hra()
root = MainApp()
root.run()``

It looks like your Auto instance is nearly the size of the Hra (size_hint = (1,.9)), and your Bullet position is based on the position of the Auto instance. Your Up, Left, Right, and Down buttons are moving the Rectangle that is drawn on the Canvas, but have no effect on the actual position of the Auto instance. So your Bullet is always created at the same position (the Auto position never changes). One way to fix it is to make the Bullet position depend on the Rectangle instead. Like this:
def movebullet(self, *args):
y = self.car.rect.pos[1] # use position of Rectangle
x = self.bullet.pos[0] + 15
#self.bullet.pos = self.car.pos
self.bullet.pos = (x,y) #tahle konfiiguarce umozni jit kulce horizontalne
and
def shoot(self, keyboard, keycode):
if (keycode[1] == 'spacebar'):
with self.canvas:
Color(0, 0, 0, 1, mode="rgba")
self.bullet = Rectangle(pos= (300, 0), size=(20, 5))
# use position of Rectangle
g1 = self.car.rect.pos[0] + 15
g2 = self.car.rect.pos[1] + 15
self.bullet.pos = (g1, g2)

Related

Snake Game: How to make the snake's body gets trimmed when its head touches its body?

I have a assignment that ask me to make a snake game with Python. The assignment asks me to make the snake's body gets trimmed when its head touches the body.
The snake body is a queue, so here is the code for forming a queue:
The snake's head is defined as the rear node and the snake's tail is defined as the front node, as shown in the picture below.
#The code of forming a queue, it cannot be modified
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
self.pre = None
self.next = None
class Queue:
def __init__(self):
self.front = None
self.rear = None
def len(self):
length = 0
cur = self.front
while cur:
cur = cur.next
length += 1
return length
def enQueue(self, x, y):
new = Node(x, y)
if self.len() == 0:
self.front = new
self.rear = new
else:
new.pre = self.rear
self.rear.next = new
self.rear = new
def deQueue(self):
if self.len() <= 1:
self.front = None
self.rear = None
else:
self.front = self.front.next
self.front.pre = None
def reverse(self):
cur = self.front
self.rear, self.front = self.front , self.rear
while cur:
cur.next, cur.pre = cur.pre, cur.next
cur = cur.pre
def printQueue(self):
cur = self.front
print("front", end=" ")
while cur:
print(f"[{cur.x}, {cur.y}]", end=" ")
cur = cur.next
print("rear")
And this is the main code for the game:
import pygame, sys, time, random
from pygame.locals import *
from pathlib import Path, os
from coor_queue import Node, Queue
from item_stack import Stack
class SnakeGame:
def __init__(self):
self.g = 30 #The width of each grid
self.dir = "right" #Initial Direction
self.snake = Queue() #Queue of the snake
for i in range(9):
self.snake.enQueue(i*self.g,9*self.g)
self.init_params()
self.init_pygame()
self.init_objects()
self.init_images()
#The code above cannot be modified
# =========================== Movement ===========================
def move(self):
headx = self.snake.rear.x
heady = self.snake.rear.y
if self.dir == "down":
heady += self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "up":
heady -= self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "left":
headx -= self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
if self.dir == "right":
headx += self.g
self.snake.enQueue(headx, heady)
self.snake.deQueue()
# =========================== Add Tails ===========================
def add_tail(self):
tailx = self.snake.front.x
taily = self.snake.front.y
newtail = Node(tailx, taily)
newtail.next = self.snake.front
self.snake.front.pre = newtail
self.snake.front = newtail
# =========================== Trim the snake's body ===========================
def eat_body(self):
# If the snake's head touches a grid (node) of the body
# Then the part from original tail to the grid which the snake's head touches
# Hint: Use self.snake
# ============The code below cannot be modified======================
def main(self):
while True:
self.keyboard_input()
self.check_input_valid()
self.move()
self.eat()
self.display()
if self.is_dead():
self.game_over()
self.fps.tick(8 + self.speed//5)
def keyboard_input(self): # Keyboard input
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord("d") or event.key == K_RIGHT: self.input_dir = "right"
if event.key == ord("a") or event.key == K_LEFT: self.input_dir = "left"
if event.key == ord("w") or event.key == K_UP: self.input_dir = "up"
if event.key == ord("s") or event.key == K_DOWN: self.input_dir = "down"
if event.key == K_ESCAPE: pygame.event.post(pygame.event.Event(QUIT))
def check_input_valid(self): #If the input direction is the opposite of the original direction, the input will be invalid
if (self.input_dir == "right" and self.dir != "left") or (self.input_dir == "left" and self.dir != "right") or \
(self.input_dir == "up" and self.dir != "down") or (self.input_dir == "down" and self.dir != "up"):
self.dir = self.input_dir
def eat(self): #Eat body or food
self.eat_food()
self.eat_body()
def display(self):
#Background
self.blit_map()
#Snake body
cur = self.snake.rear.pre
while cur:
self.blit_image("body", cur.x, cur.y, self.g, self.g)
cur = cur.pre
#Snake head
if self.snake.rear.x < self.width:
self.blit_image("head", self.snake.rear.x, self.snake.rear.y, self.g, self.g)
#Food
self.blit_image(self.food, self.foodPos.x, self.foodPos.y, self.g, self.g)
#Status Bar
self.blit_status_bar()
pygame.display.flip()
def is_dead(self):
return (self.snake.rear.x == self.width or self.snake.rear.x < 0) or \
(self.snake.rear.y == self.height or self.snake.rear.y < 0)
def game_over(self): # Game Over
self.play_theme("game_over1")
time.sleep(3)
pygame.quit()
sys.exit()
def init_params(self): #Basic parameters
self.screen_width = 1140
self.screen_height = 540
self.width = 960
self.height = 540
self.speed = 0
self.prob = 25
self.score = 0
self.spf = 10
self.satiety = 0
self.input_dir = None
def init_pygame(self): #Initialize pygame
pygame.init()
self.fps = pygame.time.Clock() #
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height)) #
pygame.display.set_caption("Snake Game") #
pygame.mixer.init()
def init_objects(self):
self.food_list = [food.split(".")[0] for food in os.listdir(Path("src/image/food"))]
self.food = None
self.select_food()
self.foodPos = Node(self.width//2, self.height//2)
def init_images(self):
self.img_StatusBar = pygame.image.load(Path("src/image/other/StatusBar.jpg")).convert_alpha()
self.img_head = pygame.image.load(Path("src/image/snake/SnakeHead.jpg")).convert_alpha()
self.img_body = pygame.image.load(Path("src/image/snake/SnakeBody.jpg")).convert_alpha()
self.img_map = pygame.image.load(Path("src/image/map/Map1.jpg")).convert_alpha()
for food in self.food_list:
exec(f"self.img_{food} = pygame.image.load(Path('src/image/food/{food}.jpg')).convert_alpha()")
def eat_food(self):
if self.snake.rear.x == self.foodPos.x and self.snake.rear.y == self.foodPos.y:
self.satiety += 1
self.speed += 1
self.spf = 10 + ((self.satiety-1)//10)*10
self.score += self.spf
self.play_effect("eat_food")
x = random.randrange(1, self.width//self.g)
y = random.randrange(1, self.height//self.g)
self.foodPos.x = x*self.g
self.foodPos.y = y*self.g
self.select_food()
self.add_tail()
def select_food(self):
while True:
next_food = self.food_list[random.randrange(len(self.food_list))]
if next_food != self.food:
self.food = next_food
break
def play_theme(self, theme):
pygame.mixer.music.load(Path(f"src/sound/theme/{theme}.mp3"))
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play()
def play_effect(self, effect):
sound = pygame.mixer.Sound(Path(f"src/sound/effect/{effect}.mp3"))
sound.set_volume(0.7)
sound.play()
def blit_image(self, name, coor_x = 0, coor_y = 0, size_x = 0, size_y = 0):
exec(f"self.img_{name} = pygame.transform.scale(self.img_{name}, size=(size_x, size_y))")
exec(f"self.screen.blit(self.img_{name}, (coor_x, coor_y))")
def blit_rect(self, data, coor_x = 0, coor_y = 0, font_size = 80, color = (0, 0, 0)):
self.Font = pygame.font.SysFont("", font_size)
self.Surf = self.Font.render(str(data), True, color)
self.Rect = self.Surf.get_rect()
self.Rect.center = (coor_x, coor_y)
self.screen.blit(self.Surf, self.Rect)
def blit_map(self):
self.blit_image("map", 0, 0, self.width, self.height)
def blit_status_bar(self):
self.blit_image("StatusBar", 960, 0, 180, self.screen_height)
self.blit_rect(self.score, 35*self.g, 1.87*self.g, font_size = 50, color = (238, 0, 0))
self.blit_rect(int(8 + self.speed)-7, 35*self.g, 4.13*self.g, font_size = 50, color = (178, 58, 238))
self.blit_rect(self.snake.len(), 35*self.g, 6.28*self.g, font_size = 50, color = (50, 205, 50))
# ==================================================================
game = SnakeGame()
game.main()
The picture below explains how trimming snake body works, the Python logo is the head.
I understand that the condition of trimming the body is when the head reaches the same grid as a part of the body. But I have no idea how to write this condition because I'm not sure if there is a way to get the coordinate from the nodes between front node and rear node.
Some further explanation is appreciated, thanks in advance.
Use a loop to compare the head of the queue against all elements of the body. The loop is similar to the loop in the print method. Return true if the position of the head is equal to a body position, else return false:
def isHeadEqualAnyBodyItem(snake):
head = snake.front
if not head:
return False
body = head.next
while body:
if head.x == body.x and head.y == body.y
return True
body = body.next
return False

my pygame window crashes whenever i added the sound/music in my game [duplicate]

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'

Putting the scrolling camera in a mini-window in pygame

I'm trying to create a game where the action is shown in a little box within the main screen object, freeing up the surrounding space for text and menus and what-not. Since the map is larger than the allotted window, I coded a basic "camera" that follows the player around. It mostly works, but I'm having trouble "trimming off" the area outside of this window.
Here's the relevant bits of code (EDITED to provide Working Example):
import pygame, os, sys
from pygame.locals import *
pygame.init()
RIGHT = 'RIGHT'
LEFT = 'LEFT'
UP = 'UP'
DOWN = 'DOWN'
class Camera():
def __init__(self, screen, x_ratio = 1, y_ratio = 1, x_offset = 0, y_offset = 0):
self.screen = screen.copy()
self.rec = self.screen.get_rect()
self.rec.width *= x_ratio
self.rec.height *= y_ratio
self.x_offset = x_offset
self.y_offset = y_offset
def get_pos(self):
return (self.x_offset - self.rec.x, self.y_offset - self.rec.y)
def get_window(self):
w = pygame.Rect(self.rec)
w.topleft = (0 - self.rec.x, 0 - self.rec.y)
return w
def move(self, x, y):
"""Move camera into new position"""
self.rec.x = x
self.rec.y = y
def track(self, obj):
while obj.rec.left < self.rec.left:
self.rec.x -= 1
while obj.rec.right > self.rec.right:
self.rec.x += 1
while obj.rec.top < self.rec.top:
self.rec.y -= 1
while obj.rec.bottom > self.rec.bottom:
self.rec.y += 1
class Map:
def __init__(self, width, height):
self.width = width
self.height = height
self.rec = pygame.Rect(0,0,self.width,self.height)
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
class Obj:
def __init__(self, char, x = 0, y = 0, width = 0, height = 0):
self.width = width
self.height = height
self.rec = pygame.Rect(x, y, width, height)
self.cur_map = None
self.timers = {}
#Dummying in chars for sprites
self.char = char
self.x_dir = 1
self.y_dir = 1
self.speed = 1
self.moving = False
def move(self):
if self.x_dir != 0 or self.y_dir != 0:
new_x = self.rec.x + (self.x_dir*self.speed)
new_y = self.rec.y + (self.y_dir*self.speed)
new_rec = pygame.Rect(new_x, new_y, self.width, self.height)
#Keep movement within bounds of map
while new_rec.left < self.cur_map.rec.left:
new_rec.x += 1
while new_rec.right > self.cur_map.rec.right:
new_rec.x -= 1
while new_rec.top < self.cur_map.rec.top:
new_rec.y += 1
while new_rec.bottom > self.cur_map.rec.bottom:
new_rec.y -= 1
self.rec = new_rec
def set_dir(self, d):
self.x_dir = 0
self.y_dir = 0
if d == LEFT:
self.x_dir = -1
elif d == RIGHT:
self.x_dir = 1
elif d == UP:
self.y_dir = -1
elif d == DOWN:
self.y_dir = 1
def set_moving(self, val = True):
self.moving = val
class Game:
def __init__(self):
self.screen_size = (800, 600)
self.screen = pygame.display.set_mode(self.screen_size)
self.map_screen = self.screen.copy()
self.title = 'RPG'
pygame.display.set_caption(self.title)
self.camera = Camera(self.screen, 0.75, 0.75)#, 10, 75)
self.fps = 80
self.clock = pygame.time.Clock()
self.debug = False
self.bg_color = (255,255,255)
self.text_size = 18
self.text_font = 'Arial'
self.text_style = pygame.font.SysFont(self.text_font, self.text_size)
self.key_binds = {LEFT : [K_LEFT, K_a], RIGHT : [K_RIGHT, K_d], UP : [K_UP, K_w], DOWN : [K_DOWN, K_s],
'interact' : [K_RETURN, K_z], 'inventory' : [K_i, K_SPACE], 'quit' : [K_ESCAPE]}
self.player = Obj('p', 0, 0, 10, self.text_size)
def draw(self, obj):
char = obj.char
self.draw_text(char, obj.rec.x, obj.rec.y, screen = self.map_screen)
def draw_text(self, text, x, y, color = (0,0,0), screen = None):
textobj = self.text_style.render(text, 1, color)
textrect = textobj.get_rect()
textrect.x = x
textrect.y = y
if screen == None:
"""Use default screen"""
self.screen.blit(textobj, textrect)
else:
screen.blit(textobj, textrect)
def play(self):
done = False
cur_map = Map(800, 800)
self.map_screen = pygame.Surface((cur_map.width, cur_map.height))
self.map_screen.fill(self.bg_color)
bg = pygame.Surface((cur_map.width, cur_map.height))
cur_map.draw(bg)
self.player.cur_map = cur_map
while not done:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key in self.key_binds[LEFT]:
self.player.set_dir(LEFT)
self.player.set_moving()
elif event.key in self.key_binds[RIGHT]:
self.player.set_dir(RIGHT)
self.player.set_moving()
elif event.key in self.key_binds[UP]:
self.player.set_dir(UP)
self.player.set_moving()
elif event.key in self.key_binds[DOWN]:
self.player.set_dir(DOWN)
self.player.set_moving()
elif event.type == KEYUP:
self.player.set_moving(False)
if self.player.moving:
self.player.move()
self.camera.track(self.player)
self.clock.tick()
self.screen.fill(self.bg_color)
self.map_screen.blit(bg, (0,0))
self.draw(self.player)
pygame.draw.rect(self.map_screen, (0,0,0), self.camera.rec, 1)
#self.screen.blit(self.map_screen, (0,0), [0 - self.camera.rec.x, 0 - self.camera.rec.y, self.camera.rec.width, self.camera.rec.height])
self.screen.blit(self.map_screen, self.camera.get_pos(), self.camera.get_window())
pygame.display.flip()
game = Game()
game.play()
Moving the player past past the bounds of the camera's window causes the window to roll up completely and disappear. I tried adjusting the blitting coordinates, as advised earlier, but it seems to only change the direction in which the window rolls up.
From your updated code, the blitting coordinates for self.screen.blit(...) are still changing: self.camera.get_window() changes value because rec.x and rec.y are values referring to the player position within the map. Hence you should define a constant minimap coordinate, this should be the same as the camera offset.
self.screen.blit(self.map_screen, (self.camera.x_offset,self.camera.y_offset), (*self.camera.get_pos(), self.camera.rec.width, self.camera.rec.height))
Change the Camera().get_pos() to:
def get_pos(self):
return (self.rec.x, self.rec.y)
I believe I only changed the self.screen.blit(...) and stopped using or rewrote your Camera functions as you're confusing yourself with all the rec variables.
To illustrate it working amend the Map().draw(screen) to:
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
pygame.draw.circle(screen, (255, 255, 255), (50, 50), 20, 2)
One tip as well don't draw the entire map at each loop, just the part that will be visible.

Label Position, Resize Background And Hide Title Bar

I'm trying to better understand Pyglet and I'm using a script posted by Torxed in my previous question. I started to modify it until I reached this point:
import pyglet, datetime, os
from pyglet.gl import *
from collections import OrderedDict
from time import time
from pathlib import Path
key = pyglet.window.key
class main(pyglet.window.Window):
#Variable Display
Fullscreen = False
CountDisplay = 0
setDisplay0 = (1024, 576)
setDisplay1 = (800, 600)
setDisplay2 = (1024, 768)
setDisplay3 = (1280, 720)
setDisplay4 = (1280, 1024)
setDisplay5 = (1366, 768)
setDisplay6 = (1920, 1080)
#Variable Info
infoHidden = False
title = "Pokémon Life And Death: Esploratori Del Proprio Destino"
build = "Versione: 0.0.0"
keyPrint = "Nessuno"
MousekeyPrint = "Nessuno"
infoFullscreen = "Disattivo"
infoDisplay = "1024, 576"
def __init__ (self, width=1024, height=576, fullscreen=False, *args, **kwargs):
super(main, self).__init__(width, height, fullscreen, *args, **kwargs)
platform = pyglet.window.get_platform()
display = platform.get_default_display()
screen = display.get_default_screen()
self.infoScreen = (screen.width, screen.height)
self.xDisplay = int(screen.width / 2 - self.width / 2)
self.yDisplay = int(screen.height / 2 - self.height / 2)
self.set_location(self.xDisplay, self.yDisplay)
self.sprites = OrderedDict()
self.spritesInfo = OrderedDict()
#Information Hidden
#Title
self.spritesInfo["title_label"] = pyglet.text.Label(self.title, x=self.infoPos("x", 0), y=self.infoPos("y", 0))
#Build Version
self.spritesInfo["build_label"] = pyglet.text.Label(self.build, x=self.infoPos("x", 0), y=self.infoPos("y", 20))
#Fullscreen
self.spritesInfo["fullscreen_label"] = pyglet.text.Label("Fullscreen: " + self.infoFullscreen, x=self.infoPos("x", 0), y=self.infoPos("y", 40))
#Display
self.spritesInfo["screen_label"] = pyglet.text.Label("Display: " + self.infoDisplay, x=self.infoPos("x", 0), y=self.infoPos("y", 60))
#FPS
self.spritesInfo["fps_label"] = pyglet.text.Label("FPS: 0", x=self.infoPos("x", 0), y=self.infoPos("y", 80))
self.last_update = time()
self.fps_count = 0
#Mouse Position
self.mouse_x = 0
self.mouse_y = 0
self.spritesInfo["mouse_label"] = pyglet.text.Label(("Mouse Position (X,Y): " + str(self.mouse_x) + "," + str(self.mouse_y)), x=self.infoPos("x", 0), y=self.infoPos("y", 100))
#Player Position
self.player_x = 0
self.player_y = 0
self.spritesInfo["player_label"] = pyglet.text.Label(("Player Position (X,Y): " + str(self.player_x) + "," + str(self.player_y)), x=self.infoPos("x", 0), y=self.infoPos("y", 120))
#Key Press
self.keys = OrderedDict()
self.spritesInfo["key_label"] = pyglet.text.Label(("Key Press: " + self.keyPrint), x=self.infoPos("x", 0), y=self.infoPos("y", 140))
#Mouse Press
self.spritesInfo["MouseKey_label"] = pyglet.text.Label(("Mouse Key Press: " + self.MousekeyPrint), x=self.infoPos("x", 0), y=self.infoPos("y", 160))
self.alive = 1
def infoPos(self, object, ny):
posInfo = self.get_size()
if object is "x":
elab = 10
elif object is "y":
elab = posInfo[1] - 20 - ny
else:
elab = 0
return elab
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_mouse_motion(self, x, y, dx, dy):
self.mouse_x = x
self.mouse_y = y
def on_mouse_release(self, x, y, button, modifiers):
self.MousekeyPrint = "Nessuno"
def on_mouse_press(self, x, y, button, modifiers):
self.MousekeyPrint = str(button)
def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
self.drag = True
print('Dragging mouse at {}x{}'.format(x, y))
def on_key_release(self, symbol, modifiers):
self.keyPrint = "Nessuno"
try:
del self.keys[symbol]
except:
pass
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE:
self.alive = 0
if symbol == key.F2:
datanow = datetime.datetime.now()
if not Path("Screenshot").is_dir():
os.makedirs("Screenshot")
pyglet.image.get_buffer_manager().get_color_buffer().save("Screenshot/"+str(datanow.day)+"-"+str(datanow.month)+"-"+str(datanow.year)+"_"+str(datanow.hour)+"."+str(datanow.minute)+"."+str(datanow.second)+".png")
if symbol == key.F3:
if self.infoHidden:
self.infoHidden = False
else:
self.infoHidden = True
if symbol == key.F10:
self.CountDisplay += 1
if self.CountDisplay == 1:
size = self.setDisplay1
elif self.CountDisplay == 2:
size = self.setDisplay2
elif self.CountDisplay == 3:
size = self.setDisplay3
elif self.CountDisplay == 4:
size = self.setDisplay4
elif self.CountDisplay == 5:
size = self.setDisplay5
elif self.CountDisplay == 6:
size = self.setDisplay6
else:
self.CountDisplay = 0
size = self.setDisplay0
self.set_size(size[0], size[1])
self.infoDisplay = str(size[0]) + "," + str(size[1])
pos = (int(self.infoScreen[0] / 2 - size[0] / 2), int(self.infoScreen[1] / 2 - size[1] / 2))
self.set_location(pos[0], pos[1])
if symbol == key.F11:
if self.Fullscreen:
self.Fullscreen = False
self.set_fullscreen(False)
self.infoFullscreen = "Disattivo"
else:
self.Fullscreen = True
self.set_fullscreen(True)
self.infoFullscreen = "Attivo"
self.keyPrint = str(symbol)
self.keys[symbol] = True
def pre_render(self):
pass
def render(self):
self.clear()
#FPS
self.fps_count += 1
if time() - self.last_update > 1:
self.spritesInfo["fps_label"].text = "FPS: " + str(self.fps_count)
self.fps_count = 0
self.last_update = time()
#Mouse Position
self.spritesInfo["mouse_label"].text = "Mouse Position (X,Y): " + str(self.mouse_x) + "," + str(self.mouse_y)
#Player Position
self.spritesInfo["player_label"].text = "Player Position (X,Y): " + str(self.player_x) + "," + str(self.player_y)
#Key Press
self.spritesInfo["key_label"].text = "Key Press: " + self.keyPrint
#Mouse Press
self.spritesInfo["MouseKey_label"].text = "Mouse Key Press: " + self.MousekeyPrint
#Fullscreen
self.spritesInfo["fullscreen_label"].text = "Fullscreen: " + self.infoFullscreen
#Display
self.spritesInfo["screen_label"].text = "Display: " + self.infoDisplay
#self.bg.draw()
self.pre_render()
for sprite in self.sprites:
self.sprites[sprite].draw()
if self.infoHidden:
for spriteInfo in self.spritesInfo:
self.spritesInfo[spriteInfo].draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
event = self.dispatch_events()
if __name__ == '__main__':
x = main()
x.run()
But now I find myself in front of a point where I can not proceed in Pyglet alone.
I can not understand how I can change the coordinates of the "label" every time the window size changes.
I would like to be able to use an image as a background and adapt it to the size of the window (basic the image is 1920x1080, ie the maximum window size). The problem is that I did not find much on this subject. I state that what I'm working on is 2D, not 3D. I had found a possible solution in another question, always answered by Torxed on the resizing of an image, but in some tests before this, after having adapted it, it did not work. So I do not know where to bang my head sincerely. In Pygame it was easy to use "pygame.transform.scale", but in Pyglet I would not know.
Finally, I tried both on the Pyglet wiki and on the web, but I did not find anything. How can I delete or hide the window title bar? In Pygame, you could with the flags. Is it possible to do this also with Pyglet?
EDIT:
I forgot to ask another question. When I press a key on the keyboard or mouse, the information displayed with F3 is printed in the corresponding key number. Is there a way to replace the number with the name of the button? For example, 97 is replaced with "A"? Obviously, I mean if there's a way without having to list all the keys and put the "if" statement for everyone.
EDIT2:
It seems like the script posted, the def on_resize (self, width, height) part does not like it very much. Let me explain, if for itself the function works correctly. The problem is that if I insert it, the labels, once pressed F3, do not appear. I tried to test it using print in several places and it seems that the only instruction that is not executed is self.spritesInfo [spriteInfo] .draw ()

Pygame objects only move on mouseclick

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:

Categories