You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
14 KiB

import time
import tkinter as tk
import glob
import os
import json
import Units
from Effects.order_click import OrderClick
from tkinter import Menu
from collections import deque
import Units.hound
import Units.zombie
class IsometricGame:
def __init__(self, width, height, data):
self.width = width
self.height = height
self.view_offset_x = 800
self.view_offset_y = 0
self.cell_width = 134
self.cell_height = 68
self.cell_selected = (0, 0)
self.last_trigger_time = 0
self.min_interval = 0.5 # Minimum interval in seconds
self.effects = []
self.editor_mode = False
self.input_lock = False
self.window = tk.Tk()
files = sorted(glob.glob("Tiles/**/*.png", recursive=True))
self.tiles = {os.path.splitext(os.path.basename(file))[0]: tk.PhotoImage(file=file) for file in files}
# self.battlefield = [[Cell(walkable = True, tile=self.tiles["landscapeTiles_067"] ) for x in range(self.width)] for y in range(self.height)]
# use data to create the battlefield
self.battlefield = [[Cell(walkable = not data[y][x], tile=self.tiles["landscapeTiles_067"]
if not data[y][x] else self.tiles["landscapeTiles_066"]
) for x in range(self.width)] for y in range(self.height)]
self.window.title("Campo di Battaglia RTS Isometrico")
self.canvas = tk.Canvas(self.window, width=1920, height=1080, bg='black')
self.canvas.pack()
self.menu = Menu(self.canvas, tearoff=0)
self.window.bind('<KeyRelease>', self.on_key_press)
self.canvas.bind('<Button-1>', self.on_canvas_click)
self.canvas.bind('<Button-3>', self.on_canvas_rclick)
self.canvas.bind('<Motion>', self.calculate_coordinates)
self.knight = Units.zombie.Unit(self, position=(1, 1))
self.draw_battlefield()
def calculate_coordinates(self, event):
if self.input_lock:
return
# Get the mouse coordinates
mouse_x = event.x
mouse_y = event.y
iso_x, iso_y = self.inv_iso_transform(mouse_x, mouse_y)
self.cell_selected = (iso_x, iso_y)
def get_direction(self, initial_coord, surrounding_coord):
# Calcola la differenza tra le coordinate
delta_x = surrounding_coord[0] - initial_coord[0]
delta_y = surrounding_coord[1] - initial_coord[1]
# Determina la direzione basandosi sulla differenza
if delta_x == -1 and delta_y == 1:
return 2 # Sud-Ovest
elif delta_x == -1 and delta_y == 0:
return 3 # Ovest
elif delta_x == -1 and delta_y == -1:
return 4 # Nord-Ovest
elif delta_x == 0 and delta_y == -1:
return 5 # Nord
elif delta_x == 1 and delta_y == -1:
return 6 # Nord-Est
elif delta_x == 1 and delta_y == 0:
return 7 # Est
elif delta_x == 1 and delta_y == 1:
return 8 # Sud-Est
elif delta_x == 0 and delta_y == 1:
return 1 # Sud
else:
return 1
def find_neighbors(self, coordinates):
"""
Find and return the cells adjacent to the cell at position (coordinates).
Adjacent cells are those directly above, below, left, right,
and all four diagonally adjacent cells.
"""
neighbors = []
x_coord, y_coord = coordinates
# 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, y_coord + delta_y
# Skip the cell itself
if delta_x == 0 and delta_y == 0:
continue
# Check if the new coordinates are within the battlefield
if 0 <= new_x < self.width and 0 <= new_y < self.height:
neighbors.append((new_x, new_y))
return neighbors
def get_closest_neighbor(self, neighbors_list, target_position):
"""
Find and return the neighbor cell in the neighbors_list closest to the target position.
"""
# If there are no neighbors, return None
if not neighbors_list:
return None
# Calculate the distance between the target position and each neighbor
distances = [abs(((neighbor[0] - target_position[0])**2 + (neighbor[1] - target_position[1])**2)**0.5) for neighbor in neighbors_list]
# Find the index of the smallest distance
min_distance_index = distances.index(min(distances))
# Return the neighbor corresponding to the smallest distance
return neighbors_list[min_distance_index]
def iso_transform(self, x, y):
screen_x = (x - y) * self.cell_width / 2 + self.view_offset_x
screen_y = (x + y) * self.cell_height / 2 + self.view_offset_y
return screen_x, screen_y
def inv_iso_transform(self, screen_x, screen_y):
x = ((screen_x - self.view_offset_x) / (self.cell_width / 2) + (screen_y - self.view_offset_y) / (self.cell_height / 2)) / 2
y = ((screen_y - self.view_offset_y) / (self.cell_height / 2) - (screen_x - self.view_offset_x) / (self.cell_width / 2)) / 2
return int(x), int(y)
def get_distance(self, position1, position2):
x1, y1 = position1
x2, y2 = position2
return abs(((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5)
def get_distance_components(self, position1, position2):
x1, y1 = position1
x2, y2 = position2
return abs(x2 - x1), abs(y2 - y1)
#function to check if a cell is near a wall
def near_wall(self, position):
x, y = position
neighbors = self.find_neighbors(position)
for neighbor in neighbors:
if not self.battlefield[neighbor[1]][neighbor[0]].walkable:
return True
def min_steps_to_target(self, start, target):
grid = [[0 for _ in range(self.width)] for _ in range(self.height)]
rows, cols = len(grid), len(grid[0])
dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]
queue = deque([start])
visited = set([start])
steps = 0
while queue:
for _ in range(len(queue)):
x, y = queue.popleft()
if (x, y) == target:
return steps
for i in range(4):
nx, ny = x + dx[i], y + dy[i]
if 0 <= nx < rows and 0 <= ny < cols and (nx, ny) not in visited:
queue.append((nx, ny))
visited.add((nx, ny))
steps += 1
return -1
def draw_battlefield(self):
self.canvas.delete("cell") # Pulisce le celle precedenti prima di ridisegnare
self.canvas.delete("cell-label")
for y, row in enumerate(self.battlefield):
for x, cell in enumerate(row):
screen_x, screen_y = self.iso_transform(x, y)
offset = (99 - cell.tile.height()) / 2
self.canvas.create_image(screen_x, screen_y+45+offset, image=cell.tile, tags="cell")
if self.editor_mode:
self.canvas.create_text(screen_x, screen_y+45, text=str(cell.elevation), tags="cell_label")
self.canvas.create_text(screen_x+10, screen_y+45, text=str(int(cell.walkable)), tags="cell_label", fill="white" if cell.walkable else "red")
self.canvas.create_text(screen_x+10, screen_y+35, text=str(int(cell.tile.height())), tags="cell_label", fill="white" if cell.walkable else "red")
def draw_units(self):
self.canvas.delete("unit") # Pulisce le unità precedenti prima di ridisegnare
gif, screen_x, screen_y = self.knight.ai() # Calcola la posizione e l'animazione del cavaliere
self.canvas.create_image(screen_x, screen_y+35, image=gif.next_frame(), tags="unit") # Disegna il cavaliere
def draw_effects(self):
# Pulisce gli effetti precedenti prima di ridisegnare
self.canvas.delete("effect")
self.canvas.delete("sel-cell")
# Disegna gli effetti
for effect in self.effects:
if not effect.next_frame(self.canvas):
self.effects.remove(effect)
# Disegna il rettangolo di selezione
cell_width = self.cell_width - 8
cell_height = self.cell_height - 4
x, y = self.iso_transform(*self.cell_selected)
def draw_line(self, start, end):
self.canvas.create_line(start[0], start[1], end[0], end[1], fill='red', tags="sel-cell", width=2)
draw_line(self, (x, y), (x+cell_width/2, y+cell_height/2))
draw_line(self, (x+cell_width/2, y+cell_height/2), (x, y+cell_height))
draw_line(self, (x, y+cell_height), (x-cell_width/2, y+cell_height/2))
draw_line(self, (x-cell_width/2, y+cell_height/2), (x, y))
if self.editor_mode:
self.canvas.create_text(55,15, text="EDITOR MODE", tags="effect", fill="blue")
def on_key_press(self, event):
current_time = time.time()
step = 30 # Distanza dello spostamento ad ogni pressione dei tasti
if current_time - self.last_trigger_time >= self.min_interval: # Check if the last trigger time is greater than the minimum interval
if event.keysym == 'Up':
self.view_offset_y += step
elif event.keysym == 'Down':
self.view_offset_y -= step
elif event.keysym == 'Left':
self.view_offset_x += step
elif event.keysym == 'Right':
self.view_offset_x -= step
elif event.keysym == 'q':
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].elevation -= 1
elif event.keysym == 'e':
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].elevation += 1
elif event.keysym == '1':
tiles_list = self.tiles.keys()
self.input_lock = True
for key, tile in enumerate(tiles_list):
self.menu.add_command(label=tile, command=lambda vars=(tile, key) : self.set_tile(*vars))
self.menu.post(event.x_root, event.y_root)
elif event.keysym == 'w': # Se si preme il tasto 'w' si cambia la walkability della cella
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].walkable ^= True
elif event.keysym == 'a': # Se si preme il tasto 'a' si cambia l'offset della cella
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].offset += 9
elif event.keysym == 'd': # Se si preme il tasto 'd' si cambia l'offset della cella
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].offset -= 11
elif event.keysym == '5':
# Handle '5' key press
pass
elif event.keysym == 'Tab':
# Handle tab key press
self.editor_mode ^= True
self.draw_battlefield()
self.draw_units()
self.draw_effects()
self.last_trigger_time = current_time
def on_canvas_click(self, event):
# calculate the clicked cell's coordinates
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.battlefield[cell_y][cell_x].walkable ^= True
self.battlefield[cell_y][cell_x].tile = self.tiles["landscapeTiles_067"] if self.battlefield[cell_y][cell_x].walkable else self.tiles["landscapeTiles_066"]
self.draw_battlefield()
self.draw_units()
def set_tile(self, name, pos):
# Handle option 1 selection
self.input_lock = False
print(f'You selected option {name}')
cell_x, cell_y = self.cell_selected
if 0 <= cell_x < self.width and 0 <= cell_y < self.height:
self.battlefield[cell_y][cell_x].tile = self.tiles[name]
self.draw_battlefield()
def on_canvas_rclick(self, event):
# calculate the clicked cell's coordinates
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
print(f'Cell clicked: ({cell_x}, {cell_y})')
x, y = self.iso_transform(cell_x, cell_y)
self.effects.append(OrderClick((x, y), color="light blue"))
if self.knight.target == (cell_x, cell_y):
return
if 0 <= cell_x < self.width and 0 <= cell_y < self.height:
self.knight.move_to((cell_x,cell_y))
def run(self):
self.draw_battlefield()
self.update()
self.window.mainloop()
def update(self):
#self.draw_battlefield()
self.draw_units()
self.draw_effects()
self.window.after(75, self.update) # Call again after 100 ms
class Cell:
def __init__(self, walkable=False, tile=None, elevation=0, offset=0):
self.tile = tile
self.walkable = walkable
self.elevation = elevation
if __name__ == "__main__":
with open('maze.json', 'r') as file:
data = json.load(file)
# Creare una matrice 10x10 piena di False
room = [[True for _ in range(10)] for _ in range(10)]
# Cambiare i valori interni della matrice in True
for i in range(1, 9):
for j in range(1, 8):
room[i][j] = False
# Creare un'apertura di un'unità verso l'esterno
room[0][4] = True # Cambia questo valore per spostare l'apertura
data =room
# data is a boolean matrix, find dmensions
width = len(data[0])
height = len(data)
game = IsometricGame(width=width, height=height, data=data)
game.run()