Japster
Member
Hi guys - working on a quick puzzle game as a free Xmas game, and it relies upon having an image cut up into random(ish) rectangles, Mondrian style... (completely real-time randomized, as opposed to a few different layouts, hence my problem!)
I'm using a recursive split method, and the first cut works fine, but I'm struggling to get my head around how to work the logic to work properly iteratively. I always seem to have a meltdown trying to implement recursive logic...
So, if I run it once, passing in the original source sprite, I get 2 smaller partial sprites as expected, either split horizontally or vertically, using this coordinate logic - this sets the coordinates correctly, from what I can tell... ie.:-
ie. I get a random horizontal/vertical split, 2 sprites:-
But if I call it again, twice, from itself, trying to pass in the 2 newly-created cut out sprites, to further split them (if they're large enough, given a minimum pixel size, otherwise I keep which half/halves I have, and exit to end that branch), I just get (e.g.) this?:-
Ideally, I've LOVE to be able to cut an image up like, eg. these examples below (albeit down to smaller pieces), but I can't seem to figure out a routine for that, hence trying the recursive binary split method...
Now I know that my code for this is horrendous, but here's the 'split' function in it's entirety - I set up some global variables in the game, and all the game code itself does is pretty much call the initial instance of this sprite-slicing routine, to fill a global ds_grid with sprite piece ID's and their correct locations within the main source image:-
Also have the following macro's set up:-
#macro Spr_ID 0
#macro x_Pos 1
#macro y_Pos 2
#macro Discard_Piece 3
#macro random_split 0
#macro hori_split 1
#macro vert_split 2
Any help pointing me towards my stupid mistake(s) would be greatly appreciated guys!
Cheers!
I'm using a recursive split method, and the first cut works fine, but I'm struggling to get my head around how to work the logic to work properly iteratively. I always seem to have a meltdown trying to implement recursive logic...
So, if I run it once, passing in the original source sprite, I get 2 smaller partial sprites as expected, either split horizontally or vertically, using this coordinate logic - this sets the coordinates correctly, from what I can tell... ie.:-
ie. I get a random horizontal/vertical split, 2 sprites:-
But if I call it again, twice, from itself, trying to pass in the 2 newly-created cut out sprites, to further split them (if they're large enough, given a minimum pixel size, otherwise I keep which half/halves I have, and exit to end that branch), I just get (e.g.) this?:-
Ideally, I've LOVE to be able to cut an image up like, eg. these examples below (albeit down to smaller pieces), but I can't seem to figure out a routine for that, hence trying the recursive binary split method...
Now I know that my code for this is horrendous, but here's the 'split' function in it's entirety - I set up some global variables in the game, and all the game code itself does is pretty much call the initial instance of this sprite-slicing routine, to fill a global ds_grid with sprite piece ID's and their correct locations within the main source image:-
Also have the following macro's set up:-
#macro Spr_ID 0
#macro x_Pos 1
#macro y_Pos 2
#macro Discard_Piece 3
#macro random_split 0
#macro hori_split 1
#macro vert_split 2
GML:
/// Slice_Sprite (Source_Sprite, This_Sprite_Piece_Index,Offset_X,Offset_Y, Split_Type)
/// @param Source_Sprite
/// @param This_Sprite_Piece_Index
/// @param Offset_X
/// @param Offset_Y
/// @param Split_Type
var source_sprite = argument[0];
var This_Sprite_Piece_Index = argument[1];
var Offset_X = argument[2];
var Offset_Y = argument[3];
var minimum_Split_Size = Smallest_Slice_Size_In_Pixels*2;
//if (argument_count != 5)
//{
// var split_type = random_split;
//}
//else
//{
var split_type = argument[4];
if (split_type == random_split)
{
split_type = choose(hori_split,vert_split);
}
//}
var t_height = sprite_get_height(source_sprite);
var t_width = sprite_get_width(source_sprite);
var vertical_split_position = 0;
var horizontal_split_position = 0;
if (split_type = hori_split)
{
var vertical_split_position =
(t_height >= (minimum_Split_Size)) *
irandom_range(Smallest_Slice_Size_In_Pixels+1,t_height-Smallest_Slice_Size_In_Pixels);
}
if (split_type = vert_split)
{
var horizontal_split_position =
(t_width >= (minimum_Split_Size)) *
irandom_range(Smallest_Slice_Size_In_Pixels+1,t_width-Smallest_Slice_Size_In_Pixels);
}
if (!horizontal_split_position && !vertical_split_position)
{
return false; // Leave alone / end this branch, as we've hit minimum size!
}
// Draw to surface, and cut both parts back out...
var t_Jigsaw = surface_create(t_width*Puzzle_Scale,t_height*Puzzle_Scale);
surface_set_target(t_Jigsaw);
draw_clear_alpha(c_black, 1);
draw_sprite_ext(source_sprite, 0, Offset_X, Offset_Y,Puzzle_Scale,Puzzle_Scale,0,c_white,1);
var t_x1 = Offset_X; // Will always be top-left
var t_y1 = Offset_Y; // Will always be top-left
var t_x4 = Offset_X + t_width*Puzzle_Scale; // Will always be bottom-right
var t_y4 = Offset_Y + t_height*Puzzle_Scale; // Will always be bottom-right
if (split_type == hori_split) // Going to slice Horizontally!
{
var t_x2 = t_x4; // Will always be top-left
var t_y2 = Offset_Y + (vertical_split_position*Puzzle_Scale); // Will always be top-left
var t_x3 = Offset_X;//horizontal_split_position*Puzzle_Scale; // Will always be bottom-right
var t_y3 = Offset_Y + (vertical_split_position*Puzzle_Scale+1); // Will always be bottom-right
}
else
{
var t_x2 = Offset_X + (horizontal_split_position*Puzzle_Scale); // Will always be top-left
var t_y2 = t_y4; // Will always be top-left
var t_x3 = Offset_X + (horizontal_split_position*Puzzle_Scale+1); // Will always be bottom-right
var t_y3 = t_y1; //vertical_split_position*Puzzle_Scale; // Will always be bottom-right
}
// discard the passed in 'source' sprite if not initial project sprite
if (This_Sprite_Piece_Index != 0) sprite_delete (source_sprite);
var t_sprite_1 = sprite_create_from_surface(t_Jigsaw, t_x1, t_y1, t_x2-t_x1,t_y2-t_y1, false, false, 0, 0);
Slice_Sprite_ID_List[# This_Sprite_Piece_Index, Spr_ID] = t_sprite_1;
Slice_Sprite_ID_List[# This_Sprite_Piece_Index, x_Pos] = t_x1;
Slice_Sprite_ID_List[# This_Sprite_Piece_Index, y_Pos] = t_y1;
var This_Sprite_Piece_Index_2 = Next_Piece_Grid_ID;
Next_Piece_Grid_ID += 1;
show_debug_message(string(Next_Piece_Grid_ID));
var t_sprite_2 = sprite_create_from_surface(t_Jigsaw, t_x3, t_y3, t_x4-t_x3,t_y4-t_y3, false, false, 0, 0);
Slice_Sprite_ID_List[# This_Sprite_Piece_Index_2, Spr_ID] = t_sprite_2;
Slice_Sprite_ID_List[# This_Sprite_Piece_Index_2, x_Pos] = t_x3;
Slice_Sprite_ID_List[# This_Sprite_Piece_Index_2, y_Pos] = t_y3;
surface_reset_target();
surface_free(t_Jigsaw);
// ^^^ Done this split! -----------------
// Next, we recursively call this routine again for each piece, if either/both are big enough...
// --------------------------------------------
// Split SPRITE 1 if possible
t_height = sprite_get_height(t_sprite_1);
t_width = sprite_get_width(t_sprite_1);
var t_split = -1; // default to no split
if (t_height >= minimum_Split_Size) && (t_width >= minimum_Split_Size)
{
t_split = choose(hori_split,vert_split);
}
else
{
if (t_height >= minimum_Split_Size)
{
t_split = hori_split;
}
else
{
if (t_width >= minimum_Split_Size) t_split = vert_split;
}
}
if (t_split >= 0) var t_result = Slice_Sprite(t_sprite_1,This_Sprite_Piece_Index,t_x1,t_y1,t_split); // We can split again, so recurse.
// --------------------------------------------
// Split SPRITE 2 if possible
t_height = sprite_get_height(t_sprite_2);
t_width = sprite_get_width(t_sprite_2);
var t_split_2 = -1; // default to no split
if (t_height >= minimum_Split_Size) && (t_width >= minimum_Split_Size)
{
t_split_2 = choose(hori_split,vert_split);
}
else
{
if (t_height >= minimum_Split_Size)
{
t_split_2 = hori_split;
}
else
{
if (t_width >= minimum_Split_Size) t_split_2 = vert_split;
}
}
if (t_split_2 >= 0) var t_result = Slice_Sprite(t_sprite_2,This_Sprite_Piece_Index_2,t_x3,t_y3,t_split_2); // We can split again, so recurse.
return (t_split || t_split_2); // if we split at least 1 of these created 'halves', return true...
Cheers!
Last edited: