1
1
forked from MDL29/JacoBot

Compare commits

...

34 Commits
main ... main

Author SHA1 Message Date
6e3aeca232 Create a full screen option for the virtual pad #77
MDL29/JacoBot#77
2024-05-18 13:04:47 +00:00
59943dc54d Imrpove robot move
close MDL29/JacoBot#80
2024-05-13 16:51:40 +02:00
792fec50d6 🤖 Add & move robot on the grid 2024-05-12 19:11:36 +02:00
ec40c35fda 💄 Draw grid from a level
MDL29/JacoBot#40
MDL29/JacoBot#72
2024-05-12 19:11:33 +02:00
ce7df429b9 💄 Create a level from Cubetto wodden carpet
MDL29/JacoBot#40
MDL29/JacoBot#72
2024-05-12 19:11:05 +02:00
557dc54acc 🍱 Add wodden tile from Cubetto carpet
MDL29/JacoBot#40
2024-05-12 19:07:50 +02:00
bb0b2caa80 Add pdbr as developement dependancy
Improve debugger with rich library : https://pypi.org/project/pdbr/
2024-05-12 18:37:30 +02:00
0d530b9ad6 Fix the garbage zone for the virtual pad #34 2024-04-27 23:57:01 +02:00
041307a28c Add flake8 linter 2024-04-25 14:46:29 +00:00
21d334ddb9 Improve README 2024-04-25 16:07:38 +02:00
5008db05e1 Creates a garbage zone for the virtual pad #34
close MDL29/JacoBot#34
2024-04-25 15:47:50 +02:00
9513e5d5bc Disable DEBUG level log for Arcade
close #58
2024-04-25 11:33:39 +02:00
c1771906e4 Add Rich Library for logging in JacoVirt
close #56
2024-04-25 10:10:36 +02:00
e31eec876a Add command & subcommand for JacoVirt via argparse
* Command `jacovirt`
* Sub command `jacovirt pad`
* Sub command `jacovirt bot`

close #20
2024-04-24 23:53:11 +02:00
ed319f0a2e Move the token of the virtual pad #51
MDL29/JacoBot#51
2024-04-24 17:28:19 +02:00
mdl29
bd926a629d window displayed 2024-04-24 16:34:01 +02:00
d9b25436e9 Improve readme for JacoVirt Python project #12
MDL29/JacoBot#12
2024-04-24 16:19:34 +02:00
b5000a668d Create a generator of token for the virtual pad #31
MDL29/JacoBot#31
2024-04-24 14:43:13 +02:00
8a60d943fd Create token sprite
MDL29/JacoBot#29
2024-04-24 11:32:04 +02:00
0708cfb319 Create instructions with Pydantic
MDL29/JacoBot#17
2024-04-24 11:08:04 +02:00
df30c40deb Add logger for the virtual pad #41
MDL29/JacoBot#29
2024-04-24 10:32:22 +02:00
7e016819dc Add .gitignore 2024-04-23 22:35:08 +02:00
mdl29
3db0ceaab3 Organisation of JacoVirt Bot 2024-04-23 13:32:47 +00:00
437f336e5a Create the main window for the virtual pad MDL29/JacoBot#29 2024-04-23 15:06:51 +02:00
mdl29
dab02d2aeb Receive instructions from Redis
MDL29/JacoBot#19
2024-04-23 14:26:27 +02:00
mdl29
6c4c40ed75 Improve JacoVirt Bot with dark & light theme 2024-04-23 14:24:24 +02:00
7ba83ee570 Change path system 2024-04-23 11:46:11 +02:00
e52488249f Send instructions from JacoPad via Redis MDL29/JacoBot#18 2024-04-23 10:18:25 +02:00
fa390c8530 Fix path for JacoVirt #5 (close) 2024-04-13 22:56:20 +02:00
3547334a31 Ajout du code de base pour le pad MDL29/JacoBot#8 2024-04-13 22:32:13 +02:00
20589e6b1e Merge pull request 'Ajout du code source du Jacobot virtuel MDL29/Jacobot#7' (#9) from Bertrand-DUCON/JacoBot:main into main
Reviewed-on: MDL29/JacoBot#9
Reviewed-by: HS-157 <hs-157@noreply.localhost>
2024-04-13 15:31:59 +00:00
mdl29
8bebe024b3 Ajout du code source du Jacobot virtuel MDL29/Jacobot#7 2024-04-13 17:24:30 +02:00
0f799f056d Merge pull request 'Init python project #5' (#6) from Romain/JacoBot:main into main
Reviewed-on: MDL29/JacoBot#6
Reviewed-by: HS-157 <hs-157@noreply.localhost>
2024-04-13 14:59:07 +00:00
aed5811aa9 Init python project #5 2024-04-13 16:55:53 +02:00
47 changed files with 824 additions and 0 deletions

232
.gitignore vendored Normal file
View File

@ -0,0 +1,232 @@
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
### PlatformIO ###
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.pio
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

View File

@ -0,0 +1,25 @@
# JacoVirt
## How run the project ?
Clone the project :
~~~
git clone https://git.afpy.org/MDL29/JacoBot.git
~~~
Go in the folder of project then in the virtual pad folder
~~~
cd Jacobot/jacovirt
~~~
Downloads dependencies and create a virtual environement
~~~
poetry install
~~~
Run the virtual pad with :
~~~
poetry run jacovirt pad
~~~
Run the virtual bot with :
~~~
poetry run jacovirt bot
~~~

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

56
jacovirt/jacovirt/args.py Normal file
View File

@ -0,0 +1,56 @@
import argparse
import logging
import jacovirt.logger
log_level = {
"CRITICAL": logging.CRITICAL,
"ERROR": logging.ERROR,
"WARN": logging.WARNING,
"INFO": logging.INFO,
"DEBUG": logging.DEBUG,
}
def main():
# General parser
parser = argparse.ArgumentParser(description=__doc__)
# Subparser
sub = parser.add_subparsers(dest="sub")
parser.add_argument(
"-l",
"--log",
choices=log_level.keys(),
default="WARN",
help=("Set level log"),
dest="log",
)
# Parser for JacoVirt Pad
pad = sub.add_parser("pad", help="Run JacoVirt Pad")
# Parser for JacoVirt Bot
bot = sub.add_parser("bot", help="Run JacoVirt Bot")
args = parser.parse_args()
if args.sub is None:
parser.print_help()
exit(1)
logging.getLogger().setLevel(args.log)
match args.sub:
case "pad":
logging.info("Lunch JacoVirt Pad")
from jacovirt.pad import window
window.main()
case "bot":
logging.info("Lunch JacoVirt Bot")
from jacovirt.bot import window
window.main()
case _:
SystemExit

View File

@ -0,0 +1,51 @@
import arcade
import logging
class Bot(arcade.Sprite):
"""
Bot sprite
"""
def __init__(self, start, grid, scale=0.75):
self.sprite = ":resources:images/space_shooter/playerShip1_green.png"
self.grid = grid
self.pos = list(start)
super().__init__(self.sprite, scale, hit_box_algorithm="None")
self.set_pos()
self.angle = 270
def set_pos(self):
for tile in self.grid.tiles:
if tile.pos == tuple(self.pos):
self.position = tile.position
logging.debug(f"Move bot to {self.pos} - {self.position}")
break
def left(self):
self.angle += 90
if self.angle >= 360:
self.angle -=360
def right(self):
self.angle -= 90
if self.angle < 0:
self.angle += 360
def forward(self):
match self.angle:
case 0:
if self.pos[1] < self.grid.column - 1:
self.pos[1] += 1
case 90:
if self.pos[0] > 0:
self.pos[0] -= 1
case 180:
if self.pos[1] > 0:
self.pos[1] -= 1
case 270:
if self.pos[0] < self.grid.row - 1:
self.pos[0] += 1
self.set_pos()

View File

@ -0,0 +1,61 @@
import arcade
from importlib import resources
from jacovirt.bot.level import level
class Tile(arcade.Sprite):
"""
Tile sprite
"""
def __init__(self, x, y, start_x, start_y, size=100, spacing=10, scale=0.5):
self.pos = (x, y)
self.theme = level.get("theme")
self.sprite = level.get(self.pos)
with resources.path("jacovirt", 'Img') as img_folder :
self.image_file_name = f"{img_folder}/bot/{self.theme}/{self.sprite}.png"
self.size = size
self.spacing = spacing
super().__init__(self.image_file_name, scale, hit_box_algorithm="None")
self.position = (
start_x + x * (self.size + self.spacing) + self.size / 2,
start_y + y * (self.size + self.spacing) + self.size / 2
)
def debug(self, size=10):
arcade.draw_text(
self.pos,
self.left + self.spacing,
self.bottom + self.spacing,
arcade.color.BLACK,
size,
)
class Grid():
"""
Grid object
"""
def __init__(self, x, y, row=6, column=6, size=100, spacing=10):
self.row = row
self.column = column
self.pos = (x, y)
self.tiles = arcade.SpriteList()
for r in range(row):
for c in range(column):
self.tiles.append(
Tile(
x=r,
y=c,
start_x=x,
start_y=y,
size=size,
spacing=spacing
)
)

View File

@ -0,0 +1,39 @@
level = {
"theme": "wooden",
(0,0): "wave",
(0,1): "castle",
(0,2): "wave",
(0,3): "tile_1",
(0,4): "R",
(0,5): "start",
(1,0): "city",
(1,1): "tile_6",
(1,2): "tile_3",
(1,3): "tile_2",
(1,4): "tree",
(1,5): "tile_1",
(2,0): "wave",
(2,1): "wave",
(2,2): "mountain",
(2,3): "tile_4",
(2,4): "wave",
(2,5): "G",
(3,0): "B",
(3,1): "tile_2",
(3,2): "tile_4",
(3,3): "Y",
(3,4): "wave",
(3,5): "tile_2",
(4,0): "wave",
(4,1): "P",
(4,2): "tile_3",
(4,3): "tile_1",
(4,4): "tile_2",
(4,5): "tile_5",
(5,0): "wave",
(5,1): "tile_1",
(5,2): "wave",
(5,3): "boat",
(5,4): "tile_1",
(5,5): "tile_4",
}

View File

@ -0,0 +1,79 @@
import arcade
import jacovirt.logger
import logging
from jacovirt.bot.grid import Grid
from jacovirt.bot.bot import Bot
# Screen title and size
SCREEN_TITLE = "JacoVirt Bot"
SCREEN_WIDTH = int(1000)
SCREEN_HEIGHT = int(1000)
# Window color
BACKGROUND_COLOR = arcade.color.CATALINA_BLUE
COLUMN = 6
ROW = 6
SIZE_TILE = 100
SPACING = 10
X_START = (SCREEN_HEIGHT - (SIZE_TILE + SPACING) * ROW) / 2
Y_START = (SCREEN_WIDTH - (SIZE_TILE + SPACING) * COLUMN) / 2
class Window(arcade.Window):
"""Main application class"""
def __init__(self):
# Init parent class
super().__init__(int(SCREEN_WIDTH), int(SCREEN_HEIGHT), SCREEN_TITLE)
# Set background color
arcade.set_background_color(BACKGROUND_COLOR)
self.grid = None
self.bot = None
def setup(self):
"""Set up the pad"""
logging.info("Set up the bot.")
self.grid = Grid(X_START, Y_START, ROW, COLUMN, SIZE_TILE, SPACING)
self.bot = Bot((0,5), self.grid)
def on_draw(self):
"""Render the screen"""
# Clear the screen
self.clear()
# Draw tiles
self.grid.tiles.draw()
# If debug log level, draw info for tiles
if logging.root.level <= logging.DEBUG:
for tile in self.grid.tiles:
tile.debug()
self.bot.draw()
def on_key_press(self, symbol, modifiers):
"""Called when the user presses key"""
if symbol == arcade.key.R:
logging.info("Restart !")
self.setup()
if symbol == arcade.key.Q:
arcade.exit()
if symbol == arcade.key.LEFT:
self.bot.left()
if symbol == arcade.key.RIGHT:
self.bot.right()
if symbol == arcade.key.UP:
self.bot.forward()
def main():
"""Main method"""
window = Window()
window.setup()
arcade.run()

View File

@ -0,0 +1,9 @@
from datetime import datetime
from typing import Literal
from pydantic import BaseModel
class Instruction(BaseModel):
move: Literal["FORWARD", "LEFT", "RIGHT"]
timestamp: datetime
source: str

View File

@ -0,0 +1,8 @@
import logging
from rich.logging import RichHandler
# Set level INFO log for Arcade library
logging.getLogger("arcade").setLevel(logging.INFO)
# Logger config
logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s", datefmt="%m/%d/%Y %H:%M:%S", handlers=[RichHandler()])

View File

@ -0,0 +1,49 @@
import arcade
from importlib import resources
class Token(arcade.Sprite):
""" Token sprite """
def __init__(self, token_type, scale=1):
# Attributes for token type
self.token_type = token_type
with resources.path("jacovirt", 'Img') as img_folder :
self.image_file_name = f"{img_folder}/pad/token/{self.token_type}.png"
# Call the parent
super().__init__(self.image_file_name, scale, hit_box_algorithm="None")
class Token_generator(arcade.Sprite):
""" Token generator sprite """
def __init__(self, token_type, scale=1):
# Attributes for token type
self.type = token_type
self.image_file_name = ":resources:images/tiles/boxCrate_double.png"
self.tokens = arcade.SpriteList()
# Call the parent
super().__init__(self.image_file_name, scale, hit_box_algorithm="None")
def create_token(self, x, y):
# Create a token
token = Token(self.type)
token.position = x, y
self.tokens.append(token)
return token
def draw_tokens(self):
self.tokens.draw()
class Token_trash(arcade.SpriteSolidColor):
def __init__(self, height, width, color=arcade.color.AMERICAN_ROSE):
super().__init__(width, height, color)
def remove_token(self, held_token):
held_token.remove_from_sprite_lists()

View File

@ -0,0 +1,188 @@
import arcade
import jacovirt.logger
import logging
from jacovirt.pad.token import Token, Token_generator, Token_trash
# Screen title and size
SCREEN_TITLE = "Jaco Pad"
SCREEN_WIDTH = int(1000)
SCREEN_HEIGHT = int(1000)
# Window color
BACKGROUND_COLOR = (133, 100, 100)
class Window(arcade.Window):
"""Main application class"""
def __init__(self):
# Init parent class
super().__init__(int(SCREEN_WIDTH), int(SCREEN_HEIGHT), SCREEN_TITLE)
# Set background color
arcade.set_background_color(BACKGROUND_COLOR)
# List of token generator
self.tokens_generator = arcade.SpriteList()
# List of trash
self.tokens_trash = arcade.SpriteList()
# The held token
self.held_token = None
# List of tokens
self.tokens = arcade.SpriteList()
def setup(self):
"""Set up the pad"""
logging.debug("Set up the pad.")
# Create a token
token = Token("up", 1)
token.position = 500, 500
self.tokens.append(token)
# Create a token generator
token_generator = Token_generator("up", 1)
token_generator.position = 200, 500
self.tokens_generator.append(token_generator)
# Create a other token generator
token_generator = Token_generator("right", 1)
token_generator.position = 800, 500
self.tokens_generator.append(token_generator)
# Create a trash for token
trash = Token_trash(200, 200)
trash.position = 500, 800
self.tokens_trash.append(trash)
# Create a camera
self.camera = arcade.Camera()
def on_draw(self):
"""Render the screen"""
self.camera.use()
# Clear the screen
self.clear()
# Draw the token generator
self.tokens_generator.draw()
# Draw the trash
self.tokens_trash.draw()
# Draw the tokens
self.tokens.draw()
def on_key_press(self, symbol, modifiers):
"""Called when the user presses key"""
logging.debug(f"User press {symbol}, {modifiers}")
if symbol == arcade.key.R:
self.setup()
print("Restart !")
if symbol == arcade.key.Q:
arcade.exit()
if symbol == arcade.key.F:
# When the user hits f. Flip between full and not full screen.
if self.fullscreen:
# If in fullscreen, switch to windowed mode
self.set_fullscreen(False)
# Resize the camera to match the window size
width, height = self.get_size()
self.camera.resize(width, height)
# Reset camera position
self.camera.move((0, 0))
else:
# If not in fullscreen, switch to fullscreen mode
# Remember the previous window size
last_width, last_height = self.get_size()
# Switch to fullscreen
self.set_fullscreen(True)
# Adjust camera and window size for fullscreen
width, height = self.get_size()
self.camera.resize(width, height)
# Calculate the difference in center position between last window size and new fullscreen size
self.x_fullscreen_diff = (last_width - width) / 2
self.y_fullscreen_diff = (last_height - height) / 2
# Move camera to keep the same center point in the game
self.camera.move((self.x_fullscreen_diff, self.y_fullscreen_diff))
def on_mouse_press(self, x, y, button, key_modifiers):
"""Called when the user presses a mouse button"""
logging.debug(f"Mouse pressed at {x},{y}")
# If the game is in fullscreen mode, adjust mouse coordinates
if self.fullscreen:
x = x + self.x_fullscreen_diff
y = y + self.y_fullscreen_diff
logging.debug(f"Mouse pressed at {x}, {y} in the game window in full screen")
# Get list of tokens we've clicked on
tokens = arcade.get_sprites_at_point((x, y), self.tokens)
# Have we clicked on a token?
if len(tokens) > 0:
# Might be a stack of tokens, get the top one
primary_token = tokens[-1]
# All other cases, grab the token we are clicking on
self.held_token = primary_token
return
# Get the list of generator we've clicked on
generators = arcade.get_sprites_at_point((x, y), self.tokens_generator)
# Have we clicked on a generator ?
if len(generators) > 0:
generator = generators[-1]
logging.debug(f"Cliced on the generator of {generator.type}")
# Create a token and take it
self.held_token = generator.create_token(x, y)
self.tokens.append(self.held_token)
def on_mouse_release(self, x, y, button, modifiers):
"""Called when the user presses a mouse button"""
logging.debug(f"Mouse relase at {x},{y}")
if self.held_token is not None:
# Find the closest trash
trash, distance = arcade.get_closest_sprite(self.held_token, self.tokens_trash)
# See if we are in contact with the closest trash, if yes delete the held token
if arcade.check_for_collision(self.held_token, trash):
trash.remove_token(self.held_token)
# Remove the token from the hand
self.held_token = None
def on_mouse_motion(self, x: float, y: float, dx: float, dy: float):
"""Called when the user moves the mouse"""
# If we are holding token, move it with the mouse
if self.held_token != None:
self.held_token.center_x += dx
self.held_token.center_y += dy
def main():
"""Main method"""
window = Window()
window.setup()
arcade.run()

27
jacovirt/pyproject.toml Normal file
View File

@ -0,0 +1,27 @@
[tool.poetry]
name = "jacovirt"
version = "0.1.0"
description = ""
authors = ["LPH"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
arcade = "^2.6.17"
redis = "^5.0.3"
pydantic = "^2.7.1"
rich = "^13.7.1"
[tool.poetry.group.dev.dependencies]
flake8 = "^7.0.0"
pdbr = "^0.8.8"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
jacovirt = "jacovirt.args:main"
[[tool.poetry.include]]
path = "jacovirt/jacovirt/Img/*"

View File