Skip to content

Elijah inventory #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions EventDispatcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
BLOCK_CHANGED = "block_changed"

class EventDispatcher:
def __init__(self):
self.listeners = {}

def register_listener(self, event_type, listener):
"""Register a listener for a specific event type."""
if event_type not in self.listeners:
self.listeners[event_type] = []
self.listeners[event_type].append(listener)

def dispatch_event(self, event_type, *args, **kwargs):
"""Trigger all listeners for a specific event type."""
if event_type in self.listeners:
for listener in self.listeners[event_type]:
listener(*args, **kwargs)
Empty file removed MainMenu.py
Empty file.
Binary file added Steve_Hand.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 14 additions & 2 deletions inventory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import block
from EventDispatcher import BLOCK_CHANGED

class Inventory:
def __init__(self, *args, **kwargs):
def __init__(self, dispatcher, *args, **kwargs):
self.hotbar = [block.PORTAL, block.STONE, block.SPRUCE_WOOD_PLANK, block.BIRCH_WOOD_PLANK, block.JUNGLE_WOOD_PLANK, block.ACACIA_WOOD_PLANK, block.DARK_OAK_WOOD_PLANK]
self.index = 0
self.index = 0
self.dispatcher = dispatcher

def set_index(self, index):
"""Set the selected slot index and notify listeners."""
self.index = index
self.dispatcher.dispatch_event(BLOCK_CHANGED)

def get_selected_block(self):
"""Get the block in the currently selected slot."""
self.dispatcher.dispatch_event(BLOCK_CHANGED)
return self.hotbar[self.index]
8 changes: 6 additions & 2 deletions player.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ def __init__(self, model: Model, window, statemachine, position = (80, 10, 80),

self.PLAYER_HEIGHT = 2

self.inventory = inventory.Inventory()
self.model = model
self.window = window
self.inventory = inventory.Inventory(window.dispatcher)
self.state_machine = statemachine
self.window.push_handlers(self)

Expand Down Expand Up @@ -196,6 +196,7 @@ def on_mouse_press(self, x, y, button, modifiers):
if previous:
texture = self.model.world[selectedBlock]
self.inventory.hotbar[self.inventory.index] = texture
self.inventory.get_selected_block()
else:
self.window.set_exclusive_mouse(True)
if self.state_machine.state == GameState.PAUSED:
Expand Down Expand Up @@ -301,7 +302,7 @@ def on_key_press(self, symbol, modifiers):
self.flying = not self.flying
elif symbol in self.num_keys:
index = (symbol - self.num_keys[0]) % len(self.inventory.hotbar)
self.inventory.index = index
self.inventory.set_index(index) # Update the selected slot

if self.state_machine.state == GameState.PLAYING:
if symbol == key.ESCAPE:
Expand All @@ -313,6 +314,9 @@ def on_key_press(self, symbol, modifiers):
self.window.set_exclusive_mouse(True)
self.state_machine.change_state(GameState.PLAYING)
return pyglet.event.EVENT_HANDLED
elif self.state_machine.state == GameState.MAIN_MENU:
if symbol == key.ESCAPE:
return pyglet.event.EVENT_HANDLED

def on_key_release(self, symbol, modifiers):
""" Called when the player releases a key. See pyglet docs for key
Expand Down
124 changes: 123 additions & 1 deletion window.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
import model
import player
import random
import block
from states import GameState, StateMachine
from EventDispatcher import EventDispatcher, BLOCK_CHANGED

#from collections import deque
from pyglet.gl import * # noqa: F403
from pyglet import image
from pyglet import sprite


class Window(pyglet.window.Window):
Expand Down Expand Up @@ -37,9 +41,24 @@ def __init__(self, *args, **kwargs):

# Instance of the model that handles the world.
self.model = model.Model()

# Load the block texture atlas
self.block_texture = image.load('Textures.png')
self.block_texture_atlas = self.block_texture.get_texture()

glEnable(self.block_texture_atlas.target) # typically target is GL_TEXTURE_2D
glBindTexture(self.block_texture_atlas.target, self.block_texture_atlas.id)

# Initialize the inventory bar

self.dispatcher = EventDispatcher()

self.dispatcher.register_listener(BLOCK_CHANGED, self.on_block_changed)

# Instance of the player that interacts with the world.
self.player = player.Player(self.model, self, self.state_machine)

self.inventory_bar = self.create_inventory_bar()

# Which sector the player is currently in.
self.sector = None
Expand Down Expand Up @@ -152,6 +171,8 @@ def on_draw(self):
self.set_2d()
self.draw_label()
self.draw_reticle()
self.inventory_bar[0].draw() # Draw the inventory bar batch
self.draw_bottom_right_image("Steve_Hand.png").draw()
# Draw the background image first
if self.state_machine.state == GameState.MAIN_MENU:
self.background_sprite.draw()
Expand Down Expand Up @@ -414,9 +435,110 @@ def create_main_menu(self):
# Add buttons to the GUI widgets list
self.gui_widgets.extend([self.quit_button, self.play_button])

def create_inventory_bar(self):
"""Create the inventory bar with only block textures."""
slot_size = 40
slot_spacing = 5
num_slots = len(self.player.inventory.hotbar)

total_width = num_slots * slot_size + (num_slots - 1) * slot_spacing
start_x = (self.width - total_width) // 2
start_y = 20

inventory_batch = pyglet.graphics.Batch()

# Create groups for z-order control
background_group = pyglet.graphics.OrderedGroup(0)
foreground_group = pyglet.graphics.OrderedGroup(1)

# Highlight the selected slot (background layer)
selected_slot_index = self.player.inventory.index
selected_slot_border = pyglet.shapes.Rectangle(
x=start_x + selected_slot_index * (slot_size + slot_spacing) - 2,
y=start_y - 2,
width=slot_size + 4,
height=slot_size + 4,
color=(255, 223, 64),
batch=inventory_batch,
group=background_group
)
selected_slot_border.opacity = 180 # Softer effect

# Slots and their corresponding textures
slots = []
for i in range(num_slots):
slot_x = start_x + i * (slot_size + slot_spacing)

# Block texture
block_texture = self.player.inventory.hotbar[i]
if block_texture != block.NONE:
reversed_coords = self.reverse_tex_coords_list(block_texture)
pixel_coords = self.get_texture_pixel_position(reversed_coords["side"][0][0], reversed_coords["side"][0][1])
# Get the correct texture region for the block
texture_region = self.block_texture_atlas.get_region(
pixel_coords[0],
pixel_coords[1],
16, 16
)
texture_sprite = sprite.Sprite(
img=texture_region,
x=slot_x + 4, y=start_y + 4,
batch=inventory_batch,
group=foreground_group # Textures drawn in front
)
texture_sprite.scale = (slot_size - 8) / 16
slots.append(texture_sprite)

return inventory_batch, slots, selected_slot_border

def draw_bottom_right_image(self, image_path):
texture_image = pyglet.image.load(image_path)

image_width = texture_image.width
image_height = texture_image.height
x_position = self.width - image_width
y_position = 0

# Create and draw the sprite
texture_sprite = sprite.Sprite(
img=texture_image,
x=x_position,
y=y_position
)
return texture_sprite

def play_button_pressed(self):
print("Resume button pressed")
self.state_machine.change_state(GameState.PLAYING)

def quit_button_pressed(self):
pyglet.app.exit()
pyglet.app.exit()

def on_block_changed(self):
"""Update the inventory bar when the inventory changes."""
self.inventory_bar = self.create_inventory_bar()

def reverse_tex_coord(self, dx, dy, w=32, h=16):
""" Reverse the texture coordinates back to (x, y). """
width = 1.0 / w
height = 1.0 / h
x = int(dx / width)
y = int(dy / height)
return x, y

def reverse_tex_coords_list(self, coord_list, w=32, h=16):
""" Reverse a full list of texture coordinates back to their original (x, y) pairs for a 3D block model. """
result = {
"top": [],
"bottom": [],
"side": [] # Only one side entry since it's repeated
}
result["top"].append(self.reverse_tex_coord(coord_list[0], coord_list[1], w, h))
result["bottom"].append(self.reverse_tex_coord(coord_list[8], coord_list[9], w, h))
result["side"].append(self.reverse_tex_coord(coord_list[16], coord_list[17], w, h))
return result

def get_texture_pixel_position(self, column, row, texture_size=16):
x = column * texture_size
y = row * texture_size
return (x, y)