For my university assignment I have to make a networkable version of pacman. I thought I would best approach this problem with making a local copy of pacman first and then extend this functionality for network play.
I would have to say that I am relatively new to java GUI development and utilizing such features within java.
http://www.planetalia.com/cursos/Java-Invaders/
http://javaboutique.internet.com/PacMan/source.html
I have started following the above links with regards to game development within java and an example of the pacman game.
I decided to represent the maze as an int array with different values meaning different things. However when the paint method inside the main game loop is run i am redrawing the whole maze with this method.
for (int i : theGame.getMaze())
{
if (i == 4)
{
g.setColor(mazeWallColour);
g.fillRect(curX, curY, cellSize, cellSize);
curX += 25;
}
else
{
curX += cellSize;
}
index++;
// Move to new row
if (index == 25)
{
index = 0;
curX = 10;
curY += cellSize;
}
}
However this is providing me with less then 1fps. Although i've noticed the example linked above uses a similar way of redrawing each time the paint method is called and i believe does this on a image that is not viewable (kinda like double buffering [I've used a BufferStrategy like the first link explains]) What would be a better way to redraw the maze?
Any pointers/advice with this would be useful.
Thank you for your time.
http://pastebin.com/m25052d5a - for the main game class.
Edit: I have just noticed something very weird happening after trying to see what code was taking so long to execute.
In the paintClear(Graphics g) method i have added
ocean = sprites.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));
g.fillRect(10, 10,getWidth() - 20,getHeight() - 110);
which made the whole thing run smoothly - however when i removed these lines the whole thing slowed down? What could have caused this?
Updated code
First off, I'd recommend that you use named constants rather than having random magic numbers in your code and consider using enums for your cell types. While it won't make your code run any faster, it certainly will make it easier to understand. Also, 'i' is normally used as a counter, not for a return value. You should probably call it cellType or something similar. I'd also recommend that you use a 2D array for your stage map since it makes a number of things easier, both logistically and conceptually.
That said, here are a few things to try:
Pull the setColor() out of the loop and do it once. The compiler might be able to do loop-invariant hoisting and thus do this for you (and probably will), but conceptually, you should probably do this anyway since it appears you want all of your walls to be one color anyway.
Try calling drawRect() instead of fillRect() and see if that draws faster. I don't think it will, but it is worth a shot, even if it looks uglier. Similarly, you can try creating an Image and then drawing that. This has the advantage that it is really easy to tell your Graphics object to implement a transform on your image. Also, consider taking this out completely and make sure that it is being a significant performance hit.
Also, normally you don't need to ask for the parent for its Graphics object and implement painting directly on it. Rather, you should override its paintComponent() method and just utilize the Graphics given to you (possibly calling helper methods as you do). Swing components are double-buffered by default, so you don't need to implement that yourself; just let the swing object do its job and let you know when to paint.
Also, you end up repainting the entire screen, which is something of overkill. If you call repaint(Rectangle), Swing can choose to redraw only the sections of your board that are explicitly marked dirty. When you update one of your sprites, call repaint(r) only on the area of the sprite's old and new locations. When you complete a level and need a new board, then you can call repaint() (without parameters) to redraw the entire map.
You should also look at Sun's tutorial to get some tips for efficiency in Swing.
I still consider myself a beginner with Java, but I recently developed a Frogger-esque game with dynamic map and editor using some of the techniques you've mentioned, and I'm only too happy to provide some help.
As mentioned, enum's are the way to go. I set my map up as a 2-dimensional array and set an enum for each different type, writing a method inside my map class to take in one image and divide each square in the map to each value in my enum.
A tutorial that helped me with mapping can be found on Coke and Code. All the source code is there if you need a hand with any of it, although you do seem to have a decent grasp of what you're doing. If you still need help I could always drag out some source code.
It looks like your call to Thread.sleep doesn't do what you intended, but I don't think it's the source of your trouble. You have:
Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));
startTime will always be less than System.currentTimeMillis(), so startTime - System.currentTimeMillis() will always be negative and thus your sleep will always be for 0 milliseconds. It's different from the example you showed because the example increments startTime by 40 milliseconds before doing the calculation. It is calculating how long to sleep for to pad out the drawing time to 40 milliseconds.
Anyway, back to your problem. I'd recommend measurement to figure out where your time is being spent. There's no point optimising until you know what's slow. You already know how to use System.currentTimeMillis(). Try using that to measure where all the time goes. Is it all spent drawing the walls?
EDIT - I see this got marked as accepted, so should I infer that the problem went away when you fixed the sleep time? I don't have a lot of Java GUI experience, but I can speculate that perhaps your code was starving out other important threads. By setting your thread to have maximum priority and only ever calling sleep(0), you pretty much guarantee that no other thread in your process can do anything. Here's a post from Raymond Chen's blog that explains why.
The code you listed above can't be the source of the 1fps problem... I have code doing far more than this that runs far faster.
Can you benchmark that code and make sure it's the root of the problem?
I'm no game developer, but that framerate seems very slow.
I'm not quite sure how your code is working, but one possibility for improving rendering performance would be to find those parts of the display that don't change much (such as the walls of the maze) and avoid re-creating them for each frame.
Create a BufferedImage containing the constant elements (maze?, background) and then re-draw it first for each frame. On top of this Buffered image, draw the variable elements (PacMan, ghosts, dots, etc).
This technique, along with many other Java2D performance tips, is discussed in Romain Guy's excellent book Filthy Rich Clients.
Just so you don't worry that it's Java, I worked on a Spectrum Analyzer (Like an o-scope) where the entire GUI portion(the trace, menus, button & wheel handling) was done in Java. When I got there it was getting 1fps, when I left it was 12-20. That had a lot of processing going on and was running on a very slow processor.
Look at only updating parts of the GUI that you need to update. Often you can redraw the entire screen but just set a clipping region to the part that is truly updated.
Be careful about inner loops--they are The Speed Killer.
Try to avoid allocating and freeing huge numbers of objects. I'm not saying don't use objects, I'm saying don't create one for each pixel :)
Good luck
Wow, that's a pretty tough problem to give someone just learning Java.
My advice? Think in terms of objects. Can you write something WITHOUT a user interface that mimics the behavior of the game itself? Once you get that working, you can concentrate on the special problems of the user interface. Yes, start with a local version before the networked piece.
I'm not a gamer. I wonder what Java2D API would offer to make your life better?
How much time do you have to finish it?
This might sound obvious but your performance problem is because you are redrawing the entire maze, which doesn't need to be done, instead you need to redraw only changed parts of your maze.
The way I've approached this issue before is by seperating the updating of the maze from the actual redrawing into different threads (kind of like a threaded MVC). Every time you change a cell in your maze you would mark it as "dirty", your redraw thread will check every now and then to redraw only the dirty cells.
Sorry for the extremly generic advice
Java/Swing double-buffers by default. If you're using Swing, you don't need to double-buffer separately, like other answers suggest.
I agree with Allain, that the code you listed can't be the cause of 1fps. I've written highly inefficient Java/Swing animation code that runs much faster than you describe. Do some more testing to narrow down the cause of the slowness.
If possible, you should keep an image of the maze, and draw it in one library call. It probably doesn't need to be full resolution, either -- if you want a blocky, 8-bit feel, I expect the graphics library will be more than happy to oblige 8^)
Also, as others have mentioned, you can save time by redrawing only those parts of the screen that need updating. This can be annoying to implement, but it may allow you to significantly improve your frame rate. Be sure to do some experiments to make sure this is the case before exerting the required effort!
Related
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.
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.
I am developing a shoot'em up type video game using Java Swing and I'm using a Java Swing Timer to control all of the screen updating. The main screen uses a BorderLayout, and I perform my graphics on a Panel contained within the BorderLayout, and use the AWT Graphics calls to draw.
Now as my game progresses, I would like to speed up the movement of my screen objects (ships), yet I still want them to smoothly cross the screen. I thought I could speeed things up by dropping the timeout value for the Java Swing Timer, down to around 5ms. But, I've noticed when I set it to anything less than 15ms, there does not seem to be much difference. Once you cross that threshold, there is almost no noticeable difference in performance. -Why is that?-
Another option would be to increase how many pixels each ship moves per update, but anything beyond 3 or 4 pixels, and things start to look jumpy.
Any ideas? And really want to keep the game in Swing, would prefer at this point not porting to a 3rd party library.
Thanks.
In all likelihood, this isn't a software issue, nor is it fixable with software. Your screen probably only refreshes about 60 times a second, meaning that the frames are only drawn 60 times per second, or once every (approximately) 16 milliseconds. Since this is a hardware barrier, there's no way to get it to update faster with software. You can probably count on your users only having 60Hz monitors, too, so it's more worthwhile to look into other solutions.
One solution that pops to mind is adding in motion blur, to make it seem like the ships are moving faster when they really aren't. It'll allow you to 'jump' a greater distance before it looks jumpy, since the blur tricks the eye into thinking it's going really fast instead of hopping across the screen. Unfortunately, the only things that I see to do motion blur are third-party libraries, though you may have better luck Googling.
I advise you that you change your Swing engine for JavaFX (at least), a technology with better performance and more tools to your disposal. Swing nowadays is considered a dead technology, as well as with the AWT before it. A great place to study and start JavaFX would be this one:
http://docs.oracle.com/javase/8/javase-clienttechnologies.htm
The ideal for the development of games, would be to use a library prepared for it, such as libGDX:
http://libgdx.badlogicgames.com/
But if your desire is to create a game in Swing, who am I to judge? Sometimes it is good to see old things. I myself still like Swing, even being obsolete compared to other things.
I think you may be implementing a wrong gameloop. Swing Timer does not really seem like a good way to update game logic. Even with different settings between different computers, is generally practical and easy to implement a gameloop to work properly, especially for the correct movement of the characters.
You see, a gameloop is the heart of a game, and needs to be implemented straight otherwise the game is developed wrong and with several limitations. Generally, in gameloop we have to take into account the desired FPS. Among game updates, we must take the time elapsed between the last update and the current update, so-called delta by many developers. You will find many materials about it on the internet, which I recommend:
http://dewitters.koonsolo.com/gameloop.html
http://www.java-gaming.org/index.php?topic=21919.0
https://www.youtube.com/watch?v=9dzhgsVaiSo
The past links will help you for sure, but if you want more about it, I recommend that you take a look at this book:
http://www.brackeen.com/javagamebook/
Even the material being old (as Swing is) you'll find details of how to implement a good gameloop with a keyboard and mouse iinput system, sound, the use of the best possible performance swing has to offer, among other cool things. And one more thing... To give you a better result with respect to the movement of the characters, I advice you to use position variables (X and Y) with decimal types such as float or double.
I hope you can do what you want. Good luck!
I'm a novice programmer and recently I came across many methods of animation:
Using BufferedImages , ie. draw to image and display using double buffering or triple buffering methods .
Making my sprites components by extending Component or Button . and repainting by repaint(g).
Rastering, using rasters and integer arrays, bitmaps and the like.
I realise that method 1 and 2 are similar as they use paint() methods , however Rastering involves self-made functions , eg. creating functions that set background by traversing the whole array representing each pixel and setting colour to desired colour .
I've seen many folks online use raster methods even though 1 & 2 seem simpler .
Please help me out here guys and tell me what path i should follow and why .
The first and second methods are very similar and would come down to the context of the problem.
The third option would, for the most part come down to providing a flexible API which was independent of the toolkit or framework which was to be used to dipslay it. One could argue that there is a speed increase, but with Swing and JavaFX working more directly with the DirectX and OpenGL pipelines, this is less of an issue.
Unless your planning on dong some seriously low level functionality or interfacing to a non-standard API I wouldn't worry to much about it (some effects painting might be faster done this way, but it's all about context)
Personally, it would focus on developing an understanding of the basics and principles involved and how they might be implemented using the first two options as it allows you to focus on those concepts with a relatively easy API
As time progress or you come across a situation that can't be resolved using these techniques, then it might be time to consider playing with the rastering approach.
Remember though, you still need to get that byte array into a format that the API wants which in of itself, will add overheads
As my research goes everywhere it's said that we should only use one sprite batch per instance. But what if i set sprite batch to static in class which controls the game (calls different screens etc).
When i have tryed this its working like charm, but is that a good practice or it may result some problems in future. Then if it could be done can i also share stage and shape renderer?
note: the main reason why i am trying to go with that "static batch technique" is that java crashes when i try to dispose stage, sprite batch or shape renderer
I do it that way as well and I didn't run into any problems so far.
You need to be careful with the SpriteBatch.begin() and SpriteBatch.end() calls, since you may never know where it was started already, and where it was stopped when it is shared.
Same applies for the Camera/ProjectionMatrix. And also for the currently used ShaderProgram in case you are working with shaders.
Make sure that you are always fully aware of where you are doing what with your SpriteBatch otherwise you might face weird bugs one day.
Stage should not be shared, since it will probably serve different purposes. For different UIs it doesn't make any sense to use only one Stage.
ShapeRenderer could be shared, since it kind of works the same like SpriteBatch, but probably you only want to use it in a single place.
dispose() should actually work without any problems. You have to make sure that you dispose everything in the correct order so nothing will be left over in the end and cause exceptions.
As #noone allready said it should not cause any problems, if you take care.
But i just wanted to point out another thing: In some Screens (MenuScreen, OptionScreen, ...) you may use Scene2dUi for some UI stuff. So you will use Stages, which belong to the Screen and are not shared. So in this case you should remember, that every Stage has its own SpriteBatch and Camera. So it could be, that you only need an additional SpriteBatch in your
GameScreen. If this is the case i would not make it static and have it only in the GameScreen.
As noone said dispose() should work, if you use the correct order, and so also going with more then 1 SpriteBatch should not cause any problems.
So i think both ways will work and are good approaches. It depends on your design and how/where you want to use the SpriteBatches and Cameras.
If I'm making a game and I want certain things to only update every so often, what's the best way to approach this?
My naive thinking is just keep a "frame" tracker that cycles via mod. math and update certain things at certain numbers.
Is there a better approach?
Much appreciated!
The easiest way to fit your game 'loop' into the libgdx system is to assume your ApplicationListener.render() method is invoked at some unknown (and perhaps variable) frequency. In this callback you'll need to figure out how much time has passed since the last call, update any time-dependent actors, and then draw the update.
This means you should make decisions about updating something "every so often" based on actual elapsed time, and not number of frames.
See the accepted answer on this question for some sample code that does this (note the 'getDeltaTime()' calls):
How to move a sprite with the keyboard keys using libGDX?