I'm a bit stumped on an Android game I am developing, so maybe someone can help me. Don't bother suggesting AndEngine; I've made it this far on my own and I'd prefer to continue on this path if possible.
The game I'm working on is a simple platformer. Originally the levels were loaded as massive bitmaps, but a few out of memory errors made it obvious that I had to come up with a more efficient system. Now I'm parsing out .tmx files into a 2d array and using a method that creates a bitmap slightly bigger than the device's screen and fills it with the appropriate tiles.
The issue is that accessing this 2d array 1500 times (using 16x16 tiles) is very expensive, and I'm having trouble figuring out a way to not do that so much. Currently I'm having to redraw the image every time I pass over 16 pixels. Current ideas include using larger tiles (smaller array, still limits level size though), attempting to shift the contents of my bitmap and only load in the new row about to be displayed, or using a larger bitmap so that new images don't need to be loaded as often. Any suggestions?
Unless already done or impossible; consider separating the background from the foreground.
If you use a simple background (think Super Mario plain blue backgrounds) then you can most likely reuse those tiles/that bitmap/color/gradient much longer than the foreground elements.
This will also make your array/s contain lots of empty spaces where no foreground exists, meaning you could collapse the array and only store the parts containing tiles. Collapsing the arrays will come with the drawback that you will have to store a height attribute for the tiles to know where they are supposed to go.
(A background separate from the foreground also give the possibility of parallax-effects (background moving in different speed than foreground))
An example of how this changes your lookup:
Consider the game is being run on a 480x800 screen in landscape-mode.
This means 50*30 (1500) tiles to look up.
Every tile is saved in a 2d-array.
The current visible area looks like this:
A ground area, 4 tiles high.
A platform, 5 tiles high and 20 tiles wide, somewhere above the ground.
Another platform 3 tiles high and 5 tiles wide, also above ground.
A wall extending from the ground to the top of the screen, 5 tiles wide.
Removing the background tiles and collapsing the arrays we only have to look up the tiles:
Ground tiles: 50*4
Platform1 tiles: 5*20
Platform2 tiles: 3*5
Wall tiles: 26*5
Total lookups: 50*4 + 5*20 + 3*5 + 26*5 = 445 which is less than a third of the original 1500.
Now, of course there is some extra work to be done to figure out the position of each tile and drawing the background, but assuming a badly optimized case where this takes as much time as the lookup it is still less time than 1000 lookups.
Of course, this is just one of possibly many approaches to the problem.
Also remember small things like that 2d arrays are much slower than 'flat' arrays. If you cannot put the data in a 1d-array, try to minimize the nested calls, e.g. get one row or column at a time and perform the lookups from that array before switching to the next:
//Really bad:
for(int x=0; x<array.length; x++){
for(int y=0; y<array[x].length; y++){
Object o = array[x][y];
}
}
//Better (can be made even better by using the for(Object o : array)-syntax):
for(int x=0; x<array.length; x++){
Object[] yArray = array[x];
for(int y=0; y<yArray.length; y++){
Object o = yArray[y];
}
}
I had to develop this project where we needed to download tiles of image from the web and display them as one whole image. The thing was a casual scroll would end up crashing the entire app because the VM would throw a OutOfMemory Exception. So I developed a view using a TwoDScrollView and MxN ImageViews, which downloaded only those views which were in the users view. As the user scrolls, we maintain a cache and start de allocating images that are "far" away from the viewing region. It was slower but it stopped crashing.
I won't be able to share my part of the code. But here's a Github repo that uses the same approach. Good Luck :)
I can't vouch for them but here's a project specifically fits your needs
Related
I was working on my own procedural generator and finished making it.
Here is how I did it,
generate the entire world at the beginning,
store info about spawn positions and tiles positions into arrays and data structures
Now obviously, I have to loop through all the arrays, to render/update stuff,
this is creating problems,
I tried dealing with this problem by applying a condition that if any object is visible, only then render update else don't, but it does not make much of a difference.
my TILE_SIZE is 1 world units
so when my world size was
a)500 by 500,fps was 60
b)2000 by 2000, fps was 50
c)5000 by 5000 fps decreased further and so on
If only I could know how Terraria does it, or any way it done, would really help thanks.
I have to loop through all the arrays, to render/update stuff
You don't have to do that.
For rendering stuff you really only need to consider the blocks that are close to the player. Here is some code(x, y are the player coordinates, width, height are the dimensions of your world, render(x, y) is a placeholder for your rendering functionality, and for simplicity I assumed the player can see 100 blocks in each direction):
for (int i = Math.max(x-100, 0); i ≤ Math.min(x+100, width); i++) {
for (int j = Math.max(y-100, 0); j ≤ Math.min(y+100, height); j++) {
render(i, j);
}
}
The process of updating can also be simplified:
For npcs you only need to check a few blocks around it.
For block updates(liquid flowing, sand falling, corruption spread, …) there are actually two possibilities:
Iterate through a different part of the array each update:
Block updates don't have to be that frequent. For fluid flow it might be good enough to update only every 50th block in each update.
You can store the blocks that might need to be updated in an ArrayList(I suggest storing only the coordinates, not the blocks itself).
Then when the update function is called you go through that list and check wether the block really needs an update. If that's the case, you add the blocks neighbors to the list, which will then get updated in the next iteration.
Make sure to remove the blocks you just updated from the list and avoid adding duplicates!
While the second approach is normally faster(ususally the list is only determined by player actions and even if the player decides to drain the entire ocean the whole list would probably take less than ¹⁄₂₀ of the entire world).
But the first approach is certainly easier to implement and will be faster if for whatever reason you have lots of block updates.
Anything you do not see on screen is stored as values. This means that all tiles that are not visible in your viewbox do not get rendered. They are stored as objects (e.g. {x, y, type}); Make sure you count how many tiles are on screen VS how many you are rendering each loop in your code. Never render something that is not visible to the user as this will eat up your memory.
Any tile groups that cannot be rendered soon (i.e. by moving left/right) are not looped through. So say you are using tile sectors to group your tiles, and you're in sector D. Moving left will put you in C, and moving right will put you in E. So these sectors should be loaded in to arrays (but not rendered) There is no need for you to loop through any other sectors (e.g. A or B). So these can be stored externally (e.g. as text files). So they are available, but not taking up space in your games memory.
Good luck. :)
This isn't directly a programing problem but I feel it still can fall under the catagory, I am sorry if this is the wrong place. I am making a game in flash using box2d and I decided to draw the levels in flash as the level design would look better, The levels are very large ( this level is 10,000 pixels long) and the canvas in flash just won't display anything.
The preview in the library seems to be able to display the drawing longer than the one on the stage. How do I go about making the canvas longer? Should I try upgrading to a newer version of flash, does that version allow this?
You just don't put everything at once over your canvas, instead draw only those level primitives or parts that are visible right now. Or, if your level is basically a pretty simple shape, you can just change its X and Y so that the relevant part of the level is displayed on stage.
Don't use giant bitmaps - they use a lot of memory, and even if not all of the content is visible, they will degrade performance considerably. For this reason, Flash imposes a size limit of 4095x4095 pixels (or an equal amount of pixels in rectangular formats).
The way to deal with this is to tile your graphics into parts of equal size, preferably smaller than the stage (1/2 or 1/3 side length is a good measure). You then place them all as a grid into a larger Sprite or MovieClip and set visible=false; on each tile. Then, at runtime, your game loop must check for each frame, which of the tiles should actually appear on the stage - and only those should then be set to visible=true;. That way, you reduce the amount of pixels drawn to what is absolutely necessary, and keep screen memory usage to a minimum.
I'm making a map editor for my 2d tile based RPG game, and I'm running into a roadblock. The problem is actually how to draw the grid lines efficiently for very large maps like, say 300x300 tiles.
Originally I called redrew the entire grid panel every time you moved the mouse or clicked(since it allows you to drag and also highlights the tile you are hovering over). This was horrible for large maps and was very slow.
So my solution was to create a bufferedImage for the grid of a specified size right when a new empty map was created, and redraw that image every time paint was called. This worked very well, except that for anything above 200x200ish java would run out of heap space in creating that bufferedImage. I can't really have a preloaded image because the user should be able to specify a new map to be any size. Also, I like the grid to be drawn over the tiles, otherwise the tiles cover up the lines and it looks messier. That means the grid has to be drawn again every time tiles are added right?
My question is, is there another way to draw a very large grid that will repaint each time you move the mouse?
The program Tiled can easily create maps of 1000x1000 or more, how is it done?? Thanks
EDIT:
I mean the actual grid LINES, not the grid content such as tiles. Right now when the grid is drawn it iterates through the 2D array and draws a line at every length of a tile.
EDIT:
I got it to work by painting only the visible portion of the screen. Turns out it's not that hard to find the coordinates of the view pane in a JScrollPane. :)
Ok so this is similair I guess to what im working on at the moment. I am currently writing a bit of simulation software with a 3D frontend in Ogre3D. I have a tile based map that can be easily 3000 x 3000 sometimes they may be even larger.
Now im not sure how you are going about drawing your grid, if you are just doing 2D/3D, but the main problem for me was how to apply different textures to each tile. If this isnt relevant then hopefully this may help anyway for future lol. The problem for me is that creating a seperate object for eacch tile is a no no, due to speed. If there are even 1024 x 1024 your looking at over 1 million tiles, each with attributes. This worked great on my first tests where I only had 10 x 10 maps but on larger maps it just ground to a halt.
What I am currently doing is rewriting it, the new approach is as follows. (You may be able to adapt this for what you are doing if it helps). The grid is now only 1 object, its a mesh in my case as im working in 3d. Each vertex holds a couple of values, one is the column and one is the row. I have a seperate texture which is the same size as my map, so for a map with 100 columns and 100 rows i create a texture 100 x 100 (this is created dynamically).
I then pass this texture and the vertices to my cg shader (this is where tyou may have to think of an equivalent way of doing things, but I think it should be doable). By looking up the colour at the pixel in this texture relating to the grid slot I want to texture I can find a colour value, these colour values relate to my texture atlas which holds all my possible textures for my map. All you then have to do is use that particular part of the texture atlas for that particular part of the mesh / grid.
I hope that makes some sort of sense, if not then id be happy to explain a bit more. I think even though im using CG shaders, you should be able to come up with an equivalent for non CG based stuff in java. The advantage of this is that you end up with one lookup texture, one object in memory and a buffer holding your vertices which is very quick for lookup.
Hope this helps.
I want to show users a heatmap with 10000 * 400 tiles. Current state in my program is that I have a class which is a JComponent. In this JComponent, I have instances of Image for the tiles. If I had a 300 * 300 matrix, the program uses between 800 and 1000 MB ram. This is too much.
What can I do else or has someone a control which can show such a big heatmap?
Today I have tested JHeatChart, which creates a BufferedImage. There the size for a 10000 * 400 matrix is under 400 MB, but the class needs over 15 Minutes to create it. This is too long.
Has anybody some idee or knows an control which can handle the data?
Since this will be a map, you do not need to create a component for each tile. many of them can be re-used. What you want to do is during initialization of the app, create a map of all possible components, and then on each tile pass a reference to that component.
Here would be an example.
public class HeatMap{
private static List<JComponent> tiles = new ArrayList<JComponent>();
private List<JComponent> heatmap = new ArrayList<JComponent>();
private Random rand = new Random();
static{
tiles.add(new JLabel("Cold"));
tiles.add(new JLabel("Hot"));
tiles.add(new JLabel("Warm"));
}
public HeatMap(){
for(int i=0; i<10000; i++){
for(int j=0; j<400; j++){
heatmap.add(tiles.get(rand.nextInt(3)));
}
}
}
}
In the above case we only have to create 3 tiles, the rest are references to those. This type of approach should help reduce your memory usage.
You could try scaling your map. So instead of priniting every single tile to your screen, if your zoomed far away, use bigger tiles. One could also try to merging the single tiles to one object instead of keeping references for every single tile.
Obviously, 10000 * 400 tiles is too many to view at once. Instead, use the fly-weight pattern to render only the tiles that are visible in the viewport of a JScrollPane. JTable is an example.
Does a tile really have to be represented as an image or would a colored box be sufficient?
If a colored box would be sufficient you might just draw the visible tiles in your paint(...) method. There would be no need to load those images.
If it has to be images, I assume that not every tile is unique, thus instead of loading an image per tile you might try and load all needed images once and have the tiles reference the corresponding image. Thus if you have 100 different images, instead of having 4000000 copies you'd have 100 and 4000000 quite small references.
Any way you present it, the user will never be able to perceive four million data points simultaneously. Therefore you should never have four million graphical widgets. Either the display should be scaled down, or (when zoomed in) you should display only a subset of all tiles at a time. Either way you will have to map the notional 4,000,000 to far fewer graphical widgets and reuse those you already have.
As other answers have specified, you should also look into using the simplest possible widget type that will do the job.
I'm trying to develop side scrolling game for android involving many many textures so I was thinking if I could create a separate layer, all a single unique color (very similar to a green screen effect) make a collidable and make it invisible to the player.
(foreground layer) visual Image
(2nd layer)collidable copy of foreground layer with main character
(3rd layer)Background image
I not sure if this is possible or how to implement it efficiently, the idea just came to me randomly one day.
Future regards, Thanks
I assume your game is entirely 2D, using either bit-blits or quads (two 3D triangles always screen-aligned) as sprites. Over the years there have been lots of schemes for doing collision detection using the actual image data, whether from the background or the sprite definition itself. If you have direct access to video RAM, reading one pixel position can quickly tell if you've collided or not, giving pixel-wise accuracy not possible with something like bounding boxes. However, there are issues greatly complicating this: figuring out what you've collided with, or if your speed lands you many pixels into a graphical object, or if it is thin and you pass through it, or how to determine an angle of deflection, etc.
Using 3D graphics hardware and quads, you could potentially change render states, rendering in monochrome to an off-screen texture, yielding the 2nd collidable layer you described. Yet that texture is then resident in graphics memory, which isn't freely/easily accessible like your system memory is. And getting that data back/forth over the bus is slow. It's also costly, requiring an entire additional render pass (worst case, halving your frame rate) plus you have all that extra graphics RAM used up... all just to do something like collision-detect. Much better schemes exist, especially using data structures.
It's better to use bounding boxes, or even a hierarchy of sub-bounding boxes. After that, you can determine if you've landed on the other side of, say, a sloped line, requiring only division/addition operations. Your game already manages all the sprites you're moving, so integrate some data structures to help your collision detection. For instance, I just suggested in another thread the use of linked lists to limit the objects you must collision-detect against one another.
Ideas like yours might not always work, but your continual creative thinking will lead to ones that do. Sometimes you just have to try coding them to find out!