Skip to content

Instantly share code, notes, and snippets.

@GarethIW
Created April 17, 2022 19:56
Show Gist options
  • Save GarethIW/d980f223c877bbf0c288f738e25c464f to your computer and use it in GitHub Desktop.
Save GarethIW/d980f223c877bbf0c288f738e25c464f to your computer and use it in GitHub Desktop.
Playdate RPG exporter
public class Exporter : MonoBehaviour
{
public Material[] GroundMaterials;
public Material[] WallMaterials;
public GameObject[] Walls;
public GameObject Ceiling;
public GameObject Floor;
public Camera Camera;
// Start is called before the first frame update
void Start()
{
StartCoroutine(nameof(Export));
}
private IEnumerator Export()
{
foreach (GameObject w in Walls)
{
w.SetActive(false);
}
// Ceilings and floors
Ceiling.SetActive(true);
Floor.SetActive(true);
Texture2D outputTexture = new Texture2D(800, 240 * 4, GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None);
Rect readRect;
foreach (Material mat in GroundMaterials)
{
Ceiling.GetComponent<MeshRenderer>().material = mat;
Floor.GetComponent<MeshRenderer>().material = mat;
int row = 0;
for (float deg = 0; deg < 360; deg += 90)
{
Camera.transform.rotation = Quaternion.Euler(0, deg, 0);
for (int frame = 0; frame < 2; frame++)
{
Camera.transform.position += Camera.transform.forward * 3f;
readRect = new Rect(0, 0, Camera.pixelWidth, (Camera.pixelHeight / 2));
Camera.Render();
yield return new WaitForSeconds(0.2f); // Pause for effect
yield return new WaitForEndOfFrame(); // This is the important yield and allows for ReadPizels
outputTexture.ReadPixels(readRect, frame * Camera.pixelWidth, row * (Camera.pixelHeight / 2));
outputTexture.Apply();
readRect = new Rect(0, (Camera.pixelHeight / 2), Camera.pixelWidth, (Camera.pixelHeight / 2));
Camera.Render();
yield return new WaitForSeconds(0.2f);
yield return new WaitForEndOfFrame();
outputTexture.ReadPixels(readRect, frame * Camera.pixelWidth, (row + 1) * (Camera.pixelHeight / 2));
outputTexture.Apply();
}
Camera.transform.position -= Camera.transform.forward * 3f;
row += 2;
}
Camera.transform.rotation = Quaternion.Euler(0, 0, 0);
var png = outputTexture.EncodeToPNG();
File.WriteAllBytes(Path.Combine(Application.persistentDataPath,$"floors-{mat.name}.png"), png);
}
Ceiling.SetActive(false);
Floor.SetActive(false);
// Walls
List<(int id, int tileX, int tileY, int drawX, int drawY, Color[] data)> spriteRects = new List<(int, int, int, int, int, Color[])>();
List<PackingRectangle> rects = new List<PackingRectangle>();
Texture2D cameraTexture = new Texture2D(Camera.pixelWidth,Camera.pixelHeight, GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None);
foreach (Material mat in WallMaterials)
{
int id = 0;
foreach (GameObject wall in Walls)
{
wall.GetComponent<MeshRenderer>().material = mat;
wall.SetActive(true);
readRect = new Rect(0, 0, Camera.pixelWidth, Camera.pixelHeight);
Camera.Render();
yield return new WaitForSeconds(0.3f);
yield return new WaitForEndOfFrame();
cameraTexture.ReadPixels(readRect, 0, 0);
cameraTexture.Apply();
Color[] temp = cameraTexture.GetPixels();
// Detect bounds of wall sprite
PackingRectangle extents = new PackingRectangle(uint.MaxValue, uint.MaxValue, uint.MinValue, uint.MinValue, id);
for (uint x = 0; x < cameraTexture.width; x++)
{
for (uint y = 0; y < cameraTexture.height; y++)
{
if (temp[x + (y * cameraTexture.width)].a != 0)
{
if (x < extents.X) extents.X = x;
if (x > extents.Width) extents.Width = x;
if (y < extents.Y) extents.Y = y;
if (y > extents.Height) extents.Height = y;
}
}
}
extents.Width -= (extents.X-1);
extents.Height -= (extents.Y - 1);
Color[] spriteData = cameraTexture.GetPixels((int)extents.X, (int) extents.Y, (int) extents.Width, (int) extents.Height);
var split = wall.name.Replace("Wall", "").Split('-');
spriteRects.Add((id,int.Parse(split[0]),int.Parse(split[1]),(int)extents.X,Camera.pixelHeight-((int)extents.Y+(int)extents.Height),spriteData));
rects.Add(extents);
id++;
wall.SetActive(false);
}
var rectArray = rects.ToArray();
RectanglePacker.Pack(rectArray, out PackingRectangle bounds);
outputTexture = new Texture2D((int)bounds.Width,(int)bounds.Height, GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None);
outputTexture.SetPixels(new Color[(int)bounds.Width*(int)bounds.Height]);
string csv = "TileX,TileY,DrawX,DrawY,RectX,RectY,RectWidth,RectHeight\n";
foreach ((int id, int tileX, int tileY, int drawX, int drawY, Color[] data) spriteRect in spriteRects)
{
var rect = rectArray.FirstOrDefault(r => r.Id == spriteRect.id);
outputTexture.SetPixels((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height, spriteRect.data);
csv += $"{spriteRect.tileX},{spriteRect.tileY},{spriteRect.drawX},{spriteRect.drawY},{rect.X},{outputTexture.height-(rect.Y+rect.Height)},{rect.Width},{rect.Height}\n"; // Flip Y positions for PD
}
outputTexture.Apply();
var png = outputTexture.EncodeToPNG();
File.WriteAllBytes(Path.Combine(Application.persistentDataPath,$"wall-{mat.name}.png"), png);
File.WriteAllText(Path.Combine(Application.persistentDataPath,$"wall-{mat.name}.csv"),csv);
}
yield return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment