From 24efee21f51ef07f053e826681d6b993ff58d242 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Tue, 3 Jan 2023 20:49:33 -0600 Subject: [PATCH 01/31] assets are in creeper_adventure --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dba7ff9..9f8a282 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: python-version: '3.10' - run: pip install -r requirements.txt - run: pyinstaller --noconsole creeper_adventure/creeper.py - - run: cp -r assets dist/creeper + - run: cp -r creeper_adventure/assets dist/creeper - name: Step 3 - Use the Upload Artifact GitHub Action uses: actions/upload-artifact@v2 with: From 8da33c8582d2eefb37c51242f0fbc80823b992dc Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 02:50:30 +0000 Subject: [PATCH 02/31] Bump version: 2.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index b5a47bc..f0468b7 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '1.0.0' +__version__ = '2.0.0' From 32e3ec31b4306061c1e801f0ae74141e0a33b27b Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Tue, 3 Jan 2023 21:02:25 -0600 Subject: [PATCH 03/31] force push tags --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f8a282..dda57b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,8 +82,8 @@ jobs: git add . git commit -m "Bump version: `hatch version`" git tag v$NEW_VERSION - git push - git push --tags + git push --force + git push --tags --force - name: publish run: | runner hatch build From c491d54e86c09e83a5aa8619bab907849641e839 Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 03:03:02 +0000 Subject: [PATCH 04/31] Bump version: 3.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index f0468b7..b37eb0b 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '2.0.0' +__version__ = '3.0.0' From 46123ff14644b0775cad685b671aad1f1a692791 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Tue, 3 Jan 2023 21:04:52 -0600 Subject: [PATCH 05/31] not runner --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dda57b0..b5472fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,5 +86,5 @@ jobs: git push --tags --force - name: publish run: | - runner hatch build - runner hatch publish + hatch build + hatch publish From 0f6659ae73a7742b5c8ba87c3875d9cd8f4bc572 Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 03:05:33 +0000 Subject: [PATCH 06/31] Bump version: 4.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index b37eb0b..b67881c 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '3.0.0' +__version__ = '4.0.0' From a1284162c2629eefa0341e1969aa26dd57f7747b Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Tue, 3 Jan 2023 21:15:38 -0600 Subject: [PATCH 07/31] don't print debug --- creeper_adventure/cli/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/creeper_adventure/cli/__init__.py b/creeper_adventure/cli/__init__.py index 76b12d9..b7e0d8e 100644 --- a/creeper_adventure/cli/__init__.py +++ b/creeper_adventure/cli/__init__.py @@ -15,5 +15,4 @@ from ..creeper import main @click.pass_context @click.option("--debug", is_flag=True, help="start with the debug menu open") def creeper_adventure(ctx: click.Context, debug): - print(debug) main(debug) From 242b4952d6bd0eaa989ff7438df0e70f528d5b71 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Wed, 4 Jan 2023 08:31:38 -0600 Subject: [PATCH 08/31] create camera --- creeper_adventure/creeper.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index e90309d..5008c0b 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -12,20 +12,29 @@ ASSETS = Path(__file__).parent / "assets" class MouseSprite: - def __init__(self, surf, hotbar): + def __init__(self, game, surf, hotbar): + self.game = game self.surf = surf self.hotbar = hotbar @property def mouse_pos(self): - return [i - 2 for i in pygame.mouse.get_pos()] + return ( + pygame.mouse.get_pos()[0] - 2 - self.game.camera[0], + pygame.mouse.get_pos()[1] - 2 - self.game.camera[1], + ) @property def rect(self): return pygame.Rect(self.mouse_pos, (4, 4)) def get_nearest_block_pos(self): - return ([i - (i % 16) for i in pygame.mouse.get_pos()],) + return ( + [ + self.mouse_pos[0] - (self.mouse_pos[0] % 16), + self.mouse_pos[1] - (self.mouse_pos[1] % 16), + ], + ) def draw(self): if self.hotbar.selected.type is None: @@ -336,6 +345,7 @@ class Creeper(Game): def __init__(self, debug=False): super().__init__() self.inventory = {} + self.camera = (0, 0) self.day_len = 1000 * 60 self.background = pygame.Surface(self.screen.get_size()) self.foreground = pygame.Surface(self.screen.get_size()) @@ -395,7 +405,7 @@ class Creeper(Game): ) ) - self.mouse_box = MouseSprite(self.screen, hotbar=self.hotbar) + self.mouse_box = MouseSprite(self, self.background, hotbar=self.hotbar) self.joysticks = {} self.hotbar_back_debounce = 1 self.hotbar_forward_debounce = 1 @@ -445,7 +455,7 @@ class Creeper(Game): self.x += 10 if keys[pygame.K_w]: self.y -= 10 - if keys[pygame.K_d]: + if keys[pygame.K_s]: self.y += 10 if keys[pygame.K_k]: self.hotbar.next(1) @@ -472,9 +482,12 @@ class Creeper(Game): for joystick in self.joysticks.values(): if joystick.get_button(4) and self.hotbar_back_debounce: + print(self.hotbar_back_debounce) self.hotbar.next(-1) self.hotbar_back_debounce = 0 - elif not joystick.get_button(4): + print(self.hotbar_back_debounce) + if not joystick.get_button(4): + print("resetting") self.hotbar_back_debounce = 1 if joystick.get_button(5) and self.hotbar_forward_debounce: @@ -567,7 +580,8 @@ class Creeper(Game): self.last_y = self.y def game(self): - self.screen.blit(self.background, (0, 0)) + # self.camera = (self.camera[0] + 1, self.camera[1]) + self.screen.blit(self.background, self.camera) self.background.fill((0, 255, 247)) self.process_deaths() for tree in self.trees: @@ -607,7 +621,7 @@ class Creeper(Game): self.inventory_menu.draw() self.main_menu.draw() - self.mouse_box = MouseSprite(self.screen, hotbar=self.hotbar) + self.mouse_box = MouseSprite(self, self.background, hotbar=self.hotbar) self.mouse_box.draw() From 8dafb9ebcf55f4d21c84eeaa926dcc93bbb540cb Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Wed, 4 Jan 2023 08:32:09 -0600 Subject: [PATCH 09/31] add birtch tree --- creeper_adventure/assets/oak_trees/6.png | Bin 0 -> 1447 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 creeper_adventure/assets/oak_trees/6.png diff --git a/creeper_adventure/assets/oak_trees/6.png b/creeper_adventure/assets/oak_trees/6.png new file mode 100644 index 0000000000000000000000000000000000000000..908228e03c4463ee364ba71326bb3d67ecb08bc8 GIT binary patch literal 1447 zcmV;Y1z7rtP)AE$6^me@v=v%)FnQ@8G-*guTpR`0f`dPc zRR>v zukay&J_Io!F;h>Z7c=mzuY2mIx{LBG@4i2)SIL_U@QK88OgAjz4dR(iOXs{#9A+g+ zAwDM_H|T=Ik6f2se&bwpSm2pqBa@mZ4ik&T4wgHZl?;`5nmD4U8s!UFmle)ioYhK= zweHDZ7|LraX|B^6K^#j+APEsNYAB-u3sKrNQcR@iJm%pacKk_l$>b`7kz)Z>sE`~# z_#gb9ty!3wbdy3cpzFo9KSqJ>U7%UF?eAmTZk_=CXW&X}`>PFL_LKB_TZQuN9YFwyu?UWIu zF#?zR14e~hs0vbN1OcT{5SKESYL)S7cW-uY_5+*;21&QR-F-9jW_IoX{^NP0#&x6i z`DtM@{^54ZHg^?NT14Z0{mG_V&HB-p^(NQ;zZf5r45x`z8<#h#B11q$%6^_lA>n0= zNo8`@oBW8>P=r`bVv6(iCO2B00_+*BW<5w~Sb2b0pvvWK?^Bg5F1+BlNvm16j`{T_ zuS6mjyl6m~g{juZy5LI_tO>x2r)(qzE1SR)0vLG1STj-u$peJ?Q>}?bQf!_=hDls~ zg#)_=hz-gc7cgZKOpeeI-y!520=8u@=RBM!B>)#cHmQ!1=2R7->AMfGil7f``6hv+ z0dm|@JRxP}$1tj?to{@N@OTwup;KK~iKF}*S0-Su12~~0n$x=~Re}PtSLhaK8_yI^ zs0y+NP+7NGpnOjgalSOg=m87S}D2HWC zCrn=%$yo$l8XGz{=jb20qLhIBJg>8?f~RsZCEjmhwPV=k`&K!w!A_6qnTpa%~`wJ^NL> zUVQ)k!)47nSbM-~IV%7F7B^D>0QfliWE{V^nSvk-Aa2p4LXhF?i@a3iP(wEq+^7)@Y2?7?6(2|2YEUYOoK-WR*w{^C{ z8nD~#gIZjM*XIIR);N5|n@pK8YYe7r|eL5_%!k6jKB;p?+a2=3B-j@;O{Qz;GN&&$Np;W<6!1nPz8S7Hu zr4W+iUp@n*gdl|wMrw6I@IvTWd4LWnr9rQUA)UM9G#Hxm` Date: Wed, 4 Jan 2023 14:32:36 +0000 Subject: [PATCH 10/31] Bump version: 5.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index b67881c..f5d8f21 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '4.0.0' +__version__ = '5.0.0' From 69db57c10e3a91888f884f18ee2c0602b2794651 Mon Sep 17 00:00:00 2001 From: Waylon Walker Date: Wed, 4 Jan 2023 09:40:01 -0600 Subject: [PATCH 11/31] Update README.md --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 0319349..b121159 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ + + + # creeper-adventure +Creeper adventure is a top down 2d adventure game that I am building with my son using pygame. + [![PyPI - Version](https://img.shields.io/pypi/v/creeper-adventure.svg)](https://pypi.org/project/creeper-adventure) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/creeper-adventure.svg)](https://pypi.org/project/creeper-adventure) @@ -16,6 +21,31 @@ pip install creeper-adventure ``` +## Running + +```console +# run the game +creeper-adventure + +# run in debug mode +creeper-adventure --debug + +# see all options available +creeper-adventure --help +``` + +## running with pipx + +`creeper-adventure` can also run using pipx if you have pipx installed. + +```console +pipx run creeper-adventure +``` + +## Download an exe + +pre-built binaries are available from the website [creeper-adventure](https://creeper-adventure.waylonwalker.com). + ## License `creeper-adventure` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. From 1aed9a28d67415da92444ff5c32719da95c377cd Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 15:40:28 +0000 Subject: [PATCH 12/31] Bump version: 6.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index f5d8f21..419e5ba 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '5.0.0' +__version__ = '6.0.0' From 013f223e9113409b851f6d4c3d6fc83e8d975b21 Mon Sep 17 00:00:00 2001 From: Waylon Walker Date: Wed, 4 Jan 2023 09:44:07 -0600 Subject: [PATCH 13/31] use raw images in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b121159..6a25d87 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - - + + # creeper-adventure From eb95eaa36d4299fa2a27e29bb04c42079da43f2c Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 15:44:32 +0000 Subject: [PATCH 14/31] Bump version: 7.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index 419e5ba..f539250 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '6.0.0' +__version__ = '7.0.0' From 1414c30a4a871babe7c531d01b0c7b5a61ff8828 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Wed, 4 Jan 2023 12:01:59 -0600 Subject: [PATCH 15/31] fix menus not working when there is no controller --- creeper_adventure/creeper.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 5008c0b..c255ca9 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -479,6 +479,20 @@ class Creeper(Game): if event.type == pygame.JOYDEVICEREMOVED: del self.joysticks[event.instance_id] + if not self.joysticks: + if (keys[pygame.K_ESCAPE]) and self.main_open_debounce: + print("opens") + self.main_menu.is_open = not self.main_menu.is_open + self.main_open_debounce = 0 + elif not keys[pygame.K_ESCAPE]: + self.main_open_debounce = 1 + + if keys[pygame.K_e] and self.inventory_open_debounce: + self.inventory_menu.is_open = not self.inventory_menu.is_open + self.inventory_open_debounce = 0 + elif not keys[pygame.K_e]: + self.inventory_open_debounce = 1 + for joystick in self.joysticks.values(): if joystick.get_button(4) and self.hotbar_back_debounce: @@ -537,6 +551,13 @@ class Creeper(Game): def inventory_keys(self): keys = self.keys + if not self.joysticks: + if keys[pygame.K_e] and self.inventory_open_debounce: + self.inventory_menu.is_open = not self.inventory_menu.is_open + self.inventory_open_debounce = 0 + elif not keys[pygame.K_e]: + self.inventory_open_debounce = 1 + for joystick in self.joysticks.values(): if ( keys[pygame.K_e] or joystick.get_button(2) @@ -548,6 +569,15 @@ class Creeper(Game): def main_keys(self): keys = self.keys + + if not self.joysticks: + if (keys[pygame.K_ESCAPE]) and self.main_open_debounce: + print("opens") + self.main_menu.is_open = not self.main_menu.is_open + self.main_open_debounce = 0 + elif not keys[pygame.K_ESCAPE]: + self.main_open_debounce = 1 + for joystick in self.joysticks.values(): if ( keys[pygame.K_ESCAPE] or joystick.get_button(9) From 9d39d94cd2db7fa4fbe28b54c7d520b76ef4c560 Mon Sep 17 00:00:00 2001 From: autobump Date: Wed, 4 Jan 2023 18:03:01 +0000 Subject: [PATCH 16/31] Bump version: 8.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index f539250..ce905de 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '7.0.0' +__version__ = '8.0.0' From c2183e3bf7c2964c025b8ea370d991c11b29b9a0 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Fri, 6 Jan 2023 09:37:51 -0600 Subject: [PATCH 17/31] add arrow key support --- creeper_adventure/creeper.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index c255ca9..7fba582 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -449,13 +449,13 @@ class Creeper(Game): def normal_keys(self): keys = self.keys - if keys[pygame.K_a]: + if keys[pygame.K_a] or keys[pygame.K_LEFT]: self.x -= 10 - if keys[pygame.K_d]: + if keys[pygame.K_d] or keys[pygame.K_RIGHT]: self.x += 10 - if keys[pygame.K_w]: + if keys[pygame.K_w] or keys[pygame.K_UP]: self.y -= 10 - if keys[pygame.K_s]: + if keys[pygame.K_s] or keys[pygame.K_DOWN]: self.y += 10 if keys[pygame.K_k]: self.hotbar.next(1) From fe12bd7404353ba87e5108f262877c2f678bfa9c Mon Sep 17 00:00:00 2001 From: autobump Date: Fri, 6 Jan 2023 15:38:41 +0000 Subject: [PATCH 18/31] Bump version: 9.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index ce905de..dffd1f8 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '8.0.0' +__version__ = '9.0.0' From 30ba66ab6c289093b408db363a8533a265e72e5c Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:43:32 -0600 Subject: [PATCH 19/31] add fps to debug --- creeper_adventure/creeper.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 7fba582..21aa72a 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -271,6 +271,14 @@ class DebugMenu(Menu): ), (10, 80), ) + self.surf.blit( + self.font.render( + f"fps: {round(self.game.clock.get_fps())}", + True, + (255, 255, 255), + ), + (10, 95), + ) class LightSource: From e39832460f53ba10b8077edfcc79d66e6cd9d82c Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:46:25 -0600 Subject: [PATCH 20/31] implement get_img --- creeper_adventure/creeper.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 21aa72a..d85cc3e 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -40,15 +40,16 @@ class MouseSprite: if self.hotbar.selected.type is None: pygame.draw.rect(self.surf, (255, 0, 0), self.rect) else: - self.img = pygame.image.load(ASSETS / f"{self.hotbar.selected.type}.png") + self.img = self.game.get_img(self.hotbar.selected.type) self.surf.blit( - pygame.transform.scale(self.img, (16, 16)), + pygame.transform.scale(self.img, (64, 64)), self.get_nearest_block_pos(), ) class TreeSprite: - def __init__(self, tree, x, y, scale, flip, surf): + def __init__(self, game, tree, x, y, scale, flip, surf): + self.game = game self.image = tree self.health = 100 self.x = x @@ -56,7 +57,7 @@ class TreeSprite: self.scale = scale self.flip = flip self.surf = surf - self.leafs = [Leaf(self, self.surf, (x + 25, y + 25)) for i in range(2)] + self.leafs = [Leaf(self.game, self.surf, (x + 25, y + 25)) for i in range(2)] self.shaking = 0 def shake(self): @@ -66,7 +67,7 @@ class TreeSprite: self.leafs.extend( [ Leaf( - self, + self.game, self.surf, ( self.x + 25 + random.randint(-10, 10), @@ -124,7 +125,11 @@ class HotBar: self.game = game self.items = [ HotBarItem( - game=self, surf=self.ui, pos=pos, scale=self.scale, margin=self.margin + game=self.game, + surf=self.ui, + pos=pos, + scale=self.scale, + margin=self.margin, ) for pos in range(num) ] @@ -180,7 +185,7 @@ class HotBarItem: self.surf.fill((185, 185, 205, 60)) if self.type: - self.img = pygame.image.load(ASSETS / f"{self.type}.png") + self.img = self.game.get_img(self.type) self.ui.blit( pygame.transform.scale( self.img, @@ -189,7 +194,7 @@ class HotBarItem: (self.pos * self.scale + self.margin, self.margin), ) font = pygame.font.SysFont(None, self.scale) - qty = str(self.game.game.inventory[self.type]) + qty = str(self.game.inventory[self.type]) img = font.render(qty, True, (255, 255, 255)) self.ui.blit( pygame.transform.scale(img, (self.scale * 0.6, self.scale * 0.6)), @@ -288,7 +293,7 @@ class LightSource: self.img = img self.center = center self.sx, self.sy = center - self.spot = pygame.image.load(ASSETS / "spotlight.png") + self.spot = self.game.get_img("spotlight") class Leaf: @@ -298,7 +303,7 @@ class Leaf: self.center = center self.sx, self.sy = center self.img = pygame.transform.scale( - pygame.image.load(ASSETS / "leaf.png"), (4, 4) + self.game.get_img("leaf"), (4, 4) ).convert_alpha() self.lifespan = lifespan self.r = random.randint(0, 360) @@ -425,6 +430,13 @@ class Creeper(Game): self.debug_menu.is_open = debug self.main_menu = Menu(self, title="main menu") + def get_img(self, img): + try: + return self._imgs[img] + except KeyError: + self._imgs[img] = pygame.image.load(ASSETS / f"{img}.png") + return self._imgs[img] + def attack(self): collisions = self.mouse_box.rect.collidedictall( From 6c9033bcd5c10a7e1b6456bd9b05e1f5861b0e45 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:46:56 -0600 Subject: [PATCH 21/31] set controller debounces --- creeper_adventure/creeper.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index d85cc3e..2e12603 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -420,11 +420,19 @@ class Creeper(Game): self.mouse_box = MouseSprite(self, self.background, hotbar=self.hotbar) self.joysticks = {} + self.hotbar_back_debounce = 1 self.hotbar_forward_debounce = 1 self.inventory_open_debounce = 1 self.debug_open_debounce = 1 self.main_open_debounce = 1 + + self.controller_hotbar_back_debounce = 1 + self.controller_hotbar_forward_debounce = 1 + self.controller_inventory_open_debounce = 1 + self.controller_debug_open_debounce = 1 + self.controller_main_open_debounce = 1 + self.inventory_menu = Menu(self, title="inventory") self.debug_menu = DebugMenu(self) self.debug_menu.is_open = debug From db22a7a168ce4f71c4c536410f323f2d146bdd17 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:47:31 -0600 Subject: [PATCH 22/31] controller fixes --- creeper_adventure/creeper.py | 38 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 2e12603..4700c70 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -522,43 +522,45 @@ class Creeper(Game): self.inventory_open_debounce = 1 for joystick in self.joysticks.values(): + if joystick.get_axis(5) > 0: + if self.attack(): + joystick.rumble(0.1, 0.0, 100) - if joystick.get_button(4) and self.hotbar_back_debounce: - print(self.hotbar_back_debounce) + if joystick.get_button(4) and self.controller_hotbar_back_debounce: + print(self.controller_hotbar_back_debounce) self.hotbar.next(-1) - self.hotbar_back_debounce = 0 + self.controller_hotbar_back_debounce = 0 print(self.hotbar_back_debounce) if not joystick.get_button(4): - print("resetting") - self.hotbar_back_debounce = 1 + self.controller_hotbar_back_debounce = 1 - if joystick.get_button(5) and self.hotbar_forward_debounce: + if joystick.get_button(5) and self.controller_hotbar_forward_debounce: self.hotbar.next(1) - self.hotbar_forward_debounce = 0 + self.controller_hotbar_forward_debounce = 0 elif not joystick.get_button(5): - self.hotbar_forward_debounce = 1 + self.controller_hotbar_forward_debounce = 1 if ( keys[pygame.K_e] or joystick.get_button(2) - ) and self.inventory_open_debounce: + ) and self.controller_inventory_open_debounce: self.inventory_menu.is_open = not self.inventory_menu.is_open - self.inventory_open_debounce = 0 - elif not (keys[pygame.K_e] or joystick.get_button(2)): - self.inventory_open_debounce = 1 + self.controller_inventory_open_debounce = 0 + elif not keys[pygame.K_e] and not joystick.get_button(2): + self.controller_inventory_open_debounce = 1 if ( keys[pygame.K_ESCAPE] or joystick.get_button(9) - ) and self.main_open_debounce: + ) and self.controller_main_open_debounce: self.main_menu.is_open = not self.main_menu.is_open - self.main_open_debounce = 0 + self.controller_main_open_debounce = 0 elif not (keys[pygame.K_ESCAPE] or joystick.get_button(9)): - self.main_open_debounce = 1 + self.controller_main_open_debounce = 1 - if keys[pygame.K_F3] and self.debug_open_debounce: + if keys[pygame.K_F3] and self.controller_debug_open_debounce: self.debug_menu.is_open = not self.debug_menu.is_open - self.debug_open_debounce = 0 + self.controller_debug_open_debounce = 0 elif not keys[pygame.K_F3]: - self.debug_open_debounce = 1 + self.controller_debug_open_debounce = 1 hats = joystick.get_numhats() for i in range(hats): From 3f5a10f0909e4dccd9bac9a54d981c3b5005ff7f Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:48:07 -0600 Subject: [PATCH 23/31] controller axis movement --- creeper_adventure/creeper.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 4700c70..08d2acb 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -579,6 +579,28 @@ class Creeper(Game): if abs(joystick.get_axis(1)) > 0.2: self.y += joystick.get_axis(1) * 10 + if abs(joystick.get_axis(3)) > 0.2 and abs(joystick.get_axis(4)) > 0.2: + pygame.mouse.set_pos( + ( + pygame.mouse.get_pos()[0] + joystick.get_axis(3) * 32, + pygame.mouse.get_pos()[1] + joystick.get_axis(4) * 32, + ) + ) + elif abs(joystick.get_axis(3)) > 0.2: + pygame.mouse.set_pos( + ( + pygame.mouse.get_pos()[0] + joystick.get_axis(3) * 32, + pygame.mouse.get_pos()[1], + ) + ) + elif abs(joystick.get_axis(4)) > 0.2: + pygame.mouse.set_pos( + ( + pygame.mouse.get_pos()[0], + pygame.mouse.get_pos()[1] + joystick.get_axis(4) * 32, + ) + ) + def inventory_keys(self): keys = self.keys if not self.joysticks: From 96f1f6b3c25a7a06b9b27de981b9c5f580bd8ba6 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:48:31 -0600 Subject: [PATCH 24/31] fix menu debounces --- creeper_adventure/creeper.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 08d2acb..50dac64 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -613,11 +613,11 @@ class Creeper(Game): for joystick in self.joysticks.values(): if ( keys[pygame.K_e] or joystick.get_button(2) - ) and self.inventory_open_debounce: + ) and self.controller_inventory_open_debounce: self.inventory_menu.is_open = not self.inventory_menu.is_open - self.inventory_open_debounce = 0 - elif not (keys[pygame.K_e] or joystick.get_button(2)): - self.inventory_open_debounce = 1 + self.controller_inventory_open_debounce = 0 + elif not keys[pygame.K_e] and not joystick.get_button(2): + self.controller_inventory_open_debounce = 1 def main_keys(self): keys = self.keys @@ -633,11 +633,11 @@ class Creeper(Game): for joystick in self.joysticks.values(): if ( keys[pygame.K_ESCAPE] or joystick.get_button(9) - ) and self.main_open_debounce: + ) and self.controller_main_open_debounce: self.main_menu.is_open = not self.main_menu.is_open - self.main_open_debounce = 0 + self.controller_main_open_debounce = 0 elif not (keys[pygame.K_ESCAPE] or joystick.get_button(9)): - self.main_open_debounce = 1 + self.controller_main_open_debounce = 1 def make_sound(self): if not hasattr(self, "last_x"): From a2ffbd4123cca59784bd5fad415e77e86e73c17a Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 17:48:58 -0600 Subject: [PATCH 25/31] draw mouse last --- creeper_adventure/creeper.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 50dac64..286bc61 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -705,8 +705,6 @@ class Creeper(Game): self.mouse_box = MouseSprite(self, self.background, hotbar=self.hotbar) - self.mouse_box.draw() - self.make_sound() if self.inventory_menu.is_open: @@ -715,6 +713,7 @@ class Creeper(Game): self.main_keys() else: self.normal_keys() + self.mouse_box.draw() def main(debug=False): From 21b631ec2a8ac3f0188b3d07dd6f4be1eae32f41 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 20:51:47 -0600 Subject: [PATCH 26/31] fps independant --- creeper_adventure/creeper.py | 117 +++++++++++++++++++++++------------ creeper_adventure/game.py | 10 ++- 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 286bc61..3636517 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -40,7 +40,7 @@ class MouseSprite: if self.hotbar.selected.type is None: pygame.draw.rect(self.surf, (255, 0, 0), self.rect) else: - self.img = self.game.get_img(self.hotbar.selected.type) + self.img = self.game.get_img(self.hotbar.selected.type).convert() self.surf.blit( pygame.transform.scale(self.img, (64, 64)), self.get_nearest_block_pos(), @@ -284,6 +284,22 @@ class DebugMenu(Menu): ), (10, 95), ) + self.surf.blit( + self.font.render( + f"fullscreen: {pygame.FULLSCREEN}", + True, + (255, 255, 255), + ), + (10, 110), + ) + self.surf.blit( + self.font.render( + f"elapsed: {self.game.elapsed}", + True, + (255, 255, 255), + ), + (10, 125), + ) class LightSource: @@ -304,10 +320,11 @@ class Leaf: self.sx, self.sy = center self.img = pygame.transform.scale( self.game.get_img("leaf"), (4, 4) - ).convert_alpha() + ) # .convert_alpha() self.lifespan = lifespan self.r = random.randint(0, 360) self.x, self.y = [int(i) + random.randint(-8, 8) for i in self.center] + self.speed = 3 self.restart() def restart(self): @@ -323,13 +340,13 @@ class Leaf: ) if self.y < self.sy + 40: - self.y += random.randint(0, 5) / 4 - self.x += random.randint(-15, 5) / 10 - self.r += random.randint(-10, 10) + self.y += random.randint(0, 5) / 4 * self.speed * self.game.elapsed + self.x += random.randint(-15, 5) / 10 * self.speed * self.game.elapsed + self.r += random.randint(-10, 10) * self.speed / 3 * self.game.elapsed elif self.y < self.sy + 45: - self.y += random.randint(-2, 5) / 10 - self.x += random.randint(-18, 2) / 10 - self.r += random.randint(-10, 25) + self.y += random.randint(-2, 5) / 10 * self.speed * self.game.elapsed + self.x += random.randint(-18, 2) / 10 * self.speed * self.game.elapsed + self.r += random.randint(-10, 25) * self.speed * self.game.elapsed else: self.restart() if self.x > self.sx + 100: @@ -357,16 +374,20 @@ class Bee: class Creeper(Game): def __init__(self, debug=False): super().__init__() - self.inventory = {} + pygame.mouse.set_visible(False) + self.inventory = {"plank-bottom": 1, "plank-top": 1} + self._imgs = {} + self.blocks = {} self.camera = (0, 0) self.day_len = 1000 * 60 self.background = pygame.Surface(self.screen.get_size()) self.foreground = pygame.Surface(self.screen.get_size()) self.build = pygame.Surface(self.screen.get_size()) - self.darkness = pygame.Surface(self.screen.get_size()).convert_alpha() + # self.darkness = pygame.Surface(self.screen.get_size()) self.axe_sound = pygame.mixer.Sound(ASSETS / "sounds/axe.mp3") self.walking_sound = pygame.mixer.Sound(ASSETS / "sounds/walking.mp3") self.walking_sound_is_playing = False + self.speed = 5 self.background.fill((0, 255, 247)) self.x, self.y = [i / 2 for i in self.screen.get_size()] @@ -395,20 +416,21 @@ class Creeper(Game): self.trees = [] x_range = [ - self.screen.get_size()[0] * 0.1, - self.screen.get_size()[0] * 0.9, + 0, + self.screen.get_size()[0], ] y_range = [ self.screen.get_size()[1] * 0.35, self.screen.get_size()[1] * 0.5, ] - for i in range(10): + for i in range(30): x = random.randint(*x_range) y = random.randint(*y_range) scale = random.randint(42, 86) self.trees.append( TreeSprite( + game=self, tree=random.choice(self.tree_imgs), x=x, y=y, @@ -433,6 +455,8 @@ class Creeper(Game): self.controller_debug_open_debounce = 1 self.controller_main_open_debounce = 1 + self.debounce_walk_img = 0 + self.inventory_menu = Menu(self, title="inventory") self.debug_menu = DebugMenu(self) self.debug_menu.is_open = debug @@ -461,8 +485,12 @@ class Creeper(Game): return True def place_block(self): - if self.hotbar.selected.type is None: - return False + # if self.hotbar.selected.type is None: + # return False + self.blocks[str(self.mouse_box.get_nearest_block_pos())] = Block( + self.hotbar.selected.type, self.mouse_box.get_nearest_block_pos() + ) + print(self.blocks) def process_deaths(self): for i, tree in enumerate(copy(self.trees)): @@ -478,13 +506,13 @@ class Creeper(Game): def normal_keys(self): keys = self.keys if keys[pygame.K_a] or keys[pygame.K_LEFT]: - self.x -= 10 + self.x -= 10 * self.speed * self.elapsed if keys[pygame.K_d] or keys[pygame.K_RIGHT]: - self.x += 10 + self.x += 10 * self.speed * self.elapsed if keys[pygame.K_w] or keys[pygame.K_UP]: - self.y -= 10 + self.y -= 10 * self.speed * self.elapsed if keys[pygame.K_s] or keys[pygame.K_DOWN]: - self.y += 10 + self.y += 10 * self.speed * self.elapsed if keys[pygame.K_k]: self.hotbar.next(1) if keys[pygame.K_j]: @@ -566,18 +594,18 @@ class Creeper(Game): for i in range(hats): hat = joystick.get_hat(i) if hat[0] == 1: - self.x += 10 + self.x += 10 * self.speed * self.elapsed if hat[0] == -1: - self.x -= 10 + self.x -= 10 * self.speed * self.elapsed if hat[1] == -1: - self.y += 10 + self.y += 10 * self.speed * self.elapsed if hat[1] == 1: - self.y -= 10 + self.y -= 10 * self.speed * self.elapsed if abs(joystick.get_axis(0)) > 0.2: - self.x += joystick.get_axis(0) * 10 + self.x += joystick.get_axis(0) * 10 * self.speed * self.elapsed if abs(joystick.get_axis(1)) > 0.2: - self.y += joystick.get_axis(1) * 10 + self.y += joystick.get_axis(1) * 10 * self.speed * self.elapsed if abs(joystick.get_axis(3)) > 0.2 and abs(joystick.get_axis(4)) > 0.2: pygame.mouse.set_pos( @@ -655,15 +683,22 @@ class Creeper(Game): ) and not self.walking_sound_is_playing: self.walking_sound.play() self.walking_sound_is_playing = True - if self.last_x != self.x or self.last_y != self.y: - + if ( + self.last_x != self.x or self.last_y != self.y + ) and self.debounce_walk_img < 0: self.creeper = next(self.creepers) + self.debounce_walk_img = 0.15 self.last_x = self.x self.last_y = self.y def game(self): # self.camera = (self.camera[0] + 1, self.camera[1]) + + self.debounce_walk_img -= self.elapsed self.screen.blit(self.background, self.camera) + for block in self.blocks.values(): + self.screen.blit(block.img, block.pos) + self.background.fill((0, 255, 247)) self.process_deaths() for tree in self.trees: @@ -683,20 +718,20 @@ class Creeper(Game): light_level = pygame.time.get_ticks() % self.day_len light_level = abs(light_level * (255 * 2 / self.day_len) - 255) - self.darkness.fill((light_level, light_level, light_level)) - if self.light_power < 500: - self.light_power = min(self.light_power**1.1, 500) - self.darkness.blit( - pygame.transform.smoothscale( - self.spot, [self.light_power, self.light_power] - ), - (self.x - self.light_power / 2, self.y - self.light_power / 2), - ) - self.screen.blit( - self.darkness, - (0, 0), - special_flags=pygame.BLEND_RGBA_MULT, - ) + # self.darkness.fill((light_level, light_level, light_level)) + # if self.light_power < 500: + # self.light_power = min(self.light_power**1.1, 500) + # self.darkness.blit( + # pygame.transform.smoothscale( + # self.spot, [self.light_power, self.light_power] + # ), + # (self.x - self.light_power / 2, self.y - self.light_power / 2), + # ) + # self.screen.blit( + # pygame.transform.scale(self.darkness, self.screen.get_size()).convert(), + # (0, 0), + # special_flags=pygame.BLEND_MULT, + # ) self.hotbar.draw() self.debug_menu.draw() diff --git a/creeper_adventure/game.py b/creeper_adventure/game.py index 852a343..957699f 100755 --- a/creeper_adventure/game.py +++ b/creeper_adventure/game.py @@ -10,11 +10,14 @@ class Game: self.screen_size = (854, 480) self.screen_size = (1280, 800) self.screen_size = (1920, 1080) - self.screen = pygame.display.set_mode(self.screen_size) + # pygame.display.set_mode(resolution, flags, bpp) + flags = pygame.DOUBLEBUF + self.screen = pygame.display.set_mode(self.screen_size, flags) self.clock = pygame.time.Clock() self.running = True self.surfs = [] + self.elapsed = 0 def should_quit(self): for event in self.events: @@ -25,7 +28,8 @@ class Game: ... def reset_screen(self): - self.screen.fill((0, 0, 0)) + ... + # self.screen.fill((0, 0, 0)) def run(self): while self.running: @@ -37,7 +41,7 @@ class Game: for surf in self.surfs: pygame.blit(surf) pygame.display.update() - self.clock.tick(30) + self.elapsed = self.clock.tick(60) / 100 pygame.quit() From d691f1a5ec1464ea621bb47d6ef5e9459c04287d Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Thu, 12 Jan 2023 20:52:10 -0600 Subject: [PATCH 27/31] block assets --- creeper_adventure/assets/plank-bottom.png | Bin 0 -> 9814 bytes creeper_adventure/assets/plank-top.png | Bin 0 -> 12362 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 creeper_adventure/assets/plank-bottom.png create mode 100644 creeper_adventure/assets/plank-top.png diff --git a/creeper_adventure/assets/plank-bottom.png b/creeper_adventure/assets/plank-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2efab19a6e3ccb446578b3c9871a4234ecd235 GIT binary patch literal 9814 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 literal 0 HcmV?d00001 diff --git a/creeper_adventure/assets/plank-top.png b/creeper_adventure/assets/plank-top.png new file mode 100644 index 0000000000000000000000000000000000000000..18e5437b7b890e3f3d876012ff352ee8ac67adae GIT binary patch literal 12362 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 T2YbXlDL_eHU9L*T;>G^~i{|2A literal 0 HcmV?d00001 From db4f2ae64bdef13fe1a14f6311b6c45dd3d91716 Mon Sep 17 00:00:00 2001 From: autobump Date: Fri, 13 Jan 2023 02:52:38 +0000 Subject: [PATCH 28/31] Bump version: 10.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index dffd1f8..e3a3b94 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '9.0.0' +__version__ = '10.0.0' From 8b1dfad72aa792823cde3971cbce4d9b252c0e55 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Sun, 15 Jan 2023 12:17:01 -0600 Subject: [PATCH 29/31] add start button --- creeper_adventure/creeper.py | 73 ++++++++++++++++++++++++++++++++---- creeper_adventure/game.py | 3 ++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py index 3636517..8cb48a8 100755 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -11,6 +11,40 @@ from creeper_adventure.game import Game ASSETS = Path(__file__).parent / "assets" +class Button: + def __init__(self, game, surf, text, x, y, w, h, on_click=lambda: ...): + self.game = game + self.surf = surf + self.text = text + self.x = x + self.y = y + self.w = w + self.h = h + self.on_click = on_click + self.font = pygame.font.SysFont(None, 32) + + def draw(self): + pygame.draw.rect(self.surf, (255, 255, 255), (self.x, self.y, self.w, self.h)) + label = self.font.render(self.text, True, (0, 0, 0)) + label_rect = label.get_rect() + label_rect.center = (self.x + self.w / 2, self.y + self.h / 2) + self.surf.blit(label, label_rect) + for event in self.game.events: + if event.type == pygame.MOUSEBUTTONDOWN: + if self.is_clicked(event.pos): + self.on_click() + # elif quit_button.is_clicked(event.pos): + # running = False + # if self.is_clicked: + # self.on_click() + + def is_clicked(self, pos): + if pos[0] > self.x and pos[0] < self.x + self.w: + if pos[1] > self.y and pos[1] < self.y + self.h: + return True + return False + + class MouseSprite: def __init__(self, game, surf, hotbar): self.game = game @@ -178,6 +212,7 @@ class HotBarItem: self.selected = False self.surf.fill((0, 0, 0)) self.type = None + self.font = pygame.font.SysFont(None, self.scale) def draw(self): self.surf.fill((0, 0, 0, 60)) @@ -193,9 +228,8 @@ class HotBarItem: ), (self.pos * self.scale + self.margin, self.margin), ) - font = pygame.font.SysFont(None, self.scale) qty = str(self.game.inventory[self.type]) - img = font.render(qty, True, (255, 255, 255)) + img = self.font.render(qty, True, (255, 255, 255)) self.ui.blit( pygame.transform.scale(img, (self.scale * 0.6, self.scale * 0.6)), (self.pos * self.scale + self.margin, self.margin), @@ -222,10 +256,12 @@ class Menu: self.scale = scale self.margin = margin self.alpha = alpha + self.font = pygame.font.SysFont(None, 20) + self.surf = pygame.Surface(self.game.screen.get_size()).convert_alpha() def draw(self): if self.is_open: - self.surf = pygame.Surface(self.game.screen.get_size()).convert_alpha() + # self.surf = pygame.Surface(self.game.screen.get_size()).convert_alpha() self.surf.fill((0, 0, 0, self.alpha)) font = pygame.font.SysFont(None, self.scale) img = font.render(self.title, True, (255, 255, 255)) @@ -245,7 +281,6 @@ class Menu: class DebugMenu(Menu): def __init__(self, game): super().__init__(title="Debug Menu", game=game, alpha=0) - self.font = pygame.font.SysFont(None, 20) def _draw(self): self.surf.blit( @@ -302,6 +337,31 @@ class DebugMenu(Menu): ) +class MainMenu(Menu): + def __init__(self, game, title): + super().__init__(game=game, title=title) + self.set_button_text() + + @property + def start_button(self): + w = 200 + h = 50 + x = self.game.screen.get_size()[0] / 2 - w / 2 + y = 300 + print(self.game.frames) + return Button(self.game, self.surf, self.button_text, x, y, w, h, self.toggle) + + def set_button_text(self): + self.button_text = "Start Game" if self.game.frames < 100 else "Continue" + + def toggle(self): + self.set_button_text() + self.is_open = not self.is_open + + def _draw(self): + self.start_button.draw() + + class LightSource: def __init__(self, game: Game, surf, img, center): self.surf = surf @@ -374,7 +434,6 @@ class Bee: class Creeper(Game): def __init__(self, debug=False): super().__init__() - pygame.mouse.set_visible(False) self.inventory = {"plank-bottom": 1, "plank-top": 1} self._imgs = {} self.blocks = {} @@ -460,7 +519,8 @@ class Creeper(Game): self.inventory_menu = Menu(self, title="inventory") self.debug_menu = DebugMenu(self) self.debug_menu.is_open = debug - self.main_menu = Menu(self, title="main menu") + self.main_menu = MainMenu(self, title="main menu") + self.main_menu.is_open = True def get_img(self, img): try: @@ -537,7 +597,6 @@ class Creeper(Game): if not self.joysticks: if (keys[pygame.K_ESCAPE]) and self.main_open_debounce: - print("opens") self.main_menu.is_open = not self.main_menu.is_open self.main_open_debounce = 0 elif not keys[pygame.K_ESCAPE]: diff --git a/creeper_adventure/game.py b/creeper_adventure/game.py index 957699f..7cfeeb9 100755 --- a/creeper_adventure/game.py +++ b/creeper_adventure/game.py @@ -4,6 +4,7 @@ import pygame class Game: def __init__(self): pygame.init() + # pygame.mouse.set_visible(False) pygame.mixer.init() pygame.display.set_caption(__file__) @@ -18,6 +19,7 @@ class Game: self.running = True self.surfs = [] self.elapsed = 0 + self.frames = 0 def should_quit(self): for event in self.events: @@ -42,6 +44,7 @@ class Game: pygame.blit(surf) pygame.display.update() self.elapsed = self.clock.tick(60) / 100 + self.frames += 1 pygame.quit() From f55c2fe32b3981073e7f0ab61640d06f7fac3a24 Mon Sep 17 00:00:00 2001 From: autobump Date: Sun, 15 Jan 2023 18:17:40 +0000 Subject: [PATCH 30/31] Bump version: 11.0.0 --- creeper_adventure/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creeper_adventure/__about__.py b/creeper_adventure/__about__.py index e3a3b94..79f884d 100644 --- a/creeper_adventure/__about__.py +++ b/creeper_adventure/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2023-present Waylon S. Walker # # SPDX-License-Identifier: MIT -__version__ = '10.0.0' +__version__ = '11.0.0' From de1001dd57fe468aa36f41d00fb8fb0506a2b7c4 Mon Sep 17 00:00:00 2001 From: "Waylon S. Walker" Date: Sat, 22 Nov 2025 22:14:46 -0600 Subject: [PATCH 31/31] wip --- .gitignore | 1 + aforest.py | 108 ++++ camera.py | 180 +++++++ constraints.py | 250 ++++++++++ creeper_adventure/assets/bee/idle/1.png | Bin creeper_adventure/assets/creeper/idle/1.png | Bin creeper_adventure/assets/creeper/idle/2.png | Bin creeper_adventure/assets/creeper/idle/3.png | Bin creeper_adventure/assets/creeper/idle/4.png | Bin creeper_adventure/assets/creeper/idle/5.png | Bin creeper_adventure/assets/leaf.png | Bin creeper_adventure/assets/oak_trees/1.png | Bin creeper_adventure/assets/oak_trees/2.png | Bin creeper_adventure/assets/oak_trees/4.png | Bin creeper_adventure/assets/oak_trees/5.png | Bin creeper_adventure/assets/spotlight.png | Bin creeper_adventure/creeper.py | 7 +- creeper_adventure/game.py | 0 forest.py | 63 +++ gpt-menu.py | 85 ++++ gradients.py | 42 ++ grass.png | Bin 0 -> 3673 bytes iso.py | 56 +++ pyproject.toml | 1 + requirements.txt | 0 site/static/creeper-1.png | Bin spacegame.py | 99 ++++ tetris.py | 521 ++++++++++++++++++++ tmp.py | 41 ++ wall.png | Bin 0 -> 5347 bytes 30 files changed, 1451 insertions(+), 3 deletions(-) create mode 100644 aforest.py create mode 100644 camera.py create mode 100644 constraints.py mode change 100755 => 100644 creeper_adventure/assets/bee/idle/1.png mode change 100755 => 100644 creeper_adventure/assets/creeper/idle/1.png mode change 100755 => 100644 creeper_adventure/assets/creeper/idle/2.png mode change 100755 => 100644 creeper_adventure/assets/creeper/idle/3.png mode change 100755 => 100644 creeper_adventure/assets/creeper/idle/4.png mode change 100755 => 100644 creeper_adventure/assets/creeper/idle/5.png mode change 100755 => 100644 creeper_adventure/assets/leaf.png mode change 100755 => 100644 creeper_adventure/assets/oak_trees/1.png mode change 100755 => 100644 creeper_adventure/assets/oak_trees/2.png mode change 100755 => 100644 creeper_adventure/assets/oak_trees/4.png mode change 100755 => 100644 creeper_adventure/assets/oak_trees/5.png mode change 100755 => 100644 creeper_adventure/assets/spotlight.png mode change 100755 => 100644 creeper_adventure/creeper.py mode change 100755 => 100644 creeper_adventure/game.py create mode 100644 forest.py create mode 100644 gpt-menu.py create mode 100644 gradients.py create mode 100644 grass.png create mode 100644 iso.py mode change 100755 => 100644 requirements.txt mode change 100755 => 100644 site/static/creeper-1.png create mode 100644 spacegame.py create mode 100644 tetris.py create mode 100644 tmp.py create mode 100644 wall.png diff --git a/.gitignore b/.gitignore index 1930ca0..26750c3 100644 --- a/.gitignore +++ b/.gitignore @@ -956,3 +956,4 @@ FodyWeavers.xsd # Additional files built by Visual Studio # End of https://www.toptal.com/developers/gitignore/api/vim,node,data,emacs,python,pycharm,executable,sublimetext,visualstudio,visualstudiocode +.null-ls_574349_tetris.py diff --git a/aforest.py b/aforest.py new file mode 100644 index 0000000..47db5fe --- /dev/null +++ b/aforest.py @@ -0,0 +1,108 @@ +import math + +import noise +import pygame + +# set up pygame +pygame.init() + +# set up the window +screen_width, screen_height = 1280, 800 +screen = pygame.display.set_mode((screen_width, screen_height)) +# set up the noise surface +noise_width, noise_height = 1280, 800 +noise_scale = 10 +noise_width = int(screen_width / noise_scale) +noise_height = int(screen_height / noise_scale) +# noise_width, noise_height = round(1280 / 10), round(800 / 10) +noise_surface = pygame.Surface((noise_width, noise_height)) +# set up the colors +BLACK = (0, 0, 0) +GREEN = (0, 255, 0) +BLUE = (0, 0, 255) +colors = [(0, 128, 0), (0, 64, 0), (0, 32, 0)] +# set up the noise +octaves = 1 +freq = 256 * octaves +# generate the noise +noise_map = [ + [ + noise.pnoise2(x / freq, y / freq, octaves, repeatx=3024, repeaty=3024) + for x in range(screen_width) + ] + for y in range(screen_height) +] +# set up the clock +clock = pygame.time.Clock() +# set up the animation +frame = 0 +# set up the noise surface cache +noise_surface_cache = [] +# set up the noise surface cache index +noise_surface_cache_index = 0 +# set up the noise surface cache size +noise_surface_cache_size = 120 +# set up the noise surface cache +for i in range(noise_surface_cache_size): + + print(f"caching {i} of {noise_surface_cache_size}") + # draw the background + for y in range(noise_height): + for x in range(noise_width): + color = colors[2] + if ( + noise_map[y * noise_scale][x * noise_scale] + + math.sin(i * (3.14 / noise_surface_cache_size)) + > 0.2 + ): + color = colors[1] + elif ( + noise_map[y * noise_scale][x * noise_scale] + + math.sin(i * (3.14 / noise_surface_cache_size)) + < 0.15 + ): + color = colors[0] + noise_surface.set_at((x, y), color) + # cache the noise surface + + noise_surface_scaled = pygame.transform.scale( + noise_surface, (screen_width, screen_height) + ) + # noise_surface_scaled_pil = Image.frombytes( + # "RGB", + # (screen_width, screen_height), + # pygame.image.tostring(noise_surface_scaled, "RGB", False), + # ) + + # noise_surface_scaled_pil = noise_surface_scaled_pil.filter( + # ImageFilter.GaussianBlur(radius=20) + # ) + # noise_surface_scaled = pygame.image.fromstring( + # noise_surface_scaled_pil.tobytes(), (screen_width, screen_height), "RGB" + # ) + noise_surface_cache.append(noise_surface_scaled) + +noise_surface_cache.extend([n for n in noise_surface_cache[::-1]]) +# main loop +running = True +print("running") +while running: + # keep loop running at the right speed + clock.tick(60) + # process events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + # increment the frame + frame += 0.2 + if frame > noise_surface_cache_size - 1: + frame = 0 + # draw the noise surface onto the screen + screen.blit(noise_surface_cache[int(frame)], (0, 0)) + + # display the fps on the screen + pygame.display.set_caption(str(clock.get_fps())) + # update the display + pygame.display.flip() + +pygame.quit() diff --git a/camera.py b/camera.py new file mode 100644 index 0000000..807f8e7 --- /dev/null +++ b/camera.py @@ -0,0 +1,180 @@ +"""Basic showcase on how the transform property on SpaceDebugDrawOptions can +be used as a camera to allow panning. Use arrows to move the camera. +""" + +__docformat__ = "reStructuredText" + +import random +import sys + +import pygame +import pymunk.pygame_util +from pymunk.vec2d import Vec2d + +random.seed(0) + + +def main(): + pygame.init() + screen = pygame.display.set_mode((600, 600)) + clock = pygame.time.Clock() + running = True + font = pygame.font.Font(None, 16) + text = font.render( + "Use Arrows (up, down, left, right) to move the camera, " + "a and z to zoom in / out and s and x to rotate.", + True, + pygame.Color("black"), + ) + + ### Physics stuff + space = pymunk.Space() + space.gravity = Vec2d(0.0, 900.0) + draw_options = pymunk.pygame_util.DrawOptions(screen) + + ## Balls + balls = [] + + body = pymunk.Body() + body.position = pymunk.Vec2d(407, 354) + s1 = pymunk.Segment(body, Vec2d(-300, -30), Vec2d(0, 0), 1.0) + s2 = pymunk.Segment(body, Vec2d(0, 0), Vec2d(0, -100), 1.0) + s1.density = 0.1 + s2.density = 0.1 + s1.friction = 1 + s2.friction = 1 + space.add(body, s1, s2) + + c1 = pymunk.constraints.DampedSpring( + space.static_body, + body, + (427, 200), + (0, -100), + Vec2d(407, 254).get_distance((427, 200)), + 2000, + 100, + ) + + c2 = pymunk.constraints.DampedSpring( + space.static_body, + body, + (87, 200), + (-300, -30), + Vec2d(107, 324).get_distance((87, 200)), + 2000, + 100, + ) + space.add(c1, c2) + + # extra to show how constraints are drawn when very small / large + body = pymunk.Body(1, 100) + body.position = 450, 305 + c3 = pymunk.constraints.DampedSpring( + space.static_body, body, (450, 300), (0, 0), 5, 1000, 100 + ) + space.add(body, c3) + body = pymunk.Body(1, 100) + body.position = 500, 2025 + c3 = pymunk.constraints.DampedSpring( + space.static_body, body, (500, 25), (0, 0), 2000, 1000, 100 + ) + space.add(body, c3) + + ticks_to_next_ball = 10 + + translation = pymunk.Transform() + scaling = 1 + rotation = 0 + + while running: + for event in pygame.event.get(): + if ( + event.type == pygame.QUIT + or event.type == pygame.KEYDOWN + and event.key == pygame.K_ESCAPE + ): + running = False + elif event.type == pygame.KEYDOWN and event.key == pygame.K_p: + pygame.image.save(screen, "camera.png") + + keys = pygame.key.get_pressed() + left = int(keys[pygame.K_LEFT]) + up = int(keys[pygame.K_UP]) + down = int(keys[pygame.K_DOWN]) + right = int(keys[pygame.K_RIGHT]) + + zoom_in = int(keys[pygame.K_a]) + zoom_out = int(keys[pygame.K_z]) + rotate_left = int(keys[pygame.K_s]) + rotate_right = int(keys[pygame.K_x]) + + translate_speed = 10 + translation = translation.translated( + translate_speed * left - translate_speed * right, + translate_speed * up - translate_speed * down, + ) + + zoom_speed = 0.1 + scaling *= 1 + (zoom_speed * zoom_in - zoom_speed * zoom_out) + + rotation_speed = 0.1 + rotation += rotation_speed * rotate_left - rotation_speed * rotate_right + + # to zoom with center of screen as origin we need to offset with + # center of screen, scale, and then offset back + draw_options.transform = ( + pymunk.Transform.translation(300, 300) + @ pymunk.Transform.scaling(scaling) + @ translation + @ pymunk.Transform.rotation(rotation) + @ pymunk.Transform.translation(-300, -300) + ) + + ticks_to_next_ball -= 1 + if ticks_to_next_ball <= 0: + ticks_to_next_ball = 100 + mass = 10 + radius = 25 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0)) + body = pymunk.Body(mass, inertia) + x = random.randint(115, 350) + body.position = x, 100 + if random.random() > 0.5: + shape = pymunk.Circle(body, radius) + else: + shape = pymunk.Poly.create_box( + body, size=(radius * 2, radius * 2), radius=2 + ) + shape.friction = 1 + space.add(body, shape) + balls.append(shape) + + ### Clear screen + screen.fill(pygame.Color("white")) + + ### Draw stuff + space.debug_draw(draw_options) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y > 500: + balls_to_remove.append(ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + screen.blit(text, (5, 5)) + + ### Update physics + dt = 1.0 / 60.0 + space.step(dt) + + ### Flip screen + pygame.display.flip() + clock.tick(50) + pygame.display.set_caption("fps: " + str(clock.get_fps())) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/constraints.py b/constraints.py new file mode 100644 index 0000000..a9d518d --- /dev/null +++ b/constraints.py @@ -0,0 +1,250 @@ +""" +Pymunk constraints demo. Showcase of all the constraints included in Pymunk. + +Adapted from the Chipmunk Joints demo: +https://github.com/slembcke/Chipmunk2D/blob/master/demo/Joints.c +""" + +import inspect +import math + +import pygame +import pymunk.pygame_util +from pymunk.vec2d import Vec2d + +pygame.init() +screen = pygame.display.set_mode((1200, 600)) +clock = pygame.time.Clock() +font = pygame.font.Font(None, 24) + + +help_txt = font.render( + "Pymunk constraints demo. Use mouse to drag/drop. Hover to see descr.", + True, + pygame.Color("darkgray"), +) + +space = pymunk.Space() +space.gravity = (0.0, 900.0) +draw_options = pymunk.pygame_util.DrawOptions(screen) + +# containers +box_size = 200 +w = screen.get_width() +h = screen.get_height() +for i in range(6): + sw = pymunk.Segment(space.static_body, (0, i * box_size), (w, i * box_size), 1) + sw.friction = 1 + sw.elasticity = 1 + sh = pymunk.Segment( + space.static_body, (i * box_size, 0), (i * box_size, h - box_size), 1 + ) + sh.friction = 1 + sh.elasticity = 1 + space.add(sw, sh) + + +def add_ball(space, pos, box_offset): + body = pymunk.Body() + body.position = Vec2d(*pos) + box_offset + shape = pymunk.Circle(body, 20) + shape.mass = 1 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def add_bar(space, pos, box_offset): + body = pymunk.Body() + body.position = Vec2d(*pos) + box_offset + shape = pymunk.Segment(body, (0, 40), (0, -40), 6) + shape.mass = 2 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def add_lever(space, pos, box_offset): + body = pymunk.Body() + body.position = pos + Vec2d(*box_offset) + (0, -20) + shape = pymunk.Segment(body, (0, 20), (0, -20), 5) + shape.mass = 1 + shape.friction = 0.7 + space.add(body, shape) + return body + + +def main(): + txts = {} + + box_offset = 0, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c: pymunk.Constraint = pymunk.PinJoint(b1, b2, (20, 0), (-20, 0)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.SlideJoint(b1, b2, (20, 0), (-20, 0), 40, 80) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 2, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.PivotJoint(b1, b2, Vec2d(*box_offset) + (100, 60)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 3, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.GrooveJoint(b1, b2, (50, 50), (50, -50), (-50, 0)) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 4, 0 + b1 = add_ball(space, (50, 60), box_offset) + b2 = add_ball(space, (150, 60), box_offset) + c = pymunk.DampedSpring(b1, b2, (30, 0), (-30, 0), 20, 5, 0.3) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 5, 0 + b1 = add_bar(space, (50, 80), box_offset) + b2 = add_bar(space, (150, 80), box_offset) + # Add some joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 80) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 80) + Vec2d(*box_offset))) + c = pymunk.DampedRotarySpring(b1, b2, 0, 3000, 60) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = 0, box_size + b1 = add_lever(space, (50, 100), box_offset) + b2 = add_lever(space, (150, 100), box_offset) + # Add some joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Hold their rotation within 90 degrees of each other. + c = pymunk.RotaryLimitJoint(b1, b2, math.pi / 2, math.pi / 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size, box_size + b1 = add_lever(space, (50, 100), box_offset) + b2 = add_lever(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Ratchet every 90 degrees + c = pymunk.RatchetJoint(b1, b2, 0, math.pi / 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 2, box_size + b1 = add_bar(space, (50, 100), box_offset) + b2 = add_bar(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Force one to sping 2x as fast as the other + c = pymunk.GearJoint(b1, b2, 0, 2) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + box_offset = box_size * 3, box_size + b1 = add_bar(space, (50, 100), box_offset) + b2 = add_bar(space, (150, 100), box_offset) + # Add some pin joints to hold the circles in place. + space.add(pymunk.PivotJoint(b1, space.static_body, (50, 100) + Vec2d(*box_offset))) + space.add(pymunk.PivotJoint(b2, space.static_body, (150, 100) + Vec2d(*box_offset))) + # Make them spin at 1/2 revolution per second in relation to each other. + c = pymunk.SimpleMotor(b1, b2, math.pi) + txts[box_offset] = inspect.getdoc(c) + space.add(c) + + # TODO add one or two advanced constraints examples, such as a car or rope + + mouse_joint = None + mouse_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC) + + # Build rendered help texts + box_texts = {} + for k in txts: + l = 0 + box_texts[k] = [] + # Only take the first 5 lines. + for line in txts[k].splitlines()[:5]: + txt = font.render(line, True, pygame.Color("black")) + box_texts[k].append(txt) + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + exit() + elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + exit() + elif event.type == pygame.MOUSEBUTTONDOWN: + if mouse_joint is not None: + space.remove(mouse_joint) + mouse_joint = None + + p = Vec2d(*event.pos) + hit = space.point_query_nearest(p, 5, pymunk.ShapeFilter()) + if hit is not None and hit.shape.body.body_type == pymunk.Body.DYNAMIC: + shape = hit.shape + # Use the closest point on the surface if the click is outside + # of the shape. + if hit.distance > 0: + nearest = hit.point + else: + nearest = p + mouse_joint = pymunk.PivotJoint( + mouse_body, + shape.body, + (0, 0), + shape.body.world_to_local(nearest), + ) + mouse_joint.max_force = 50000 + mouse_joint.error_bias = (1 - 0.15) ** 60 + space.add(mouse_joint) + + elif event.type == pygame.MOUSEBUTTONUP: + if mouse_joint is not None: + space.remove(mouse_joint) + mouse_joint = None + + screen.fill(pygame.Color("white")) + + screen.blit(help_txt, (5, screen.get_height() - 20)) + + mouse_pos = pygame.mouse.get_pos() + + # Display help message + x = mouse_pos[0] // box_size * box_size + y = mouse_pos[1] // box_size * box_size + + if (x, y) in box_texts: + txts = box_texts[(x, y)] + i = 0 + for txt in txts: + pos = (5, box_size * 2 + 10 + i * 20) + screen.blit(txt, pos) + i += 1 + + mouse_body.position = mouse_pos + + space.step(1.0 / 60) + + space.debug_draw(draw_options) + pygame.display.flip() + + clock.tick(60) + pygame.display.set_caption(f"fps: {clock.get_fps()}") + + +if __name__ == "__main__": + main() diff --git a/creeper_adventure/assets/bee/idle/1.png b/creeper_adventure/assets/bee/idle/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/1.png b/creeper_adventure/assets/creeper/idle/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/2.png b/creeper_adventure/assets/creeper/idle/2.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/3.png b/creeper_adventure/assets/creeper/idle/3.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/4.png b/creeper_adventure/assets/creeper/idle/4.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/creeper/idle/5.png b/creeper_adventure/assets/creeper/idle/5.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/leaf.png b/creeper_adventure/assets/leaf.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/1.png b/creeper_adventure/assets/oak_trees/1.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/2.png b/creeper_adventure/assets/oak_trees/2.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/4.png b/creeper_adventure/assets/oak_trees/4.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/oak_trees/5.png b/creeper_adventure/assets/oak_trees/5.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/assets/spotlight.png b/creeper_adventure/assets/spotlight.png old mode 100755 new mode 100644 diff --git a/creeper_adventure/creeper.py b/creeper_adventure/creeper.py old mode 100755 new mode 100644 index 8cb48a8..f9eccd1 --- a/creeper_adventure/creeper.py +++ b/creeper_adventure/creeper.py @@ -1,10 +1,12 @@ -import random from copy import copy from itertools import cycle, repeat from pathlib import Path +import random +from typing import List, Optional -import pygame from more_itertools import flatten +from pydantic import BaseModel +import pygame from creeper_adventure.game import Game @@ -348,7 +350,6 @@ class MainMenu(Menu): h = 50 x = self.game.screen.get_size()[0] / 2 - w / 2 y = 300 - print(self.game.frames) return Button(self.game, self.surf, self.button_text, x, y, w, h, self.toggle) def set_button_text(self): diff --git a/creeper_adventure/game.py b/creeper_adventure/game.py old mode 100755 new mode 100644 diff --git a/forest.py b/forest.py new file mode 100644 index 0000000..3a67d9c --- /dev/null +++ b/forest.py @@ -0,0 +1,63 @@ +import math + +from noise import pnoise2 +import pygame + +# Initialize pygame +pygame.init() + +base = 0 +persistence = 0.4 +lacunarity = 2.0 +more_x = 0 +# Set up the drawing window +screen = pygame.display.set_mode([800, 600]) + + +def S(): + i = 0 + while True: + i += 0.1 + yield math.sin(i) + + +s = S() + +# Run until the user asks to quit +running = True +while running: + + # Did the user click the window close button? + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Fill the background with white + screen.fill((255, 255, 255)) + + m = next(s) + # Generate Perlin noise + for x in range(800): + for y in range(600): + noise = pnoise2( + x / 10, + y / 10, + octaves=4, + persistence=persistence + m / 10, + lacunarity=lacunarity, + repeatx=1024, + repeaty=1024, + base=base, + ) + if noise > 0.2: + pygame.draw.rect(screen, (0, 255, 0), (x, y, 1, 1)) + elif noise > 0: + pygame.draw.rect(screen, (0, 128, 0), (x, y, 1, 1)) + else: + pygame.draw.rect(screen, (0, 64, 0), (x, y, 1, 1)) + + # Flip the display + pygame.display.flip() + +# Done! Time to quit. +pygame.quit() diff --git a/gpt-menu.py b/gpt-menu.py new file mode 100644 index 0000000..12c26fe --- /dev/null +++ b/gpt-menu.py @@ -0,0 +1,85 @@ +import pygame + +# Initialize Pygame +pygame.init() + +EVENTS = [] +# Set screen size +screen = pygame.display.set_mode((800, 600)) + +# Set title +pygame.display.set_caption("My RPG Game") + +# Load font +font = pygame.font.Font(None, 30) + +# Define button class +class Button: + def __init__(self, text, x, y, w, h, on_click=lambda: ...): + self.text = text + self.x = x + self.y = y + self.w = w + self.h = h + self.on_click = on_click + + def draw(self, surface): + pygame.draw.rect(surface, (255, 255, 255), (self.x, self.y, self.w, self.h)) + label = font.render(self.text, True, (0, 0, 0)) + label_rect = label.get_rect() + label_rect.center = (self.x + self.w / 2, self.y + self.h / 2) + surface.blit(label, label_rect) + for event in EVENTS: + if event.type == pygame.MOUSEBUTTONDOWN: + if self.is_clicked(event.pos): + self.on_click() + # elif quit_button.is_clicked(event.pos): + # running = False + # if self.is_clicked: + # self.on_click() + + def is_clicked(self, pos): + if pos[0] > self.x and pos[0] < self.x + self.w: + if pos[1] > self.y and pos[1] < self.y + self.h: + return True + return False + + +# Create buttons +start_button = Button( + "Start Game", 300, 300, 200, 50, lambda: print("start this thing") +) +running = True + + +def stop(): + global running + running = False + + +quit_button = Button("Quit Game", 300, 400, 200, 50, stop) + +# Main loop +while running: + EVENTS = pygame.event.get() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Check for button clicks + + # Draw background + screen.fill((0, 0, 0)) + + # Draw title + title = font.render("Creeper Adventure", True, (255, 255, 255)) + screen.blit(title, (250, 200)) + + # Draw buttons + start_button.draw(screen) + quit_button.draw(screen) + + pygame.display.update() + +# Quit Pygame +pygame.quit() diff --git a/gradients.py b/gradients.py new file mode 100644 index 0000000..4834b3b --- /dev/null +++ b/gradients.py @@ -0,0 +1,42 @@ +from noise import pnoise2 +import pygame +import random + +# Initialize pygame +pygame.init() + +# Set the size of the window +width, height = 800, 600 +screen = pygame.display.set_mode((width, height)) + +# Create a list of 3 random blues +blues = [] +for i in range(3): + blues.append( + (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + ) + +# Create a perlin noise surface +noise_surface = pygame.Surface((width, height)) +for x in range(width): + for y in range(height): + # Calculate the perlin noise value + noise_value = pnoise2(x / 100, y / 100) + # Map the noise value to a color + color_index = int(noise_value * (len(blues) - 1)) + color = blues[color_index] + # Set the color of the pixel + noise_surface.set_at((x, y), color) + +# Blit the noise surface to the screen +screen.blit(noise_surface, (0, 0)) + +# Update the display +pygame.display.flip() + +# Keep the window open until it is closed +while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + exit() diff --git a/grass.png b/grass.png new file mode 100644 index 0000000000000000000000000000000000000000..894be7d2fda1bfa7ef7e7ba3867c17e634f1bf07 GIT binary patch literal 3673 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 p0 MOVESIDEWAYSFREQ: + if movingLeft and isValidPosition(board, fallingPiece, adjX=-1): + fallingPiece['x'] -= 1 + elif movingRight and isValidPosition(board, fallingPiece, adjX=1): + fallingPiece['x'] += 1 + lastMoveSidewaysTime = time.time() + + if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): + fallingPiece['y'] += 1 + lastMoveDownTime = time.time() + + # let the piece fall if it is time to fall + if time.time() - lastFallTime > fallFreq: + # see if the piece has landed + if not isValidPosition(board, fallingPiece, adjY=1): + # falling piece has landed, set it on the board + addToBoard(board, fallingPiece) + score += removeCompleteLines(board) + level, fallFreq = calculateLevelAndFallFreq(score) + fallingPiece = None + else: + # piece did not land, just move the piece down + fallingPiece['y'] += 1 + lastFallTime = time.time() + + # drawing everything on the screen + DISPLAYSURF.fill(BGCOLOR) + drawBoard(board) + drawStatus(score, level) + drawNextPiece(nextPiece) # Here + if fallingPiece != None: + drawPiece(fallingPiece) + + pygame.display.update() + FPSCLOCK.tick(FPS) + + +def makeTextObjs(text, font, color): + surf = font.render(text, True, color) + return surf, surf.get_rect() + + +def terminate(): + pygame.quit() + sys.exit() + + +def checkForKeyPress(): + # Go through event queue looking for a KEYUP event. + # Grab KEYDOWN events to remove them from the event queue. + checkForQuit() + + for event in pygame.event.get([KEYDOWN, KEYUP]): + if event.type == KEYDOWN: + continue + return event.key + return None + + +def showTextScreen(text): + # This function displays large text in the + # center of the screen until a key is pressed. + # Draw the text drop shadow + titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR) + titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) + DISPLAYSURF.blit(titleSurf, titleRect) + + # Draw the text + titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR) + titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) + DISPLAYSURF.blit(titleSurf, titleRect) + + # Draw the additional "Press a key to play." text. + pressKeySurf, pressKeyRect = makeTextObjs( + 'Press a key to play.', BASICFONT, TEXTCOLOR) + pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100) + DISPLAYSURF.blit(pressKeySurf, pressKeyRect) + + while checkForKeyPress() == None: + pygame.display.update() + FPSCLOCK.tick() + + +def checkForQuit(): + for event in pygame.event.get(QUIT): # get all the QUIT events + terminate() # terminate if any QUIT events are present + for event in pygame.event.get(KEYUP): # get all the KEYUP events + if event.key == K_ESCAPE: + terminate() # terminate if the KEYUP event was for the Esc key + pygame.event.post(event) # put the other KEYUP event objects back + + +def calculateLevelAndFallFreq(score): + # Based on the score, return the level the player is on and + # how many seconds pass until a falling piece falls one space. + level = int(score / 10) + 1 + fallFreq = 0.27 - (level * 0.02) + return level, fallFreq + + +def getNewPiece(): + # return a random new piece in a random rotation and color + shape = random.choice(list(PIECES.keys())) + newPiece = {'shape': shape, + 'rotation': random.randint(0, len(PIECES[shape]) - 1), + 'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), + 'y': -2, # start it above the board (i.e. less than 0) + 'color': random.randint(0, len(COLORS) - 1)} + return newPiece + + +def addToBoard(board, piece): + # fill in the board based on piece's location, shape, and rotation + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK: + board[x + piece['x']][y + piece['y']] = piece['color'] + + +def getBlankBoard(): + # create and return a new blank board data structure + board = [] + for i in range(BOARDWIDTH): + board.append([BLANK] * BOARDHEIGHT) + return board + + +def isOnBoard(x, y): + return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT + + +def isValidPosition(board, piece, adjX=0, adjY=0): + # Return True if the piece is within the board and not colliding + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + isAboveBoard = y + piece['y'] + adjY < 0 + if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK: + continue + if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY): + return False + if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK: + return False + return True + + +def isCompleteLine(board, y): + # Return True if the line filled with boxes with no gaps. + for x in range(BOARDWIDTH): + if board[x][y] == BLANK: + return False + return True + + +def removeCompleteLines(board): + # Remove any completed lines on the board, move everything above them down, and return the number of complete lines. + numLinesRemoved = 0 + y = BOARDHEIGHT - 1 # start y at the bottom of the board + while y >= 0: + if isCompleteLine(board, y): + # Remove the line and pull boxes down by one line. + for pullDownY in range(y, 0, -1): + for x in range(BOARDWIDTH): + board[x][pullDownY] = board[x][pullDownY - 1] + # Set very top line to blank. + for x in range(BOARDWIDTH): + board[x][0] = BLANK + numLinesRemoved += 1 + # Note on the next iteration of the loop, y is the same. + # This is so that if the line that was pulled down is also + # complete, it will be removed. + else: + y -= 1 # move on to check next row up + return numLinesRemoved + + +def convertToPixelCoords(boxx, boxy): + # Convert the given xy coordinates of the board to xy + # coordinates of the location on the screen. + return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE)) + + +def drawBox(boxx, boxy, color, pixelx=None, pixely=None): + # draw a single box (each tetromino piece has four boxes) + # at xy coordinates on the board. Or, if pixelx & pixely + # are specified, draw to the pixel coordinates stored in + # pixelx & pixely (this is used for the "Next" piece). + if color == BLANK: + return + if pixelx == None and pixely == None: + pixelx, pixely = convertToPixelCoords(boxx, boxy) + pygame.draw.rect(DISPLAYSURF, COLORS[color], + (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1)) + pygame.draw.rect( + DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4)) + + +def drawBoard(board): + # draw the border around the board + pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, + (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5) + + # fill the background of the board + pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, + BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT)) + # draw the individual boxes on the board + for x in range(BOARDWIDTH): + for y in range(BOARDHEIGHT): + drawBox(x, y, board[x][y]) + + +def drawStatus(score, level): + # draw the score text + scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR) + scoreRect = scoreSurf.get_rect() + scoreRect.topleft = (WINDOWWIDTH - 150, 20) + DISPLAYSURF.blit(scoreSurf, scoreRect) + + # draw the level text + levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR) + levelRect = levelSurf.get_rect() + levelRect.topleft = (WINDOWWIDTH - 150, 50) + DISPLAYSURF.blit(levelSurf, levelRect) + + +def drawPiece(piece, pixelx=None, pixely=None): + shapeToDraw = PIECES[piece['shape']][piece['rotation']] + if pixelx == None and pixely == None: + # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure + pixelx, pixely = convertToPixelCoords(piece['x'], piece['y']) + + # draw each of the boxes that make up the piece + for x in range(TEMPLATEWIDTH): + for y in range(TEMPLATEHEIGHT): + if shapeToDraw[y][x] != BLANK: + drawBox(None, None, piece['color'], pixelx + + (x * BOXSIZE), pixely + (y * BOXSIZE)) + + +def drawNextPiece(piece): + # draw the "next" text + nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR) + nextRect = nextSurf.get_rect() + nextRect.topleft = (WINDOWWIDTH - 120, 80) + DISPLAYSURF.blit(nextSurf, nextRect) + # draw the "next" piece + drawPiece(piece, pixelx=WINDOWWIDTH - 120, pixely=100) + + +if __name__ == '__main__': + main() diff --git a/tmp.py b/tmp.py new file mode 100644 index 0000000..a82b9ca --- /dev/null +++ b/tmp.py @@ -0,0 +1,41 @@ +import noise +import pygame + +# Initialize pygame +pygame.init() + +# Set up the drawing window +screen = pygame.display.set_mode([800, 600]) + +# Run until the user asks to quit +running = True +while running: + + # Did the user click the window close button? + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Fill the background with black + screen.fill((0, 0, 0)) + + # Draw stars + for i in range(2000): + x = int(noise.pnoise1(i / 10.0, octaves=4) * 800) + y = int(noise.pnoise1(i / 10.0 + 1000, octaves=4) * 600) + pygame.draw.circle(screen, (255, 255, 255), (x, y), 2) + + # Draw the moon + pygame.draw.circle(screen, (180, 180, 180), (400, 5600 - 200), 5000, 0) # moon + + # Draw craters on the surface of the moon (masked by the shape of the moon) + for i in range(20): + x = int(noise.pnoise1(i / 10.0, octaves=4) * 800) + y = int(noise.pnoise1(i / 10.0 + 1000, octaves=4) * 600) + pygame.draw.circle(screen, (100, 100, 100), (x, y), 20, 0) + + # Flip the display + pygame.display.flip() + +# Done! Time to quit. +pygame.quit() diff --git a/wall.png b/wall.png new file mode 100644 index 0000000000000000000000000000000000000000..a81bb686aa0e12414dbb72aea3e77bd6c972d4ac GIT binary patch literal 5347 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 BZpr`v literal 0 HcmV?d00001