Hiya!
Need to do something similar to footprints where repeated copies of a sprite are left permanently across the screen. It's not actually footprints, but that was the best analogy I could think of. Something moving along and leaving sprites in its wake that stay where they're put.
Is there a way to do this with drawing surfaces or dynamicsprites or something that will save me making an object for each 'footprint' or something like that?
I was initially thinking merge into background, but that also deletes the object.
If it's a permanent effect, then drawing onto a room's background may be a way:
https://adventuregamestudio.github.io/ags-manual/Room.html#roomgetdrawingsurfaceforbackground
But modified backgrounds are not saved in between rooms, so if you need this to be kept when returning back to the same room, then you'll have to save the footprint information in variables and reapply the images in "room load" event.
If it's a temporary effect (where footprints are removed over time, for example), then it will require to store a copy of original room background, and tracking their locations anyway.
For temporary effect an alternative to drawing over a background is Room Overlays, which are dynamically created objects:
https://adventuregamestudio.github.io/ags-manual/Overlay.html#overlaycreateroomgraphical
Although this approach will require storing an array of overlay pointers.
Here's a bit more detail:
This is for an access ladder on the side of a spaceship. Initially, it is just two rails, with the rungs able to slide up and down the rails but all clustered at the top of the rail, out of reach. Once activated, the rungs move down the rails as a cluster, with each rung stopping at its designated location. So I need to be able to move a "rung cluster" sprite along a path, "dropping off" an individual rung sprite every n pixels. Once in place, they stay there, and the placement is always the same.
Easy enough to do with objects, but there's 18 of them so I thought I'd see if there was a more efficient way.
I did look at drawing surfaces. I guess I would use DrawImage to place the sprites, but there doesn't seem to be a way to move a sprite within a drawing surface, so I guess I would have to erase and redraw? So maybe the clustered rungs, the moving part, have to be a separate object, and I use DrawImage to drop a rung sprite at certain locations as that object moves?
The effect needs to be permanent, but as long as it plays correctly once, I can replace it with a static sprite when the player leaves, since the arrangement of these things is always the same.
Quote from: FortressCaulfield on Fri 13/06/2025 12:04:10Easy enough to do with objects, but there's 18 of them so I thought I'd see if there was a more efficient way.
After reading your explanation, personally I would not bother with drawing surfaces and just use objects, or room overlays (overlays may be created and removed dynamically). That's the most natural approach IMO, and there's nothing inefficient in them, they take a minuscule amount of memory each; the 95% of memory is taken by sprites, but from your explanation it seems that you will be reusing same "section" sprite (?), thus having no redundant memory duplication.
Drawing on a room background is a "legacy" way of displaying things. Also, using objects / overlays will save multiple abilities: displaying something behind the ladder, applying real-time effects, and so forth, would the need arise.
It would certainly be more convenient if objects supported repeating texture (tiling), in which case you'd only require 1 object for the full ladder, but unfortunately it's currently not the case in AGS.
If you still intend to use DrawingSurface, animating with the drawing surface will be suboptimal, as you mentioned, and combining "complete" part and a moving/animating object / overlay is indeed a better solution. Since the ladder may only expand in one direction, and in chunks, then you will only need 1 variable containing number of sections in order to recreate the background after returning to the room.
Thanks for the help (and, indeed, ALL your help!) I think I'll try the drawing surface just to learn how to use it but if I don't get it within an hour, resort to objects.
What I wanted to avoid was having to deal with making 18 additional objects in the editor, honestly. Possibly skill issue on my part, I admit, but I find myself wishing I could just declare a bunch of objects in script.
Quote from: FortressCaulfield on Fri 13/06/2025 19:42:36Possibly skill issue on my part, I admit, but I find myself wishing I could just declare a bunch of objects in script.
That's what you do with Overlays. Although they are more limited compared to Objects (for instance, they do not have a built-in interaction handling), but they are enough to display and move a sprite.
https://adventuregamestudio.github.io/ags-manual/Overlay.html
I tried it with the drawing surface and it works really well except for one thing... it doesn't update the surface til it exits the function its in, so it draws all the rungs at once.
Then I tried it with overlays but the issue there is I can't do it with a while loop. With the idea to move the rung and drop a copy of it every 50 pixels along a line:
oRung.Move(100,700,5,eNoBlock, eAnywhere);
L+= 10;
while (oRung.Moving)
{
Overlay* OL1 = Overlay.CreateGraphical(oRung.X, oRung.Y + 21, 978);
L = 0;
}
I'd need to be able to put them in an array.
But objects are already in an array.
So either I do it with objects or move the surface drawing function to rep-exec for the room. Hmmm...
First of all, in order to update the game screen the script should return to the engine.
If you are doing something in a loop, then call Wait(1) to let engine update and render.
QuoteI'd need to be able to put them in an array.
You can create an array of Overlays in script:
Overlay* overs[N];
array may be declared outside of a function, in which case overlays persist after the function ends, or locally, in which case they are all removed as soon as the function ends.
Whether to use a loop or do this in rep-exec is a choice to make. Both may work, but which is better depends on circumstances.
>First of all, in order to update the game screen the script should return to the engine.
If you are doing something in a loop, then call Wait(1) to let engine update and render.
I tried that and it didn't work. The function doing this is afterfadein.
I've got my array of objects doing ALMOST what I want, but new problem!
I'm using object.Move to animate them sliding along the rails, from 39,24 to 51,554, no block, eanywhere... but it doesn't go in a straight line. It goes MOSTLY straight but then has to correct with a 6 pixel jump right at the end, which ruins the effect. I guess I'm going to have to use a linear tween.
Is move only capable of straight lines if the ratio of x travel to y travel works out to an integer?
Quote from: FortressCaulfield on Yesterday at 03:21:34>First of all, in order to update the game screen the script should return to the engine.
If you are doing something in a loop, then call Wait(1) to let engine update and render.
I tried that and it didn't work. The function doing this is afterfadein.
Please post your code. This normally is supposed to work, that's how loops with game redraw are done. It's hard to know what may be wrong without seeing actual code.
Quote from: FortressCaulfield on Yesterday at 03:21:34I'm using object.Move to animate them sliding along the rails, from 39,24 to 51,554, no block, eanywhere... but it doesn't go in a straight line. It goes MOSTLY straight but then has to correct with a 6 pixel jump right at the end, which ruins the effect. I guess I'm going to have to use a linear tween.
Is move only capable of straight lines if the ratio of x travel to y travel works out to an integer?
Hmm, I imagined we are speaking about a ladder moving straight vertically, but apparently it's a diagonal move.
AGS pathfinding and move has imprecisions (they were improved in AGS 4.0), but "6 pixels jump" sounds way too much. Usually I'd expect a correction within 1-2 pixels. I cannot imagine how does your case look like in practice, can you post some screenshot? What is the mask resolution setting in this room?
In any case, using a floating-point movement (either scripting yourself or with a tween module) might solve imprecise object motion.
room is 1280x800. I have it working now. I bypassed tweens and moves altogether and just handled all the movement directly in a loop.
the original version using the draw surface looked like this:
oLad1.Graphic = 978;
oLad1.SetPosition(39, 19);
oLad1.Move(51, 559, 5, eNoBlock, eAnywhere);
DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
while(oLad1.Moving)
{
L++;
if (L == 9) //puts rungs 45 pixels apart
{
surface.DrawImage(oLad1.X, oLad1.Y, 978);
L = 0;
}
Wait(1);
}
Moves the first rung like it's supposed to be the others aren't drawn in til it exists room_afterfadein
Quote from: FortressCaulfield on Yesterday at 14:09:47room is 1280x800.
I meant the "Mask Resolution", that's a setting that tells a ratio between room background and walkable mask, it may be seen in room properties.
If it's too high (like 1:4) then the moving characters or objects may seemingly "jump" between coordinates (idk if it's your case, I suppose you would have other issues with that too if that were the case.)
Regarding your DrawingSurface code, you did not call surface.Release() prior to Wait. Unless you call Release, the surface will not be updated, it works like "Submit changes". In principle, working with DrawingSurface inside the loop would be like:
> loop
- get drawing surface
- draw stuff
- release surface
- wait(1)
<
Mask resolution is 1:1.
I did try release, but I thought once released I couldn't use it again and would need to declare a whole new surface with a different name, like merging an object with the background.
At any rate, the version I made with the objects works and allowed me to have them move in a different way that works better. Thanks for all the help though!