Browse Source

Implement marine unit visibility and movement logic; add map loading from JSON

master
Matteo Benedetto 7 months ago
parent
commit
20bb62ee97
  1. 42
      Entities/Units/marine.py
  2. 15
      Entities/entity.py
  3. 10
      assets/maps/map.json
  4. 6
      conf/keybinding_paused.json
  5. 6
      conf/keybinding_start_menu.json
  6. 7
      conf/keymap_game.json
  7. 58
      engine_demo.py
  8. 6
      enne2engine/controls.py
  9. 46
      enne2engine/isogeometry.py
  10. 43
      enne2engine/sdl2_wrapper.py
  11. 132
      sdl2_wrapper.py

42
Entities/Units/marine.py

@ -3,23 +3,45 @@ from Entities.entity import Entity
class Marine(Entity):
next_cell = (1,1)
target_cell = (8,7)
movement = 0
view = 3
def update(self):
self.move()
super().update()
def set_visibility(self):
# Set visibility based on the distance to the cursor
distance = self.graphics.get_distance((self.x, self.y), self.engine.cursor_pos)
if distance < self.view:
self.graphics.set_opacity(self.frame, 1.0)
else:
self.graphics.set_opacity(self.frame, 0.5)
def select_unit(self):
self.selected = True
# Play a random voice response when selected
sound_file = f"marine/tmawht0{random.randint(0, 4)}.wav"
sound_file = f"marine/tmawht0{random.randint(0, 3)}.wav"
print(f"Playing sound: {sound_file}")
self.graphics.play_sound(sound_file)
def move(self):
if (self.x, self.y) != self.next_cell:
self.iso_x, self.iso_y = self.graphics.iso_transform(self.x, self.y)
self.position = (self.x, self.y)
if self.target_cell != (self.x, self.y) and self.selected:
target_iso_x, target_iso_y = self.graphics.iso_transform(self.target_cell[0], self.target_cell[1])
self.graphics.draw_square(target_iso_x, target_iso_y, color=(255, 0, 0, 255), margin=6)
if self.position != self.target_cell:
if self.position == self.next_cell:
self.next_cell = self.graphics.get_next_cell(self.next_cell, self.target_cell)
self.engine.entities_positions[self.next_cell] = self
if self.engine.entities_positions.get(self.target_cell) is not None:
if self.engine.entities_positions.get(self.target_cell) != self:
self.target_cell = self.graphics.find_neighbors(self.target_cell)[0] or self.position
return
# Set walking animation and direction
self.action = "walk"
self.direction = self.graphics.get_direction((self.x, self.y), self.next_cell)
@ -29,15 +51,21 @@ class Marine(Entity):
target_x, target_y = self.graphics.iso_transform(self.next_cell[0], self.next_cell[1])
# Increment movement counter
self.movement += 0.01
self.movement += 0.1
# Calculate how far we've moved (0.0 to 1.0)
move_progress = min(self.movement, 1.0)
# Calculate new position based on progress between cells
self.iso_x = self.iso_x + (target_x - self.iso_x) * move_progress
self.iso_y = self.iso_y + (target_y - self.iso_y) * move_progress
print(f"Moving to {self.iso_x}, {self.iso_y} with progress {move_progress}")
if self.movement >= 1.0:
# Reset movement and set to idle
self.movement = 0
self.iso_x, self.iso_y = self.graphics.iso_transform(self.x, self.y)
self.x, self.y = self.next_cell
self.iso_x, self.iso_y = self.graphics.iso_transform(self.x, self.y)
else:
self.action = "idle"
def set_target_cell(self, target_cell):
self.target_cell = target_cell
self.graphics.play_sound(f"marine/tmayes0{random.randint(0, 3)}.wav")

15
Entities/entity.py

@ -5,6 +5,7 @@ class Entity:
self.graphics = engine.graphics
self.x = x
self.y = y
self.next_cell = (x, y)
self.iso_x, self.iso_y = self.graphics.iso_transform(self.x, self.y)
self.action = action
self.direction = direction
@ -15,15 +16,19 @@ class Entity:
self.movement = 0
def update(self):
x, y = self.graphics.iso_transform(self.x, self.y)
occlusion = self.graphics.get_distance((self.x, self.y), self.engine.cursor_pos) / 4
# Set color based on selection status
color = (255, 255, 0, 255) if self.selected else (0, 255, 0, 255)
self.graphics.draw_square(self.x, self.y, color=color, margin=4)
color = (0, 255, 0, 255)
if self.selected:
self.graphics.draw_square(self.iso_x, self.iso_y, color=color, margin=4)
# Draw target indicator if target is set
occlusion = self.graphics.map_shadow[self.y][self.x]
if occlusion >= 0.8:
return
self.frame = self.graphics.render_sprite(f"{self.asset}_{self.action}_dir{self.direction}", self.iso_x, self.iso_y, self.frame, occlusion)

10
assets/maps/map.json

@ -0,0 +1,10 @@
[
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": true, "tile": "landscapeTiles_066" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": true, "tile": "landscapeTiles_066" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": true, "tile": "landscapeTiles_066" }],
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": false, "tile": "landscapeTiles_001" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }],
[{ "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": false, "tile": "landscapeTiles_067" }, { "wall": true, "tile": "landscapeTiles_066" }]
]

6
conf/keybinding_paused.json

@ -0,0 +1,6 @@
{
"reset_game": ["Return", 13],
"pause": ["P", 16],
"quit": ["Q", 12]
}

6
conf/keybinding_start_menu.json

@ -0,0 +1,6 @@
{
"start_game": ["Return", 13],
"toggle_full_screen": ["F"],
"quit": ["Q", 12]
}

7
conf/keymap_game.json

@ -0,0 +1,7 @@
{
"keydown:up": "scroll_up",
"keydown:down": "scroll_down",
"keydown:left": "scroll_left",
"keydown:right": "scroll_right"
}

58
engine_demo.py

@ -3,26 +3,24 @@ from enne2engine.pyglet_wrapper import PygletWrapper
from enne2engine.controls import UserControls
import sys
import os
import json
from Entities.Units.marine import Marine
class GameEngine(UserControls):
def __init__(self):
super().__init__()
if "--pyglet" in sys.argv:
self.graphics = PygletWrapper()
else:
self.graphics = SDL2Wrapper(self)
self.map = [
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': True, 'tile': "landscapeTiles_066" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': True, 'tile': "landscapeTiles_066" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': True, 'tile': "landscapeTiles_066" }],
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': False, 'tile': "landscapeTiles_001" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }],
[{ 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': False, 'tile': "landscapeTiles_067" }, { 'wall': True, 'tile': "landscapeTiles_066" }]
]
self.graphics = SDL2Wrapper(self)
# Load map from JSON file
try:
with open("assets/maps/map.json", "r") as map_file:
self.map = json.load(map_file)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading map file: {e}")
print("Exiting program.")
sys.exit(0)
self.frame_time = 0
self.cursor_pos = (0, 0)
@ -33,32 +31,48 @@ class GameEngine(UserControls):
def run(self):
running = True
# Set a custom scale if needed
self.graphics.set_scaling_factor(0.5) # 50% scale
self.graphics.set_scaling_factor(0.50) # 50% scale
self.entities.append(Marine("knight", 0, 0, "idle", 1, 1, self))
self.graphics.create_background(self.map, "tiles")
self.entities.append(Marine("knight", 5, 0, "idle", 1, 1, self))
while running:
# Start the frame timer
perf_counter = self.graphics.get_perf_counter()
# Initialize the map shadow and entities positions
self.map_shadow = [ [0 for _ in range(len(self.map[0]))] for _ in range(len(self.map)) ]
self.entities_positions.clear()
for entity in self.entities:
self.entities_positions[entity.next_cell] = entity
self.entities_positions[(entity.x, entity.y)] = entity
self.graphics.create_background(self.map, "tiles")
# Create the map background texture with tiles
self.graphics.create_background(self.map, "tiles", self.map_shadow)
# Handle events
event = self.graphics.handle_events()
if event:
#print(f"Event detected: {event}")
if event.startswith("MOUSEDOWN"):
pass
if event.startswith("MOUSEDOWN"):
print(f"Mouse down event: {event}")
print(f"Button pressed: {event[-1]}")
if event[-1] == "3":
print("Right mouse button pressed")
for entity in self.entities:
if entity.selected:
entity.set_target_cell(self.cursor_pos)
elif event.startswith("SELECTION"):
# Handle multiple unit selection
self.select_units_in_area(event)
elif event.startswith("MOUSEUP"):
self.select_entity_at_cursor()
if event[-1] == "1":
self.select_entity_at_cursor()
self.handle_events("keymap_game", event)
running = False if event == "QUIT" else True
self.graphics.clear_screen()
self.graphics.render_background()
#self.graphics.render_tile(spritesheet_name="tiles", tile="landscapeTiles_064", x=0, y=0)
#self.graphics.draw_square(0,0)
self.cursor_pos = self.graphics.draw_cursor()
# Draw the selection rectangle if selecting
if self.graphics.is_mouse_button_pressed(1):
self.graphics.draw_selection_rectangle()

6
enne2engine/controls.py

@ -23,16 +23,12 @@ class UserControls:
def scroll_up(self):
self.graphics.view_offset_y += 10
self.graphics.create_background(self.map, "tiles")
def scroll_down(self):
self.graphics.view_offset_y -= 10
self.graphics.create_background(self.map, "tiles")
def scroll_left(self):
self.graphics.view_offset_x += 10
self.graphics.create_background(self.map, "tiles")
def scroll_right(self):
self.graphics.view_offset_x -= 10
self.graphics.create_background(self.map, "tiles")
self.graphics.view_offset_x -= 10

46
enne2engine/isogeometry.py

@ -50,13 +50,44 @@ class IsometricGeometry:
for delta_x in [-1, 0, 1]:
for delta_y in [-1, 0, 1]:
new_x, new_y = x_coord + delta_x, y_coord + delta_y
# Check if the new coordinates are within the battlefield
if 0 <= new_x < self.width and 0 <= new_y < self.height:
# Skip the cell itself
if delta_x == 0 and delta_y == 0:
continue
# Skip walls
if self.engine.map[new_y][new_x]["wall"]:
continue
if self.engine.entities_positions.get((new_x, new_y)) is not None:
continue
neighbors.append((new_x, new_y))
return neighbors
def find_neighbors_at_distance(self, coordinates, distance):
"""
Find and return the cells at a specific distance from the cell at position (coordinates).
"""
neighbors = []
x_coord, y_coord = coordinates
# Skip the cell itself
if delta_x == 0 and delta_y == 0:
continue
# Check all eight possible directions
for delta_x in [-1, 0, 1]:
for delta_y in [-1, 0, 1]:
new_x, new_y = x_coord + delta_x * distance, y_coord + delta_y * distance
# Check if the new coordinates are within the battlefield
if 0 <= new_x < self.width and 0 <= new_y < self.height:
# Skip the cell itself
if delta_x == 0 and delta_y == 0:
continue
# Skip walls
if self.engine.map[new_y][new_x]["wall"]:
continue
if self.engine.entities_positions.get((new_x, new_y)) is not None:
continue
neighbors.append((new_x, new_y))
return neighbors
@ -131,4 +162,11 @@ class IsometricGeometry:
visited.add((nx, ny))
steps += 1
return -1
return -1
def get_next_cell(self, start, target):
# Get the neighbors of the start cell
neighbors = self.find_neighbors(start)
# Get the closest neighbor to the target cell
closest_neighbor = self.get_closest_neighbor(neighbors, target)
return closest_neighbor

43
enne2engine/sdl2_wrapper.py

@ -25,11 +25,11 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
self.base_cell_size = 132 # Original/base cell size
self.scaling_factor = 0.5 # Default scaling factor (can be changed)
self.cell_size = int(self.base_cell_size * self.scaling_factor) # Effective cell size
self.view_offset_x = 0
self.view_offset_x = 400
self.view_offset_y = 0
self.surface_width = 0
self.surface_height = 0
self.window = sdl2.ext.Window("My Game", size=self.view_size)
self.window = sdl2.ext.Window("Enne2EngineDEMO", size=self.view_size)
self.window.show() # Mostra la finestra
self.renderer = sdl2.ext.Renderer(self.window, flags=sdl2.SDL_RENDERER_ACCELERATED)
self.tile_managers = {}
@ -74,16 +74,16 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
elif event.type == sdl2.SDL_MOUSEBUTTONDOWN:
x, y = event.button.x, event.button.y
# Left mouse button (button 1)
self.selection_start = (x, y)
self.selection_current = (x, y)
if event.button.button == 1:
self.selection_start = (x, y)
self.selection_current = (x, y)
self.selecting = True
return f"MOUSEDOWN:{x}:{y}"
return f"MOUSEDOWN:{x}:{y}:{event.button.button}"
elif event.type == sdl2.SDL_MOUSEBUTTONUP:
x, y = event.button.x, event.button.y
# Left mouse button (button 1)
if event.button.button == 1:
result = f"MOUSEUP:{x}:{y}"
result = f"MOUSEUP:{x}:{y}:{event.button.button}"
# Return the selection area if it's large enough and we were selecting
if self.selecting and self.selection_start and self.get_selection_size() > 5:
result = f"SELECTION:{self.selection_start[0]}:{self.selection_start[1]}:{x}:{y}"
@ -146,29 +146,19 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
sdl2.SDL_SetRenderTarget(self.renderer.sdlrenderer, None)
return (frame + 1) % total_frames
def create_background(self, map, spritesheet_name):
def create_background(self, map, spritesheet_name, map_shadow):
# Set page as render target and initialize it
sdl2.SDL_SetRenderTarget(self.renderer.sdlrenderer, self.tiles_texture)
sdl2.SDL_SetRenderDrawColor(self.renderer.sdlrenderer, 0, 0, 0, 255) # Green background
sdl2.SDL_RenderClear(self.renderer.sdlrenderer)
self.height = len(map)
self.width = len(map[0])
self.map_shadow = map_shadow
tilesheet_texture = self.tile_managers[spritesheet_name].get_tilesheet_texture()
def get_shadow(x, y):
if (x, y) == self.engine.cursor_pos:
return 0
distance = self.get_distance((x, y), self.engine.cursor_pos)
if distance <2:
self.engine.map[y][x]['visited'] = True
return 0.2
elif distance < 3:
self.engine.map[y][x]['visited'] = True
return 0.5
else:
if self.engine.map[y][x].get('visited', False):
return 0.8
else:
return 1
return min(self.map_shadow[y][x], 1)
def blit_tile(tile, x, y):
tile_rect = self.tile_managers[spritesheet_name].get_tile_rect(tile)
@ -236,9 +226,8 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
self.renderer.draw_line(points=[(iso_x - self.cell_size//2, iso_y + self.cell_size//4), (iso_x, iso_y)], color=(255, 0, 0, 255))
return c_x, c_y
def draw_square(self, x, y, color=(0, 255, 0, 255), margin=6):
def draw_square(self, iso_x, iso_y, color=(0, 255, 0, 255), margin=6):
sdl2.SDL_SetRenderTarget(self.renderer.sdlrenderer, self.sprite_texture)
iso_x, iso_y = self.iso_transform(x, y)
# Apply margin to reduce the size of the square
adjusted_size = self.cell_size - margin*2
@ -304,9 +293,6 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
"""
self.scaling_factor = factor
self.cell_size = int(self.base_cell_size * self.scaling_factor)
# Regenerate background if needed
if hasattr(self.engine, 'map'):
self.create_background(self.engine.map, "tiles")
def play_sound(self, sound_file):
"""
@ -388,4 +374,7 @@ class SDL2Wrapper(IsometricGeometry, SDL2Gui):
# Check if the requested button is pressed
if button in button_masks:
return bool(button_state & button_masks[button])
return False
return False
def set_opacity(self, x, y, opacity):
self.engine.map_shadow[y][x] = max(self.engine.map_shadow[y][x], opacity)

132
sdl2_wrapper.py

@ -0,0 +1,132 @@
from enne2engine.sdl2_wrapper import SDL2Wrapper
from enne2engine.pyglet_wrapper import PygletWrapper
from enne2engine.controls import UserControls
import sys
import os
import json
from Entities.Units.marine import Marine
class GameEngine(UserControls):
def __init__(self):
super().__init__()
self.graphics = SDL2Wrapper(self)
# Load map from JSON file
try:
with open("assets/maps/map.json", "r") as map_file:
self.map = json.load(map_file)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading map file: {e}")
print("Exiting program.")
sys.exit(0)
self.frame_time = 0
self.cursor_pos = (0, 0)
self.load_assets()
self.entities = []
self.entities_positions = {}
def run(self):
running = True
# Set a custom scale if needed
self.graphics.set_scaling_factor(0.75) # 50% scale
self.entities.append(Marine("knight", 0, 0, "idle", 1, 1, self))
while running:
# Start the frame timer
perf_counter = self.graphics.get_perf_counter()
# Initialize the map shadow and entities positions
self.map_shadow = [ [0 for _ in range(len(self.map[0]))] for _ in range(len(self.map)) ]
self.entities_positions.clear()
for entity in self.entities:
self.entities_positions[(entity.x, entity.y)] = entity
# Create the map background texture with tiles
self.graphics.create_background(self.map, "tiles", self.map_shadow)
# Handle events
event = self.graphics.handle_events()
if event:
#print(f"Event detected: {event}")
if event.startswith("MOUSEDOWN"):
pass
elif event.startswith("SELECTION"):
# Handle multiple unit selection
self.select_units_in_area(event)
elif event.startswith("MOUSEUP"):
self.select_entity_at_cursor()
self.handle_events("keymap_game", event)
running = False if event == "QUIT" else True
self.graphics.clear_screen()
self.graphics.render_background()
self.cursor_pos = self.graphics.draw_cursor()
# Draw the selection rectangle if selecting
if self.graphics.is_mouse_button_pressed(1):
self.graphics.draw_selection_rectangle()
for entity in self.entities:
entity.update()
self.graphics.render_sprites()
self.graphics.update_status(f"Frame time: {round(self.frame_time)}ms - FPS: {round(1000/self.frame_time if self.frame_time != 0 else 1)}")
self.graphics.present_renderer()
self.frame_time = self.graphics.get_frame_time(perf_counter)
self.graphics.delay_frame(self.frame_time,50)
self.graphics.quit()
def set_cursor(self, x, y):
self.graphics.cursor = (x, y)
def load_assets(self):
self.graphics.load_tilesheet("tiles", "assets/tiles/landscapeTiles_sheet.png")
for dir in os.listdir("assets/KnightBasic"):
for file in os.listdir(f"assets/KnightBasic/{dir}"):
if file.endswith(".json"):
self.graphics.load_spritesheet(file[:-5].lower(), f"assets/KnightBasic/{dir}/{file}")
def select_entity_at_cursor(self):
cursor_x, cursor_y = self.cursor_pos
print(f"Cursor position: {cursor_x}, {cursor_y}")
# First deselect all entities
for entity in self.entities:
entity.selected = False
# Then select the entity at cursor position, if any
entity = self.entities_positions.get((cursor_x, cursor_y))
if entity:
entity.select_unit()
print(f"Selected entity at cursor: {entity.asset} at position {entity.x}, {entity.y}")
else:
print("No entity selected at cursor position.")
def select_units_in_area(self, selection_event):
"""Select all units within the specified selection area."""
# Parse selection coordinates
_, start_x, start_y, end_x, end_y = selection_event.split(":")
start_x, start_y, end_x, end_y = int(start_x), int(start_y), int(end_x), int(end_y)
# Calculate selection rectangle in screen coordinates
min_x = min(start_x, end_x)
max_x = max(start_x, end_x)
min_y = min(start_y, end_y)
max_y = max(start_y, end_y)
# First deselect all entities
for entity in self.entities:
entity.selected = False
# Select entities within the rectangle
for entity in self.entities:
# Convert entity position to screen coordinates
screen_x, screen_y = self.graphics.iso_transform(entity.x, entity.y)
# Check if entity is within selection rectangle
if min_x <= screen_x <= max_x and min_y <= screen_y <= max_y:
entity.select_unit()
print(f"Selected entity in area: {entity.asset} at position {entity.x}, {entity.y}")
if __name__ == "__main__":
engine = GameEngine()
engine.run()
Loading…
Cancel
Save