diff --git a/CREDITS b/CREDITS
index 015b4a1..41dd75b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,5 +1,8 @@
The Roboto Black font used in this project is licensed under the Open Font License. Read assets/fonts/OFL.txt for more information.
+Graphics from Kenney's Platformer Winter Pack and Kenney's New Platformer Pack
+https://www.kenney.nl
+
Huge Thanks to Python for being the programming language used in this game.
https://www.python.org/
diff --git a/assets/graphics/KenneyNewPlatformerPack/License.txt b/assets/graphics/KenneyNewPlatformerPack/License.txt
new file mode 100644
index 0000000..687772b
--- /dev/null
+++ b/assets/graphics/KenneyNewPlatformerPack/License.txt
@@ -0,0 +1,28 @@
+
+
+ New Platformer Pack (1.0)
+
+ Created/distributed by Kenney (www.kenney.nl)
+ Creation date: 01-05-2025
+
+ ------------------------------
+
+ License: (Creative Commons Zero, CC0)
+ http://creativecommons.org/publicdomain/zero/1.0/
+
+ You can use this content for personal, educational, and commercial purposes.
+
+ Support by crediting 'Kenney' or 'www.kenney.nl' (this is not a requirement)
+
+ ------------------------------
+
+ • Website : www.kenney.nl
+ • Donate : www.kenney.nl/donate
+
+ • Patreon : patreon.com/kenney
+
+ Follow on social media for updates:
+
+ • Twitter: twitter.com/KenneyNL
+ • BlueSky: kenney.bsky.social
+ • Instagram: instagram.com/kenney_nl
\ No newline at end of file
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_a.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_a.png
new file mode 100644
index 0000000..2c40758
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_a.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_b.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_b.png
new file mode 100644
index 0000000..dbbf7d3
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_climb_b.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_duck.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_duck.png
new file mode 100644
index 0000000..316b236
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_duck.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_front.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_front.png
new file mode 100644
index 0000000..9f13164
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_front.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_hit.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_hit.png
new file mode 100644
index 0000000..b92eb94
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_hit.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_idle.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_idle.png
new file mode 100644
index 0000000..8502a95
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_idle.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_jump.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_jump.png
new file mode 100644
index 0000000..af20711
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_jump.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_a.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_a.png
new file mode 100644
index 0000000..e134fcf
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_a.png differ
diff --git a/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_b.png b/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_b.png
new file mode 100644
index 0000000..8852432
Binary files /dev/null and b/assets/graphics/KenneyNewPlatformerPack/character/character_green_walk_b.png differ
diff --git a/assets/graphics/KenneyPlatformerWinter/license.txt b/assets/graphics/KenneyPlatformerWinter/license.txt
new file mode 100644
index 0000000..f58b0d6
--- /dev/null
+++ b/assets/graphics/KenneyPlatformerWinter/license.txt
@@ -0,0 +1,14 @@
+
+###############################################################################
+
+ Platformer graphics (Ice World) by Kenney Vleugels (www.kenney.nl)
+
+ ------------------------------
+
+ License (CC0)
+ http://creativecommons.org/publicdomain/zero/1.0/
+
+ You may use these graphics in personal and commercial projects.
+ Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
+
+###############################################################################
\ No newline at end of file
diff --git a/assets/graphics/KenneyPlatformerWinter/sheet.png b/assets/graphics/KenneyPlatformerWinter/sheet.png
new file mode 100644
index 0000000..c237b99
Binary files /dev/null and b/assets/graphics/KenneyPlatformerWinter/sheet.png differ
diff --git a/assets/graphics/KenneyPlatformerWinter/sheet.tsx b/assets/graphics/KenneyPlatformerWinter/sheet.tsx
new file mode 100644
index 0000000..c539640
--- /dev/null
+++ b/assets/graphics/KenneyPlatformerWinter/sheet.tsx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/assets/map.tmx b/assets/map.tmx
new file mode 100644
index 0000000..cc2e493
--- /dev/null
+++ b/assets/map.tmx
@@ -0,0 +1,65 @@
+
+
diff --git a/assets/sound/background.mp3 b/assets/sound/background.mp3
new file mode 100644
index 0000000..e82f2ee
Binary files /dev/null and b/assets/sound/background.mp3 differ
diff --git a/assets/sound/freeze.wav b/assets/sound/freeze.wav
new file mode 100644
index 0000000..69dae3d
Binary files /dev/null and b/assets/sound/freeze.wav differ
diff --git a/game/play.py b/game/play.py
index b35db12..d41cece 100644
--- a/game/play.py
+++ b/game/play.py
@@ -1,7 +1,7 @@
-import arcade, arcade.gui
+import arcade, arcade.gui, json
-from utils.constants import button_style
-from utils.preload import button_texture, button_hovered_texture
+from utils.constants import FOLLOW_DECAY_CONST, GRAVITY, PLAYER_MOVEMENT_SPEED, PLAYER_JUMP_SPEED, GRID_PIXEL_SIZE
+from utils.preload import tile_map, player_still_animation, player_jump_animation, player_walk_animation, freeze_sound, background_sound
class Game(arcade.gui.UIView):
def __init__(self, pypresence_client):
@@ -10,21 +10,139 @@ class Game(arcade.gui.UIView):
self.pypresence_client = pypresence_client
self.pypresence_client.update(state="Keeping the warmth")
+ self.camera_sprites = arcade.Camera2D()
+ self.camera_bounds = self.window.rect
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
+
+ self.scene = self.create_scene()
+ self.spawn_position = tile_map.object_lists["spawn"][0].shape
+
+ player_x, player_y = self.spawn_position
+
+ self.player = arcade.TextureAnimationSprite(animation=player_still_animation, center_x=player_x, center_y=player_y)
+
+ self.physics_engine = arcade.PhysicsEnginePlatformer(
+ self.player, gravity_constant=GRAVITY,
+ walls=[self.scene["walls"], self.scene["ice"]]
+ )
+
self.warmth = 100
- self.camera = arcade.Camera2D()
- self.spritelist = arcade.SpriteList()
+ self.direction = "right"
+
+ self.scene.add_sprite("Player", self.player)
+
+ with open("settings.json", "r") as file:
+ self.settings = json.load(file)
+
+ if self.settings.get("sfx", True):
+ self.freeze_player = freeze_sound.play(loop=True, volume=self.settings.get("sfx_volume", 100) / 100)
+ self.freeze_player.pause()
+
+ self.background_player = background_sound.play(loop=True, volume=self.settings.get("sfx_volume", 100) / 100)
def on_show_view(self):
super().on_show_view()
- self.warmth_meter = self.anchor.add(arcade.gui.UISlider(value=100, max_value=100, min_value=0), anchor_x="center", anchor_y="bottom")
- def on_update(self, delta_time):
- self.warmth_meter.value = self.warmth
+ def reset(self):
+ self.warmth = 100
+ self.player.change_x, self.player.change_y = 0, 0
+ self.player.position = self.spawn_position
+
+ def create_scene(self) -> arcade.Scene:
+ self.camera_bounds = arcade.LRBT(
+ self.window.width/2.0,
+ tile_map.width * GRID_PIXEL_SIZE - self.window.width/2.0,
+ self.window.height/2.0,
+ tile_map.height * GRID_PIXEL_SIZE
+ )
+
+ return arcade.Scene.from_tilemap(tile_map)
def on_draw(self):
- super().on_draw()
+ self.clear()
- with self.camera.activate():
- self.spritelist.draw()
\ No newline at end of file
+ with self.camera_sprites.activate():
+ self.scene.draw()
+
+ self.ui.draw()
+ arcade.draw_lbwh_rectangle_filled(self.window.width / 4, 0, (self.window.width / 2), self.window.height / 20, arcade.color.SKY_BLUE)
+ arcade.draw_lbwh_rectangle_filled(self.window.width / 4, 0, (self.window.width / 2) * (self.warmth / 100), self.window.height / 20, arcade.color.RED)
+
+ def center_camera_to_player(self):
+ self.camera_sprites.position = arcade.math.smerp_2d(
+ self.camera_sprites.position,
+ self.player.position,
+ self.window.delta_time,
+ FOLLOW_DECAY_CONST,
+ )
+
+ self.camera_sprites.view_data.position = arcade.camera.grips.constrain_xy(
+ self.camera_sprites.view_data, self.camera_bounds
+ )
+
+ def clamp(self, value, min_value, max_value):
+ return max(min_value, min(value, max_value))
+
+ def change_player_animation(self, animation):
+ if self.player.animation != animation:
+ self.player.animation = animation
+
+ def on_update(self, delta_time: float):
+ hit_list = self.physics_engine.update()
+ self.center_camera_to_player()
+
+ if self.warmth <= 0:
+ self.reset()
+
+ if self.player.collides_with_list(self.scene["spikes"]):
+ self.reset()
+
+ if self.player.center_x < 0 or self.player.center_x > tile_map.width * GRID_PIXEL_SIZE:
+ self.reset()
+ elif self.player.center_y < 0:
+ self.reset()
+
+ ice_touch = any([ice_sprite in hit_list for ice_sprite in self.scene["ice"]]) and self.physics_engine.can_jump()
+
+ if self.window.keyboard[arcade.key.UP] or self.window.keyboard[arcade.key.SPACE]:
+ if self.physics_engine.can_jump():
+ self.player.change_y = PLAYER_JUMP_SPEED
+
+ if self.window.keyboard[arcade.key.LEFT] or self.window.keyboard[arcade.key.A]:
+ self.player.change_x = -PLAYER_MOVEMENT_SPEED
+ self.direction = "left"
+
+ elif self.window.keyboard[arcade.key.RIGHT] or self.window.keyboard[arcade.key.D]:
+ self.player.change_x = PLAYER_MOVEMENT_SPEED
+ self.direction = "right"
+
+ else:
+ if ice_touch:
+ if self.direction == "right":
+ self.player.change_x = self.clamp(self.player.change_x * 0.7, PLAYER_MOVEMENT_SPEED * 0.05, PLAYER_MOVEMENT_SPEED)
+ else:
+ self.player.change_x = self.clamp(self.player.change_x * 0.7, -PLAYER_MOVEMENT_SPEED, -PLAYER_MOVEMENT_SPEED * 0.05)
+ else:
+ self.player.change_x = 0
+
+ if ice_touch:
+ self.player.change_x *= 1.3
+
+ if abs(self.player.rect.distance_from_bounds(self.spawn_position)) > GRID_PIXEL_SIZE * 5:
+ if self.settings.get("sfx", True) and not self.freeze_player.playing:
+ self.freeze_player.play()
+ self.warmth = self.clamp(self.warmth - 0.1, 0, 100)
+ else:
+ if self.settings.get("sfx", True):
+ self.freeze_player.pause()
+ self.warmth = self.clamp(self.warmth + 0.05, 0, 100)
+
+ if self.player.change_y > 0:
+ self.change_player_animation(player_jump_animation)
+ elif abs(self.player.change_x) > 0:
+ self.change_player_animation(player_walk_animation)
+ else:
+ self.change_player_animation(player_still_animation)
+
+ self.player.update_animation()
\ No newline at end of file
diff --git a/game/sprites.py b/game/sprites.py
deleted file mode 100644
index e69de29..0000000
diff --git a/menus/main.py b/menus/main.py
index bdb9c5b..fa98dce 100644
--- a/menus/main.py
+++ b/menus/main.py
@@ -52,10 +52,10 @@ class Main(arcade.gui.UIView):
self.title_label = self.box.add(arcade.gui.UILabel(text="Ember Keeper", font_name="Roboto", font_size=48))
- self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style))
+ self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 10, style=big_button_style))
self.play_button.on_click = lambda event: self.play()
- self.settings_button = self.box.add(arcade.gui.UITextureButton(text="Settings", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style))
+ self.settings_button = self.box.add(arcade.gui.UITextureButton(text="Settings", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=self.window.height / 10, style=big_button_style))
self.settings_button.on_click = lambda event: self.settings()
def play(self):
diff --git a/run.py b/run.py
index 4da1b34..36fee4a 100644
--- a/run.py
+++ b/run.py
@@ -19,7 +19,7 @@ from arcade.experimental.controller_window import ControllerWindow
sys.excepthook = on_exception
-__builtins__.print = lambda *args, **kwargs: logging.debug(" ".join(map(str, args)))
+# __builtins__.print = lambda *args, **kwargs: logging.debug(" ".join(map(str, args)))
if not log_dir in os.listdir():
os.makedirs(log_dir)
diff --git a/utils/constants.py b/utils/constants.py
index 506f3c4..238917f 100644
--- a/utils/constants.py
+++ b/utils/constants.py
@@ -3,6 +3,12 @@ from arcade.types import Color
from arcade.gui.widgets.buttons import UITextureButtonStyle, UIFlatButtonStyle
from arcade.gui.widgets.slider import UISliderStyle
+FOLLOW_DECAY_CONST = 0.3
+GRAVITY = 1.5
+PLAYER_MOVEMENT_SPEED = 10
+PLAYER_JUMP_SPEED = 28
+GRID_PIXEL_SIZE = 70
+
menu_background_color = (30, 30, 47)
log_dir = 'logs'
discord_presence_id = 1443616900096590027
diff --git a/utils/preload.py b/utils/preload.py
index fcd2cf3..0cda6df 100644
--- a/utils/preload.py
+++ b/utils/preload.py
@@ -5,4 +5,20 @@ _module_dir = os.path.dirname(os.path.abspath(__file__))
_assets_dir = os.path.join(os.path.dirname(_module_dir), 'assets')
button_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button.png')))
-button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button_hovered.png')))
\ No newline at end of file
+button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button_hovered.png')))
+
+def animation_from(path_list):
+ return arcade.TextureAnimation([
+ arcade.TextureKeyframe(arcade.load_texture(path))
+ for path in path_list
+ ])
+
+player_walk_animation = animation_from([os.path.join(_assets_dir, 'graphics', 'KenneyNewPlatformerPack', 'character', 'character_green_walk_a.png'), os.path.join(_assets_dir, 'graphics', 'KenneyNewPlatformerPack', 'character', 'character_green_walk_b.png')])
+player_still_animation = animation_from([os.path.join(_assets_dir, 'graphics', 'KenneyNewPlatformerPack', 'character', 'character_green_idle.png')])
+player_jump_animation = animation_from([os.path.join(_assets_dir, 'graphics', 'KenneyNewPlatformerPack', 'character', 'character_green_jump.png')])
+player_duck_animation = animation_from([os.path.join(_assets_dir, 'graphics', 'KenneyNewPlatformerPack', 'character', 'character_green_duck.png')])
+
+background_sound = arcade.Sound(os.path.join(_assets_dir, "sound", "background.mp3"))
+freeze_sound = arcade.Sound(os.path.join(_assets_dir, "sound", "freeze.wav"))
+
+tile_map = arcade.load_tilemap(os.path.join(_assets_dir, "map.tmx"))