80 lines
3.3 KiB
Python
80 lines
3.3 KiB
Python
# CAKEFOOT by @ohsqueezy for <https://foam.shampoo.ooo> and <https://ohsqueezy.itch.io>
|
|
#
|
|
# This file contains functions to facilitate transforming an SVG file with bezier curve data exported from GIMP into a Cakefoot level.
|
|
#
|
|
# This script is not essential for building the game. It is intended to be used manually to help build the `curve` field for a level in
|
|
# `resource/levels.json`.
|
|
#
|
|
# Create a path in GIMP, and export it to file by right-clicking the path in the path tool tab. Call the groups function on the path, and
|
|
# a list will be returned with one group of points per curve in the file.
|
|
|
|
import pathlib
|
|
import numpy as np
|
|
from bs4 import BeautifulSoup as BS
|
|
|
|
def groups(path: pathlib.Path, reverse: bool = False) -> list[list[tuple[float, float]]]:
|
|
"""
|
|
Read the groups of bezier curves in an SVG file exported by the GIMP path tool. A list of curves will be returned, each group in the
|
|
list consisting of a list of 2D floating point coordinates.
|
|
|
|
@param path SVG file with bezier curve
|
|
@param reverse For each group of points, return the reverse order they appear in the file
|
|
@return A three dimensional list, groups of 2D float coordinates
|
|
"""
|
|
groups = []
|
|
with path.open() as svg:
|
|
|
|
# Parse using XML mode, extract the "d" attribute from the "path" element
|
|
for content in BS(svg, features="xml").find("path").attrs["d"].split():
|
|
|
|
# Unless the content is just "M" or "C", it should contain a coordinate
|
|
if content != "M" and content != "C":
|
|
group = content
|
|
|
|
# Trim off the M that indicates the next group start at the end of the content
|
|
if content.endswith("M"):
|
|
group = content[:-1]
|
|
|
|
# Parse the coordinate data
|
|
groups[-1].append(tuple(float(point) for point in group.split(",")))
|
|
|
|
# A single "M" or a coordinate ending in "M" indicates a new group is starting
|
|
if content.endswith("M"):
|
|
groups.append([])
|
|
|
|
# Reverse groups after finished parsing if requested
|
|
if reverse:
|
|
for ii in range(len(groups)):
|
|
groups[ii] = list(reversed(groups[ii]))
|
|
|
|
return groups
|
|
|
|
def wrap_group(group: list[tuple[float, float]], x_offset: float, y_offset: float) -> list[tuple[float, float]]:
|
|
"""
|
|
Offset a given a list of 2D points by the given offset.
|
|
|
|
@param group List of 2D points
|
|
@param x_offset Amount to move in the X direction
|
|
@param y_offset Amount to move in the Y direction
|
|
@return Group after applying offset
|
|
"""
|
|
offset_group = []
|
|
for coordinates in group:
|
|
offset_group.append((coordinates[0] + x_offset, coordinates[1] + y_offset))
|
|
return offset_group
|
|
|
|
def format_group(group: list[tuple[float, float]]) -> str:
|
|
"""
|
|
@param group A 2D bezier curve as a list of float coordinates (see `groups` function)
|
|
@return Curve printed as a string appropriate for a JSON array for use with the Cakefoot levels file
|
|
"""
|
|
output = "\"curve\": ["
|
|
for ii, coordinates in enumerate(group):
|
|
if ii % 6 == 0:
|
|
output += "\n "
|
|
output += f"[{coordinates[0]:8}, {coordinates[1]:8}]"
|
|
if ii < len(group) - 1:
|
|
output += ", "
|
|
output += "\n]"
|
|
return output
|