diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/UTMIST-AI2-2025.iml b/.idea/UTMIST-AI2-2025.iml new file mode 100644 index 0000000..d7ea347 --- /dev/null +++ b/.idea/UTMIST-AI2-2025.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7d2f77b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,212 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b018bdd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8e70da0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..025d57b --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + { + "associatedIndex": 0 +} + + + + { + "keyToString": { + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.git.unshallow": "true", + "git-widget-placeholder": "member-A", + "last_opened_file_path": "C:/Users/moham/Documents/GitHub/UTMIST-AI2-2025", + "settings.editor.selected.configurable": "preferences.pluginManager" + } +} + + + + + + + + + + + 1753690758554 + + + + \ No newline at end of file diff --git a/UTMIST_AI2_Env_OFFICIAL.ipynb b/UTMIST_AI2_Env_OFFICIAL.ipynb index de59c76..a610652 100644 --- a/UTMIST_AI2_Env_OFFICIAL.ipynb +++ b/UTMIST_AI2_Env_OFFICIAL.ipynb @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -45,10 +45,93 @@ "id": "zYnCLbw8FS3x", "outputId": "48895970-31b6-40db-dcd6-f518738f309d" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading assets.zip...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?id=1F2MJQ5enUPVtyi3s410PUuv8LiWr8qCz\n", + "To: c:\\Users\\moham\\Documents\\GitHub\\UTMIST-AI2-2025\\assets.zip\n", + "100%|██████████| 5.01M/5.01M [00:01<00:00, 3.32MB/s]\n", + "100%|██████████| 5.01M/5.01M [00:01<00:00, 3.32MB/s]\n", + "'unzip' is not recognized as an internal or external command,\n", + "operable program or batch file.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Extracting assets.zip...\n", + "Downloading attacks.zip...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?id=1LAOL8sYCUfsCk3TEA3vvyJCLSl0EdwYB\n", + "To: c:\\Users\\moham\\Documents\\GitHub\\UTMIST-AI2-2025\\attacks.zip\n", + "100%|██████████| 9.24k/9.24k [00:00<00:00, 9.86MB/s]\n", + "'unzip' is not recognized as an internal or external command,\n", + "operable program or batch file.\n" + ] + } + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading assets.zip...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?id=1F2MJQ5enUPVtyi3s410PUuv8LiWr8qCz\n", + "To: c:\\Users\\moham\\Documents\\GitHub\\UTMIST-AI2-2025\\assets.zip\n", + "100%|██████████| 5.01M/5.01M [00:01<00:00, 3.32MB/s]\n", + "'unzip' is not recognized as an internal or external command,\n", + "operable program or batch file.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Extracting assets.zip...\n", + "Downloading attacks.zip...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?id=1LAOL8sYCUfsCk3TEA3vvyJCLSl0EdwYB\n", + "To: c:\\Users\\moham\\Documents\\GitHub\\UTMIST-AI2-2025\\attacks.zip\n", + "100%|██████████| 9.24k/9.24k [00:00<00:00, 9.86MB/s]\n", + "'unzip' is not recognized as an internal or external command,\n", + "operable program or batch file.\n" + ] + } + ], "source": [ "# Delete assets.zip and /content/assets/\n", - "import shutil, gdown, os\n", + "import shutil, gdown, os, zipfile\n", + "import shutil, gdown, os, zipfile\n", "if os.path.exists('assets'):\n", " shutil.rmtree('assets')\n", "if os.path.exists('assets.zip'):\n", @@ -63,6 +146,14 @@ "\n", "# Unzip\n", "!unzip -q \"/content/$data_path\"\n", + "with zipfile.ZipFile(\"assets.zip\", 'r') as zip_ref:\n", + " os.makedirs(\"/content/$data_path\", exist_ok=True)\n", + " print(\"Extracting assets.zip...\")\n", + " zip_ref.extractall(\"./content/$data_path\")\n", + "with zipfile.ZipFile(\"assets.zip\", 'r') as zip_ref:\n", + " os.makedirs(\"/content/$data_path\", exist_ok=True)\n", + " print(\"Extracting assets.zip...\")\n", + " zip_ref.extractall(\"./content/$data_path\")\n", "\n", "# Delete attacks.zip and /content/attacks/\n", "if os.path.exists('attacks'):\n", @@ -75,10 +166,18 @@ "print(\"Downloading attacks.zip...\")\n", "url = \"https://drive.google.com/file/d/1LAOL8sYCUfsCk3TEA3vvyJCLSl0EdwYB/view?usp=sharing\"\n", "gdown.download(url, output=data_path, fuzzy=True)\n", - "\n", + "# Unzip\n", + "!unzip -q \"/content/$data_path\"\n", + "!unzip -q \"/content/$data_path\"\n", + "with zipfile.ZipFile(\"attacks.zip\", 'r') as zip_ref:\n", + " os.makedirs(\"/content/$data_path\", exist_ok=True)\n", + " #print(\"Extracting attacks.zip...\")\n", + " #print(\"Extracting attacks.zip...\")\n", + " zip_ref.extractall(\"./content/$data_path\")\n", "\n", "# Unzip\n", - "!unzip -q \"/content/$data_path\"" + "#!unzip -q \"/content/$data_path\"" + "#!unzip -q \"/content/$data_path\"" ] }, { @@ -92,7 +191,8 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -100,7 +200,20 @@ "id": "0d1cDyIvNRB7", "outputId": "e885b742-5adc-4b82-e758-4b92095b689b" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "19" + "19" + ] + }, + "execution_count": 2, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import gc\n", "gc.collect()" @@ -108,7 +221,8 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -145,7 +259,8 @@ "#!pip install torch==2.4.1 triton==3.0.0 gymnasium pygame==2.6.1 pymunk==6.2.1 scikit-image scikit-video sympy==1.5.1 stable_baselines3 sb3-contrib jupyter gdown opencv-python\n", "\n", "#!pip freeze > /content/requirements_v0.txt\n", - "!pip install -r requirements.txt" + "%pip install -r requirements.txt" + "%pip install -r requirements.txt" ] }, { @@ -214,7 +329,14 @@ "\n", "import gymnasium\n", "from gymnasium import spaces\n", - "\n", + "%pip install stable-baselines3 \n", + "%pip install pymunk \n", + "%pip install scikit-image\n", + "%pip install scikit-video\n", + "%pip install stable-baselines3 \n", + "%pip install pymunk \n", + "%pip install scikit-image\n", + "%pip install scikit-video\n", "from stable_baselines3.common.monitor import Monitor\n", "\n", "import pygame\n", @@ -1041,7 +1163,8 @@ "outputs": [], "source": [ "from pymunk.pygame_util import DrawOptions\n", - "\n", + "import os\n", + "import os\n", "\"\"\"Coord system\n", " +------ > x\n", " |\n", @@ -1216,7 +1339,10 @@ " 'Unarmed Groundpound': MoveType.GROUNDPOUND,\n", " }\n", "\n", - " for file in sorted(os.listdir('attacks')):\n", + " for file in sorted(os.listdir(\"path='content/$data_path/attacks'\")):\n", + " print('Loading attack file:', file)\n", + " for file in sorted(os.listdir(\"path='content/$data_path/attacks'\")):\n", + " print('Loading attack file:', file)\n", " name = file.split('.')[0]\n", " if name not in self.keys.keys(): continue\n", " with open(os.path.join('attacks', file)) as f:\n", @@ -3292,6 +3418,7 @@ " self.opponent.damage_done += damage_default\n", "\n", " def load_assets(self):\n", + " import gdown, os, zipfile\n", " if self.assets_loaded: return\n", " if os.path.isdir('assets'): return\n", "\n", @@ -3303,14 +3430,22 @@ "\n", "\n", " # check if directory\n", - " !unzip -q \"/content/$data_path\"\n", + " with zipfile.ZipFile(\"assets.zip\", 'r') as zip_ref:\n", + " os.makedirs(\"/content/$data_path\", exist_ok=True)\n", + " print(\"Extracting assets.zip...\")\n", + " zip_ref.extractall(\"./content/$data_path\")\n", " print(\"Downloaded!\")\n", "\n", " self.assets_loaded = True\n", "\n", " def is_on_floor(self) -> bool:\n", " old_cond = (abs(self.body.position.y - 1.540) < 0.03 and abs(self.body.position.x) < 5.77)\n", - " return self.shape.cache_bb().intersects(self.env.objects['ground'].shape.cache_bb()) or old_cond\n", + " doesCollide = self.shape.cache_bb().intersects(self.env.objects['ground'].shape.cache_bb()) or \\\n", + " self.shape.cache_bb().intersects(self.env.objects['stage'].shape.cache_bb())\n", + " return doesCollide or old_cond\n", + " doesCollide = self.shape.cache_bb().intersects(self.env.objects['ground'].shape.cache_bb()) or \\\n", + " self.shape.cache_bb().intersects(self.env.objects['stage'].shape.cache_bb())\n", + " return doesCollide or old_cond\n", " #return abs(self.body.position.y - 1.540) < 0.03 and abs(self.body.position.x) < 5.77\n", "\n", " def set_gravity_disabled(self, disabled:bool) -> None:\n", @@ -4724,6 +4859,8 @@ "outputs": [], "source": [ "from stable_baselines3 import PPO, A2C, SAC # Sample RL Algo imports\n", + "%pip install sb3-contrib\n", + "%pip install sb3-contrib\n", "from sb3_contrib import RecurrentPPO # Importing an LSTM" ] }, @@ -4813,6 +4950,20 @@ "Video('vis.mp4', embed=True, width=800)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": { @@ -5726,7 +5877,26 @@ "name": "python3" }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.1" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.1" } }, "nbformat": 4, diff --git a/content/$data_path/assets/attacks/unarmeddair.gif b/content/$data_path/assets/attacks/unarmeddair.gif new file mode 100644 index 0000000..503b236 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddair.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddair_end.gif b/content/$data_path/assets/attacks/unarmeddair_end.gif new file mode 100644 index 0000000..df8fb63 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddair_end.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddair_held.gif b/content/$data_path/assets/attacks/unarmeddair_held.gif new file mode 100644 index 0000000..125eb49 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddair_held.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddlight.gif b/content/$data_path/assets/attacks/unarmeddlight.gif new file mode 100644 index 0000000..3ef0833 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddlight.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddlight_start.gif b/content/$data_path/assets/attacks/unarmeddlight_start.gif new file mode 100644 index 0000000..c28621f Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddlight_start.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsig.gif b/content/$data_path/assets/attacks/unarmeddsig.gif new file mode 100644 index 0000000..8af5db5 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsig.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsig_end.gif b/content/$data_path/assets/attacks/unarmeddsig_end.gif new file mode 100644 index 0000000..a4cccd4 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsig_end.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsig_held.gif b/content/$data_path/assets/attacks/unarmeddsig_held.gif new file mode 100644 index 0000000..1b7e7a2 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsig_held.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsigpaper.gif b/content/$data_path/assets/attacks/unarmeddsigpaper.gif new file mode 100644 index 0000000..742bfe2 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsigpaper.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsigrock.gif b/content/$data_path/assets/attacks/unarmeddsigrock.gif new file mode 100644 index 0000000..2c83244 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsigrock.gif differ diff --git a/content/$data_path/assets/attacks/unarmeddsigscissors.gif b/content/$data_path/assets/attacks/unarmeddsigscissors.gif new file mode 100644 index 0000000..0479666 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmeddsigscissors.gif differ diff --git a/content/$data_path/assets/attacks/unarmedgp.gif b/content/$data_path/assets/attacks/unarmedgp.gif new file mode 100644 index 0000000..bbf3aa6 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedgp.gif differ diff --git a/content/$data_path/assets/attacks/unarmedgp_end.gif b/content/$data_path/assets/attacks/unarmedgp_end.gif new file mode 100644 index 0000000..4b692e1 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedgp_end.gif differ diff --git a/content/$data_path/assets/attacks/unarmedgp_held.gif b/content/$data_path/assets/attacks/unarmedgp_held.gif new file mode 100644 index 0000000..5df3fac Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedgp_held.gif differ diff --git a/content/$data_path/assets/attacks/unarmednlightfinisher.gif b/content/$data_path/assets/attacks/unarmednlightfinisher.gif new file mode 100644 index 0000000..b82d934 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednlightfinisher.gif differ diff --git a/content/$data_path/assets/attacks/unarmednlightnofinisher.gif b/content/$data_path/assets/attacks/unarmednlightnofinisher.gif new file mode 100644 index 0000000..81c07cb Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednlightnofinisher.gif differ diff --git a/content/$data_path/assets/attacks/unarmednsig_held.gif b/content/$data_path/assets/attacks/unarmednsig_held.gif new file mode 100644 index 0000000..b7de9ca Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednsig_held.gif differ diff --git a/content/$data_path/assets/attacks/unarmednsig_paper.gif b/content/$data_path/assets/attacks/unarmednsig_paper.gif new file mode 100644 index 0000000..298ea28 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednsig_paper.gif differ diff --git a/content/$data_path/assets/attacks/unarmednsig_rock.gif b/content/$data_path/assets/attacks/unarmednsig_rock.gif new file mode 100644 index 0000000..a9a00b9 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednsig_rock.gif differ diff --git a/content/$data_path/assets/attacks/unarmednsig_scissors.gif b/content/$data_path/assets/attacks/unarmednsig_scissors.gif new file mode 100644 index 0000000..005d44d Binary files /dev/null and b/content/$data_path/assets/attacks/unarmednsig_scissors.gif differ diff --git a/content/$data_path/assets/attacks/unarmedrecovery.gif b/content/$data_path/assets/attacks/unarmedrecovery.gif new file mode 100644 index 0000000..c6ad3a4 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedrecovery.gif differ diff --git a/content/$data_path/assets/attacks/unarmedsair.gif b/content/$data_path/assets/attacks/unarmedsair.gif new file mode 100644 index 0000000..73bacca Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedsair.gif differ diff --git a/content/$data_path/assets/attacks/unarmedslight.gif b/content/$data_path/assets/attacks/unarmedslight.gif new file mode 100644 index 0000000..c0d6f73 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedslight.gif differ diff --git a/content/$data_path/assets/attacks/unarmedssig.gif b/content/$data_path/assets/attacks/unarmedssig.gif new file mode 100644 index 0000000..75acebf Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedssig.gif differ diff --git a/content/$data_path/assets/attacks/unarmedssig_end.gif b/content/$data_path/assets/attacks/unarmedssig_end.gif new file mode 100644 index 0000000..ee5ce88 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedssig_end.gif differ diff --git a/content/$data_path/assets/attacks/unarmedssig_held.gif b/content/$data_path/assets/attacks/unarmedssig_held.gif new file mode 100644 index 0000000..c2bc923 Binary files /dev/null and b/content/$data_path/assets/attacks/unarmedssig_held.gif differ diff --git a/content/$data_path/assets/effects/gravitycancel.gif b/content/$data_path/assets/effects/gravitycancel.gif new file mode 100644 index 0000000..50ce6bd Binary files /dev/null and b/content/$data_path/assets/effects/gravitycancel.gif differ diff --git a/content/$data_path/assets/effects/ground_boom.gif b/content/$data_path/assets/effects/ground_boom.gif new file mode 100644 index 0000000..2828b5d Binary files /dev/null and b/content/$data_path/assets/effects/ground_boom.gif differ diff --git a/content/$data_path/assets/effects/plate.png b/content/$data_path/assets/effects/plate.png new file mode 100644 index 0000000..5549e54 Binary files /dev/null and b/content/$data_path/assets/effects/plate.png differ diff --git a/content/$data_path/assets/effects/plate_up.gif b/content/$data_path/assets/effects/plate_up.gif new file mode 100644 index 0000000..530f18c Binary files /dev/null and b/content/$data_path/assets/effects/plate_up.gif differ diff --git a/content/$data_path/assets/effects/side_swoosh.gif b/content/$data_path/assets/effects/side_swoosh.gif new file mode 100644 index 0000000..961fbc9 Binary files /dev/null and b/content/$data_path/assets/effects/side_swoosh.gif differ diff --git a/content/$data_path/assets/map/bg.jpg b/content/$data_path/assets/map/bg.jpg new file mode 100644 index 0000000..d3a1516 Binary files /dev/null and b/content/$data_path/assets/map/bg.jpg differ diff --git a/content/$data_path/assets/map/skylight.png b/content/$data_path/assets/map/skylight.png new file mode 100644 index 0000000..6440e61 Binary files /dev/null and b/content/$data_path/assets/map/skylight.png differ diff --git a/content/$data_path/assets/map/stage.png b/content/$data_path/assets/map/stage.png new file mode 100644 index 0000000..077922c Binary files /dev/null and b/content/$data_path/assets/map/stage.png differ diff --git a/content/$data_path/assets/player/movement/aldown.gif b/content/$data_path/assets/player/movement/aldown.gif new file mode 100644 index 0000000..638b8ae Binary files /dev/null and b/content/$data_path/assets/player/movement/aldown.gif differ diff --git a/content/$data_path/assets/player/movement/algroundpound.png b/content/$data_path/assets/player/movement/algroundpound.png new file mode 100644 index 0000000..f58fdf4 Binary files /dev/null and b/content/$data_path/assets/player/movement/algroundpound.png differ diff --git a/content/$data_path/assets/player/movement/alnsig.gif b/content/$data_path/assets/player/movement/alnsig.gif new file mode 100644 index 0000000..b3e67f1 Binary files /dev/null and b/content/$data_path/assets/player/movement/alnsig.gif differ diff --git a/content/$data_path/assets/player/movement/alpunch.gif b/content/$data_path/assets/player/movement/alpunch.gif new file mode 100644 index 0000000..57af7ea Binary files /dev/null and b/content/$data_path/assets/player/movement/alpunch.gif differ diff --git a/content/$data_path/assets/player/movement/alssig.gif b/content/$data_path/assets/player/movement/alssig.gif new file mode 100644 index 0000000..30dfbf8 Binary files /dev/null and b/content/$data_path/assets/player/movement/alssig.gif differ diff --git a/content/$data_path/assets/player/movement/alup.gif b/content/$data_path/assets/player/movement/alup.gif new file mode 100644 index 0000000..fb0ae3c Binary files /dev/null and b/content/$data_path/assets/player/movement/alup.gif differ diff --git a/content/$data_path/assets/player/movement/backdash.gif b/content/$data_path/assets/player/movement/backdash.gif new file mode 100644 index 0000000..c40b8bf Binary files /dev/null and b/content/$data_path/assets/player/movement/backdash.gif differ diff --git a/content/$data_path/assets/player/movement/dodge.gif b/content/$data_path/assets/player/movement/dodge.gif new file mode 100644 index 0000000..8f88fc9 Binary files /dev/null and b/content/$data_path/assets/player/movement/dodge.gif differ diff --git a/content/$data_path/assets/player/movement/hurt_down.png b/content/$data_path/assets/player/movement/hurt_down.png new file mode 100644 index 0000000..687e2f8 Binary files /dev/null and b/content/$data_path/assets/player/movement/hurt_down.png differ diff --git a/content/$data_path/assets/player/movement/hurt_up.png b/content/$data_path/assets/player/movement/hurt_up.png new file mode 100644 index 0000000..a95bbb5 Binary files /dev/null and b/content/$data_path/assets/player/movement/hurt_up.png differ diff --git a/content/$data_path/assets/player/movement/idle.gif b/content/$data_path/assets/player/movement/idle.gif new file mode 100644 index 0000000..5f06e09 Binary files /dev/null and b/content/$data_path/assets/player/movement/idle.gif differ diff --git a/content/$data_path/assets/player/movement/into_run.gif b/content/$data_path/assets/player/movement/into_run.gif new file mode 100644 index 0000000..f4fb60d Binary files /dev/null and b/content/$data_path/assets/player/movement/into_run.gif differ diff --git a/content/$data_path/assets/player/movement/jump.gif b/content/$data_path/assets/player/movement/jump.gif new file mode 100644 index 0000000..7fb00c6 Binary files /dev/null and b/content/$data_path/assets/player/movement/jump.gif differ diff --git a/content/$data_path/assets/player/movement/run.gif b/content/$data_path/assets/player/movement/run.gif new file mode 100644 index 0000000..fc4c5e3 Binary files /dev/null and b/content/$data_path/assets/player/movement/run.gif differ diff --git a/content/$data_path/assets/player/movement/turn.gif b/content/$data_path/assets/player/movement/turn.gif new file mode 100644 index 0000000..6aef634 Binary files /dev/null and b/content/$data_path/assets/player/movement/turn.gif differ diff --git a/content/$data_path/assets/player/movement/walk.gif b/content/$data_path/assets/player/movement/walk.gif new file mode 100644 index 0000000..8d6227d Binary files /dev/null and b/content/$data_path/assets/player/movement/walk.gif differ diff --git a/content/$data_path/assets/player/taunt/alhappy.gif b/content/$data_path/assets/player/taunt/alhappy.gif new file mode 100644 index 0000000..71aff81 Binary files /dev/null and b/content/$data_path/assets/player/taunt/alhappy.gif differ diff --git a/content/$data_path/assets/player/taunt/alkai.gif b/content/$data_path/assets/player/taunt/alkai.gif new file mode 100644 index 0000000..3fc420c Binary files /dev/null and b/content/$data_path/assets/player/taunt/alkai.gif differ diff --git a/content/$data_path/assets/player/taunt/altroll.gif b/content/$data_path/assets/player/taunt/altroll.gif new file mode 100644 index 0000000..012de4a Binary files /dev/null and b/content/$data_path/assets/player/taunt/altroll.gif differ diff --git a/content/$data_path/assets/ui/alicon_alive.png b/content/$data_path/assets/ui/alicon_alive.png new file mode 100644 index 0000000..62d0c0b Binary files /dev/null and b/content/$data_path/assets/ui/alicon_alive.png differ diff --git a/content/$data_path/assets/ui/alicon_dead.png b/content/$data_path/assets/ui/alicon_dead.png new file mode 100644 index 0000000..e8a6477 Binary files /dev/null and b/content/$data_path/assets/ui/alicon_dead.png differ diff --git a/content/$data_path/assets/ui/player1ui.png b/content/$data_path/assets/ui/player1ui.png new file mode 100644 index 0000000..1f04194 Binary files /dev/null and b/content/$data_path/assets/ui/player1ui.png differ diff --git a/content/$data_path/assets/ui/player2ui.png b/content/$data_path/assets/ui/player2ui.png new file mode 100644 index 0000000..a13e394 Binary files /dev/null and b/content/$data_path/assets/ui/player2ui.png differ diff --git a/content/$data_path/attacks/Hammer SLight.json b/content/$data_path/attacks/Hammer SLight.json new file mode 100644 index 0000000..582e127 --- /dev/null +++ b/content/$data_path/attacks/Hammer SLight.json @@ -0,0 +1,87 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 142, + "cooldown": 11, + "stunTime": 25, + "onMissNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 9, + "attackFrames": 3 + }, + { + "attackFrames": 4, + "baseDamage": 17, + "variableForce": 8.0, + "fixedForce": 56.0, + "hitboxes": [ + { + "xOffset": 190, + "yOffset": -50, + "width": 116, + "height": 96 + }, + { + "xOffset": 217, + "yOffset": -39, + "width": 78, + "height": 120 + } + ] + }, + { + "attackFrames": 5, + "baseDamage": 15, + "variableForce": 8.0, + "fixedForce": 30.0, + "hitboxes": [ + { + "xOffset": 203, + "yOffset": -50, + "width": 90, + "height": 96 + }, + { + "xOffset": 217, + "yOffset": -39, + "width": 78, + "height": 120 + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 143, + "recovery": 19, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0 + } + ] + }, + { + "powerID": 144, + "fixedRecovery": 1, + "recovery": 23, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0 + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed DAir.json b/content/$data_path/attacks/Unarmed DAir.json new file mode 100644 index 0000000..6b5ddeb --- /dev/null +++ b/content/$data_path/attacks/Unarmed DAir.json @@ -0,0 +1,109 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 13, + "cooldown": 9, + "stunTime": 19, + "disableCasterGravity": true, + "onMissNextPowerIndex": 1, + "onGroundNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 4, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 0.0, + "directionDeg": 0.0 + } + } + ] + }, + { + "startupFrames": 4, + "attackFrames": 16, + "baseDamage": 16, + "variableForce": 5.0, + "fixedForce": 65.0, + "hitboxes": [ + { + "xOffset": 21, + "yOffset": 33, + "width": 30, + "height": 30 + }, + { + "xOffset": 27, + "yOffset": 40, + "width": 34, + "height": 46 + }, + { + "xOffset": 48, + "yOffset": 69, + "width": 44, + "height": 48 + } + ], + "collisionCheckPoints": [ + { + "xOffset": 60, + "yOffset": 82 + } + ], + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 8.0, + "directionDeg": -45.0 + } + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 15, + "recovery": 19, + "stunTime": 19, + "casts": [ + { + "startupFrames": 4, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 2.0, + "directionDeg": -45.0 + } + } + ] + } + ] + }, + { + "powerID": 14, + "recovery": 23, + "stunTime": 19, + "casts": [ + { + "startupFrames": 3, + "attackFrames": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed DLight.json b/content/$data_path/attacks/Unarmed DLight.json new file mode 100644 index 0000000..966212e --- /dev/null +++ b/content/$data_path/attacks/Unarmed DLight.json @@ -0,0 +1,227 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 23, + "cooldown": 13, + "stunTime": 31, + "hitAngleDeg": 90.0, + "transitionOnInstantHit": true, + "onMissNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 5, + "attackFrames": 3, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -10, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 5, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.75, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -15, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + }, + { + "attackFrames": 9, + "baseDamage": 8, + "variableForce": 5.0, + "fixedForce": 45.0, + "hitboxes": [ + { + "xOffset": 62, + "yOffset": 69, + "width": 124, + "height": 56 + } + ], + "frameChanges": [ + { + "frame": 0, + "hurtboxPositionChange": { + "active": true, + "xOffset": -15, + "yOffset": 20, + "width": 290, + "height": 320 + } + }, + { + "frame": 5, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 3.0, + "activeY": false, + "magnitudeY": 0.0 + } + } + ] + }, + { + "attackFrames": 3, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 1.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -5, + "yOffset": 20, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 24, + "fixedRecovery": 1, + "casts": [ + { + "attackFrames": 2, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 3.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -15, + "yOffset": 20, + "width": 290, + "height": 320 + } + }, + { + "frame": 2, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 25, + "fixedRecovery": 1, + "recovery": 13, + "casts": [ + { + "attackFrames": 4, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 1.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 6, + "yOffset": 20, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.5, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 8, + "yOffset": 16, + "width": 290, + "height": 320 + } + }, + { + "frame": 6, + "hurtboxPositionChange": { + "active": true, + "xOffset": 5, + "yOffset": 9, + "width": 290, + "height": 320 + } + }, + { + "frame": 8, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed DSig.json b/content/$data_path/attacks/Unarmed DSig.json new file mode 100644 index 0000000..eaaa16d --- /dev/null +++ b/content/$data_path/attacks/Unarmed DSig.json @@ -0,0 +1,117 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "HEAVY", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 26, + "minCharge": 2, + "isCharge": true, + "enableFloorDrag": true, + "casts": [ + { + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + } + } + ] + }, + { + "startupFrames": 72, + "attackFrames": 1 + } + ], + "onMissNextPowerIndex": 1 + }, + { + "powerID": 27, + "recovery": 21, + "stunTime": 18, + "hitAngleDeg": 10.0, + "enableFloorDrag": true, + "casts": [ + { + "startupFrames": 7, + "attackFrames": 2, + "baseDamage": 16, + "variableForce": 60.0, + "fixedForce": 40.0, + "hitboxes": [ + { + "xOffset": 27, + "yOffset": 44, + "width": 144, + "height": 68 + } + ] + }, + { + "attackFrames": 5, + "baseDamage": 16, + "variableForce": 60.0, + "fixedForce": 40.0, + "hitboxes": [ + { + "xOffset": 43, + "yOffset": 41, + "width": 146, + "height": 100 + }, + { + "xOffset": 108, + "yOffset": 24, + "width": 126, + "height": 94 + } + ] + }, + { + "startupFrames": 9, + "attackFrames": 3, + "baseDamage": 16, + "variableForce": 60.0, + "fixedForce": 40.0, + "hitAngleDeg": 170.0, + "hitboxes": [ + { + "xOffset": -60, + "yOffset": 42, + "width": 114, + "height": 90 + }, + { + "xOffset": -26, + "yOffset": 54, + "width": 156, + "height": 80 + } + ] + }, + { + "attackFrames": 2, + "baseDamage": 16, + "variableForce": 60.0, + "fixedForce": 40.0, + "hitAngleDeg": 170.0, + "hitboxes": [ + { + "xOffset": -46, + "yOffset": 59, + "width": 166, + "height": 84 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed Groundpound.json b/content/$data_path/attacks/Unarmed Groundpound.json new file mode 100644 index 0000000..8609796 --- /dev/null +++ b/content/$data_path/attacks/Unarmed Groundpound.json @@ -0,0 +1,137 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "HEAVY", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 16, + "cooldown": 19, + "minCharge": 40, + "stunTime": 19, + "hitAngleDeg": -90.0, + "transitionOnInstantHit": true, + "onMissNextPowerIndex": 2, + "onGroundNextPowerIndex": 3, + "casts": [ + { + "startupFrames": 15, + "attackFrames": 2, + "baseDamage": 17, + "variableForce": 46.0, + "fixedForce": 48.0, + "frameChanges": [ + { + "frame": 15, + "casterVelocitySet": { + "active": true, + "magnitude": 0.0, + "directionDeg": 0.0 + } + } + ] + }, + { + "attackFrames": 39, + "baseDamage": 17, + "variableForce": 46.0, + "fixedForce": 48.0, + "hitboxes": [ + { + "xOffset": -8, + "yOffset": 85, + "width": 48, + "height": 100 + } + ], + "collisionCheckPoints": [ + { + "xOffset": -8, + "yOffset": 85 + } + ], + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 6.0, + "directionDeg": -90.0 + } + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 18, + "fixedRecovery": 5, + "recovery": 16, + "stunTime": 19, + "casts": [ + { + "startupFrames": 3, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 3, + "casterVelocitySet": { + "active": true, + "magnitude": 3.0, + "directionDeg": 90.0 + } + } + ] + } + ] + }, + { + "powerID": 17, + "fixedRecovery": 1, + "recovery": 7, + "stunTime": 19, + "casts": [ + { + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 0.0, + "directionDeg": 0.0 + } + } + ] + } + ] + }, + { + "powerID": 19, + "fixedRecovery": 1, + "recovery": 16, + "stunTime": 19, + "casts": [ + { + "attackFrames": 2, + "baseDamage": 17, + "variableForce": 46.0, + "fixedForce": 48.0, + "hitboxes": [ + { + "xOffset": 5, + "yOffset": 43, + "width": 98, + "height": 74 + } + ] + }, + { + "attackFrames": 7 + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed NAir.json b/content/$data_path/attacks/Unarmed NAir.json new file mode 100644 index 0000000..b74a685 --- /dev/null +++ b/content/$data_path/attacks/Unarmed NAir.json @@ -0,0 +1,288 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 6, + "cooldown": 7, + "stunTime": 17, + "disableHitGravity": true, + "targetAllHitAgents": true, + "onHitVelocitySetActive": true, + "onHitVelocitySetMagnitude": 1.0, + "onHitVelocitySetDirectionDeg": 90.0, + "casts": [ + { + "startupFrames": 7, + "attackFrames": 5, + "baseDamage": 3, + "variableForce": 27.0, + "fixedForce": 40.0, + "hitboxes": [ + { + "xOffset": 46, + "yOffset": 46, + "width": 30, + "height": 30 + }, + { + "xOffset": 59, + "yOffset": 10, + "width": 70, + "height": 84 + }, + { + "xOffset": 63, + "yOffset": -10, + "width": 68, + "height": 106 + } + ], + "frameChanges": [ + { + "frame": 7, + "casterVelocityDampXY": { + "activeX": true, + "dampX": 0.4, + "activeY": false, + "dampY": 0.0 + }, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 12, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onMissNextPowerIndex": 1 + }, + { + "powerID": 7, + "recovery": 4, + "stunTime": 21, + "disableHitGravity": true, + "targetAllHitAgents": true, + "onHitVelocitySetActive": true, + "onHitVelocitySetMagnitude": 1.0, + "onHitVelocitySetDirectionDeg": 90.0, + "onMissNextPowerIndex": 3, + "casts": [ + { + "startupFrames": 8, + "attackFrames": 5, + "baseDamage": 3, + "variableForce": 28.0, + "fixedForce": 40.0, + "hitboxes": [ + { + "xOffset": 44, + "yOffset": 32, + "width": 60, + "height": 50 + }, + { + "xOffset": 75, + "yOffset": 4, + "width": 94, + "height": 54 + } + ], + "frameChanges": [ + { + "frame": 0, + "casterVelocityDampXY": { + "activeX": true, + "dampX": 0.7, + "activeY": false, + "dampY": 0.0 + }, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 11, + "yOffset": 5, + "width": 290, + "height": 302 + } + }, + { + "frame": 2, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 7, + "width": 290, + "height": 292 + } + }, + { + "frame": 8, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -2, + "yOffset": 20, + "width": 312, + "height": 272 + } + }, + { + "frame": 15, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -5, + "yOffset": 11, + "width": 300, + "height": 298 + } + } + ] + } + ], + "onHitNextPowerIndex": 2 + }, + { + "powerID": 9, + "recovery": 22, + "stunTime": 19, + "hitAngleDeg": 45.0, + "casts": [ + { + "startupFrames": 8, + "attackFrames": 5, + "baseDamage": 5, + "variableForce": 37.0, + "fixedForce": 71.0, + "hitboxes": [ + { + "xOffset": 51, + "yOffset": 8, + "width": 134, + "height": 66 + } + ], + "frameChanges": [ + { + "frame": 0, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 12, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 29, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "dealtPositionTarget": { + "active": true, + "xOffset": 70, + "yOffset": -30 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 24, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 8, + "casterVelocitySet": { + "active": true, + "magnitude": 1.0, + "directionDeg": 180.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 12, + "yOffset": 9, + "width": 290, + "height": 302 + } + }, + { + "frame": 16, + "casterVelocitySet": { + "active": true, + "magnitude": 0.2, + "directionDeg": 180.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 8, + "fixedRecovery": 1, + "recovery": 15, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": 1.0 + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed NLight.json b/content/$data_path/attacks/Unarmed NLight.json new file mode 100644 index 0000000..4c9935e --- /dev/null +++ b/content/$data_path/attacks/Unarmed NLight.json @@ -0,0 +1,469 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 1, + "recovery": 3, + "cooldown": 16, + "stunTime": 17, + "hitAngleDeg": 90.0, + "disableHitGravity": true, + "onHitVelocitySetActive": true, + "casts": [ + { + "startupFrames": 5, + "attackFrames": 3, + "baseDamage": 3, + "fixedForce": 25.0, + "hitboxes": [ + { + "xOffset": 76, + "yOffset": 4, + "width": 90, + "height": 66 + } + ], + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -8, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 5, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "dealtPositionTarget": { + "active": true, + "xOffset": 80, + "yOffset": -40 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 33, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 8, + "dealtPositionTarget": { + "active": true, + "xOffset": 80, + "yOffset": -40 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onMissNextPowerIndex": 1 + }, + { + "powerID": 2, + "stunTime": 17, + "hitAngleDeg": -85.0, + "disableHitGravity": true, + "onHitVelocitySetActive": true, + "onMissNextPowerIndex": 4, + "casts": [ + { + "startupFrames": 6, + "attackFrames": 6, + "baseDamage": 3, + "fixedForce": 20.0, + "hitboxes": [ + { + "xOffset": 74, + "yOffset": -29, + "width": 74, + "height": 72 + }, + { + "xOffset": 51, + "yOffset": -8, + "width": 44, + "height": 74 + } + ], + "frameChanges": [ + { + "frame": 0, + "dealtPositionTarget": { + "active": true, + "xOffset": 80, + "yOffset": -40 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 17, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "hurtboxPositionChange": { + "active": true, + "xOffset": 25, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 6, + "dealtPositionTarget": { + "active": true, + "xOffset": 90, + "yOffset": -20 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 16, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 9, + "dealtPositionTarget": { + "active": true, + "xOffset": 90, + "yOffset": -20 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onHitNextPowerIndex": 2 + }, + { + "powerID": 3, + "recovery": 3, + "stunTime": 20, + "hitAngleDeg": 90.0, + "disableHitGravity": true, + "onHitVelocitySetActive": true, + "onMissNextPowerIndex": 3, + "casts": [ + { + "startupFrames": 6, + "attackFrames": 3, + "baseDamage": 3, + "fixedForce": 26.0, + "hitboxes": [ + { + "xOffset": 61, + "yOffset": -2, + "width": 88, + "height": 130 + } + ], + "frameChanges": [ + { + "frame": 0, + "dealtPositionTarget": { + "active": true, + "xOffset": 90, + "yOffset": -20 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 24, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "dealtPositionTarget": { + "active": true, + "xOffset": 90, + "yOffset": -20 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 27, + "yOffset": -30, + "width": 290, + "height": 320 + } + }, + { + "frame": 6, + "dealtPositionTarget": { + "active": true, + "xOffset": 110, + "yOffset": -40 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 9, + "dealtPositionTarget": { + "active": true, + "xOffset": 110, + "yOffset": -40 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 30, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onHitNextPowerIndex": 3 + }, + { + "powerID": 4, + "recovery": 22, + "stunTime": 23, + "hitAngleDeg": 30.0, + "casts": [ + { + "startupFrames": 3, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "hurtboxPositionChange": { + "active": true, + "xOffset": 5, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 3, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 1.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + }, + { + "startupFrames": 3, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "hurtboxPositionChange": { + "active": true, + "xOffset": -33, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + }, + { + "startupFrames": 3, + "attackFrames": 1, + "frameChanges": [ + { + "frame": 3, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.4, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -55, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + }, + { + "startupFrames": 2, + "attackFrames": 5, + "baseDamage": 5, + "variableForce": 31.0, + "fixedForce": 52.0, + "hitboxes": [ + { + "xOffset": 39, + "yOffset": 10, + "width": 116, + "height": 62 + } + ], + "frameChanges": [ + { + "frame": 2, + "hurtboxPositionChange": { + "active": true, + "xOffset": -62, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 8, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -54, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 10, + "hurtboxPositionChange": { + "active": true, + "xOffset": -50, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 12, + "hurtboxPositionChange": { + "active": true, + "xOffset": -46, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 14, + "hurtboxPositionChange": { + "active": true, + "xOffset": -45, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 15, + "hurtboxPositionChange": { + "active": true, + "xOffset": -32, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 17, + "hurtboxPositionChange": { + "active": true, + "xOffset": -26, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 19, + "hurtboxPositionChange": { + "active": true, + "xOffset": -12, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 20, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 5, + "fixedRecovery": 2, + "recovery": 9, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0 + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed NSig.json b/content/$data_path/attacks/Unarmed NSig.json new file mode 100644 index 0000000..a2ff6c1 --- /dev/null +++ b/content/$data_path/attacks/Unarmed NSig.json @@ -0,0 +1,73 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "HEAVY", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 28, + "minCharge": 10, + "isCharge": true, + "enableFloorDrag": true, + "casts": [ + { + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + } + } + ] + }, + { + "startupFrames": 72, + "attackFrames": 1 + } + ], + "onMissNextPowerIndex": 1 + }, + { + "powerID": 29, + "fixedRecovery": 4, + "recovery": 16, + "stunTime": 18, + "hitAngleDeg": 90.0, + "enableFloorDrag": true, + "casts": [ + { + "startupFrames": 4, + "attackFrames": 6, + "baseDamage": 20, + "variableForce": 46.0, + "fixedForce": 40.0, + "hitboxes": [ + { + "xOffset": 53, + "yOffset": -42, + "width": 34, + "height": 140 + }, + { + "xOffset": 40, + "yOffset": -86, + "width": 42, + "height": 130 + }, + { + "xOffset": 27, + "yOffset": 0, + "width": 46, + "height": 94 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed Recovery.json b/content/$data_path/attacks/Unarmed Recovery.json new file mode 100644 index 0000000..9d0fd51 --- /dev/null +++ b/content/$data_path/attacks/Unarmed Recovery.json @@ -0,0 +1,232 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "HEAVY", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 10, + "cooldown": 12, + "stunTime": 25, + "hitAngleDeg": 80.0, + "disableCasterGravity": true, + "onMissNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 11, + "attackFrames": 3, + "baseDamage": 15, + "variableForce": 40.0, + "fixedForce": 55.0, + "hitboxes": [ + { + "xOffset": 50, + "yOffset": -42, + "width": 34, + "height": 116 + }, + { + "xOffset": 37, + "yOffset": -81, + "width": 36, + "height": 112 + }, + { + "xOffset": 23, + "yOffset": -120, + "width": 34, + "height": 52 + }, + { + "xOffset": 35, + "yOffset": -23, + "width": 34, + "height": 50 + } + ], + "frameChanges": [ + { + "frame": 6, + "hurtboxPositionChange": { + "active": true, + "xOffset": 11, + "yOffset": 5, + "width": 290, + "height": 302 + } + }, + { + "frame": 9, + "hurtboxPositionChange": { + "active": true, + "xOffset": 9, + "yOffset": 4, + "width": 284, + "height": 310 + } + }, + { + "frame": 11, + "casterVelocitySet": { + "active": true, + "magnitude": 6.0, + "directionDeg": 70.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -6, + "yOffset": -8, + "width": 290, + "height": 320 + } + } + ] + }, + { + "attackFrames": 3, + "baseDamage": 15, + "variableForce": 40.0, + "fixedForce": 55.0, + "hitboxes": [ + { + "xOffset": 50, + "yOffset": -47, + "width": 34, + "height": 106 + }, + { + "xOffset": 37, + "yOffset": -81, + "width": 36, + "height": 112 + }, + { + "xOffset": 23, + "yOffset": -120, + "width": 34, + "height": 52 + } + ] + }, + { + "attackFrames": 3, + "baseDamage": 15, + "variableForce": 40.0, + "fixedForce": 55.0, + "hitboxes": [ + { + "xOffset": 50, + "yOffset": -60, + "width": 34, + "height": 80 + }, + { + "xOffset": 37, + "yOffset": -92, + "width": 36, + "height": 88 + }, + { + "xOffset": 23, + "yOffset": -116, + "width": 34, + "height": 52 + } + ] + }, + { + "attackFrames": 5, + "frameChanges": [ + { + "frame": 0, + "hurtboxPositionChange": { + "active": true, + "xOffset": -8, + "yOffset": -2, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 1600, + "recovery": 16, + "casts": [ + { + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 6.0, + "directionDeg": 70.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -17, + "yOffset": -6, + "width": 290, + "height": 320 + } + }, + { + "frame": 6, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 1601, + "fixedRecovery": 2, + "recovery": 19, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySet": { + "active": true, + "magnitude": 6.0, + "directionDeg": 70.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": -17, + "yOffset": -6, + "width": 290, + "height": 320 + } + }, + { + "frame": 8, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed SAir.json b/content/$data_path/attacks/Unarmed SAir.json new file mode 100644 index 0000000..a98a19c --- /dev/null +++ b/content/$data_path/attacks/Unarmed SAir.json @@ -0,0 +1,159 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 12, + "cooldown": 14, + "stunTime": 17, + "onMissNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 13, + "attackFrames": 3, + "baseDamage": 13, + "variableForce": 40.0, + "fixedForce": 45.0, + "hitboxes": [ + { + "xOffset": 83, + "yOffset": 25, + "width": 80, + "height": 42 + }, + { + "xOffset": 125, + "yOffset": 53, + "width": 56, + "height": 48 + } + ], + "frameChanges": [ + { + "frame": 13, + "casterVelocitySet": { + "active": true, + "magnitude": 4.0, + "directionDeg": 15.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 31, + "yOffset": 0, + "width": 320, + "height": 290 + } + } + ] + }, + { + "attackFrames": 2, + "baseDamage": 13, + "variableForce": 37.0, + "fixedForce": 45.0, + "hitboxes": [ + { + "xOffset": 92, + "yOffset": 25, + "width": 60, + "height": 42 + }, + { + "xOffset": 125, + "yOffset": 53, + "width": 56, + "height": 48 + } + ] + }, + { + "attackFrames": 2, + "baseDamage": 13, + "variableForce": 36.0, + "fixedForce": 45.0, + "hitboxes": [ + { + "xOffset": 133, + "yOffset": 60, + "width": 38, + "height": 34 + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 770, + "recovery": 14, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 2, + "hurtboxPositionChange": { + "active": true, + "xOffset": 17, + "yOffset": 2, + "width": 300, + "height": 268 + } + }, + { + "frame": 4, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 771, + "fixedRecovery": 5, + "recovery": 17, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 4, + "hurtboxPositionChange": { + "active": true, + "xOffset": 17, + "yOffset": 2, + "width": 300, + "height": 268 + } + }, + { + "frame": 7, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed SLight.json b/content/$data_path/attacks/Unarmed SLight.json new file mode 100644 index 0000000..f48356f --- /dev/null +++ b/content/$data_path/attacks/Unarmed SLight.json @@ -0,0 +1,225 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "LIGHT", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 20, + "cooldown": 10, + "stunTime": 18, + "onMissNextPowerIndex": 2, + "casts": [ + { + "startupFrames": 2, + "attackFrames": 2, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 23, + "yOffset": 0, + "width": 290, + "height": 320 + } + }, + { + "frame": 2, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 25, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + }, + { + "startupFrames": 3, + "attackFrames": 2, + "frameChanges": [ + { + "frame": 3, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.75, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": -15, + "width": 290, + "height": 320 + } + }, + { + "frame": 4, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 0.0, + "activeY": false, + "magnitudeY": 0.0 + } + } + ] + }, + { + "startupFrames": 1, + "attackFrames": 4, + "baseDamage": 13, + "variableForce": 20.0, + "fixedForce": 80.0, + "hitboxes": [ + { + "xOffset": 63, + "yOffset": -12, + "width": 146, + "height": 58 + } + ], + "frameChanges": [ + { + "frame": 1, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.75, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": -25, + "width": 290, + "height": 320 + } + } + ] + } + ], + "onHitNextPowerIndex": 1 + }, + { + "powerID": 772, + "recovery": 18, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.75, + "activeY": false, + "magnitudeY": 0.0 + } + }, + { + "frame": 7, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 4.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": -17, + "width": 290, + "height": 320 + } + }, + { + "frame": 11, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + }, + { + "powerID": 773, + "fixedRecovery": 2, + "recovery": 18, + "casts": [ + { + "attackFrames": 1, + "baseDamage": -1, + "variableForce": -1.0, + "fixedForce": -1.0, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.75, + "activeY": false, + "magnitudeY": 0.0 + } + }, + { + "frame": 8, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 4.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": -17, + "width": 290, + "height": 320 + } + }, + { + "frame": 12, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 2.0, + "activeY": false, + "magnitudeY": 0.0 + }, + "hurtboxPositionChange": { + "active": true, + "xOffset": 0, + "yOffset": 0, + "width": 290, + "height": 320 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/content/$data_path/attacks/Unarmed SSig.json b/content/$data_path/attacks/Unarmed SSig.json new file mode 100644 index 0000000..190c493 --- /dev/null +++ b/content/$data_path/attacks/Unarmed SSig.json @@ -0,0 +1,84 @@ +{ + "move": { + "gadgetThrow": false, + "actionKey": "HEAVY", + "initialPowerIndex": 0 + }, + "powers": [ + { + "powerID": 21, + "minCharge": 11, + "isCharge": true, + "enableFloorDrag": true, + "casts": [ + { + "attackFrames": 1, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": false, + "magnitudeX": 0.0, + "activeY": true, + "magnitudeY": 0.0 + } + } + ] + }, + { + "startupFrames": 81, + "attackFrames": 1 + } + ], + "onMissNextPowerIndex": 1 + }, + { + "powerID": 22, + "recovery": 18, + "stunTime": 18, + "enableFloorDrag": true, + "casts": [ + { + "startupFrames": 7, + "attackFrames": 8, + "baseDamage": 18, + "variableForce": 55.0, + "fixedForce": 45.0, + "hitboxes": [ + { + "xOffset": 96, + "yOffset": -27, + "width": 116, + "height": 48 + } + ], + "frameChanges": [ + { + "frame": 7, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 6.0, + "activeY": false, + "magnitudeY": 0.0 + } + } + ] + }, + { + "attackFrames": 9, + "frameChanges": [ + { + "frame": 0, + "casterVelocitySetXY": { + "activeX": true, + "magnitudeX": 2.0, + "activeY": false, + "magnitudeY": 0.0 + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/environment/WarehouseBrawl.py b/environment/WarehouseBrawl.py new file mode 100644 index 0000000..86bb502 --- /dev/null +++ b/environment/WarehouseBrawl.py @@ -0,0 +1,411 @@ +import environment; + + +class WarehouseBrawl(MalachiteEnv[np.ndarray, np.ndarray, int]): + + BRAWL_TO_UNITS = 1.024 / 320 # Conversion factor + + def __init__(self, mode: RenderMode=RenderMode.RGB_ARRAY, resolution: CameraResolution=CameraResolution.LOW, train_mode: bool = False): + super(WarehouseBrawl, self).__init__() + + self.stage_width_tiles: float = 29.8 + self.stage_height_tiles: float = 16.8 + self.number_of_platforms: int = 2 + + self.mode = mode + self.resolution = resolution + self.train_mode = train_mode + + self.agents = [0, 1] # Agent 0, agent 1 + self.logger = ['', ''] + + # Params + self.fps = 30 + self.dt = 1 / self.fps + self.max_timesteps = self.fps * 90 + + self.agent_1_name = 'Team 1' + self.agent_2_name = 'Team 2' + + # Signals + self.knockout_signal = Signal(self) + self.win_signal = Signal(self) + self.hit_during_stun = Signal(self) + + # Observation Space + self.observation_space = self.get_observation_space() + + self.camera = Camera() + + # Action Space + # WASD + self.action_space = self.get_action_space() + # spaces.Box(low=np.array([0] * 4), high=np.array([1] * 4), shape=(4,), dtype=np.float32) + + self.action_spaces, self.observation_spaces = {}, {} + for agent_id in self.agents: + self.action_spaces[agent_id] = self.action_space + self.observation_spaces[agent_id] = self.observation_space + + self.load_attacks() + + self.reset() + + def get_observation_space(self): + # lowarray = np.array( + # [0, -self.screen_width_tiles/2, -self.screen_width_tiles/2, 0, 0, 0, 0, 0] + + # [0 for _ in range(len(Player.states))] + + # [0] + + # [(0, -self.screen_width_tiles, -self.screen_width_tiles, 0, 0)[i%5] for i in range(self.max_ammo*5)] + + # [0, -self.screen_width_tiles/2, -self.screen_width_tiles/2, 0, -self.screen_width_tiles, -self.screen_width_tiles, -self.screen_width_tiles, -self.screen_width_tiles, + # 0, 0, 0, 0] + + # [0 for _ in range(len(Player.states))] + + # [(0, -self.screen_width_tiles, -self.screen_width_tiles, 0, 0)[i%5] for i in range(self.max_ammo*5)] + + # [0] + # ) + # higharray = np.array( + # [1, self.screen_width_tiles/2, self.screen_width_tiles/2, self.screen_width_tiles/2, 2 * math.pi, 10, 20, 3] + + # [1 for _ in range(len(Player.states))] + + # [2*math.pi] + + # [(1, self.screen_width_tiles, self.screen_width_tiles, 2*math.pi, 2*math.pi)[i%5] for i in range(self.max_ammo*5)] + + # [1, self.screen_width_tiles/2, self.screen_width_tiles/2, self.screen_width_tiles/2, self.screen_width_tiles, self.screen_width_tiles, self.screen_width_tiles, self.screen_width_tiles, + # 2 * math.pi, 2 * math.pi, 20, 3] + + # [1 for _ in range(len(Player.states))] + + # [(1, self.screen_width_tiles, self.screen_width_tiles, 2*math.pi, 2*math.pi)[i%5] for i in range(self.max_ammo*5)] + + # [self.time_limit] + # ) + + obs_helper = ObsHelper() + self.add_player_obs(obs_helper, 'player') + self.add_player_obs(obs_helper, 'opponent') + + print('Obs space', obs_helper.low, obs_helper.high) + + self.obs_helper = obs_helper + + return self.obs_helper.get_as_box() + + def add_player_obs(self, obs_helper, name: str='player') -> None: + # Note: Some low and high bounds are off here. To ensure everyone's code + # still works, we are not modifying them, but will elaborate in comments. + # Pos: Unnormalized, goes from [-18, -7], [18, 7], in game units + obs_helper.add_section([-1, -1], [1, 1], f"{name}_pos") + # Vel: Unnormalized, goes from [-10, -10], [10, 10] in game units + obs_helper.add_section([-1, -1], [1, 1], f"{name}_vel") + obs_helper.add_section([0], [1], f"{name}_facing") + obs_helper.add_section([0], [1], f"{name}_grounded") + obs_helper.add_section([0], [1], f"{name}_aerial") + obs_helper.add_section([0], [2], f"{name}_jumps_left") + obs_helper.add_section([0], [12], f"{name}_state") + obs_helper.add_section([0], [1], f"{name}_recoveries_left") + # Dodge timer: Unnormalized, goes from [0], [82] in frames. + # Represents the time remaining until can dodge again + obs_helper.add_section([0], [1], f"{name}_dodge_timer") + # Stun frames: Unnormalized, goes from [0], [80] in frames + # Represents the time remaining until the player transitions + # out of StunState. + obs_helper.add_section([0], [1], f"{name}_stun_frames") + obs_helper.add_section([0], [1], f"{name}_damage") + obs_helper.add_section([0], [3], f"{name}_stocks") + obs_helper.add_section([0], [11], f"{name}_move_type") + + def get_action_space(self): + act_helper = ActHelper() + act_helper.add_key("w") # W (Aim up) + act_helper.add_key("a") # A (Left) + act_helper.add_key("s") # S (Aim down/fastfall) + act_helper.add_key("d") # D (Right) + act_helper.add_key("space") # Space (Jump) + act_helper.add_key("h") # H (Pickup/Throw) + act_helper.add_key("l") # L (Dash/Dodge) + act_helper.add_key("j") # J (Light Attack) + act_helper.add_key("k") # K (Heavy Attack) + act_helper.add_key("g") # G (Taunt) + + print('Action space', act_helper.low, act_helper.high) + + self.act_helper = act_helper + + return self.act_helper.get_as_box() + + def square_floor_collision(arbiter, space, data): + """ + Collision handler callback that is called when a square collides with the platform. + It sets the square's collision flag so that is_on_floor() returns True. + """ + shape_a, shape_b = arbiter.shapes + # Check both shapes; one of them should be a square. + if hasattr(shape_a, "owner") and isinstance(shape_a.owner, Player): + shape_a.owner.collided_this_step = True + if hasattr(shape_b, "owner") and isinstance(shape_b.owner, Player): + shape_b.owner.collided_this_step = True + return True + + def get_stats(self, agent_id: int) -> PlayerStats: + player = self.players[agent_id] + return PlayerStats( + damage_taken=player.damage_taken_total, + damage_done=player.damage_done, + lives_left=player.stocks) + + def load_attacks(self): + # load all from /content/attacks + self.attacks = {} + + self.keys = { + 'Unarmed NLight': MoveType.NLIGHT, + 'Unarmed DLight': MoveType.DLIGHT, + 'Unarmed SLight': MoveType.SLIGHT, + 'Unarmed NSig': MoveType.NSIG, + 'Unarmed DSig': MoveType.DSIG, + 'Unarmed SSig': MoveType.SSIG, + 'Unarmed NAir': MoveType.NAIR, + 'Unarmed DAir': MoveType.DAIR, + 'Unarmed SAir': MoveType.SAIR, + 'Unarmed Recovery': MoveType.RECOVERY, + 'Unarmed Groundpound': MoveType.GROUNDPOUND, + } + + for file in sorted(os.listdir('attacks')): + name = file.split('.')[0] + if name not in self.keys.keys(): continue + with open(os.path.join('attacks', file)) as f: + move_data = json.load(f) + + self.attacks[self.keys[name]] = move_data + + + def step(self, action: dict[int, np.ndarray]): + # Create new rewards dict + self.cur_action = action + self.rewards = {agent: 0 for agent in self.agents} + self.terminated = False + self.logger = ['', ''] + + self.camera.process() + + # Process all other steps + for obj_name, obj in self.objects.items(): + # If player + if isinstance(obj, Player): + continue + else: + obj.process() + # Pre-process player step + for agent in self.agents: + player = self.players[agent] + player.pre_process() + + # Process player step + for agent in self.agents: + player = self.players[agent] + player.process(action[agent]) + if player.stocks <= 0: + self.terminated = True + self.win_signal.emit(agent='player' if agent == 1 else 'opponent') + if player.on_platform is not None: + platform_vel = player.on_platform.velocity + player.body.velocity += pymunk.Vec2d(platform_vel.x, platform_vel.y) + + + + # Process physics info + for obj_name, obj in self.objects.items(): + obj.physics_process(self.dt) + + # PyMunk step + self.space.step(self.dt) + self.steps += 1 + + truncated = self.steps >= self.max_timesteps + + # Collect observations + observations = {agent: self.observe(agent) for agent in self.agents} + + return observations, self.rewards, self.terminated, truncated, {} + + def add_reward(self, agent: int, reward: float) -> None: + # Not really in use + self.rewards[agent] += reward + + def reset(self, seed=None) -> Tuple[dict[int, np.ndarray], dict[str, Any]]: + self.seed = seed + + + + + self.space = pymunk.Space() + self.dt = 1 / 30.0 + self.space.gravity = 0, 17.808 + + self.steps = 0 + + # Other params + self.rewards = {agent: 0 for agent in self.agents} + + # Game Objects + self.objects: dict[str, GameObject] = {} + + self.players: list[Player] = [] + self.camera.reset(self) + self._setup() + + return {agent: self.observe(agent) for agent in self.agents}, {} + + def observe(self, agent: int) -> np.ndarray: + # lh = LowHigh() + # lh += [-1, -1], [1, 1] # 2d vector to goal + # lh += [-1, -1], [1, 1] # 2d vector of global position + # lh += [-1, -1], [1, 1] # 2d vector of global velocity + + obs = [] + obs += self.players[agent].get_obs() + obs += self.players[1-agent].get_obs() + #obs += self.players[agent].body.position.x, self.players[agent].body.position.y + #obs += self.players[agent].body.position.x, self.players[agent].body.position.y + #obs += self.players[agent].body.velocity.x, self.players[agent].body.velocity.y + + return np.array(obs) + + def render(self) -> None | np.ndarray | str | list: + return self.camera.get_frame(self) + + def handle_ui(self, canvas: pygame.Surface) -> None: + # Define UI + # player_stat = f"P1: {self.players[0].stocks}, P2: {self.players[1].stocks}" + # text_surface = self.camera.font.render(player_stat, True, (255, 255, 255)) # White text + # text_rect = text_surface.get_rect(center=(self.camera.window_width // 2, 50)) # Center the text + # canvas.blit(text_surface, text_rect) + + # # Damage + # small_font = pygame.font.Font(None, 20) + # text_surface = small_font.render(f"{self.players[0].damage}%, {self.players[1].damage}%", True, (255, 255, 255)) # White text + # text_rect = text_surface.get_rect(center=(self.camera.window_width // 2, 70)) # Center the text + # canvas.blit(text_surface, text_rect) + + # Smaller text + small_font = pygame.font.Font(None, 30) + text_surface = small_font.render(f"Time: {self.steps}", True, (255, 255, 255)) # White text + text_rect = text_surface.get_rect(center=(self.camera.window_width // 2, 30)) # Center the text + canvas.blit(text_surface, text_rect) + + # Smaller text + small_font = pygame.font.Font(None, 20) + text_surface = small_font.render(f"P1: {self.logger[0]['transition']}, P2: {self.logger[1]['transition']}", True, (255, 255, 255)) # White text + text_rect = text_surface.get_rect(center=(self.camera.window_width // 2, 50)) # Center the text + canvas.blit(text_surface, text_rect) + + # Smaller text + small_font = pygame.font.Font(None, 20) + text_surface = small_font.render(f"P1: {self.logger[0].get('move_type', '')}, P2: {self.logger[1].get('move_type', '')}", True, (255, 255, 255)) # White text + text_rect = text_surface.get_rect(center=(self.camera.window_width // 2, 70)) # Center the text + canvas.blit(text_surface, text_rect) + + # Smaller text + text_surface = small_font.render(f"P1 Total Reward: {self.logger[0].get('total_reward', '')}, Reward {self.logger[0].get('reward', '')}", True, (255, 255, 255)) # White text + text_rect = text_surface.get_rect(center=(0, self.camera.window_height - 40)) # Center the text + # make it left + text_rect.left = 0 + canvas.blit(text_surface, text_rect) + + text_surface = small_font.render(f"P2 Total Reward: {self.logger[1].get('total_reward', '')}, Reward {self.logger[1].get('reward', '')}", True, (255, 255, 255)) # White text + text_rect = text_surface.get_rect(center=(0, self.camera.window_height - 20)) # Center the text + text_rect.left = 0 + canvas.blit(text_surface, text_rect) + + + + def observation_space(self, agent: AgentID) -> gymnasium.spaces.Space: + return self.observation_spaces[agent] + + def action_space(self, agent: AgentID) -> gymnasium.spaces.Space: + return self.action_spaces[agent] + + def close(self) -> None: + self.camera.close() + + + def pre_solve_oneway(self, arbiter, space, data): + player_shape, platform_shape = arbiter.shapes + player = player_shape.owner + + normal = arbiter.contact_point_set.normal + if normal.y <= 0: + return False + + # Debug: see if S is being read + if "S" in player.input.key_status: + print("S held:", player.input.key_status["S"].held) + + if player.input.key_status["S"].held: + player.on_platform = None + return False + + player.on_platform = platform_shape.body if hasattr(platform_shape, "body") else None + return True + + + def separate_player_platform(self, arbiter, space, data): + player_shape, platform_shape = arbiter.shapes + player = player_shape.owner + player.on_platform = None + + + def _setup(self): + # Collsion fix + handler = self.space.add_collision_handler(PLAYER, + PLAYER + 1) # (Player1 collision_type, Player2 collision_type) + handler.begin = lambda *args, **kwargs: False + + + for player_Num in range(2): + for platform_Num in range(1, self.number_of_platforms + 1): + handler = self.space.add_collision_handler(PLAYER + player_Num, PLATFORM + platform_Num) + handler.pre_solve = self.pre_solve_oneway + handler.separate = self.separate_player_platform + + # Environment + ground = Ground(self.space, 0, 2.03, 10.67) + self.objects['ground'] = ground + + + stage1 = Stage(self.space, 1, 4, 2, 2, 2) + self.objects['stage1'] = stage1 + # State the waypoint positions for this platform. + # Note that in our case the y axis increases DOWNWARDS, NOT UPWARD + stage1.waypoint1 = (0,1) + stage1.waypoint2 = (0,1) + + stage2 = Stage(self.space, 2, 4, 2, 2, 2) + self.objects['stage2'] = stage2 + # State the waypoint positions for this platform. + # Note that in our case the y axis increases DOWNWARDS, NOT UPWARD + stage2.waypoint1 = (-4,-1) + stage2.waypoint2 = (4,-1) + + + # Players + # randomize start pos, binary + p1_right = bool(random.getrandbits(1)) + p1_start_pos = [5, 0] if p1_right else [-5, 0] + p2_start_pos = [-5, 0] if p1_right else [5, 0] + + # Uncomment this if you'd like. It makes train_mode RANDOMIZE the + # position of both players, so that they get used to many + # different positions in the map! + + # if self.train_mode: + # p1_start_pos = [random.uniform(-5, 5), 0] + # p2_start_pos = [random.uniform(-5, 5), 0] + # else: + # p1_start_pos = [5, 0] if p1_right else [-5, 0] + # p2_start_pos = [-5, 0] if p1_right else [5, 0] + + p1 = Player(self, 0, start_position=p1_start_pos, color=[0, 0, 255, 255]) + p2 = Player(self, 1, start_position=p2_start_pos, color=[0, 255, 0, 255]) + + self.objects['player'] = p1 + self.objects['opponent'] = p2 + + self.players += [p1, p2] + diff --git a/environment/__pycache__/WarehouseBrawl.cpython-313.pyc b/environment/__pycache__/WarehouseBrawl.cpython-313.pyc new file mode 100644 index 0000000..884fce4 Binary files /dev/null and b/environment/__pycache__/WarehouseBrawl.cpython-313.pyc differ diff --git a/environment/__pycache__/agent.cpython-313.pyc b/environment/__pycache__/agent.cpython-313.pyc new file mode 100644 index 0000000..a13f8f9 Binary files /dev/null and b/environment/__pycache__/agent.cpython-313.pyc differ diff --git a/environment/__pycache__/environment.cpython-313.pyc b/environment/__pycache__/environment.cpython-313.pyc new file mode 100644 index 0000000..ed1fed4 Binary files /dev/null and b/environment/__pycache__/environment.cpython-313.pyc differ diff --git a/environment/agent.py b/environment/agent.py index 7678dd3..3738c45 100644 --- a/environment/agent.py +++ b/environment/agent.py @@ -601,7 +601,6 @@ def run_match(agent_1: Agent | partial, video_path: Optional[str]=None, agent_1_name: Optional[str]=None, agent_2_name: Optional[str]=None, - mode=RenderMode.RGB_ARRAY, resolution = CameraResolution.LOW, reward_manager: Optional[RewardManager]=None, train_mode=False @@ -611,7 +610,7 @@ def run_match(agent_1: Agent | partial, observations, infos = env.reset() obs_1 = observations[0] obs_2 = observations[1] - + print("RUN MATCH IS RUNNING") if reward_manager is not None: reward_manager.reset() reward_manager.subscribe_signals(env) @@ -649,32 +648,33 @@ def run_match(agent_1: Agent | partial, if not agent_1.initialized: agent_1.get_env_info(env) if not agent_2.initialized: agent_2.get_env_info(env) # 596, 336 + platform1 = env.objects["platform1"] + platform2 = env.objects["platform2"] - for _ in tqdm(range(max_timesteps), total=max_timesteps): - # actions = {agent: agents[agent].predict(None) for agent in range(2)} + for time in tqdm(range(max_timesteps), total=max_timesteps): + platform1.physics_process(0.05) + platform2.physics_process(0.5) - # observations, rewards, terminations, truncations, infos + full_action = { + 0: agent_1.predict(obs_1), + 1: agent_2.predict(obs_2) + } - full_action = { - 0: agent_1.predict(obs_1), - 1: agent_2.predict(obs_2) - } + observations, rewards, terminated, truncated, info = env.step(full_action) + obs_1 = observations[0] + obs_2 = observations[1] - observations, rewards, terminated, truncated, info = env.step(full_action) - obs_1 = observations[0] - obs_2 = observations[1] + if reward_manager is not None: + reward_manager.process(env, 1 / env.fps) - if reward_manager is not None: - reward_manager.process(env, 1 / env.fps) + if video_path is not None: + img = env.render() + writer.writeFrame(img) + del img - if video_path is not None: - img = env.render() - writer.writeFrame(img) - del img + if terminated or truncated: + break - if terminated or truncated: - break - #env.show_image(img) if video_path is not None: writer.close() @@ -1400,8 +1400,13 @@ def gen_reward_manager(): def run_real_time_match(agent_1: UserInputAgent, agent_2: Agent, max_timesteps=30*90, resolution=CameraResolution.LOW): pygame.init() - screen = pygame.display.set_mode((1920, 1080)) # Set screen dimensions + screen = pygame.display.set_mode((500, 500), pygame.RESIZABLE) # Set screen dimensions + screen_surface = pygame.Surface((500, 500)) pygame.display.set_caption("AI Squared - Player vs AI Demo") + screen.fill((0, 0, 0)) # Fill screen with black + rect = screen_surface.get_rect(center=screen.get_rect().center) + #screen.blit(screen_surface, rect) + # pygame.display.flip() clock = pygame.time.Clock() # Initialize environment @@ -1416,12 +1421,19 @@ def run_real_time_match(agent_1: UserInputAgent, agent_2: Agent, max_timesteps=3 # Run the match loop running = True timestep = 0 + platform1 = env.objects["platform1"] + #stage2 = env.objects["stage2"] while running and timestep < max_timesteps: # Pygame event to handle real-time user input for event in pygame.event.get(): if event.type == QUIT: running = False - + if event.type == pygame.VIDEORESIZE: + screen = pygame.display.set_mode(event.size, pygame.RESIZABLE) + scaled = pygame.transform.smoothscale(screen_surface, screen.get_size()) + screen.blit(scaled, (0, 0)) + platform1.physics_process(2) + # stage2.physics_process(0.05) # User input action_1 = agent_1.predict(obs_1) @@ -1445,6 +1457,8 @@ def run_real_time_match(agent_1: UserInputAgent, agent_2: Agent, max_timesteps=3 # If the match is over (either terminated or truncated), stop the loop if terminated or truncated: running = False + + timestep += 1 diff --git a/environment/assets/map/platform.png b/environment/assets/map/platform.png new file mode 100644 index 0000000..9b0b991 Binary files /dev/null and b/environment/assets/map/platform.png differ diff --git a/environment/environment.py b/environment/environment.py index b4495d5..9cf7df6 100644 --- a/environment/environment.py +++ b/environment/environment.py @@ -773,11 +773,12 @@ class WarehouseBrawl(MalachiteEnv[np.ndarray, np.ndarray, int]): BRAWL_TO_UNITS = 1.024 / 320 # Conversion factor - def __init__(self, mode: RenderMode=RenderMode.RGB_ARRAY, resolution: CameraResolution=CameraResolution.MEDIUM, train_mode: bool = False): + def __init__(self, mode: RenderMode=RenderMode.RGB_ARRAY, resolution: CameraResolution=CameraResolution.LOW, train_mode: bool = False): super(WarehouseBrawl, self).__init__() self.stage_width_tiles: float = 29.8 self.stage_height_tiles: float = 16.8 + self.number_of_platforms: int = 2 self.mode = mode self.resolution = resolution @@ -958,7 +959,6 @@ def step(self, action: dict[int, np.ndarray]): continue else: obj.process() - # Pre-process player step for agent in self.agents: player = self.players[agent] @@ -971,8 +971,12 @@ def step(self, action: dict[int, np.ndarray]): if player.stocks <= 0: self.terminated = True self.win_signal.emit(agent='player' if agent == 1 else 'opponent') + if player.on_platform is not None: + platform_vel = player.on_platform.velocity + player.body.velocity = pymunk.Vec2d(platform_vel.x, platform_vel.y) + + - # Process physics info for obj_name, obj in self.objects.items(): @@ -1088,50 +1092,88 @@ def action_space(self, agent: AgentID) -> gymnasium.spaces.Space: def close(self) -> None: self.camera.close() + + + def pre_solve_oneway(self, arbiter, space, data): + """ + Handle one-way platform collision logic. + Allow players to pass through from below, but land on top. + Allow drop-through when S key is pressed. + """ + player_shape, platform_shape = arbiter.shapes + player = player_shape.owner + + # Get collision normal (points from platform to player) + normal = arbiter.contact_point_set.normal + + # If player is coming from above (normal.y > 0), allow collision + # If player is coming from below/side (normal.y <= 0), ignore collision + if normal.y <= 0: + return False + + # Check if player is pressing S to drop through platform + if hasattr(player.input, 'key_status') and "S" in player.input.key_status: + if player.input.key_status["S"].held: + print("S was pressed") + player.on_platform = None + print(player.on_platform); + return False + if player.start_position[1] < platform_shape.owner.body.position[1]: + return False; + # Player is landing on platform from above - enable collision + player.on_platform = platform_shape.body + return True + + def separate_player_platform(self, arbiter, space, data): + """ + Called when player separates from platform. + """ + player_shape, platform_shape = arbiter.shapes + player = player_shape.owner + player.on_platform = None def _setup(self): - # Collsion fix - handler = self.space.add_collision_handler(3, 4) # (Player1 collision_type, Player2 collision_type) + # Collision fix - prevent players from colliding with each other + handler = self.space.add_collision_handler(PLAYER, PLAYER + 1) handler.begin = lambda *args, **kwargs: False + # Set up one-way platform collision for each player and platform combination + for player_num in range(2): + for platform_num in range(1, self.number_of_platforms + 1): + handler = self.space.add_collision_handler(PLAYER + player_num, PLATFORM + platform_num) + handler.pre_solve = self.pre_solve_oneway + handler.separate = self.separate_player_platform + # Environment - ground = Ground(self.space, 0, 2.03, 10.67) - #platform1 = Ground(self.space, 5, 0, 2) # First platform - #platform2 = Ground(self.space, 2, 3, 2) # Second platform with a gap + ground1 = Ground(self.space, 6, 3, 10) + self.objects['ground1'] = ground1 - self.objects['ground'] = ground - #self.objects['platform1'] = platform1 - #self.objects['platform2'] = platform2 + ground2 = Ground(self.space, -6, 3, 10) + self.objects['ground2'] = ground2 - # Particle - #particle = Particle(self, [0, 0], 'test/unarmedgp.gif', scale=0.2) - #self.objects['particle'] = particle + # Create platforms with proper positioning + platform1 = Stage(self.space, 1, 0, 1, 2, 1, (100, 100, 200, 255)) + self.objects['platform1'] = platform1 + platform1.waypoint1 = (-2, 0) + platform1.waypoint2 = (2, 0) - # Target - #target = Target() - #self.objects['target'] = target + # stage2 = Stage(self.space, 2, 0, -1, 2, 1, (200, 100, 100, 255)) + # self.objects['stage2'] = stage2 + # stage2.waypoint1 = (-4, -1) + # platform2.waypoint2 = (4, -1) - # Players - # randomize start pos, binary + # Players setup (rest of your existing code) p1_right = bool(random.getrandbits(1)) - - # random between -5 and 5 - if self.train_mode: - p1_start_pos = [random.uniform(-5, 5), 0] - p2_start_pos = [random.uniform(-5, 5), 0] - else: - p1_start_pos = [5, 0] if p1_right else [-5, 0] - p2_start_pos = [-5, 0] if p1_right else [5, 0] + p1_start_pos = [5, 0] if p1_right else [-5, 0] + p2_start_pos = [-5, 0] if p1_right else [5, 0] p1 = Player(self, 0, start_position=p1_start_pos, color=[0, 0, 255, 255]) p2 = Player(self, 1, start_position=p2_start_pos, color=[0, 255, 0, 255]) self.objects['player'] = p1 self.objects['opponent'] = p2 - self.players += [p1, p2] - # ### GameObject # In[ ]: @@ -1187,12 +1229,15 @@ def draw_image(canvas, img, pos, desired_width, camera, flipped: bool = False): # In[ ]: +GROUND = 1 +PLAYER = 3 +PLATFORM = 5 class Ground(GameObject): def __init__(self, space, x, y, width_ground, color=(150, 150, 150, 255)): - self.body = pymunk.Body(x, y, body_type=pymunk.Body.STATIC) + self.body = pymunk.Body(body_type=pymunk.Body.STATIC) self.shape = pymunk.Poly.create_box(self.body, (width_ground, 0.1)) - self.shape.collision_type = 2 # Ground + self.shape.collision_type = GROUND # Ground self.shape.owner = self self.shape.body.position = (x, y) self.shape.friction = 0.7 @@ -1204,28 +1249,124 @@ def __init__(self, space, x, y, width_ground, color=(150, 150, 150, 255)): self.loaded = False def load_assets(self): - if self.loaded: return + if self.loaded: + return self.loaded = True self.bg_img = pygame.image.load('assets/map/bg.jpg') self.stage_img = pygame.image.load('assets/map/stage.png') + print("Ground is rendered") def render(self, canvas, camera) -> None: self.load_assets() - #self.draw_image(canvas, self.bg_img, (0, 0), 29.8, camera) - self.draw_image(canvas, self.stage_img, (0, 0.8), self.width_ground * 3.2, camera) + self.draw_image(canvas, self.stage_img, (self.shape.body.position.x, self.shape.body.position.y-(2.03-0.8)), self.width_ground * 3.2, camera) + + self.draw_outline(canvas,camera) + + def draw_outline(self, canvas, camera): + # 1. Get the vertices of the shape (in local body space) + local_vertices = self.shape.get_vertices() + + # 2. Convert to world space (apply rotation and position) + world_vertices = [v.rotated(self.body.angle) + self.body.position for v in local_vertices] + + # 3. Convert to screen space using camera.gtp() + screen_points = [camera.gtp(v) for v in world_vertices] + + # 4. Draw red outline + pygame.draw.polygon(canvas, (255, 0, 0), screen_points, width=2)#martin class Stage(GameObject): - def __init__(self, space, x, y, width, height, color=(150, 150, 150, 255)): - self.body = pymunk.Body(x, y, body_type=pymunk.Body.STATIC) - self.shape = pymunk.Poly.create_box(self.body, (width, height)) - self.shape.body.position = (x + width // 2, y) - self.shape.friction = 0.7 + def __init__(self, space, platform_id: int, x, y, width, height, color=(150, 150, 150, 255)): + self.body = pymunk.Body(body_type=pymunk.Body.KINEMATIC) + self.body.position = (x, y) # Set initial position + self.shape = pymunk.Poly.create_box(self.body, (width, height * 0.1)) + self.shape.friction = 0.9 # Add some friction so players can walk normally self.shape.color = color + self.shape.collision_type = PLATFORM + platform_id + self.shape.platform_id = platform_id # Store platform ID for reference + self.shape.owner = self; space.add(self.shape, self.body) + self.width = width + self.height = height + self.loaded = False + self.velocity_x = 0; + self.velocity_y = 0; + + # Movement config + self.waypoint1 = (0, 0) + self.waypoint2 = (0, 0) + self.moving_to_w2 = True + + def load_assets(self): + if self.loaded: return + self.loaded = True + self.bg_img = pygame.image.load('assets/map/bg.jpg') + self.platform_img = pygame.image.load('assets/map/platform.png') + print("Stage is rendered") def render(self, canvas, camera) -> None: - pass + self.load_assets() + self.draw_image(canvas, self.platform_img, (self.body.position.x, self.body.position.y), self.width, camera) + self.draw_outline(canvas, camera) + + def draw_outline(self, canvas, camera): + # 1. Get the vertices of the shape (in local body space) + local_vertices = self.shape.get_vertices() + + # 2. Convert to world space (apply rotation and position) + world_vertices = [v.rotated(self.body.angle) + self.body.position for v in local_vertices] + + # 3. Convert to screen space using camera.gtp() + screen_points = [camera.gtp(v) for v in world_vertices] + + # 4. Draw red outline + pygame.draw.polygon(canvas, (255, 0, 0), screen_points, width=2) + + def physics_process(self, deltaTime: float) -> None: + """Move between waypoints with smooth acceleration/deceleration.""" + import math + + currentPos = self.body.position + target = self.waypoint2 if self.moving_to_w2 else self.waypoint1 + + dx = target[0] - currentPos[0] + dy = target[1] - currentPos[1] + dist = math.sqrt(dx*dx + dy*dy) + + # If we're very close to the target, stop and swap direction + if dist < 0.1: + self.body.velocity = (0, 0) + self.moving_to_w2 = not self.moving_to_w2 + return + + # Direction vector (normalized) + dir_x = dx / dist + dir_y = dy / dist + + # Segment vector and length + seg_x = self.waypoint2[0] - self.waypoint1[0] + seg_y = self.waypoint2[1] - self.waypoint1[1] + seg_len = max(math.sqrt(seg_x*seg_x + seg_y*seg_y), 0.05) + + # Projection of current position onto the segment + # (how far along the path we are, normalized 0→1) + rel_x = currentPos[0] - self.waypoint1[0] + rel_y = currentPos[1] - self.waypoint1[1] + progress = (rel_x * seg_x + rel_y * seg_y) / (seg_len * seg_len) + progress = max(0.0, min(1.0, progress)) # clamp to [0, 1] + + # Smooth speed profile: cosine-shaped ease-in/out + # At 0 or 1 → 0 speed, at 0.5 → max speed + base_speed = 5.0 # maximum speed at midpoint + speed = base_speed * math.sin(progress * math.pi) + 0.03 ; + + # Apply velocity + velocity_x = dir_x * speed + velocity_y = dir_y * speed ; + self.body.velocity = (velocity_x, velocity_y) + + class Target(GameObject): def __init__(self): @@ -1576,6 +1717,11 @@ def physics_process(self, dt: float) -> PlayerObjectState: # Check for dash if self.p.input.key_status["l"].just_pressed: return self.p.states['dash'] + + if self.p.shape.cache_bb().intersects(self.p.env.objects['platform1'].shape.cache_bb()) and not self.p.input.key_status["S"].held: + self.p.body.velocity = pymunk.Vec2d(int(self.p.facing) * self.p.move_speed + self.p.env.objects['platform1'].body.velocity[0], self.p.body.velocity.y + self.p.env.objects['platform1'].body.velocity[1]) + return None; + # Handle movement self.p.body.velocity = pymunk.Vec2d(direction * self.p.move_speed, self.p.body.velocity.y) @@ -1629,6 +1775,9 @@ def physics_process(self, dt: float) -> PlayerObjectState: if abs(direction) > 1e-2: self.p.facing = Facing.from_direction(direction) return self.p.states['walking'] + if self.p.shape.cache_bb().intersects(self.p.env.objects['platform1'].shape.cache_bb()) and not self.p.input.key_status["S"].held: + self.p.body.velocity = pymunk.Vec2d(self.p.env.objects['platform1'].body.velocity[0],self.p.env.objects['platform1'].body.velocity[1]) + return None # gradual ease @@ -2667,7 +2816,6 @@ def __init__(self, env, agent_id: int, start_position=[0,0], color=[200, 200, 0, hitbox_size = Capsule.get_hitbox_size(290//2, 320//2) self.hurtbox_collider = CapsuleCollider(center=(0, 0), width=hitbox_size[0], height=hitbox_size[1]) - self.start_position = start_position # Create input handlers @@ -2756,7 +2904,7 @@ def __init__(self, env, agent_id: int, start_position=[0,0], color=[200, 200, 0, # Create PyMunk Object self.shape = pymunk.Poly.create_box(None, size=(width, height)) - self.shape.collision_type = 3 if agent_id == 0 else 4 + self.shape.collision_type = PLAYER if agent_id == 0 else PLAYER + 1 self.shape.owner = self #self.moment = pymunk.moment_for_poly(self.mass, self.shape.get_vertices()) self.moment = 1e9 @@ -2784,6 +2932,7 @@ def __init__(self, env, agent_id: int, start_position=[0,0], color=[200, 200, 0, self.jump_cooldown = self.env.fps * 0.5 self.dash_time = self.env.fps * 0.3 self.dash_cooldown = 8 + self.on_platform = None # Signals self.just_got_hit = False @@ -2877,10 +3026,6 @@ def load_assets(self): self.assets_loaded = True - def is_on_floor(self) -> bool: - old_cond = (abs(self.body.position.y - 1.540) < 0.03 and abs(self.body.position.x) < 5.77) - return self.shape.cache_bb().intersects(self.env.objects['ground'].shape.cache_bb()) or old_cond - #return abs(self.body.position.y - 1.540) < 0.03 and abs(self.body.position.x) < 5.77 def set_gravity_disabled(self, disabled:bool) -> None: self.body.gravity_scale = 0 if disabled else 1 @@ -2925,6 +3070,14 @@ def render(self, screen, camera) -> None: screen_pos = camera.gtp((int(position[0]), int(position[1])-1)) pygame.draw.circle(camera.canvas, cc, screen_pos, camera.scale_gtp() * 0.25) + def is_on_floor(self) -> bool: + if(self.shape.cache_bb().intersects(self.env.objects['ground1'].shape.cache_bb()) or + self.shape.cache_bb().intersects(self.env.objects['ground2'].shape.cache_bb())): + return True + if(self.shape.cache_bb().intersects(self.env.objects['platform1'].shape.cache_bb()) and self.body.position[1] <= self.env.objects['platform1'].body.position[1]):#mohamed + return True + return False + def set_hitboxes_to_draw(self, hitboxes: Optional[List[Any]]=None, points: Optional[List[Any]]=None, @@ -3098,7 +3251,7 @@ def physics_process(self, delta: float) -> None: self.body.velocity = (self.body.velocity.x + self.damage_velocity[0] + self.target_vel[0], self.body.velocity.y + self.damage_velocity[1] + self.target_vel[1]) - + # print(self.body.velocity) if new_state is not None: new_state.reset(self.state) self.state.exit() diff --git a/environment/pvp_match.py b/environment/pvp_match.py index 250346a..7a3e3d1 100644 --- a/environment/pvp_match.py +++ b/environment/pvp_match.py @@ -1,5 +1,5 @@ -import skvideo -import skvideo.io +# import skvideo +# import skvideo.io from IPython.display import Video from agent import SB3Agent, RecurrentPPOAgent, BasedAgent, UserInputAgent, ConstantAgent, run_match, run_real_time_match, CameraResolution, gen_reward_manager diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c289359 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,68 @@ +gdown==5.2.0 +gym==0.25.2 +gym-notices==0.0.8 +gymnasium==1.0.0 +jupyter==1.1.1 +jupyter-console==6.1.0 +jupyter-events==0.12.0 +jupyter-leaflet==0.19.2 +jupyter-lsp==2.2.5 +jupyter_client==7.4.9 +jupyter_core==5.7.2 +jupyter_server==2.15.0 +jupyter_server_terminals==0.5.3 +jupyterlab==4.3.5 +jupyterlab_pygments==0.3.0 +jupyterlab_server==2.27.3 +jupyterlab_widgets==3.0.13 +memory-profiler==0.61.0 +numpy==1.26.4 +nvidia-cublas-cu12==12.1.3.1 +nvidia-cuda-cupti-cu12==12.1.105 +nvidia-cuda-nvcc-cu12==12.5.82 +nvidia-cuda-nvrtc-cu12==12.1.105 +nvidia-cuda-runtime-cu12==12.1.105 +nvidia-cudnn-cu12==9.1.0.70 +nvidia-cufft-cu12==11.0.2.54 +nvidia-curand-cu12==10.3.2.106 +nvidia-cusolver-cu12==11.4.5.107 +nvidia-cusparse-cu12==12.1.0.106 +nvidia-nccl-cu12==2.20.5 +nvidia-nvcomp-cu12==4.1.0.6 +nvidia-nvjitlink-cu12==12.5.82 +nvidia-nvtx-cu12==12.1.105 +nvtx==0.2.10 +nx-cugraph-cu12 @ https://pypi.nvidia.com/nx-cugraph-cu12/nx_cugraph_cu12-24.12.0-py3-none-any.whl +openai==1.61.1 +opencv-contrib-python==4.11.0.86 +opencv-python==4.11.0.86 +opencv-python-headless==4.11.0.86 +pygame==2.6.1 +pymunk==6.2.1 +PyOpenGL==3.1.9 +pyspark==3.5.4 +pytensor==2.26.4 +pytest==8.3.4 +python-apt==0.0.0 +python-box==7.3.2 +python-dateutil==2.8.2 +python-json-logger==3.2.1 +python-louvain==0.16 +python-slugify==8.0.4 +python-snappy==0.7.3 +python-utils==3.9.1 +sb3_contrib==2.5.0 +scikit-image==0.25.1 +scikit-learn==1.6.1 +scikit-video==1.1.11 +scipy==1.13.1 +sklearn-compat==0.1.3 +sklearn-pandas==2.2.0 +stable_baselines3==2.5.0 +sympy==1.5.1 +torch==2.4.1 +tqdm==4.67.1 +traitlets==5.7.1 +traittypes==0.2.1 +transformers==4.48.2 +triton==3.0.0 \ No newline at end of file diff --git a/rl-model/_stable_baselines3_version b/rl-model/_stable_baselines3_version new file mode 100644 index 0000000..fad066f --- /dev/null +++ b/rl-model/_stable_baselines3_version @@ -0,0 +1 @@ +2.5.0 \ No newline at end of file diff --git a/rl-model/data b/rl-model/data new file mode 100644 index 0000000..ecadc06 --- /dev/null +++ b/rl-model/data @@ -0,0 +1,124 @@ +{ + "policy_class": { + ":type:": "", + ":serialized:": "gAWVSAAAAAAAAACMJXNiM19jb250cmliLmNvbW1vbi5yZWN1cnJlbnQucG9saWNpZXOUjBpSZWN1cnJlbnRBY3RvckNyaXRpY1BvbGljeZSTlC4=", + "__module__": "sb3_contrib.common.recurrent.policies", + "__doc__": "\n Recurrent policy class for actor-critic algorithms (has both policy and value prediction).\n To be used with A2C, PPO and the likes.\n It assumes that both the actor and the critic LSTM\n have the same architecture.\n\n :param observation_space: Observation space\n :param action_space: Action space\n :param lr_schedule: Learning rate schedule (could be constant)\n :param net_arch: The specification of the policy and value networks.\n :param activation_fn: Activation function\n :param ortho_init: Whether to use or not orthogonal initialization\n :param use_sde: Whether to use State Dependent Exploration or not\n :param log_std_init: Initial value for the log standard deviation\n :param full_std: Whether to use (n_features x n_actions) parameters\n for the std instead of only (n_features,) when using gSDE\n :param use_expln: Use ``expln()`` function instead of ``exp()`` to ensure\n a positive standard deviation (cf paper). It allows to keep variance\n above zero and prevent it from growing too fast. In practice, ``exp()`` is usually enough.\n :param squash_output: Whether to squash the output using a tanh function,\n this allows to ensure boundaries when using gSDE.\n :param features_extractor_class: Features extractor to use.\n :param features_extractor_kwargs: Keyword arguments\n to pass to the features extractor.\n :param share_features_extractor: If True, the features extractor is shared between the policy and value networks.\n :param normalize_images: Whether to normalize images or not,\n dividing by 255.0 (True by default)\n :param optimizer_class: The optimizer to use,\n ``th.optim.Adam`` by default\n :param optimizer_kwargs: Additional keyword arguments,\n excluding the learning rate, to pass to the optimizer\n :param lstm_hidden_size: Number of hidden units for each LSTM layer.\n :param n_lstm_layers: Number of LSTM layers.\n :param shared_lstm: Whether the LSTM is shared between the actor and the critic\n (in that case, only the actor gradient is used)\n By default, the actor and the critic have two separate LSTM.\n :param enable_critic_lstm: Use a seperate LSTM for the critic.\n :param lstm_kwargs: Additional keyword arguments to pass the the LSTM\n constructor.\n ", + "__init__": "", + "_build_mlp_extractor": "", + "_process_sequence": ")>", + "forward": "", + "get_distribution": "", + "predict_values": "", + "evaluate_actions": "", + "_predict": "", + "predict": "", + "__abstractmethods__": "frozenset()", + "_abc_impl": "<_abc._abc_data object at 0x7efb7c0c71c0>" + }, + "verbose": 1, + "policy_kwargs": { + ":type:": "", + ":serialized:": "gAWVvwAAAAAAAAB9lCiMDWFjdGl2YXRpb25fZm6UjBt0b3JjaC5ubi5tb2R1bGVzLmFjdGl2YXRpb26UjARSZUxVlJOUjBBsc3RtX2hpZGRlbl9zaXpllE0AAowIbmV0X2FyY2iUXZR9lCiMAnBplF2UKEsgSyBljAJ2ZpRdlChLIEsgZXVhjAtzaGFyZWRfbHN0bZSIjBJlbmFibGVfY3JpdGljX2xzdG2UiYwYc2hhcmVfZmVhdHVyZXNfZXh0cmFjdG9ylIh1Lg==", + "activation_fn": "", + "lstm_hidden_size": 512, + "net_arch": [ + { + "pi": [ + 32, + 32 + ], + "vf": [ + 32, + 32 + ] + } + ], + "shared_lstm": true, + "enable_critic_lstm": false, + "share_features_extractor": true + }, + "num_timesteps": 12400123, + "_total_timesteps": 1000000000, + "_num_timesteps_at_start": 0, + "seed": null, + "action_noise": null, + "start_time": 1739559806726511302, + "learning_rate": 0.0003, + "tensorboard_log": null, + "_last_obs": { + ":type:": "", + ":serialized:": "gAWV7QAAAAAAAACMEm51bXB5LmNvcmUubnVtZXJpY5SMC19mcm9tYnVmZmVylJOUKJZ4AAAAAAAAAJybTcDBGU+/AAAAAD55mD8AAIA/AAAAAAAAgD8AAABAAAAAQQAAAAAAAAAAAAAAAAAAAAAAAIA/AAAwQZRBkT9IPco/mzwtNGq2FrQAAAAAAACAPwAAAAAAAABAAAAAQQAAgD8AAAAAAAAAAAAAAAAAAABAAAAAQJSMBW51bXB5lIwFZHR5cGWUk5SMAmY0lImIh5RSlChLA4wBPJROTk5K/////0r/////SwB0lGJLAUsehpSMAUOUdJRSlC4=" + }, + "_last_episode_starts": { + ":type:": "", + ":serialized:": "gAWVdAAAAAAAAACMEm51bXB5LmNvcmUubnVtZXJpY5SMC19mcm9tYnVmZmVylJOUKJYBAAAAAAAAAACUjAVudW1weZSMBWR0eXBllJOUjAJiMZSJiIeUUpQoSwOMAXyUTk5OSv////9K/////0sAdJRiSwGFlIwBQ5R0lFKULg==" + }, + "_last_original_obs": null, + "_episode_num": 0, + "use_sde": false, + "sde_sample_freq": -1, + "_current_progress_remaining": 0.987634, + "_stats_window_size": 100, + "ep_info_buffer": { + ":type:": "", + ":serialized:": "gAWVRAwAAAAAAACMC2NvbGxlY3Rpb25zlIwFZGVxdWWUk5QpS2SGlFKUKH2UKIwBcpRHwByPs3Q2MsKMAWyUTYwKjAF0lEdBBzsltAX2unV9lChoBkfAK8Kujh1klWgHTYwKaAhHQQc7jDO2RaJ1fZQoaAZHP7BGMGX5WR1oB02MCmgIR0EHO/EgFHJ+dX2UKGgGR0BPCgIhQm/naAdNLgpoCEdBBzxEQ/PgN3V9lChoBkfAQ/KmwaBI4GgHTYwKaAhHQQc8mzP420l1fZQoaAZHwBZsfq5byH5oB02MCmgIR0EHPPaIXbdrdX2UKGgGR8AxnGdZq20BaAdNjApoCEdBBz1M/CEYfnV9lChoBkdAUjnVrhzeXWgHTRMDaAhHQQc9aEgEEDB1fZQoaAZHQFJcljEvTPVoB021AWgIR0EHPXA1t4zKdX2UKGgGR8AuYMSbpeNUaAdNjApoCEdBBz3GkLH+63V9lChoBkdAUc9+fAbhnGgHTfgHaAhHQQc+DpeD3/R1fZQoaAZHwCkiq2jO9nNoB02MCmgIR0EHPkf/io87dX2UKGgGR0BSXr3Gn4wiaAdNdQFoCEdBBz5OxJZntnV9lChoBkdAHZ5hBqsU7GgHTYwKaAhHQQc+hol+mWN1fZQoaAZHQE+LfVI7NjdoB00nBGgIR0EHPqbsXaakdX2UKGgGR8BcPY2CNCJGaAdNCQpoCEdBBz7+CElE7XV9lChoBkdAU3BNO/L1VmgHTSQFaAhHQQc/J1Y9Pk91fZQoaAZHQFI0GVzIV/NoB034AmgIR0EHPzx0z0pWdX2UKGgGR8BArWpqASWaaAdNjApoCEdBBz+X7frKNnV9lChoBkdAUP6uLaVUuWgHTZ8CaAhHQQc/q9fWMCN1fZQoaAZHQBHDfJmukk9oB02MCmgIR0EHQAaSTY/WdX2UKGgGR0BST/tQbdadaAdN7gFoCEdBB0ANjEcbSHV9lChoBkfAU+EAsCkoF2gHTQgGaAhHQQdAQeKNQ0p1fZQoaAZHwE0ltIClrM1oB02MCmgIR0EHQJ8MCcPOdX2UKGgGR0BSXXuRcNYsaAdNhQFoCEdBB0ClUwco6XV9lChoBkfARPhuAI6bOWgHTUkFaAhHQQdA1BDIBBB1fZQoaAZHQEKxaHKwIMVoB02MCmgIR0EHQUtA5zYFdX2UKGgGR0BRM4BvJiiJaAdNNgJoCEdBB0FWsz67/XV9lChoBkdAMCFEiMYMv2gHTYwKaAhHQQdUpjObAk91fZQoaAZHQFHfA/9pAUtoB01ECGgIR0EHVOkJCSiedX2UKGgGR8BT5f6j3225aAdNTwZoCEdBB1UiPwqiGnV9lChoBkfAMNcEA5q/NGgHTYwKaAhHQQdVeBOt4iZ1fZQoaAZHQEw7iDujRD1oB025CGgIR0EHVcXsERradX2UKGgGR8BTq5r1uivgaAdN0ANoCEdBB1XlAhr303V9lChoBkfAVRZgKF7D22gHTcMIaAhHQQdWM7UdaMd1fZQoaAZHwFASdmQKa5RoB03xBWgIR0EHVmnQQ176dX2UKGgGR0AwjiDujRD1aAdNjApoCEdBB1bHpnlGPXV9lChoBkdAT9QoLG7z1GgHTf8BaAhHQQdWz9LhaTx1fZQoaAZHwC5XVRUFSsNoB02MCmgIR0EHVymkSuhcdX2UKGgGR8BZwClabF0gaAdNXAhoCEdBB1d5NdNWVHV9lChoBkdAOzijDbah6GgHTYwKaAhHQQdXuPBPbfx1fZQoaAZHQEI8X5WRzRxoB02MCmgIR0EHWBkRc3VDdX2UKGgGR0Ay7vttygf2aAdNjApoCEdBB1h8DVH4GnV9lChoBkdATvYn+hoM8mgHTS4IaAhHQQdYxPHDJlt1fZQoaAZHQE6nUgB91EFoB00SCWgIR0EHWSB2RA8kdX2UKGgGR8BAiPES/TLGaAdNjApoCEdBB1mUTX6InHV9lChoBkdAUiROafBeomgHTYsEaAhHQQdZwrFCLMt1fZQoaAZHwGPkRptaY/poB02rBmgIR0EHWgn0voNedX2UKGgGR0AFEqBmPHT7aAdNjApoCEdBB1p1QVTJhnV9lChoBkdAUCdhnanJk2gHTZcBaAhHQQdagA1+iJx1fZQoaAZHwFK31qWTouBoB03CBmgIR0EHWsKZd4VzdX2UKGgGR8BUTNF8XvYwaAdNmQhoCEdBB1sU1V7x/nV9lChoBkdAUjj7N0NjLGgHTVEDaAhHQQdbNE9eyAx1fZQoaAZHwBZkmICU5dZoB02MCmgIR0EHW5sR/3FldX2UKGgGR8BXK/GQ0XP7aAdNQwpoCEdBB27Ko1WKdnV9lChoBkdAGuI065oXbmgHTYwKaAhHQQdvMWagElp1fZQoaAZHwBJh6fJ3gUFoB02MCmgIR0EHb5OReTmodX2UKGgGR0BXSkt7KJVKaAdNSQJoCEdBB2+hwZTAFnV9lChoBkfAK7zUqhDgImgHTYwKaAhHQQdv/JzdUKl1fZQoaAZHwFHNRPGhmGxoB01QBWgIR0EHcC5s+FDfdX2UKGgGR8BWt6S5iExqaAdNzgNoCEdBB3BMxYV6/3V9lChoBkdASfhxHXmNi2gHTd4HaAhHQQdwllq0tyx1fZQoaAZHwFG2rvb48EFoB03nBGgIR0EHcMTsgEEDdX2UKGgGR0AkjOW0JF9baAdNjApoCEdBB3E2snTiKnV9lChoBkdAVK7g4wRGt2gHTfUFaAhHQQdxbi7cO9Z1fZQoaAZHQEUI+/xlQMxoB00VCGgIR0EHcbo1WjoIdX2UKGgGR8AOWL74zrNXaAdNjApoCEdBB3IaFANXo3V9lChoBkfAB1DAJswcpGgHTYwKaAhHQQdyfWb70nR1fZQoaAZHwDcU6zVtoBdoB02MCmgIR0EHcuLWKuSwdX2UKGgGR0BSaZWzWwu/aAdNcgJoCEdBB3L44moitHV9lChoBkfAQK0B2fTTfGgHTYwKaAhHQQdzYZQ+EAZ1fZQoaAZHQFJir1dxAB1oB022AWgIR0EHc2oGL1mKdX2UKGgGR8AuJ0cOskpraAdNjApoCEdBB3PVYjt5U3V9lChoBkfAU8nmEGqxT2gHTcsEaAhHQQd0BYg9Net1fZQoaAZHwEqt+4LCvX9oB02zBmgIR0EHdEUmDlHSdX2UKGgGR0BMD+iaiKziaAdNMwpoCEdBB3SpBs0pE3V9lChoBkfAU9yxfOUt7WgHTVoGaAhHQQd0574/u9h1fZQoaAZHQEw7vUjLSu1oB03LCWgIR0EHdUYnmq5tdX2UKGgGR0ASDpRoAXEZaAdNjApoCEdBB3WtRVOsT3V9lChoBkdAUSicCo0hvGgHTUQDaAhHQQd1yfc5bQl1fZQoaAZHQFTTqDsdDIBoB00gAmgIR0EHddZqYqoZdX2UKGgGR0BSXF4C6pYLaAdN9gFoCEdBB3XlSElE7XV9lChoBkdAAeaLn9vS+mgHTYwKaAhHQQd2RS5EMLF1fZQoaAZHQAGpZfUnXupoB02MCmgIR0EHiYEsLncMdX2UKGgGR0AnD6cAiml7aAdNHQloCEdBB4nboESuhnV9lChoBkdAUmK8nNPgvWgHTbIBaAhHQQeJ5MfukUN1fZQoaAZHwELZ0Dlo11poB02MCmgIR0EHilKSBbwCdX2UKGgGR8BdB39FWn0kaAdNcARoCEdBB4p/nU4JeHV9lChoBkdAULB/LDAJs2gHTcYIaAhHQQeK1/2EkB11fZQoaAZHwEze68xsVL1oB02MCmgIR0EHizslT3qSdX2UKGgGR0AtF+S8rZrYaAdNjApoCEdBB4umICyQgnV9lChoBkdAT4kQTVUdaWgHTQMFaAhHQQeL1x+YMOR1fZQoaAZHQDRKBUaQ3gloB02MCmgIR0EHjDv5ULlWdX2UKGgGR8BR0BEroW56aAdNIARoCEdBB4xj2Jk5InV9lChoBkdAUmv4mCyyEGgHTXwBaAhHQQeMbBfUnXx1fZQoaAZHQFXOL8rI5o5oB03YCWgIR0EHjNFrksBidX2UKGgGR8BT+vAbhm5EaAdNqAZoCEdBB40Vng3tKXV9lChoBkfAHlpbD/EOy2gHTYwKaAhHQQeNfCAiml91fZQoaAZHwF5V1IAfdRBoB00RCWgIR0EHjdWNkOI7dX2UKGgGR0BSHbehwl0HaAdNNQNoCEdBB430Gq7yx3VlLg==" + }, + "ep_success_buffer": { + ":type:": "", + ":serialized:": "gAWVIAAAAAAAAACMC2NvbGxlY3Rpb25zlIwFZGVxdWWUk5QpS2SGlFKULg==" + }, + "_n_updates": 2290, + "observation_space": { + ":type:": "", + ":serialized:": "gAWVmAMAAAAAAACMFGd5bW5hc2l1bS5zcGFjZXMuYm94lIwDQm94lJOUKYGUfZQojAVkdHlwZZSMBW51bXB5lIwFZHR5cGWUk5SMAmY0lImIh5RSlChLA4wBPJROTk5K/////0r/////SwB0lGKMBl9zaGFwZZRLHoWUjANsb3eUjBJudW1weS5jb3JlLm51bWVyaWOUjAtfZnJvbWJ1ZmZlcpSTlCiWeAAAAAAAAAAAAIC/AACAvwAAgL8AAIC/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIC/AACAvwAAgL8AAIC/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUaAtLHoWUjAFDlHSUUpSMDWJvdW5kZWRfYmVsb3eUaBMolh4AAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBlGgIjAJiMZSJiIeUUpQoSwOMAXyUTk5OSv////9K/////0sAdJRiSx6FlGgWdJRSlIwEaGlnaJRoEyiWeAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AAAAQAAAQEEAAIA/AACAPwAAgD8AAIA/AABAQAAAMEEAAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AAAAQAAAQEEAAIA/AACAPwAAgD8AAIA/AABAQAAAMEGUaAtLHoWUaBZ0lFKUjA1ib3VuZGVkX2Fib3ZllGgTKJYeAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAZRoHUsehZRoFnSUUpSMCGxvd19yZXBylIx6Wy0xLiAtMS4gLTEuIC0xLiAgMC4gIDAuICAwLiAgMC4gIDAuICAwLiAgMC4gIDAuICAwLiAgMC4gIDAuIC0xLiAtMS4gLTEuCiAtMS4gIDAuICAwLiAgMC4gIDAuICAwLiAgMC4gIDAuICAwLiAgMC4gIDAuICAwLl2UjAloaWdoX3JlcHKUjHpbIDEuICAxLiAgMS4gIDEuICAxLiAgMS4gIDEuICAyLiAxMi4gIDEuICAxLiAgMS4gIDEuICAzLiAxMS4gIDEuICAxLiAgMS4KICAxLiAgMS4gIDEuICAxLiAgMi4gMTIuICAxLiAgMS4gIDEuICAxLiAgMy4gMTEuXZSMCl9ucF9yYW5kb22UTnViLg==", + "dtype": "float32", + "_shape": [ + 30 + ], + "low": "[-1. -1. -1. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. -1. -1.\n -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]", + "bounded_below": "[ True True True True True True True True True True True True\n True True True True True True True True True True True True\n True True True True True True]", + "high": "[ 1. 1. 1. 1. 1. 1. 1. 2. 12. 1. 1. 1. 1. 3. 11. 1. 1. 1.\n 1. 1. 1. 1. 2. 12. 1. 1. 1. 1. 3. 11.]", + "bounded_above": "[ True True True True True True True True True True True True\n True True True True True True True True True True True True\n True True True True True True]", + "low_repr": "[-1. -1. -1. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. -1. -1.\n -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]", + "high_repr": "[ 1. 1. 1. 1. 1. 1. 1. 2. 12. 1. 1. 1. 1. 3. 11. 1. 1. 1.\n 1. 1. 1. 1. 2. 12. 1. 1. 1. 1. 3. 11.]", + "_np_random": null + }, + "action_space": { + ":type:": "", + ":serialized:": "gAWVpgIAAAAAAACMFGd5bW5hc2l1bS5zcGFjZXMuYm94lIwDQm94lJOUKYGUfZQojAVkdHlwZZSMBW51bXB5lIwFZHR5cGWUk5SMAmY0lImIh5RSlChLA4wBPJROTk5K/////0r/////SwB0lGKMBl9zaGFwZZRLCoWUjANsb3eUjBJudW1weS5jb3JlLm51bWVyaWOUjAtfZnJvbWJ1ZmZlcpSTlCiWKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlGgLSwqFlIwBQ5R0lFKUjA1ib3VuZGVkX2JlbG93lGgTKJYKAAAAAAAAAAEBAQEBAQEBAQGUaAiMAmIxlImIh5RSlChLA4wBfJROTk5K/////0r/////SwB0lGJLCoWUaBZ0lFKUjARoaWdolGgTKJYoAAAAAAAAAAAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD+UaAtLCoWUaBZ0lFKUjA1ib3VuZGVkX2Fib3ZllGgTKJYKAAAAAAAAAAEBAQEBAQEBAQGUaB1LCoWUaBZ0lFKUjAhsb3dfcmVwcpSMAzAuMJSMCWhpZ2hfcmVwcpSMAzEuMJSMCl9ucF9yYW5kb22UjBRudW1weS5yYW5kb20uX3BpY2tsZZSMEF9fZ2VuZXJhdG9yX2N0b3KUk5SMBVBDRzY0lGgyjBRfX2JpdF9nZW5lcmF0b3JfY3RvcpSTlIaUUpR9lCiMDWJpdF9nZW5lcmF0b3KUjAVQQ0c2NJSMBXN0YXRllH2UKGg9ihEEm0A0C/4lUCLrKLamm7aqAIwDaW5jlIoQjy2GWehVOrQ6X9ZMP3sSWXWMCmhhc191aW50MzKUSwCMCHVpbnRlZ2VylEsAdWJ1Yi4=", + "dtype": "float32", + "_shape": [ + 10 + ], + "low": "[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]", + "bounded_below": "[ True True True True True True True True True True]", + "high": "[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]", + "bounded_above": "[ True True True True True True True True True True]", + "low_repr": "0.0", + "high_repr": "1.0", + "_np_random": "Generator(PCG64)" + }, + "n_envs": 1, + "n_steps": 54000, + "gamma": 0.99, + "gae_lambda": 0.95, + "ent_coef": 0.05, + "vf_coef": 0.5, + "max_grad_norm": 0.5, + "rollout_buffer_class": null, + "rollout_buffer_kwargs": {}, + "batch_size": 16, + "n_epochs": 10, + "clip_range": { + ":type:": "", + ":serialized:": "gAWVUAQAAAAAAACMF2Nsb3VkcGlja2xlLmNsb3VkcGlja2xllIwOX21ha2VfZnVuY3Rpb26Uk5QoaACMDV9idWlsdGluX3R5cGWUk5SMCENvZGVUeXBllIWUUpQoSwFLAEsASwFLBUsTQzSVAZcAdAEAAAAAAAAAAAAAAgCJAXwApgEAAKsBAAAAAAAAAACmAQAAqwEAAAAAAAAAAFMAlE6FlIwFZmxvYXSUhZSMEnByb2dyZXNzX3JlbWFpbmluZ5SFlIxhL2hvbWUvbWFnbnVzbzcvbWluaWZvcmdlMy9lbnZzL3Jscy9saWIvcHl0aG9uMy4xMS9zaXRlLXBhY2thZ2VzL3N0YWJsZV9iYXNlbGluZXMzL2NvbW1vbi91dGlscy5weZSMCDxsYW1iZGE+lIwhZ2V0X3NjaGVkdWxlX2ZuLjxsb2NhbHM+LjxsYW1iZGE+lEtiQxr4gAClZahOqE7QO03RLE7ULE7RJk/UJk+AAJRDAJSMDnZhbHVlX3NjaGVkdWxllIWUKXSUUpR9lCiMC19fcGFja2FnZV9flIwYc3RhYmxlX2Jhc2VsaW5lczMuY29tbW9ulIwIX19uYW1lX1+UjB5zdGFibGVfYmFzZWxpbmVzMy5jb21tb24udXRpbHOUjAhfX2ZpbGVfX5SMYS9ob21lL21hZ251c283L21pbmlmb3JnZTMvZW52cy9ybHMvbGliL3B5dGhvbjMuMTEvc2l0ZS1wYWNrYWdlcy9zdGFibGVfYmFzZWxpbmVzMy9jb21tb24vdXRpbHMucHmUdU5OaACMEF9tYWtlX2VtcHR5X2NlbGyUk5QpUpSFlHSUUpRoAIwSX2Z1bmN0aW9uX3NldHN0YXRllJOUaCN9lH2UKGgajAg8bGFtYmRhPpSMDF9fcXVhbG5hbWVfX5SMIWdldF9zY2hlZHVsZV9mbi48bG9jYWxzPi48bGFtYmRhPpSMD19fYW5ub3RhdGlvbnNfX5R9lIwOX19rd2RlZmF1bHRzX1+UTowMX19kZWZhdWx0c19flE6MCl9fbW9kdWxlX1+UaBuMB19fZG9jX1+UTowLX19jbG9zdXJlX1+UaACMCl9tYWtlX2NlbGyUk5RoAihoByhLAUsASwBLAUsBSxNDCJUBlwCJAVMAlGgJKYwBX5SFlGgOjARmdW5jlIwZY29uc3RhbnRfZm4uPGxvY2Fscz4uZnVuY5RLhkMI+IAA2A8SiAqUaBKMA3ZhbJSFlCl0lFKUaBdOTmgfKVKUhZR0lFKUaCVoQX2UfZQoaBqMBGZ1bmOUaCmMGWNvbnN0YW50X2ZuLjxsb2NhbHM+LmZ1bmOUaCt9lGgtTmguTmgvaBtoME5oMWgzRz/JmZmZmZmahZRSlIWUjBdfY2xvdWRwaWNrbGVfc3VibW9kdWxlc5RdlIwLX19nbG9iYWxzX1+UfZR1hpSGUjCFlFKUhZRoSl2UaEx9lHWGlIZSMC4=" + }, + "clip_range_vf": null, + "normalize_advantage": true, + "target_kl": null, + "lr_schedule": { + ":type:": "", + ":serialized:": "gAWVUAQAAAAAAACMF2Nsb3VkcGlja2xlLmNsb3VkcGlja2xllIwOX21ha2VfZnVuY3Rpb26Uk5QoaACMDV9idWlsdGluX3R5cGWUk5SMCENvZGVUeXBllIWUUpQoSwFLAEsASwFLBUsTQzSVAZcAdAEAAAAAAAAAAAAAAgCJAXwApgEAAKsBAAAAAAAAAACmAQAAqwEAAAAAAAAAAFMAlE6FlIwFZmxvYXSUhZSMEnByb2dyZXNzX3JlbWFpbmluZ5SFlIxhL2hvbWUvbWFnbnVzbzcvbWluaWZvcmdlMy9lbnZzL3Jscy9saWIvcHl0aG9uMy4xMS9zaXRlLXBhY2thZ2VzL3N0YWJsZV9iYXNlbGluZXMzL2NvbW1vbi91dGlscy5weZSMCDxsYW1iZGE+lIwhZ2V0X3NjaGVkdWxlX2ZuLjxsb2NhbHM+LjxsYW1iZGE+lEtiQxr4gAClZahOqE7QO03RLE7ULE7RJk/UJk+AAJRDAJSMDnZhbHVlX3NjaGVkdWxllIWUKXSUUpR9lCiMC19fcGFja2FnZV9flIwYc3RhYmxlX2Jhc2VsaW5lczMuY29tbW9ulIwIX19uYW1lX1+UjB5zdGFibGVfYmFzZWxpbmVzMy5jb21tb24udXRpbHOUjAhfX2ZpbGVfX5SMYS9ob21lL21hZ251c283L21pbmlmb3JnZTMvZW52cy9ybHMvbGliL3B5dGhvbjMuMTEvc2l0ZS1wYWNrYWdlcy9zdGFibGVfYmFzZWxpbmVzMy9jb21tb24vdXRpbHMucHmUdU5OaACMEF9tYWtlX2VtcHR5X2NlbGyUk5QpUpSFlHSUUpRoAIwSX2Z1bmN0aW9uX3NldHN0YXRllJOUaCN9lH2UKGgajAg8bGFtYmRhPpSMDF9fcXVhbG5hbWVfX5SMIWdldF9zY2hlZHVsZV9mbi48bG9jYWxzPi48bGFtYmRhPpSMD19fYW5ub3RhdGlvbnNfX5R9lIwOX19rd2RlZmF1bHRzX1+UTowMX19kZWZhdWx0c19flE6MCl9fbW9kdWxlX1+UaBuMB19fZG9jX1+UTowLX19jbG9zdXJlX1+UaACMCl9tYWtlX2NlbGyUk5RoAihoByhLAUsASwBLAUsBSxNDCJUBlwCJAVMAlGgJKYwBX5SFlGgOjARmdW5jlIwZY29uc3RhbnRfZm4uPGxvY2Fscz4uZnVuY5RLhkMI+IAA2A8SiAqUaBKMA3ZhbJSFlCl0lFKUaBdOTmgfKVKUhZR0lFKUaCVoQX2UfZQoaBqMBGZ1bmOUaCmMGWNvbnN0YW50X2ZuLjxsb2NhbHM+LmZ1bmOUaCt9lGgtTmguTmgvaBtoME5oMWgzRz8zqSowVTJhhZRSlIWUjBdfY2xvdWRwaWNrbGVfc3VibW9kdWxlc5RdlIwLX19nbG9iYWxzX1+UfZR1hpSGUjCFlFKUhZRoSl2UaEx9lHWGlIZSMC4=" + } +} \ No newline at end of file diff --git a/rl-model/policy.optimizer.pth b/rl-model/policy.optimizer.pth new file mode 100644 index 0000000..013a940 Binary files /dev/null and b/rl-model/policy.optimizer.pth differ diff --git a/rl-model/policy.pth b/rl-model/policy.pth new file mode 100644 index 0000000..6e2f31d Binary files /dev/null and b/rl-model/policy.pth differ diff --git a/rl-model/pytorch_variables.pth b/rl-model/pytorch_variables.pth new file mode 100644 index 0000000..b3e5f5c Binary files /dev/null and b/rl-model/pytorch_variables.pth differ diff --git a/rl-model/system_info.txt b/rl-model/system_info.txt new file mode 100644 index 0000000..09e6dd4 --- /dev/null +++ b/rl-model/system_info.txt @@ -0,0 +1,9 @@ +- OS: Linux-5.4.0-200-generic-x86_64-with-glibc2.31 # 220-Ubuntu SMP Fri Sep 27 13:19:16 UTC 2024 +- Python: 3.11.11 +- Stable-Baselines3: 2.5.0 +- PyTorch: 2.4.1+cu121 +- GPU Enabled: True +- Numpy: 1.26.4 +- Cloudpickle: 3.1.1 +- Gymnasium: 1.0.0 +- OpenAI Gym: 0.25.2