Windows Need help otmizing my game

Callam

Member
Hey guys.

I'm making a paint by number game for my daughter, she really likes pokemon so i wanna do the original 151 in it. I spent several hours doing just bulbasaur. I've got it so it works perfect, however i feel theres a much better way it could be done, right now its using at least 60 objects for just Bulbasaur.

Theres nothing special or different about this, its just like any other coloring game on the app stores, pick a color, the blocks to be colored get highlighted. Once every color is done, then you get a congrats and it takes you back to the image selection

Basically i wanna simplfy the whole thing so its much more effiecent than having to work with so many objects.

Here's a few quick screenshots and a link to the project file.

Any help would be greatly appreciated.

Download Link

Pokemon 1.pngPokemon 2.pngPokemon 3.pngPokemon 4.png
 

Nidoking

Member
I think you might be able to do this with resource files and a smaller number of actual objects, but it would require changing some of the basic mechanics you've already implemented. If you're up for that, you could make the numbers and colors a property of the objects rather than separate objects for each one. You could have one "obj_square" that has a number and a color, initialized to a value such as 0x000001 (or an additional "colored" boolean). When it's uncolored, it will draw the number on top of the blank square graphic, and once it's colored, it will instead draw a rectangle of the appropriate color while keeping the number in case it needs to be recolored. Likewise, the selectable color squares could all be one object, each initialized with its own color. When one is selected, you tell all of the others to deselect, then set some global property with the color of the selected one so you know what color to paint. You'll need to update with constructions to check the number value for each obj_square, but that will hopefully be simpler with just one of each type of object to update.

Once you've done that, it should make the actual implementation much cleaner, and now it's just a matter of developing the rooms with the individual Pokemon. For those, you can likely read in a text file that contains the numbers of the squares in the room, with 0 being no square. You can create the rooms dynamically, either at the start of the game or on demand, creating and initializing tiles upon room start based on the information in the file. Once you have that working, you'll be able to create new Pokemon by creating new files and adding the filename to your game, and tweaking the drawing will be as simple as editing the file and rerunning.
 
My thought would be to try and get away from having an object per cell and instead work with surfaces and something like a ds_grid to hold the color data and compare mouse position. You could have a front surface to hold the colors and a back surface to hold the numbers. You would need a controller object that takes the mouse position and coverts it to the position of the grid, then it should be fairly simple to know what cell they clicked and what color data it contains.

Alternatively you could just use a surface for the color numbers. Drawing text in gm is very expensive and so if you're just drawing normalvtext in each be cell that is eating up a ton of processing for no reason.
 

GMWolf

aka fel666
What you are looking for is palette swapping.
Basically, make a sprite for each Pokémon, but have each region be a different colour (it doesn't matter what the colours are as long as each section is different from every other section within a sprite).

The you will want to apply a pallet swapping shader. A Google search for game maker pallet swapping should yield several results featuring pallet swapping shaders.

Then you need to change the pallet based on the selected colours. (This will depend on the shader, and how you want your game to work)


If you want something simpler, you could make each section of the Pokémon sprites a different object & instance, rather than each individual pixel be a different object.
This would be fairly fast (but requires many sprites and objects)
 

jo-thijs

Member
Hey guys.

I'm making a paint by number game for my daughter, she really likes pokemon so i wanna do the original 151 in it. I spent several hours doing just bulbasaur. I've got it so it works perfect, however i feel theres a much better way it could be done, right now its using at least 60 objects for just Bulbasaur.

Theres nothing special or different about this, its just like any other coloring game on the app stores, pick a color, the blocks to be colored get highlighted. Once every color is done, then you get a congrats and it takes you back to the image selection

Basically i wanna simplfy the whole thing so its much more effiecent than having to work with so many objects.

Here's a few quick screenshots and a link to the project file.

Any help would be greatly appreciated.

Download Link

View attachment 29402View attachment 29403View attachment 29404View attachment 29405
Nice project.

Here are some tips:
1) You can group together sprites and objects that are very similar in sub folders.
In the resource tree (menu on the left side), right click on "Sprites" and click on "Create Group", you can create subfolders.
This helps keeping projects with lots of resources overviewable.

2) Learn about arrays.
You can store any amount of values simultaneously in a single variable by using arrays, which is super helpful for these kind of things.
Read up on them here, as I'll use them quite a bit.

3) Objects in GameMaker have a built-in variable image_blend.
With this variable, you can filter colors out of sprites.
If you have a white square, then the color that will actually be drawn, is exactly the color image_blend is set to.
You can use this to only need 1 obj_bulbasaurX object and only 1 spr_bulbasaurX sprite.
A reference for how you can specify colours in GML can be found here.

For now, just keep this in mind, I'll come back to it later.

4) In obj_selectX, you use drawing functions in a mouse click event.
Generally, drawing functions only work in draw events, so you can get rid of:
GML:
draw_set_font(font0);
draw_set_colour(c_black);
draw_text(100, 100, "1 - " + string(global.bulbasaur1) + "/75")
in the mouse left pressed event of obj_select1 for example.

5) You only need 1 obj_select and you don't need the global.bulbasaurX variables.
You can derive the amount of squares that still need to be painted by counting the amount of obj_X instances in the room.
You can derive the value to which global.bulbasaurcolor needs to be set when clicking on an obj_select instance by looking at the y-value.

This means that you can remove all your obj_selectX objects and create a new object_select object with:
- spr_select as sprite
- as create event:
GML:
my_index = (y - 192) / 32;
- as step event:
GML:
var obj_X;
obj_X[0] = obj_1;
obj_X[1] = obj_2;
obj_X[2] = obj_3;
obj_X[3] = obj_4;
obj_X[4] = obj_5;
obj_X[5] = obj_6;
obj_X[6] = obj_7;
obj_X[7] = obj_8;
obj_X[8] = obj_9;
obj_X[9] = obj_10;
obj_X[10] = obj_11;
obj_X[11] = obj_12;
obj_X[12] = obj_13;
obj_X[13] = obj_14;
obj_X[14] = obj_15;
obj_X[15] = obj_16;
if instance_number(obj_X[my_index]) == 0 {
    instance_change(obj_done, false);
}
- as mouse left pressed event:
GML:
global.bulbasaurcolor = my_index + 1;
6) Let's now tackle the bottleneck of your project: converting an image into objects per pixel.
Ideally, you should just have to add a sprite and have some code that automatically converts this sprite into the desired objects.
For this, we need a system to iterate through every pixel of the image however.
We can perform iterations using for-loops.
We are able to extract colors from sprites using surfaces in combination with buffers.
It's a lot to take in at once if you're new to GameMaker, but it will make development for this project a lot easier.

I'll also be using the with construction, the other keyword, list data structures, the increment operator, local scope variables and some common built-in functions.

Rename spr_bulbasaur2 to spr_image_pixel.
Remove spr_bulbasaur1 and spr_bulbasaur3 through spr_bulbasaur16.
Rename obj_bulbasaur2 to obj_image_pixel.
Remove obj_bulbasaur1 and obj_bulbasaur3 through obj_bulbasaur16.

Create a new object called obj_sprite_converter.
Put in its create event:

GML:
var obj_X;
obj_X[0] = obj_1;
obj_X[1] = obj_2;
obj_X[2] = obj_3;
obj_X[3] = obj_4;
obj_X[4] = obj_5;
obj_X[5] = obj_6;
obj_X[6] = obj_7;
obj_X[7] = obj_8;
obj_X[8] = obj_9;
obj_X[9] = obj_10;
obj_X[10] = obj_11;
obj_X[11] = obj_12;
obj_X[12] = obj_13;
obj_X[13] = obj_14;
obj_X[14] = obj_15;
obj_X[15] = obj_16;

var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var temp_surf = surface_create(w, h);
surface_set_target(temp_surf);
draw_clear_alpha(c_black, 0);
draw_sprite(global.sprite_to_convert, 0, 0, 0);
surface_reset_target();
var temp_buff = buffer_create(w * h * 4, buffer_grow, 1);
buffer_get_surface(temp_buff, temp_surf, 0, 0, 0);
for(var i = 0; i < w; i++) {
    for(var j = 0; j < h; j++) {
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
        var alpha = buffer_read(temp_buff, buffer_u8) / 255;
        if alpha > 0 {
            var color = make_colour_rgb(red, green, blue);
            var color_index = ds_list_find_index(global.color_list, color);
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
            pixel_inst.my_color = color;
        }
    }
}
buffer_delete(temp_buff);
surface_free(temp_surf);

for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var ox = 32;
    var oy = 192 + k * 32;
    var select_background_inst = instance_create(ox, oy, obj_image_pixel);
    select_background_inst.image_blend = ds_list_find_value(global.color_list, k);
    select_background_inst.image_xscale = 2;
    select_background_inst.image_yscale = 2;
    instance_create(ox, oy, obj_select);
}

instance_destroy();
Now add a new sprite containing bulbasaur and call it spr_bulbasaur.

Then create a new room called rm_paint_bulbasaur and put it as first room.
Give this room a width of 1920 and a height of 1080.
Put an instance of object obj_game and object obj_brush in the room.
In the room creation code, put:
GML:
global.sprite_to_convert = spr_img_test;
global.color_list = ds_list_create();
ds_list_add(global.color_list, make_colour_rgb(54, 59, 79));
ds_list_add(global.color_list, make_colour_rgb(255, 255, 255));
ds_list_add(global.color_list, make_colour_rgb(156, 27, 48));
ds_list_add(global.color_list, make_colour_rgb(76, 17, 26));
// Repeat this for all the remaining colors
instance_create(0, 0, obj_sprite_converter);
Finally, change every collision event of obj_brush with obj_X to:
GML:
// Replace X with the appropriate number
if global.bulbasaurcolor == X {
    with other {
        instance_change(obj_image_pixel, false);
        image_blend = ds_list_find_value(global.color_list, X - 1);
    }
    global.bulbasaurtotal += 1;
}
And run the game to see the results.
Everything should still work the same, but it is all generated from a sprite now.

7) I can still further improve the design by e.g. getting rid of the multiple obj_X objects,
but I think this is already a lot to process and understand and that you will already be able to quickly expand your project now.

I hope this helps.
If you have any questions, feel free to ask them!
 
Last edited:

Callam

Member
Thanks for all the response, much appreciated, i intend to try each on one of them, however with my basic understanding i may fail at impleting them

@jo-thijs


I believe i've followed your guide exactly however i'm getting this error message

Download

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

Push :: Execution Error - Variable Index [0,17] out of range [1,16] - -7.obj_X(100001,17)
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 37) - var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 37)
called from - gml_Room_rm_paint_bulbasaur_Create (line 23) - instance_create(0, 0, obj_sprite_converter);
 
Last edited:

TsukaYuriko

Q&A Spawn Camper
Forum Staff
Moderator
You're trying to access index 17, which is outside of the size 16. A size of 16 means the maximum accessible index there is 15 (0~15, 16 elements, so size 16). 17 is two above the limit.
 

jo-thijs

Member
Thanks for all the response, much appreciated, i intend to try each on one of them, however with my basic understanding i may fail at impleting them

@jo-thijs


I believe i've followed your guide exactly however i'm getting this error message


___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

Push :: Execution Error - Variable Index [0,17] out of range [1,16] - -7.obj_X(100001,17)
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 37) - var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 37)
called from - gml_Room_rm_paint_bulbasaur_Create (line 23) - instance_create(0, 0, obj_sprite_converter);
You're trying to access index 17, which is outside of the size 16. A size of 16 means the maximum accessible index there is 15 (0~15, 16 elements, so size 16). 17 is two above the limit.
Correct. This means that you've specified at least 18 colors in the room creation code, while I hadn't made a suggestion yet to generalize obj_X, so you can currently only use 16 colors.
To get around this limitation:
1) Create a font for the digits that are used in spr_1 through spr_18.
2) Create a sprite looking exactly like spr_1, but without any digits and call it spr_image_pixel_uncolored.
3) Remove spr_1 through spr_18.
4) Create a new object called spr_image_pixel_uncolored with:
spr_image_pixel_uncolored as sprite,
create event:
GML:
image_speed = 0;
step event:
GML:
if global.bulbasaurcolor = my_color_index {
    image_index = 1;
} else {
    image_index = 0;
}
5) Remove obj_1 through obj_16.
6) In the create event of obj_sprite_converter, remove these lines at the start:
GML:
var obj_X;
obj_X[0] = obj_1;
obj_X[1] = obj_2;
obj_X[2] = obj_3;
obj_X[3] = obj_4;
obj_X[4] = obj_5;
obj_X[5] = obj_6;
obj_X[6] = obj_7;
obj_X[7] = obj_8;
obj_X[8] = obj_9;
obj_X[9] = obj_10;
obj_X[10] = obj_11;
obj_X[11] = obj_12;
obj_X[12] = obj_13;
obj_X[13] = obj_14;
obj_X[14] = obj_15;
obj_X[15] = obj_16;
and replace this line:
GML:
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
with these lines:
GML:
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_image_pixel_uncolored);
            pixel_inst.my_color_index = color_index;
7) Create a script scr_count_uncolored_image_pixels_with_index:
GML:
var count = 0;
with obj_image_pixel_uncolored {
    if my_color_index = argument0 {
        count += 1;
    }
}
return count;
8) Replace the step event of obj_select with:
GML:
if scr_count_uncolored_image_pixels_with_index(my_index) == 0 {
    instance_change(obj_done, false);
}
9) In obj_brush, add a collision event with obj_image_pixel_uncolored with as code:
GML:
if global.bulbasaurcolor == other.my_color_index + 1 {
    with other {
        instance_change(obj_image_pixel, false);
        image_blend = ds_list_find_value(global.color_list, my_color_index);
    }
    global.bulbasaurtotal += 1;
}
And that should fix that.

I also just noticed I forgot to take obj_bulbasaurcount and obj_congrats into account in my previous post.
So, also:
10) Change the step event of obj_bulbasaurcount to:
GML:
if !instance_exists(obj_image_pixel_uncolored) {
    instance_create(512, 512, obj_congrats);
}
11) Create a new script scr_count_colored_image_pixels_with_index:
GML:
var count = 0;
var color = ds_list_find_value(global.color_list, argument0);
with obj_image_pixel {
    if image_blend == color {
        count += 1;
    }
}
return count;
12) Change the draw event of obj_bulbasaurcount to:
GML:
draw_set_font(font0);
draw_set_colour(c_black);
for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var count_uncolored = scr_count_uncolored_image_pixels_with_index(k);
    var count_colored = scr_count_colored_image_pixels_with_index(k);
    draw_text(1692, 5 + k * 15, string(k + 1) + " - " + string(count_colored) + "/" + string(count_colored + count_uncolored));
}
var k = ds_list_size(global.color_list);
var count_uncolored = instance_number(obj_image_pixel_uncolored);
var count_colored = instance_number(obj_image_pixel);
draw_text(1692, 5 + k * 15, "Total - " + string(count_colored) + "/" + string(count_colored + count_uncolored));
EDIT:
Oh, I forgot a step:
In the draw event of obj_image_pixel_uncolored, put:
GML:
draw_self();
draw_set_halign(fa_center);
draw_set_valign(fa_middle);
draw_set_color(c_black);
draw_set_font(fnt_insert_your_font_name_here);
draw_text(x + 8, y + 8, my_color_index + 1)
draw_set_halign(fa_left);
draw_set_valign(fa_top);
 
Last edited:

Callam

Member
Thanks for response, this has definitely thinned out the objects, im getting this error however. Something about color_index not being set before being read?. Sorry i know i'm being incredibly nooby right now, once this is working fine then i can anaylze all the code and understand it


___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

local variable color_index(100001, -2147483648) not set before reading it.
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 1) - var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 1)
called from - gml_Room_rm_paint_bulbasaur_Create (line 23) - instance_create(0, 0, obj_sprite_converter);
 

jo-thijs

Member
Thanks for response, this has definitely thinned out the objects, im getting this error however. Something about color_index not being set before being read?. Sorry i know i'm being incredibly nooby right now, once this is working fine then i can anaylze all the code and understand it


___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

local variable color_index(100001, -2147483648) not set before reading it.
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 1) - var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_X[color_index]);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 1)
called from - gml_Room_rm_paint_bulbasaur_Create (line 23) - instance_create(0, 0, obj_sprite_converter);
I think something went wrong in step 6 in my second post.
I have this as the create event of obj_sprite_converter:
GML:
var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var temp_surf = surface_create(w, h);
surface_set_target(temp_surf);
draw_clear_alpha(c_black, 0);
draw_sprite(global.sprite_to_convert, 0, 0, 0);
surface_reset_target();
var temp_buff = buffer_create(w * h * 4, buffer_grow, 1);
buffer_get_surface(temp_buff, temp_surf, 0, 0, 0);
for(var i = 0; i < w; i++) {
    for(var j = 0; j < h; j++) {
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
        var alpha = buffer_read(temp_buff, buffer_u8) / 255;
        if alpha > 0 {
            var color = make_colour_rgb(red, green, blue);
            var color_index = ds_list_find_index(global.color_list, color);
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_image_pixel_uncolored);
            pixel_inst.my_color_index = color_index;
            pixel_inst.my_color = color;
        }
    }
}
buffer_delete(temp_buff);
surface_free(temp_surf);

for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var ox = 32;
    var oy = 192 + k * 32;
    var select_background_inst = instance_create(ox, oy, obj_bulbasaur2);
    select_background_inst.image_blend = ds_list_find_value(global.color_list, k);
    select_background_inst.image_xscale = 2;
    select_background_inst.image_yscale = 2;
    instance_create(ox, oy, obj_select);
}

instance_destroy();
If you use this code, does it still give the same error?
 

Callam

Member
I think something went wrong in step 6 in my second post.
I have this as the create event of obj_sprite_converter:
GML:
var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var temp_surf = surface_create(w, h);
surface_set_target(temp_surf);
draw_clear_alpha(c_black, 0);
draw_sprite(global.sprite_to_convert, 0, 0, 0);
surface_reset_target();
var temp_buff = buffer_create(w * h * 4, buffer_grow, 1);
buffer_get_surface(temp_buff, temp_surf, 0, 0, 0);
for(var i = 0; i < w; i++) {
    for(var j = 0; j < h; j++) {
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
        var alpha = buffer_read(temp_buff, buffer_u8) / 255;
        if alpha > 0 {
            var color = make_colour_rgb(red, green, blue);
            var color_index = ds_list_find_index(global.color_list, color);
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_image_pixel_uncolored);
            pixel_inst.my_color_index = color_index;
            pixel_inst.my_color = color;
        }
    }
}
buffer_delete(temp_buff);
surface_free(temp_surf);

for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var ox = 32;
    var oy = 192 + k * 32;
    var select_background_inst = instance_create(ox, oy, obj_bulbasaur2);
    select_background_inst.image_blend = ds_list_find_value(global.color_list, k);
    select_background_inst.image_xscale = 2;
    select_background_inst.image_yscale = 2;
    instance_create(ox, oy, obj_select);
}

instance_destroy();
If you use this code, does it still give the same error?
its gives me this error


___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

global variable name 'sprite_to_convert' index (100041) not set before reading it.
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 1) - var w = sprite_get_width(global.sprite_to_convert);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 1)
 

jo-thijs

Member
its gives me this error


___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_sprite_converter:

global variable name 'sprite_to_convert' index (100041) not set before reading it.
at gml_Object_obj_sprite_converter_CreateEvent_1 (line 1) - var w = sprite_get_width(global.sprite_to_convert);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_sprite_converter_CreateEvent_1 (line 1)
Have you put obj_sprite_converter in the rm_paint_bulbasaur?
Because you're not supposed to do that, the instance should get created in the room creation code.

Also, do you have this line in the room creation code of rm_paint_bulbasaur?
GML:
global.sprite_to_convert = spr_bulbasaur;
That should have set the global variable.
 

Callam

Member
Have you put obj_sprite_converter in the rm_paint_bulbasaur?
Because you're not supposed to do that, the instance should get created in the room creation code.

Also, do you have this line in the room creation code of rm_paint_bulbasaur?
GML:
global.sprite_to_convert = spr_bulbasaur;
That should have set the global variable.
followed those steps no errors, just a blank screen now.

ill put a link to download, might be easier for you to look and see if you can find the problem than having to ask me a million different things

screenshot.png
 

jo-thijs

Member
followed those steps no errors, just a blank screen now.

ill put a link to download, might be easier for you to look and see if you can find the problem than having to ask me a million different things

View attachment 29449
Ok, try the following steps:
1) Use this as room creation code:
GML:
global.sprite_to_convert = spr_bulbasaur;
global.color_list = ds_list_create();
ds_list_add(global.color_list, make_colour_rgb(54, 59, 79));
ds_list_add(global.color_list, make_colour_rgb(255, 255, 255));
ds_list_add(global.color_list, make_colour_rgb(156, 27, 48));
ds_list_add(global.color_list, make_colour_rgb(76, 17, 26));
ds_list_add(global.color_list, make_colour_rgb(172, 114, 151));
ds_list_add(global.color_list, make_colour_rgb(97, 59, 84));
ds_list_add(global.color_list, make_colour_rgb(192, 201, 234));
ds_list_add(global.color_list, make_colour_rgb(39, 69, 65));
ds_list_add(global.color_list, make_colour_rgb(82, 145, 115));
ds_list_add(global.color_list, make_colour_rgb(63, 115, 109));
ds_list_add(global.color_list, make_colour_rgb(107, 185, 146));
ds_list_add(global.color_list, make_colour_rgb(44, 93, 64));
ds_list_add(global.color_list, make_colour_rgb(61, 112, 82));
ds_list_add(global.color_list, make_colour_rgb(32, 62, 35));
ds_list_add(global.color_list, make_colour_rgb(108, 181, 106));
ds_list_add(global.color_list, make_colour_rgb(63, 127, 70));
instance_create(0, 0, obj_sprite_converter);
2) Create a new object called obj_select_background with spr_image_pixel as sprite.

3) Change the create event of obj_sprite_converter to:
GML:
var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var temp_surf = surface_create(w, h);
surface_set_target(temp_surf);
draw_clear_alpha(c_black, 0);
draw_sprite(global.sprite_to_convert, 0, 0, 0);
surface_reset_target();
var temp_buff = buffer_create(w * h * 4, buffer_grow, 1);
buffer_get_surface(temp_buff, temp_surf, 0, 0, 0);
for(var j = 0; j < h; j++) {
    for(var i = 0; i < w; i++) {
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
        var alpha = buffer_read(temp_buff, buffer_u8) / 255;
        if alpha > 0 {
            var color = make_colour_rgb(red, green, blue);
            var color_index = ds_list_find_index(global.color_list, color);
            var pixel_inst = instance_create(432 + i * 16, 48 + j * 16, obj_image_pixel_uncolored);
            pixel_inst.my_color_index = color_index;
            pixel_inst.my_color = color;
        }
    }
}
buffer_delete(temp_buff);
surface_free(temp_surf);

for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var ox = 32;
    var oy = 192 + k * 32;
    var select_background_inst = instance_create(ox, oy, obj_select_background);
    select_background_inst.image_blend = ds_list_find_value(global.color_list, k);
    select_background_inst.image_xscale = 2;
    select_background_inst.image_yscale = 2;
    instance_create(ox, oy, obj_select);
}

instance_destroy();
4) Scale spr_bulbasaur down by 50% in both width and height.

5) Change the step event of obj_image_pixel_uncolored to:
GML:
if global.bulbasaurcolor = my_color_index + 1 {
    image_index = 1;
} else {
    image_index = 0;
}
6) If you run the project now, you'll see some number 0s.
These correspond to pixels in spr_bulbasaur that are slightly different than the color you gave them in your original version.
Fix those differences in the sprite.

7) Put an instance of obj_bulbasaur_count in the room.

8) Change font0 to font1 in the draw event of obj_bulbasaur_count.
 

Callam

Member
Ok, try the following steps:
Followed the steps and OMG it works. Wasn't expecting that, ran the game and boom there it is in all of its glory. i tested it and everything seems to work fine the only problem im having is the color palette on the game doesnt match up to the sprite. I checked the room creation code numbers, and they all match the sprite colors, so im not sure what the problem is.

Also is it possible to number the select buttons like the pixels to be colored? so its easier to see what your selecting

Thanks again man, i appreicate the amount of effort your putting into helping me

screenshot.png
 

jo-thijs

Member
Followed the steps and OMG it works. Wasn't expecting that, ran the game and boom there it is in all of its glory. i tested it and everything seems to work fine the only problem im having is the color palette on the game doesnt match up to the sprite. I checked the room creation code numbers, and they all match the sprite colors, so im not sure what the problem is.

Also is it possible to number the select buttons like the pixels to be colored? so its easier to see what your selecting

Thanks again man, i appreicate the amount of effort your putting into helping me

View attachment 29455
That looks like colors are stored in RGBA (red - green - blue - alpha) format in buffers on your device whereas they are stored in BGRA (blue - green - red - alpha) format on my device...
The docs state that on a windows target a BGRA format is used however.
Are you using a different target?

In any case, you can fix the color pallet for you locally by changing these lines in the create event of obj_sprite_converter:
GML:
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
to:
GML:
        var red = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var blue = buffer_read(temp_buff, buffer_u8);
 

Callam

Member
That looks like colors are stored in RGBA (red - green - blue - alpha) format in buffers on your device whereas they are stored in BGRA (blue - green - red - alpha) format on my device...
The docs state that on a windows target a BGRA format is used however.
Are you using a different target?

In any case, you can fix the color pallet for you locally by changing these lines in the create event of obj_sprite_converter:
GML:
        var blue = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var red = buffer_read(temp_buff, buffer_u8);
to:
GML:
        var red = buffer_read(temp_buff, buffer_u8);
        var green = buffer_read(temp_buff, buffer_u8);
        var blue = buffer_read(temp_buff, buffer_u8);
Thats fixed the color issues, everything seems to be working good. Is it not possible then to add numbers to the selectors?

How i add more images? im presuming its not gonna be as simple as just adding a new room with new code and a new sprite
 
Last edited:

jo-thijs

Member
Thats fixed the color issues, everything seems to be working good.
Yes, just be aware that the colors may currently be weird again when you test it on an other device.

Is it not possible then to add numbers to the selectors?
It sure is possible.
In the draw event of obj_selector, put:
GML:
draw_self();

draw_set_font(font1);
draw_set_color(c_black);
draw_set_halign(fa_center);
draw_set_valign(fa_middle);
draw_text(x + 16, y + 16, my_index + 1);
draw_set_valign(fa_top);
draw_set_halign(fa_left);
How i add more images? im presuming its not gonna be as simple as just adding a new room with new code and a new sprite
It sure is. That's the entire point behind obj_sprite_converter.
You create your new sprite.
You create a new room.
You put in the new room an instance of obj_game, obj_brush and obj_bulbasaur_count.
And finally, you put some code in the room creation code where:
1) you set global.sprite_to_convert to the sprite you need to the new sprite,
2) you set global.color_list to a new list containing every selectable color, and
3) you create an instance of obj_sprite_converter.
 

Callam

Member
was so easy to add new stuff, however the problem im having is the sprite hangs off the screen, is there a way to change it without having to scale the sprite down more as it goes all blurry


is it possible to save a specific rooms info, the default save load functions act all weird, for example if i save bulbasaur half done then go to ivysaur and hit load, itll autmatically fill in random colors on ivysaur and throw up the congratulations message

thanks
screenshot.png
screenshot 2.png
 

TsukaYuriko

Q&A Spawn Camper
Forum Staff
Moderator
If the sprite is too big to fit into the room, you have to either make the room bigger, or make the tiles representing the pixels smaller. Use the biggest sprite you have as a reference for the maximum size when making either of these changes so you won't have to do this again in the future.

Default saving and loading is not to be used when dynamic data structures are in use, as they will not be saved and loaded properly (and by that, I mean not at all). You'll have to rely on a custom saving and loading mechanism here.
 

jo-thijs

Member
was so easy to add new stuff, however the problem im having is the sprite hangs off the screen, is there a way to change it without having to scale the sprite down more as it goes all blurry
If the sprite is too big to fit into the room, you have to either make the room bigger, or make the tiles representing the pixels smaller. Use the biggest sprite you have as a reference for the maximum size when making either of these changes so you won't have to do this again in the future.
Correct, but there is also a third option: make the drawing zoomable and scrollable.
At the moment, I lack. time to create an example of how to do this, but I'll get to it when I can.

is it possible to save a specific rooms info, the default save load functions act all weird, for example if i save bulbasaur half done then go to ivysaur and hit load, itll autmatically fill in random colors on ivysaur and throw up the congratulations message
Default saving and loading is not to be used when dynamic data structures are in use, as they will not be saved and loaded properly (and by that, I mean not at all). You'll have to rely on a custom saving and loading mechanism here.
Correct. You could for example save the state of the bulbasaur drawing to a text file called bulbasaur.sav.
You can then have a line of text for each row of pixels in the bulbasaur drawing and have the n-th character in the file correspond to the n-th pixel in the row.
You can then use the character 1 to indicate the pixel has been colored, 0 to indicate it has not been colored yet and a space to indicate background.
It's by far not the most optimal saving method (in terms of disk space), but it is quite visual and easy to reason about.
Saving the state of the ivysaur drawing would then work similarly for the text file ivysaur.sav.
Again, at the moment I lack time to create a full example of how to do this, but I'll get to it once I can.
 

Callam

Member
Correct, but there is also a third option: make the drawing zoomable and scrollable.
At the moment, I lack. time to create an example of how to do this, but I'll get to it when I can.



Correct. You could for example save the state of the bulbasaur drawing to a text file called bulbasaur.sav.
You can then have a line of text for each row of pixels in the bulbasaur drawing and have the n-th character in the file correspond to the n-th pixel in the row.
You can then use the character 1 to indicate the pixel has been colored, 0 to indicate it has not been colored yet and a space to indicate background.
It's by far not the most optimal saving method (in terms of disk space), but it is quite visual and easy to reason about.
Saving the state of the ivysaur drawing would then work similarly for the text file ivysaur.sav.
Again, at the moment I lack time to create a full example of how to do this, but I'll get to it once I can.
Gonna play around with some the things TsukaYuriko said on a backup file incase i invetibly mess up. If you could show me the save/laod system and make it scrollable and zoomable whenever you have the free time thatd be appriecated. I did want to have the zoomable feature it was something id seen in other similar games and thought worked great
 

chamaeleon

Member
Gonna play around [...] on a backup file
If your project is important to you, please, please implement an automated backup solution and version control. When it comes to backups it should not be something you have to think about, it should just happen regularly without your intervention. It is fine of course to create a copy of a project to play around with and perhaps delete after, but please don't use this as your backup solution.
 
  • Like
Reactions: Yal

Callam

Member
If your project is important to you, please, please implement an automated backup solution and version control. When it comes to backups it should not be something you have to think about, it should just happen regularly without your intervention. It is fine of course to create a copy of a project to play around with and perhaps delete after, but please don't use this as your backup solution.
Thats actually something ive never considered, ive jsut always done the old copy and paste. Screwed up once and lost a project but it was still basic ideas/concept testing so it was maybe an hours work. I will definitely have to do this, thanks
 

GMWolf

aka fel666
Thats actually something ive never considered, ive jsut always done the old copy and paste. Screwed up once and lost a project but it was still basic ideas/concept testing so it was maybe an hours work. I will definitely have to do this, thanks
If you are looking to go further with you Game Dev career and are willing to invest the timr then I would highly recommend using source control. It may seem intimidating at first but it will save you from a lot of pain and misery down the line.
Probably not worth applying to every project (until you are proficient with it) but if a project is lasting more than a couple weeks SCM becomes a great ally.
 

jo-thijs

Member
was so easy to add new stuff, however the problem im having is the sprite hangs off the screen, is there a way to change it without having to scale the sprite down more as it goes all blurry
If the sprite is too big to fit into the room, you have to either make the room bigger, or make the tiles representing the pixels smaller. Use the biggest sprite you have as a reference for the maximum size when making either of these changes so you won't have to do this again in the future.
Correct, but there is also a third option: make the drawing zoomable and scrollable.
At the moment, I lack. time to create an example of how to do this, but I'll get to it when I can.
Ok, so I got around creating a zoomable and scrollable example.
There were many ways to tackle this, but I decided to use views.
I split the screen up in 2 separate views, one for the select bar (that shouldn't zoom) and one for the drawing (that should zoom).
Some things can appear on both sides of the screen, while they should not zoom either (like the brush or the congrats or the pixel count information).
These objects use the draw GUI event to always be properly drawn.
Of course, when dragging the view around, you want to measure mouse coordinates relative to the screen, not the room (otherwise, you would get jumpy effects).
So, instead of using mouse_x and mouse_y, I used device_mouse_x_to_gui(0) and device_mouse_y_to_gui(0).
Here are the steps to take:
1) Create a new object called obj_zoom_controller, with as:
- create event:
GML:
var spr_w = sprite_get_width(global.sprite_to_convert);
var spr_h = sprite_get_height(global.sprite_to_convert);

screen_width = 1920;
screen_height = 1080;
screen_xdivide = 320;

left_limit = 320;
top_limit = 0;
right_limit = max(screen_width, left_limit + (spr_w + 14) * 16);
bottom_limit = max(screen_height, top_limit + (spr_h + 6) * 16);

view_xport[0] = 0;
view_yport[0] = 0;
view_wport[0] = screen_xdivide;
view_hport[0] = screen_height;
view_xview[0] = 0;
view_yview[0] = 0;
view_wview[0] = screen_xdivide;
view_hview[0] = screen_height;
view_visible[0] = true;

view_xport[1] = screen_xdivide;
view_yport[1] = 0;
view_wport[1] = screen_width - screen_xdivide;
view_hport[1] = screen_height;
view_xview[1] = left_limit;
view_yview[1] = top_limit;
view_wview[1] = screen_width - screen_xdivide;
view_hview[1] = screen_height;
view_visible[1] = true;

view_enabled = true;

zoom_factor = 0.875;

drag_x = 0;
drag_y = 0;
dragging = false;
- step event:
GML:
if mouse_check_button(mb_left) {
    var new_drag_x = device_mouse_x_to_gui(0);
    var new_drag_y = device_mouse_y_to_gui(0);
    if dragging {
        var scale = view_wview[1] / view_wport[1];
        var px = view_xview[1];
        var py = view_yview[1];
        var nx = clamp(px - (new_drag_x - drag_x) * scale, left_limit, right_limit - view_wview[1]);
        var ny = clamp(py - (new_drag_y - drag_y) * scale, top_limit, bottom_limit - view_hview[1]);
        view_xview[1] = nx;
        view_yview[1] = ny;
        drag_x -= (nx - px) / scale;
        drag_y -= (ny - py) / scale;
    } else if new_drag_x > screen_xdivide {
        drag_x = new_drag_x;
        drag_y = new_drag_y;
        dragging = true;
    }
} else {
    dragging = false;
}
- mouse wheel up event:
GML:
var x_factor = (device_mouse_x(0) - view_xview[1]) / view_wview[1];
var y_factor = (device_mouse_y(0) - view_yview[1]) / view_hview[1];
var mx = view_xview[1] + view_wview[1] * x_factor;
var my = view_yview[1] + view_hview[1] * y_factor;
var new_width = view_wview[1] * zoom_factor;
var new_height = view_hview[1] * zoom_factor;

if new_height >= 540 {
    view_wview[1] = new_width;
    view_hview[1] = new_height;
    view_xview[1] = clamp(mx - view_wview[1] * x_factor, left_limit, right_limit - view_wview[1]);
    view_yview[1] = clamp(my - view_hview[1] * y_factor, top_limit, bottom_limit - view_hview[1]);
}
- mouse wheel down event:
GML:
var x_factor = (device_mouse_x(0) - view_xview[1]) / view_wview[1];
var y_factor = (device_mouse_y(0) - view_yview[1]) / view_hview[1];
var mx = view_xview[1] + view_wview[1] * x_factor;
var my = view_yview[1] + view_hview[1] * y_factor;
var new_width = view_wview[1] / zoom_factor;
var new_height = view_hview[1] / zoom_factor;

if new_width <= right_limit - left_limit && new_height <= bottom_limit - top_limit  {
    view_wview[1] = new_width;
    view_hview[1] = new_height;
    view_xview[1] = clamp(mx - view_wview[1] * x_factor, left_limit, right_limit - view_wview[1]);
    view_yview[1] = clamp(my - view_hview[1] * y_factor, top_limit, bottom_limit - view_hview[1]);
}
2) Extend the room creation code with:
GML:
instance_create(0, 0, obj_zoom_controller);
3) Change the collision event of obj_brush to an end step event with as code:
GML:
with instance_position(mouse_x, mouse_y, obj_image_pixel_uncolored) {
    with other {
        if global.bulbasaurcolor == other.my_color_index + 1 {
            with other {
                instance_change(obj_image_pixel, false);
                image_blend = ds_list_find_value(global.color_list, my_color_index);
            }
            global.bulbasaurtotal += 1;
        }
    }
}
4) Add a draw event to obj_brush with as code:
GML:
///Draw nothing
5) Add a draw GUI event to obj_brush with as code:
GML:
draw_sprite(sprite_index, -1, device_mouse_x_to_gui(0), device_mouse_y_to_gui(0));
6) Change the draw event of obj_bulbasaurcount into a draw GUI event with as code:
GML:
draw_set_color(c_white);
draw_rectangle(1687, 0, 1920, 10 + (ds_list_size(global.color_list) + 1) * 15, false);
draw_set_font(font1);
draw_set_colour(c_black);
for(var k = 0; k < ds_list_size(global.color_list); k++) {
    var count_uncolored = scr_count_uncolored_image_pixels_with_index(k);
    var count_colored = scr_count_colored_image_pixels_with_index(k);
    draw_text(1692, 5 + k * 15, string(k + 1) + " - " + string(count_colored) + "/" + string(count_colored + count_uncolored));
}
var k = ds_list_size(global.color_list);
var count_uncolored = instance_number(obj_image_pixel_uncolored);
var count_colored = instance_number(obj_image_pixel);
draw_text(1692, 5 + k * 15, "Total - " + string(count_colored) + "/" + string(count_colored + count_uncolored));
7) Add a draw event to obj_congrats with as code:
GML:
///Draw nothing
8) Add a Draw GUI event to obj_congrats with as code:
GML:
draw_self();
 

jo-thijs

Member
is it possible to save a specific rooms info, the default save load functions act all weird, for example if i save bulbasaur half done then go to ivysaur and hit load, itll autmatically fill in random colors on ivysaur and throw up the congratulations message
Default saving and loading is not to be used when dynamic data structures are in use, as they will not be saved and loaded properly (and by that, I mean not at all). You'll have to rely on a custom saving and loading mechanism here.
Correct. You could for example save the state of the bulbasaur drawing to a text file called bulbasaur.sav.
You can then have a line of text for each row of pixels in the bulbasaur drawing and have the n-th character in the file correspond to the n-th pixel in the row.
You can then use the character 1 to indicate the pixel has been colored, 0 to indicate it has not been colored yet and a space to indicate background.
It's by far not the most optimal saving method (in terms of disk space), but it is quite visual and easy to reason about.
Saving the state of the ivysaur drawing would then work similarly for the text file ivysaur.sav.
Again, at the moment I lack time to create a full example of how to do this, but I'll get to it once I can.
And I got around doing this.

I actually didn't notice before that you already started implementing your own save mechanics.
You only saved statistics there however, rather than the state of every pixel.

Try this:
1) Add this to every room creation code:
GML:
global.save_file_name = "bulbasaur.sav"; // Change bulbasaur.sav to the filmename for the current drawing
2) Change scr_savegame to:
GML:
var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var f = file_text_open_write(global.save_file_name);
for (var i = 0; i < w; i++) {
    for (var j = 0; j < h; j++) {
        var X = 432 + 8 + i * 16;
        var Y = 48 + 8 + j * 16;
        var c;
        if position_meeting(X, Y, obj_image_pixel_uncolored) {
            c = '0';
        } else if position_meeting(X, Y, obj_image_pixel) {
            c = '1';
        } else {
            c = ' ';
        }
        file_text_write_string(f, c);
    }
    file_text_writeln(f);
}
file_text_close(f);
3) Change scr_loadgame to:
GML:
if file_exists(global.save_file_name) {
    var w = sprite_get_width(global.sprite_to_convert);
    var h = sprite_get_height(global.sprite_to_convert);
    var f = file_text_open_read(global.save_file_name);
    for (var i = 0; i < w; i++) {
        var line = file_text_read_string(f);
        for (var j = 0; j < h; j++) {
            if string_length(line) > 0 {
                var c = string_char_at(line, 1);
                line = string_delete(line, 1, 1);
                var X = 432 + 8 + i * 16;
                var Y = 48 + 8 + j * 16;
                switch c {
                case '0':
                    with instance_position(X, Y, obj_image_pixel) {
                        with instance_create(x, y, obj_image_pixel_uncolored) {
                            my_color_index = ds_list_find_index(global.color_list, other.image_blend);
                        }
                        instance_destroy();
                    }
                    break;
                case '1':
                    with instance_position(X, Y, obj_image_pixel_uncolored) {
                        with instance_create(x, y, obj_image_pixel) {
                            image_blend = ds_list_find_value(global.color_list, other.my_color_index);
                        }
                        instance_destroy();
                    }
                    break;
                }
            }
        }
        file_text_readln(f);
    }
    file_text_close(f);
   
    with obj_done {
        instance_create(x, y, obj_select);
        instance_destroy();
    }
   
    with obj_congrats {
        instance_destroy();
    }
}
And that should do the trick.

I did notice however I made a mistake in the step event of obj_bulbasaurcount, spawning a new instance of obj_congratulations every frame.
So, also change that step event to:
GML:
if !instance_exists(obj_image_pixel_uncolored)
&& !instance_exists(obj_congrats) {
    instance_create(512, 512, obj_congrats);
}
 
Last edited:

Callam

Member
And I got around doing this.

I actually didn't notice before that you already started implementing your own save mechanics.
You only saved statistics there however, rather than the state of every pixel.

Try this:
1) Add this to every room creation code:
GML:
global.save_file_name = "bulbasaur.sav"; // Change bulbasaur.sav to the filmename for the current drawing
2) Change scr_savegame to:
GML:
var w = sprite_get_width(global.sprite_to_convert);
var h = sprite_get_height(global.sprite_to_convert);
var f = file_text_open_write(global.save_file_name);
for (var i = 0; i < w; i++) {
    for (var j = 0; j < h; j++) {
        var X = 432 + 8 + i * 16;
        var Y = 48 + 8 + j * 16;
        var c;
        if position_meeting(X, Y, obj_image_pixel_uncolored) {
            c = '0';
        } else if position_meeting(X, Y, obj_image_pixel) {
            c = '1';
        } else {
            c = ' ';
        }
        file_text_write_string(f, c);
    }
    file_text_writeln(f);
}
file_text_close(f);
3) Change scr_loadgame to:
Code:
if file_exists(global.save_file_name) {
    var w = sprite_get_width(global.sprite_to_convert);
    var h = sprite_get_height(global.sprite_to_convert);
    var f = file_text_open_read(global.save_file_name);
    for (var i = 0; i < w; i++) {
        var line = file_text_read_string(f);
        for (var j = 0; j < h; j++) {
            if string_length(line) > 0 {
                var c = string_char_at(line, 1);
                line = string_delete(line, 1, 1);
                var X = 432 + 8 + i * 16;
                var Y = 48 + 8 + j * 16;
                switch c {
                case '0':
                    with instance_position(X, Y, obj_image_pixel) {
                        with instance_create(x, y, obj_image_pixel_uncolored) {
                            my_color_index = ds_list_find_index(global.color_list, other.image_blend);
                        }
                        instance_destroy();
                    }
                    break;
                case '1':
                    with instance_position(X, Y, obj_image_pixel_uncolored) {
                        with instance_create(x, y, obj_image_pixel) {
                            image_blend = ds_list_find_value(global.color_list, other.my_color_index);
                        }
                        instance_destroy();
                    }
                    break;
                }
            }
        }
        file_text_readln(f);
    }
    file_text_close(f);
   
    with obj_done {
        instance_create(x, y, obj_select);
        instance_destroy();
    }
   
    with obj_congrats {
        instance_destroy();
    }
}
And that should do the trick.

I did notice however I made a mistake in the step event of obj_bulbasaurcount, spawning a new instance of obj_congratulations every frame.
So, also change that step event to:
Code:
if !instance_exists(obj_image_pixel_uncolored)
&& !instance_exists(obj_congrats) {
    instance_create(512, 512, obj_congrats);
}
you work wonders my friend. and fast too, thank you. You've managed to implement saving/loading and zooming into my game before ive even fixed the sprite being too big for the room issue
 

Callam

Member
And I got around doing this.

I actually didn't notice before that you already started implementing your own save mechanics.
You only saved statistics there however, rather than the state of every pixel.
I'm experiencing a weird issue where it draws a different sprite for what should be in the room, for example i go to rm_paint_charmander, but it also loads rm_paint_squirtle (all in 0) in the background. Doesnt happen everytime strangely

Download
 

Attachments

Last edited:

jo-thijs

Member
I'm experiencing a weird issue where it draws a different sprite for what should be in the room, for example i go to rm_paint_charmander, but it also loads rm_paint_squirtle (all in 0) in the background. Doesnt happen everytime strangely

Download
Strange.
I can only think of 1 reason for this.
Surfaces aren't cleared properly.
We can't read the color of pixels straight from a sprite, so we allocate a surface to draw the sprite onto.
After we created all the uncolored pixel objects, we no longer need the surface, so we free up the resource.
When we later ask for a surface again (because we went to a different image), we may get the previously freed surface served back to us.
When we draw over that, we start with the previous image drawn on it.
However, the strange part is that before drawing the pokemon image to the surface, this line of code is executed:
GML:
draw_clear_alpha(c_black, 0);
This should effectively clear the previous image, but apparently that function isn't working.
It's because of this part in the manual that I was previously unaware of:
This is only for use in the draw event of an instance (it will not show if used in any other event)
This can easily be fixed however.
Replace the line above (calling draw_clear_alpha) in obj_sprite_converter by:
GML:
draw_set_blend_mode_ext(bm_one, bm_zero);
draw_set_color(c_black);
draw_set_alpha(0);
draw_rectangle(0, 0, w, h, false);
draw_set_alpha(1);
draw_set_blend_mode(bm_normal);
Now, I noticed something else that's strange.
In the room creation codes, you fill up global.color_list with the colors from the image.
Colors are created using make_colour_rgb.
However, you always pass the blue component of the color as first argument and the red component as last.
The fact that this shows you the correct colors means that it isn't that your device uses RGBA format in the surface buffer,
but rather that there is a bug on your end with either the function make_colour_rgb or with image_blend.
Either way, that's very strange.
Can you:
1) open a new empty project
2) create a sprite that is a white square
3) create an object with that sprite and with in its create event:
GML:
image_blend = c_red;
show_message("Red: " + string(c_red) + ", Image Blend: " + string(image_blend));
show_message("From RGB: " + make_colour_rgb(127, 63, 31));
4) create a new room and put an instance of the object above in it
5) run the project
6) take not of what the messages popping up say
7) take note of the color of the object
8) share the results with us

Also, I noticed some slight lag when running your project.
I can help out with that if it ever becomes an issue.
I already ran the profiler on it and it would be due to the many draw events being executed by all the uncolored images, which can definitely be improved.
 

Callam

Member
For my actual project your code seems to be working, im not experienceing the issue anymore with my 7 sprites. I went into the different rooms colored some saved backed out and repeated then jumped backwards and forwards and all seemed to be working. Hopefully thats fixed the problem permantly for that


As for the RGB test i created a new project and this happened (See Pic) and then when i hit okay it threw this error message up

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_whitesquare:

DoAdd :: Execution Error
at gml_Object_obj_whitesquare_CreateEvent_1 (line 3) - show_message("From RGB: " + make_colour_rgb(127, 63, 31));
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_whitesquare_CreateEvent_1 (line 3)
 

Attachments

Last edited:

chamaeleon

Member
okay so i created a new project and this happened (See Pic) and then when i hit okay it threw this error message up

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_whitesquare:

DoAdd :: Execution Error
at gml_Object_obj_whitesquare_CreateEvent_1 (line 3) - show_message("From RGB: " + make_colour_rgb(127, 63, 31));
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_whitesquare_CreateEvent_1 (line 3)
You can't add a number to a string. You'll need to wrap make_color_rgb in string().
 

jo-thijs

Member
For my actual project your code seems to be working, im not experienceing the issue anymore with my 7 sprites. I went into the different rooms colored some saved backed out and repeated then jumped backwards and forwards and all seemed to be working. Hopefully thats fixed the problem permantly for that


As for the RGB test i created a new project and this happened (See Pic) and then when i hit okay it threw this error message up

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_whitesquare:

DoAdd :: Execution Error
at gml_Object_obj_whitesquare_CreateEvent_1 (line 3) - show_message("From RGB: " + make_colour_rgb(127, 63, 31));
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_whitesquare_CreateEvent_1 (line 3)
You can't add a number to a string. You'll need to wrap make_color_rgb in string().
Ah yes, sorry for that.
It should have been this code instead:
GML:
image_blend = c_red;
show_message("Red: " + string(c_red) + ", Image Blend: " + string(image_blend));
show_message("From RGB: " + string(make_colour_rgb(127, 63, 31)));
The 255 matches what is expected and what I get on my end.
 

Callam

Member
Ah yes, sorry for that.
It should have been this code instead:
GML:
image_blend = c_red;
show_message("Red: " + string(c_red) + ", Image Blend: " + string(image_blend));
show_message("From RGB: " + string(make_colour_rgb(127, 63, 31)));
The 255 matches what is expected and what I get on my end.
Fixed the code and this is what i get
 

Attachments

jo-thijs

Member
Fixed the code and this is what i get
Ok, that's the expected result for make_colour_rgb, but the unexpected colour for the rectangle.
Apparently, image_blend is broken for you, mixing up blue with red.
I don't know what the reason for this could be.
Maybe something went wrong during the installation of GameMaker?
Maybe a bug occurred in a very specific minor version of GameMaker that you're on?
Maybe it has something to do with the device you're using and/or the target you're compiling for?

Currently, if you're not planning on releasing this project, there is no issue.
If you ever do release it, the color scheme may be messed up for other people.
If drawing rectangles with a certain draw_set_colour works correctly for you, then you can work around the issue by drawing a rectangle rather than a sprite in the draw event of obj_image_pixel.
 

Callam

Member
Ok, that's the expected result for make_colour_rgb, but the unexpected colour for the rectangle.
Apparently, image_blend is broken for you, mixing up blue with red.
I don't know what the reason for this could be.
Maybe something went wrong during the installation of GameMaker?
Maybe a bug occurred in a very specific minor version of GameMaker that you're on?
Maybe it has something to do with the device you're using and/or the target you're compiling for?

Currently, if you're not planning on releasing this project, there is no issue.
If you ever do release it, the color scheme may be messed up for other people.
If drawing rectangles with a certain draw_set_colour works correctly for you, then you can work around the issue by drawing a rectangle rather than a sprite in the draw event of obj_image_pixel.
i created an .exe and sent it to my sister to test on her pc. She got the exact same results i did
 
Top