unified GameGridAlly and GameGridEnemy

This commit is contained in:
Faraphel 2023-02-23 19:05:28 +01:00
parent db21bf5e04
commit a096785c28
8 changed files with 110 additions and 209 deletions

View file

@ -7,9 +7,9 @@ A faire :
- Voir si les event listener intégré à pyglet sont plus pratique que l'event propagation
- Documenter
- Ajouter plus d'event sur les widgets
- Ecran de victoire
- Affichage des coups de l'opposant
- Faire marcher le tchat
- Sauvegarde / Quitter

View file

@ -5,7 +5,6 @@ import pyglet
from source.gui.scene.abc import Scene
from source.gui import widget, texture
from source.gui.widget.grid import GameGridAlly, GameGridEnemy
from source import core
from source.network.packet import PacketChat, PacketBombPlaced, PacketBoatPlaced
from source.type import Point2D
@ -38,7 +37,7 @@ class Game(Scene):
)
self.grid_ally = self.add_widget(
GameGridAlly,
widget.GameGrid,
x=75, y=0.25, width=0.35, height=0.5,
@ -63,17 +62,19 @@ class Game(Scene):
self.grid_ally.add_listener("on_all_boats_placed", board_ally_ready)
self.grid_enemy = self.add_widget(
GameGridEnemy,
widget.GameGrid,
x=lambda widget: widget.scene.window.width - 75 - widget.width, y=0.25, width=0.35, height=0.5,
grid_style=texture.Grid.Style1,
boat_style=texture.Grid.Boat.Style1,
bomb_style=texture.Grid.Bomb.Style1,
rows=8, columns=8,
background_batch=self.batch_grid_background,
line_batch=self.batch_grid_line,
cursor_batch=self.batch_grid_cursor,
boat_batch=self.batch_grid_boat,
bomb_batch=self.batch_grid_bomb
)

View file

@ -1,25 +1,25 @@
from copy import copy
from typing import TYPE_CHECKING, Type
import pyglet
import numpy as np
import pyglet.shapes
from source.core import Board, Boat
from source.core.enums import Orientation
from source.core.error import InvalidBoatPosition
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.grid.abc import GameGrid
from source.core import Board, Boat
from source.type import Point2D, ColorRGB
from source.gui.widget.abc import BoxWidget
from source.type import Distance, ColorRGB, Point2D
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class GameGridAlly(GameGrid):
class GameGrid(BoxWidget):
"""
A game grid that represent the ally grid.
A widget that represent a game grid.
"""
def __init__(self, scene: "Scene",
@ -31,15 +31,23 @@ class GameGridAlly(GameGrid):
boat_style: Type[Style],
bomb_style: Type[Style],
boats_length: list[int],
x: Distance = 0,
y: Distance = 0,
width: Distance = None,
height: Distance = None,
preview_color: ColorRGB = (150, 255, 150),
boats_length: list[int] = None,
**kwargs):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
super().__init__(scene, rows, columns, grid_style, **kwargs)
super().__init__(scene, x, y, width, height)
self.boats_length = boats_length # the list of the size of the boats to place
self.rows = rows
self.columns = columns
self.boats_length = [] if boats_length is None else boats_length # the list of the size of the boats to place
self.preview_color = preview_color
self.board = Board(rows=self.rows, columns=self.columns)
@ -47,19 +55,69 @@ class GameGridAlly(GameGrid):
self._boat_kwargs = dict_filter_prefix("boat_", kwargs)
self._bomb_kwargs = dict_filter_prefix("bomb_", kwargs)
self.grid_style = grid_style
self.boat_style = boat_style
self.bomb_style = bomb_style
self.background = Sprite(
img=grid_style.get("background"),
**dict_filter_prefix("background_", kwargs)
)
self.lines: list[pyglet.shapes.Line] = [
pyglet.shapes.Line(
0, 0, 0, 0,
**dict_filter_prefix("line_", kwargs)
)
for _ in range((self.columns - 1) + (self.rows - 1))
]
self.cursor = pyglet.shapes.Rectangle(
0, 0, 0, 0,
color=(0, 0, 0, 100),
**dict_filter_prefix("cursor_", kwargs)
)
self.add_listener("on_click_release", self.on_click_release)
self.add_listener("on_hover", lambda rel_x, rel_y: self.preview_boat(self.get_cell_from_rel(rel_x, rel_y)))
self.add_listener("on_hover_leave", lambda *_: self.hide_cursor())
self.add_listener("on_hover", self._refresh_cursor)
self._refresh_size()
def get_cell_from_rel(self, rel_x: int, rel_y: int) -> tuple[int, int]:
"""
Return the cell of the grid from a point relative position
"""
return (
int((rel_x-1) / self.cell_width),
int((rel_y-1) / self.cell_height)
)
# refresh
def _refresh_size(self):
super()._refresh_size()
self.background.x, self.background.y = self.xy
self.background.width, self.background.height = self.size
# lines
for column, line in enumerate(self.lines[:self.columns - 1], start=1):
line.x = self.x + self.cell_width * column
line.x2 = line.x
line.y = self.y
line.y2 = self.y2
for row, line in enumerate(self.lines[-self.rows + 1:], start=1):
line.x = self.x
line.x2 = self.x2
line.y = self.y + self.cell_height * row
line.y2 = line.y
# sprites
for (x, y), sprite in self.cell_sprites.items():
# calcul des décalages à cause de la rotation qui est faite par rapport à l'origine de l'image
offset_x = 0 if sprite.rotation <= 90 else self.cell_width
@ -75,6 +133,20 @@ class GameGridAlly(GameGrid):
sprite.width = width
sprite.height = height
def _refresh_cursor(self, rel_x: int, rel_y: int):
cell_x, cell_y = self.get_cell_from_rel(rel_x, rel_y)
self.cursor.x = self.x + cell_x * self.width / self.columns
self.cursor.y = self.y + cell_y * self.height / self.rows
self.cursor.width, self.cursor.height = self.cell_size
self.preview_boat((cell_x, cell_y)) # display the previsualisation of the boat on this cell
# function
def hide_cursor(self):
self.cursor.width, self.cursor.height = 0, 0
def display_board(self, board: Board, preview: bool = False):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
@ -151,7 +223,6 @@ class GameGridAlly(GameGrid):
else: self.display_board(preview_board, preview=True)
def place_bomb(self, cell: Point2D, touched: bool):
self.cell_sprites[cell] = Sprite(
img=self.bomb_style.get("touched" if touched else "missed"),
**self._bomb_kwargs
@ -169,6 +240,26 @@ class GameGridAlly(GameGrid):
case pyglet.window.mouse.LEFT:
self.place_boat(cell)
self.trigger_event("on_request_place_bomb", cell)
# property
@property
def cell_width(self) -> float:
return self.width / self.columns
@property
def cell_height(self) -> float:
return self.height / self.rows
@property
def cell_size(self) -> tuple[float, float]:
return self.cell_width, self.cell_height
# event
def on_resize(self, width: int, height: int):
self._refresh_size()
def draw(self):
self.background.draw()

View file

@ -4,3 +4,4 @@ from .Input import Input
from .Image import Image
from .Checkbox import Checkbox
from .Scroller import Scroller
from .GameGrid import GameGrid

View file

@ -1,65 +0,0 @@
from typing import Type, TYPE_CHECKING
import pyglet
from source.gui.texture.abc import Style
from source.gui.widget.grid.abc import GameGrid
from source.gui.sprite import Sprite
from source.type import Point2D
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class GameGridEnemy(GameGrid):
"""
A game grid that represent the enemy grid.
"""
def __init__(self, scene: "Scene",
rows: int,
columns: int,
grid_style: Type[Style],
bomb_style: Type[Style],
**kwargs):
self.cell_sprites: dict[Point2D, "Sprite"] = {}
super().__init__(scene, rows, columns, grid_style, **kwargs)
self._bomb_kwargs = dict_filter_prefix("bomb_", kwargs)
self.bomb_style = bomb_style
self.add_listener("on_click_release", self.on_click_release)
def _refresh_size(self):
super()._refresh_size()
for (x, y), sprite in self.cell_sprites.items():
sprite.x = self.x + (self.cell_width * x)
sprite.y = self.y + (self.cell_height * y)
sprite.width = self.cell_width
sprite.height = self.cell_height
def place_bomb(self, cell: Point2D, touched: bool):
self.cell_sprites[cell] = Sprite(
img=self.bomb_style.get("touched" if touched else "missed"),
**self._bomb_kwargs
)
self._refresh_size()
def on_click_release(self, rel_x: int, rel_y: int, button: int, modifiers: int):
cell = self.get_cell_from_rel(rel_x, rel_y)
if button == pyglet.window.mouse.LEFT:
self.trigger_event("on_request_place_bomb", cell)
def draw(self):
self.background.draw()
for sprite in self.cell_sprites.values(): sprite.draw()
self.cursor.draw()
for line in self.lines: line.draw()

View file

@ -1,2 +0,0 @@
from .GameGridAlly import GameGridAlly
from .GameGridEnemy import GameGridEnemy

View file

@ -1,124 +0,0 @@
from typing import TYPE_CHECKING, Type
import pyglet.shapes
from source.gui.sprite import Sprite
from source.gui.texture.abc import Style
from source.gui.widget.abc import BoxWidget
from source.type import Distance
from source.utils import dict_filter_prefix
if TYPE_CHECKING:
from source.gui.scene.abc import Scene
class GameGrid(BoxWidget):
"""
A widget that represent a game grid.
"""
def __init__(self, scene: "Scene",
rows: int,
columns: int,
style: Type[Style],
x: Distance = 0,
y: Distance = 0,
width: Distance = None,
height: Distance = None,
**kwargs):
super().__init__(scene, x, y, width, height)
self.rows = rows
self.columns = columns
self.style = style
self.background = Sprite(
img=style.get("background"),
**dict_filter_prefix("background_", kwargs)
)
self.lines: list[pyglet.shapes.Line] = [
pyglet.shapes.Line(
0, 0, 0, 0,
**dict_filter_prefix("line_", kwargs)
)
for _ in range((self.columns - 1) + (self.rows - 1))
]
self.cursor = pyglet.shapes.Rectangle(
0, 0, 0, 0,
color=(0, 0, 0, 100),
**dict_filter_prefix("cursor_", kwargs)
)
self.add_listener("on_hover_leave", lambda *_: self.hide_cursor())
self.add_listener("on_hover", self._refresh_cursor)
self._refresh_size()
def get_cell_from_rel(self, rel_x: int, rel_y: int) -> tuple[int, int]:
"""
Return the cell of the grid from a point relative position
"""
return (
int((rel_x-1) / self.cell_width),
int((rel_y-1) / self.cell_height)
)
# refresh
def _refresh_size(self):
self.background.x, self.background.y = self.xy
self.background.width, self.background.height = self.size
for column, line in enumerate(self.lines[:self.columns - 1], start=1):
line.x = self.x + self.cell_width * column
line.x2 = line.x
line.y = self.y
line.y2 = self.y2
for row, line in enumerate(self.lines[-self.rows + 1:], start=1):
line.x = self.x
line.x2 = self.x2
line.y = self.y + self.cell_height * row
line.y2 = line.y
def _refresh_cursor(self, rel_x: int, rel_y: int):
cell_x, cell_y = self.get_cell_from_rel(rel_x, rel_y)
self.cursor.x = self.x + cell_x * self.width / self.columns
self.cursor.y = self.y + cell_y * self.height / self.rows
self.cursor.width, self.cursor.height = self.cell_size
def hide_cursor(self):
self.cursor.width, self.cursor.height = 0, 0
# property
@property
def cell_width(self) -> float:
return self.width / self.columns
@property
def cell_height(self) -> float:
return self.height / self.rows
@property
def cell_size(self) -> tuple[float, float]:
return self.cell_width, self.cell_height
# event
def on_resize(self, width: int, height: int):
self._refresh_size()
def draw(self):
self.background.draw()
self.cursor.draw()
for line in self.lines: line.draw()

View file

@ -1 +0,0 @@
from .GameGrid import GameGrid