ID:1020972
 
(See the best response by Hiead.)
In another post I saw somebody saying that images should be created when the program is first run, and saved for later use.

Is it possible and/or worthwhile to do this for images that will be displayed in many different locations, i.e. 'special effects' like an explosion?

What I mean is, I always thought I had to use the image() proc for each new explosion/whatever. Is there a way to only use image() once and then create new instances of the graphic when needed?
image() returns an /image object. Depending on how you use it, this may not actually affect you. For example, you can add a single object instance to multiple lists; one object as an overlay for multiple objects.
How are you using images?
Best response
For your uses, it may or may not be beneficial.

If I remember to do so, when I get back in a couple weeks, I'll write up an article regarding this. In the meantime, probably the most practical application of this is for HUDs and other on-screen items that are redundant for every player. I believe that Shadowdarke's RoofLib used this method, also.
Well, one way I'm using images is to draw projectiles. I have a proc that calculates the path of a projectile and checks for collisions without using any movement functions. So, without an atom moving across the screen, I wrote another proc to draw the path:

    RenderProjectile(obj/weapon/firetype, location, direction)
set background = 1
var/image/I
I = image('fire.dmi', location, firetype.state, MOB_LAYER + 1, direction)
world << I
spawn(firetype.frames) del I


Because the image proc takes a location argument, I thought this was the only way to draw the image in different locations every time. Then I realized that you can actually modify the image object's loc var, although I don't know if this really does anything once it is attached to something, and furthermore I still need more than one instance so that the same image can be seen more than one time on the screen. Right?
So using Rise of Heroes as an example & the FireBolt spell in the game, you want something that shoots a FireBolt like normal but only show the image of the FireBolt shooting towards the enemy to kill it, to the one that used the spell?

If so, maybe this will help clarify to others who can help what your use case is & help you to achieve it.
Not exactly. The projectiles actually move along a path and have collision detection. Otherwise I would just use missile() :D
OK, so basically an object that moves in a pre-defined manner triggered by something, potenetially multiple people able to see different ones, triggered by the same thing but moving across a different path for each person(or the same path but at different spots.

If it were one path, one spot for all people but visibility should be determined by a pre-set condition then you could link the image() for each person to that moving object(invisible) & only apply the appropriate collision if they can see it, otherwise ignore them.

If it needs a different path for each new person & moves along with collision detection it may be appropriate to make multiple normal objects(invisible) linking the image to said object & delete it when it's no longer needed for the person(s) involved.

image(s) aren't really meant to be moved around, unless not linked to an object but a location, in which case you can keep re-setting the images location to move it along a set path...

Really there are multiple ways to do what you want, we just need a simple clarification to give you exactly what you want for the use case your desiring.
In response to Superbike32
The more practical way to have a moving projectile is to just use an /obj. If the /obj needs only be visible to certain people, use atom.override and attach an image (one image) to it to be displayed to those certain people.
In response to Superbike32
Superbike32 wrote:
image(s) aren't really meant to be moved around, unless not linked to an object but a location, in which case you can keep re-setting the images location to move it along a set path...

Well, no. Images aren't really meant to not be attached to an object. If the object they're attached to is intended to be moving, then they are also intended to be moved around.


Magicsofa wrote:
In another post I saw somebody saying that images should be created when the program is first run, and saved for later use.

Depending on what posts you were reading, there is a decent chance you are misinterpreting this in one or more ways.

Possible interpretations that would make your statement valid:

- The first time you create a dynamically generated image you should decide if it is likely to be reused in exactly its current form without any modifications. If the answer is yes, it should be stored and used for later.

- If you are ever using a dynamically generated image whose generated result is always the same (such as a transparent equivalent of a normal icon) then you should generate it ahead of time and include it in the project, rather than just generating it every launch.



Then I realized that you can actually modify the image object's loc var, although I don't know if this really does anything once it is attached to something, and furthermore I still need more than one instance so that the same image can be seen more than one time on the screen. Right?

You shouldn't be moving images directly. If you are intending to move an image then it should be attached to a movable atom, and you move the atom instead of the image.

No, you do not need more than one instance of the same image to display it to more than one person.

var/image/I
I = image('fire.dmi', location, firetype.state, MOB_LAYER + 1, direction)
for(var/client/C)
C.images+=I


The above sample would function, and all clients in the world would be shown the same image file.

If this image file were attached to an object any movements to the object will be reflected immediately, just like the image were an overlay or underlay.


What I mean is, I always thought I had to use the image() proc for each new explosion/whatever. Is there a way to only use image() once and then create new instances of the graphic when needed?

Yes. It involves your programming design, you're already currently capable of doing it with your current knowledge, your mind just needs to understand what you're trying to accomplish and why. Once you get that far, it's actually very simple to do what you want. An example of my code where var/image/tI is a var storing a transparent image.

/.../proc/AddViewer(mob/M)
if(counterSeen==0) //my internal var, this means nobody is currently looking at this
if(!tI) tIBuild() //if there isnt already an image for this, create it

counterSeen++
if(M.client) M.client.images+= tI


Since in my code I keep track of counterSeen internally, I don't need to check to see if the transparent image has been generated if its value is nonzero. You could simply have the if(!tI) Make TI Proc() line, and that would accomplish our purpose.

tIBuild() is simply a proc that fills the tI var with an image it generates. All we're trying to accomplish by checking to see if the image has already been generated is to avoid making it again, because pretty much anything we program is slower than simply doing a var check. So instead of creating a new image each time, we are simply doing an if() check each time.


In your case, you are likely using a projectile image that isn't going to change and is going to be the same for everyone who sees it, and there is no need for it to be generated on the fly. As a consequence, I would say:

Kaiochao wrote:
The more practical way to have a moving projectile is to just use an /obj. If the /obj needs only be visible to certain people, use atom.override and attach an image (one image) to it to be displayed to those certain people.

Simply go with a normal object, normal icon, pixel offsets, etc. Images are generally something you would want to use in cases where you want different players to view the same object in different ways, or not view the object at all. (Or if you want to dynamically generate different images)

If you really want to look more at the idea of only generating an image when it is needed, you can see fully working versions of my examples in my tree transparency lib. However, there is really nothing more to the process than what I showed you here.
http://www.byond.com/developer/AJX/TreeTransparency
In response to Kaiochao
Kaiochao wrote:
The more practical way to have a moving projectile is to just use an /obj. If the /obj needs only be visible to certain people, use atom.override and attach an image (one image) to it to be displayed to those certain people.

Why is this more practical? I figured that creating a new atom requires a bit more processing than a new image, and furthermore I want some of my projectiles to have trails, which means I would have to create a ton of images anyway. However, all projectiles are visible to everyone, so that aspect of /images is not really being used in this case.

AJX wrote:
Depending on what posts you were reading, there is a decent chance you are misinterpreting this in one or more ways.

It was in reference to the on-screen menus in NEStalgia. I think the poster said that all the menus that could be displayed were generated once at runtime, rather than every time you open a menu. This makes perfect sense to me but of course the menus always appear in the same spot, unlike projectiles flying around the screen.

No, you do not need more than one instance of the same image to display it to more than one person.

I'm currently displaying all images using >> world. (Side question: does that 'display' the images to non-client mobs??)

Here's a scenario that might better explain what I'm asking about: A player clicks on the map, causing a projectile to be fired due east. Then they take a couple steps to the north and click again, this time to the east and a little bit north of their location. Another projectile appears, with a different origin and slightly different angle of motion. Both projectiles are on-screen at the same time, but always at different locations. They also have a trail animation lasting three frames, meaning the "head" of the projectile as well as a three-tile-long "tail" must be rendered.

What I'm doing now is creating a new image for every location that the projectile passes through. The images do not move since they are attached to a turf, and they have an animation that looks like it is "dwindling away." In other words, four images are visible for each projectile, each one in a different frame of their animation.

The trail effect could theoretically be created using big icons, but this seems far from practical. I would have to make about 32 rotations for each one, and include animations for the initial firing and collision of each one so that it doesn't stick out behind you when you shoot it or disappear instantly when it hits something.




In response to AJX
Kaiochao wrote:
An example of my code where var/image/tI is a var storing a transparent image.

But, can you display ten replicas of tI at different locations without using the image() proc?
In response to Magicsofa
Magicsofa wrote:
Why is this more practical? I figured that creating a new atom requires a bit more processing than a new image, and furthermore I want some of my projectiles to have trails, which means I would have to create a ton of images anyway.

Because you were proposing moving the image manually, which isn't really 'intended' or 'effective'. Creating a new atom does require more processing than a new image, this is true, but there is more to it here than just that.

Trails can easily be applied as overlays with pixel offsets.


AJX wrote:
Depending on what posts you were reading, there is a decent chance you are misinterpreting this in one or more ways.

It was in reference to the on-screen menus in NEStalgia. I think the poster said that all the menus that could be displayed were generated once at runtime, rather than every time you open a menu. This makes perfect sense to me but of course the menus always appear in the same spot, unlike projectiles flying around the screen.

The spot they're appearing is less of an issue than the manner in which they're appearing. If the text on the menus isn't changing, then yes preloading is a great idea.

No, you do not need more than one instance of the same image to display it to more than one person.

I'm currently displaying all images using >> world. (Side question: does that 'display' the images to non-client mobs??)

(From my understanding, which may come to be corrected) No. I figure any attempts to display an image to a non-player using the << method will likely be ignored or simply have no effect. And I assume any attempts to manually add an image to client.images where there is no client present will of course throw runtime errors.

Here's a scenario that might better explain what I'm asking about: A player clicks on the map, causing a projectile to be fired due east. Then they take a couple steps to the north and click again, this time to the east and a little bit north of their location. Another projectile appears, with a different origin and slightly different angle of motion. Both projectiles are on-screen at the same time, but always at different locations. They also have a trail animation lasting three frames, meaning the "head" of the projectile as well as a three-tile-long "tail" must be rendered.

What I'm doing now is creating a new image for every location that the projectile passes through. The images do not move since they are attached to a turf, and they have an animation that looks like it is "dwindling away." In other words, four images are visible for each projectile, each one in a different frame of their animation.

The trail effect could theoretically be created using big icons, but this seems far from practical. I would have to make about 32 rotations for each one, and include animations for the initial firing and collision of each one so that it doesn't stick out behind you when you shoot it or disappear instantly when it hits something.

There are lots of ways to handle trails, really just a choice of preference until you have more requirements to work with. I'd just add each step of the trail as a new step is taken, then upon collision remove the farthest away each "step" duration until none remain then remove the projectile.


Regarding your projectiles, I think you have everything necessary to construct a better system. You already are doing the parts that are usually considered "difficult", such as the actual pixel movement and collision itself.

If you still have any specific questions feel free to shoot, but since your main issues appear to be with aesthetics it may be more beneficial to you to check out some of the pixel movement libs on the hub and see how they handle it. Some of them do it well, some not so much. It can be a good exercise to try and figure out which are useful or not.

Magicsofa wrote:
An example of my code where var/image/tI is a var storing a transparent image.

But, can you display ten replicas of tI at different locations without using the image() proc?

Your quote was miss-tagged, I said that not Kaio.

To answer your question, yes, but only by using the image as an overlay or underlay on other objects. (as I understand it underlays and overlays are actually images generated when they are added, and so are independent of the originals being used to add to the list. )

If I were intending to use the image at multiple different locations, I would generate the icon first, then set it wherever it was necessary. If it needed to be on a moving object, I'd give it its own moving object, etc.

In actual practice, no, I could not. The reason being my code is for displaying a second version of tree icons which is see through, letting the player see what is behind it. Since each image is attached to its own tree, because each tree has its own sight handling, I wouldn't be using this image elsewhere.


This however works. It's a modified version of Volte's dynamic shadows lib, to prevent generating a new shadow every single time one is needed. Can also be found in my aforementioned lib. Same purpose as the other code, no reason to generate new copies of icons that I have already generated.

// ...
var/iconHolder/iH=locate("[type]:[angle]:[thedir]")

if(!iH)

iH=new
iH.tag="[type]:[angle]:[thedir]"

iHCount++
//Log("[iHCount]: [iH.tag]","iH")

iH.icon = icon(src.icon,src.icon_state,thedir) // Duplicate src's icon, and darken it the right amount
iH.icon+=rgb(255,255,255)
iH.icon-=rgb(BrightSubtract,BrightSubtract,BrightSubtract)

var/icon/I=new(iH.icon)
I.Turn(angle) // Turn the shadow in the right direction.
iH.icon=I

iH.pixel_x += cos(90-angle) * 16 // Displace the shadow correctly.
iH.pixel_y += sin(90-angle) * 16 - 16

src.underlays+=iH
// ...


Thanks for all the help guys...I am going to work on improving my projectile handling in multiple ways. I just did a test with 62 projectile-firing AI's with projectile rendering disabled, and got significant slowdown. It is quite a bit worse with my image-based rendering enabled too so I think I'll take a look at those libraries and see what I can do about both the rendering and the actual projectile calculations

I don't think I will have 62 projectile enemies at a time in the actual game but better safe than sorry :D