Compare commits

...

4 Commits

  1. BIN
      Effects/__pycache__/animated_gif.cpython-311.pyc
  2. BIN
      Effects/__pycache__/order_click.cpython-311.pyc
  3. 10
      Effects/animated_gif.py
  4. 2
      Effects/order_click.py
  5. BIN
      Units/__pycache__/knight.cpython-311.pyc
  6. 103
      Units/knight.py
  7. 129
      main.py
  8. 8
      maze.json
  9. 2
      maze.py

BIN
Effects/__pycache__/animated_gif.cpython-311.pyc

Binary file not shown.

BIN
Effects/__pycache__/order_click.cpython-311.pyc

Binary file not shown.

10
Effects/animated_gif.py

@ -1,4 +1,4 @@
import tkinter as tk
import pyglet
import itertools
class AnimatedGif:
@ -11,12 +11,12 @@ class AnimatedGif:
i = 0
while True:
try:
image = tk.PhotoImage(file=path, format='gif -index %i' %(i))
resized_image = image.subsample(1) # Resize image to half
self.frames.append(resized_image)
image = pyglet.image.load_animation(path)
frame = image.get_texture(i)
self.frames.append(frame)
i += 1
except tk.TclError:
except IndexError:
break
def next_frame(self):

2
Effects/order_click.py

@ -8,7 +8,7 @@ class OrderClick:
def next_frame(self, canvas: Canvas) -> bool:
self.radius -= 5
shift = 30
canvas.create_oval(self.position[0]-self.radius, self.position[1]-self.radius/2+shift, self.position[0]+self.radius, self.position[1]+self.radius/2+shift, fill="", tags="effect", outline=self.color, width=2)
#canvas.create_oval(self.position[0]-self.radius, self.position[1]-self.radius/2+shift, self.position[0]+self.radius, self.position[1]+self.radius/2+shift, fill="", tags="effect", outline=self.color, width=2)
if not self.radius:
return False

BIN
Units/__pycache__/knight.cpython-311.pyc

Binary file not shown.

103
Units/knight.py

@ -1,8 +1,6 @@
import tkinter as tk
import pyglet
import os
import glob
import time
import random
from Effects.animated_gif import AnimatedGif
from Effects.order_click import OrderClick
@ -11,94 +9,57 @@ class Knight:
def __init__(self, engine, position=(0,0)):
self.engine = engine
self.position = position
self.target = position
self.target = (8,5)
self.destination = position
gifs = glob.glob("KnightBasic/**/*.gif", recursive=True)
self.animation = {os.path.basename(gif): AnimatedGif(gif) for gif in gifs}
self.animation = {os.path.basename(gif): pyglet.sprite.Sprite(pyglet.resource.animation(gif)) for gif in gifs}
self.state = "Walk"
self.speed = .05 # This is now the delay between updates in seconds
self.speed = .025 # This is now the delay between updates in seconds
self.partial_move = 0
self.direction = 2
self.direction = 7
self.visited = [self.position]
self.starting_position = (position)
def ai(self):
screen_x, screen_y = self.engine.iso_transform(*self.position)
if self.position != self.target:
if self.position == self.target:
self.visited = [self.target]
self.position = self.target
self.starting_position = self.target
self.destination = self.target
self.state = "Idle"
self.partial_move = 1
else:
self.direction = self.engine.get_direction(self.position,self.destination)
if self.partial_move<1:
screen_x_dest, screen_y_dest = self.engine.iso_transform(*self.destination)
self.partial_move += self.speed
if self.partial_move > 1:
self.partial_move = 1
screen_x += (screen_x_dest - screen_x) * self.partial_move
screen_y += (screen_y_dest - screen_y) * self.partial_move
else:
screen_x, screen_y = self.engine.iso_transform(*self.destination)
neighbors_list = self.engine.find_neighbors(self.destination) # Get the neighbors of the destination cell
# Remove any neighbors that are not walkable
neighbors_list = [cell for cell in neighbors_list if self.engine.battlefield[cell[1]][cell[0]].walkable]
old_distance_from_target = self.engine.get_distance(self.destination,self.target)
old_distance_from_start = self.engine.get_distance(self.destination,self.starting_position)
for cell_visited in self.visited:
if cell_visited in neighbors_list:
neighbors_list.remove(cell_visited)
#self.visited = self.visited[-2:]
self.position = self.destination
self.visited.append(self.position)
for cell in neighbors_list:
self.engine.effects.append(OrderClick(self.engine.iso_transform(*cell),color="lightblue"))
for cell in self.visited:
self.engine.effects.append(OrderClick(self.engine.iso_transform(*cell),color="red"))
if not neighbors_list:
print("No neighbors")
#neighbors_list.append(self.visited)
#self.target = self.position
self.destination = None
self.destination = self.engine.get_closest_neighbor(neighbors_list,self.target)
self.partial_move = 0
else:
self.destination = self.engine.get_closest_neighbor(neighbors_list,self.target)
new_distance_from_target = self.engine.get_distance(self.destination,self.target)
new_distance_from_start = self.engine.get_distance(self.destination,self.starting_position)
if new_distance_from_target >= old_distance_from_target or new_distance_from_start < old_distance_from_start:
print(f"{time.time()} - No progress")
new_neighbors_list = []
for neighbor in neighbors_list:
neighbor_neighbors_list = self.engine.find_neighbors(neighbor)
for neighbor_neighbor in neighbor_neighbors_list:
# consider only the neighbors of the neighbors that are walkable
if not self.engine.battlefield[neighbor_neighbor[1]][neighbor_neighbor[0]].walkable:
if neighbor_neighbor not in self.visited:
# if the neighbor of the neighbor is not walkable and has not been visited, add it to the list of visited cells
new_neighbors_list.append(neighbor)
break
# scegli uhn vicino casualmente come destinaziione
self.destination = new_neighbors_list[random.randint(0,len(new_neighbors_list)-1)]
if self.destination:
self.engine.effects.append(OrderClick(self.engine.iso_transform(*self.destination),color="purple"))
self.partial_move = 0
if self.position != self.target:
self.direction = self.engine.get_direction(self.position,self.destination)
else:
print("No destination")
self.visited = [self.position]
self.destination = self.position
#self.target = self.position
self.engine.effects.append(OrderClick(self.engine.iso_transform(*self.destination),color="brown"))
else:
self.visited = [self.target]
self.position = self.target
self.starting_position = self.target
self.destination = self.target
self.state = "Idle"
self.partial_move = 1
gif = self.animation.get(f'Knight_{self.state}_dir{self.direction}.gif')
return gif, screen_x, screen_y
return gif, screen_x, screen_y
def move_to(self, target):
if self.target == target and self.state == "Walk":
return
self.speed = .05
self.target = target
self.state = "Walk"
def run_to(self, target):
if self.target == target and self.state == "Run":
return
self.speed = .10
self.target = target
self.state = "Run"

129
main.py

@ -1,13 +1,11 @@
import time
import tkinter as tk
import glob
import os
import json
import pyglet
from Units.knight import Knight
from Effects.order_click import OrderClick
from tkinter import Menu
@ -15,40 +13,59 @@ 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 = 132
self.cell_height = 66
self.cell_selected = (0, 0)
self.view_offset_x = 800
self.view_offset_y = 500
self.last_trigger_time = 0
self.min_interval = 0.5 # Minimum interval in seconds
self.effects = []
# Create a window with a specific size and title
self.window = pyglet.window.Window(width=1920, height=1080, caption='Campo di Battaglia RTS Isometrico')
self.batch = pyglet.graphics.Batch()
@self.window.event
def on_draw():
self.window.clear()
self.draw_battlefield()
@self.window.event
def on_mouse_scroll(x, y, scroll_x, scroll_y):
# Adjust the view offset based on the scroll direction
self.view_offset_y += scroll_y * 70 # Adjust the multiplier as needed
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.tiles = {os.path.splitext(os.path.basename(file))[0]: pyglet.image.load(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)
def create_sprite(tile, x, y):
print(x, y)
x,y= self.iso_transform(x, y)
print(x, y)
return pyglet.sprite.Sprite(tile, y=y, x=x)
self.battlefield = [[Cell(walkable = not data[row][column], sprite=create_sprite(tile=self.tiles["landscapeTiles_067"], y=(self.height-row), x=(self.width-column))
if not data[row][column] else create_sprite(tile=self.tiles["landscapeTiles_066"], y=(self.height-row), x=(self.width-column))
) for column in range(self.width)] for row in range(self.height)]
# Crea lo sprite del tile, aggiungilo al batch (e al gruppo, se usato)
# sprite = pyglet.sprite.Sprite(img=tile_image, x=x, y=y, batch=batch)
# tile_sprites.append(sprite)
# 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_right_click)
# self.canvas.bind('<Double-Button-3>', self.on_canvas_double_right_click)
# self.canvas.bind('<Motion>', self.calculate_coordinates)
self.knight = Knight(self, (1,1))
#self.knight = Knight(self, (1,1))
self.draw_battlefield()
def calculate_coordinates(self, event):
@ -128,8 +145,8 @@ class IsometricGame:
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
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):
@ -143,23 +160,18 @@ class IsometricGame:
return abs(((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5)
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")
for y, row in list(enumerate(self.battlefield)):
for x, cell in list(enumerate(row)):
cell.sprite.draw()
#self.canvas.create_image(screen_x, screen_y+45+offset, image=cell.tile, tags="cell")
def draw_units(self):
self.canvas.delete("unit") # Pulisce le unità precedenti prima di ridisegnare
def draw_units(self):
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
gif.x = screen_x - self.cell_width/2
gif.y = screen_y + height*3
gif.draw()
#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
@ -237,8 +249,21 @@ class IsometricGame:
self.battlefield[cell_y][cell_x].walkable ^= True
self.draw_battlefield()
self.draw_units()
def on_canvas_right_click(self, event):
# calculate the clicked cell's coordinates
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.effects.append(OrderClick(self.iso_transform(cell_x, cell_y),color="lightblue"))
if 0 <= cell_x < self.width and 0 <= cell_y < self.height:
self.knight.move_to((cell_x, cell_y))
def on_canvas_double_right_click(self, event):
# calculate the clicked cell's coordinates
cell_x, cell_y = self.inv_iso_transform(event.x, event.y)
self.effects.append(OrderClick(self.iso_transform(cell_x, cell_y),color="darkblue"))
if 0 <= cell_x < self.width and 0 <= cell_y < self.height:
self.knight.run_to((cell_x, cell_y))
def set_tile(self, name, pos):
# Handle option 1 selection
@ -249,37 +274,15 @@ class IsometricGame:
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.starting_position = self.knight.position
self.knight.target = (cell_x,cell_y)
self.knight.state = "Walk"
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
def __init__(self, walkable=False, sprite=None, elevation=0, offset=0):
self.sprite = sprite
self.walkable = walkable
self.elevation = elevation
@ -292,4 +295,4 @@ if __name__ == "__main__":
width = len(data[0])
height = len(data)
game = IsometricGame(width=width, height=height, data=data)
game.run()
pyglet.app.run()

8
maze.json

@ -1 +1,7 @@
[[true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true], [true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, true], [true, true, true, true, false, false, false, true, true, false, false, false, true, false, false, false, true, true, true, false, true], [true, false, false, false, false, false, true, false, false, false, true, false, true, false, true, false, true, false, false, false, true], [true, false, true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, false, true, true, true], [true, false, false, false, true, false, false, false, true, false, true, false, true, false, true, false, true, false, false, false, true], [true, false, true, true, true, false, true, true, true, false, true, false, true, false, true, false, true, true, false, false, true], [true, false, true, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, true, false, true], [true, false, true, false, true, false, true, true, true, false, true, false, false, false, false, false, true, false, true, false, true], [true, false, true, false, true, false, false, false, true, false, true, false, true, false, false, false, false, false, true, false, true], [true, false, true, false, true, true, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true], [true, false, true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false, false, false, true], [true, false, true, true, true, true, true, false, true, false, true, true, true, true, true, false, false, true, true, false, true], [true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, true, false, false, false, true], [true, false, true, false, true, false, true, false, true, true, false, true, true, false, true, false, true, true, true, true, true], [true, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, false, true], [true, false, true, false, true, true, true, true, true, false, false, false, true, false, true, true, true, true, false, false, true], [true, false, true, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, true], [true, false, true, true, true, true, true, false, true, false, true, true, true, true, true, false, false, false, true, false, true], [true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, true], [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true]]
[
[true, true, true, true, true],
[true, false, true, false, true],
[true, false, false, false, true],
[true, false, false, false, true],
[true, true, true, true, true]
]

2
maze.py

@ -99,5 +99,5 @@ class MazeGenerator:
self.window.mainloop()
# Crea e avvia il generatore di labirinti
generator = MazeGenerator(20, 20)
generator = MazeGenerator(5, 5)
generator.run()

Loading…
Cancel
Save