Module: EpicShadows 1.0 (AGS 3.02+) - based on Shadow module by SSH

Started by Dusk, Sat 23/08/2008 21:37:12

Previous topic - Next topic

Dusk

Hi, this is the first module I post. I Hope that someone will find it useful. :)
A related question: I got a warnings.log because the dynamic sprites of the shadows cache aren't freed. I know that this isn't a memory leak, because it's a prefixed amount of sprites created once and never cleared.
To avoid the warnings I thought of adding a clear_cache function, but the user should manually call it before quit (AFAIK there's no game_quit handler like game_start, or anything similar).
By the way, I suppose that we can just ignore the warnings and be happy, 'cause the OS will free itself all the game memory when you quit it.
Of course I'm open to suggestions to improve the module :)

Get it here (demo game included, documentation in the script header):
http://www.duskzone.it/works/ags/EpicShadows.zip

From the script header:

What did I change from the original 'Shadow' module by SSH?

The wonderful thing of the original Shadow module was that you just had to
import it and all your characters had cleverly drawn shadows
(with caching, scaling and depending on character dimensions).
By the way it had some major issues, pointed by the author itself:

-   Animated background frames mess it up.
-   Walkbehinds don't work on the shadow.

I managed to solve these issues drawing shadows to a DynamicSprite and
assigning it to a "dummy object".
Walkbehinds and animated backgrounds work (shadows are by default drawn
behind other stuff, the dummy object is set with Baseline 1), but the
drawback is that you have to put an object in every room where
you want shadows to make the module work.

So, if you don't have walkbehinds or animated backgrounds, go for the
original module. :)
If you have them, placing the dummy object in each room is boring, but
less boring and more functional (IMHO) that the other approaches to the
problem (like the one of the dummy shadow character with Follow_Exactly...
if you can have 5 characters in a room).

I did also another minor change: I scaled the shadow respect to the Character.Z.
I needed this with a flying character, to make the shadow gradually disappear
when he starts to float and gradually appear when he approaches the ground.

Another little improvement is the Shadow.SetScale function, to adjust the
dynamically calculated width of the shadow on a per character basis.

Warning: having a room-wide dynamic sprite was SLOW, so I optimized a bit
letting you define the "shadowable area" of a room when you put the
"dummy object".
In short, drag it such that its Y is above the walkable areas: no shadows
will be drawn above it.

This should work in the most common case of the walkable areas in the lower
part of the screen...
if you're coding a SpiderMan adventure and he walks on the ceiling, you might
need to change some lines of code to have better performances :)

The module scans for an object called "ModShadows" when you enter a room.
If he finds it, he creates the sprite and draws the shadows. If he doesn't,
nothing is done.

Letting the user disable shadows to have better performances is reasonable,
maybe from a "game settings" GUI, so you can toggle the feature on/off
with Shadow.SetActive(bool trueFalse). If you call Shadow.SetActive(false),
the "ModShadows" objects will be ignored (and made invisible, of course) and
no shadows will be drawn.

Other features should work exactly as in the original module.

Thankyou SSH!

  Dusk

Ghost

Quote from: Dusk on Sat 23/08/2008 21:37:12
By the way, I suppose that we can just ignore the warnings and be happy, 'cause the OS will free itself all the game memory when you quit it.

Then let us assume that I do not turn my PC off very often, and start a game made with that module several times. Sounds paranoid? Not from a programmer's point of view, not at all. I don't think you should "ignore the warnings and be happy"- instead keep in mind that any newcomer might grap your module and use it, oblivious to the fact that he is creating leaks.

Not meant to sound harsh, but still, I stand true to the point. At least point out somewhere in a readme or in the code that a user must free the sprites himself- simplest way would be to put that into a (self-made) "QUIT GAME" gui button. Even that isn't foolproof (because it will not be triggered when someone quits via ALT-X), but it is the best (and therefor the least) one can do.


EDIT: Okay, seems I got you wrong there, as Snarky pointed out. Sorry  :-[

Snarky

What he's saying is that your OS will free all the memory used by the game once you quit it, so your scenario shouldn't cause any problems. This is true, at least in most cases.

Divon

I seem to have stumbled upon a problem with this module that I havent been able to figure out (been messing with this on and off for several days)...

It seems that this error occurs (as best I can tell) when the width of the shadow reaches a certain size.  I'm not 100% certain thats when it occurs, but it seems that whenever the shadow gets very large, the game will crash.  When I run the game in the editor, this is the error I get:

Error running function 'repeatedly_execute_always': Error: Array index out of bounds (index: 217, bounds: 0..199)

The line in question that gets highlighted, line 178 in EpicShadows.asc, is this:

sSurface.DrawImage(this.lastx-GetViewportX(), this.lasty-offsetY, this.cache[width].Graphic);

Anyone have any clue on this?  I'm stumped.

monkey0506

Quote from: Dusk on Sat 23/08/2008 21:37:12I managed to solve these issues drawing shadows to a DynamicSprite and
assigning it to a "dummy object".

Just as a point of interest, IIRC when SSH wrote the Shadow module the DrawingSurface functions hadn't been implemented yet. However with these functions it would be possible to build a dynamic sprite and then modify the character's graphic manually each loop.

You're already drawing the shadows and everything so what I'm suggesting is you could do something such as:

Code: ags
// top of script
int oldFrameID = 0;
DynamicSprite *newFrame;

// wherever you build the shadow
if (newFrame != null) { // release the old DynamicSprite
  ViewFrame *frame = Game.GetViewFrame(CHARACTER.View, CHARACTER.Loop, CHARACTER.Frame); // replace CHARACTER as appropriate with iterator or such
  frame.Graphic = oldFrameID; // restore the original sprite back to the ViewFrame
  newFrame.Delete(); // delete the old DynamicSprite
}
ViewFrame *frame = Game.GetViewFrame(CHARACTER.View, CHARACTER.Loop, CHARACTER.Frame);
int width = Game.SpriteWidth[frame.Graphic] + SHADOW_WIDTH; // replace SHADOW_WIDTH as appropriate
int height = Game.SpriteHeight[frame.Graphic] + SHADOW_HEIGHT; // replace SHADOW_HEIGHT as appropriate
newFrame = DynamicSprite.Create(width, height);
DrawingSurface *surface = newFrame.GetDrawingSurface();
// draw shadow onto surface
// i.e. something such as surface.DrawCircle, or however you're creating the shadow
surface.DrawImage(0, 0, frame.Graphic); // draw the character's sprite on top of the shadow
surface.Release();
oldFrameID = frame.Graphic; // store the old sprite slot number
frame.Graphic = newFrame.Graphic; // assign the ViewFrame to use the modified DynamicSprite w/ shadow


This way there's no need to depend on objects and AGS would automatically handle walk-behinds, animated backgrounds, etc. just as it does with the normal character sprites.

NOTE: I just wanted to make note that in the code snippet above SHADOW_WIDTH and SHADOW HEIGHT should be taken into account as being relative to the dimensions of the character's sprite. What I mean is that SHADOW_WIDTH should really be the actual width of the shadow less the width of the character's sprite. SHADOW_HEIGHT should just be however far below the character's feet the shadow should extend.

Code: ags
int SHADOW_WIDTH = ACTUAL_WIDTH_OF_SHADOW - Game.SpriteWidth[frame.Graphic]; // get difference in size between shadow and sprite
if (SHADOW_WIDTH < 0) SHADOW_WIDTH = 0; // if sprite is wider then just set this to 0
int SHADOW_HEIGHT = ACTUAL_HEIGHT_OF_SHADOW / 2; // i.e. to display the shadow centred around the character's feet


The reason I checked if SHADOW_WIDTH is less than 0 is because if the actual sprite is wider already than the shadow then the DynamicSprite won't need to be any wider than that, even with the shadow in place. ;)

Divon

I cant try this until later because I'm at work -- but would it being tied to an object somehow effect the maximum width of the shadow?  Either way the shadow is being drawn to a dynamic sprite, so wouldnt the point of the object really just be to let the engine know to activate the shadows?

Sorry, normally I'm good at following other peoples code, but I just cant wrap my brain around this module very well.  I guess its because theres a fair amount of functions in it that I am still relatively unfamiliar with.

SSH

Divon, you need to change EPICSHADOWS_MAX_WIDTH in the module header to a number larger than the largest shadow width that you wish to use.
12

Divon

Wow SSH, I'm embarassed, hahaha.  Thanks for posting the fix.  I can't believe I didn't realize that... for some unknown reason I was thinking that the max shadow width would automatically be the width of the room.  I dont even know what would have caused me to ever think that.

Thanks again!  :)

George Stobbart

Hi, I saw the shadows that form is referred to AGS 2.6, I have version 3.1 and I tried the form but does not work ... you may be able to get the shadows thanks to a form compatible with AGS 3.1?
Thanks in advance for any replies. ???

George Stobbart

Can someone answer me?

Or is there some other form compatible with AGS 3.1 for the shadows of the characters?
Answer me soon ...

Gilbert

What's the problem you're getting? (Error messages, etc.)

According to the subject title of this thread, the module was for AGS V3.02+, not V2.6 (module support wasn't even implemented in V2.6). Considering that there weren't that many changes from V3.02 to V3.12 (much less than the differences between V2.6 and V3.12, at least), I think even if this module really won't work now, it could be fixed with just some small tweaking, but we want to know how it won't work first.

George Stobbart

Quote from: Gilbet V7000a on Thu 02/12/2010 11:11:23
What's the problem you're getting? (Error messages, etc.)

According to the subject title of this thread, the module was for AGS V3.02+, not V2.6 (module support wasn't even implemented in V2.6). Considering that there weren't that many changes from V3.02 to V3.12 (much less than the differences between V2.6 and V3.12, at least), I think even if this module really won't work now, it could be fixed with just some small tweaking, but we want to know how it won't work first.
Thanks for your interest friend.

There are no error messages.
When I click "import script" load the form and does not appear any shade except for my character, it seems that the module is not compatible with my version of ags ...

Sorry for my English, I'm Italian

Gilbert

I tried compiling the demo that came with the module using V3.12 and both characters in it had shadows. Are you sure that you didn't do any other things that may interfere with it.

If you cannot figure this out, you may upload your game source (containing just one room with more than 1 characters in it and has this problem is okay) and maybe some people would be able to tell you what's being wrong after looking at it.


Gilbert

Hmmm. I see that there is no character shadow in the game, but as I mentioned, we need the source files of the game to see what happened, otherwise we're just as clueless.

Just make a copy of your game's folder, delete all the subfolders inside it (we don't need stuff in the _Debug, Compiled, etc. folders) and you may also delete most of the .crm files until only the one for the first room is left, so that your game's idea won't be leaked to us and to reduce the filesize. Pack the remaining stuff and upload it.


Gilbert

Alright. After some checking, I've found the problem.

Seems that this module is not as "automatic" as it is claimed. In fact, these are hidden in the first post:

Quote from: Dusk on Sat 23/08/2008 21:37:12
...but the drawback is that you have to put an object in every room where
you want shadows to make the module work.

...

The module scans for an object called "ModShadows" when you enter a room.
If he finds it, he creates the sprite and draws the shadows. If he doesn't,
nothing is done.

So, what you have to do is to add a new object to every room that shadows under characters are needed (you can skip those rooms like close up portraits, etc. as you don't need this effect) and change its Description field to ModShadows and things should work.

Icey


George Stobbart

Quote from: Gilbet V7000a on Fri 03/12/2010 01:10:33
Alright. After some checking, I've found the problem.

Seems that this module is not as "automatic" as it is claimed. In fact, these are hidden in the first post:

Quote from: Dusk on Sat 23/08/2008 21:37:12
...but the drawback is that you have to put an object in every room where
you want shadows to make the module work.

...

The module scans for an object called "ModShadows" when you enter a room.
If he finds it, he creates the sprite and draws the shadows. If he doesn't,
nothing is done.

So, what you have to do is to add a new object to every room that shadows under characters are needed (you can skip those rooms like close up portraits, etc. as you don't need this effect) and change its Description field to ModShadows and things should work.
Thank you for your time, you were right, it works now, thanks again!  :D ;)

Britishgaming

Hi there. Apologies for bumping an old topic.

Just wondered if it would be possible to tweak this module so it shows a dynamic sprite based on my main character's current movements, instead of a circle.

I replaced

//surface.DrawCircle(half, half, half);
   
with
   
    DynamicSprite* manshadow = DynamicSprite.CreateFromExistingSprite(player.Frame);
    surface.DrawImage(half, half, man.Graphic);

But, that didn't work. Any ideas?

Thanks

Slasher

#20
Hi

when the player starts from a walkbehind the shadow fails to appear. The object is spelled right and is just above walkable area. It is ok in other rooms

any ideas?

Slasher

I edited the room to not have that particular walkbehind and it works as it should... all ok (nod)

Potajito

Hi there! As I'm still using this module, I did a quick and dirt fix for it to work in modern AGS versions (module compatibility setting wasn't cutting it). Posting it here in case anyone wants it: https://drive.google.com/file/d/1iLAHrmQ2Fnqp_hfuuPNCz-g-O77KOf7O/view?usp=sharing

Crimson Wizard

Quote from: Potajito on Mon 31/05/2021 16:56:22
As I'm still using this module, I did a quick and dirt fix for it to work in modern AGS versions (module compatibility setting wasn't cutting it).

This module compiles properly if you set "Script compatibility level" to 3.4.1 (3.5.0 was the first version where System.ViewportWidth and other viewport-related things were deprecated). Or were there any other problems?

Potajito

Quote from: Crimson Wizard on Mon 31/05/2021 17:06:29
Quote from: Potajito on Mon 31/05/2021 16:56:22
As I'm still using this module, I did a quick and dirt fix for it to work in modern AGS versions (module compatibility setting wasn't cutting it).

This module compiles properly if you set "Script compatibility level" to 3.4.1 (3.5.0 was the first version where System.ViewportWidth and other viewport-related things were deprecated). Or were there any other problems?
There were! It wasn't properly hiding the dummy object when changing rooms.

Crimson Wizard

Quote from: Potajito on Mon 31/05/2021 23:38:28
There were! It wasn't properly hiding the dummy object when changing rooms.

Do you know what happened to be a reason?
I'm comparing original code and your version, and don't see much difference tbh, rather than for initial object position. Everything else is mostly GetViewport* functions replaced with Camera counterparts.
I'm asking because in theory I'd like to keep AGS 3.5.* backwards compatible as much as possible.

One thing that I might mention, you create new camera every time a room is loaded, but that camera is never deleted.
Custom Viewports and Cameras are bit special in a way that they are not automatically deleted even when the pointer variable is gone. You have to actually call .Delete() for it.
(All created cameras are stored in Game.Cameras[] array)

Code: ags

this.shadowsCanvas = DynamicSprite.Create(cam.Width, Room.Height-this.oShadows.Y);

Probably you could just use Game.Camera.Width instead here.

Laura Hunt

Quote from: Crimson Wizard on Tue 01/06/2021 00:02:11
One thing that I might mention, you create new camera every time a room is loaded, but that camera is never deleted.

Off-topic, but this reminded me that in "La Maleta", a warning.log was generated after I finished playing with a huge list of dynamic sprites that were never deleted. Potajito, maybe you've already fixed that, but if not, you might want to look into it :)

Potajito

Quote from: Crimson Wizard on Tue 01/06/2021 00:02:11
Quote from: Potajito on Mon 31/05/2021 23:38:28
There were! It wasn't properly hiding the dummy object when changing rooms.

Do you know what happened to be a reason?
I'm comparing original code and your version, and don't see much difference tbh, rather than for initial object position. Everything else is mostly GetViewport* functions replaced with Camera counterparts.
I'm asking because in theory I'd like to keep AGS 3.5.* backwards compatible as much as possible.

One thing that I might mention, you create new camera every time a room is loaded, but that camera is never deleted.
Custom Viewports and Cameras are bit special in a way that they are not automatically deleted even when the pointer variable is gone. You have to actually call .Delete() for it.
(All created cameras are stored in Game.Cameras[] array)

Code: ags

this.shadowsCanvas = DynamicSprite.Create(cam.Width, Room.Height-this.oShadows.Y);

Probably you could just use Game.Camera.Width instead here.
True that! Thanks for mentioning. I used Game.Camera.Width initially, then made some changes, then deleted them and that remained there. I'm still trying to understand the camera/viewport system and their differences D:

Quote from: Laura Hunt on Tue 01/06/2021 08:09:52
Quote from: Crimson Wizard on Tue 01/06/2021 00:02:11
One thing that I might mention, you create new camera every time a room is loaded, but that camera is never deleted.

Off-topic, but this reminded me that in "La Maleta", a warning.log was generated after I finished playing with a huge list of dynamic sprites that were never deleted. Potajito, maybe you've already fixed that, but if not, you might want to look into it :)
Yeah, that should be fixed now!

SMF spam blocked by CleanTalk