Moving background diagonally

Started by Val, Thu 10/08/2017 07:31:23

Previous topic - Next topic

Val

Hello. I'm trying to scroll a background diagonally with direction and speed variables. The background is created from DynamicSprite with twice the size (2x2) of the actual image and the original background drawn on the four quadrant. My question is how to calculate moving the background, making point B move to point C (downleft moving effect) with changeable speed.



This is the code:

Code: ags

DynamicSprite *Backdrop;
int movx, movy;

// called once on room's Load
function SetBackdrop()
{
  Backdrop = DynamicSprite.Create(Room.Width * 2, Room.Height * 2, false);
  DrawingSurface *surface = Backdrop.GetDrawingSurface();
  surface.DrawImage(0, 0, 95, 0, Room.Width, Room.Height);
  surface.DrawImage(Room.Width, 0, 95, 0, Room.Width, Room.Height);
  surface.DrawImage(0, Room.Height, 95, 0, Room.Width, Room.Height);
  surface.DrawImage(Room.Width, Room.Height, 95, 0, Room.Width, Room.Height);
  surface.DrawingColor = 13;
  surface.DrawLine(0, Room.Height * 2, Room.Width * 2,  0, 4); // DownLeft line
  surface.Release();
}

// called on repeatedly_execute()
function MoveBackdrop(CharacterDirection direction, int speed)
{
  if (Backdrop == null || direction == eDirectionNone) return;

  DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
  
  int accelx = 16 * speed; //<-- Question
  int accely = 9 * speed;  //<-- Question

  if (direction == eDirectionDownLeft)
  {
    movx = movx + accelx;
    movy = movy - accely;
	  
    if (movx >= 0)
    {
      movx = Room.Width - Backdrop.Width;
      movy = 0;
    }
  }

  surface.DrawImage(movx, movy, Backdrop.Graphic, 0);
  
  surface.Release();
}


TIA.

Snarky

#1
If you want the movement to just be along a straight line (the diagonal), I say create a function that draws it in a position between 0 and 1, where 0 is the start (upper right) and 1 the end (lower left) position â€" from this you calculate the x and y offsets. Keep a variable of the current position value. Then adjust the value each turn to move the background, depending on the speed you want (e.g. from 0 to 0.05, 0.10, 0.15... to move slowly, with a speed of 0.05 per turn, or from 0 to 0.2, 0.4, 0.6... to move more quickly, at a speed of 0.2 per turn).

If you want the speed to vary, this is where differentiation/derivation comes into play:

Your basic value is the position
The change in the position each turn (first derivative) is the movement speed
The change in the movement speed each turn (second derivative) is the acceleration

So if you want the movement speed to change gradually, you need to store not only the position, but the current movement speed, and then adjust that each turn. If you increase it by a constant value each turn you'll get steady acceleration, faster and faster, like when something is falling. If you first increase it and then decrease it (e.g. increase until speed is 5 and then decrease again, or increase while the position is less than 0.5 and then decrease), you'll get an ease-in, ease-out effect, more like a camera move.

Val

Quoteâ€" from this you calculate the x and y offsets. Keep a variable of the current position value. Then...
This is what I was asking for, I'm not good with math and I can't formulate the 'movx' and 'movy' variables in the code to move alongside the diagonal if I add speed. If you try my code you can see I hardcoded 16:9 because I uses 1080p for the game. It works fine, but I don't know how to add speed and make an equation to be implemented on the code so that it moves in perfect diagonal line (the 'DownLeft line' in the code).

Thanks for the tip on speed variation logic, I might try to implement that later on.

Snarky

Well, I think you're just confusing yourself by not clearly distinguishing between position and movement. The thing you need to store is the position (which we can also represent as "how far along we are": a proportion of the total distance), and then you just use the movement speed to update the position.

There are lots of different ways to figure out how to do that update (some of which are more efficient to calculate), but let's take a general example, where you want to move from point x_start,y_start to x_end,y_end, and we store it as a proportion. To calculate a position x,y that is proportion of the way between, you can do it like this:

Code: ags
// Variables declared either globally or as function arguments
  int x_start, x_end, y_start, y_end; 
  float proportion;

  // Calculation of coordinates
  int x = FloatToInt(IntToFloat(x_end) * proportion + IntToFloat(x_start) * (1.0 - proportion), eRoundNearest);
  int y = FloatToInt(IntToFloat(y_end) * proportion + IntToFloat(y_start) * (1.0 - proportion), eRoundNearest);


We do all the calculation in floats for maximal accuracy, and then round off to the closest int. You see that we just take a weighted average of the start and end coordinates, according to the proportion (when proportion is 0, we use 100% of the start coordinate and 0% of the end coordinate, when it is 0.1 it's 90% to 10%, and so on).

OK, now we just need to update the proportion, which is pretty simple:

Code: ags
float proportion;

void MoveBackdrop(CharacterDirection direction, float speed)
{
  if (Backdrop == null || direction == eDirectionNone) return;

  // Update the proportion by a certain amount (the movement speed)
  proportion = proportion + speed;
  // Make sure the proportion is in the [0.0, 1.0] range
  if(proportion > 1.0)
    proportion = 1.0;
  else if(proportion < 0.0)
    proportion = 0.0;

  // We set x/y_start/end with the particular values for the movement we want
  if(CharacterDirection == eDirectionDownLeft)
  {
    int x_start = Room.Width * 2;
    int y_start = 0;

    int x_end = Room.Width;
    int y_end = Room.Height;
  }
  else if(CharacterDirection == eDirectionDownRight)
  {
    // etc.
  }
  // etc.

  // Calculate the coordinates from the proportion
  int x_offset = FloatToInt(IntToFloat(x_end) * proportion + IntToFloat(x_start) * (1.0 - proportion), eRoundNearest);
  int y_offset = FloatToInt(IntToFloat(y_end) * proportion + IntToFloat(y_start) * (1.0 - proportion), eRoundNearest);  

  // Render
  DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
  surface.DrawImage(x_offset, y_offset, Backdrop.Graphic, 0);
  surface.Release();
}


This all assumes that the CharacterDirection doesn't change during the scrolling. If it does, it'll suddenly jump from one position to another when it changes direction.

Val

QuoteWell, I think you're just confusing yourself by not clearly distinguishing between position and movement.

I did confuse that, forgive this old fart lol. I thank you for the enlightenment, I get the idea but not yet the implementation. I'm sure I'll get there with this. Really appreciate your help and generous code. Cheers.

Monsieur OUXX

Everything Snarky said is correct, but another approach would be to use the Tweens module. I didn't double-check, but I think that the latest version can tween the viewport. That's less code to worry about, plus it can ease in and out.
 

SMF spam blocked by CleanTalk