Offsetting a sprite

Started by Scavenger, Sun 01/06/2014 22:13:13

Previous topic - Next topic

Scavenger

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.

Code: AGS


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?

Khris

You only need 4 draw commands to shift the image, you have to sanitize x and y first though:

Code: ags
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();
}

Scavenger

Ah! Thankyou! That works much better. I'm not quite sure what these lines do, though:
Code: AGS
  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?

Gurok

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:
Code: AGS
  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:

Code: ags

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.
[img]http://7d4iqnx.gif;rWRLUuw.gi

Khris

Here's an amended version:
Code: ags
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.

SMF spam blocked by CleanTalk