Different background at a radius to player

Started by Scarab, Fri 29/05/2009 19:31:59

Previous topic - Next topic

Scarab

Greetings.
I was looking to see of there was a way to change the background at a fixed radius around the player when he walks, as though he's holding a lantern/torch.
I don't just want a lighter background around him, but a different image as though he's holding a blacklight.
Cheers for any help anyone can give me.

Peace ;D
Scarab

monkey0506

Just as a point of interest, were you wanting to display just an alternate background, or did you want this blacklight effect to apply to everything within the radius, the character included?

Scarab

Just the background really, because it would make the character look really wierd to have him with a blue tinge as well.

monkey0506

#3
If you were to import the altered background as a secondary frame you could possibly work something up using DynamicSprite.CreateFromBackground, DynamicSprite.Create, DynamicSprite.GetDrawingSurface, DrawingSurface.Clear, DrawingSurface.DrawCircle, DrawingSurface.Release, DynamicSprite.CopyTransparencyMask, Room.GetDrawingSurfaceForBackground, and DrawingSurface.DrawImage...

Not that I've put any thought into it or anything...:P...but for right now I do have to go to work. Perhaps someone else will see what I'm talking about and can post the code. Or maybe you can figure it out from he manual entries. Otherwise, I'll try and post some example code when I get home.... ;)

Actually DrawingSurface.Clear is probably redundant as AFAIK DynamicSprite.Create already creates it on a blank canvas...

Khris

Yep, definitely possible using the mentioned commands.

1. Determine the coordinates of the rectangle containing the part of the background that's supposed to be changed
2. Create a dynamic sprite containing that rectangle
3. Paint on that using the transparent color pink (255, 0, 255) and a loop & adequate formula (assuming you want e.g. a circle shape)
4. Draw that onto the background

Scarab

Well, unfortuantely, a lot of this is going over my head. I went to the manual to look up Dyanmic Sprites, but that really didnt help at all. Someone's really going to have to spell this one out for me, because I'm currently passing through StruggleTown, and my car has broken down.  :(

monkey0506

Okay, so try something like this. First import the "blacklight" version of the entire background as the second background frame.

Code: ags
// room script
DrawingSurface *backgroundCopy;

// enter room
  SetBackgroundFrame(0); // make sure we don't animate the backgrounds

// room's repeatedly_execute
  ViewFrame *frame = Game.GetViewFrame(player.View, player.Loop, player.Frame);
  int rad = (Game.SpriteHeight[frame.Graphic] * player.Scaling) / 200; // set the radius to be half the player's height
  DynamicSprite *backgroundSprite = DynamicSprite.CreateFromBackground(1, player.x - rad, player.y - (rad * 2), rad * 2, rad * 2);
  DynamicSprite *circleSprite = DynamicSprite.Create(rad * 2, rad * 2);
  DrawingSurface *surface = circleSprite.GetDrawingSurface();
  surface.DrawingColor = 0;
  surface.DrawCircle(rad, rad, rad);
  surface.Release();
  backgroundSprite.CopyTransparencyMask(circleSprite.Graphic); // crop out the unwanted areas, leaving us with a circle from the second background
  circleSprite.Delete();
  surface = Room.GetDrawingSurfaceForBackground();
  if (backgroundCopy == null) backgroundCopy = surface.CreateCopy();
  else surface.DrawSurface(backgroundCopy);
  surface.DrawImage(player.x - rad, player.y - (rad * 2), backgroundSprite.Graphic);
  surface.Release();
  backgroundSprite.Delete();

// leave room
  if (backgroundCopy != null) backgroundCopy.Release();


Since it wasn't specified I assumed a radius of half the player's current scaled height. If you wanted a smoother, anti-aliased effect you could import a solid black alpha smoothed circle sprite and then replace the circleSprite definition and drawing the circle by just copying the transparency mask directly from the sprite.

The basic idea here is that you're going to grab the appropriate portion of the second background frame and then use that as a base for your effect. Next you're going to create a sprite with a circle on it, the same size as you want the overall effect to be. You will then copy the transparency from the circle sprite onto the background sprite, thus effectively cropping off the areas around the circular area. This leaves us with a circular portion of the secondary background. Then we draw that back into its respective location on the primary background, and voila!...maybe.

Could be slow on older systems or in rooms with a lot of other things going on. Also I made a point of not testing my code because I'm that brilliant. :P

Scarab

Thanks guys, especially Mo, that script works a treat.
However, there are a few problems that have arisen whilst testing it:

1. As the sprite is larger now, as he aproaches the doors on either end of the room, part of the circle leaves the game, causing it to crash.
   
   My solution to this will simply be to make the blank area outside the room longer in relation to the room itself, so let me know if there is a better way, as I will lose all my hotsopts and areas etc. If not, its not a huge deal

2. The circle does not emanate from the character's centre, but just rises up so that the base is always at his feet, this is not noticible when the radiuus is half his height as in the original script above, but I need It a bit bigger to be practical to the scene, and it ends up looking a bit awkward.
Is there a way I can have the circle emanating from the centre of the sprite, or even better, the torch/lantern in his hand?
Any help is appreciated.

Peace
Scarab


monkey0506

#8
1. What exactly is the error you're getting. AFAIK the DrawingSurface functions should be able to accept co-ordinates that would result in drawing "outside" the actual area, but I could be hallucinating. Actually as a matter of fact if you're trying to grab an area of the background outside the actual size of the background that could be causing problems right there...

Try replacing:

Code: ags
  DynamicSprite *backgroundSprite = DynamicSprite.CreateFromBackground(1, player.x - rad, player.y - (rad * 2), rad * 2, rad * 2);


With:

Code: ags
  int x = player.x - rad;
  int y = player.y - (rad * 2);
  int xx = x;
  int yy = y;
  if (x < 0) xx = 0;
  if (y < 0) yy = 0;
  DynamicSprite *backgroundSprite = DynamicSprite.CreateFromBackground(1, xx, yy, rad * 2, rad * 2);
  if ((x != xx) || (y != yy)) backgroundSprite.ChangeCanvasSize(rad * 2, rad * 2, xx - x, yy - y);


2. The lines relevant to the sizing/positioning of the effect are these:

Code: ags
  int rad = (Game.SpriteHeight[frame.Graphic] * player.Scaling) / 200; // set the radius to be half the player's height
  DynamicSprite *backgroundSprite = DynamicSprite.CreateFromBackground(1, player.x - rad, player.y - (rad * 2), rad * 2, rad * 2);
  // ...
  surface.DrawImage(player.x - rad, player.y - (rad * 2), backgroundSprite.Graphic);


If you want the effect to have a radius of the player's height you can change the 200 to 100. Or for 75% (giving a diameter of 150% of the player's height of course) you could set it to 133. Etc. and so forth. If you're confused how I came up with that, take 100 and divide by the percentage you want, i.e. 0.75 (75%). So 100 / 0.75 = 133.333. For 80% you would use 100 / 0.8 = 125.

As far as the positioning it's a simple matter of offsetting the x/y values. If you really wanted to attend Crazy Go Nuts University, you could even go as far as:

Code: ags
  int x = player.x - rad;
  int y = (player.y - (rad * 2)) - ((10 * player.Scaling) / 100); // move the area up 10 (scaled) pixels
  if (player.Loop == 1) x -= (5 * player.Scaling) / 100; // player is facing left, move the area left 5 (scaled) pixels
  else if (player.Loop == 2) x += (5 * player.Scaling) / 100; // player facing right, move the area right 5 (scaled) pixels
  int xx = x;
  int yy = y;
  if (x < 0) xx = 0;
  if (y < 0) yy = 0;
  DynamicSprite *backgroundSprite = DynamicSprite.CreateFromBackground(1, xx, yy, rad * 2, rad * 2);
  if ((x != xx) || (y != yy)) backgroundSprite.ChangeCanvasSize(rad * 2, rad * 2, xx - x, yy - y);
  // ...
  surface.DrawImage(x, y, backgroundSprite.Graphic);


Note here that I'm only dividing by 100. This is of course because we're only calculating the scaling. Not also taking a percentage of the player's height. You should here be able to position the effect directly around the blacklight and then it should properly scale as the character moves around.

Oh and of course, you're welcome by the way. It's my pleasure to help you out with this. Besides, I get terribly bored so this works out well for me. :D

Scarab

mm, the first problem is persisting, even when I switched the codes, it's coming up with the message "AGS had a problem running your game. The error can be seen below, and is most likely due to a scripting problem. The line in the script where the problem took place has been hightlighted for you.

'DynamicSprite.CreateFromBackground: invalid co-ordinates specified'
"
To solve this I'll just redraw the room, as it was only a hallway anyway.


Furthermore, another problem I came across was that when a hotspot with a walkto point was clicked, the "light" stayed where it was until he arrived, and I'm not sure on how to make it continue to follow the character.

Also, when I modified the code to move the origin of the circle, it stays in the same place in relation to the original background and the character, but the image of the "blacklight" background is out of line by the co-ordinates specified, So it doesn't line up with the background and the light is still attatched to the character's feet.
Hope that makes sense,I'm a bit out of my depth here in the coding :-[

Wonkyth

I haven't been following this thread, but the problem with the hotspot walkto thing is probably a blocking problem.
"But with a ninja on your face, you live longer!"

Wonkyth

I haven't been following this thread, but the problem with the hotspot walkto thing is probably a blocking problem.

And don't worry about being out of your depth.
I am, and I figure that the only way to get a handle on these kind of things is to try.
"But with a ninja on your face, you live longer!"

SMF spam blocked by CleanTalk