Browse Source

Supprimer 'dev_edit.py'

master
nfx 1 month ago
parent
commit
bb493f6de4
  1. 274
      dev_edit.py

274
dev_edit.py

@ -1,274 +0,0 @@
"""
LEVEL EDITOR(prototype)
The file that allows to create and edit levels
THIS PROGRAM IS DEPRECATED, USE LVL_EDIT.PY TO EDIT LEVELS
"""
import pyxel
import json
import shutil
CELL_SIZE = 20
GRID_X = 11
GRID_Y = 6
WIN_X = CELL_SIZE*GRID_X
WIN_Y = CELL_SIZE*GRID_Y
def clamp(n: int, a: int, b: int):
"""
:param n: The number to be clamped
:param a: The minimum limit
:param b: The maximum limit
:return: The clamped number
Returns the provided number n clamped between a and b
"""
if n < a:
return a
if n > b:
return b
return n
def get_file_content(lvl: int) -> list:
"""
:param lvl: (int) The id of the file to read
:return: (list) The level content of the file
Reads a level file content and returns its data
"""
file = open(f"lvl/{lvl}.json", "r", encoding="utf-8")
decoder = json.JSONDecoder()
content = decoder.decode(file.read())
file.close()
return content
def can_load(lvl: int) -> bool:
"""
:param lvl: (int) The id of the file to check for
:return: Returns if the level file exists and can be loaded
"""
try:
file = get_file_content(lvl)
return len(file) == GRID_Y
except FileNotFoundError:
return False
class LevelManager:
def __init__(self):
self.level = 0 # the id of the currently loaded stage
self.cache = [] # the current stage state is stored there
self.tileTypes = { # helps with tile identifiers
"empty": 0,
"wall": 1,
"player": 3,
"exit": 2,
"switch_blue": 4,
"s_wall_blue": 5
}
def load(self, lvl: int):
"""
:param lvl: (int) the level id
Reloads the game using the specified level
"""
self.level = lvl
self.cache = get_file_content(lvl)
def save(self, lvl: int):
"""
:param lvl: (int) the level id
Saves the cache under the specified level id
"""
file = open(f"lvl/{lvl}.json", "w", encoding="utf-8")
encoder = json.JSONEncoder()
file.write(encoder.encode(self.cache))
file.close()
def update_tile(self, position: tuple[int, int], val: int):
"""
:param position: (tuple) The position of the tile to modify
:param val: (int) The new value of the tile
Updates the specified tile from the cache to the specified value
"""
self.cache[position[1]][position[0]] = val
def get_tile(self, position: tuple[int, int]) -> int:
"""
:param position: (tuple) the position of the requested tile
:return: (int) the value of the tile
Fetches the current value of the specified tile or -1 if out of range
"""
if not self.is_in_range(position):
return -1
return self.cache[position[1]][position[0]]
def is_in_range(self, position: tuple[int, int]) -> bool:
"""
:param position: (tuple) The position that will be checked
:return: (bool) indicates whether the said position is in map bounds
Checks if the given position is within the map range(a level should have been loaded first)
"""
if len(self.cache) == 0:
return False
if position[0] < 0 or position[1] < 0:
return False
if position[1] > GRID_Y-1:
return False
if position[0] > GRID_X-1:
return False
return True
def move_tile(self, tile_a, tile_b):
"""
:param tile_a: (tuple) The position of the tile to be moved
:param tile_b: (tuple) The position of the target tile
Moves the content of tile_a to tile_b(overwrites tile_b and sets tile_a to 0)
This is meant for player movement
"""
if tile_a != tile_b:
content = self.get_tile(tile_a)
self.update_tile(tile_b, content)
self.update_tile(tile_a, self.tileTypes['empty'])
def find_object(self, elt: int) -> tuple[int, int]:
"""
:param elt: (int) The type of element to find on the map(use self.tileTypes)
:return: (tuple) The position of the tile(or (-1, -1) if not found)
Finds the first instance of the provided element on the board, and returns its position
"""
for y in range(GRID_Y):
for x in range(GRID_X):
if self.cache[y][x] == elt:
return x, y
return -1, -1
def find_player(self): # finds the player in the stage grid and returns its coordinates
return self.find_object(self.tileTypes['player'])
def input_cmd():
cmd_txt = input("cmd => ").split(" ")
if cmd_txt[0] == "load" and len(cmd_txt) > 1 and cmd_txt[1].isnumeric() and can_load(int(cmd_txt[1])):
print(f"Now editing level {cmd_txt[1]}")
runner.level.load(int(cmd_txt[1]))
elif cmd_txt[0] == "create" and len(cmd_txt) > 1 and cmd_txt[1].isnumeric():
print(f"Now editing level {cmd_txt[1]}")
shutil.copyfile("lvl_template.json", f'lvl/{cmd_txt[1]}.json')
runner.level.load(int(cmd_txt[1]))
elif cmd_txt[0] == "save":
runner.level.save(runner.level.level)
print(f"Saved successfully")
else:
print("Invalid Command")
class Editor:
def __init__(self):
self.level = LevelManager() # An instance that manages level data and navigating
self.isInit = False # Safety attribute that prevents init from running twice
self.cursor = (0, 0) # Describes the mouse position(snapped to grid)
self.toolToggle = 0
self.toolToggleRotation = [
self.level.tileTypes['wall'],
self.level.tileTypes['exit'],
self.level.tileTypes['switch_blue'],
self.level.tileTypes['s_wall_blue']
]
self.element_display = [
"empty",
"wall",
"exit",
"player",
"blue switch",
"blue switch wall"
]
def on_click(self): # toggles the presence of an element at cursor position
tile = self.level.get_tile(self.cursor)
if tile != self.toolToggleRotation[self.toolToggle] and tile != self.level.tileTypes['player']:
self.level.update_tile(self.cursor, self.toolToggleRotation[self.toolToggle])
elif tile != self.level.tileTypes['player']:
self.level.update_tile(self.cursor, self.level.tileTypes['empty'])
def move_player(self): # moves the player to the cursor(overwrites said tile)
if self.cursor[0] >= 0 and self.cursor[1] >= 0:
plr_pos = self.level.find_player()
self.level.move_tile(plr_pos, self.cursor)
def tool_rotation(self): # Changes the element that will be placed on click
next_index = self.toolToggle + 1
if next_index >= len(self.toolToggleRotation):
self.toolToggle = 0
else:
self.toolToggle = next_index
new_element = self.toolToggleRotation[self.toolToggle]
print(f"Now placing {self.element_display[new_element]}")
# manages controls and tools
def upd(self):
mx, my = pyxel.mouse_x, pyxel.mouse_y
self.cursor = (mx//CELL_SIZE, my//CELL_SIZE)
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
self.on_click()
elif pyxel.btnp(pyxel.KEY_E):
self.move_player()
elif pyxel.btnp(pyxel.KEY_A):
self.tool_rotation()
elif pyxel.btnp(pyxel.KEY_C):
input_cmd()
# utility methods that draws the cursor to the mouse position
def draw_cursor(self):
x, y = self.cursor
center_x = x*CELL_SIZE+CELL_SIZE//2
center_y = y*CELL_SIZE+CELL_SIZE//2
pyxel.circb(center_x, center_y, 5, 4)
# self-explanatory, manages what's seen on screen
def display(self):
pyxel.cls(0)
for y in range(GRID_Y):
for x in range(GRID_X):
tile = self.level.get_tile((x, y))
if tile == self.level.tileTypes['wall']:
pyxel.rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE, 7)
elif tile == self.level.tileTypes['exit']:
pyxel.rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE, 11)
elif tile == self.level.tileTypes['player']:
pyxel.circ(x*CELL_SIZE+CELL_SIZE//2, y*CELL_SIZE+CELL_SIZE//2, CELL_SIZE//2-1, 8)
elif tile == self.level.tileTypes['switch_blue']:
pyxel.circ(x*CELL_SIZE+CELL_SIZE//2, y*CELL_SIZE+CELL_SIZE//2, CELL_SIZE//3-1, 12)
elif tile == self.level.tileTypes['s_wall_blue']:
pyxel.rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE, 12)
self.draw_cursor()
def init(self, lvl: int): # opens the editor window and loads the specified stage
if not self.isInit:
self.isInit = True
self.level.load(lvl)
pyxel.init(WIN_X, WIN_Y, title="ice_walker editor")
pyxel.mouse(True)
pyxel.run(self.upd, self.display)
def start_editor():
runner.init(int(lvl_id))
if __name__ == "__main__":
lvl_id = input("Please enter the id of the level to load: ")
if lvl_id.isnumeric():
print(f"Now editing level {lvl_id}")
runner = Editor()
start_editor()
else:
print("Invalid level id provided, please rerun and try again")
Loading…
Cancel
Save