GameMaker [Solved] Drawing sprite images center-aligned like text

Biosyn

Member
Greetings GMC,

Simple issue. I know we can draw text such that it is center aligned. I'm hoping there's a way to draw a series of sprite images such that they are drawn with center alignment. A for loop can handle drawing a series of sprite images with left/right alignment (using something like x+/-xx*i), but I don't know if there's a way to draw them with center alignment.

To help illustrate the problem, here is an example of drawing one to five circles:

a) Left alignment (doable):

Code:
1: O
2: OO
3: OOO
b) Center alignment (don't know how to do this):

Code:
1:       O
2:      OO
5:     OOOOO
EDIT: text alignment here is a bit off, but hope the general idea is clear.

I tried looking online, but didn't find anything. I'd like to avoid using sprites only to depict the alignment since its massively inefficient to do it that way.

Thanks in advance for any guidance.
 
Last edited:

Niels

Member
Like posted about, easiest way is to set the origin of the sprite to the center.
Second option is to use a + sprite_width /2 offset (asuming origin is still set to the left of the sprite).
 

Biosyn

Member
Thank you both.

I will explain more. The sprite origin is already centered. I'm using the following code to create a row of images using a sprite:

Code:
for (var i = 0; i < 20; ++i) {//
    draw_sprite(spr_icon,0, 100+30*i,300)
}
This draws a row of 20 images, starting with the first icon in the row at position x=100, where x=100 is positioned at the center of the sprite. Each icon has a gap of 30 pixels between each other's sprite center. If I draw another similar row (using "j" instead of "i" in the for loop) below the first one, with more icons in the row, I get the following drawn:

upload_2019-10-18_11-53-28.png



What I want instead is:

upload_2019-10-18_11-53-55.png

Just like how the font function fa_center works to align a drawn text. When more letters are added, it "offsets" each letter in both directions away from the center. I can't seem to find a way to adjust the for loop above to achieve the same effect only for sprite images drawn instead of text.

Thanks!
 

Attachments

It seems like you only need to compute the total width of a row, and then offset the start of that row by half of that width.
However, you'll also need to find which row has the greatest width, because it's mid point will be the location from which you will be offsetting.

If all your sprites are the same size, and the spacing is all uniform too, then the total width of any row with number of sprites (n) above zero, should be: n*(sprite_width+spacing)-spacing

EDIT: Offset calculated above would be to the left-most side of the row. If your sprites' origin is not at the left edge, then you will need to account for that.
 
Last edited:

Biosyn

Member
Thank you @flyingsaucerinvasion

I tried your solution but I'm getting something like the following (the third row is simply for illustration):

upload_2019-10-18_14-5-23.png

I've set the sprite origin to the left-most point (0). The draw code:

Code:
var spacing=30
var sprite_w=10
var start_x=200

var n_i=1
var n_j=3

var total_width_i=n_i*(sprite_w+spacing)-spacing
var total_width_j=n_j*(sprite_w+spacing)-spacing

for (var i = 0; i < n_i; ++i) {//
    draw_sprite(spr_icon,0, start_x+(total_width_i-5)+(spacing*i),250)
}
 
    for (var j = 0; j < n_j; ++j) {//
    draw_sprite(spr_icon,0, start_x+(total_width_j)+(spacing*j),300)
}
Also, just wanted to clarify if the solution provided can be used dynamically. I'm not sure it can work if I needed to draw, say, only one row with one sprite image because of always needing to offset (which wouldn't be needed if only one icon in the row is being drawn at a point) and the need to have more than one rows. Apologies if I've misunderstood.

Thanks!
 
Here's a really simple example:

Code:
    var _sprite_width = 32;
    var _spacing = 10;
    var _y = y;
    for(var n = 1; n <= 10; n += 1){
        var _x = x-(n*(_sprite_width+_spacing)-_spacing)/2;
        repeat(n){
            draw_sprite(spr_yellow_origin0,0,_x,_y);
            _x += _spacing + _sprite_width;
        }
        _y += 48;
    }
Drawing 10 rows, first row has 1 item, each row has 1 more than the previous. The offsets are calculated relative to x,y, which is just the origin of the list or whatever you want to call it.
 

CloseRange

Member
What @flyingsaucerinvasion is correct but I want to provide a more complex answer because I like scripts and I don't see scripts being made so I'm sad.

make a script called draw_row:
Code:
/// @desc draw_row(x, y, count, max_count);
/// @arg x this is the x coord of the row (from the left most side, not inducing the offset)
/// @arg y this is the y coord of the row
/// @arg count this is how big the row should be (how many squares to draw)
/// @arg max_count this is the biggest any row can be (the bottom row, perhaps?)
/// @arg sprite this is the sprite to draw. Just in case you want to change it.
var sx = argument[0];
var sy = argument[1];
var count = argument[2];
var max_count = argument[3];
var sprite = argument[4];

var size = 32; // size of the sprite
var padding = 10; // size of the space between each sprite

var max_width = (size+padding) * max_count; // calculates the biggest the width can be (as flyingsaucerinvasion suggested)
var my_width = (size+padding) * count; // calculates the width of just this row
var offset = (max_width - my_width) / 2;
for(var i=0; i<count; i++) {
     var dx = sx + i * (size+padding) + offset;
     draw_sprite(sprite, 0, dx, sy);
}
honestly half of the code is just comments and a lot more is just storing arguments in variables. The rest is just what flying said but a bit more dynamic cus now you can just do this:
Code:
draw_row(200, 250, 4, 6, spr_yellow);
draw_row(200, 300, 6, 6, spr_yellow);
draw_row(200, 350, 2, 6, spr_yellow);
hopefully I didn't make any mistakes... I just wrote it on the forums without testing. oops :rolleyes:
 
Top