Проблема с отскакиванием мячей(Python, raylib)
В этом коде по какой-то причине мячи не отскакивают друг от друга, я не понимаю почему. Обработка коллизий происходит в game_scene_process_logic().
import datetime
import random
import pyray
from raylib import colors
class Image:
def __init__(self, x, y, filename):
self.image = pyray.load_image(filename)
self.texture = pyray.load_texture_from_image(self.image)
self.rect = pyray.Rectangle(x, y, self.texture.width, self.texture.height)
self.filename = filename
def draw(self):
pyray.draw_texture(self.texture, self.rect.x, self.rect.y, None )
class Ball(Image):
def __init__(self, x, y, filename, shift_x, shift_y):
Image.__init__(self, x, y, filename)
self.shift = pyray.Vector2(shift_x, shift_y)
self.radius = self.texture.width//2
self.initial = {}
self.position = pyray.Vector2(x, y)
def activate(self):
self.position.x = self.initial["x"]
self.position.y = self.initial["y"]
self.shift_x = self.initial["shift_x"]
self.shift_y = self.initial["shift_y"]
def step(self):
self.position.x+=self.shift.x
self.position.x += self.shift.y
def collides_with_horizontal_border(self, window_height):
if self.position.y>window_height or self.position.y<window_height:
return True
else:
return False
def collides_with_vertical_border(self, window_width):
if self.position.x>window_width or self.position.x<window_width:
return True
else:
return False
def bounce_x(self):
self.shift.x *= -1
def bounce_y(self):
self.shift.y *= -1
def collides_with(self, other_ball):
if pyray.check_collision_circles(pyray.Vector2(self.position.x, self.position.y), self.radius, pyray.Vector2(other_ball.position.x, other_ball.position.y), other_ball.radius):
return True
else:
return False
def collide(self, other_ball):
temp = self.shift
self.shift = other_ball.shift
other_ball.shift = temp
def logic(self, window_width, window_height):
self.step()
if self.collides_with_horizontal_border(window_height):
self.bounce_y()
if self.collides_with_vertical_border(window_width):
self.bounce_x()
def main():
# Инициализация окна
window_width = 800
window_height = 600
pyray.init_window(window_width, window_height, 'Hello, raylib')
pyray.set_exit_key(pyray.KeyboardKey.KEY_F8)
pyray.set_target_fps(120)
# Инициализация глобальных переменных
scene_index = 0
scene_changed = True
background_color = colors.BLACK
# Инициализация сцены 0 (menu)
scene_0_button_new_geometry = pyray.Rectangle(window_width / 2 - 100 / 2, window_height / 2 - 10 - 50, 100, 50)
scene_0_button_exit_geometry = pyray.Rectangle(window_width / 2 - 100 / 2, window_height / 2 + 10, 100, 50)
motion_seconds = 3
motion_start = datetime.datetime.now()
motion_now = datetime.datetime.now()
percent_completed = 0
line_color = colors.WHITE
# Инициализация сцены 1 (game)
ball_image = pyray.load_image('basketball.png')
ball_texture = pyray.load_texture_from_image(ball_image)
pyray.unload_image(ball_image)
del ball_image
max_collision_count = 5
collision_text_format = 'Collisions: {}/' + str(max_collision_count)
# ball_0_position = pyray.Vector2(10, 10)
# ball_0_shift = [1, 1]
ball_0 = Ball(10, 10, "basketball.png", 1, 1)
# ball_1_position = pyray.Vector2(500, 100)
# ball_1_shift = [-1, 1]
ball_1 = Ball(500, 100, "basketball.png", -1, 1)
# ball_2_position = pyray.Vector2(400, 500)
# ball_2_shift = [-1, -1]
ball_2 = Ball(400, 500, "basketball.png", -1, -1)
balls = [ball_0, ball_1, ball_2]
collision_count = 0
# Инициализация сцены 2 (gameover)
max_wait_seconds = 3
wait_seconds = 0
gameover_text_format = 'Game over ({}/{})'.format('{}', max_wait_seconds)
open_scene_datetime = datetime.datetime.now()
# Основной цикл программы
while not pyray.window_should_close():
# Действия, выполняемые при первом появлении сцены на экране
if scene_changed:
scene_changed = False
if scene_index == 0: # menu
motion_start, percent_completed = menu_scene_on_activate(motion_start, percent_completed)
elif scene_index == 1: # game
balls = game_scene_on_activate(balls)
#Рандомизируем позицию мячей
elif scene_index == 2: # gameover
open_scene_datetime = game_over_scene_on_activate(open_scene_datetime)
# Обработка событий различных сцен (при каждом кадре)
if not scene_changed:
if scene_index == 0: # menu
scene_changed, scene_index = menu_scene_process_event(scene_0_button_exit_geometry,
scene_0_button_new_geometry, scene_changed,
scene_index)
elif scene_index == 1: # game
scene_changed, scene_index = game_scene_process_event(scene_changed, scene_index)
elif scene_index == 2: # gameover
scene_changed, scene_index = game_over_scene_process_event(scene_changed, scene_index)
# Обработка логики работы сцен (при каждом кадре)
if not scene_changed:
if scene_index == 0: # menu
percent_completed = menu_scene_process_logic(motion_seconds, motion_start, percent_completed)
elif scene_index == 1: # game
balls, collision_count, scene_changed, scene_index = game_scene_process_logic(balls, ball_texture, collision_count, max_collision_count, scene_changed, scene_index, window_height, window_width)
elif scene_index == 2: # gameover
scene_changed, scene_index, wait_seconds = game_over_scene_process_logic(max_wait_seconds,
open_scene_datetime,
scene_changed, scene_index,
wait_seconds)
# Обработка отрисовки различных сцен (при каждом кадре)
if not scene_changed:
pyray.begin_drawing()
pyray.clear_background(background_color)
if scene_index == 0: # menu
menu_scene_process_draw(line_color, percent_completed)
elif scene_index == 1: # game
game_scene_process_draw(balls, ball_texture, collision_count, collision_text_format)
elif scene_index == 2: # gameover
game_over_scene_process_draw(gameover_text_format, wait_seconds)
pyray.end_drawing()
pyray.unload_texture(ball_texture)
pyray.close_window()
exit(0)
def game_over_scene_process_draw(gameover_text_format, wait_seconds):
pyray.draw_text(gameover_text_format.format(wait_seconds), 100, 250, 78, colors.RED)
def game_scene_process_draw(balls, ball_texture, collision_count, collision_text_format):
for i in balls:
pyray.draw_texture_v(ball_texture, i.position, colors.WHITE)
pyray.draw_text(collision_text_format.format(collision_count), 10, 10, 78, colors.WHITE)
def menu_scene_process_draw(line_color, percent_completed):
# четыре анимированные линии (две кнопки уже отрисовались)
pyray.draw_line_ex(pyray.Vector2(100, 100), pyray.Vector2(100 + 600 * percent_completed, 100),
4, line_color)
pyray.draw_line_ex(pyray.Vector2(700, 100), pyray.Vector2(700, 100 + 400 * percent_completed, ),
4, line_color)
pyray.draw_line_ex(pyray.Vector2(700, 500), pyray.Vector2(700 - 600 * percent_completed, 500),
4, line_color)
pyray.draw_line_ex(pyray.Vector2(100, 500), pyray.Vector2(100, 500 - 400 * percent_completed),
4, line_color)
def game_over_scene_process_logic(max_wait_seconds, open_scene_datetime, scene_changed, scene_index, wait_seconds):
now = datetime.datetime.now()
wait_seconds = (now - open_scene_datetime).seconds
# Переключение сцен при достижении нужного количества секунд (микросекунд)
if wait_seconds == max_wait_seconds:
scene_changed = True
scene_index = 0
return scene_changed, scene_index, wait_seconds
def game_scene_process_logic(balls, ball_texture, collision_count, max_collision_count, scene_changed,
scene_index, window_height, window_width):
# Движение мячиков
for i in balls:
i.position.x += i.shift[0]
i.position.y += i.shift[1]
# Отражение от стенок
for i in balls:
if i.position.x < 0 or i.position.x + ball_texture.width > window_width:
i.shift[0] *= -1
if i.position.y < 0 or i.position.y + ball_texture.height > window_height:
i.shift[1] *= -1
# Обработка коллизий
for i in range(len(balls)):
for j in range(len(balls)):
if balls[i].collides_with(balls[j]) and i != j:
balls[i].collide(balls[j])
collision_count+=1
# Переключение сцен при достижении нужного количества коллизий
if collision_count == max_collision_count:
scene_changed = True
scene_index = 2
return balls, collision_count, scene_changed, scene_index
def menu_scene_process_logic(motion_seconds, motion_start, percent_completed):
motion_now = datetime.datetime.now()
delta = (motion_now - motion_start)
ms = delta.seconds * 1000000 + delta.microseconds
percent_completed = min(1.0, ms / (motion_seconds * 1000000))
return percent_completed
def game_over_scene_process_event(scene_changed, scene_index):
if pyray.is_key_down(pyray.KeyboardKey.KEY_ESCAPE):
scene_changed = True
scene_index = 0
return scene_changed, scene_index
def game_scene_process_event(scene_changed, scene_index):
if pyray.is_key_down(pyray.KeyboardKey.KEY_ESCAPE):
scene_changed = True
scene_index = 0
return scene_changed, scene_index
def menu_scene_process_event(scene_0_button_exit_geometry, scene_0_button_new_geometry, scene_changed, scene_index):
if pyray.gui_button(scene_0_button_new_geometry, 'New game'):
scene_changed = True
scene_index = 1
if pyray.gui_button(scene_0_button_exit_geometry, 'Exit'):
pyray.close_window()
exit(0)
return scene_changed, scene_index
def game_over_scene_on_activate(open_scene_datetime):
open_scene_datetime = datetime.datetime.now()
return open_scene_datetime
def game_scene_on_activate(balls):
for i in balls:
i.shift = [random.choice([-1, 1]), random.choice([-1, 1])]
i.position = pyray.Vector2(random.randint(10, 500), random.randint(10, 500))
return balls
def menu_scene_on_activate(motion_start, percent_completed):
motion_start = datetime.datetime.now()
motion_now = datetime.datetime.now()
percent_completed = 0
return motion_start, percent_completed
if __name__ == '__main__':
main()