Reputation: 50
I'm trying to decide between several ways of drawing images for objects in a game.
I want objects to have their own draw()
method, but I'm afraid that I may cause unnecessary copies of the image or some other drop in efficiency, noticeable or not.
The first way loads the BufferedImages
when the level starts.
public class levelone{
BufferedImage imageguy;
public void draw(Graphics2d g){
g.drawImage(imageguy, null, guy.getx(), guy.gety());
}
}
The second way loads the image in the guy.class and draws it from there with just a guy.draw(g);
call in the levelone.class.
The third way loads the image in levelone.class and draws it from guy.class with just guy.draw(imageguy, g);
in levelone.class.
Help me understand the best way to go about this please. If it's not clear what I'm asking, do tell and I'll try to make it more comprehensible.
Upvotes: 3
Views: 65
Reputation:
This is more of a design question. For a start, this:
... some other drop in efficiency, noticeable or not.
... is not a very healthy or productive way of thinking. If it's not noticeable, it's not worth worrying about. Otherwise you might as well be writing your game in assembly code if you are going to obsess over every clock cycle.
But there might be broader scale design-level scalability concerns here of note.
It's worth noting that coupling rendering/drawing logic with a high-level class can become a maintenance burden. It depends on the scope of your project, but if it's a rather large project, you'll have a lot more breathing room if you separate the drawing/rendering logic from your game logic. Then you can focus your full attention on just what a "Monster" or an "Item" or something of that sort needs to do from a game design standpoint without worrying about how it'll be drawn. The drawing is done elsewhere.
But if we assume you want to have the drawing logic inside these objects anyway, then it seems like your question ultimately boils down to where you want to store some image buffers for graphics related to the objects in your game.
And the short answer is, "it depends". What assumptions do you feel confident making? For example, in your posted code:
public void draw(Graphics2d g){
g.drawImage(imageguy, null, guy.getx(), guy.gety());
}
... this seems kind of ridiculous if all you'll ever do is blit the object image to the graphic. If all you're ever going to do is blit the item's image to the graphic, then you might as well eliminate the draw
method outright, expose a public accessor to the image, and let one central place handle the responsibility of blitting those images at the right time and place.
And at that point, if all you're doing is storing images and exposing accessors to them in your objects, then you might as well let the outside world concern itself with loading/storing those images and blitting them, leaving your objects clean and devoid of drawing logic outright. That'll also give you the most flexibility to optimize when and how things are drawn without intrusively touching all your objects.
But are you always going to just blit images from an object? Will there ever be a case where an object in your game might draw additional things, shapes, text, etc? If so, you might want to keep the draw
method.
So the ultimate question to me is, do you really want to do drawing inside your objects or not?
If not, then you'll have the most flexibility to optimize to your heart's content, since you can leave the responsibility of most efficiently loading and storing and drawing graphics to a central render engine instead of spreading that responsibility over every object in your game (and potentially having to change all of them if you ever want to do things differently).
if you do want this, then you might as well fully encapsulate all the details involved with rendering an object inside an object, including keeping whatever assets it needs to do that so that the outside world doesn't have to bother with it and can just call 'draw' and pass in a drawing target (Graphics2D, e.g.).
So I would suggest that maybe none of your proposals may be ideal. But if there's one option that might be bad, I'd say it's your third. That is:
The third way loads the image in levelone.class and draws it from guy.class with just guy.draw(imageguy, g); in levelone.class.
The problem here is that you're kind of getting the worst of both worlds. You're leaking the drawing details of this 'guy' to the outside world, but the outside world still has to depend on the 'guy' to do the drawing by passing those drawing details back in. If nothing else, you want to really give either the guy or the outside world the primary responsibility here, with the latter being more flexible, but the former being more encapsulated. When the outside world has to pass a guy's image back to the guy for the guy to draw, then you get neither of these benefits. If you really want a guy to "draw himself", then you generally want to be able to do it without too much help from the outside. Give one entity the firm responsibility instead of spreading it across multiple.
About unnecessary copies of the same image, that's easily solved no matter what you do with a central image cache. An easy way is just use a map. When loading an image, search the map for the path. If it already exists, return a reference to an already-loaded image. Otherwise load the image and insert that the path/image as a key/value pair to the map.
Upvotes: 1