Compare commits

...

4 Commits

Author SHA1 Message Date
En Yi d2e5ed82ad Change level preview based on selection
Changelog:
- Finish script to generate level preview altas
- Update render to pick preview based on scroll area selection
- Fix level order check in scripts
2025-01-21 22:13:05 +08:00
En Yi 9598fe7d35 Fix preview render size & add to level select 2025-01-21 21:31:03 +08:00
En Yi 925526199e Add water preview render 2025-01-20 22:09:41 +08:00
En Yi ee43a87f8a Add rendering for all tiles and entities 2025-01-20 21:47:09 +08:00
3 changed files with 104 additions and 47 deletions

View File

@ -61,7 +61,7 @@ pprint.pprint(ids_tiletype_map)
def get_level_order(lvl) -> int: def get_level_order(lvl) -> int:
order = 65535; order = 65535;
for data in lvl['fieldInstances']: for data in lvl['fieldInstances']:
if data["__identifier"] == "Order": if data["__identifier"] == "Order" and data["realEditorValues"]:
order = data["__value"] order = data["__value"]
return order return order

View File

@ -44,39 +44,67 @@ ENUMIDS_TILETYPE_MAPPING = {
'Urchin': 25, 'Urchin': 25,
} }
DANGER_COLOUR = (239,79,81,255)
WCRATE_COLOUR = (160,117,48,255)
MCRATE_COLOUR = (110,110,110,255)
WATER_COLOUR = (0,0,110,128)
REC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s-1)), c) REC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s-1)), c)
UPHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s//2-1)), c) UPHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s-1, y+s//2-1)), c)
DOWNHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x, y+s//2), (x+s-1,y+s-1)), c) DOWNHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x, y+s//2), (x+s-1,y+s-1)), c)
LEFTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s//2-1, y+s-1)), c) LEFTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x,y), (x+s//2-1, y+s-1)), c)
RIGHTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x+s//2,y), (x+s-1, y+s-1)), c) RIGHTHALFREC_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.rectangle(((x+s//2,y), (x+s-1, y+s-1)), c)
CIRCLE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.circle((x+s//2, y+s//2), s//2, c) CIRCLE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.circle((x+s//2, y+s//2), s//2, c)
TRIANGLE_DRAW_FUNCTION = lambda ctx,x,y,s,c : ctx.regular_polygon(((x+s//2, y+s//2), s//2), 3, 0, c)
def draw_bomb_tile(ctx, x, y, s, c):
REC_DRAW_FUNCTION(ctx, x, y, s, c)
ctx.line((x,y,x+s-1,y+s-1), DANGER_COLOUR, 1)
ctx.line((x,y+s-1,x+s-1,y), DANGER_COLOUR, 1)
def draw_arrow_tile(ctx, x, y, s, c, d):
REC_DRAW_FUNCTION(ctx, x, y, s, c)
if d == 0:
ctx.line((x+s//2,y+s//2,x+s//2,y), DANGER_COLOUR, 1)
elif d == 1:
ctx.line((x+s//2,y+s//2,x+s-1,y+s//2), DANGER_COLOUR, 1)
elif d == 2:
ctx.line((x+s//2,y+s//2,x+s//2,y+s-1), DANGER_COLOUR, 1)
elif d == 3:
ctx.line((x+s//2,y+s//2,x,y+s//2), DANGER_COLOUR, 1)
def draw_urchin_tile(ctx, x, y, s, c):
ctx.line((x,y,x+s-1,y+s-1), c, 1)
ctx.line((x,y+s-1,x+s-1,y), c, 1)
ctx.line((x+(s-1)//2,y,x+(s-1)//2,y+s-1), c, 1)
ctx.line((x,y+(s-1)//2,x+s-1,y+(s-1)//2), c, 1)
TILETYPE_SHAPE_MAP = { TILETYPE_SHAPE_MAP = {
'Solid': (REC_DRAW_FUNCTION, (0,0,0,255)), 'Solid': (REC_DRAW_FUNCTION, (0,0,0,255)),
'WoodenPlat': (UPHALFREC_DRAW_FUNCTION, (128,64,0,255)), 'WoodenPlat': (UPHALFREC_DRAW_FUNCTION, (128,64,0,255)),
'Ladder': (REC_DRAW_FUNCTION, (214,141,64,255)), 'Ladder': (REC_DRAW_FUNCTION, (214,141,64,255)),
'LSpike': (LEFTHALFREC_DRAW_FUNCTION, (239,79,81,255)), 'LSpike': (LEFTHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
'RSpike': (RIGHTHALFREC_DRAW_FUNCTION, (239,79,81,255)), 'RSpike': (RIGHTHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
'USpike': (UPHALFREC_DRAW_FUNCTION, (239,79,81,255)), 'USpike': (UPHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
'DSpike': (DOWNHALFREC_DRAW_FUNCTION, (239,79,81,255)), 'DSpike': (DOWNHALFREC_DRAW_FUNCTION, DANGER_COLOUR),
'EmptyWCrate': (REC_DRAW_FUNCTION, (160,117,48,255)), 'EmptyWCrate': (REC_DRAW_FUNCTION, WCRATE_COLOUR),
#'LArrowWCrate': 9, 'LArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,3), WCRATE_COLOUR),
#'RArrowWCrate': 10, 'RArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,1), WCRATE_COLOUR),
#'UArrowWCrate': 11, 'UArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,0), WCRATE_COLOUR),
#'DArrowWCrate': 12, 'DArrowWCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,2), WCRATE_COLOUR),
#'BombWCrate': 13, 'BombWCrate': (draw_bomb_tile, WCRATE_COLOUR),
'EmptyMCrate': (REC_DRAW_FUNCTION, (225,225,225,255)), 'EmptyMCrate': (REC_DRAW_FUNCTION, MCRATE_COLOUR),
#'LArrowMCrate': 15, 'LArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,3), MCRATE_COLOUR),
#'RArrowMCrate': 16, 'RArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,1), MCRATE_COLOUR),
#'UArrowMCrate': 17, 'UArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,0), MCRATE_COLOUR),
#'DArrowMCrate': 18, 'DArrowMCrate': (lambda ctx,x,y,s,c : draw_arrow_tile(ctx,x,y,s,c,2), MCRATE_COLOUR),
#'BombMCrate': 19, 'BombMCrate': (draw_bomb_tile, MCRATE_COLOUR),
'Boulder': (CIRCLE_DRAW_FUNCTION, (45,45,45,255)), 'Boulder': (CIRCLE_DRAW_FUNCTION, (45,45,45,255)),
#'Runner': 21, 'Runner': (TRIANGLE_DRAW_FUNCTION, (0,0,128,255)),
'Player': (REC_DRAW_FUNCTION, (255,0,255,255)), 'Player': (REC_DRAW_FUNCTION, (255,0,255,255)),
'Chest': (REC_DRAW_FUNCTION, (255,255,0,255)), 'Chest': (REC_DRAW_FUNCTION, (255,255,0,255)),
'Exit': (REC_DRAW_FUNCTION, (0,255,0,255)), 'Exit': (REC_DRAW_FUNCTION, (0,255,0,255)),
#'Urchin': 25, 'Urchin': (draw_urchin_tile, DANGER_COLOUR),
} }
# First go to tilesets and find Simple_tiles identifier, then find enumTags to identifier which tile type is what tileid # First go to tilesets and find Simple_tiles identifier, then find enumTags to identifier which tile type is what tileid
@ -98,7 +126,7 @@ pprint.pprint(ids_tiletype_map)
def get_level_order(lvl) -> int: def get_level_order(lvl) -> int:
order = 65535; order = 65535;
for data in lvl['fieldInstances']: for data in lvl['fieldInstances']:
if data["__identifier"] == "Order": if data["__identifier"] == "Order" and data["realEditorValues"]:
order = data["__value"] order = data["__value"]
return order return order
@ -123,10 +151,24 @@ converted_filename = '.'.join(fileparts)
# Get the tile size that fit within the dimensions # Get the tile size that fit within the dimensions
# Error out if tile size is zero # Error out if tile size is zero
# Figure out the offset to center the render # Figure out the offset to center the render
TILE_SIZE = 8 LEVELS_PER_ROW = 5
N_ROWS = n_levels // LEVELS_PER_ROW
if n_levels % LEVELS_PER_ROW != 0:
N_ROWS += 1
IMG_WIDTH = 400
IMG_HEIGHT = 400
FULL_IMG_WIDTH = LEVELS_PER_ROW * IMG_WIDTH
FULL_IMG_HEIGHT = N_ROWS * IMG_HEIGHT
# Each level should be packed as: [width, 2 bytes][height, 2 bytes][tile_type,entity,water,padding 1,1,1,1 bytes][tile_type,entity,water,padding 1,1,1,1 bytes]... # Each level should be packed as: [width, 2 bytes][height, 2 bytes][tile_type,entity,water,padding 1,1,1,1 bytes][tile_type,entity,water,padding 1,1,1,1 bytes]...
# Then loop the levels. Read the layerIndstances # Then loop the levels. Read the layerIndstances
for level in all_levels[17:18]:
lvl_render = Image.new("RGBA", (FULL_IMG_WIDTH, FULL_IMG_HEIGHT), (255,255,255,0))
render_ctx = ImageDraw.Draw(lvl_render)
for l, level in enumerate(all_levels):
lx = (l % LEVELS_PER_ROW) * IMG_WIDTH
ly = (l // LEVELS_PER_ROW) * IMG_HEIGHT
n_chests : int = 0 n_chests : int = 0
# Search for __identifier for the level layout # Search for __identifier for the level layout
level_name = "" level_name = ""
@ -156,16 +198,20 @@ for level in all_levels[17:18]:
width = level_layout["__cWid"] width = level_layout["__cWid"]
height = level_layout["__cHei"] height = level_layout["__cHei"]
print(f"Dim.: {width}x{height}. N Tiles: {width * height}") print(f"Dim.: {width}x{height}. N Tiles: {width * height}")
IMG_WIDTH = width * TILE_SIZE
IMG_HEIGHT = height * TILE_SIZE TILE_SIZE = 400 // max(width, height)
TILE_SIZE = max(TILE_SIZE,1)
# Create a W x H array of tile information # Create a W x H array of tile information
n_tiles = width * height n_tiles = width * height
lvl_render = Image.new("RGBA", (IMG_WIDTH, IMG_HEIGHT), (255,255,255,0)) LVL_SIZE = (width*TILE_SIZE-1, height*TILE_SIZE-1)
render_ctx = ImageDraw.Draw(lvl_render) OFFSET = ((IMG_WIDTH - LVL_SIZE[0]) // 2 + lx, (IMG_HEIGHT - LVL_SIZE[1])//2 + ly)
render_ctx.rectangle((OFFSET, (OFFSET[0]+width*TILE_SIZE-1, OFFSET[1] + height*TILE_SIZE-1)), (64,64,64,255))
# Loop through gridTiles, get "d" as the index to fill the info # Loop through gridTiles, get "d" as the index to fill the info
for i, tile in enumerate(level_layout["gridTiles"]): for i, tile in enumerate(level_layout["gridTiles"]):
x, y= (tile["d"][0] % width * TILE_SIZE, tile["d"][0] // width * TILE_SIZE) x, y= (tile["d"][0] % width * TILE_SIZE + OFFSET[0], tile["d"][0] // width * TILE_SIZE + OFFSET[1])
try: try:
if ids_tiletype_map[tile["t"]] in TILETYPE_SHAPE_MAP: if ids_tiletype_map[tile["t"]] in TILETYPE_SHAPE_MAP:
draw_func, colour = TILETYPE_SHAPE_MAP[ids_tiletype_map[tile["t"]]] draw_func, colour = TILETYPE_SHAPE_MAP[ids_tiletype_map[tile["t"]]]
@ -176,27 +222,32 @@ for level in all_levels[17:18]:
print("Error on tile", x, y) print("Error on tile", x, y)
render_ctx.circle((x,y), 2,(255,0,0,255)) render_ctx.circle((x,y), 2,(255,0,0,255))
print(e) print(e)
lvl_render.show()
#for i, water_level in enumerate(water_layout["intGridCsv"]):
# tiles_info[i][2] = water_level
## Subject to change ## Subject to change
#for ent in entity_layout["entityInstances"]: for ent in entity_layout["entityInstances"]:
# x,y = ent["__grid"] x,y = ent["__grid"]
# tiles_info[y*width + x][0] = ENUMIDS_TILETYPE_MAPPING[ent["__identifier"]] x *= TILE_SIZE
# if ent["__identifier"] == "Urchin": x += OFFSET[0]
# spd_encoding = 0 y *= TILE_SIZE
# for urchin_data in ent['fieldInstances']: y += OFFSET[1]
# if urchin_data["__identifier"] == "Direction": ent = ent["__identifier"]
# spd_encoding |= urchin_data["__value"] << 2 try:
# elif urchin_data["__identifier"] == "SpeedLevel": if ent in TILETYPE_SHAPE_MAP:
# spd_encoding |= urchin_data["__value"] draw_func, colour = TILETYPE_SHAPE_MAP[ent]
draw_func(render_ctx, x, y, TILE_SIZE, colour)
else:
print(ent, "is not mapped");
except Exception as e:
print("Error on tile", x, y)
render_ctx.circle((x,y), 2,(255,0,0,255))
print(e)
# tiles_info[y*width + x][0] += spd_encoding for i, water_level in enumerate(water_layout["intGridCsv"]):
if water_level == 0:
continue
#for y in range(height): x, y = (i % width * TILE_SIZE + OFFSET[0], i // width * TILE_SIZE + OFFSET[1])
# for x in range(width): height = TILE_SIZE * water_level / 4
# print(tiles_info[y*width + x], end=" ") render_ctx.rectangle(((x,y+TILE_SIZE-height), (x+TILE_SIZE-1, y+TILE_SIZE-1)), WATER_COLOUR)
# print()
lvl_render.save("preview.png")
lvl_render.show()

View File

@ -10,10 +10,16 @@ static void level_select_render_func(Scene_t* scene)
Sprite_t* spr = get_sprite(&scene->engine->assets, "bunny_spr1"); Sprite_t* spr = get_sprite(&scene->engine->assets, "bunny_spr1");
Sprite_t* level_board = get_sprite(&scene->engine->assets, "lvl_board"); Sprite_t* level_board = get_sprite(&scene->engine->assets, "lvl_board");
Sprite_t* level_select = get_sprite(&scene->engine->assets, "lvl_select"); Sprite_t* level_select = get_sprite(&scene->engine->assets, "lvl_select");
Sprite_t* preview = get_sprite(&scene->engine->assets, "lvlprvw");
BeginTextureMode(scene->layers.render_layers[0].layer_tex); BeginTextureMode(scene->layers.render_layers[0].layer_tex);
ClearBackground(BLANK); ClearBackground(BLANK);
draw_sprite(level_select, 0, (Vector2){0,0},0, false); draw_sprite(level_select, 0, (Vector2){0,0},0, false);
draw_sprite(level_board, 0, (Vector2){level_select->frame_size.x,0},0, false); draw_sprite(level_board, 0, (Vector2){level_select->frame_size.x,0},0, false);
draw_sprite(preview, data->scroll_area.curr_selection, (Vector2){
level_select->frame_size.x + (level_board->frame_size.x - preview->frame_size.x) / 2,
(level_board->frame_size.y - preview->frame_size.y) / 2,
},0, false);
DrawText("Level Select", 10, 10, 40, BLACK); DrawText("Level Select", 10, 10, 40, BLACK);
vert_scrollarea_render(&data->scroll_area); vert_scrollarea_render(&data->scroll_area);
draw_sprite( draw_sprite(