[SOLVED + Module Download] Vertically Mirrored Character on Scaling background

Started by SpacePirateCaine, Mon 27/01/2014 14:09:30

Previous topic - Next topic

SpacePirateCaine

Hi all once again (Hopefully two in one day isn't too much),

I'm currently working on a room in my game that has a "reflective floor", where I would like the main character to have a reflection walking with him, purely for aesthetics.

I've managed to set up a separate mirrored character that has all of the same animations, flipped vertically, and have the character following the character's movements without much issue, but the problem crops up when I use Continuous Scaling in my background as the player walks further back into the room - as the character's movements are tied to the coordinates of the player, the sprite gets "smaller" correctly, but appears further and further away from the character's feet. I've attempted to tweak the reflected character's z coordinates based on the player's y in the room's script with iffy results ranging from appearing to remain connected but no longer scaling to disappearing altogether.

The code I have is as follows:

Code: ags

function room_FirstLoad()
{
  cTytanReflect.z = player.y-75;
  cTytanReflect.Transparency = 70;
}

function room_RepExec()
{
  cTytanReflect.x = player.x;
  cTytanReflect.y = player.y+130;
  cTytanReflect.Frame = player.Frame;
  int l = player.Loop;
  if (l == 0 || l == 3) l = 3 - l;
  cTytanReflect.Loop = l;
}


(Code largely poached from Khris' code in another mirror thread and re-purposed to my own needs)
The current code has the reflective character staying more or less at the feet of my Player sprite, but is not scaling properly. Is there some easy way to set the main hotspot to the top of a character's sprite which would allow the sprite to scale correctly from that point, or am I grasping at straws?
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Gilbert

In this random test of mine(skip to around 0:18), I used the following line to reposition the reflection every frame.
Code: ags
  oRef.X=player.x-(tmpspr1.Width/2); oRef.Y=(player.y+tmpspr1.Height)-2;

I didn't use a character for the reflection though. Instead, it's an object in the room, which was updated actively by flipping and scaling the current frame of the character into a dynamic sprite (the resultant sprite was tmpspr1 and the room object was oRef) every frame.

SpacePirateCaine

Ahoy Iceboty!

Thank you very much - the positioning trick works like a charm: I managed to get it working using the character, though I'm still having issues with scaling. If I can use dynamic sprites to mirror the current sprite of the player per frame as displayed due to scaling, that would make the whole process much, much easier since I won't have to manually create and import additional sprites for the "reflection" character.

I'm trying to figure out how this works: I see in your demo video there that your sprite is animating and updating correctly, but I'm brand new to the whole concept of dynamic sprites. I am able to create a dynamic sprite using
Code: ags

  DynamicSprite* tmpspr1 = DynamicSprite.CreateFromExistingSprite(object[1].Graphic);

Where object1 is oRef (Is that even the right way to do this?), but i'm not sure how I should be updating the sprite to be a copy of the player. Object.Frame and Object.Loop are read-only values so I can't use the same method that I had with updating the character frames.

I assume i will also need to make use of
Code: ags

  tmpspr1.Flip(eFlipUpsideDown);

to display the image upside-down when all is said and done, but I'm more of an designer/artist than scripter, so it takes a long time for me to wrap my head around a lot of this.
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Khris

The problem is that if you scale the character, the reflection character must move up by (height - height*scaling/100).

I put something together: https://www.dropbox.com/s/j6smvh8hu1kvndt/GroundReflection.scm
Tested it with a 16-bit game, worked fine.
Use like this:
Code: ags
function room_Load()
{
  GroundReflection.SetOffsetFront(-3); // for back & front loop, move reflection up 3 pixels
  GroundReflection.SetOffsetSide(-5); // for side loops, move up 5 pixels
  GroundReflection.SetTransparency(70); // default is 50
  GroundReflection.Enable();  // the only non-optional line
}


The offset stuff is in case the walk cycle frames don't go all the way to the sprite's bottom edge.
The code also uses player.z; if the character floats, the reflection will move down accordingly.

The reflection grabs the player's frame and draws it to the background, which means you don't have to set up a view first.

Gilbert

As I'm too lazy to explain, I'll post the part of code that did that in the demo:
Code: ags

  pframe = Game.GetViewFrame(player.View, player.Loop, player.Frame);
  tmpslot=pframe.Graphic;
  tmpspr1=DynamicSprite.CreateFromExistingSprite(tmpslot);
  if (pframe.Flipped) tmpspr1.Flip(eFlipBoth); else tmpspr1.Flip(eFlipUpsideDown);
  tmpspr1.Resize((tmpspr1.Width*player.Scaling)/100, (tmpspr1.Height*player.Scaling)/100);
  oRef.Graphic=tmpspr1.Graphic;
  oRef.X=player.x-(tmpspr1.Width/2); oRef.Y=(player.y+tmpspr1.Height)-2;

(BTW these codes are in repeatedly_execute_always() of the room.

Slasher

Hi,

I think that Khris' GroundReflection module has possibilities and could come in very useful, in fact I have a use for it in my latest game. Tried and it works fine.

My only wishlist would be for the 'reflection' to be dictated by where the light source is coming from, especially View 1 and 2.

Thumbs up (nod)

Slasher

Khris

What exactly do you mean? On even ground, a reflection always points straight down, regardless of the position of the light source.

Slasher

#7
Hi Khris,

I always thought that if light source was to the right of you then reflective shadow would be to the left of you and vice versa  etc etc :-\

PS For  mirror / water reflection then I have to agree with you. ;)

Khris

If by "reflective shadow" you're referring to the reflection, then that's complete nonsense.
How reflections work is extremely simple, yet most people can't do them correctly. Even Heroine's Quest botched them completely.

A reflection mirrors everything in 3D space, which means that a ground reflection is basically a person standing upside down "inside" the ground, with their soles touching the characters'.
The position of this reflection does not change one iota if the light source is moved. Also, this person will look like it extends into the ground, regardless of the camera position.

Edit:
Why the F**K would it matter whether it's a polished floor or a mirror...??

SpacePirateCaine

#9
If I might interject, I think Slasher is thinking shadows, as opposed to reflections, and getting the terminology wrong.

Slasher - in this case, Khris' awesome module (Which works like a charm, by the way - thank you so much!) only really deals with flat reflective surfaces below the character - mirrors/polished floors/water/etc. The reason I needed a solution like this is because I have a room (and now will probably make a few rooms) that have reflective floors and also used scaling walkable areas, like so:


The player-character is the guy standing in the middle with blonde hair.

What you seem to be thinking of is a shadow as it's cast from your feet, which would definitely be contingent on the location of the light source - in this case from behind the player character? I agree that with extra tweaking that I'm by no means capable of at my level you could also use something like this to generate more realistic shadows. Considering how shadows work, though, it's probably more work than it's worth as the minute you hit a surface parallel to the player character, the illusion is broken.

That said, thank you Khris for this module! I'll study the script inside and see if I can learn something from it.

Also, thanks to Gilbot for the pushes in the right direction!

One thing that others using this module might want to keep in mind - the reflection doesn't seem to be affected by walk-behinds, so at present you will need to use objects with a high-value baseline to block the reflection, if you have foreground elements.
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Grim

I've been cheeky and downloaded Chris' module;) It's absolutely fantastic! It does exactly what I wanted to do in a room with wet floor.

One problem though- it cuts 10 fps (again, Dualnames' noise module did the same recently... I'm sensing a worrying pattern here). So I'm down to 30-31 fps. Is it an issue with my game (800:600 resolution, large sprites within a room, AGS 3.3.0)? Is there any way to reduce the slowdown? And mostly, would it matter to an average player if in a room or two framerate dropped from 40 to 30? What are the standards for these kinds of things?

SpacePirateCaine

I didn't notice any significant framerate drop but I am running at 320x200 with 75-pixel tall characters, so not really taxing in the first place - especially with a moderately fast gaming rig.. I suppose I should do a little testing with a framerate monitor just in case but with the average adventure game, you aren't exactly doing precision twitch gaming anyway, so some potential framerate drop probably wouldn't be too tragic.
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Khris

Glad it's working, but yes, the module has its limitations due to how AGS works.
Since it uses rawdrawing as opposed to a character, when the scaling level isn't 100%, it resizes the character sprite each frame. This can get slow for larger sprites (and is recommended against in the manual for that reason).

As for walkbehinds, there's nothing that can be done about that. One feasible solution would be to implement every walkbehind as non-clickable object instead and have the module draw all the objects' reflections, too.

slasher/barefoot/steptoe:
In case you were actually talking about reflective dynamic shadows, why would they be colored? I mean you tested the module, right? Also, I already did that.

Slasher

Hi Khris,

I'm afraid it was a case of me 'going off track', please excuse me :-[

Of course it's about 'reflections'...silly me, and yes, it works fine based on that.

Thanks for taking the time to produce the Module Khris ;)

I seem to remember you did a shadow demo some while back.....

cheers

Slasher




SpacePirateCaine

It works like a charm, Khris - amazing, and in such short time as well.

I'd also like to note for others that want to get a little greedy with their reflections that it does indeed work with multiple characters at once (without any noticeable framerate drop), though you need to duplicate a lot of the script and I also needed to nest a few if statements that reference Global Variables to ensure that the game didn't crash when a character wasn't in the room - I named them as booleans "Character_InRoom", so "if (Character_InRoom = true)" and set those on room_Load() and room_Leave(), respectively.

For those interested in duplicating, I was able to copy lines 20~39, roughly - the following:

Code: ags

  ViewFrame *vf = Game.GetViewFrame(player.View, player.Loop, player.Frame);
  int slot = vf.Graphic;
  reflection = DynamicSprite.CreateFromExistingSprite(slot);
  if (vf.Flipped) reflection.Flip(eFlipBoth);
  else reflection.Flip(eFlipUpsideDown);
  int sc = player.Scaling;
  int w = Game.SpriteWidth[slot];
  int h = Game.SpriteHeight[slot];
  if (sc != 100) {
    w = (w * sc) / 100;
    h = (h * sc) / 100;
    reflection.Resize(w, h);
  }
  int x = player.x - w/2;
  int y = player.y;
  int y_offset = player.z;
  if (player.Loop == 0 || player.Loop == 3) y_offset += offset_front;
  else y_offset += offset_side;
  y += (y_offset * sc)/100;


then create dupes of all of the defined integers and their references within the script (vf, slot, reflection, sc, w, h, x, y and y_offset become vf2, slot2, reflection2, sc2, w2, h2, x2, y2 and y_offset2, respectively), then place the copies of those lines after the following lines:

Code: ags

  DrawingSurface *ds = Room.GetDrawingSurfaceForBackground();
  if (background != null) ds.DrawImage(0, 0, background.Graphic);


being sure to nest the ds.DrawImage calls within the if statements, and doing the final ds.DrawImage and ds.Release() after the close bracket of the "if (Character_InRoom = true)" statements.

My thanks once again to you, Khris, for this amazing module - I will put it to good use!
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Slasher

#15
Hi,

Ref: Note for Khris.

Is it the nature of the beast that the GroundReflection module disables animate backgrounds because I notice that no background animates if the module becomes enabled? I disabled the module and the background animates ok.

cheers

slasher

Khris

Yes, I forgot to add that to the limitations. Currently, the code does not work with animated backgrounds; since it draws the first background sprite on the background each loop to remove the previous reflection, it effectively (though not actually) disables background animation.

I'm not really releasing this as an official module anyway right now, originally I just wanted to provide some reflection code. But since I had it in a game anyway for testing purposes I thought why not upload it as .scm file.

SpacePirateCaine

Don't know if I'd ever have noticed anyway - I tend to go overboard on my animations so the 5-frame limit means I always use objects for my animating BG elements anyways. Perfect still for my needs at least.
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

Monsieur OUXX

I didn't read all this, but... you could also have used (or slightly adapted) the ready-to-use EasyMirrors module.
 

SpacePirateCaine

Hi Monsieur OUXX,

Actually, in my search to find a solution to my issue I did try Easy Mirrors before posting here - unfortunately, considering the sheer size of my reflected surfaces (The whole floor of a number of rooms), the slowdown was unmanageable. To your credit, however, the module was very easy to set up and I had it working in-game fairly quickly.

It did a great job in only reflecting onto the surfaces that I specified, however, so that's a big plus for it.
Check out MonstroCity! | Level 0 NPCs on YouTube! | Life's far too short to be pessimistic.

SMF spam blocked by CleanTalk