diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e7eeb1547..83e676be2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. mac/linux/windows] - - Version [e.g. 0.3.0] + - Version [e.g. 0.3.1] **Additional context** Add any other context about the problem here. diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e9e24fa4..16502fa97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10.0) -project(Griddly VERSION 0.3.0) +project(Griddly VERSION 0.3.1) set(BINARY ${CMAKE_PROJECT_NAME}) diff --git a/bindings/python.cpp b/bindings/python.cpp index 2ec41e27f..9e94db8a9 100644 --- a/bindings/python.cpp +++ b/bindings/python.cpp @@ -12,7 +12,7 @@ namespace griddly { PYBIND11_MODULE(python_griddly, m) { m.doc() = "Griddly python bindings"; - m.attr("version") = "0.3.0"; + m.attr("version") = "0.3.1"; #ifndef NDEBUG spdlog::set_level(spdlog::level::debug); diff --git a/docs/conf.py b/docs/conf.py index c74a68984..d37ad1189 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Chris Bamford' # The full version, including alpha/beta/rc tags -release = '0.3.0' +release = '0.3.1' # -- General configuration --------------------------------------------------- diff --git a/docs/games/Bait/index.rst b/docs/games/Bait/index.rst index d1a221974..227715257 100644 --- a/docs/games/Bait/index.rst +++ b/docs/games/Bait/index.rst @@ -101,13 +101,13 @@ Objects - mushroom - wall * - Map Char -> - - A - - 0 - - 1 - - k - - g - - m - - w + - `A` + - `0` + - `1` + - `k` + - `g` + - `m` + - `w` * - Vector - .. image:: img/Bait-tile-avatar-Vector.png - .. image:: img/Bait-tile-hole-Vector.png diff --git a/docs/games/Bait_With_Keys/index.rst b/docs/games/Bait_With_Keys/index.rst index aa88eda39..012a92b5c 100644 --- a/docs/games/Bait_With_Keys/index.rst +++ b/docs/games/Bait_With_Keys/index.rst @@ -101,13 +101,13 @@ Objects - mushroom - wall * - Map Char -> - - A - - 0 - - 1 - - k - - g - - m - - w + - `A` + - `0` + - `1` + - `k` + - `g` + - `m` + - `w` * - Vector - .. image:: img/Bait_With_Keys-tile-avatar-Vector.png - .. image:: img/Bait_With_Keys-tile-hole-Vector.png diff --git a/docs/games/Butterflies_and_Spiders/index.rst b/docs/games/Butterflies_and_Spiders/index.rst index f6936a6be..c23443524 100644 --- a/docs/games/Butterflies_and_Spiders/index.rst +++ b/docs/games/Butterflies_and_Spiders/index.rst @@ -147,11 +147,11 @@ Objects - spider - catcher * - Map Char -> - - w - - 1 - - 0 - - S - - A + - `w` + - `1` + - `0` + - `S` + - `A` * - Vector - .. image:: img/Butterflies_and_Spiders-tile-wall-Vector.png - .. image:: img/Butterflies_and_Spiders-tile-butterfly-Vector.png diff --git a/docs/games/Clusters/index.rst b/docs/games/Clusters/index.rst index 2f588d4bc..e54806163 100644 --- a/docs/games/Clusters/index.rst +++ b/docs/games/Clusters/index.rst @@ -103,15 +103,15 @@ Objects - blue_box - blue_block * - Map Char -> - - A - - w - - h - - 2 - - b - - 3 - - c - - 1 - - a + - `A` + - `w` + - `h` + - `2` + - `b` + - `3` + - `c` + - `1` + - `a` * - Vector - .. image:: img/Clusters-tile-avatar-Vector.png - .. image:: img/Clusters-tile-wall-Vector.png diff --git a/docs/games/Cook_Me_Pasta/index.rst b/docs/games/Cook_Me_Pasta/index.rst index cc2a8b8b4..8aff5f574 100644 --- a/docs/games/Cook_Me_Pasta/index.rst +++ b/docs/games/Cook_Me_Pasta/index.rst @@ -111,14 +111,14 @@ Objects - tomato - tuna * - Map Char -> - - A - - w - - k - - l - - b - - p - - o - - t + - `A` + - `w` + - `k` + - `l` + - `b` + - `p` + - `o` + - `t` * - Vector - .. image:: img/Cook_Me_Pasta-tile-avatar-Vector.png - .. image:: img/Cook_Me_Pasta-tile-wall-Vector.png diff --git a/docs/games/Doggo/index.rst b/docs/games/Doggo/index.rst index e5da3e086..0f79d6a0f 100644 --- a/docs/games/Doggo/index.rst +++ b/docs/games/Doggo/index.rst @@ -97,9 +97,9 @@ Objects - stick - doggo * - Map Char -> - - W - - g - - A + - `W` + - `g` + - `A` * - Vector - .. image:: img/Doggo-tile-wall-Vector.png - .. image:: img/Doggo-tile-stick-Vector.png diff --git a/docs/games/Drunk_Dwarf/index.rst b/docs/games/Drunk_Dwarf/index.rst index 98dfb094e..e192335c0 100644 --- a/docs/games/Drunk_Dwarf/index.rst +++ b/docs/games/Drunk_Dwarf/index.rst @@ -103,15 +103,15 @@ Objects - bookshelf - key * - Map Char -> - - W - - g - - A - - D - - d - - c - - t - - b - - k + - `W` + - `g` + - `A` + - `D` + - `d` + - `c` + - `t` + - `b` + - `k` * - Vector - .. image:: img/Drunk_Dwarf-tile-wall-Vector.png - .. image:: img/Drunk_Dwarf-tile-coffin_bed-Vector.png diff --git a/docs/games/Eyeball/index.rst b/docs/games/Eyeball/index.rst index 3586e1d96..79a08abce 100644 --- a/docs/games/Eyeball/index.rst +++ b/docs/games/Eyeball/index.rst @@ -61,9 +61,9 @@ Objects - eye_drops - eyeball * - Map Char -> - - W - - g - - A + - `W` + - `g` + - `A` * - Vector - .. image:: img/Eyeball-tile-wall-Vector.png - .. image:: img/Eyeball-tile-eye_drops-Vector.png diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png index f75002878..365e536a9 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-level-Block2D-1.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png index b20750d00..c0fda0b40 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-harvester-Sprite2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png index 0c3816092..88f120874 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-puncher-Sprite2D.png differ diff --git a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png index 6cd64873a..e047db70c 100644 Binary files a/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png and b/docs/games/GriddlyRTS/img/GriddlyRTS-tile-pusher-Sprite2D.png differ diff --git a/docs/games/GriddlyRTS/index.rst b/docs/games/GriddlyRTS/index.rst index 1ca4024d1..ba7f11d35 100644 --- a/docs/games/GriddlyRTS/index.rst +++ b/docs/games/GriddlyRTS/index.rst @@ -90,13 +90,13 @@ Objects - movable_wall - base * - Map Char -> - - M - - H - - P - - p - - W - - w - - B + - `M` + - `H` + - `P` + - `p` + - `W` + - `w` + - `B` * - Vector - .. image:: img/GriddlyRTS-tile-minerals-Vector.png - .. image:: img/GriddlyRTS-tile-harvester-Vector.png diff --git a/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-healer-Sprite2D.png b/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-healer-Sprite2D.png index 407587998..19b1c435f 100644 Binary files a/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-healer-Sprite2D.png and b/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-healer-Sprite2D.png differ diff --git a/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-warrior-Sprite2D.png b/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-warrior-Sprite2D.png index c4a859553..4c555b33b 100644 Binary files a/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-warrior-Sprite2D.png and b/docs/games/Heal_Or_Die/img/Heal_Or_Die-tile-warrior-Sprite2D.png differ diff --git a/docs/games/Heal_Or_Die/index.rst b/docs/games/Heal_Or_Die/index.rst index ad4b25d7e..8cd675556 100644 --- a/docs/games/Heal_Or_Die/index.rst +++ b/docs/games/Heal_Or_Die/index.rst @@ -80,10 +80,10 @@ Objects - healer - warrior * - Map Char -> - - M - - H - - h - - w + - `M` + - `H` + - `h` + - `w` * - Vector - .. image:: img/Heal_Or_Die-tile-mountain-Vector.png - .. image:: img/Heal_Or_Die-tile-hole-Vector.png diff --git a/docs/games/Kill_The_King/img/Kill_The_King-level-Sprite2D-0.png b/docs/games/Kill_The_King/img/Kill_The_King-level-Sprite2D-0.png index f0853f560..a56f8e9db 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-level-Sprite2D-0.png and b/docs/games/Kill_The_King/img/Kill_The_King-level-Sprite2D-0.png differ diff --git a/docs/games/Kill_The_King/img/Kill_The_King-tile-archer-Sprite2D.png b/docs/games/Kill_The_King/img/Kill_The_King-tile-archer-Sprite2D.png index ff200345c..bde64c8e3 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-tile-archer-Sprite2D.png and b/docs/games/Kill_The_King/img/Kill_The_King-tile-archer-Sprite2D.png differ diff --git a/docs/games/Kill_The_King/img/Kill_The_King-tile-forest-Sprite2D.png b/docs/games/Kill_The_King/img/Kill_The_King-tile-forest-Sprite2D.png index 3c956d05d..482908b11 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-tile-forest-Sprite2D.png and b/docs/games/Kill_The_King/img/Kill_The_King-tile-forest-Sprite2D.png differ diff --git a/docs/games/Kill_The_King/img/Kill_The_King-tile-healer-Sprite2D.png b/docs/games/Kill_The_King/img/Kill_The_King-tile-healer-Sprite2D.png index 407587998..faa743f3a 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-tile-healer-Sprite2D.png and b/docs/games/Kill_The_King/img/Kill_The_King-tile-healer-Sprite2D.png differ diff --git a/docs/games/Kill_The_King/img/Kill_The_King-tile-king-Sprite2D.png b/docs/games/Kill_The_King/img/Kill_The_King-tile-king-Sprite2D.png index bc99cebfa..a6dc009ef 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-tile-king-Sprite2D.png and b/docs/games/Kill_The_King/img/Kill_The_King-tile-king-Sprite2D.png differ diff --git a/docs/games/Kill_The_King/img/Kill_The_King-tile-warrior-Sprite2D.png b/docs/games/Kill_The_King/img/Kill_The_King-tile-warrior-Sprite2D.png index c4a859553..4c555b33b 100644 Binary files a/docs/games/Kill_The_King/img/Kill_The_King-tile-warrior-Sprite2D.png and b/docs/games/Kill_The_King/img/Kill_The_King-tile-warrior-Sprite2D.png differ diff --git a/docs/games/Kill_The_King/index.rst b/docs/games/Kill_The_King/index.rst index 91ea9867b..5ddf0bebb 100644 --- a/docs/games/Kill_The_King/index.rst +++ b/docs/games/Kill_The_King/index.rst @@ -73,14 +73,14 @@ Objects - archer - king * - Map Char -> - - M - - W - - F - - H - - h - - w - - a - - k + - `M` + - `W` + - `F` + - `H` + - `h` + - `w` + - `a` + - `k` * - Vector - .. image:: img/Kill_The_King-tile-mountain-Vector.png - .. image:: img/Kill_The_King-tile-water-Vector.png diff --git a/docs/games/Labyrinth/index.rst b/docs/games/Labyrinth/index.rst index fde613a2a..fbac5176f 100644 --- a/docs/games/Labyrinth/index.rst +++ b/docs/games/Labyrinth/index.rst @@ -98,10 +98,10 @@ Objects - trap - wall * - Map Char -> - - A - - x - - t - - w + - `A` + - `x` + - `t` + - `w` * - Vector - .. image:: img/Labyrinth-tile-avatar-Vector.png - .. image:: img/Labyrinth-tile-exit-Vector.png diff --git a/docs/games/Partially_Observable_Bait/index.rst b/docs/games/Partially_Observable_Bait/index.rst index b149ded78..5fccd7e1d 100644 --- a/docs/games/Partially_Observable_Bait/index.rst +++ b/docs/games/Partially_Observable_Bait/index.rst @@ -101,13 +101,13 @@ Objects - mushroom - wall * - Map Char -> - - A - - 0 - - 1 - - k - - g - - m - - w + - `A` + - `0` + - `1` + - `k` + - `g` + - `m` + - `w` * - Vector - .. image:: img/Partially_Observable_Bait-tile-avatar-Vector.png - .. image:: img/Partially_Observable_Bait-tile-hole-Vector.png diff --git a/docs/games/Partially_Observable_Clusters/index.rst b/docs/games/Partially_Observable_Clusters/index.rst index 6a9a3f7f8..d9be2d8d0 100644 --- a/docs/games/Partially_Observable_Clusters/index.rst +++ b/docs/games/Partially_Observable_Clusters/index.rst @@ -103,15 +103,15 @@ Objects - blue_box - blue_block * - Map Char -> - - A - - w - - h - - 2 - - b - - 3 - - c - - 1 - - a + - `A` + - `w` + - `h` + - `2` + - `b` + - `3` + - `c` + - `1` + - `a` * - Vector - .. image:: img/Partially_Observable_Clusters-tile-avatar-Vector.png - .. image:: img/Partially_Observable_Clusters-tile-wall-Vector.png diff --git a/docs/games/Partially_Observable_Cook_Me_Pasta/index.rst b/docs/games/Partially_Observable_Cook_Me_Pasta/index.rst index 115b86ed2..e48a5b551 100644 --- a/docs/games/Partially_Observable_Cook_Me_Pasta/index.rst +++ b/docs/games/Partially_Observable_Cook_Me_Pasta/index.rst @@ -111,14 +111,14 @@ Objects - tomato - tuna * - Map Char -> - - A - - w - - k - - l - - b - - p - - o - - t + - `A` + - `w` + - `k` + - `l` + - `b` + - `p` + - `o` + - `t` * - Vector - .. image:: img/Partially_Observable_Cook_Me_Pasta-tile-avatar-Vector.png - .. image:: img/Partially_Observable_Cook_Me_Pasta-tile-wall-Vector.png diff --git a/docs/games/Partially_Observable_Labyrinth/index.rst b/docs/games/Partially_Observable_Labyrinth/index.rst index 42a80cae4..060c7494b 100644 --- a/docs/games/Partially_Observable_Labyrinth/index.rst +++ b/docs/games/Partially_Observable_Labyrinth/index.rst @@ -98,10 +98,10 @@ Objects - trap - wall * - Map Char -> - - A - - x - - t - - w + - `A` + - `x` + - `t` + - `w` * - Vector - .. image:: img/Partially_Observable_Labyrinth-tile-avatar-Vector.png - .. image:: img/Partially_Observable_Labyrinth-tile-exit-Vector.png diff --git a/docs/games/Partially_Observable_Sokoban_-_2/index.rst b/docs/games/Partially_Observable_Sokoban_-_2/index.rst index 9c6e828ef..ef1a9055a 100644 --- a/docs/games/Partially_Observable_Sokoban_-_2/index.rst +++ b/docs/games/Partially_Observable_Sokoban_-_2/index.rst @@ -99,11 +99,11 @@ Objects - hole - avatar * - Map Char -> - - b - - f - - w - - h - - A + - `b` + - `f` + - `w` + - `h` + - `A` * - Vector - .. image:: img/Partially_Observable_Sokoban_-_2-tile-box-Vector.png - .. image:: img/Partially_Observable_Sokoban_-_2-tile-box_in_place-Vector.png diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-0.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-0.png new file mode 100644 index 000000000..9ce3e2c03 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-0.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png new file mode 100644 index 000000000..0e0d2779e Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-1.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-2.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-2.png new file mode 100644 index 000000000..08b80407c Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Block2D-2.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-0.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-0.png new file mode 100644 index 000000000..335547d1c Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-0.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-1.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-1.png new file mode 100644 index 000000000..ae3e181e3 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-1.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-2.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-2.png new file mode 100644 index 000000000..94fb66b95 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Sprite2D-2.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-0.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-0.png new file mode 100644 index 000000000..a53b664ae Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-0.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-1.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-1.png new file mode 100644 index 000000000..c85c5cd9d Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-1.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-2.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-2.png new file mode 100644 index 000000000..c499a8fe1 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-level-Vector-2.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Block2D.png new file mode 100644 index 000000000..579c53d56 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Sprite2D.png new file mode 100644 index 000000000..f1dcf9a8e Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Vector.png new file mode 100644 index 000000000..3b74da918 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-attack_fire-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Block2D.png new file mode 100644 index 000000000..0e34ebaef Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Sprite2D.png new file mode 100644 index 000000000..408707572 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Vector.png new file mode 100644 index 000000000..d8a72ac84 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-avatar-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Block2D.png new file mode 100644 index 000000000..fdf5b422e Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Sprite2D.png new file mode 100644 index 000000000..cd719e795 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Vector.png new file mode 100644 index 000000000..09f573db4 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-goal-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Block2D.png new file mode 100644 index 000000000..511aa028e Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Sprite2D.png new file mode 100644 index 000000000..cb457e470 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Vector.png new file mode 100644 index 000000000..95e86ee99 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-key-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Block2D.png new file mode 100644 index 000000000..5e37a1188 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Sprite2D.png new file mode 100644 index 000000000..8abc0c5fd Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Vector.png new file mode 100644 index 000000000..37ac5d892 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-spider-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Block2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Block2D.png new file mode 100644 index 000000000..62a2c51fd Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Block2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Sprite2D.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Sprite2D.png new file mode 100644 index 000000000..677f7693f Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Sprite2D.png differ diff --git a/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Vector.png b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Vector.png new file mode 100644 index 000000000..0ae910660 Binary files /dev/null and b/docs/games/Partially_Observable_Zelda/img/Partially_Observable_Zelda-tile-wall-Vector.png differ diff --git a/docs/games/Partially_Observable_Zelda/index.rst b/docs/games/Partially_Observable_Zelda/index.rst new file mode 100644 index 000000000..d3df8fb9a --- /dev/null +++ b/docs/games/Partially_Observable_Zelda/index.rst @@ -0,0 +1,489 @@ +Partially Observable Zelda +========================== + +Description +------------- + +A port of the GVGAI game "Zelda", but partially observable. Pick up keys to reach doors and avoid enemies. + +Levels +--------- + +.. list-table:: Levels + :header-rows: 1 + + * - + - Vector + - Sprite2D + - Block2D + * - .. list-table:: + + * - Level ID + - 0 + * - Size + - 13x9 + - .. thumbnail:: img/Partially_Observable_Zelda-level-Vector-0.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Sprite2D-0.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Block2D-0.png + * - .. list-table:: + + * - Level ID + - 1 + * - Size + - 15x16 + - .. thumbnail:: img/Partially_Observable_Zelda-level-Vector-1.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Sprite2D-1.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Block2D-1.png + * - .. list-table:: + + * - Level ID + - 2 + * - Size + - 30x9 + - .. thumbnail:: img/Partially_Observable_Zelda-level-Vector-2.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Sprite2D-2.png + - .. thumbnail:: img/Partially_Observable_Zelda-level-Block2D-2.png + +Code Example +------------ + +The most basic way to create a Griddly Gym Environment. Defaults to level 0 and SPRITE_2D rendering. + +.. code-block:: python + + + import gym + import griddly + + if __name__ == '__main__': + + env = gym.make('GDY-Partially-Observable-Zelda-v0') + env.reset() + + # Replace with your own control algorithm! + for s in range(1000): + obs, reward, done, info = env.step(env.action_space.sample()) + env.render() # Renders the environment from the perspective of a single player + + env.render(observer='global') # Renders the entire environment + + +Objects +------- + +.. list-table:: Tiles + :header-rows: 2 + + * - Name -> + - avatar + - attack_fire + - key + - goal + - spider + - wall + * - Map Char -> + - `A` + - `x` + - `+` + - `g` + - `3` + - `w` + * - Vector + - .. image:: img/Partially_Observable_Zelda-tile-avatar-Vector.png + - .. image:: img/Partially_Observable_Zelda-tile-attack_fire-Vector.png + - .. image:: img/Partially_Observable_Zelda-tile-key-Vector.png + - .. image:: img/Partially_Observable_Zelda-tile-goal-Vector.png + - .. image:: img/Partially_Observable_Zelda-tile-spider-Vector.png + - .. image:: img/Partially_Observable_Zelda-tile-wall-Vector.png + * - Sprite2D + - .. image:: img/Partially_Observable_Zelda-tile-avatar-Sprite2D.png + - .. image:: img/Partially_Observable_Zelda-tile-attack_fire-Sprite2D.png + - .. image:: img/Partially_Observable_Zelda-tile-key-Sprite2D.png + - .. image:: img/Partially_Observable_Zelda-tile-goal-Sprite2D.png + - .. image:: img/Partially_Observable_Zelda-tile-spider-Sprite2D.png + - .. image:: img/Partially_Observable_Zelda-tile-wall-Sprite2D.png + * - Block2D + - .. image:: img/Partially_Observable_Zelda-tile-avatar-Block2D.png + - .. image:: img/Partially_Observable_Zelda-tile-attack_fire-Block2D.png + - .. image:: img/Partially_Observable_Zelda-tile-key-Block2D.png + - .. image:: img/Partially_Observable_Zelda-tile-goal-Block2D.png + - .. image:: img/Partially_Observable_Zelda-tile-spider-Block2D.png + - .. image:: img/Partially_Observable_Zelda-tile-wall-Block2D.png + + +Actions +------- + +attack +^^^^^^ + +:Relative: The actions are calculated relative to the object being controlled. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - attack front + + +move +^^^^ + +:Relative: The actions are calculated relative to the object being controlled. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Rotate left + * - 2 + - Move forwards + * - 3 + - Rotate right + * - 4 + - Move Backwards + + +random_movement +^^^^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Left + * - 2 + - Up + * - 3 + - Right + * - 4 + - Down + + +remove_sprite +^^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Left + * - 2 + - Up + * - 3 + - Right + * - 4 + - Down + + +YAML +---- + +.. code-block:: YAML + + Version: "0.1" + Environment: + Name: Partially Observable Zelda + Description: A port of the GVGAI game "Zelda", but partially observable. Pick up keys to reach doors and avoid enemies. + Observers: + Sprite2D: + TileSize: 24 + BackgroundTile: gvgai/newset/floor2.png + Player: + Observer: + RotateWithAvatar: true + TrackAvatar: true + Height: 5 + Width: 5 + OffsetX: 0 + OffsetY: 2 + AvatarObject: avatar + Termination: + Win: + - eq: [goal:count, 0] + Lose: + - eq: [avatar:count, 0] + Levels: + - | + wwwwwwwwwwwww + w...........w + w...........w + w.+...A.....w + w...........w + w...........w + w......3....w + w.g.........w + wwwwwwwwwwwww + - | + wwwwwwwwwwwwwww + w.............w + w......w......w + w......w......w + w......w......w + w..3...w..+...w + w......w......w + w......w......w + w.wwwwwwwwwww.w + w.....Aw......w + w......w......w + w......w......w + w......w......w + w......w......w + w...........g.w + wwwwwwwwwwwwwww + - | + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + w........+....3..............w + w............................w + w...A.............3..........w + w............................w + w....................3.......w + w..............wwwwwwwwwwwwwww + w..........................g.w + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + Actions: + # Define action that cannot be controlled by the player. + # (In this case the spider movement) + - Name: random_movement + InputMapping: + Internal: true + Behaviours: + # The gnome and the spider can move into empty space + - Src: + Object: spider + Commands: + - mov: _dest + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: _empty + # The spider will not move into the wall, but it needs to keep moving + - Src: + Object: spider + Commands: + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: [wall, key, goal, spider] + # If the gnome moves into a spider + - Src: + Object: spider + Dst: + Object: avatar + Commands: + - remove: true + - reward: -1 + # remove the recently spawned attack animation sprite + - Name: remove_sprite + InputMapping: + Internal: true + Behaviours: + - Src: + Object: attack_fire + Commands: + - remove: true + Dst: + Object: attack_fire + # Define the move action + - Name: move + InputMapping: + Inputs: + 1: + Description: Rotate left + OrientationVector: [-1, 0] + 2: + Description: Move forwards + OrientationVector: [0, -1] + VectorToDest: [0, -1] + 3: + Description: Rotate right + OrientationVector: [1, 0] + 4: + Description: Move Backwards + VectorToDest: [0, 1] + OrientationVector: [0, -1] + Relative: true + Behaviours: + # Tell the gnome to rotate if it performs an action on itself (Rotate left and Rotate right actions) + - Src: + Object: avatar + Commands: + - rot: _dir + Dst: + Object: avatar + # Only an avatar with a key can win + - Src: + Preconditions: + - eq: [src.has_key, 1] + Object: avatar + Commands: + - reward: 1 + # - decr: has_key + - mov: _dest + # - set_tile: 0 + Dst: + Object: goal + Commands: + - remove: true + # If the gnome moves into a gem object, the stick is removed, triggering a win condition + - Src: + Object: avatar + Commands: + - mov: _dest + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - incr: has_key + - reward: 1 + - set_tile: 1 + Dst: + Object: key + Commands: + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - remove: true + # If the gnome moves into a spider + - Src: + Object: avatar + Commands: + - remove: true + - reward: -1 + Dst: + Object: spider + # The gnome and the spider can move into empty space + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: _empty + - Name: attack + InputMapping: + Inputs: + 1: + Description: attack front + OrientationVector: [ -1, 0 ] + VectorToDest: [-1, 0] + Relative: true + Behaviours: + - Src: + Object: avatar + Commands: + - spawn: attack_fire + Dst: + Object: [spider, _empty] + Commands: + - remove: true + Objects: + - Name: avatar + Z: 3 + MapCharacter: A + Variables: + - Name: has_key + Observers: + Sprite2D: + - Image: gvgai/oryx/swordman1_0.png + - Image: gvgai/oryx/swordmankey1_0.png + Block2D: + - Shape: triangle + Color: [0.0, 0.5, 0.5] + Scale: 0.75 + - Shape: triangle + Color: [0.3, 0.5, 0.2] + Scale: 1.0 + - Name: attack_fire + Z: 1 + InitialActions: + - Action: remove_sprite + Delay: 3 + MapCharacter: x + Observers: + Sprite2D: + - Image: gvgai/oryx/fire1.png + Block2D: + - Shape: square + Color: [1.0, 0.0, 0.0] + Scale: 0.5 + - Name: key + Z: 2 + MapCharacter: "+" + Observers: + Sprite2D: + - Image: gvgai/oryx/key2.png + Block2D: + - Shape: triangle + Color: [0.5, 1.0, 0.5] + Scale: 0.7 + - Name: goal + Z: 2 + MapCharacter: g + Observers: + Sprite2D: + - Image: gvgai/oryx/doorclosed1.png + Block2D: + - Shape: square + Color: [0.0, 0.7, 0.0] + Scale: 0.7 + # - Name: chaser + # Z: 2 + # MapCharacter: "3" + # Observers: + # Sprite2D: + # - Image: gvgai/oryx/skeleton1.png + - Name: spider + Z: 2 + InitialActions: + - Action: random_movement + Delay: 5 + MapCharacter: "3" + Observers: + Sprite2D: + - Image: oryx/oryx_fantasy/avatars/spider1.png + Block2D: + - Shape: triangle + Color: [0.9, 0.1, 0.1] + Scale: 0.5 + - Name: wall + MapCharacter: w + Observers: + Sprite2D: + - TilingMode: WALL_16 + Image: + - gvgai/oryx/wall3_0.png + - gvgai/oryx/wall3_1.png + - gvgai/oryx/wall3_2.png + - gvgai/oryx/wall3_3.png + - gvgai/oryx/wall3_4.png + - gvgai/oryx/wall3_5.png + - gvgai/oryx/wall3_6.png + - gvgai/oryx/wall3_7.png + - gvgai/oryx/wall3_8.png + - gvgai/oryx/wall3_9.png + - gvgai/oryx/wall3_10.png + - gvgai/oryx/wall3_11.png + - gvgai/oryx/wall3_12.png + - gvgai/oryx/wall3_13.png + - gvgai/oryx/wall3_14.png + - gvgai/oryx/wall3_15.png + Block2D: + - Shape: square + Color: [0.7, 0.7, 0.7] + Scale: 1.0 + diff --git a/docs/games/Partially_Observable_Zen_Puzzle/index.rst b/docs/games/Partially_Observable_Zen_Puzzle/index.rst index effc6084d..8e92b0d71 100644 --- a/docs/games/Partially_Observable_Zen_Puzzle/index.rst +++ b/docs/games/Partially_Observable_Zen_Puzzle/index.rst @@ -97,9 +97,9 @@ Objects - ground - rock * - Map Char -> - - A - - g - - r + - `A` + - `g` + - `r` * - Vector - .. image:: img/Partially_Observable_Zen_Puzzle-tile-avatar-Vector.png - .. image:: img/Partially_Observable_Zen_Puzzle-tile-ground-Vector.png diff --git a/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-0.png b/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-0.png index 80c3d03a5..d7de8f5e6 100644 Binary files a/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-0.png and b/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-0.png differ diff --git a/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-1.png b/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-1.png index a71521984..4e92ccf0a 100644 Binary files a/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-1.png and b/docs/games/Push_Mania/img/Push_Mania-level-Sprite2D-1.png differ diff --git a/docs/games/Push_Mania/img/Push_Mania-tile-hole-Sprite2D.png b/docs/games/Push_Mania/img/Push_Mania-tile-hole-Sprite2D.png index 607687709..d4a7ccc74 100644 Binary files a/docs/games/Push_Mania/img/Push_Mania-tile-hole-Sprite2D.png and b/docs/games/Push_Mania/img/Push_Mania-tile-hole-Sprite2D.png differ diff --git a/docs/games/Push_Mania/img/Push_Mania-tile-pusher-Sprite2D.png b/docs/games/Push_Mania/img/Push_Mania-tile-pusher-Sprite2D.png index ac61a81f7..37d47b533 100644 Binary files a/docs/games/Push_Mania/img/Push_Mania-tile-pusher-Sprite2D.png and b/docs/games/Push_Mania/img/Push_Mania-tile-pusher-Sprite2D.png differ diff --git a/docs/games/Push_Mania/index.rst b/docs/games/Push_Mania/index.rst index 4444f72b6..67c10ae09 100644 --- a/docs/games/Push_Mania/index.rst +++ b/docs/games/Push_Mania/index.rst @@ -77,8 +77,8 @@ Objects - hole - pusher * - Map Char -> - - H - - p + - `H` + - `p` * - Vector - .. image:: img/Push_Mania-tile-hole-Vector.png - .. image:: img/Push_Mania-tile-pusher-Vector.png diff --git a/docs/games/Random_butterflies/index.rst b/docs/games/Random_butterflies/index.rst index 4839ffd50..5e5f22e6f 100644 --- a/docs/games/Random_butterflies/index.rst +++ b/docs/games/Random_butterflies/index.rst @@ -148,11 +148,11 @@ Objects - spider - catcher * - Map Char -> - - w - - 1 - - 0 - - S - - A + - `w` + - `1` + - `0` + - `S` + - `A` * - Vector - .. image:: img/Random_butterflies-tile-wall-Vector.png - .. image:: img/Random_butterflies-tile-butterfly-Vector.png diff --git a/docs/games/Sokoban/index.rst b/docs/games/Sokoban/index.rst index 3477cce49..bf98f9af7 100644 --- a/docs/games/Sokoban/index.rst +++ b/docs/games/Sokoban/index.rst @@ -107,10 +107,10 @@ Objects - hole - avatar * - Map Char -> - - b - - w - - h - - A + - `b` + - `w` + - `h` + - `A` * - Vector - .. image:: img/Sokoban-tile-box-Vector.png - .. image:: img/Sokoban-tile-wall-Vector.png diff --git a/docs/games/Sokoban_-_2/index.rst b/docs/games/Sokoban_-_2/index.rst index 9640fa6fc..e3a3cecc0 100644 --- a/docs/games/Sokoban_-_2/index.rst +++ b/docs/games/Sokoban_-_2/index.rst @@ -99,11 +99,11 @@ Objects - hole - avatar * - Map Char -> - - b - - f - - w - - h - - A + - `b` + - `f` + - `w` + - `h` + - `A` * - Vector - .. image:: img/Sokoban_-_2-tile-box-Vector.png - .. image:: img/Sokoban_-_2-tile-box_in_place-Vector.png diff --git a/docs/games/Spider_Nest/index.rst b/docs/games/Spider_Nest/index.rst index b80dd0ba3..856034e95 100644 --- a/docs/games/Spider_Nest/index.rst +++ b/docs/games/Spider_Nest/index.rst @@ -66,12 +66,12 @@ Objects - nest - lava * - Map Char -> - - W - - G - - g - - A - - N - - L + - `W` + - `G` + - `g` + - `A` + - `N` + - `L` * - Vector - .. image:: img/Spider_Nest-tile-wall-Vector.png - .. image:: img/Spider_Nest-tile-spider-Vector.png diff --git a/docs/games/Spiders/index.rst b/docs/games/Spiders/index.rst index 13d45efde..42b046d90 100644 --- a/docs/games/Spiders/index.rst +++ b/docs/games/Spiders/index.rst @@ -104,10 +104,10 @@ Objects - gem - gnome * - Map Char -> - - W - - G - - g - - A + - `W` + - `G` + - `g` + - `A` * - Vector - .. image:: img/Spiders-tile-wall-Vector.png - .. image:: img/Spiders-tile-spider-Vector.png diff --git a/docs/games/Zelda/index.rst b/docs/games/Zelda/index.rst index 81b3910dd..6a89ae685 100644 --- a/docs/games/Zelda/index.rst +++ b/docs/games/Zelda/index.rst @@ -82,12 +82,12 @@ Objects - spider - wall * - Map Char -> - - A - - x - - + - - g - - 3 - - w + - `A` + - `x` + - `+` + - `g` + - `3` + - `w` * - Vector - .. image:: img/Zelda-tile-avatar-Vector.png - .. image:: img/Zelda-tile-attack_fire-Vector.png diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-0.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-0.png new file mode 100644 index 000000000..9ce3e2c03 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-0.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png new file mode 100644 index 000000000..3ff002988 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-1.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-2.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-2.png new file mode 100644 index 000000000..98194c60f Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Block2D-2.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-0.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-0.png new file mode 100644 index 000000000..335547d1c Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-0.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-1.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-1.png new file mode 100644 index 000000000..ea6ee5738 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-1.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-2.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-2.png new file mode 100644 index 000000000..a6c5544d1 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Sprite2D-2.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-0.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-0.png new file mode 100644 index 000000000..a53b664ae Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-0.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-1.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-1.png new file mode 100644 index 000000000..e9dde405b Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-1.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-2.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-2.png new file mode 100644 index 000000000..7073dc2bc Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-level-Vector-2.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Block2D.png new file mode 100644 index 000000000..579c53d56 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Sprite2D.png new file mode 100644 index 000000000..f1dcf9a8e Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Vector.png new file mode 100644 index 000000000..3b74da918 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-attack_fire-Vector.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Block2D.png new file mode 100644 index 000000000..0e34ebaef Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Sprite2D.png new file mode 100644 index 000000000..408707572 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Vector.png new file mode 100644 index 000000000..d8a72ac84 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-avatar-Vector.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Block2D.png new file mode 100644 index 000000000..fdf5b422e Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Sprite2D.png new file mode 100644 index 000000000..cd719e795 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Vector.png new file mode 100644 index 000000000..09f573db4 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-goal-Vector.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Block2D.png new file mode 100644 index 000000000..511aa028e Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Sprite2D.png new file mode 100644 index 000000000..cb457e470 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Vector.png new file mode 100644 index 000000000..95e86ee99 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-key-Vector.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Block2D.png new file mode 100644 index 000000000..5e37a1188 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Sprite2D.png new file mode 100644 index 000000000..8abc0c5fd Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Vector.png new file mode 100644 index 000000000..37ac5d892 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-spider-Vector.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Block2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Block2D.png new file mode 100644 index 000000000..62a2c51fd Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Block2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Sprite2D.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Sprite2D.png new file mode 100644 index 000000000..677f7693f Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Sprite2D.png differ diff --git a/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Vector.png b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Vector.png new file mode 100644 index 000000000..0ae910660 Binary files /dev/null and b/docs/games/Zelda_Sequential/img/Zelda_Sequential-tile-wall-Vector.png differ diff --git a/docs/games/Zelda_Sequential/index.rst b/docs/games/Zelda_Sequential/index.rst new file mode 100644 index 000000000..b746b914e --- /dev/null +++ b/docs/games/Zelda_Sequential/index.rst @@ -0,0 +1,476 @@ +Zelda Sequential +================ + +Description +------------- + +A port of the GVGAI game "Zelda". Pick up keys to reach doors in the correct order and avoid enemies. For example, previously you could go -- key -> door -> door. But now you would need to go -- key -> door --> key --> door. + +Levels +--------- + +.. list-table:: Levels + :header-rows: 1 + + * - + - Vector + - Sprite2D + - Block2D + * - .. list-table:: + + * - Level ID + - 0 + * - Size + - 13x9 + - .. thumbnail:: img/Zelda_Sequential-level-Vector-0.png + - .. thumbnail:: img/Zelda_Sequential-level-Sprite2D-0.png + - .. thumbnail:: img/Zelda_Sequential-level-Block2D-0.png + * - .. list-table:: + + * - Level ID + - 1 + * - Size + - 13x9 + - .. thumbnail:: img/Zelda_Sequential-level-Vector-1.png + - .. thumbnail:: img/Zelda_Sequential-level-Sprite2D-1.png + - .. thumbnail:: img/Zelda_Sequential-level-Block2D-1.png + * - .. list-table:: + + * - Level ID + - 2 + * - Size + - 30x9 + - .. thumbnail:: img/Zelda_Sequential-level-Vector-2.png + - .. thumbnail:: img/Zelda_Sequential-level-Sprite2D-2.png + - .. thumbnail:: img/Zelda_Sequential-level-Block2D-2.png + +Code Example +------------ + +The most basic way to create a Griddly Gym Environment. Defaults to level 0 and SPRITE_2D rendering. + +.. code-block:: python + + + import gym + import griddly + + if __name__ == '__main__': + + env = gym.make('GDY-Zelda-Sequential-v0') + env.reset() + + # Replace with your own control algorithm! + for s in range(1000): + obs, reward, done, info = env.step(env.action_space.sample()) + env.render() # Renders the environment from the perspective of a single player + + env.render(observer='global') # Renders the entire environment + + +Objects +------- + +.. list-table:: Tiles + :header-rows: 2 + + * - Name -> + - avatar + - attack_fire + - key + - goal + - spider + - wall + * - Map Char -> + - `A` + - `x` + - `+` + - `g` + - `3` + - `w` + * - Vector + - .. image:: img/Zelda_Sequential-tile-avatar-Vector.png + - .. image:: img/Zelda_Sequential-tile-attack_fire-Vector.png + - .. image:: img/Zelda_Sequential-tile-key-Vector.png + - .. image:: img/Zelda_Sequential-tile-goal-Vector.png + - .. image:: img/Zelda_Sequential-tile-spider-Vector.png + - .. image:: img/Zelda_Sequential-tile-wall-Vector.png + * - Sprite2D + - .. image:: img/Zelda_Sequential-tile-avatar-Sprite2D.png + - .. image:: img/Zelda_Sequential-tile-attack_fire-Sprite2D.png + - .. image:: img/Zelda_Sequential-tile-key-Sprite2D.png + - .. image:: img/Zelda_Sequential-tile-goal-Sprite2D.png + - .. image:: img/Zelda_Sequential-tile-spider-Sprite2D.png + - .. image:: img/Zelda_Sequential-tile-wall-Sprite2D.png + * - Block2D + - .. image:: img/Zelda_Sequential-tile-avatar-Block2D.png + - .. image:: img/Zelda_Sequential-tile-attack_fire-Block2D.png + - .. image:: img/Zelda_Sequential-tile-key-Block2D.png + - .. image:: img/Zelda_Sequential-tile-goal-Block2D.png + - .. image:: img/Zelda_Sequential-tile-spider-Block2D.png + - .. image:: img/Zelda_Sequential-tile-wall-Block2D.png + + +Actions +------- + +attack +^^^^^^ + +:Relative: The actions are calculated relative to the object being controlled. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - attack front + + +move +^^^^ + +:Relative: The actions are calculated relative to the object being controlled. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Rotate left + * - 2 + - Move forwards + * - 3 + - Rotate right + * - 4 + - Move Backwards + + +random_movement +^^^^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Left + * - 2 + - Up + * - 3 + - Right + * - 4 + - Down + + +remove_sprite +^^^^^^^^^^^^^ + +:Internal: This action can only be called from other actions, not by the player. + +.. list-table:: + :header-rows: 1 + + * - Action Id + - Mapping + * - 1 + - Left + * - 2 + - Up + * - 3 + - Right + * - 4 + - Down + + +YAML +---- + +.. code-block:: YAML + + Version: "0.1" + Environment: + Name: Zelda Sequential + Description: A port of the GVGAI game "Zelda". Pick up keys to reach doors in the correct order and avoid enemies. For example, previously you could go -- key -> door -> door. But now you would need to go -- key -> door --> key --> door. + Observers: + Sprite2D: + TileSize: 24 + BackgroundTile: gvgai/newset/floor2.png + Player: + AvatarObject: avatar + Termination: + Win: + - eq: [goal:count, 0] + Lose: + - eq: [avatar:count, 0] + Levels: + - | + wwwwwwwwwwwww + w...........w + w...........w + w.+...A.....w + w...........w + w...........w + w......3....w + w.g.........w + wwwwwwwwwwwww + - | + wwwwwwwwwwwww + w.....+..+g.w + w.+.w.g.....w + w.....Ag..3.w + w+..+.......w + w....w..+...w + w.........g.w + w.3...+++.+ww + wwwwwwwwwwwww + - | + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + w........+.............g.....w + w............................w + w...A.............3..........w + w............................w + w....................3.......w + w..............wwwwwwwwwwwwwww + w......................+...g.w + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + Actions: + # Define action that cannot be controlled by the player. + # (In this case the spider movement) + - Name: random_movement + InputMapping: + Internal: true + Behaviours: + # The gnome and the spider can move into empty space + - Src: + Object: spider + Commands: + - mov: _dest + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: _empty + # The spider will not move into the wall, but it needs to keep moving + - Src: + Object: spider + Commands: + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: [wall, key, goal, spider] + # If the gnome moves into a spider + - Src: + Object: spider + Dst: + Object: avatar + Commands: + - remove: true + - reward: -1 + # remove the recently spawned attack animation sprite + - Name: remove_sprite + InputMapping: + Internal: true + Behaviours: + - Src: + Object: attack_fire + Commands: + - remove: true + Dst: + Object: attack_fire + # Define the move action + - Name: move + InputMapping: + Inputs: + 1: + Description: Rotate left + OrientationVector: [-1, 0] + 2: + Description: Move forwards + OrientationVector: [0, -1] + VectorToDest: [0, -1] + 3: + Description: Rotate right + OrientationVector: [1, 0] + 4: + Description: Move Backwards + VectorToDest: [0, 1] + OrientationVector: [0, -1] + Relative: true + Behaviours: + # Tell the gnome to rotate if it performs an action on itself (Rotate left and Rotate right actions) + - Src: + Object: avatar + Commands: + - rot: _dir + Dst: + Object: avatar + # Only an avatar with a key can win + - Src: + Preconditions: + - eq: [src.has_key, 1] + Object: avatar + Commands: + - reward: 1 + - decr: has_key + - mov: _dest + - set_tile: 0 + Dst: + Object: goal + Commands: + - remove: true + # If the gnome moves into a gem object, the stick is removed, triggering a win condition + - Src: + Object: avatar + Commands: + - mov: _dest + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - incr: has_key + - reward: 1 + - set_tile: 1 + Dst: + Object: key + Commands: + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - remove: true + # If the gnome moves into a spider + - Src: + Object: avatar + Commands: + - remove: true + - reward: -1 + Dst: + Object: spider + # The gnome and the spider can move into empty space + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: _empty + - Name: attack + InputMapping: + Inputs: + 1: + Description: attack front + OrientationVector: [ -1, 0 ] + VectorToDest: [-1, 0] + Relative: true + Behaviours: + - Src: + Object: avatar + Commands: + - spawn: attack_fire + Dst: + Object: [spider, _empty] + Commands: + - remove: true + Objects: + - Name: avatar + Z: 3 + MapCharacter: A + Variables: + - Name: has_key + Observers: + Sprite2D: + - Image: gvgai/oryx/swordman1_0.png + - Image: gvgai/oryx/swordmankey1_0.png + Block2D: + - Shape: triangle + Color: [0.0, 0.5, 0.5] + Scale: 0.75 + - Shape: triangle + Color: [0.3, 0.5, 0.2] + Scale: 1.0 + - Name: attack_fire + Z: 1 + InitialActions: + - Action: remove_sprite + Delay: 3 + MapCharacter: x + Observers: + Sprite2D: + - Image: gvgai/oryx/fire1.png + Block2D: + - Shape: square + Color: [1.0, 0.0, 0.0] + Scale: 0.5 + - Name: key + Z: 2 + MapCharacter: "+" + Observers: + Sprite2D: + - Image: gvgai/oryx/key2.png + Block2D: + - Shape: triangle + Color: [0.5, 1.0, 0.5] + Scale: 0.7 + - Name: goal + Z: 2 + MapCharacter: g + Observers: + Sprite2D: + - Image: gvgai/oryx/doorclosed1.png + Block2D: + - Shape: square + Color: [0.0, 0.7, 0.0] + Scale: 0.7 + # - Name: chaser + # Z: 2 + # MapCharacter: "3" + # Observers: + # Sprite2D: + # - Image: gvgai/oryx/skeleton1.png + - Name: spider + Z: 2 + InitialActions: + - Action: random_movement + Delay: 5 + MapCharacter: "3" + Observers: + Sprite2D: + - Image: oryx/oryx_fantasy/avatars/spider1.png + Block2D: + - Shape: triangle + Color: [0.9, 0.1, 0.1] + Scale: 0.5 + - Name: wall + MapCharacter: w + Observers: + Sprite2D: + - TilingMode: WALL_16 + Image: + - gvgai/oryx/wall3_0.png + - gvgai/oryx/wall3_1.png + - gvgai/oryx/wall3_2.png + - gvgai/oryx/wall3_3.png + - gvgai/oryx/wall3_4.png + - gvgai/oryx/wall3_5.png + - gvgai/oryx/wall3_6.png + - gvgai/oryx/wall3_7.png + - gvgai/oryx/wall3_8.png + - gvgai/oryx/wall3_9.png + - gvgai/oryx/wall3_10.png + - gvgai/oryx/wall3_11.png + - gvgai/oryx/wall3_12.png + - gvgai/oryx/wall3_13.png + - gvgai/oryx/wall3_14.png + - gvgai/oryx/wall3_15.png + Block2D: + - Shape: square + Color: [0.7, 0.7, 0.7] + Scale: 1.0 + + diff --git a/docs/games/Zen_Puzzle/index.rst b/docs/games/Zen_Puzzle/index.rst index 8e80f0c6f..ecba52b97 100644 --- a/docs/games/Zen_Puzzle/index.rst +++ b/docs/games/Zen_Puzzle/index.rst @@ -97,9 +97,9 @@ Objects - ground - rock * - Map Char -> - - A - - g - - r + - `A` + - `g` + - `r` * - Vector - .. image:: img/Zen_Puzzle-tile-avatar-Vector.png - .. image:: img/Zen_Puzzle-tile-ground-Vector.png diff --git a/docs/games/img/Partially_Observable_Zelda-taster.png b/docs/games/img/Partially_Observable_Zelda-taster.png new file mode 100644 index 000000000..94fb66b95 Binary files /dev/null and b/docs/games/img/Partially_Observable_Zelda-taster.png differ diff --git a/docs/games/img/Zelda_Sequential-taster.png b/docs/games/img/Zelda_Sequential-taster.png new file mode 100644 index 000000000..a6c5544d1 Binary files /dev/null and b/docs/games/img/Zelda_Sequential-taster.png differ diff --git a/docs/games/index.rst b/docs/games/index.rst index 5a343bf7d..0a8cac5de 100644 --- a/docs/games/index.rst +++ b/docs/games/index.rst @@ -25,6 +25,8 @@ Single-Player Random_butterflies/index Cook_Me_Pasta/index Partially_Observable_Bait/index + Zelda_Sequential/index + Partially_Observable_Zelda/index Sokoban/index Zelda/index Clusters/index @@ -166,14 +168,28 @@ Single-Player :width: 200 Get the key and unlock the door. Fill in the holes in the floor with blocks to get to the key. - * - **Sokoban** + * - **Zelda Sequential** + + .. image:: img/Zelda_Sequential-taster.png + :target: Zelda_Sequential/index.html + :width: 200 + + A port of the GVGAI game "Zelda". Pick up keys to reach doors in the correct order and avoid enemies. For example, previously you could go -- key -> door -> door. But now you would need to go -- key -> door --> key --> door. + - **Partially Observable Zelda** + + .. image:: img/Partially_Observable_Zelda-taster.png + :target: Partially_Observable_Zelda/index.html + :width: 200 + + A port of the GVGAI game "Zelda", but partially observable. Pick up keys to reach doors and avoid enemies. + - **Sokoban** .. image:: img/Sokoban-taster.png :target: Sokoban/index.html :width: 200 Push the boxes into holes. - - **Zelda** + * - **Zelda** .. image:: img/Zelda-taster.png :target: Zelda/index.html @@ -187,15 +203,13 @@ Single-Player :width: 200 Cluster the coloured objects together by pushing them against the static coloured blocks. - * - **Zen Puzzle** + - **Zen Puzzle** .. image:: img/Zen_Puzzle-taster.png :target: Zen_Puzzle/index.html :width: 200 Set all the tiles in the level to the same color, but you cannot move over a tile more than once! (Not even sure why this is zen its super frustrating) - - - - *** diff --git a/python/benchmarks/BWDistantResources32x32.yaml b/python/benchmarks/BWDistantResources32x32.yaml new file mode 100644 index 000000000..76b50c0e5 --- /dev/null +++ b/python/benchmarks/BWDistantResources32x32.yaml @@ -0,0 +1,133 @@ +Version: "0.1" +Environment: + Name: BWDistantResources32x32 + Observers: + Sprite2D: + TileSize: 16 + BackgroundTile: oryx/oryx_tiny_galaxy/tg_sliced/tg_world/tg_world_floor_panel_metal_a.png + Player: + Count: 2 + Termination: + Lose: + - eq: [base:count, 0] # If the player has no bases + Win: + - eq: [_score, 10] # First player to 10 reward points + Levels: + - | + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . M M M + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . M M + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . M + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . H1 . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . B1 . . . . . . . . . . . . . . . . W . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . W W W W W . . . . + . . . . W W W W W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . B2 . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . H2 . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + M . . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + M M . . . . . . W . . . . . . . . . . . . . . . . . . . . . . . + M M M . . . . . W . . . . . . . . . . . . . . . . . . . . . . . +Actions: + - Name: gather + Behaviours: + - Src: + Object: harvester + Commands: + - incr: resources + - reward: 1 + Dst: + Object: minerals + Commands: + - decr: resources + - Src: + Object: harvester + Commands: + - decr: resources + - reward: 1 + Dst: + Object: base + Commands: + - incr: resources + + - Name: move + Behaviours: + - Src: + Object: [harvester] + Commands: + - mov: _dest # mov will move the object, _dest is the destination location of the action + Dst: + Object: _empty + +Objects: + - Name: minerals + MapCharacter: M + Variables: + - Name: resources + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_items/tg_items_crystal_green.png + Block2D: + - Shape: triangle + Color: [0.0, 1.0, 0.0] + Scale: 1.0 + + - Name: fixed_wall + MapCharacter: W + Observers: + Sprite2D: + - TilingMode: WALL_2 # Will tile walls with two images + Image: + - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img33.png + - oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img40.png + Block2D: + - Color: [0.5, 0.5, 0.5] + Shape: square + + - Name: harvester + MapCharacter: H + Variables: + - Name: resources + InitialValue: 0 + - Name: health + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_monsters/tg_monsters_jelly_d1.png + Block2D: + - Shape: square + Color: [0.6, 0.2, 0.2] + Scale: 0.5 + + - Name: base + MapCharacter: B + Variables: + - Name: resources + InitialValue: 0 + - Name: health + InitialValue: 10 + Observers: + Sprite2D: + - Image: oryx/oryx_tiny_galaxy/tg_sliced/tg_world_fixed/img324.png + Block2D: + - Color: [0.8, 0.8, 0.3] + Shape: triangle \ No newline at end of file diff --git a/python/benchmarks/benchmark.py b/python/benchmarks/benchmark.py index f1aef323f..9c855ee4a 100644 --- a/python/benchmarks/benchmark.py +++ b/python/benchmarks/benchmark.py @@ -31,11 +31,13 @@ def gvgai_test_old(): if __name__ == '__main__': + #env = griddly('dmlab_pushbox.yaml') + #env = minigrid_test() - env = griddly('Single-Player/Mini-Grid/minigrid-eyeball.yaml') + #env = griddly('Single-Player/Mini-Grid/minigrid-eyeball.yaml') #env = micro_rts_test() - #env = griddly('RTS/BWDistantResources32x32.yaml') + env = griddly('BWDistantResources32x32.yaml') # memory usage recorded in these tests is inaccurate because the GVGAI environment is in a different process #env = gvgai_test() @@ -55,7 +57,8 @@ def gvgai_test_old(): frames += 1 obs, reward, done, info = env.step(env.action_space.sample()) - rendered_obs = env.render(mode='rgb_array') + #env.render() + #rendered_obs = env.render(mode='rgb_array') if frames % 1000 == 0: end = timer() diff --git a/python/benchmarks/dmlab_pushbox.yaml b/python/benchmarks/dmlab_pushbox.yaml new file mode 100644 index 000000000..4a8e5c095 --- /dev/null +++ b/python/benchmarks/dmlab_pushbox.yaml @@ -0,0 +1,185 @@ +Version: "0.1" +Environment: + Name: Pushbox + Description: Push the boxes onto the marked spaces, once a box has moved onto a space, it cannot be moved + Observers: + Sprite2D: + TileSize: 8 + BackgroundTile: gvgai/newset/floor2.png + Player: + AvatarObject: avatar # The player can only control a single avatar in the game + Termination: + Win: + - eq: [ box:count, 0 ] # If there are no boxes left + Levels: + - | + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w w w w w . . . . . w + w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w w w w w . h b h . w + w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w w . . . . b A b . w + w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w w . . . . h b h . w + w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w w . . . . . . . . w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w + - | + w w w w w w w w w w + w w w w . . . . . w + w w w w . h b h . w + w . . . . b A b . w + w . . . . h b h . w + w . . . . . . . . w + w w w w w w w w w w + w w w w w w w w w w + w w w w w w w w w w + + +Actions: + # Define the move action + - Name: move + Behaviours: + # The agent can move around freely in empty space and over holes + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: [ _empty, hole ] + + # Boxes can move into empty space + - Src: + Object: box + Commands: + - mov: _dest + Dst: + Object: _empty + + # The agent can push boxes + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: [ box, box_in_place ] + Commands: + - exec: + Action: move + + # If a box is moved into a hole, it should change to in-place box + - Src: + Object: [ box, box_in_place ] + Commands: + - mov: _dest + - change_to: box_in_place + - reward: 1 + Dst: + Object: hole + + # If in-place box is moved into empty space, it should be a plain box + - Src: + Object: box_in_place + Commands: + - mov: _dest + - change_to: box + - reward: -1 + Dst: + Object: _empty + +Objects: + - Name: box + Z: 2 + MapCharacter: b + Observers: + Sprite2D: + - Image: gvgai/newset/block2.png + Block2D: + - Shape: square + Color: [ 1.0, 0.0, 0.0 ] + Scale: 0.5 + + - Name: box_in_place + Z: 2 + MapCharacter: f + Observers: + Sprite2D: + - Image: gvgai/newset/block1.png + Block2D: + - Shape: square + Color: [ 0.0, 1.0, 0.0 ] + Scale: 0.5 + + - Name: wall + MapCharacter: w + Observers: + Sprite2D: + - TilingMode: WALL_16 + Image: + - gvgai/oryx/wall3_0.png + - gvgai/oryx/wall3_1.png + - gvgai/oryx/wall3_2.png + - gvgai/oryx/wall3_3.png + - gvgai/oryx/wall3_4.png + - gvgai/oryx/wall3_5.png + - gvgai/oryx/wall3_6.png + - gvgai/oryx/wall3_7.png + - gvgai/oryx/wall3_8.png + - gvgai/oryx/wall3_9.png + - gvgai/oryx/wall3_10.png + - gvgai/oryx/wall3_11.png + - gvgai/oryx/wall3_12.png + - gvgai/oryx/wall3_13.png + - gvgai/oryx/wall3_14.png + - gvgai/oryx/wall3_15.png + Block2D: + - Shape: triangle + Color: [ 0.6, 0.6, 0.6 ] + Scale: 0.9 + + - Name: hole + Z: 1 + MapCharacter: h + Observers: + Sprite2D: + - Image: gvgai/oryx/cspell4.png + Block2D: + - Shape: triangle + Color: [ 0.0, 1.0, 0.0 ] + Scale: 0.6 + + - Name: avatar + Z: 2 + MapCharacter: A + Observers: + Sprite2D: + - Image: gvgai/oryx/knight1.png + Block2D: + - Shape: triangle + Color: [ 0.2, 0.2, 0.6 ] + Scale: 1.0 diff --git a/python/docs/snippet.py b/python/docs/snippet.py index 97f815465..a38d6692a 100644 --- a/python/docs/snippet.py +++ b/python/docs/snippet.py @@ -1,15 +1,14 @@ import gym -from griddly import GymWrapperFactory, gd +import griddly if __name__ == '__main__': - wrapper = GymWrapperFactory() - wrapper.build_gym_from_yaml( - 'Sokoban-Adv', - 'Single-Player/GVGAI/sokoban.yaml', - player_observer_type=gd.ObserverType.SPRITE_2D, - level=2 - ) + env = gym.make('GDY-Partially-Observable-Zelda-v0') + env.reset() - env = gym.make('GDY-Sokoban-Adv-v0') - env.reset() \ No newline at end of file + # Replace with your own control algorithm! + for s in range(1000): + obs, reward, done, info = env.step(env.action_space.sample()) + env.render() # Renders the environment from the perspective of a single player + + env.render(observer='global') # Renders the entire environment \ No newline at end of file diff --git a/python/docs/sphinxdocs/game_docs.py b/python/docs/sphinxdocs/game_docs.py index 1b5dd1a01..d1b0426fd 100644 --- a/python/docs/sphinxdocs/game_docs.py +++ b/python/docs/sphinxdocs/game_docs.py @@ -42,7 +42,7 @@ def _generate_object_description(self, game_description): continue key_table_name_header += f' - {object_name}\n' - key_table_mapchar_header += f' - {map_character}\n' + key_table_mapchar_header += f' - `{map_character}`\n' for observer_type_string, tile_data in object_data['Tiles'].items(): relative_image_path = os.path.join('img', f'{name.replace(" ", "_")}-tile-{object_name}-{observer_type_string}.png') diff --git a/python/examples/griddlyrts/play_griddlyrts_gym.py b/python/examples/griddlyrts/play_griddlyrts_gym.py index da32a08ff..b743486fd 100644 --- a/python/examples/griddlyrts/play_griddlyrts_gym.py +++ b/python/examples/griddlyrts/play_griddlyrts_gym.py @@ -12,8 +12,8 @@ wrapper.build_gym_from_yaml("GriddlyRTS-Adv", 'RTS/GriddlyRTS.yaml', global_observer_type=gd.ObserverType.ISOMETRIC, - player_observer_type=gd.ObserverType.SPRITE_2D, - level=0) + player_observer_type=gd.ObserverType.ISOMETRIC, + level=2) env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') # env_original = gym.make(f'GDY-GriddlyRTS-Adv-v0') @@ -40,7 +40,7 @@ global_visualization = env.render(observer='global', mode='rgb_array') global_recorder.start("global_video_test.mp4", global_visualization.shape) - for s in range(1000): + for s in range(10000): frames += 1 @@ -51,10 +51,11 @@ # # action_masks = env.get_unit_action_mask([6, 3], ['gather', 'move'], padded=False) - obs, reward, done, info = env.step(action) - env.render(observer='global') - env.render() + env.render(observer=0) + env.render(observer=1) + + obs, reward, done, info = env.step(action) global_observation = env.render(mode='rgb_array', observer='global') diff --git a/python/griddly/GymWrapper.py b/python/griddly/GymWrapper.py index 042c419d9..0a4a13e41 100644 --- a/python/griddly/GymWrapper.py +++ b/python/griddly/GymWrapper.py @@ -59,6 +59,8 @@ def __init__(self, yaml_file=None, level=0, global_observer_type=gd.ObserverType self._player_last_observation = [] self._global_last_observation = None + self._enable_history = False + self.game.init(self._is_clone) def get_state(self): @@ -71,6 +73,7 @@ def get_tile_size(self, player=0): return self._players[player - 1].get_tile_size() def enable_history(self, enable=True): + self._enable_history = enable self.game.enable_history(enable) def step(self, action): @@ -129,6 +132,9 @@ def step(self, action): self._player_last_observation[p] = np.array(self._players[p].observe(), copy=False) obs = self._player_last_observation[0] if self.player_count == 1 else self._player_last_observation + + if self._enable_history: + info['History'] = self.game.get_history() return obs, reward, done, info def reset(self, level_id=None, level_string=None, global_observations=False): diff --git a/python/setup.py b/python/setup.py index 2c8f5543f..560910dce 100644 --- a/python/setup.py +++ b/python/setup.py @@ -71,7 +71,7 @@ def griddly_package_data(config='Debug'): setup( name='griddly', - version="0.3.0", + version="0.3.1", author_email="chrisbam4d@gmail.com", description="Griddly Python Libraries", long_description=long_description, diff --git a/python/tests/history_test.py b/python/tests/history_test.py new file mode 100644 index 000000000..17f07e0e0 --- /dev/null +++ b/python/tests/history_test.py @@ -0,0 +1,182 @@ +import numpy as np +import gym +import pytest +from griddly import GymWrapperFactory, gd + + +@pytest.fixture +def test_name(request): + return request.node.name + + +def build_test_env(test_name, yaml_file, enable_history=True): + wrapper_factory = GymWrapperFactory() + + wrapper_factory.build_gym_from_yaml( + test_name, + yaml_file, + global_observer_type=gd.ObserverType.VECTOR, + player_observer_type=gd.ObserverType.VECTOR, + ) + + env = gym.make(f'GDY-{test_name}-v0') + env.reset() + env.enable_history(enable_history) + return env + + +def test_step_SinglePlayer_HasHistory(test_name): + """ + Assuming there is a single avatar + Action is in form env.step(actionId) + """ + + env = build_test_env( + test_name, + "tests/gdy/test_step_SinglePlayer_SingleActionType.yaml" + ) + + obs, reward, done, info = env.step(1) + + expected_history = [{ + 'PlayerId': 1, + 'ActionName': 'move', + 'Tick': 0, + 'Reward': 0, + 'Delay': 0, + 'SourceObjectName': 'avatar', + 'DestinationObjectName': '_empty', + 'SourceObjectPlayerId': 1, + 'DestinationObjectPlayerId': 0, + 'SourceLocation': [2.0, 3.0], + 'DestinationLocation': [1.0, 3.0] + }] + + assert info['History'] == expected_history + + +def test_step_SinglePlayer_NoHistory(test_name): + """ + Assuming there is a single avatar + Action is in form env.step(actionId) + """ + + env = build_test_env( + test_name, + "tests/gdy/test_step_SinglePlayer_SingleActionType.yaml", + enable_history=False + ) + + obs, reward, done, info = env.step(1) + + assert 'History' not in info + + sample = env.action_space.sample() + assert isinstance(sample, int) + + +def test_step_SinglePlayer_MultipleAction(test_name): + """ + There is no avatar + Player performing multiple actions in a single step + + env.step([ + [x1, y1, actionId1], + [x2, y2, actionId2] + ]) + """ + env = build_test_env( + test_name, + "tests/gdy/test_step_SinglePlayer_SelectSource_SingleActionType_MultipleAction.yaml" + ) + + obs, reward, done, info = env.step([ + [2, 3, 1], + [1, 4, 3], + ]) + + expected_history = [ + {'PlayerId': 1, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar1', + 'DestinationObjectName': '_empty', + 'SourceObjectPlayerId': 1, 'DestinationObjectPlayerId': 0, 'SourceLocation': [2.0, 3.0], + 'DestinationLocation': [1.0, 3.0]}, + {'PlayerId': 1, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar2', + 'DestinationObjectName': '_empty', + 'SourceObjectPlayerId': 1, 'DestinationObjectPlayerId': 0, 'SourceLocation': [1.0, 4.0], + 'DestinationLocation': [2.0, 4.0]}] + + assert info['History'] == expected_history + + +def test_step_MultiplePlayer_History(test_name): + """ + There is an avatar + Multiple players + + env.step([ + [actionId_player1], + [actionId_player2] + ]) + """ + env = build_test_env( + test_name, + "tests/gdy/test_step_MultiPlayer_SingleActionType.yaml" + ) + + obs, reward, done, info = env.step([ + 1, + 3, + ]) + + expected_history = [ + {'PlayerId': 1, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar', + 'DestinationObjectName': '_empty', 'SourceObjectPlayerId': 1, 'DestinationObjectPlayerId': 0, + 'SourceLocation': [1.0, 3.0], 'DestinationLocation': [0.0, 3.0]}, + {'PlayerId': 2, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar', + 'DestinationObjectName': '_empty', 'SourceObjectPlayerId': 2, 'DestinationObjectPlayerId': 0, + 'SourceLocation': [3.0, 3.0], 'DestinationLocation': [4.0, 3.0]}] + + assert info['History'] == expected_history + + +def test_step_MultiplePlayer_MultipleAction_History(test_name): + """ + There no avatar, multiple players + + env.step([ + [ # player 1 multiple actions + [x1, y1, action_type, actionId1], + [x2, y2, action_type, actionId2] + ], + [ # player 2 multiple actions + [x1, y1, action_type, actionId1], + ], + ]) + """ + env = build_test_env( + test_name, + "tests/gdy/test_step_MultiPlayer_SelectSource_MultipleActionType_MultipleAction.yaml" + ) + + obs, reward, done, info = env.step([ + [ + [1, 3, 0, 1], + [3, 4, 1, 3], + ], + [ + [3, 3, 0, 1], + ] + ]) + + expected_history = [ + {'PlayerId': 1, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar1', + 'DestinationObjectName': '_empty', 'SourceObjectPlayerId': 1, 'DestinationObjectPlayerId': 0, + 'SourceLocation': [1.0, 3.0], 'DestinationLocation': [0.0, 3.0]}, + {'PlayerId': 1, 'ActionName': 'other_move', 'Tick': 0, 'Reward': 1, 'Delay': 0, 'SourceObjectName': 'avatar2', + 'DestinationObjectName': '_empty', 'SourceObjectPlayerId': 1, 'DestinationObjectPlayerId': 0, + 'SourceLocation': [3.0, 4.0], 'DestinationLocation': [4.0, 4.0]}, + {'PlayerId': 2, 'ActionName': 'move', 'Tick': 0, 'Reward': 0, 'Delay': 0, 'SourceObjectName': 'avatar1', + 'DestinationObjectName': '_empty', 'SourceObjectPlayerId': 2, 'DestinationObjectPlayerId': 0, + 'SourceLocation': [3.0, 3.0], 'DestinationLocation': [2.0, 3.0]}] + + assert info['History'] == expected_history diff --git a/resources/games/Single-Player/GVGAI/zelda_partially_observable.yaml b/resources/games/Single-Player/GVGAI/zelda_partially_observable.yaml new file mode 100644 index 000000000..f12ec336f --- /dev/null +++ b/resources/games/Single-Player/GVGAI/zelda_partially_observable.yaml @@ -0,0 +1,293 @@ +Version: "0.1" +Environment: + Name: Partially Observable Zelda + Description: A port of the GVGAI game "Zelda", but partially observable. Pick up keys to reach doors and avoid enemies. + Observers: + Sprite2D: + TileSize: 24 + BackgroundTile: gvgai/newset/floor2.png + Player: + Observer: + RotateWithAvatar: true + TrackAvatar: true + Height: 5 + Width: 5 + OffsetX: 0 + OffsetY: 2 + AvatarObject: avatar + Termination: + Win: + - eq: [goal:count, 0] + Lose: + - eq: [avatar:count, 0] + Levels: + - | + wwwwwwwwwwwww + w...........w + w...........w + w.+...A.....w + w...........w + w...........w + w......3....w + w.g.........w + wwwwwwwwwwwww + - | + wwwwwwwwwwwwwww + w.............w + w......w......w + w......w......w + w......w......w + w..3...w..+...w + w......w......w + w......w......w + w.wwwwwwwwwww.w + w.....Aw......w + w......w......w + w......w......w + w......w......w + w......w......w + w...........g.w + wwwwwwwwwwwwwww + - | + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + w........+....3..............w + w............................w + w...A.............3..........w + w............................w + w....................3.......w + w..............wwwwwwwwwwwwwww + w..........................g.w + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww +Actions: + # Define action that cannot be controlled by the player. + # (In this case the spider movement) + - Name: random_movement + InputMapping: + Internal: true + Behaviours: + # The gnome and the spider can move into empty space + - Src: + Object: spider + Commands: + - mov: _dest + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: _empty + # The spider will not move into the wall, but it needs to keep moving + - Src: + Object: spider + Commands: + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: [wall, key, goal, spider] + # If the gnome moves into a spider + - Src: + Object: spider + Dst: + Object: avatar + Commands: + - remove: true + - reward: -1 + # remove the recently spawned attack animation sprite + - Name: remove_sprite + InputMapping: + Internal: true + Behaviours: + - Src: + Object: attack_fire + Commands: + - remove: true + Dst: + Object: attack_fire + # Define the move action + - Name: move + InputMapping: + Inputs: + 1: + Description: Rotate left + OrientationVector: [-1, 0] + 2: + Description: Move forwards + OrientationVector: [0, -1] + VectorToDest: [0, -1] + 3: + Description: Rotate right + OrientationVector: [1, 0] + 4: + Description: Move Backwards + VectorToDest: [0, 1] + OrientationVector: [0, -1] + Relative: true + Behaviours: + # Tell the gnome to rotate if it performs an action on itself (Rotate left and Rotate right actions) + - Src: + Object: avatar + Commands: + - rot: _dir + Dst: + Object: avatar + # Only an avatar with a key can win + - Src: + Preconditions: + - eq: [src.has_key, 1] + Object: avatar + Commands: + - reward: 1 + # - decr: has_key + - mov: _dest + # - set_tile: 0 + Dst: + Object: goal + Commands: + - remove: true + # If the gnome moves into a gem object, the stick is removed, triggering a win condition + - Src: + Object: avatar + Commands: + - mov: _dest + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - incr: has_key + - reward: 1 + - set_tile: 1 + Dst: + Object: key + Commands: + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - remove: true + # If the gnome moves into a spider + - Src: + Object: avatar + Commands: + - remove: true + - reward: -1 + Dst: + Object: spider + # The gnome and the spider can move into empty space + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: _empty + - Name: attack + InputMapping: + Inputs: + 1: + Description: attack front + OrientationVector: [ -1, 0 ] + VectorToDest: [-1, 0] + Relative: true + Behaviours: + - Src: + Object: avatar + Commands: + - spawn: attack_fire + Dst: + Object: [spider, _empty] + Commands: + - remove: true +Objects: + - Name: avatar + Z: 3 + MapCharacter: A + Variables: + - Name: has_key + Observers: + Sprite2D: + - Image: gvgai/oryx/swordman1_0.png + - Image: gvgai/oryx/swordmankey1_0.png + Block2D: + - Shape: triangle + Color: [0.0, 0.5, 0.5] + Scale: 0.75 + - Shape: triangle + Color: [0.3, 0.5, 0.2] + Scale: 1.0 + - Name: attack_fire + Z: 1 + InitialActions: + - Action: remove_sprite + Delay: 3 + MapCharacter: x + Observers: + Sprite2D: + - Image: gvgai/oryx/fire1.png + Block2D: + - Shape: square + Color: [1.0, 0.0, 0.0] + Scale: 0.5 + - Name: key + Z: 2 + MapCharacter: "+" + Observers: + Sprite2D: + - Image: gvgai/oryx/key2.png + Block2D: + - Shape: triangle + Color: [0.5, 1.0, 0.5] + Scale: 0.7 + - Name: goal + Z: 2 + MapCharacter: g + Observers: + Sprite2D: + - Image: gvgai/oryx/doorclosed1.png + Block2D: + - Shape: square + Color: [0.0, 0.7, 0.0] + Scale: 0.7 + # - Name: chaser + # Z: 2 + # MapCharacter: "3" + # Observers: + # Sprite2D: + # - Image: gvgai/oryx/skeleton1.png + - Name: spider + Z: 2 + InitialActions: + - Action: random_movement + Delay: 5 + MapCharacter: "3" + Observers: + Sprite2D: + - Image: oryx/oryx_fantasy/avatars/spider1.png + Block2D: + - Shape: triangle + Color: [0.9, 0.1, 0.1] + Scale: 0.5 + - Name: wall + MapCharacter: w + Observers: + Sprite2D: + - TilingMode: WALL_16 + Image: + - gvgai/oryx/wall3_0.png + - gvgai/oryx/wall3_1.png + - gvgai/oryx/wall3_2.png + - gvgai/oryx/wall3_3.png + - gvgai/oryx/wall3_4.png + - gvgai/oryx/wall3_5.png + - gvgai/oryx/wall3_6.png + - gvgai/oryx/wall3_7.png + - gvgai/oryx/wall3_8.png + - gvgai/oryx/wall3_9.png + - gvgai/oryx/wall3_10.png + - gvgai/oryx/wall3_11.png + - gvgai/oryx/wall3_12.png + - gvgai/oryx/wall3_13.png + - gvgai/oryx/wall3_14.png + - gvgai/oryx/wall3_15.png + Block2D: + - Shape: square + Color: [0.7, 0.7, 0.7] + Scale: 1.0 \ No newline at end of file diff --git a/resources/games/Single-Player/GVGAI/zelda_sequential.yaml b/resources/games/Single-Player/GVGAI/zelda_sequential.yaml new file mode 100644 index 000000000..ed6df165b --- /dev/null +++ b/resources/games/Single-Player/GVGAI/zelda_sequential.yaml @@ -0,0 +1,279 @@ +Version: "0.1" +Environment: + Name: Zelda Sequential + Description: A port of the GVGAI game "Zelda". Pick up keys to reach doors in the correct order and avoid enemies. For example, previously you could go -- key -> door -> door. But now you would need to go -- key -> door --> key --> door. + Observers: + Sprite2D: + TileSize: 24 + BackgroundTile: gvgai/newset/floor2.png + Player: + AvatarObject: avatar + Termination: + Win: + - eq: [goal:count, 0] + Lose: + - eq: [avatar:count, 0] + Levels: + - | + wwwwwwwwwwwww + w...........w + w...........w + w.+...A.....w + w...........w + w...........w + w......3....w + w.g.........w + wwwwwwwwwwwww + - | + wwwwwwwwwwwww + w.....+..+g.w + w.+.w.g.....w + w.....Ag..3.w + w+..+.......w + w....w..+...w + w.........g.w + w.3...+++.+ww + wwwwwwwwwwwww + - | + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww + w........+.............g.....w + w............................w + w...A.............3..........w + w............................w + w....................3.......w + w..............wwwwwwwwwwwwwww + w......................+...g.w + wwwwwwwwwwwwwwwwwwwwwwwwwwwwww +Actions: + # Define action that cannot be controlled by the player. + # (In this case the spider movement) + - Name: random_movement + InputMapping: + Internal: true + Behaviours: + # The gnome and the spider can move into empty space + - Src: + Object: spider + Commands: + - mov: _dest + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: _empty + # The spider will not move into the wall, but it needs to keep moving + - Src: + Object: spider + Commands: + - exec: + Action: random_movement + Delay: 5 + Randomize: true + Dst: + Object: [wall, key, goal, spider] + # If the gnome moves into a spider + - Src: + Object: spider + Dst: + Object: avatar + Commands: + - remove: true + - reward: -1 + # remove the recently spawned attack animation sprite + - Name: remove_sprite + InputMapping: + Internal: true + Behaviours: + - Src: + Object: attack_fire + Commands: + - remove: true + Dst: + Object: attack_fire + # Define the move action + - Name: move + InputMapping: + Inputs: + 1: + Description: Rotate left + OrientationVector: [-1, 0] + 2: + Description: Move forwards + OrientationVector: [0, -1] + VectorToDest: [0, -1] + 3: + Description: Rotate right + OrientationVector: [1, 0] + 4: + Description: Move Backwards + VectorToDest: [0, 1] + OrientationVector: [0, -1] + Relative: true + Behaviours: + # Tell the gnome to rotate if it performs an action on itself (Rotate left and Rotate right actions) + - Src: + Object: avatar + Commands: + - rot: _dir + Dst: + Object: avatar + # Only an avatar with a key can win + - Src: + Preconditions: + - eq: [src.has_key, 1] + Object: avatar + Commands: + - reward: 1 + - decr: has_key + - mov: _dest + - set_tile: 0 + Dst: + Object: goal + Commands: + - remove: true + # If the gnome moves into a gem object, the stick is removed, triggering a win condition + - Src: + Object: avatar + Commands: + - mov: _dest + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - incr: has_key + - reward: 1 + - set_tile: 1 + Dst: + Object: key + Commands: + - eq: + Arguments: [ src.has_key, 0 ] + Commands: + - remove: true + # If the gnome moves into a spider + - Src: + Object: avatar + Commands: + - remove: true + - reward: -1 + Dst: + Object: spider + # The gnome and the spider can move into empty space + - Src: + Object: avatar + Commands: + - mov: _dest + Dst: + Object: _empty + - Name: attack + InputMapping: + Inputs: + 1: + Description: attack front + OrientationVector: [ -1, 0 ] + VectorToDest: [-1, 0] + Relative: true + Behaviours: + - Src: + Object: avatar + Commands: + - spawn: attack_fire + Dst: + Object: [spider, _empty] + Commands: + - remove: true +Objects: + - Name: avatar + Z: 3 + MapCharacter: A + Variables: + - Name: has_key + Observers: + Sprite2D: + - Image: gvgai/oryx/swordman1_0.png + - Image: gvgai/oryx/swordmankey1_0.png + Block2D: + - Shape: triangle + Color: [0.0, 0.5, 0.5] + Scale: 0.75 + - Shape: triangle + Color: [0.3, 0.5, 0.2] + Scale: 1.0 + - Name: attack_fire + Z: 1 + InitialActions: + - Action: remove_sprite + Delay: 3 + MapCharacter: x + Observers: + Sprite2D: + - Image: gvgai/oryx/fire1.png + Block2D: + - Shape: square + Color: [1.0, 0.0, 0.0] + Scale: 0.5 + - Name: key + Z: 2 + MapCharacter: "+" + Observers: + Sprite2D: + - Image: gvgai/oryx/key2.png + Block2D: + - Shape: triangle + Color: [0.5, 1.0, 0.5] + Scale: 0.7 + - Name: goal + Z: 2 + MapCharacter: g + Observers: + Sprite2D: + - Image: gvgai/oryx/doorclosed1.png + Block2D: + - Shape: square + Color: [0.0, 0.7, 0.0] + Scale: 0.7 + # - Name: chaser + # Z: 2 + # MapCharacter: "3" + # Observers: + # Sprite2D: + # - Image: gvgai/oryx/skeleton1.png + - Name: spider + Z: 2 + InitialActions: + - Action: random_movement + Delay: 5 + MapCharacter: "3" + Observers: + Sprite2D: + - Image: oryx/oryx_fantasy/avatars/spider1.png + Block2D: + - Shape: triangle + Color: [0.9, 0.1, 0.1] + Scale: 0.5 + - Name: wall + MapCharacter: w + Observers: + Sprite2D: + - TilingMode: WALL_16 + Image: + - gvgai/oryx/wall3_0.png + - gvgai/oryx/wall3_1.png + - gvgai/oryx/wall3_2.png + - gvgai/oryx/wall3_3.png + - gvgai/oryx/wall3_4.png + - gvgai/oryx/wall3_5.png + - gvgai/oryx/wall3_6.png + - gvgai/oryx/wall3_7.png + - gvgai/oryx/wall3_8.png + - gvgai/oryx/wall3_9.png + - gvgai/oryx/wall3_10.png + - gvgai/oryx/wall3_11.png + - gvgai/oryx/wall3_12.png + - gvgai/oryx/wall3_13.png + - gvgai/oryx/wall3_14.png + - gvgai/oryx/wall3_15.png + Block2D: + - Shape: square + Color: [0.7, 0.7, 0.7] + Scale: 1.0 diff --git a/src/Griddly/Core/Grid.cpp b/src/Griddly/Core/Grid.cpp index 83692b14c..83320e715 100644 --- a/src/Griddly/Core/Grid.cpp +++ b/src/Griddly/Core/Grid.cpp @@ -70,6 +70,13 @@ void Grid::resetGlobalVariables(std::unordered_map{}); + } + } + for (int p = 0; p < playerCount_ + 1; p++) { updatedLocations_[p].insert(location); } @@ -102,12 +109,11 @@ bool Grid::updateLocation(std::shared_ptr object, glm::ivec2 previousLoc return true; } -std::unordered_set Grid::getUpdatedLocations(uint32_t playerId) const { - auto updatedLocationForPlayer = updatedLocations_.find(playerId); - if (updatedLocationForPlayer == updatedLocations_.end()) { - return {}; +const std::unordered_set& Grid::getUpdatedLocations(uint32_t playerId) const { + if(playerId >= updatedLocations_.size()) { + return EMPTY_LOCATIONS; } - return updatedLocationForPlayer->second; + return updatedLocations_[playerId]; } int32_t Grid::executeAndRecord(uint32_t playerId, std::shared_ptr action) { @@ -267,14 +273,14 @@ void Grid::setTickCount(int32_t tickCount) { *gameTicks_ = tickCount; } -std::unordered_set>& Grid::getObjects() { +const std::unordered_set>& Grid::getObjects() { return this->objects_; } -TileObjects Grid::getObjectsAt(glm::ivec2 location) const { +const TileObjects& Grid::getObjectsAt(glm::ivec2 location) const { auto i = occupiedLocations_.find(location); if (i == occupiedLocations_.end()) { - return {}; + return EMPTY_OBJECTS; } else { return i->second; } diff --git a/src/Griddly/Core/Grid.hpp b/src/Griddly/Core/Grid.hpp index dc9bb2a80..293c0dbb3 100644 --- a/src/Griddly/Core/Grid.hpp +++ b/src/Griddly/Core/Grid.hpp @@ -8,14 +8,14 @@ #include #include -#include "GDY/Objects/Object.hpp" #include "GDY/Actions/Action.hpp" +#include "GDY/Objects/Object.hpp" #include "LevelGenerators/LevelGenerator.hpp" #include "Util/util.hpp" #define GLM_ENABLE_EXPERIMENTAL -#include #include +#include #define TileObjects std::map> @@ -31,13 +31,12 @@ struct GridEvent { std::string sourceObjectName; std::string destObjectName; - + uint32_t sourceObjectPlayerId = 0; uint32_t destinationObjectPlayerId = 0; glm::vec2 sourceLocation; glm::vec2 destLocation; - }; struct GlobalVariableDefinition { @@ -52,7 +51,6 @@ class Grid : public std::enable_shared_from_this { Grid(); ~Grid(); - virtual void setPlayerCount(uint32_t playerCount); virtual void resetMap(uint32_t height, uint32_t width); virtual void resetGlobalVariables(std::unordered_map globalVariableDefinitions); @@ -70,7 +68,7 @@ class Grid : public std::enable_shared_from_this { // Mark a particular location to be repainted virtual bool invalidateLocation(glm::ivec2 location); - virtual std::unordered_set getUpdatedLocations(uint32_t player) const; + virtual const std::unordered_set& getUpdatedLocations(uint32_t player) const; virtual void purgeUpdatedLocations(uint32_t player); virtual uint32_t getWidth() const; @@ -80,15 +78,15 @@ class Grid : public std::enable_shared_from_this { virtual void setTickCount(int32_t tickCount); virtual void initObject(std::string objectName); - virtual void addObject(glm::ivec2 location, std::shared_ptr object, bool applyInitialActions=true); + virtual void addObject(glm::ivec2 location, std::shared_ptr object, bool applyInitialActions = true); virtual bool removeObject(std::shared_ptr object); - virtual std::unordered_set>& getObjects(); + virtual const std::unordered_set>& getObjects(); /** * Gets all the objects at a certain location */ - virtual TileObjects getObjectsAt(glm::ivec2 location) const; + virtual const TileObjects& getObjectsAt(glm::ivec2 location) const; /** * Gets the object with the highest Z index at a certain tile location @@ -114,7 +112,6 @@ class Grid : public std::enable_shared_from_this { virtual void purgeHistory(); private: - GridEvent buildGridEvent(std::shared_ptr action, uint32_t playerId, uint32_t tick); void recordGridEvent(GridEvent event, int32_t reward); @@ -127,7 +124,7 @@ class Grid : public std::enable_shared_from_this { // For every game tick record a list of locations that should be updated. // This is so we can highly optimize observers to only re-render changed grid locations - std::unordered_map> updatedLocations_; + std::vector> updatedLocations_; std::unordered_set objectNames_; std::unordered_set> objects_; @@ -136,6 +133,10 @@ class Grid : public std::enable_shared_from_this { std::unordered_map> playerAvatars_; std::unordered_map>> globalVariables_; + // return reference to this if there are no object in getObjectAt + const std::map> EMPTY_OBJECTS = {}; + const std::unordered_set EMPTY_LOCATIONS = {}; + // A priority queue of actions that are delayed in time (time is measured in game ticks) VectorPriorityQueue delayedActions_; diff --git a/src/Griddly/Core/Observers/BlockObserver.cpp b/src/Griddly/Core/Observers/BlockObserver.cpp index e4e53b077..e01d74aee 100644 --- a/src/Griddly/Core/Observers/BlockObserver.cpp +++ b/src/Griddly/Core/Observers/BlockObserver.cpp @@ -37,7 +37,7 @@ void BlockObserver::init(ObserverConfig observerConfig) { } void BlockObserver::renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation orientation) const { - auto objects = grid_->getObjectsAt(objectLocation); + auto& objects = grid_->getObjectsAt(objectLocation); auto tileSize = observerConfig_.tileSize; for (auto objectIt : objects) { diff --git a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp index 93f9d19f6..501b24703 100644 --- a/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp +++ b/src/Griddly/Core/Observers/IsometricSpriteObserver.cpp @@ -22,12 +22,15 @@ void IsometricSpriteObserver::resetShape() { gridWidth_ = observerConfig_.overrideGridWidth > 0 ? observerConfig_.overrideGridWidth : grid_->getWidth(); gridHeight_ = observerConfig_.overrideGridHeight > 0 ? observerConfig_.overrideGridHeight : grid_->getHeight(); + gridBoundary_.x = grid_->getWidth(); + gridBoundary_.y = grid_->getHeight(); + auto tileSize = observerConfig_.tileSize; pixelWidth_ = (gridWidth_ + gridHeight_) * tileSize.x / 2; pixelHeight_ = (gridWidth_ + gridHeight_) * (observerConfig_.isoTileHeight / 2) + tileSize.y + observerConfig_.isoTileDepth; - isoOriginOffset_ = {gridHeight_*tileSize.x / 2, tileSize.y / 2}; + isoOriginOffset_ = {gridHeight_ * tileSize.x / 2, tileSize.y / 2}; observationShape_ = {3, pixelWidth_, pixelHeight_}; observationStrides_ = {1, 3, 3 * pixelWidth_}; @@ -76,10 +79,9 @@ std::vector IsometricSpriteObserver::calculateDirtyRectangles(std::uno } void IsometricSpriteObserver::renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation renderOrientation) const { - auto objects = grid_->getObjectsAt(objectLocation); + auto& objects = grid_->getObjectsAt(objectLocation); auto tileSize = observerConfig_.tileSize; - uint32_t backgroundSpriteArrayLayer = device_->getSpriteArrayLayer("_iso_background_"); const glm::vec4 color = {1.0, 1.0, 1.0, 1.0}; @@ -152,4 +154,25 @@ glm::vec2 IsometricSpriteObserver::isometricOutputLocation(glm::vec2 outputLocat return localOffset + isoOriginOffset_ + outputLocation * isoMat * tilePosition; } +void IsometricSpriteObserver::render(vk::VulkanRenderContext& ctx) const { + auto tileSize = observerConfig_.tileSize; + auto tileOffset = (glm::vec2)tileSize / 2.0f; + + if (avatarObject_ != nullptr) { + VulkanGridObserver::render(ctx); + } else { + auto objy = observerConfig_.gridYOffset; + for (auto outy = 0; outy < gridHeight_; outy++) { + auto objx = observerConfig_.gridXOffset; + for (auto outx = 0; outx < gridWidth_; outx++) { + if (objx < gridBoundary_.x && objx >= 0 && objy < gridBoundary_.y && objy >= 0) { + renderLocation(ctx, {objx, objy}, {outx, outy}, tileOffset, Direction::NONE); + } + objx++; + } + objy++; + } + } +} + } // namespace griddly diff --git a/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp b/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp index 5fa785cae..ed722f0c2 100644 --- a/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp +++ b/src/Griddly/Core/Observers/IsometricSpriteObserver.hpp @@ -16,7 +16,10 @@ class IsometricSpriteObserver : public SpriteObserver { protected: void renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation orientation) const override; void resetShape() override; + + virtual void render(vk::VulkanRenderContext& ctx) const; glm::vec2 isometricOutputLocation(glm::vec2 outputLocation, glm::vec2 offset) const; + std::vector calculateDirtyRectangles(std::unordered_set updatedLocations) const override; private: diff --git a/src/Griddly/Core/Observers/Observer.hpp b/src/Griddly/Core/Observers/Observer.hpp index 411b5da07..cf5d98403 100644 --- a/src/Griddly/Core/Observers/Observer.hpp +++ b/src/Griddly/Core/Observers/Observer.hpp @@ -67,6 +67,9 @@ class Observer { virtual void resetShape() = 0; + // Boundary of the game grid regardless of render shape + glm::ivec2 gridBoundary_; + const std::shared_ptr grid_; std::shared_ptr avatarObject_; ObserverConfig observerConfig_; diff --git a/src/Griddly/Core/Observers/SpriteObserver.cpp b/src/Griddly/Core/Observers/SpriteObserver.cpp index b91e8161b..56bf0a70e 100644 --- a/src/Griddly/Core/Observers/SpriteObserver.cpp +++ b/src/Griddly/Core/Observers/SpriteObserver.cpp @@ -166,7 +166,7 @@ std::string SpriteObserver::getSpriteName(std::string objectName, std::string ti } void SpriteObserver::renderLocation(vk::VulkanRenderContext& ctx, glm::ivec2 objectLocation, glm::ivec2 outputLocation, glm::ivec2 tileOffset, DiscreteOrientation renderOrientation) const { - auto objects = grid_->getObjectsAt(objectLocation); + auto& objects = grid_->getObjectsAt(objectLocation); auto tileSize = observerConfig_.tileSize; for (auto objectIt : objects) { diff --git a/src/Griddly/Core/Observers/VectorObserver.cpp b/src/Griddly/Core/Observers/VectorObserver.cpp index e309ef6db..4b5059122 100644 --- a/src/Griddly/Core/Observers/VectorObserver.cpp +++ b/src/Griddly/Core/Observers/VectorObserver.cpp @@ -15,21 +15,26 @@ void VectorObserver::init(ObserverConfig observerConfig) { } ObserverType VectorObserver::getObserverType() const { - return ObserverType::VECTOR; + return ObserverType::VECTOR; } glm::ivec2 VectorObserver::getTileSize() const { - return glm::ivec2{1,1}; + return glm::ivec2{1, 1}; } void VectorObserver::resetShape() { gridWidth_ = observerConfig_.overrideGridWidth > 0 ? observerConfig_.overrideGridWidth : grid_->getWidth(); gridHeight_ = observerConfig_.overrideGridHeight > 0 ? observerConfig_.overrideGridHeight : grid_->getHeight(); + gridBoundary_.x = grid_->getWidth(); + gridBoundary_.y = grid_->getHeight(); + auto uniqueObjectCount = grid_->getUniqueObjectCount(); observationShape_ = {uniqueObjectCount, gridWidth_, gridHeight_}; observationStrides_ = {1, uniqueObjectCount, uniqueObjectCount * gridWidth_}; + + observation_ = std::shared_ptr(new uint8_t[uniqueObjectCount * gridWidth_ * gridHeight_]{}); } std::shared_ptr VectorObserver::reset() { @@ -40,8 +45,6 @@ std::shared_ptr VectorObserver::reset() { std::shared_ptr VectorObserver::update() const { auto uniqueObjectCount = grid_->getUniqueObjectCount(); - std::shared_ptr observation(new uint8_t[uniqueObjectCount * gridWidth_ * gridHeight_]{}); - if (avatarObject_ != nullptr) { auto avatarLocation = avatarObject_->getLocation(); auto avatarOrientation = avatarObject_->getObjectOrientation(); @@ -61,7 +64,7 @@ std::shared_ptr VectorObserver::update() const { for (auto objectIt : grid_->getObjectsAt({objx, objy})) { auto object = objectIt.second; int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + observation_.get()[idx] = 1; } outy++; } @@ -76,7 +79,7 @@ std::shared_ptr VectorObserver::update() const { for (auto objectIt : grid_->getObjectsAt({objx, objy})) { auto object = objectIt.second; int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + observation_.get()[idx] = 1; } outy--; } @@ -91,7 +94,7 @@ std::shared_ptr VectorObserver::update() const { for (auto objectIt : grid_->getObjectsAt({objx, objy})) { auto object = objectIt.second; int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + observation_.get()[idx] = 1; } outx++; } @@ -105,7 +108,7 @@ std::shared_ptr VectorObserver::update() const { for (auto objectIt : grid_->getObjectsAt({objx, objy})) { auto object = objectIt.second; int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + observation_.get()[idx] = 1; } outx--; } @@ -121,11 +124,13 @@ std::shared_ptr VectorObserver::update() const { for (auto objx = pGrid.left; objx <= pGrid.right; objx++) { outy = 0; for (auto objy = pGrid.bottom; objy <= pGrid.top; objy++) { - // place a 1 in every object "slice" where that object appears - for (auto objectIt : grid_->getObjectsAt({objx, objy})) { - auto object = objectIt.second; - int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + if (objx < gridBoundary_.x && objx >= 0 && objy < gridBoundary_.y && objy >= 0) { + // place a 1 in every object "slice" where that object appears + for (auto objectIt : grid_->getObjectsAt({objx, objy})) { + auto object = objectIt.second; + int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); + observation_.get()[idx] = 1; + } } outy++; } @@ -133,28 +138,37 @@ std::shared_ptr VectorObserver::update() const { } } } else { - // Can optimize these by only updating states that change and keeping a buffer of the entire state - auto left = observerConfig_.gridXOffset; - auto right = observerConfig_.gridXOffset + gridWidth_ - 1; - auto bottom = observerConfig_.gridYOffset; - auto top = observerConfig_.gridYOffset + gridHeight_ - 1; - uint32_t outx = 0, outy = 0; - for (auto objx = left; objx <= right; objx++) { - outy = 0; - for (auto objy = bottom; objy <= top; objy++) { - for (auto objectIt : grid_->getObjectsAt({objx, objy})) { - auto object = objectIt.second; - - int idx = uniqueObjectCount * (gridWidth_ * outy + outx) + object->getObjectId(); - observation.get()[idx] = 1; + const auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); + + for (auto& location : updatedLocations) { + if (location.x >= observerConfig_.gridXOffset && + location.x < gridWidth_ + observerConfig_.gridXOffset && + location.y >= observerConfig_.gridYOffset && + location.y < gridHeight_ + observerConfig_.gridYOffset) { + auto outputLocation = glm::ivec2( + location.x - observerConfig_.gridXOffset, + location.y - observerConfig_.gridYOffset); + + if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { + auto memPtr = observation_.get() + uniqueObjectCount * (gridWidth_ * outputLocation.y + outputLocation.x); + + auto size = sizeof(uint8_t) * uniqueObjectCount; + memset(memPtr, 0, size); + + auto& objects = grid_->getObjectsAt(location); + for (auto objectIt : objects) { + auto object = objectIt.second; + auto memPtrObject = memPtr + object->getObjectId(); + *memPtrObject = 1; + } } - outy++; } - outx++; } } - return observation; + grid_->purgeUpdatedLocations(observerConfig_.playerId); + + return observation_; } void VectorObserver::print(std::shared_ptr observation) { diff --git a/src/Griddly/Core/Observers/VectorObserver.hpp b/src/Griddly/Core/Observers/VectorObserver.hpp index 633b3edf6..975b64568 100644 --- a/src/Griddly/Core/Observers/VectorObserver.hpp +++ b/src/Griddly/Core/Observers/VectorObserver.hpp @@ -20,6 +20,7 @@ class VectorObserver : public Observer { void print(std::shared_ptr observation) override; private: + std::shared_ptr observation_; }; } // namespace griddly \ No newline at end of file diff --git a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp index 015e44ac0..86a2dda69 100644 --- a/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp +++ b/src/Griddly/Core/Observers/Vulkan/VulkanDevice.cpp @@ -191,12 +191,11 @@ void VulkanDevice::resetRenderSurface(uint32_t pixelWidth, uint32_t pixelHeight) VkCommandBuffer VulkanDevice::beginCommandBuffer() { VkCommandBuffer commandBuffer; + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vk::initializers::commandBufferAllocateInfo(commandPool_, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); vk_check(vkAllocateCommandBuffers(device_, &cmdBufAllocateInfo, &commandBuffer)); - VkCommandBufferBeginInfo cmdBufInfo = - vk::initializers::commandBufferBeginInfo(); - + VkCommandBufferBeginInfo cmdBufInfo = vk::initializers::commandBufferBeginInfo(); vk_check(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo)); return commandBuffer; @@ -219,7 +218,7 @@ VulkanRenderContext VulkanDevice::beginRender() { VulkanRenderContext renderContext = {}; - auto commandBuffer = beginCommandBuffer(); + VkCommandBuffer commandBuffer = beginCommandBuffer(); renderContext.commandBuffer = commandBuffer; @@ -378,7 +377,7 @@ void VulkanDevice::drawSprite(VulkanRenderContext& renderContext, uint32_t array glm::mat4 mvpMatrix = ortho_ * model; SpritePushConstants modelColorSprite = {mvpMatrix, color, arrayLayer}; - if(outlineColor.a != 0) { + if (outlineColor.a != 0) { modelColorSprite.isOutline = 1; modelColorSprite.outlineColor = outlineColor; } @@ -460,7 +459,7 @@ void VulkanDevice::copyBufferToImage(VkBuffer bufferSrc, VkImage imageDst, std:: } void VulkanDevice::copyImage(VkImage imageSrc, VkImage imageDst, std::vector rects) { - auto commandBuffer = beginCommandBuffer(); + VkCommandBuffer commandBuffer = beginCommandBuffer(); auto numRects = rects.size(); @@ -516,7 +515,6 @@ void VulkanDevice::copyImage(VkImage imageSrc, VkImage imageDst, std::vectorgetWidth(), grid_->getHeight()); observerConfig_ = observerConfig; auto imagePath = resourceConfig_.imagePath; auto shaderPath = resourceConfig_.shaderPath; diff --git a/src/Griddly/Core/Observers/VulkanGridObserver.cpp b/src/Griddly/Core/Observers/VulkanGridObserver.cpp index 649bec898..edc6139df 100644 --- a/src/Griddly/Core/Observers/VulkanGridObserver.cpp +++ b/src/Griddly/Core/Observers/VulkanGridObserver.cpp @@ -1,8 +1,8 @@ #include "VulkanGridObserver.hpp" #include -#include #include +#include #include "../Grid.hpp" #include "Vulkan/VulkanDevice.hpp" @@ -19,6 +19,9 @@ void VulkanGridObserver::resetShape() { gridWidth_ = observerConfig_.overrideGridWidth > 0 ? observerConfig_.overrideGridWidth : grid_->getWidth(); gridHeight_ = observerConfig_.overrideGridHeight > 0 ? observerConfig_.overrideGridHeight : grid_->getHeight(); + gridBoundary_.x = grid_->getWidth(); + gridBoundary_.y = grid_->getHeight(); + auto tileSize = observerConfig_.tileSize; pixelWidth_ = gridWidth_ * tileSize.x; @@ -30,21 +33,20 @@ void VulkanGridObserver::resetShape() { void VulkanGridObserver::init(ObserverConfig observerConfig) { VulkanObserver::init(observerConfig); - + uint32_t players = 1; - for(auto object : grid_->getObjects()) { - if(object->getPlayerId() > players) { + for (auto object : grid_->getObjects()) { + if (object->getPlayerId() > players) { players = object->getPlayerId(); } } - float s = 1.0; float v = 0.6; - float h_inc = 360.0/players; - for(int p = 0; p VulkanGridObserver::calculateDirtyRectangles(std::unordere // Because we make the dirty rectangles slightly larger than the sprites, must check boundaries do not go beyond // the render image surface - // Because we make the dirty rectangles slightly larger than the sprites, must check boundaries do not go beyond + // Because we make the dirty rectangles slightly larger than the sprites, must check boundaries do not go beyond // the render image surface auto extentWidth = (uint32_t)tileSize.x + 4; auto boundaryX = (int32_t)extentWidth + offset.x - (int32_t)pixelWidth_; if (boundaryX > 0) { - extentWidth -= boundaryX; + extentWidth -= boundaryX; } auto extentHeight = (uint32_t)tileSize.y + 4; auto boundaryY = (int32_t)extentHeight + offset.y - (int32_t)pixelHeight_; if (boundaryY > 0) { - extentHeight -= boundaryY; + extentHeight -= boundaryY; } VkExtent2D extent; @@ -167,30 +169,53 @@ void VulkanGridObserver::render(vk::VulkanRenderContext& ctx) const { outx++; } } - } // namespace griddly - else { - // TODO: Because this observation is not actually moving we can almost certainly optimize this to only update the updated locations - //if (observerConfig_.gridXOffset != 0 || observerConfig_.gridYOffset != 0) { - auto left = observerConfig_.gridXOffset; - auto right = observerConfig_.gridXOffset + gridWidth_; - auto bottom = observerConfig_.gridYOffset; - auto top = observerConfig_.gridYOffset + gridHeight_; - int32_t outx = 0, outy = 0; - for (auto objx = left; objx < right; objx++) { - outy = 0; - for (auto objy = bottom; objy < top; objy++) { - renderLocation(ctx, {objx, objy}, {outx, outy}, tileOffset, Direction::NONE); - outy++; + } else { + // in 2D RTS games have to render the objects around the rendered location so the highlighting works correctly + if (observerConfig_.playerCount > 1) { + auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); + + for (auto& location : updatedLocations) { + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + auto sublocation = glm::ivec2( + location.x + i, + location.y + j); + + if (sublocation.x >= observerConfig_.gridXOffset && + sublocation.x < gridWidth_ + observerConfig_.gridXOffset && + sublocation.y >= observerConfig_.gridYOffset && + sublocation.y < gridHeight_ + observerConfig_.gridYOffset) { + auto outputLocation = glm::ivec2( + sublocation.x - observerConfig_.gridXOffset, + sublocation.y - observerConfig_.gridYOffset); + + if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { + renderLocation(ctx, sublocation, outputLocation, tileOffset, Direction::NONE); + } + } + } + } } - outx++; - } - // } else { - // auto updatedLocations = grid_->getUpdatedLocations(); - // for (auto location : updatedLocations) { - // renderLocation(ctx, location, location, tileOffset, Direction::NONE); - // } - // } + } else { + auto& updatedLocations = grid_->getUpdatedLocations(observerConfig_.playerId); + + for (auto& location : updatedLocations) { + if (location.x >= observerConfig_.gridXOffset && + location.x < gridWidth_ + observerConfig_.gridXOffset && + location.y >= observerConfig_.gridYOffset && + location.y < gridHeight_ + observerConfig_.gridYOffset) { + auto outputLocation = glm::ivec2( + location.x - observerConfig_.gridXOffset, + location.y - observerConfig_.gridYOffset); + + if (outputLocation.x < gridWidth_ && outputLocation.x >= 0 && outputLocation.y < gridHeight_ && outputLocation.y >= 0) { + renderLocation(ctx, location, outputLocation, tileOffset, Direction::NONE); + } + } + } + } } -} // namespace griddly +} + } // namespace griddly \ No newline at end of file diff --git a/tests/resources/observer/isometric/defaultObserverConfig.png b/tests/resources/observer/isometric/defaultObserverConfig.png index f45901c82..a3968d89e 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig.png and b/tests/resources/observer/isometric/defaultObserverConfig.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar.png index f45901c82..a3968d89e 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png index 645722391..a2d284b21 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_DOWN.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png index 2e5688cd3..064f32130 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_LEFT.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png index f45901c82..a3968d89e 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_NONE.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png index 6c5adfe62..6dc52ca71 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_RIGHT.png differ diff --git a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png index f45901c82..a3968d89e 100644 Binary files a/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png and b/tests/resources/observer/isometric/defaultObserverConfig_trackAvatar_rotateWithAvatar_UP.png differ diff --git a/tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png b/tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png and b/tests/resources/observer/isometric/partialObserver_trackAvatar_DOWN.png differ diff --git a/tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png b/tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png and b/tests/resources/observer/isometric/partialObserver_trackAvatar_LEFT.png differ diff --git a/tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png b/tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png and b/tests/resources/observer/isometric/partialObserver_trackAvatar_NONE.png differ diff --git a/tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png b/tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png and b/tests/resources/observer/isometric/partialObserver_trackAvatar_RIGHT.png differ diff --git a/tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png b/tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png and b/tests/resources/observer/isometric/partialObserver_trackAvatar_UP.png differ diff --git a/tests/resources/observer/isometric/partialObserver_withOffset.png b/tests/resources/observer/isometric/partialObserver_withOffset.png index 5b7f68892..b7f59079c 100644 Binary files a/tests/resources/observer/isometric/partialObserver_withOffset.png and b/tests/resources/observer/isometric/partialObserver_withOffset.png differ diff --git a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png index 6981d7559..da1ca80df 100644 Binary files a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png and b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_DOWN.png differ diff --git a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png index da139b758..539c379aa 100644 Binary files a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png and b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_LEFT.png differ diff --git a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png index 8fb70bbb5..966ee2c04 100644 Binary files a/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png and b/tests/resources/observer/isometric/partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Global.png b/tests/resources/observer/sprite/multiPlayer_Outline_Global.png index 8676664fc..ee537f4bc 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Global.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Global.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png index d6169fd70..32299f64b 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player1.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png index d35846293..484b40f16 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player2.png differ diff --git a/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png b/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png index 0ca1d8d9d..94e26d0e5 100644 Binary files a/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png and b/tests/resources/observer/sprite/multiPlayer_Outline_Player3.png differ diff --git a/tests/src/Griddly/Core/GDY/Actions/ActionTest.cpp b/tests/src/Griddly/Core/GDY/Actions/ActionTest.cpp index e01e87ea2..f67a34e24 100644 --- a/tests/src/Griddly/Core/GDY/Actions/ActionTest.cpp +++ b/tests/src/Griddly/Core/GDY/Actions/ActionTest.cpp @@ -1,5 +1,5 @@ #include "Griddly/Core/GDY/Actions/Action.hpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp b/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp index 07c0c5904..9165a649e 100644 --- a/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp +++ b/tests/src/Griddly/Core/GDY/GDYFactoryTest.cpp @@ -6,11 +6,11 @@ #include "Griddly/Core/GDY/Actions/Action.hpp" #include "Griddly/Core/GDY/GDYFactory.hpp" -#include "Mocks//Griddly/Core/LevelGenerators/MockLevelGenerator.cpp" -#include "Mocks/Griddly/Core/GDY/MockTerminationGenerator.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObject.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks//Griddly/Core/LevelGenerators/MockLevelGenerator.hpp" +#include "Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObject.hpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp b/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp index d0a0aedd0..8e0bad5d8 100644 --- a/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp +++ b/tests/src/Griddly/Core/GDY/Objects/ObjectTest.cpp @@ -2,9 +2,9 @@ #include "Griddly/Core/GDY/Objects/Object.hpp" #include "Griddly/Core/GDY/Objects/ObjectGenerator.hpp" -#include "Mocks/Griddly/Core/GDY/Actions/MockAction.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/GDY/Actions/MockAction.hpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp b/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp index 750f3b1cc..b31304605 100644 --- a/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp +++ b/tests/src/Griddly/Core/GDY/TerminationHandlerTest.cpp @@ -3,8 +3,8 @@ #include #include "Griddly/Core/GDY/TerminationHandler.hpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" -#include "Mocks/Griddly/Core/Players/MockPlayer.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "Mocks/Griddly/Core/Players/MockPlayer.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Griddly/Core/GameProcessTest.cpp b/tests/src/Griddly/Core/GameProcessTest.cpp index ab59f9923..80f0e0c90 100644 --- a/tests/src/Griddly/Core/GameProcessTest.cpp +++ b/tests/src/Griddly/Core/GameProcessTest.cpp @@ -2,12 +2,12 @@ #include "Griddly/Core/TestUtils/common.hpp" #include "Griddly/Core/TurnBasedGameProcess.cpp" -#include "Mocks/Griddly/Core/GDY/MockGDYFactory.cpp" -#include "Mocks/Griddly/Core/GDY/MockTerminationHandler.cpp" -#include "Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" -#include "Mocks/Griddly/Core/Observers/MockObserver.cpp" -#include "Mocks/Griddly/Core/Players/MockPlayer.cpp" +#include "Mocks/Griddly/Core/GDY/MockGDYFactory.hpp" +#include "Mocks/Griddly/Core/GDY/MockTerminationHandler.hpp" +#include "Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.hpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "Mocks/Griddly/Core/Observers/MockObserver.hpp" +#include "Mocks/Griddly/Core/Players/MockPlayer.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Griddly/Core/LevelGenerator/MapReaderTest.cpp b/tests/src/Griddly/Core/LevelGenerator/MapReaderTest.cpp index 3e1c366dd..ec085d696 100644 --- a/tests/src/Griddly/Core/LevelGenerator/MapReaderTest.cpp +++ b/tests/src/Griddly/Core/LevelGenerator/MapReaderTest.cpp @@ -2,9 +2,9 @@ #include #include "Griddly/Core/LevelGenerators/MapReader.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObject.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObject.hpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" using ::testing::_; diff --git a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp index 6ac5f4c02..8a920552c 100644 --- a/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/BlockObserverTest.cpp @@ -1,7 +1,8 @@ #include "Griddly/Core/Observers/BlockObserver.hpp" -#include "Griddly/Core/TestUtils/common.hpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "ObserverTestData.hpp" +#include "ObserverRTSTestData.hpp" #include "VulkanObserverTest.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -14,109 +15,10 @@ using ::testing::Mock; using ::testing::Pair; using ::testing::Return; using ::testing::ReturnRef; +using ::testing::Invoke; namespace griddly { -std::unordered_set> blocks_mockRTSGridFunctions(std::shared_ptr& mockGridPtr) { - // make a grid where multiple objects are owned by different players - // 1 1 1 1 1 - // 1 A1 B2 C3 1 - // 1 A2 B3 C1 1 - // 1 A3 B1 C2 1 - // 1 1 1 1 1 - - auto mockObjectWallPtr = mockObject("W", 0, 3); - - auto mockObjectA1Ptr = mockObject("A", 1, 0); - auto mockObjectA2Ptr = mockObject("A", 2, 0); - auto mockObjectA3Ptr = mockObject("A", 3, 0); - - auto mockObjectB1Ptr = mockObject("B", 1, 1); - auto mockObjectB2Ptr = mockObject("B", 2, 1); - auto mockObjectB3Ptr = mockObject("B", 3, 1); - - auto mockObjectC1Ptr = mockObject("C", 1, 2); - auto mockObjectC2Ptr = mockObject("C", 2, 2); - auto mockObjectC3Ptr = mockObject("C", 3, 2); - - auto objects = std::unordered_set>{ - mockObjectWallPtr, - mockObjectA1Ptr, - mockObjectA2Ptr, - mockObjectA3Ptr, - mockObjectB1Ptr, - mockObjectB2Ptr, - mockObjectB3Ptr, - mockObjectC1Ptr, - mockObjectC2Ptr, - mockObjectC3Ptr}; - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObjectA1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{{0, mockObjectB1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObjectC1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObjectA2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockObjectB2Ptr}})); - ; - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObjectC2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObjectA3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{{0, mockObjectB3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObjectC3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); - - return objects; -} - std::unordered_map getMockRTSBlockDefinitions() { float red[]{0.5, 0.2, 0.2}; float green[]{0.2, 0.5, 0.2}; @@ -169,95 +71,6 @@ std::unordered_map getMockRTSBlockDefinitions() { }; } -void blocks_mockGridFunctions(std::shared_ptr& mockGridPtr, std::shared_ptr& mockAvatarObjectPtr) { - // make a 5 by 5 grid with an avatar in the center and some stuff around it, there are 4 types of object - // "4" is the avatar type - // 11111 - // 12031 - // 12431 - // 13021 - // 11111 - - auto mockObject1Ptr = mockObject("mo1", 1, 0); - auto mockObject2Ptr = mockObject("mo2", 1, 1); - auto mockObject3Ptr = mockObject("mo3", 1, 2); - - auto objects = std::unordered_set>{mockObject1Ptr, mockObject2Ptr, mockObject3Ptr}; - - EXPECT_CALL(*mockGridPtr, getObjects()) - .WillRepeatedly(ReturnRef(objects)); - - EXPECT_CALL(*mockAvatarObjectPtr, getObjectId()).WillRepeatedly(Return(3)); - EXPECT_CALL(*mockAvatarObjectPtr, getLocation()).WillRepeatedly(Return(glm::ivec2{2, 2})); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectName()).WillRepeatedly(Return("avatar")); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectRenderTileName()).WillRepeatedly(Return("avatar" + std::to_string(0))); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - // A horrible way of making a mock grid but fuck it - ON_CALL(*mockGridPtr, getObjectsAt).WillByDefault(Return(std::map>{})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockAvatarObjectPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); -} - std::unordered_map getMockBlockDefinitions() { float red[]{1.0, 0.0, 0.0}; float green[]{0.0, 1.0, 0.0}; @@ -292,7 +105,7 @@ std::unordered_map getMockBlockDefinitions() { mockObject3BlockDefinition.shape = square; mockObject3BlockDefinition.scale = 0.7f; - // mock avatar 3 + // mock avatar BlockDefinition mockAvatarBlockDefinition; for (std::size_t c = 0; c < 3; c++) { mockAvatarBlockDefinition.color[c] = white[c]; @@ -315,28 +128,17 @@ void runBlockObserverTest(ObserverConfig observerConfig, std::string filenameExpectedOutputFilename, bool trackAvatar, bool writeOutputFile = false) { - ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; + ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; observerConfig.tileSize = glm::ivec2(20, 20); + ObserverTestData testEnvironment = ObserverTestData(observerConfig, DiscreteOrientation(avatarDirection), trackAvatar); - auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(mockGridPtr, resourceConfig, getMockBlockDefinitions())); - - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); - - auto mockAvatarObjectPtr = std::shared_ptr(new MockObject()); - auto orientation = DiscreteOrientation(avatarDirection); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectOrientation).WillRepeatedly(Return(orientation)); - - blocks_mockGridFunctions(mockGridPtr, mockAvatarObjectPtr); + std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(testEnvironment.mockGridPtr, resourceConfig, getMockBlockDefinitions())); blockObserver->init(observerConfig); if (trackAvatar) { - blockObserver->setAvatar(mockAvatarObjectPtr); + blockObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } auto resetObservation = blockObserver->reset(); @@ -362,8 +164,7 @@ void runBlockObserverTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockAvatarObjectPtr.get())); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + testEnvironment.verifyAndClearExpectations(); } void runBlockObserverRTSTest(ObserverConfig observerConfig, @@ -375,16 +176,10 @@ void runBlockObserverRTSTest(ObserverConfig observerConfig, observerConfig.tileSize = glm::ivec2(50, 50); auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(mockGridPtr, resourceConfig, getMockRTSBlockDefinitions())); - auto objects = blocks_mockRTSGridFunctions(mockGridPtr); - - EXPECT_CALL(*mockGridPtr, getObjects) - .WillRepeatedly(ReturnRef(objects)); - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); + ObserverRTSTestData testEnvironment = ObserverRTSTestData(observerConfig); + + std::shared_ptr blockObserver = std::shared_ptr(new BlockObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSBlockDefinitions())); blockObserver->init(observerConfig); @@ -410,7 +205,7 @@ void runBlockObserverRTSTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + testEnvironment.verifyAndClearExpectations(); } TEST(BlockObserverTest, defaultObserverConfig) { diff --git a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp index 6ed7b246d..4485f562f 100644 --- a/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/IsometricSpriteObserverTest.cpp @@ -1,6 +1,7 @@ #include "Griddly/Core/Observers/IsometricSpriteObserver.hpp" -#include "Griddly/Core/TestUtils/common.hpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "ObserverRTSTestData.hpp" +#include "ObserverTestData.hpp" #include "VulkanObserverTest.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -9,6 +10,7 @@ using ::testing::AnyNumber; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::Eq; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Pair; using ::testing::Return; @@ -16,135 +18,6 @@ using ::testing::ReturnRef; namespace griddly { -std::unordered_set> isometricSprites_mockRTSGridFunctions(std::shared_ptr& mockGridPtr) { - // make a grid where multiple objects are owned by different players - // 1 1 1 1 1 - // 1 A1 B2 C3 1 - // 1 A2 B3 C1 1 - // 1 A3 B1 C2 1 - // 1 1 1 1 1 - - auto mockObjectWallPtr = mockObject("W", 0, 3); - - auto mockObjectA1Ptr = mockObject("A", 1, 0); - auto mockObjectA2Ptr = mockObject("A", 2, 0); - auto mockObjectA3Ptr = mockObject("A", 3, 0); - - auto mockObjectB1Ptr = mockObject("B", 1, 1); - auto mockObjectB2Ptr = mockObject("B", 2, 1); - auto mockObjectB3Ptr = mockObject("B", 3, 1); - - auto mockObjectC1Ptr = mockObject("C", 1, 2); - auto mockObjectC2Ptr = mockObject("C", 2, 2); - auto mockObjectC3Ptr = mockObject("C", 3, 2); - - auto objects = std::unordered_set>{ - mockObjectWallPtr, - mockObjectA1Ptr, - mockObjectA2Ptr, - mockObjectA3Ptr, - mockObjectB1Ptr, - mockObjectB2Ptr, - mockObjectB3Ptr, - mockObjectC1Ptr, - mockObjectC2Ptr, - mockObjectC3Ptr}; - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObjectA1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{{0, mockObjectB1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObjectC1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObjectA2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockObjectB2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObjectC2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObjectA3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{{0, mockObjectB3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObjectC3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(mockObjectA1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(mockObjectB1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(mockObjectC1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(mockObjectA2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(mockObjectB2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(mockObjectC2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(mockObjectA3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(mockObjectB3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(mockObjectC3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(mockObjectWallPtr)); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); - - return objects; -} - std::unordered_map getMockRTSIsometricSpriteDefinitions() { // mock wall object SpriteDefinition mockObject1SpriteDefinition; @@ -203,17 +76,10 @@ void runIsometricSpriteObserverRTSTest(ObserverConfig observerConfig, observerConfig.isoTileDepth = 4; auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(mockGridPtr, resourceConfig, getMockRTSIsometricSpriteDefinitions())); - - auto objects = isometricSprites_mockRTSGridFunctions(mockGridPtr); - EXPECT_CALL(*mockGridPtr, getObjects) - .WillRepeatedly(ReturnRef(objects)); + ObserverRTSTestData testEnvironment = ObserverRTSTestData(observerConfig); - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); + std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSIsometricSpriteDefinitions())); isometricObserver->init(observerConfig); @@ -240,126 +106,7 @@ void runIsometricSpriteObserverRTSTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); -} - -std::unordered_set> isometricSprites_mockGridFunctions(std::shared_ptr& mockGridPtr, std::shared_ptr& mockAvatarObjectPtr) { - // make a 5 by 5 grid with an avatar in the center and some stuff around it, there are 4 types of object - // "4" is the avatar type - // 11111 - // 12031 - // 12431 - // 13021 - // 11111 - - auto mockObject1Ptr = mockObject("mo1", 1, 0); - auto mockObject2Ptr = mockObject("mo2", 1, 1); - auto mockObject3Ptr = mockObject("mo3", 1, 2); - - auto objects = std::unordered_set>{mockObject1Ptr, mockObject2Ptr, mockObject3Ptr}; - - EXPECT_CALL(*mockAvatarObjectPtr, getObjectId()).WillRepeatedly(Return(3)); - EXPECT_CALL(*mockAvatarObjectPtr, getLocation()).WillRepeatedly(Return(glm::ivec2{2, 2})); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectName()).WillRepeatedly(Return("avatar")); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectRenderTileName()).WillRepeatedly(Return("avatar" + std::to_string(0))); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - // A horrible way of making a mock grid but fuck it - ON_CALL(*mockGridPtr, getObjectsAt).WillByDefault(Return(std::map>{})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockAvatarObjectPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - // So the tiling for isometrics is calculated correctly for walls - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(nullptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(mockAvatarObjectPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(mockObject1Ptr)); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); - - return objects; + testEnvironment.verifyAndClearExpectations(); } std::unordered_map getMockIsometricSpriteDefinitions() { @@ -421,27 +168,14 @@ void runIsometricSpriteObserverTest(ObserverConfig observerConfig, observerConfig.isoTileHeight = 16; observerConfig.isoTileDepth = 4; - auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(mockGridPtr, resourceConfig, getMockIsometricSpriteDefinitions())); - - auto mockAvatarObjectPtr = std::shared_ptr(new MockObject()); - auto orientation = DiscreteOrientation(avatarDirection); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectOrientation).WillRepeatedly(Return(orientation)); - - auto objects = isometricSprites_mockGridFunctions(mockGridPtr, mockAvatarObjectPtr); - - EXPECT_CALL(*mockGridPtr, getObjects()) - .WillRepeatedly(ReturnRef(objects)); + ObserverTestData testEnvironment = ObserverTestData(observerConfig, DiscreteOrientation(avatarDirection), trackAvatar); - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); + std::shared_ptr isometricObserver = std::shared_ptr(new IsometricSpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockIsometricSpriteDefinitions())); isometricObserver->init(observerConfig); if (trackAvatar) { - isometricObserver->setAvatar(mockAvatarObjectPtr); + isometricObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } auto resetObservation = isometricObserver->reset(); @@ -464,8 +198,7 @@ void runIsometricSpriteObserverTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockAvatarObjectPtr.get())); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + testEnvironment.verifyAndClearExpectations(); } TEST(IsometricSpriteObserverTest, defaultObserverConfig) { diff --git a/tests/src/Griddly/Core/Observers/ObserverRTSTestData.hpp b/tests/src/Griddly/Core/Observers/ObserverRTSTestData.hpp new file mode 100644 index 000000000..aeec65626 --- /dev/null +++ b/tests/src/Griddly/Core/Observers/ObserverRTSTestData.hpp @@ -0,0 +1,168 @@ +#include "Griddly/Core/TestUtils/common.hpp" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using ::testing::AnyNumber; +using ::testing::AtLeast; +using ::testing::ElementsAre; +using ::testing::ElementsAreArray; +using ::testing::Eq; +using ::testing::Invoke; +using ::testing::Mock; +using ::testing::Pair; +using ::testing::Return; +using ::testing::ReturnRef; + +namespace griddly { + +class ObserverRTSTestData { + public: + ObserverRTSTestData(ObserverConfig observerConfig) { + // make a grid where multiple objects are owned by different players + // 1 1 1 1 1 + // 1 A1 B2 C3 1 + // 1 A2 B3 C1 1 + // 1 A3 B1 C2 1 + // 1 1 1 1 1 + + mockObjectWallPtr = mockObject("W", 0, 3); + mockObjectA1Ptr = mockObject("A", 1, 0); + mockObjectA2Ptr = mockObject("A", 2, 0); + mockObjectA3Ptr = mockObject("A", 3, 0); + mockObjectB1Ptr = mockObject("B", 1, 1); + mockObjectB2Ptr = mockObject("B", 2, 1); + mockObjectB3Ptr = mockObject("B", 3, 1); + mockObjectC1Ptr = mockObject("C", 1, 2); + mockObjectC2Ptr = mockObject("C", 2, 2); + mockObjectC3Ptr = mockObject("C", 3, 2); + + mockRTSObjects = std::unordered_set>{ + mockObjectWallPtr, + mockObjectA1Ptr, + mockObjectA2Ptr, + mockObjectA3Ptr, + mockObjectB1Ptr, + mockObjectB2Ptr, + mockObjectB3Ptr, + mockObjectC1Ptr, + mockObjectC2Ptr, + mockObjectC3Ptr}; + + mockRTSGridData = { + {{0, 0}, {{0, mockObjectWallPtr}}}, + {{1, 0}, {{0, mockObjectWallPtr}}}, + {{2, 0}, {{0, mockObjectWallPtr}}}, + {{3, 0}, {{0, mockObjectWallPtr}}}, + {{4, 0}, {{0, mockObjectWallPtr}}}, + + {{0, 1}, {{0, mockObjectWallPtr}}}, + {{1, 1}, {{0, mockObjectA1Ptr}}}, + {{2, 1}, {{0, mockObjectB1Ptr}}}, + {{3, 1}, {{0, mockObjectC1Ptr}}}, + {{4, 1}, {{0, mockObjectWallPtr}}}, + + {{0, 2}, {{0, mockObjectWallPtr}}}, + {{1, 2}, {{0, mockObjectA2Ptr}}}, + {{2, 2}, {{0, mockObjectB2Ptr}}}, + {{3, 2}, {{0, mockObjectC2Ptr}}}, + {{4, 2}, {{0, mockObjectWallPtr}}}, + + {{0, 3}, {{0, mockObjectWallPtr}}}, + {{1, 3}, {{0, mockObjectA3Ptr}}}, + {{2, 3}, {{0, mockObjectB3Ptr}}}, + {{3, 3}, {{0, mockObjectC3Ptr}}}, + {{4, 3}, {{0, mockObjectWallPtr}}}, + + {{0, 4}, {{0, mockObjectWallPtr}}}, + {{1, 4}, {{0, mockObjectWallPtr}}}, + {{2, 4}, {{0, mockObjectWallPtr}}}, + {{3, 4}, {{0, mockObjectWallPtr}}}, + {{4, 4}, {{0, mockObjectWallPtr}}}, + }; + + mockGridPtr = std::shared_ptr(new MockGrid()); + EXPECT_CALL(*mockGridPtr, getWidth) + .WillRepeatedly(Return(5)); + EXPECT_CALL(*mockGridPtr, getHeight) + .WillRepeatedly(Return(5)); + + EXPECT_CALL(*mockGridPtr, getObjects()).WillRepeatedly(ReturnRef(mockRTSObjects)); + EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); + EXPECT_CALL(*mockGridPtr, getUpdatedLocations).WillRepeatedly(ReturnRef(mockRTSUpdatedLocations)); + + bool hasOffsets = observerConfig.gridXOffset != 0 || observerConfig.gridYOffset != 0; + + if (!hasOffsets) { + EXPECT_CALL(*mockGridPtr, purgeUpdatedLocations).Times(AtLeast(1)); + } + + EXPECT_CALL(*mockGridPtr, getObjectsAt).WillRepeatedly(Invoke([this](glm::ivec2 location) -> const TileObjects& { + return mockRTSGridData.at(location); + })); + + EXPECT_CALL(*mockGridPtr, getObject).WillRepeatedly(Invoke([this](glm::ivec2 location) -> const std::shared_ptr { + if (mockRTSGridData.find(location) == mockRTSGridData.end()) { + return nullptr; + } + + auto objectsAt = mockRTSGridData.at(location); + if (objectsAt.size() > 0) { + return objectsAt.at(0); + } else { + return nullptr; + } + })); + + } + + std::shared_ptr mockGridPtr; + + std::shared_ptr mockObjectWallPtr; + std::shared_ptr mockObjectA1Ptr; + std::shared_ptr mockObjectA2Ptr; + std::shared_ptr mockObjectA3Ptr; + std::shared_ptr mockObjectB1Ptr; + std::shared_ptr mockObjectB2Ptr; + std::shared_ptr mockObjectB3Ptr; + std::shared_ptr mockObjectC1Ptr; + std::shared_ptr mockObjectC2Ptr; + std::shared_ptr mockObjectC3Ptr; + + std::unordered_set> mockRTSObjects; + + std::unordered_map mockRTSGridData; + + const std::unordered_set mockRTSUpdatedLocations = { + {0, 0}, + {0, 1}, + {0, 2}, + {0, 3}, + {0, 4}, + {1, 0}, + {1, 1}, + {1, 2}, + {1, 3}, + {1, 4}, + {2, 0}, + {2, 1}, + {2, 2}, + {2, 3}, + {2, 4}, + {3, 0}, + {3, 1}, + {3, 2}, + {3, 3}, + {3, 4}, + {4, 0}, + {4, 1}, + {4, 2}, + {4, 3}, + {4, 4}, + }; + + void verifyAndClearExpectations() { + EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + } +}; + +} \ No newline at end of file diff --git a/tests/src/Griddly/Core/Observers/ObserverTestData.hpp b/tests/src/Griddly/Core/Observers/ObserverTestData.hpp new file mode 100644 index 000000000..89b1c1386 --- /dev/null +++ b/tests/src/Griddly/Core/Observers/ObserverTestData.hpp @@ -0,0 +1,141 @@ +#include "Griddly/Core/TestUtils/common.hpp" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using ::testing::AnyNumber; +using ::testing::ElementsAre; +using ::testing::ElementsAreArray; +using ::testing::Eq; +using ::testing::Invoke; +using ::testing::Mock; +using ::testing::Pair; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::AtLeast; + +namespace griddly { + +class ObserverTestData { + public: + ObserverTestData(ObserverConfig observerConfig, DiscreteOrientation orientation, bool trackAvatar) { + mockAvatarObjectPtr = mockObject("avatar", 1, 3, 0, {2, 2}); + mockSinglePlayerObject1Ptr = mockObject("mo1", 1, 0); + mockSinglePlayerObject2Ptr = mockObject("mo2", 1, 1); + mockSinglePlayerObject3Ptr = mockObject("mo3", 1, 2); + mockSinglePlayerObjects = {mockSinglePlayerObject1Ptr, mockSinglePlayerObject2Ptr, mockSinglePlayerObject3Ptr}; + + mockSinglePlayerGridData = { + {{0, 0}, {{0, mockSinglePlayerObject1Ptr}}}, + {{1, 0}, {{0, mockSinglePlayerObject1Ptr}}}, + {{2, 0}, {{0, mockSinglePlayerObject1Ptr}}}, + {{3, 0}, {{0, mockSinglePlayerObject1Ptr}}}, + {{4, 0}, {{0, mockSinglePlayerObject1Ptr}}}, + + {{0, 1}, {{0, mockSinglePlayerObject1Ptr}}}, + {{1, 1}, {{0, mockSinglePlayerObject2Ptr}}}, + {{2, 1}, {}}, + {{3, 1}, {{0, mockSinglePlayerObject3Ptr}}}, + {{4, 1}, {{0, mockSinglePlayerObject1Ptr}}}, + + {{0, 2}, {{0, mockSinglePlayerObject1Ptr}}}, + {{1, 2}, {{0, mockSinglePlayerObject2Ptr}}}, + {{2, 2}, {{0, mockAvatarObjectPtr}}}, + {{3, 2}, {{0, mockSinglePlayerObject3Ptr}}}, + {{4, 2}, {{0, mockSinglePlayerObject1Ptr}}}, + + {{0, 3}, {{0, mockSinglePlayerObject1Ptr}}}, + {{1, 3}, {{0, mockSinglePlayerObject3Ptr}}}, + {{2, 3}, {}}, + {{3, 3}, {{0, mockSinglePlayerObject2Ptr}}}, + {{4, 3}, {{0, mockSinglePlayerObject1Ptr}}}, + + {{0, 4}, {{0, mockSinglePlayerObject1Ptr}}}, + {{1, 4}, {{0, mockSinglePlayerObject1Ptr}}}, + {{2, 4}, {{0, mockSinglePlayerObject1Ptr}}}, + {{3, 4}, {{0, mockSinglePlayerObject1Ptr}}}, + {{4, 4}, {{0, mockSinglePlayerObject1Ptr}}}, + }; + + mockGridPtr = std::shared_ptr(new MockGrid()); + EXPECT_CALL(*mockGridPtr, getWidth) + .WillRepeatedly(Return(5)); + EXPECT_CALL(*mockGridPtr, getHeight) + .WillRepeatedly(Return(5)); + + EXPECT_CALL(*mockGridPtr, getObjects()).WillRepeatedly(ReturnRef(mockSinglePlayerObjects)); + EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); + EXPECT_CALL(*mockGridPtr, getUpdatedLocations).WillRepeatedly(ReturnRef(mockSinglePlayerUpdatedLocations)); + + bool hasOffsets = observerConfig.gridXOffset != 0 || observerConfig.gridYOffset != 0; + + if (!trackAvatar && !hasOffsets) { + EXPECT_CALL(*mockGridPtr, purgeUpdatedLocations).Times(AtLeast(1)); + } + EXPECT_CALL(*mockGridPtr, getObjectsAt).WillRepeatedly(Invoke([this](glm::ivec2 location) -> const TileObjects& { + return mockSinglePlayerGridData.at(location); + })); + + EXPECT_CALL(*mockGridPtr, getObject).WillRepeatedly(Invoke([this](glm::ivec2 location) -> const std::shared_ptr { + + if(mockSinglePlayerGridData.find(location) == mockSinglePlayerGridData.end()) { + return nullptr; + } + + auto objectsAt = mockSinglePlayerGridData.at(location); + if (objectsAt.size() > 0) { + return objectsAt.at(0); + } else { + return nullptr; + } + })); + + EXPECT_CALL(*mockAvatarObjectPtr, getObjectRenderTileName()).WillRepeatedly(Return("avatar" + std::to_string(0))); + EXPECT_CALL(*mockAvatarObjectPtr, getObjectOrientation).WillRepeatedly(Return(orientation)); + } + + std::shared_ptr mockGridPtr; + + std::shared_ptr mockAvatarObjectPtr; + std::shared_ptr mockSinglePlayerObject1Ptr; + std::shared_ptr mockSinglePlayerObject2Ptr; + std::shared_ptr mockSinglePlayerObject3Ptr; + + std::unordered_set> mockSinglePlayerObjects; + + std::unordered_map mockSinglePlayerGridData; + + const std::unordered_set mockSinglePlayerUpdatedLocations = { + {0, 0}, + {0, 1}, + {0, 2}, + {0, 3}, + {0, 4}, + {1, 0}, + {1, 1}, + {1, 2}, + {1, 3}, + {1, 4}, + {2, 0}, + {2, 1}, + {2, 2}, + {2, 3}, + {2, 4}, + {3, 0}, + {3, 1}, + {3, 2}, + {3, 3}, + {3, 4}, + {4, 0}, + {4, 1}, + {4, 2}, + {4, 3}, + {4, 4}, + }; + + void verifyAndClearExpectations() { + EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockAvatarObjectPtr.get())); + EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + } +}; + +} // namespace griddly \ No newline at end of file diff --git a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp index 0f95587bb..3874befc9 100644 --- a/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/SpriteObserverTest.cpp @@ -1,6 +1,7 @@ #include "Griddly/Core/Observers/SpriteObserver.hpp" -#include "Griddly/Core/TestUtils/common.hpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "ObserverRTSTestData.hpp" +#include "ObserverTestData.hpp" #include "VulkanObserverTest.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -9,6 +10,7 @@ using ::testing::AnyNumber; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::Eq; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Pair; using ::testing::Return; @@ -16,136 +18,6 @@ using ::testing::ReturnRef; namespace griddly { -std::unordered_set> sprites_mockRTSGridFunctions(std::shared_ptr& mockGridPtr) { - // make a grid where multiple objects are owned by different players - // 1 1 1 1 1 - // 1 A1 B2 C3 1 - // 1 A2 B3 C1 1 - // 1 A3 B1 C2 1 - // 1 1 1 1 1 - - auto mockObjectWallPtr = mockObject("W", 0, 3); - - auto mockObjectA1Ptr = mockObject("A", 1, 0); - auto mockObjectA2Ptr = mockObject("A", 2, 0); - auto mockObjectA3Ptr = mockObject("A", 3, 0); - - auto mockObjectB1Ptr = mockObject("B", 1, 1); - auto mockObjectB2Ptr = mockObject("B", 2, 1); - auto mockObjectB3Ptr = mockObject("B", 3, 1); - - auto mockObjectC1Ptr = mockObject("C", 1, 2); - auto mockObjectC2Ptr = mockObject("C", 2, 2); - auto mockObjectC3Ptr = mockObject("C", 3, 2); - - auto objects = std::unordered_set>{ - mockObjectWallPtr, - mockObjectA1Ptr, - mockObjectA2Ptr, - mockObjectA3Ptr, - mockObjectB1Ptr, - mockObjectB2Ptr, - mockObjectB3Ptr, - mockObjectC1Ptr, - mockObjectC2Ptr, - mockObjectC3Ptr}; - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))) - .WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObjectA1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{{0, mockObjectB1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObjectC1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObjectA2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockObjectB2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObjectC2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObjectA3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{{0, mockObjectB3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObjectC3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObjectWallPtr}})); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(mockObjectA1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(mockObjectB1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(mockObjectC1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(mockObjectA2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(mockObjectB2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(mockObjectC2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(mockObjectA3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(mockObjectB3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(mockObjectC3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(mockObjectWallPtr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(mockObjectWallPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(mockObjectWallPtr)); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); - - return objects; -} - std::unordered_map getMockRTSSpriteDefinitions() { // mock wall object SpriteDefinition mockObjectWallBlockDefinition; @@ -215,17 +87,10 @@ void runSpriteObserverRTSTest(ObserverConfig observerConfig, observerConfig.tileSize = glm::ivec2(50, 50); auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(mockGridPtr, resourceConfig, getMockRTSSpriteDefinitions())); - - auto objects = sprites_mockRTSGridFunctions(mockGridPtr); - EXPECT_CALL(*mockGridPtr, getObjects) - .WillRepeatedly(ReturnRef(objects)); + ObserverRTSTestData testEnvironment = ObserverRTSTestData(observerConfig); - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); + std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockRTSSpriteDefinitions())); spriteObserver->init(observerConfig); @@ -252,127 +117,7 @@ void runSpriteObserverRTSTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); -} - -std::unordered_set> sprites_mockGridFunctions(std::shared_ptr& mockGridPtr, std::shared_ptr& mockAvatarObjectPtr) { - // make a 5 by 5 grid with an avatar in the center and some stuff around it, there are 4 types of object - // "4" is the avatar type - // 11111 - // 12031 - // 12431 - // 13021 - // 11111 - - auto mockObject1Ptr = mockObject("mo1", 1, 0); - auto mockObject2Ptr = mockObject("mo2", 1, 1); - auto mockObject3Ptr = mockObject("mo3", 1, 2); - - auto objects = std::unordered_set>{mockObject1Ptr, mockObject2Ptr, mockObject3Ptr}; - - EXPECT_CALL(*mockAvatarObjectPtr, getObjectId()) - .WillRepeatedly(Return(3)); - EXPECT_CALL(*mockAvatarObjectPtr, getLocation()).WillRepeatedly(Return(glm::ivec2{2, 2})); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectName()).WillRepeatedly(Return("avatar")); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectRenderTileName()).WillRepeatedly(Return("avatar" + std::to_string(0))); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - // A horrible way of making a mock grid but fuck it - ON_CALL(*mockGridPtr, getObjectsAt).WillByDefault(Return(std::map>{})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockAvatarObjectPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - // So the tiling for sprites is calculated correctly for walls - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(nullptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(mockAvatarObjectPtr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(mockObject3Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(nullptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(mockObject2Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(mockObject1Ptr)); - - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(mockObject1Ptr)); - ON_CALL(*mockGridPtr, getObject(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(mockObject1Ptr)); - - std::unordered_set updatedLocations = { - {0, 0}, - {0, 1}, - {0, 2}, - {0, 3}, - {0, 4}, - {1, 0}, - {1, 1}, - {1, 2}, - {1, 3}, - {1, 4}, - {2, 0}, - {2, 1}, - {2, 2}, - {2, 3}, - {2, 4}, - {3, 0}, - {3, 1}, - {3, 2}, - {3, 3}, - {3, 4}, - {4, 0}, - {4, 1}, - {4, 2}, - {4, 3}, - {4, 4}, - }; - - ON_CALL(*mockGridPtr, getUpdatedLocations).WillByDefault(Return(updatedLocations)); - - return objects; + testEnvironment.verifyAndClearExpectations(); } std::unordered_map getMockSpriteDefinitions() { @@ -445,27 +190,14 @@ void runSpriteObserverTest(ObserverConfig observerConfig, ResourceConfig resourceConfig = {"resources/images", "resources/shaders"}; observerConfig.tileSize = glm::ivec2(24, 24); - auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(mockGridPtr, resourceConfig, getMockSpriteDefinitions())); - - auto mockAvatarObjectPtr = std::shared_ptr(new MockObject()); - auto orientation = DiscreteOrientation(avatarDirection); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectOrientation).WillRepeatedly(Return(orientation)); - - auto objects = sprites_mockGridFunctions(mockGridPtr, mockAvatarObjectPtr); + ObserverTestData testEnvironment = ObserverTestData(observerConfig, DiscreteOrientation(avatarDirection), trackAvatar); - EXPECT_CALL(*mockGridPtr, getObjects()) - .WillRepeatedly(ReturnRef(objects)); - - EXPECT_CALL(*mockGridPtr, getWidth) - .WillRepeatedly(Return(5)); - EXPECT_CALL(*mockGridPtr, getHeight) - .WillRepeatedly(Return(5)); + std::shared_ptr spriteObserver = std::shared_ptr(new SpriteObserver(testEnvironment.mockGridPtr, resourceConfig, getMockSpriteDefinitions())); spriteObserver->init(observerConfig); if (trackAvatar) { - spriteObserver->setAvatar(mockAvatarObjectPtr); + spriteObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } auto resetObservation = spriteObserver->reset(); @@ -488,8 +220,7 @@ void runSpriteObserverTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedImageData.get(), dataLength)); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockAvatarObjectPtr.get())); - EXPECT_TRUE(Mock::VerifyAndClearExpectations(mockGridPtr.get())); + testEnvironment.verifyAndClearExpectations(); } TEST(SpriteObserverTest, defaultObserverConfig) { diff --git a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp index 3b09f7fd2..e2db9e958 100644 --- a/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp +++ b/tests/src/Griddly/Core/Observers/VectorObserverTest.cpp @@ -1,8 +1,8 @@ #include "Griddly/Core/GDY/Objects/Object.hpp" #include "Griddly/Core/Grid.hpp" #include "Griddly/Core/Observers/VectorObserver.hpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObject.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" +#include "ObserverTestData.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -10,94 +10,36 @@ using ::testing::AnyNumber; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::Eq; +using ::testing::Invoke; using ::testing::Mock; using ::testing::Pair; using ::testing::Return; +using ::testing::ReturnRef; namespace griddly { -void vector_mockGridFunctions(std::shared_ptr& mockGridPtr, std::shared_ptr& mockAvatarObjectPtr) { - // make a 5 by 5 grid with an avatar in the center and some stuff around it, there are 4 types of object - // "4" is the avatar type - // 11111 - // 12031 - // 12431 - // 13021 - // 11111 - - auto mockObject1Ptr = std::shared_ptr(new MockObject()); - EXPECT_CALL(*mockObject1Ptr, getObjectId()).WillRepeatedly(Return(0)); - auto mockObject2Ptr = std::shared_ptr(new MockObject()); - EXPECT_CALL(*mockObject2Ptr, getObjectId()).WillRepeatedly(Return(1)); - auto mockObject3Ptr = std::shared_ptr(new MockObject()); - EXPECT_CALL(*mockObject3Ptr, getObjectId()).WillRepeatedly(Return(2)); - - EXPECT_CALL(*mockAvatarObjectPtr, getObjectId()).WillRepeatedly(Return(3)); - EXPECT_CALL(*mockAvatarObjectPtr, getLocation()).WillRepeatedly(Return(glm::ivec2{2, 2})); - - EXPECT_CALL(*mockGridPtr, getUniqueObjectCount).WillRepeatedly(Return(4)); - - // A horrible way of making a mock grid but fuck it - ON_CALL(*mockGridPtr, getObjectsAt).WillByDefault(Return(std::map>{})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 0}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 1}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 1}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 1}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 1}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 2}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 2}))).WillByDefault(Return(std::map>{{0, mockAvatarObjectPtr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 2}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 2}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 3}))).WillByDefault(Return(std::map>{{0, mockObject3Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 3}))).WillByDefault(Return(std::map>{})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 3}))).WillByDefault(Return(std::map>{{0, mockObject2Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 3}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{0, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{1, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{2, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{3, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); - ON_CALL(*mockGridPtr, getObjectsAt(Eq(glm::ivec2{4, 4}))).WillByDefault(Return(std::map>{{0, mockObject1Ptr}})); -} - void runVectorObserverTest(ObserverConfig observerConfig, Direction avatarDirection, std::vector expectedObservationShape, std::vector expectedObservationStride, uint8_t* expectedData, bool trackAvatar) { - auto mockGridPtr = std::shared_ptr(new MockGrid()); - std::shared_ptr vectorObserver = std::shared_ptr(new VectorObserver(mockGridPtr)); - - auto mockAvatarObjectPtr = std::shared_ptr(new MockObject()); - auto orientation = DiscreteOrientation(avatarDirection); - EXPECT_CALL(*mockAvatarObjectPtr, getObjectOrientation).WillRepeatedly(Return(orientation)); + + ObserverTestData testEnvironment = ObserverTestData(observerConfig, DiscreteOrientation(avatarDirection), trackAvatar); - vector_mockGridFunctions(mockGridPtr, mockAvatarObjectPtr); + std::shared_ptr vectorObserver = std::shared_ptr(new VectorObserver(testEnvironment.mockGridPtr)); vectorObserver->init(observerConfig); - if (trackAvatar) { - vectorObserver->setAvatar(mockAvatarObjectPtr); + vectorObserver->setAvatar(testEnvironment.mockAvatarObjectPtr); } auto resetObservation = vectorObserver->reset(); - ASSERT_EQ(vectorObserver->getTileSize(), glm::ivec2(1,1)); + ASSERT_EQ(vectorObserver->getTileSize(), glm::ivec2(1, 1)); ASSERT_EQ(vectorObserver->getShape(), expectedObservationShape); ASSERT_EQ(vectorObserver->getStrides(), expectedObservationStride); - + auto updateObservation = vectorObserver->update(); size_t dataLength = vectorObserver->getShape()[0] * vectorObserver->getShape()[1] * vectorObserver->getShape()[2]; @@ -107,6 +49,8 @@ void runVectorObserverTest(ObserverConfig observerConfig, ASSERT_THAT(resetObservationPointer, ElementsAreArray(expectedData, dataLength)); ASSERT_THAT(updateObservationPointer, ElementsAreArray(expectedData, dataLength)); + + testEnvironment.verifyAndClearExpectations(); } TEST(VectorObserverTest, defaultObserverConfig) { @@ -145,6 +89,24 @@ TEST(VectorObserverTest, partialObserver) { runVectorObserverTest(config, Direction::NONE, {4, 3, 5}, {1, 4, 12}, expectedData[0][0], false); } +TEST(VectorObserverTest, partialObserver_withOffset) { + ObserverConfig config = { + 3, + 5, + 0, + 1, + false}; + + uint8_t expectedData[5][3][4] = { + {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}, + {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}}, + {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}}, + {{1, 0, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 0}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}}; + + runVectorObserverTest(config, Direction::NONE, {4, 3, 5}, {1, 4, 12}, expectedData[0][0], false); +} + TEST(VectorObserverTest, defaultObserverConfig_trackAvatar) { ObserverConfig config = { 5, @@ -424,7 +386,6 @@ TEST(VectorObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar runVectorObserverTest(config, Direction::NONE, {4, 5, 3}, {1, 4, 20}, expectedData[0][0], true); } - TEST(VectorObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_UP) { ObserverConfig config = { 5, @@ -441,7 +402,6 @@ TEST(VectorObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar runVectorObserverTest(config, Direction::UP, {4, 5, 3}, {1, 4, 20}, expectedData[0][0], true); } - TEST(VectorObserverTest, partialObserver_withOffset_trackAvatar_rotateWithAvatar_RIGHT) { ObserverConfig config = { 5, diff --git a/tests/src/Griddly/Core/Players/PlayerTest.cpp b/tests/src/Griddly/Core/Players/PlayerTest.cpp index 65ba184ca..eef53db2c 100644 --- a/tests/src/Griddly/Core/Players/PlayerTest.cpp +++ b/tests/src/Griddly/Core/Players/PlayerTest.cpp @@ -1,10 +1,10 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "Mocks/Griddly/Core/GDY/Actions/MockAction.cpp" -#include "Mocks/Griddly/Core/MockGameProcess.cpp" -#include "Mocks/Griddly/Core/Observers/MockObserver.cpp" -#include "Mocks/Griddly/Core/MockGrid.cpp" +#include "Mocks/Griddly/Core/GDY/Actions/MockAction.hpp" +#include "Mocks/Griddly/Core/MockGameProcess.hpp" +#include "Mocks/Griddly/Core/Observers/MockObserver.hpp" +#include "Mocks/Griddly/Core/MockGrid.hpp" #include "Griddly/Core/Players/Player.hpp" diff --git a/tests/src/Griddly/Core/TestUtils/common.hpp b/tests/src/Griddly/Core/TestUtils/common.hpp index eceb765fb..52d86f44c 100644 --- a/tests/src/Griddly/Core/TestUtils/common.hpp +++ b/tests/src/Griddly/Core/TestUtils/common.hpp @@ -2,8 +2,8 @@ #pragma once #include -#include "Mocks/Griddly/Core/GDY/Actions/MockAction.cpp" -#include "Mocks/Griddly/Core/GDY/Objects/MockObject.cpp" +#include "Mocks/Griddly/Core/GDY/Actions/MockAction.hpp" +#include "Mocks/Griddly/Core/GDY/Objects/MockObject.hpp" #include "gmock/gmock.h" #include "gtest/gtest.h" diff --git a/tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.cpp b/tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.hpp similarity index 98% rename from tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.cpp rename to tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.hpp index 99fee38ac..3893005a1 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/Actions/MockAction.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/Actions/Action.hpp" #include "gmock/gmock.h" @@ -19,7 +21,7 @@ class MockAction : public Action { MOCK_METHOD(glm::ivec2, getVectorToDest, (), (const)); MOCK_METHOD(glm::ivec2, getOrientationVector, (), (const)); - + MOCK_METHOD(std::string, getActionName, (), (const)); MOCK_METHOD(std::string, getDescription, (), (const)); MOCK_METHOD(uint32_t, getDelay, (), (const)); diff --git a/tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.cpp b/tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.hpp similarity index 99% rename from tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.cpp rename to tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.hpp index ba0c37e9a..5f1183887 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/MockGDYFactory.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/GDYFactory.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.cpp b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp similarity index 97% rename from tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.cpp rename to tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp index 6d7e3bd1e..a2fe76ba9 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationGenerator.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include "Griddly/Core/GDY/TerminationGenerator.hpp" diff --git a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.cpp b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.hpp similarity index 97% rename from tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.cpp rename to tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.hpp index ea1e8fb7d..b5fc38a15 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/MockTerminationHandler.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/TerminationHandler.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.cpp b/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.hpp similarity index 99% rename from tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.cpp rename to tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.hpp index 547b53beb..34f005f26 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObject.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/Objects/Object.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp b/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp similarity index 98% rename from tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp rename to tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp index 364f299f9..41653e435 100644 --- a/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.cpp +++ b/tests/src/Mocks/Griddly/Core/GDY/Objects/MockObjectGenerator.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/Objects/ObjectGenerator.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.cpp b/tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.hpp similarity index 96% rename from tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.cpp rename to tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.hpp index 7cbbe2af6..f4be87153 100644 --- a/tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.cpp +++ b/tests/src/Mocks/Griddly/Core/LevelGenerators/MockLevelGenerator.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/GDY/Objects/ObjectGenerator.hpp" #include "Griddly/Core/LevelGenerators/MapReader.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/MockGameProcess.cpp b/tests/src/Mocks/Griddly/Core/MockGameProcess.hpp similarity index 98% rename from tests/src/Mocks/Griddly/Core/MockGameProcess.cpp rename to tests/src/Mocks/Griddly/Core/MockGameProcess.hpp index 1df42c24d..69fc40849 100644 --- a/tests/src/Mocks/Griddly/Core/MockGameProcess.cpp +++ b/tests/src/Mocks/Griddly/Core/MockGameProcess.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include "Griddly/Core/GameProcess.hpp" diff --git a/tests/src/Mocks/Griddly/Core/MockGrid.cpp b/tests/src/Mocks/Griddly/Core/MockGrid.hpp similarity index 82% rename from tests/src/Mocks/Griddly/Core/MockGrid.cpp rename to tests/src/Mocks/Griddly/Core/MockGrid.hpp index 4abe485ee..ff278013c 100644 --- a/tests/src/Mocks/Griddly/Core/MockGrid.cpp +++ b/tests/src/Mocks/Griddly/Core/MockGrid.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/Grid.hpp" #include "gmock/gmock.h" @@ -11,7 +13,8 @@ class MockGrid : public Grid { MOCK_METHOD(void, resetGlobalVariables, ((std::unordered_map)), ()); MOCK_METHOD((std::unordered_map), update, (), ()); - MOCK_METHOD((std::unordered_set), getUpdatedLocations, (), (const)); + MOCK_METHOD((const std::unordered_set&), getUpdatedLocations, (uint32_t playerId), (const)); + MOCK_METHOD(void, purgeUpdatedLocations, (uint32_t playerId), ()); MOCK_METHOD(uint32_t, getWidth, (), (const)); MOCK_METHOD(uint32_t, getHeight, (), (const)); @@ -28,9 +31,9 @@ class MockGrid : public Grid { MOCK_METHOD((std::unordered_map>>), getGlobalVariables, (), (const)); - MOCK_METHOD(std::unordered_set>&, getObjects, (), ()); + MOCK_METHOD((const std::unordered_set>&), getObjects, (), ()); MOCK_METHOD(std::shared_ptr, getObject, (glm::ivec2 location), (const)); - MOCK_METHOD((TileObjects), getObjectsAt, (glm::ivec2 location), (const)); + MOCK_METHOD((const TileObjects&), getObjectsAt, (glm::ivec2 location), (const)); MOCK_METHOD((std::unordered_map>), getPlayerAvatarObjects, (), (const)); diff --git a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.cpp b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp similarity index 97% rename from tests/src/Mocks/Griddly/Core/Observers/MockObserver.cpp rename to tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp index 40aeb26c4..d0f71241f 100644 --- a/tests/src/Mocks/Griddly/Core/Observers/MockObserver.cpp +++ b/tests/src/Mocks/Griddly/Core/Observers/MockObserver.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/Observers/Observer.hpp" #include "gmock/gmock.h" diff --git a/tests/src/Mocks/Griddly/Core/Players/MockPlayer.cpp b/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp similarity index 98% rename from tests/src/Mocks/Griddly/Core/Players/MockPlayer.cpp rename to tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp index 10c768630..2b343dfe7 100644 --- a/tests/src/Mocks/Griddly/Core/Players/MockPlayer.cpp +++ b/tests/src/Mocks/Griddly/Core/Players/MockPlayer.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "Griddly/Core/Players/Player.hpp" #include "Griddly/Core/GameProcess.hpp" #include "gmock/gmock.h"