Enhance marine unit functionality: update visibility logic, improve movement handling, and refactor ray casting for better performance and clarity.

This commit is contained in:
Matteo Benedetto
2025-08-18 17:58:13 +02:00
parent 17f895fa08
commit ce74da63ba
5 changed files with 239 additions and 30 deletions
+85 -23
View File
@@ -11,7 +11,8 @@ class Marine(Entity):
def update(self):
self.centered_position = (self.iso_x, self.iso_y)
self.cast_rays_to_distance(6)
# Aggiorna il campo visivo dell'unità (fog of war)
self.cast_rays_to_distance(7)
self.move()
super().update()
@@ -40,8 +41,8 @@ class Marine(Entity):
# Controlla se l'unità èha raggiunto la cella di destinazione
if self.target_cell != (self.x, self.y):
# Contolla che la cella target non sia occupata da una unità che abbia quella cella come target
if self.engine.entities_positions.get(self.target_cell):
if self.engine.entities_positions.get(self.target_cell).target_cell == self.target_cell and self.engine.entities_positions.get(self.target_cell) != self:
if self.game.entities_positions.get(self.target_cell):
if self.game.entities_positions.get(self.target_cell).target_cell == self.target_cell and self.game.entities_positions.get(self.target_cell) != self:
#calcola un nuovo target
self.target_cell = self.graphics.get_next_cell(self.target_cell, self.position, ignore_units=True)
if not self.target_cell:
@@ -58,7 +59,7 @@ class Marine(Entity):
self.next_cell = self.graphics.get_next_cell(self.next_cell, self.target_cell)
# Se l'algoritmo ha efettivamente trovato una cella, occupa la posizione
if self.next_cell:
self.engine.entities_positions[self.next_cell] = self
self.game.entities_positions[self.next_cell] = self
# Se la cella di destinazione è occupata da un'altra entità, fermati
else:
self.action = "idle"
@@ -115,23 +116,84 @@ class Marine(Entity):
self.graphics.play_sound(f"marine/tmayes0{random.randint(0, 3)}.wav")
self.game.cmd_sound_effects = True
def cast_rays_to_distance(self, distance):
# Cast rays to check for visibility
done_cells = {}
for angle in range(0, 360, 20):
for i in range(distance, 0, -1):
ray_x = int(self.centered_position[0] + (distance -i) * int(self.engine.graphics.cell_size/3) * math.sin(math.radians(angle)))
ray_y = int(self.centered_position[1] - (distance - i)* int(self.engine.graphics.cell_size/6) * math.cos(math.radians(angle)))
v_x, v_y = self.graphics.inv_iso_transform(ray_x, ray_y)
if v_x>= 0 and v_x < len(self.engine.map[0]) and v_y >= 0 and v_y < len(self.engine.map):
if (v_x, v_y) not in done_cells.keys():
done_cells.update({(v_x, v_y): self.game.map_shadow[v_y][v_x]})
self.engine.map[v_y][v_x]["visited"] = True
self.game.map_shadow[v_y][v_x] = 0
if i == 1:
def cast_rays_to_distance(self, view_distance):
"""
Rivela tutte le celle nel raggio di vista dell'unità usando ray casting.
Le celle vengono illuminate indipendentemente dagli ostacoli,
ma quelle più lontane hanno maggiore ombreggiatura.
"""
# Pre-calcolo dei valori trigonometrici per ottimizzazione
if not hasattr(self, '_precomputed_angles'):
self._precompute_ray_angles()
revealed_cells = {}
# Lancia raggi in 18 direzioni (ogni 20 gradi)
for angle_idx, (sin_val, cos_val) in enumerate(self._ray_directions):
if angle_idx == 0:
self._cast_visibility_ray(angle_idx, sin_val, cos_val, view_distance+1, revealed_cells)
else:
self._cast_visibility_ray(angle_idx, sin_val, cos_val, view_distance, revealed_cells)
self.game.map_shadow[v_y][v_x] = max(done_cells.get((v_x, v_y), 0)-0.5, 0)
print(done_cells.get((v_x, v_y), 0))
#self.graphics.draw_line((self.centered_position[0], self.centered_position[1], ray_x, ray_y), color=(0, 255, 0, 255))
continue
def _precompute_ray_angles(self):
"""Pre-calcola i valori sin/cos per evitare calcoli ripetuti ogni frame"""
self._ray_directions = []
for angle in range(0, 360, 20):
radians = math.radians(angle)
self._ray_directions.append((math.sin(radians), math.cos(radians)))
self._precomputed_angles = True
def _cast_visibility_ray(self, angle_idx, sin_val, cos_val, max_distance, revealed_cells):
"""
Lancia un singolo raggio di visibilità dalla posizione dell'unità.
Rivela tutte le celle lungo il percorso, applicando ombreggiatura crescente con la distanza.
"""
cell_size_x = int(self.engine.graphics.cell_size/3)
cell_size_y = int(self.engine.graphics.cell_size/6)
# Calcola le posizioni lungo il raggio partendo dalla distanza massima verso il centro
for step in range(max_distance, 0, -1):
current_distance = max_distance - step
# Calcola la posizione del punto sul raggio
ray_x = int(self.centered_position[0] + current_distance * cell_size_x * sin_val)
ray_y = int(self.centered_position[1] - current_distance * cell_size_y * cos_val)
# Converte le coordinate schermo in coordinate griglia
grid_x, grid_y = self.graphics.inv_iso_transform(ray_x, ray_y)
# Verifica che le coordinate siano valide
if self._is_valid_grid_position(grid_x, grid_y):
self._reveal_cell(grid_x, grid_y, step, revealed_cells)
# Disegna il raggio solo per il punto più distante (visualizzazione debug)
# if step == 1:
# self.graphics.draw_line(
# (self.centered_position[0], self.centered_position[1], ray_x, ray_y),
# color=(0, 255, 0, 255)
# )
def _is_valid_grid_position(self, grid_x, grid_y):
"""Controlla se le coordinate della griglia sono valide"""
map_width = len(self.engine.map[0])
map_height = len(self.engine.map)
return 0 <= grid_x < map_width and 0 <= grid_y < map_height
def _reveal_cell(self, grid_x, grid_y, distance_step, revealed_cells):
"""
Rivela una singola cella della mappa e applica l'ombreggiatura appropriata.
Le celle più vicine (distance_step == 1) hanno ombra ridotta.
"""
cell_key = (grid_x, grid_y)
# Salva il valore originale dell'ombra solo se non già processata
if cell_key not in revealed_cells:
revealed_cells[cell_key] = self.game.map_shadow[grid_y][grid_x]
# Marca la cella come visitata e rimuovi l'ombra base
self.engine.map[grid_y][grid_x]["visited"] = True
self.game.map_shadow[grid_y][grid_x] = 0
# Applica ombreggiatura speciale per le celle ai bordi del campo visivo
if distance_step == 1:
original_shadow = revealed_cells.get(cell_key, 0)
self.game.map_shadow[int(grid_y)][int(grid_x)] = max(original_shadow - 0.5, 0)