make a game
This commit is contained in:
parent
53d878c75a
commit
dab0697f45
4 changed files with 227 additions and 11 deletions
|
|
@ -81,7 +81,8 @@ def get_config(overrides: dict = {}) -> Config:
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def get_session(config: Config = None) -> "Session":
|
def get_session() -> "Session":
|
||||||
|
config = get_config()
|
||||||
with Session(config.database.engine) as session:
|
with Session(config.database.engine) as session:
|
||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|
|
||||||
165
learn_sql_model/game/game.py
Normal file
165
learn_sql_model/game/game.py
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
# using pygame make a game using Hero
|
||||||
|
# it should be gamepad and mouse compatible
|
||||||
|
# it should have a server that keeps track of the game logic
|
||||||
|
# it should have a renderer that renders the game
|
||||||
|
# it should have a client that sends commands to the server
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
from rich.console import Console
|
||||||
|
import typer
|
||||||
|
from typer import Typer
|
||||||
|
|
||||||
|
from learn_sql_model.models.hero import (
|
||||||
|
Hero,
|
||||||
|
HeroCreate,
|
||||||
|
HeroDelete,
|
||||||
|
HeroRead,
|
||||||
|
HeroUpdate,
|
||||||
|
)
|
||||||
|
|
||||||
|
speed = 10
|
||||||
|
|
||||||
|
pygame.font.init() # you have to call this at the start,
|
||||||
|
# if you want to use this module.
|
||||||
|
my_font = pygame.font.SysFont("Comic Sans MS", 30)
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
def __init__(self, name, secret_name):
|
||||||
|
self.hero = Hero(name=name, secret_name=secret_name, x=400, y=300, size=50)
|
||||||
|
self.hero = HeroCreate(**self.hero.dict()).post()
|
||||||
|
|
||||||
|
self.screen = pygame.display.set_mode((800, 600))
|
||||||
|
self.clock = pygame.time.Clock()
|
||||||
|
self.running = True
|
||||||
|
self.screen.fill((0, 0, 0))
|
||||||
|
|
||||||
|
self.moving_up = False
|
||||||
|
self.moving_down = False
|
||||||
|
self.moving_left = False
|
||||||
|
self.moving_right = False
|
||||||
|
|
||||||
|
self.others = HeroRead.list()
|
||||||
|
|
||||||
|
atexit.register(self.quit)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.running:
|
||||||
|
self.handle_events()
|
||||||
|
self.update()
|
||||||
|
self.render()
|
||||||
|
self.clock.tick(60)
|
||||||
|
self.quit()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
HeroDelete(id=self.hero.id).delete()
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
HeroUpdate(
|
||||||
|
**{k: v for k, v in self.hero.dict().items() if v is not None}
|
||||||
|
).update()
|
||||||
|
|
||||||
|
self.others = HeroRead.list()
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
Console().print(self.hero)
|
||||||
|
self.screen.fill((0, 0, 0))
|
||||||
|
|
||||||
|
for other in self.others:
|
||||||
|
pygame.draw.circle(self.screen, (255, 0, 0), (other.x, other.y), other.size)
|
||||||
|
self.screen.blit(
|
||||||
|
my_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(
|
||||||
|
my_font.render(self.hero.name, False, (255, 255, 255)),
|
||||||
|
(self.hero.x, self.hero.y),
|
||||||
|
)
|
||||||
|
|
||||||
|
# update the screen
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
def handle_events(self):
|
||||||
|
self.events = pygame.event.get()
|
||||||
|
for event in self.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.moving_left = True
|
||||||
|
if event.key == pygame.K_RIGHT:
|
||||||
|
self.moving_right = True
|
||||||
|
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
|
||||||
|
|
||||||
|
def check_events(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_collisions(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
app = Typer()
|
||||||
|
|
||||||
|
|
||||||
|
@app.command()
|
||||||
|
def run(
|
||||||
|
name: str = typer.Option(...),
|
||||||
|
secret_name: str = typer.Option(...),
|
||||||
|
):
|
||||||
|
client = Client(name, secret_name)
|
||||||
|
client.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app()
|
||||||
|
|
@ -12,6 +12,9 @@ from learn_sql_model.models.pet import Pet
|
||||||
class HeroBase(SQLModel, table=False):
|
class HeroBase(SQLModel, table=False):
|
||||||
name: str
|
name: str
|
||||||
secret_name: str
|
secret_name: str
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
size: int
|
||||||
age: Optional[int] = None
|
age: Optional[int] = None
|
||||||
shoe_size: Optional[int] = None
|
shoe_size: Optional[int] = None
|
||||||
|
|
||||||
|
|
@ -34,6 +37,8 @@ class HeroCreate(HeroBase):
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
raise RuntimeError(f"{r.status_code}:\n {r.text}")
|
raise RuntimeError(f"{r.status_code}:\n {r.text}")
|
||||||
|
|
||||||
|
return Hero.parse_obj(r.json())
|
||||||
|
|
||||||
|
|
||||||
class HeroRead(HeroBase):
|
class HeroRead(HeroBase):
|
||||||
id: int
|
id: int
|
||||||
|
|
@ -80,6 +85,8 @@ class HeroUpdate(SQLModel):
|
||||||
secret_name: Optional[str] = None
|
secret_name: Optional[str] = None
|
||||||
age: Optional[int] = None
|
age: Optional[int] = None
|
||||||
shoe_size: Optional[int] = None
|
shoe_size: Optional[int] = None
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
|
||||||
pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
|
pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
|
||||||
pet: Optional[Pet] = Relationship(back_populates="hero")
|
pet: Optional[Pet] = Relationship(back_populates="hero")
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ from learn_sql_model.api.app import app
|
||||||
from learn_sql_model.cli.hero import hero_app
|
from learn_sql_model.cli.hero import hero_app
|
||||||
from learn_sql_model.config import get_config, get_session
|
from learn_sql_model.config import get_config, get_session
|
||||||
from learn_sql_model.factories.hero import HeroFactory
|
from learn_sql_model.factories.hero import HeroFactory
|
||||||
from learn_sql_model.models.hero import Hero
|
from learn_sql_model.models.hero import Hero, HeroCreate, HeroRead
|
||||||
|
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
@ -76,15 +76,6 @@ def test_api_read_hero(session: Session, client: TestClient):
|
||||||
session.add(hero_1)
|
session.add(hero_1)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
response = client.get(f"/hero/999")
|
|
||||||
assert response.status_code == 404
|
|
||||||
|
|
||||||
|
|
||||||
def test_api_read_hero_404(session: Session, client: TestClient):
|
|
||||||
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
|
|
||||||
session.add(hero_1)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
response = client.get(f"/hero/{hero_1.id}")
|
response = client.get(f"/hero/{hero_1.id}")
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
|
@ -95,6 +86,15 @@ def test_api_read_hero_404(session: Session, client: TestClient):
|
||||||
assert data["id"] == hero_1.id
|
assert data["id"] == hero_1.id
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_read_hero_404(session: Session, client: TestClient):
|
||||||
|
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
|
||||||
|
session.add(hero_1)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
response = client.get(f"/hero/999")
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
def test_api_update_hero(session: Session, client: TestClient):
|
def test_api_update_hero(session: Session, client: TestClient):
|
||||||
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
|
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
|
||||||
session.add(hero_1)
|
session.add(hero_1)
|
||||||
|
|
@ -233,3 +233,46 @@ def test_cli_list(mocker):
|
||||||
assert f"secret_name='{hero_1.secret_name}'" in result.stdout
|
assert f"secret_name='{hero_1.secret_name}'" in result.stdout
|
||||||
assert f"name='{hero_2.name}'" in result.stdout
|
assert f"name='{hero_2.name}'" in result.stdout
|
||||||
assert f"secret_name='{hero_2.secret_name}'" in result.stdout
|
assert f"secret_name='{hero_2.secret_name}'" in result.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_model_post(mocker):
|
||||||
|
patch_httpx_post = mocker.patch(
|
||||||
|
"httpx.post", return_value=mocker.Mock(status_code=200)
|
||||||
|
)
|
||||||
|
hero = HeroFactory().build(name="Steelman", age=25)
|
||||||
|
hero_create = HeroCreate(**hero.dict())
|
||||||
|
hero_create.post()
|
||||||
|
assert patch_httpx_post.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_model_post_500(mocker):
|
||||||
|
patch_httpx_post = mocker.patch(
|
||||||
|
"httpx.post", return_value=mocker.Mock(status_code=500)
|
||||||
|
)
|
||||||
|
hero = HeroFactory().build(name="Steelman", age=25)
|
||||||
|
hero_create = HeroCreate(**hero.dict())
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
hero_create.post()
|
||||||
|
assert patch_httpx_post.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_model_read_hero(mocker, session: Session, client: TestClient):
|
||||||
|
mocker.patch(
|
||||||
|
"learn_sql_model.config.Database.engine",
|
||||||
|
new_callable=lambda: create_engine(
|
||||||
|
"sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
SQLModel.metadata.create_all(config.database.engine)
|
||||||
|
|
||||||
|
hero = Hero(name="Deadpond", secret_name="Dive Wilson")
|
||||||
|
session = config.database.session
|
||||||
|
session.add(hero)
|
||||||
|
session.commit()
|
||||||
|
session.refresh(hero)
|
||||||
|
|
||||||
|
hero_read = HeroRead.get(id=hero.id)
|
||||||
|
assert hero_read.name == "Deadpond"
|
||||||
|
assert hero_read.secret_name == "Dive Wilson"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue