wip
This commit is contained in:
parent
78cc5ff0cd
commit
70f4a89e30
10 changed files with 564 additions and 182 deletions
2
.pyflyby
2
.pyflyby
|
|
@ -1,3 +1,5 @@
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
|
||||||
|
|
||||||
from learn_sql_model.api.websocket_connection_manager import manager
|
from learn_sql_model.api.websocket_connection_manager import manager
|
||||||
from learn_sql_model.config import Config
|
from learn_sql_model.config import Config
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ WORKDIR /app
|
||||||
Copy pyproject.toml /app
|
Copy pyproject.toml /app
|
||||||
COPY learn_sql_model/__about__.py /app/learn_sql_model/__about__.py
|
COPY learn_sql_model/__about__.py /app/learn_sql_model/__about__.py
|
||||||
COPY README.md /app
|
COPY README.md /app
|
||||||
RUN pip3 install .
|
RUN pip3 install '.[api]'
|
||||||
COPY . /app
|
COPY . /app
|
||||||
RUN pip3 install .
|
RUN pip3 install '.[api]'
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import httpx
|
import httpx
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
import typer
|
import typer
|
||||||
import uvicorn
|
|
||||||
|
|
||||||
from learn_sql_model.cli.common import verbose_callback
|
from learn_sql_model.cli.common import verbose_callback
|
||||||
from learn_sql_model.config import get_config
|
from learn_sql_model.config import get_config
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
|
||||||
|
uvicorn = _optional_import_("uvicorn", group="api")
|
||||||
api_app = typer.Typer()
|
api_app = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ from rich.console import Console
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from learn_sql_model.config import get_config
|
from learn_sql_model.config import get_config
|
||||||
from learn_sql_model.factories.hero import HeroFactory
|
|
||||||
from learn_sql_model.models.hero import (
|
from learn_sql_model.models.hero import (
|
||||||
Hero,
|
Hero,
|
||||||
HeroCreate,
|
HeroCreate,
|
||||||
|
|
@ -15,6 +14,13 @@ from learn_sql_model.models.hero import (
|
||||||
HeroUpdate,
|
HeroUpdate,
|
||||||
Heros,
|
Heros,
|
||||||
)
|
)
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
|
||||||
|
HeroFactory = _optional_import_(
|
||||||
|
"learn_sql_model.factories.hero",
|
||||||
|
"HeroFactory",
|
||||||
|
group="api",
|
||||||
|
)
|
||||||
|
|
||||||
hero_app = typer.Typer()
|
hero_app = typer.Typer()
|
||||||
|
|
||||||
|
|
@ -46,7 +52,7 @@ def list(
|
||||||
) -> Union[Hero, List[Hero]]:
|
) -> Union[Hero, List[Hero]]:
|
||||||
"list many heros"
|
"list many heros"
|
||||||
heros = Heros.list(where=where, offset=offset, limit=limit)
|
heros = Heros.list(where=where, offset=offset, limit=limit)
|
||||||
Console().print(heros)
|
Console().print(hero)
|
||||||
return hero
|
return hero
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
import atexit
|
import atexit
|
||||||
|
|
||||||
import pygame
|
|
||||||
from typer import Typer
|
from typer import Typer
|
||||||
from websocket import create_connection
|
from websocket import create_connection
|
||||||
|
|
||||||
from learn_sql_model.game.menu import Menu
|
|
||||||
from learn_sql_model.config import get_config
|
from learn_sql_model.config import get_config
|
||||||
from learn_sql_model.console import console
|
from learn_sql_model.console import console
|
||||||
from learn_sql_model.factories.hero import HeroFactory
|
from learn_sql_model.game.map import Map
|
||||||
from learn_sql_model.models.hero import HeroCreate, HeroDelete, HeroUpdate, Heros
|
from learn_sql_model.game.menu import Menu
|
||||||
|
from learn_sql_model.game.player import Player
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
|
||||||
|
pygame = _optional_import_("pygame", group="game")
|
||||||
|
|
||||||
speed = 10
|
speed = 10
|
||||||
|
|
||||||
config = get_config()
|
config = get_config()
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
hero = HeroFactory().build(size=50, x=100, y=100)
|
|
||||||
self.hero = HeroCreate(**hero.dict()).post()
|
|
||||||
|
|
||||||
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
|
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
|
||||||
pygame.display.set_caption("Learn SQL Model")
|
pygame.display.set_caption("Learn SQL Model")
|
||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
|
|
@ -30,13 +30,15 @@ class Client:
|
||||||
self.moving_left = False
|
self.moving_left = False
|
||||||
self.moving_right = False
|
self.moving_right = False
|
||||||
self.ticks = 0
|
self.ticks = 0
|
||||||
self.others = []
|
self.player = Player(self)
|
||||||
self.menu = Menu(self)
|
self.menu = Menu(self)
|
||||||
|
self.map = Map(self)
|
||||||
self.font = pygame.font.SysFont("", 50)
|
self.font = pygame.font.SysFont("", 50)
|
||||||
|
self.joysticks = {}
|
||||||
|
|
||||||
atexit.register(self.quit)
|
atexit.register(self.quit)
|
||||||
|
|
||||||
@ property
|
@property
|
||||||
def ws(self):
|
def ws(self):
|
||||||
def connect():
|
def connect():
|
||||||
self._ws = create_connection(
|
self._ws = create_connection(
|
||||||
|
|
@ -59,67 +61,23 @@ class Client:
|
||||||
console.print("render")
|
console.print("render")
|
||||||
self.render()
|
self.render()
|
||||||
time = self.clock.tick(60)
|
time = self.clock.tick(60)
|
||||||
|
self.elapsed = time / 100
|
||||||
self.ticks += 1
|
self.ticks += 1
|
||||||
console.print(f"time: {time}")
|
console.print(f"time: {time}")
|
||||||
console.print(f"ticks: {self.ticks}")
|
console.print(f"ticks: {self.ticks}")
|
||||||
self.quit()
|
self.quit()
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
try:
|
self.running = False
|
||||||
HeroDelete(id=self.hero.id).delete()
|
self.player.quit()
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.moving_up:
|
...
|
||||||
self.hero.y -= speed
|
|
||||||
if self.moving_down:
|
|
||||||
self.hero.y += speed
|
|
||||||
if self.moving_left:
|
|
||||||
self.hero.x -= speed
|
|
||||||
if self.moving_right:
|
|
||||||
self.hero.x += speed
|
|
||||||
|
|
||||||
if self.hero.x < 0 + self.hero.size:
|
|
||||||
self.hero.x = 0 + self.hero.size
|
|
||||||
if self.hero.x > self.screen.get_width() - self.hero.size:
|
|
||||||
self.hero.x = self.screen.get_width() - self.hero.size
|
|
||||||
if self.hero.y < 0 + self.hero.size:
|
|
||||||
self.hero.y = 0 + self.hero.size
|
|
||||||
if self.hero.y > self.screen.get_height() - self.hero.size:
|
|
||||||
self.hero.y = self.screen.get_height() - self.hero.size
|
|
||||||
|
|
||||||
if self.ticks % 5 == 0 or self.ticks == 0:
|
|
||||||
console.print("updating")
|
|
||||||
update = HeroUpdate(**self.hero.dict(exclude_unset=True))
|
|
||||||
console.print(update)
|
|
||||||
self.ws.send(update.json())
|
|
||||||
console.print("sent")
|
|
||||||
|
|
||||||
raw_heros = self.ws.recv()
|
|
||||||
console.print(raw_heros)
|
|
||||||
self.others = Heros.parse_raw(raw_heros)
|
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
self.screen.fill((0, 0, 0))
|
self.screen.fill((0, 0, 0))
|
||||||
|
self.map.render()
|
||||||
for other in self.others.heros:
|
self.player.render()
|
||||||
if other.id != self.hero.id:
|
|
||||||
pygame.draw.circle(
|
|
||||||
self.screen, (255, 0, 0), (other.x, other.y), other.size
|
|
||||||
)
|
|
||||||
self.screen.blit(
|
|
||||||
self.font.render(other.name, False, (255, 255, 255), 1),
|
|
||||||
(other.x, other.y),
|
|
||||||
)
|
|
||||||
|
|
||||||
pygame.draw.circle(
|
|
||||||
self.screen, (0, 0, 255), (self.hero.x, self.hero.y), self.hero.size
|
|
||||||
)
|
|
||||||
self.screen.blit(
|
|
||||||
self.font.render(self.hero.name, False, (255, 255, 255)),
|
|
||||||
(self.hero.x, self.hero.y),
|
|
||||||
)
|
|
||||||
|
|
||||||
# update the screen
|
# update the screen
|
||||||
self.menu.render()
|
self.menu.render()
|
||||||
|
|
@ -127,52 +85,18 @@ class Client:
|
||||||
|
|
||||||
def handle_events(self):
|
def handle_events(self):
|
||||||
self.events = pygame.event.get()
|
self.events = pygame.event.get()
|
||||||
|
self.menu.handle_events(self.events)
|
||||||
|
self.player.handle_events()
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
self.running = False
|
self.running = False
|
||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.JOYDEVICEADDED:
|
||||||
if event.key == pygame.K_ESCAPE:
|
# This event will be generated when the program starts for every
|
||||||
self.running = False
|
# joystick, filling up the list without needing to create them manually.
|
||||||
if event.key == pygame.K_LEFT:
|
joy = pygame.joystick.Joystick(event.device_index)
|
||||||
self.moving_left = True
|
self.joysticks[joy.get_instance_id()] = joy
|
||||||
if event.key == pygame.K_RIGHT:
|
if event.type == pygame.JOYDEVICEREMOVED:
|
||||||
self.moving_right = True
|
del self.joysticks[event.instance_id]
|
||||||
if event.key == pygame.K_UP:
|
|
||||||
self.moving_up = True
|
|
||||||
if event.key == pygame.K_DOWN:
|
|
||||||
self.moving_down = True
|
|
||||||
# wasd
|
|
||||||
if event.key == pygame.K_w:
|
|
||||||
self.moving_up = True
|
|
||||||
if event.key == pygame.K_s:
|
|
||||||
self.moving_down = True
|
|
||||||
if event.key == pygame.K_a:
|
|
||||||
self.moving_left = True
|
|
||||||
if event.key == pygame.K_d:
|
|
||||||
self.moving_right = True
|
|
||||||
# controller left joystick
|
|
||||||
|
|
||||||
if event.type == pygame.KEYUP:
|
|
||||||
if event.key == pygame.K_LEFT:
|
|
||||||
self.moving_left = False
|
|
||||||
if event.key == pygame.K_RIGHT:
|
|
||||||
self.moving_right = False
|
|
||||||
if event.key == pygame.K_UP:
|
|
||||||
self.moving_up = False
|
|
||||||
if event.key == pygame.K_DOWN:
|
|
||||||
self.moving_down = False
|
|
||||||
# wasd
|
|
||||||
if event.key == pygame.K_w:
|
|
||||||
self.moving_up = False
|
|
||||||
if event.key == pygame.K_s:
|
|
||||||
self.moving_down = False
|
|
||||||
if event.key == pygame.K_a:
|
|
||||||
self.moving_left = False
|
|
||||||
if event.key == pygame.K_d:
|
|
||||||
self.moving_right = False
|
|
||||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
||||||
if event.button == 1: # Left mouse button
|
|
||||||
self.menu.handle_click()
|
|
||||||
|
|
||||||
def check_events(self):
|
def check_events(self):
|
||||||
pass
|
pass
|
||||||
|
|
@ -184,7 +108,7 @@ class Client:
|
||||||
game_app = Typer()
|
game_app = Typer()
|
||||||
|
|
||||||
|
|
||||||
@ game_app.command()
|
@game_app.command()
|
||||||
def run():
|
def run():
|
||||||
client = Client()
|
client = Client()
|
||||||
client.run()
|
client.run()
|
||||||
|
|
|
||||||
99
learn_sql_model/game/map.py
Normal file
99
learn_sql_model/game/map.py
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
import pydantic
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
|
snoise2 = _optional_import_("noise", "snoise2", group="game")
|
||||||
|
pygame = _optional_import_("pygame", group="game")
|
||||||
|
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
|
class Point(pydantic.BaseModel):
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
|
||||||
|
|
||||||
|
class Map:
|
||||||
|
def __init__(self, game):
|
||||||
|
self.game = game
|
||||||
|
# self.grass = pygame.image.load("grass.webp").convert_alpha()
|
||||||
|
# self.rock = pygame.image.load("rock.jpg").convert_alpha()
|
||||||
|
# self.dirt = pygame.image.load("dirt.jpg").convert_alpha()
|
||||||
|
self.brown = (204, 153, 102)
|
||||||
|
self.grey = (128, 128, 128)
|
||||||
|
self.green = (0, 255, 0)
|
||||||
|
self.white = (255, 255, 255)
|
||||||
|
self.resolution = 16
|
||||||
|
self.scale = 0.14 # Determines the "smoothness" of the terrain
|
||||||
|
self.scale = 0.05 # Determines the "smoothness" of the terrain
|
||||||
|
self.offset = Point(x=0, y=0)
|
||||||
|
self.last_offset = self.offset
|
||||||
|
self.screen_width = self.game.screen.get_width()
|
||||||
|
self.screen_height = self.game.screen.get_height()
|
||||||
|
self.octaves = 2 # Number of layers of noise to combine
|
||||||
|
self.persistence = 0.05 # Amplitude of each octave
|
||||||
|
self.lacunarity = 1.0 # Frequency of each octave
|
||||||
|
self.thresh = 125
|
||||||
|
self.pre_draw()
|
||||||
|
|
||||||
|
def refresh_surf(self):
|
||||||
|
self.surf = pygame.Surface((self.screen_width, self.screen_height))
|
||||||
|
|
||||||
|
def get_noise(self, x, y):
|
||||||
|
value = snoise2(
|
||||||
|
(x + self.offset.x) * self.scale,
|
||||||
|
(y + self.offset.y) * self.scale,
|
||||||
|
self.octaves,
|
||||||
|
self.persistence,
|
||||||
|
self.lacunarity,
|
||||||
|
)
|
||||||
|
value = (value + 1) / 2 * 255
|
||||||
|
return value
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
self.game.screen.blit(
|
||||||
|
pygame.transform.scale(self.surf, (self.screen_width, self.screen_height)),
|
||||||
|
(0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
def point_check_collision(self, x, y, thresh=None):
|
||||||
|
return self.get_noise(x / self.resolution, y / self.resolution) < (
|
||||||
|
thresh or self.thresh
|
||||||
|
)
|
||||||
|
|
||||||
|
def pre_draw(self):
|
||||||
|
self.refresh_surf()
|
||||||
|
for x in range(int(self.screen_width)):
|
||||||
|
for y in range(int(self.screen_height)):
|
||||||
|
if not self.point_check_collision(x, y):
|
||||||
|
pygame.draw.rect(
|
||||||
|
self.surf,
|
||||||
|
self.white,
|
||||||
|
(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
pygame.image.save(self.surf, "map.png")
|
||||||
|
# av1 = (
|
||||||
|
# Image.open("rock.jpg")
|
||||||
|
# .convert("RGB")
|
||||||
|
# .resize((self.screen_width, self.screen_height))
|
||||||
|
# )
|
||||||
|
# av2 = (
|
||||||
|
# Image.open("dirt.jpg")
|
||||||
|
# .convert("RGB")
|
||||||
|
# .resize((self.screen_width, self.screen_height))
|
||||||
|
# )
|
||||||
|
# mask = (
|
||||||
|
# Image.open("map.png")
|
||||||
|
# .convert("L")
|
||||||
|
# .resize((self.screen_width, self.screen_height))
|
||||||
|
# .filter(ImageFilter.GaussianBlur(3))
|
||||||
|
# )
|
||||||
|
# Image.composite(av2, av1, mask).save("result.png")
|
||||||
|
# result = pygame.image.load("result.png")
|
||||||
|
# self.surf.blit(result, (0, 0))
|
||||||
|
|
@ -1,29 +1,26 @@
|
||||||
from pydantic import BaseModel
|
from typing import Callable, Tuple
|
||||||
from typing import Tuple, Callable
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
import pygame
|
|
||||||
|
|
||||||
screen_sizes = [
|
screen_sizes = [
|
||||||
(480, 360), # 360p
|
(480, 360), # 360p
|
||||||
(640, 480), # VGA
|
(640, 480), # VGA
|
||||||
(800, 600), # SVGA
|
(800, 600), # SVGA
|
||||||
(1024, 768), # XGA
|
(1024, 768), # XGA
|
||||||
(1280, 720), # HD 720p
|
(1280, 720), # HD 720p
|
||||||
(1366, 768), # HD 1366x768
|
(1366, 768), # HD 1366x768
|
||||||
(1600, 900), # HD+ 1600x900
|
(1600, 900), # HD+ 1600x900
|
||||||
(1920, 1080), # Full HD 1080p
|
(1920, 1080), # Full HD 1080p
|
||||||
(2560, 1440), # 2K / QHD 1440p
|
(2560, 1440), # 2K / QHD 1440p
|
||||||
(3840, 2160) # 4K / UHD 2160p
|
(3840, 2160), # 4K / UHD 2160p
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MenuItem(BaseModel):
|
class MenuItem(BaseModel):
|
||||||
display_text: str
|
display_text: str
|
||||||
on_click: Callable = None
|
on_click: Callable = None
|
||||||
text_color: Tuple[str, str, str] = (0, 0, 0)
|
text_color: Tuple[str, str, str] = (0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Menu:
|
class Menu:
|
||||||
|
|
@ -32,24 +29,53 @@ class Menu:
|
||||||
|
|
||||||
self.game = game
|
self.game = game
|
||||||
self.hamburger = Hamburger(game)
|
self.hamburger = Hamburger(game)
|
||||||
self.menu_width = min(max(200, self.game.screen.get_width()
|
|
||||||
* 0.8), self.game.screen.get_width())
|
self.padding = 10
|
||||||
self.menu_height = min(max(200, self.game.screen.get_height()
|
self.font_size = 50
|
||||||
* 0.8), self.game.screen.get_height())
|
self.line_height = 55
|
||||||
|
|
||||||
|
self.menu_width = min(
|
||||||
|
max(200, self.game.screen.get_width() * 0.8), self.game.screen.get_width()
|
||||||
|
)
|
||||||
|
self.menu_height = min(
|
||||||
|
max(200, self.game.screen.get_height() * 0.8), self.game.screen.get_height()
|
||||||
|
)
|
||||||
self.x = (self.game.screen.get_width() - self.menu_width) / 2
|
self.x = (self.game.screen.get_width() - self.menu_width) / 2
|
||||||
self.y = (self.game.screen.get_height() - self.menu_height) / 2
|
self.y = (self.game.screen.get_height() - self.menu_height) / 2
|
||||||
self.color = (100, 100, 100)
|
self.color = (100, 100, 100)
|
||||||
self.is_menu_open = False
|
self.is_menu_open = False
|
||||||
|
|
||||||
self.surface = pygame.Surface((self.menu_width, self.menu_height))
|
self.surface = pygame.Surface((self.menu_width, self.menu_height))
|
||||||
self.font = pygame.font.SysFont("", 50)
|
self.font = pygame.font.SysFont("", self.font_size)
|
||||||
self.screen_size_index = False
|
|
||||||
self.padding = 10
|
|
||||||
|
|
||||||
self.items = [
|
self.screen_size_index = False
|
||||||
MenuItem(display_text='Menu'),
|
|
||||||
MenuItem(display_text='Screen Size'),
|
@property
|
||||||
MenuItem(display_text=f'{self.game.screen.get_width()}x{self.game.screen.get_height()}', color=(50, 0, 0))
|
def items(self) -> list[MenuItem]:
|
||||||
|
return [
|
||||||
|
MenuItem(
|
||||||
|
display_text="Menu",
|
||||||
|
on_click=lambda: print("clicked on me, the menu"),
|
||||||
|
),
|
||||||
|
MenuItem(
|
||||||
|
display_text="Screen Size",
|
||||||
|
on_click=self.next_screen_size,
|
||||||
|
),
|
||||||
|
MenuItem(
|
||||||
|
display_text=f"{self.game.screen.get_width()}x{self.game.screen.get_height()}",
|
||||||
|
color=(50, 0, 0),
|
||||||
|
on_click=self.next_screen_size,
|
||||||
|
),
|
||||||
|
MenuItem(
|
||||||
|
display_text=f"{self.game.player.hero.name}",
|
||||||
|
color=(50, 0, 0),
|
||||||
|
on_click=self.game.player.rename_hero,
|
||||||
|
),
|
||||||
|
MenuItem(
|
||||||
|
display_text="quit",
|
||||||
|
color=(50, 0, 0),
|
||||||
|
on_click=lambda: self.game.quit(),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
|
|
@ -60,39 +86,42 @@ class Menu:
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
text = self.font.render(item.display_text, True, item.text_color)
|
text = self.font.render(item.display_text, True, item.text_color)
|
||||||
self.surface.blit(text, pos)
|
self.surface.blit(text, pos)
|
||||||
pos = (pos[0], pos[1] + 50)
|
pos = (pos[0], pos[1] + self.line_height)
|
||||||
|
|
||||||
# put text in the menu surface
|
|
||||||
# text = self.font.render("Menu", True, (0, 0, 0))
|
|
||||||
# self.surface.blit(text, (0, 0))
|
|
||||||
# text = self.font.render("Screen Size", True, (0, 0, 0))
|
|
||||||
# self.surface.blit(text, (0, 60))
|
|
||||||
# text = self.font.render(
|
|
||||||
# f'{self.game.screen.get_width()}x{self.game.screen.get_height()}', True, (25, 25, 25))
|
|
||||||
# self.surface.blit(text, (10, 120))
|
|
||||||
#
|
|
||||||
self.game.screen.blit(self.surface, (self.x, self.y))
|
self.game.screen.blit(self.surface, (self.x, self.y))
|
||||||
|
|
||||||
self.hamburger.render()
|
self.hamburger.render()
|
||||||
|
|
||||||
|
def next_screen_size(self):
|
||||||
|
if self.screen_size_index is False:
|
||||||
|
self.screen = pygame.display.set_mode(screen_sizes[0])
|
||||||
|
self.screen_size_index = 0
|
||||||
|
if self.screen_size_index == len(screen_sizes) - 1:
|
||||||
|
self.screen_size_index = 0
|
||||||
|
else:
|
||||||
|
self.screen_size_index += 1
|
||||||
|
self.screen = pygame.display.set_mode(screen_sizes[self.screen_size_index])
|
||||||
|
|
||||||
def get_mouse_pos(self):
|
def get_mouse_pos(self):
|
||||||
'get mouse position relative to self.surface'
|
"get mouse position relative to self.surface"
|
||||||
x, y = pygame.mouse.get_pos()
|
x, y = pygame.mouse.get_pos()
|
||||||
return x - self.x, y - self.y
|
return x - self.x, y - self.y
|
||||||
|
|
||||||
|
def handle_events(self, events):
|
||||||
|
self.hamburger.handle_events(self, events)
|
||||||
|
for event in events:
|
||||||
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
|
if event.button == 1: # Left mouse button
|
||||||
|
self.handle_click()
|
||||||
|
|
||||||
def handle_click(self):
|
def handle_click(self):
|
||||||
self.hamburger.handle_click(self)
|
|
||||||
pos = self.get_mouse_pos()
|
pos = self.get_mouse_pos()
|
||||||
print(pos)
|
pos_idx = int(pos[1] // self.line_height)
|
||||||
if pos[1] > 120 and pos[1] < 180 and pos[0] > 0 and pos[0] < self.menu_width:
|
if pos_idx > len(self.items):
|
||||||
if self.screen_size_index is False:
|
return
|
||||||
self.screen = pygame.display.set_mode(screen_sizes[0])
|
if pos_idx < 0:
|
||||||
self.screen_size_index = 0
|
return
|
||||||
if self.screen_size_index == len(screen_sizes) - 1:
|
self.items[pos_idx].on_click()
|
||||||
self.screen_size_index = 0
|
|
||||||
else:
|
|
||||||
self.screen_size_index += 1
|
|
||||||
self.screen = pygame.display.set_mode(screen_sizes[self.screen_size_index])
|
|
||||||
|
|
||||||
|
|
||||||
class Hamburger:
|
class Hamburger:
|
||||||
|
|
@ -106,21 +135,45 @@ class Hamburger:
|
||||||
self.x = self.game.screen.get_width() - self.hamburger_width - 20
|
self.x = self.game.screen.get_width() - self.hamburger_width - 20
|
||||||
self.y = 20
|
self.y = 20
|
||||||
self.color = (100, 100, 100)
|
self.color = (100, 100, 100)
|
||||||
self.rect = pygame.Rect(self.x, self.y, self.hamburger_width,
|
self.rect = pygame.Rect(
|
||||||
self.hamburger_height)
|
self.x, self.y, self.hamburger_width, self.hamburger_height
|
||||||
self.surface = pygame.Surface(
|
)
|
||||||
(self.hamburger_width, self.hamburger_height))
|
self.surface = pygame.Surface((self.hamburger_width, self.hamburger_height))
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
pygame.draw.rect(self.surface, self.color,
|
pygame.draw.rect(
|
||||||
(0, 0, self.hamburger_width, self.bar_height),)
|
self.surface,
|
||||||
pygame.draw.rect(self.surface, self.color,
|
self.color,
|
||||||
(0, self.bar_height + self.bar_spacing, self.hamburger_width, self.bar_height),)
|
(0, 0, self.hamburger_width, self.bar_height),
|
||||||
pygame.draw.rect(self.surface, self.color,
|
)
|
||||||
(0, 2 * (self.bar_height + self.bar_spacing), self.hamburger_width, self.bar_height),)
|
pygame.draw.rect(
|
||||||
|
self.surface,
|
||||||
|
self.color,
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
self.bar_height + self.bar_spacing,
|
||||||
|
self.hamburger_width,
|
||||||
|
self.bar_height,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
pygame.draw.rect(
|
||||||
|
self.surface,
|
||||||
|
self.color,
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
2 * (self.bar_height + self.bar_spacing),
|
||||||
|
self.hamburger_width,
|
||||||
|
self.bar_height,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
self.game.screen.blit(self.surface, (self.x, self.y))
|
self.game.screen.blit(self.surface, (self.x, self.y))
|
||||||
|
|
||||||
|
def handle_events(self, menu: Menu, events):
|
||||||
|
for event in events:
|
||||||
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
|
if event.button == 1: # Left mouse button
|
||||||
|
self.handle_click(menu)
|
||||||
|
|
||||||
def handle_click(self, menu):
|
def handle_click(self, menu):
|
||||||
pos = pygame.mouse.get_pos()
|
pos = pygame.mouse.get_pos()
|
||||||
|
|
|
||||||
219
learn_sql_model/game/player.py
Normal file
219
learn_sql_model/game/player.py
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
from learn_sql_model.console import console
|
||||||
|
from learn_sql_model.models.hero import HeroCreate, HeroDelete, HeroUpdate, Heros
|
||||||
|
from learn_sql_model.optional import _optional_import_
|
||||||
|
|
||||||
|
pygame = _optional_import_("pygame", group="game")
|
||||||
|
HeroFactory = _optional_import_(
|
||||||
|
"learn_sql_model.factories.hero",
|
||||||
|
"HeroFactory",
|
||||||
|
group="game",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Player:
|
||||||
|
def __init__(self, game):
|
||||||
|
hero = HeroFactory().build(size=25, x=100, y=100)
|
||||||
|
self.hero = HeroCreate(**hero.dict()).post()
|
||||||
|
|
||||||
|
self.game = game
|
||||||
|
self.others = Heros(heros=[])
|
||||||
|
self.width = 16
|
||||||
|
self.height = 16
|
||||||
|
self.white = (255, 255, 255)
|
||||||
|
self.x = self.game.screen.get_width() / 2
|
||||||
|
self.y = self.game.screen.get_height() / 2
|
||||||
|
self.speed = 5
|
||||||
|
self.max_speed = 5
|
||||||
|
self.image = pygame.image.load("player.png").convert_alpha()
|
||||||
|
self.x_last = self.x
|
||||||
|
self.y_last = self.y
|
||||||
|
self.hitbox_surface = pygame.Surface((self.width, self.height))
|
||||||
|
self.hitbox_surface.fill(self.white)
|
||||||
|
pygame.draw.rect(
|
||||||
|
self.hitbox_surface, (255, 0, 0), (0, 0, self.width, self.height), 1
|
||||||
|
)
|
||||||
|
self.hitbox_surface.set_alpha(0)
|
||||||
|
self.moving_up = False
|
||||||
|
self.moving_down = False
|
||||||
|
self.moving_left = False
|
||||||
|
self.moving_right = False
|
||||||
|
|
||||||
|
def rename_hero(self):
|
||||||
|
old_hero = self.hero
|
||||||
|
hero = HeroFactory().build(
|
||||||
|
size=self.hero.size, x=self.hero.x, y=self.hero.y, id=old_hero.id
|
||||||
|
)
|
||||||
|
self.hero = HeroCreate(**hero.dict()).post()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
try:
|
||||||
|
HeroDelete(id=self.hero.id).delete()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_events(self):
|
||||||
|
# Update the self
|
||||||
|
for event in self.game.events:
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
self.running = False
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == pygame.K_ESCAPE:
|
||||||
|
self.running = False
|
||||||
|
if event.key == pygame.K_LEFT:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_left = True
|
||||||
|
if event.key == pygame.K_RIGHT:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_right = True
|
||||||
|
if event.key == pygame.K_UP:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_up = True
|
||||||
|
if event.key == pygame.K_DOWN:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_down = True
|
||||||
|
# wasd
|
||||||
|
if event.key == pygame.K_w:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_up = True
|
||||||
|
if event.key == pygame.K_s:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_down = True
|
||||||
|
if event.key == pygame.K_a:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_left = True
|
||||||
|
if event.key == pygame.K_d:
|
||||||
|
self.speed = self.max_speed
|
||||||
|
self.moving_right = True
|
||||||
|
|
||||||
|
if event.type == pygame.KEYUP:
|
||||||
|
if event.key == pygame.K_LEFT:
|
||||||
|
self.moving_left = False
|
||||||
|
if event.key == pygame.K_RIGHT:
|
||||||
|
self.moving_right = False
|
||||||
|
if event.key == pygame.K_UP:
|
||||||
|
self.moving_up = False
|
||||||
|
if event.key == pygame.K_DOWN:
|
||||||
|
self.moving_down = False
|
||||||
|
# wasd
|
||||||
|
if event.key == pygame.K_w:
|
||||||
|
self.moving_up = False
|
||||||
|
if event.key == pygame.K_s:
|
||||||
|
self.moving_down = False
|
||||||
|
if event.key == pygame.K_a:
|
||||||
|
self.moving_left = False
|
||||||
|
if event.key == pygame.K_d:
|
||||||
|
self.moving_right = False
|
||||||
|
|
||||||
|
for joystick in self.joysticks.values():
|
||||||
|
if abs(joystick.get_axis(0)) > 0.2:
|
||||||
|
self.x += joystick.get_axis(0) * 10 * self.speed * self.elapsed
|
||||||
|
if abs(joystick.get_axis(1)) > 0.2:
|
||||||
|
self.y += joystick.get_axis(1) * 10 * self.speed * self.elapsed
|
||||||
|
|
||||||
|
if abs(joystick.get_axis(3)) > 0.2 and abs(joystick.get_axis(4)) > 0.2:
|
||||||
|
pygame.mouse.set_pos(
|
||||||
|
(
|
||||||
|
pygame.mouse.get_pos()[0] + joystick.get_axis(3) * 32,
|
||||||
|
pygame.mouse.get_pos()[1] + joystick.get_axis(4) * 32,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif abs(joystick.get_axis(3)) > 0.2:
|
||||||
|
pygame.mouse.set_pos(
|
||||||
|
(
|
||||||
|
pygame.mouse.get_pos()[0] + joystick.get_axis(3) * 32,
|
||||||
|
pygame.mouse.get_pos()[1],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif abs(joystick.get_axis(4)) > 0.2:
|
||||||
|
pygame.mouse.set_pos(
|
||||||
|
(
|
||||||
|
pygame.mouse.get_pos()[0],
|
||||||
|
pygame.mouse.get_pos()[1] + joystick.get_axis(4) * 32,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self.moving_left:
|
||||||
|
self.hero.x -= self.speed
|
||||||
|
if self.moving_right:
|
||||||
|
self.hero.x += self.speed
|
||||||
|
if self.moving_up:
|
||||||
|
self.hero.y -= self.speed
|
||||||
|
if self.moving_down:
|
||||||
|
self.hero.y += self.speed
|
||||||
|
# Check for self collisions with the walls and the black tiles on the map
|
||||||
|
if self.hero.x < 0:
|
||||||
|
self.hero.x = 0
|
||||||
|
if self.hero.x > self.game.screen.get_width() - self.width:
|
||||||
|
self.hero.x = self.game.screen.get_width() - self.width
|
||||||
|
if self.hero.y < 0:
|
||||||
|
self.hero.y = 0
|
||||||
|
if self.hero.y > self.game.screen.get_height() - self.height:
|
||||||
|
self.hero.y = self.game.screen.get_height() - self.height
|
||||||
|
|
||||||
|
self.pos = pygame.math.Vector2(self.hero.x, self.hero.y)
|
||||||
|
|
||||||
|
if self.game.map.point_check_collision(self.pos.x, self.pos.y):
|
||||||
|
|
||||||
|
start_pos = pygame.math.Vector2(self.x_last, self.y_last)
|
||||||
|
end_pos = pygame.math.Vector2(self.hero.x, self.hero.y)
|
||||||
|
movement_vector = end_pos - start_pos
|
||||||
|
try:
|
||||||
|
movement_direction = movement_vector.normalize()
|
||||||
|
except:
|
||||||
|
end_pos = pygame.math.Vector2(self.hero.x + 128, self.hero.y + 128)
|
||||||
|
movement_vector = end_pos - start_pos
|
||||||
|
movement_direction = movement_vector.normalize()
|
||||||
|
movement_speed = 0.05
|
||||||
|
|
||||||
|
self.hero.x = self.x_last
|
||||||
|
self.hero.y = self.y_last
|
||||||
|
|
||||||
|
self.pos = pygame.math.Vector2(start_pos)
|
||||||
|
|
||||||
|
while self.game.map.point_check_collision(self.pos.x, self.pos.y):
|
||||||
|
self.pos += movement_speed * movement_direction
|
||||||
|
self.hero.x = self.pos.x
|
||||||
|
self.hero.y = self.pos.y
|
||||||
|
|
||||||
|
self.pos -= movement_speed * movement_direction
|
||||||
|
self.hero.x = self.pos.x
|
||||||
|
self.hero.y = self.pos.y
|
||||||
|
|
||||||
|
self.x_last = self.hero.x
|
||||||
|
self.y_last = self.hero.y
|
||||||
|
|
||||||
|
if self.game.ticks % 5 == 0 or self.game.ticks == 0:
|
||||||
|
console.print("updating")
|
||||||
|
update = HeroUpdate(**self.hero.dict(exclude_unset=True))
|
||||||
|
console.print(update)
|
||||||
|
self.game.ws.send(update.json())
|
||||||
|
console.print("sent")
|
||||||
|
|
||||||
|
raw_heros = self.game.ws.recv()
|
||||||
|
console.print(raw_heros)
|
||||||
|
self.others = Heros.parse_raw(raw_heros)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
self.move()
|
||||||
|
self.game.screen.blit(
|
||||||
|
pygame.transform.scale(self.image, (16, 16)),
|
||||||
|
(self.x - 8 - self.game.map.offset.x, self.y - 8 - self.game.map.offset.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
for other in self.others.heros:
|
||||||
|
if other.id != self.hero.id:
|
||||||
|
pygame.draw.circle(
|
||||||
|
self.game.screen, (255, 0, 0), (other.x, other.y), other.size
|
||||||
|
)
|
||||||
|
self.game.screen.blit(
|
||||||
|
self.game.font.render(other.name, False, (255, 255, 255), 1),
|
||||||
|
(other.x, other.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
pygame.draw.circle(
|
||||||
|
self.game.screen, (0, 0, 255), (self.hero.x, self.hero.y), self.hero.size
|
||||||
|
)
|
||||||
|
self.game.screen.blit(
|
||||||
|
self.game.font.render(self.hero.name, False, (255, 255, 255), 1),
|
||||||
|
(self.hero.x, self.hero.y),
|
||||||
|
)
|
||||||
63
learn_sql_model/optional.py
Normal file
63
learn_sql_model/optional.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
|
||||||
|
def _optional_import_(
|
||||||
|
module: str,
|
||||||
|
name: str = None,
|
||||||
|
group: str = None,
|
||||||
|
package="learn_sql_model",
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
lazily throws import errors only then the optional import is used, and
|
||||||
|
includes a group install command for the user to install all dependencies
|
||||||
|
for the requested feature.
|
||||||
|
"""
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(module)
|
||||||
|
return module if name is None else getattr(module, name)
|
||||||
|
except ImportError as e:
|
||||||
|
msg = textwrap.dedent(
|
||||||
|
f"""
|
||||||
|
"pip install '{package}[{group}]'" package to make use of this feature
|
||||||
|
Alternatively "pip install '{package}[all]'" package to install all optional dependencies
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
import_error = e
|
||||||
|
|
||||||
|
class _failed_import:
|
||||||
|
"""
|
||||||
|
Lazily throw an import error. Errors should be thrown whether the
|
||||||
|
user tries to call the module, get an attubute from the module, or
|
||||||
|
getitem from the module.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _failed_import(self, *args):
|
||||||
|
raise ImportError(msg) from import_error
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
"""
|
||||||
|
Throw error if the user tries to call the module i.e
|
||||||
|
_optional_import_('dummy')()
|
||||||
|
"""
|
||||||
|
self._failed_import(*args)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
"""
|
||||||
|
Throw error if the user tries to get an attribute from the
|
||||||
|
module i.e _optional_import_('dummy').dummy.
|
||||||
|
"""
|
||||||
|
if name == "_failed_import":
|
||||||
|
return object.__getattribute__(self, name)
|
||||||
|
self._failed_import()
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
"""
|
||||||
|
Throw error if the user tries to get an item from the module
|
||||||
|
i.e _optional_import_('dummy')['dummy']
|
||||||
|
"""
|
||||||
|
self._failed_import()
|
||||||
|
|
||||||
|
return _failed_import()
|
||||||
|
|
@ -24,36 +24,51 @@ classifiers = [
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"python-socketio[client]",
|
"python-socketio[client]",
|
||||||
"fastapi-socketio",
|
|
||||||
"psycopg2-binary",
|
|
||||||
'pygame',
|
|
||||||
'black',
|
|
||||||
'alembic',
|
|
||||||
'pygame',
|
|
||||||
'pyinstaller',
|
|
||||||
"pyflyby",
|
|
||||||
"anyconfig",
|
"anyconfig",
|
||||||
"copier",
|
"copier",
|
||||||
"engorgio",
|
"engorgio",
|
||||||
"fastapi",
|
"fastapi",
|
||||||
"httpx",
|
"httpx",
|
||||||
"passlib[bcrypt]",
|
"pydantic[dotenv]",
|
||||||
"polyfactory",
|
"pyflyby",
|
||||||
"psycopg2",
|
"pyinstaller",
|
||||||
"python-jose[cryptography]",
|
|
||||||
"python-multipart",
|
|
||||||
"rich",
|
"rich",
|
||||||
"sqlmodel",
|
"sqlmodel",
|
||||||
"textual",
|
"textual",
|
||||||
"toml",
|
"toml",
|
||||||
"trogon",
|
"trogon",
|
||||||
"typer",
|
"typer",
|
||||||
"uvicorn[standard]",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
game = [
|
||||||
|
"noise",
|
||||||
|
"pygame",
|
||||||
|
"polyfactory",
|
||||||
|
"faker",
|
||||||
|
]
|
||||||
|
api = [
|
||||||
|
"fastapi-socketio",
|
||||||
|
"passlib[bcrypt]",
|
||||||
|
"psycopg2",
|
||||||
|
"psycopg2-binary",
|
||||||
|
"python-jose[cryptography]",
|
||||||
|
"python-multipart",
|
||||||
|
"uvicorn[standard]",
|
||||||
|
]
|
||||||
|
manage = [
|
||||||
|
"alembic",
|
||||||
|
"polyfactory",
|
||||||
|
"faker",
|
||||||
|
]
|
||||||
|
all = [
|
||||||
|
"learn_sql_model[game, api, manage]",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Documentation = "https://github.com/waylonwalker/learn-sql-model#readme"
|
Documentation = "https://github.com/waylonwalker/learn-sql-model#readme"
|
||||||
Issues = "https://github.com/waylonwalker/learn-sql-model/issues"
|
Issues = "https://github.com/waylonwalker/learn-sql-model/issues"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue