我需要将像素艺术.png 转换为json。我有这个结构。我已经在 .spwn 上编写了工作脚本并且它工作正常。但在 C# 上,我遇到了编程世界的技能问题之一。
722 像素/对象 - 开始时。 380 个对象必须经过优化。
Program.cs文件:
using Structures;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.Json;
class MainClass
{
public static int NULL_cnt, COLOR_cnt = 0;
public static List<Structures.Color>? pallete;
public static bool Color_exist(Structures.Color Color)
{
if (pallete == null)
{
pallete = new List<Structures.Color>();
pallete.Add(Color);
}
foreach (Structures.Color clr in pallete)
{
if (clr.Equals(Color)) return true;
}
pallete.Add(Color);
return false;
}
public static int Serch_clr_id(Structures.Color color)
{
Color_exist(color);
for (int id = 0; id < pallete.Count; id++)
{
if (pallete[id].Equals(color)) return id;
}
return -1;
}
public static int Get_block_index_by_pos(float x, float y, Block[] blocks)
{
Block to_check = null;
foreach(Block block in blocks)
{
if (block.x == x && block.y == y) {
to_check = block;
break;
}
}
return blocks.ToList().IndexOf(to_check);
}
public static Block Get_block_by_pos(float x, float y, Block[] blocks)
{
foreach (Block block in blocks)
{
if (block.x == x && block.y == y) return block;
}
return null;
}
public static int Get_index_by_block(Block block, Block[] blocks)
{
return blocks.ToList().IndexOf(block);
}
public static bool Is_optimizeble(Block block, Block[] blocks_array, int size, Size img_size)
{
int x = (int)block.x;
int y = (int)block.y;
if (x + size > img_size.Width || y + size > img_size.Height) return false;
for (int X = x; X < x + size; X++)
{
for (int Y = y; Y < y + size; Y++)
{
Block to_check = Get_block_by_pos(X, Y, blocks_array);
if (to_check == null)
{
return false;
}
if (to_check.color_id != block.color_id)
{
return false;
}
}
}
return true;
}
public static Block[] Optimize(Block[] blocks, Size size)
{
// Optimization algorithm
List<Block> new_blocks = blocks.ToList();
List<Block> to_fill = new List<Block>();
bool flag = false;
for (int pixel_size = 4; pixel_size > 1; pixel_size -= 2)
{
List<Block> blocks_to_check = new_blocks;
while (true)
{
flag = true;
//List<Block> local_BTC = blocks_to_check;
foreach (Block block in blocks_to_check.ToList())
{
blocks_to_check.Remove(block);
if (Is_optimizeble(block, new_blocks.ToArray(), pixel_size, size))
{
flag = false;
float X = block.x;
float Y = block.y;
for (int x = (int)X; x < X + pixel_size; x++)
{
for (int y = (int)Y; y < Y + pixel_size; y++)
{
int to_remove = Get_block_index_by_pos(x, y, new_blocks.ToArray<Block>());
if (to_remove != -1) new_blocks.RemoveAt(to_remove);
}
}
bool condition = pixel_size == 4;
float offset_multipling = condition ? 1.5f : 0.5f;
to_fill.Add(new Block(
condition ? (int)Block_ID.Full_Pixel : (int)Block_ID.Quadro_Pixel,
block.x + offset_multipling,
block.y + offset_multipling,
block.color_id
));
break;
}
}
if (flag)
{
flag = false;
break;
}
}
}
return to_fill.ToArray<Block>();
}
public static JSON_Image Convert(Bitmap image)
{
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
Size size = image.Size;
Block[] blocks = new Block[size.Width * size.Height];
for (int index = 0; index < size.Width * size.Height; index++)
{
int xPos = index % size.Width;
int yPos = (int)(index / size.Width);
Structures.Color curr_color = new Structures.Color(image.GetPixel(xPos, yPos));
blocks[index] = new Block(((int)Block_ID.Pixel), xPos, yPos, Serch_clr_id(curr_color));
}
List<Block> blocks_to_check = new List<Block>();
foreach (Block block in blocks)
{
if (pallete[block.color_id].a == 0) continue;
blocks_to_check.Add(block);
}
int[] arr_size = new int[2] { size.Width, size.Height };
Console.WriteLine($"{blocks_to_check.Count} LIST\n{blocks.Length} ARRAY");
blocks = Optimize(blocks_to_check.ToArray<Block>(), size);
Console.WriteLine($"Optimization result: {blocks.Length} blocks");
return new JSON_Image(arr_size, pallete.ToArray(), blocks);
}
static void Main(string[] args)
{
Bitmap img = new Bitmap("C:\\Users\\DENIS\\Desktop\\kris.png", false);
string fileName = "C:\\Users\\DENIS\\Desktop\\kris.json";
string jsonString = JsonSerializer.Serialize(Convert(img));
File.WriteAllText(fileName, jsonString);
Console.WriteLine($"{NULL_cnt} {COLOR_cnt}");
}
}
结构.cs
namespace Structures
{
internal enum Block_ID
{
Pixel = 917,
Quadro_Pixel = 916,
Full_Pixel = 955
}
internal class Block
{
public int obj_id { get; set; }
public float x { get; set; }
public float y { get; set; }
public int color_id { get; set; }
public Block(int OBJ_ID, float X, float Y, int COLOR_ID)
{
obj_id = OBJ_ID;
x = X;
y = Y;
color_id = COLOR_ID;
}
public bool Equals(Block other) => this.obj_id == other.obj_id && this.x == other.x && this.y == other.y && this.color_id == other.color_id;
}
internal class Color
{
public int r { get; set; }
public int g { get; set; }
public int b { get; set; }
public int a { get; set; }
public Color(int R, int G, int B, int A)
{
r = R; g = G; b = B; a = A;
}
public Color(System.Drawing.Color color)
{
r = color.R; g = color.G; b = color.B; a = color.A;
}
public int[] ToArray() => new int[4] { this.r, this.g, this.b, this.a };
public bool Equals(Color other) => this.r == other.r && this.g == other.g && this.b == other.b && this.a == other.a;
}
internal class JSON_Image
{
public int[] size { get; set; } = new int[2];
public Array[] Blocks { get; set; }
public Array[] Colors_set { get; set; }
public JSON_Image(int[] size, Color[] colors_set, Block[] blocks)
{
this.size = size;
Blocks = new Array[blocks.Length];
Colors_set = new Array[colors_set.Length];
for (int i = 0; i < blocks.Length; i++) this.Blocks[i] = new float[4] { blocks[i].obj_id, blocks[i].x, blocks[i].y, blocks[i].color_id };
for (int i = 0; i < colors_set.Length; i++) this.Colors_set[i] = new float[4] { colors_set[i].r, colors_set[i].g, colors_set[i].b, colors_set[i].a };
}
}
}
Image_json_into_gd_art.spwn
extract obj_props
// block size 30, 1/4 block size 7.5 | id 917
path = "C:\\Users\\DENIS\\Desktop\\gd gameplay deltarune-undertale\\Undertale-Deltarune-gameplay-in-GD-with-SPWN\\spwn files\\"
let channels_colors_set = []
let colors = []
let imgSize = []
let blocks = []
let gridSize = 7.5
let offset = 0
check_match = (match_c) {
for color in colors {
if (color.r8() == match_c.r8() && color.b8() == match_c.b8() && color.g8() == match_c.g8() && color.a8() == match_c.a8()) {
return true
}
}
return false
}
get_block_by_pos = (x, y, blocks_array) {
for block in blocks_array {
if block[X] == x * gridSize && block[Y] == y * gridSize {
return block
}
}
return null
}
is_optimizeble = (block, blocks_array, size) {
$.print("Next...")
let block_cc = block[COLOR]
let X = block[X] / gridSize
let Y = block[Y] / gridSize
let succes_cnt = 0
if X + size > imgSize[0] || Y + size > imgSize[1] { return false }
for x in X..X+size { for y in Y..Y+size {
let to_check = get_block_by_pos(x, y, blocks_array)
if to_check == null { return false }
if to_check[COLOR] != block_cc { return false }
succes_cnt += 1
$.print(succes_cnt / (size ** 2))
}}
return true
}
optimize = (objects){
let new_blocks = objects
let new_fill_blocks = []
let flag = false
let optimized = {}
$.print("Objects count optimization...")
for optim_block_size in 5..2..2 {
let blocks_to_check = new_blocks
let optimized[@string(optim_block_size)] = 0
while true {
flag = true
for block in blocks_to_check {
$.print("Remains to check: ", blocks_to_check.length)
blocks_to_check.pop(blocks_to_check.index(block))
if is_optimizeble(block, new_blocks, optim_block_size) {
flag = false
let Xpos = block[X] / gridSize
let Ypos = block[Y] / gridSize
for x in Xpos..Xpos+optim_block_size { for y in Ypos..Ypos+optim_block_size {
let a = new_blocks.index(get_block_by_pos(x, y, new_blocks))
if a != null {
$.print("Removing block...")
new_blocks.pop(a)
}}}
let filling_offset = 11.25 if optim_block_size == 4 else 3.75
let filling = obj {
X: Xpos * gridSize + filling_offset,
Y: Ypos * gridSize + filling_offset,
OBJ_ID: 955 if optim_block_size == 4 else 916,
SCALING: 1,
ROTATION: 0,
COLOR: block[COLOR]
}
optimized[@string(optim_block_size)] += 1
new_fill_blocks.push(filling)
$.print("Done: ", @string(optimized[@string(optim_block_size)]))
$.print("Blocks: ", @string(new_blocks.length + new_fill_blocks.length))
$.print("Filling block at X: ", @string(filling[X]), " | Y: ", @string(filling[Y]), "\n")
break
}
}
if flag == true {
flag = false
break
}
}
}
for block in new_fill_blocks {
new_blocks.push(block)
}
$.print("Optimization results:")
for [optSize, optCnt] in optimized {
$.print(optSize, "x", optSize, ": ", (@number(optSize) ** 2) * optCnt, " -> ", optCnt)
}
$.print("In short: ", blocks.length, " -> ", new_blocks.length)
$.print("Optimized: ", blocks.length - new_blocks.length, "\n")
return new_blocks
}
$.print("Reading JSON...")
let data = $.readfile(path + "kris.json", "json")
let raw_colors_set = data['Colors_set']
imgSize = data['size']
let pixels = data['Blocks']
$.print("Done\n")
$.print("Color optimization...")
for color in raw_colors_set {
if !check_match(rgb8(color[0], color[1], color[2], color[3])) {
let cc = ?c
cc.set(rgb8(color[0], color[1], color[2], color[3]))
channels_colors_set.push(cc)
colors.push(rgb8(color[0], color[1], color[2], color[3]))
}
}
$.print("Done\n")
$.print("Adding blocks...")
for pixel in pixels {
if raw_colors_set[pixel[3] - 1][3] != 0 {
blocks.push( obj {
X: pixel[1] * gridSize + offset,
Y: pixel[2] * gridSize,
OBJ_ID: pixel[0],
COLOR: channels_colors_set[pixel[3]]
})
}
}
//offset += 30
$.print("Done\n")
//blocks = optimize(blocks)
$.print("Adding blocks into level...")
for block in blocks {
$.add(block)
}
$.print("Done\n")
拜托,我在调试中花费了 6 小时以上,但什么也没得到。
我尝试修复 List.Index(block) 的 -1,但什么也没有 我尝试将平铺队列从 4x4 -> 2x2 更改为 2x2 -> 4x4 还有其他东西,比如缓冲区。
错误出现在 C# 奇怪的数据存储中。我需要改变
List<Block> blocks_to_check = new_blocks;
到
List<Block> blocks_to_check = new_blocks.ToList();
C# 同步
blocks_to_check
和 new_blocks
并且将列表转换为“其他”列表后问题得到解决。