Created
April 17, 2022 19:56
-
-
Save GarethIW/d980f223c877bbf0c288f738e25c464f to your computer and use it in GitHub Desktop.
Playdate RPG exporter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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