I'm trying to make a simple graphical effect - offsetting a sprite from it's original coordinates, and wrapping it around to the other side if parts go beyond the boundaries of the sprite (for instance, if a row of pixels go beyond the height of the sprite, that row is put back at 0 - basically moving the sprite around the canvas and wrapping it around). I've come up with something that sort of works, but I don't think it's very efficient or even correct.
function Offset (this DynamicSprite*, int x, int y)
{
DynamicSprite *tempspr = DynamicSprite.Create (this.Width, this.Height);
DrawingSurface *surface = tempspr.GetDrawingSurface ();
surface.DrawImage (0+x, 0+y, this.Graphic);
surface.DrawImage (0+x-this.Width, 0+y, this.Graphic);
surface.DrawImage (0+x+this.Width, 0+y, this.Graphic);
surface.DrawImage (0+x, 0+y+this.Height, this.Graphic);
surface.DrawImage (0+x, 0+y-this.Height, this.Graphic);
surface.DrawImage (0+x-this.Width, 0+y-this.Height, this.Graphic);
surface.DrawImage (0+x+this.Width, 0+y+this.Height, this.Graphic);
surface.DrawImage (0+x-this.Width, 0+y+this.Height, this.Graphic);
surface.DrawImage (0+x+this.Width, 0+y-this.Height, this.Graphic);
surface.Release ();
surface = this.GetDrawingSurface ();
surface.DrawingColor = 0;
surface.DrawRectangle (0, 0, this.Width, this.Height);
surface.DrawImage (0, 0, tempspr.Graphic);
tempspr.Delete ();
surface.Release ();
}
Is there an easier way to do this?
You only need 4 draw commands to shift the image, you have to sanitize x and y first though:
void Offset(this DynamicSprite*, int x, int y)
{
int w = this.Width;
int h = this.Height;
while (x < 0) x += w; x = x % w;
while (y < 0) y += h; y = y % h;
DynamicSprite *tempspr = DynamicSprite.Create(w, h);
DrawingSurface *surface = tempspr.GetDrawingSurface();
surface.DrawImage(x - w, y - h, this.Graphic);
surface.DrawImage(x - w, y, this.Graphic);
surface.DrawImage(x, y - h, this.Graphic);
surface.DrawImage(x, y, this.Graphic);
surface.Release();
surface = this.GetDrawingSurface();
surface.Clear(COLOR_TRANSPARENT);
surface.DrawImage(0, 0, tempspr.Graphic);
tempspr.Delete();
surface.Release();
}
Ah! Thankyou! That works much better. I'm not quite sure what these lines do, though:
while (x < 0) x += w; x = x % w;
while (y < 0) y += h; y = y % h;
So, while x < 0, add the width of the image to the offset, and make x the remainder of the division the offset by the width. If I'm reading this correctly, it's making the offset a number between 0 and the width/height of the image?
Quote from: Scavenger on Mon 02/06/2014 01:53:12
Ah! Thankyou! That works much better. I'm not quite sure what these lines do, though:
while (x < 0) x += w; x = x % w;
while (y < 0) y += h; y = y % h;
So, while x < 0, add the width of the image to the offset, and make x the remainder of the division the offset by the width. If I'm reading this correctly, it's making the offset a number between 0 and the width/height of the image?
That's what it does. And if you swap the order of the statements, you don't even need to use while:
x = x % w; if (x < 0) x += w;
y = y % h; if (y < 0) y += h;
It might also be worth wrapping some of those DrawImage calls in if statements to avoid useless draws where x == 0 or y == 0.
Here's an amended version:
void Offset(this DynamicSprite*, int x, int y)
{
int w = this.Width;
int h = this.Height;
x = x % w; if (x < 0) x += w;
y = y % h; if (y < 0) y += h;
if (x == 0 && y == 0) return;
DynamicSprite *tempspr = DynamicSprite.Create(w, h);
DrawingSurface *surface = tempspr.GetDrawingSurface();
if (x > 0 && y > 0) surface.DrawImage(x - w, y - h, this.Graphic);
if (x > 0) surface.DrawImage(x - w, y, this.Graphic);
if (y > 0) surface.DrawImage(x, y - h, this.Graphic);
surface.DrawImage(x, y, this.Graphic);
surface.Release();
surface = this.GetDrawingSurface();
surface.Clear(COLOR_TRANSPARENT);
surface.DrawImage(0, 0, tempspr.Graphic);
tempspr.Delete();
surface.Release();
}
I was too lazy to test AGS's % behavior, turns out -35 % 30 is indeed -5 (not -25), so Gurok is correct.