I'm currently developping a roguelike game, using Swing. I'm using an array of JLabel to display the tiles. When the user input a direction, I redraw the whole tab using the following method (I'm using simplified variable name here) :
for (int i=0 ; i<array.length ; i++){
for(int j=0 ; j<array[i].length ; j++){
this.remove(array[i][j]);
array[i][j] = new JLabel(new ImageIcon(TILEARRAY[i][j]));
this.add(array[i][j]);
this.validate();
}
}
But it's very heavy to deal with, about 0.5s to redraw the whole panel, and when I press the direction, it can't draw fast enough to have a real-time display (it actually does the loop, along the waiting time, and when the whole displacement has been done, draws). I'd like to know if there's a easier and faster way to achieve this, with a " smooth " feeling (let's say like in Stone Soup Dungeon Crawl (tiles version)), using Swing.
Every suggestion on an efficient 2D library for Java is welcome too. I know there is Slick2D, but is there any good other library for this kind of games ?
Thanks
(sorry if my english is bad, I'm not a native speaker of English)
Call the this.validate(); just once after both loops to avoid layout preferences recalculations
UPDATE. Keep ImageIcons in a Map and reuse them rather than recreating. Key could be i+"_"+j String
Related
Over the past few days, I've coded a (horribly patched together) text RPG game in Java. The positioning in the world is pretty much controlled by a simple 100x100 2D array of Strings. I then convert the Strings into actual objects when the player actually comes upon the grid.
What I have in mind is to have a graphic display showing this 100x100 grid with an image in each section of the grid that corresponds with what is in the array.
For example, if the String at block[10][15] is "rock", the graphic display section of the grid at row 10, column 15 would show a picture of a rock.
Ideally, this graphic would refresh every time I loop in my do-while loop. Oddly, what I have in mind is something that looks remarkably similar to the early pokemon games.
I apologize if my description is badly worded or my question too ambiguous. I have only learned java for half a semester in my computer science course, so my knowledge is limited to the basics we learned in the one semester. I do like to pursue various projects outside of class, like the text chess game that I (proudly) coded. I prefer to create everything from scratch so that I can learn the basics before using various libraries.
Could somebody please point me in the right direction for what I am looking for or offer a better way to go after this display?
Thank you very much in advance. Please let me know if a reference to my code would better help answer my question.
Firstly,you can use enums instead of strings as mentioned by Jack above. Eg
private enum Objects{
Rock(1),Coin(8),Med(45)...and so on
}
In your array, you may store these objects as numbers rather than strings.
eg:
boolean stopFlag=false;
do{
//check each element of your world array with the enum and draw it
for(int i=0;i<yourObjectsArray.length;i++)
{
for(int j=0;j<yourObjectsArray[i].length;j++){
switch(yourObjectsArray[i][j])
{
case Objects.Rock: drawRock(i,j);
break;
case Objects.Coin: drawCoin(i,j);
break;
//and so on....
}
}
}
//you can also put this into a separate function as drawWorld() and pass the objects.
//Key press checking logic here. If user presses exit key [esc] then you set the stopFlag as true
if(keypress==KEY_ESC){ stopFlag=true;}
}while(!stopFlag);
An example of Draw Rock:
private void drawRock(int i,int j){
//i and j are the cols and row values so you need to resolve them to coordinates.
//I am assuming u have a 800*600 screen and you mentioned that your world is 100x100 array. Then each of your object is 8*6 units in size so
xCoord=i*8;
yCoord=j*6;
//So if you have to draw a rock on [10][15] it will resolve as
//xCoord=10*8-> 80
//yCoord=15*6-> 90 so it will draw your rock in (80,90) on the screen
//Now you can either open the rock image from your disk now or u maintain one instance of rock at the beginning of the program so that you can use the same image later rather than opening it everytime you encounter a new Rock object in your array.For now I will open it here.
String path = "C:\\YourGameDirectory\\rock.jpg";
URL url = new File(path).toURI().toURL();
BufferedImage rockImg = ImageIO.read(url);
//draw it to the screen now if you have the graphics instance.
yourUIPanel.getGraphics().drawImage(rockImg,xCoord,yCoord,yourUIPanel);
// You may find many resources that teach you how to draw an image on the screen in Java. You may repeat the same for all the objects.
}
I hope the above codes helped you a-bit. If not,its my bad.
You can try this tutorial series to get started. Although its in C , it has concepts that will help u acheive what you have mentioned above.
Easiest thing to use for such tasks in my personal experience is Processing, which is a light framework which is able to provide a simple API to draw things.
There is a reference, and many tutorials so it shouldn't be that hard to get start with even if you are not expert.
As a side node: why do you use strings to store kinds of blocks? Could you use something better like an enum?
You might want to check out the source code of my old roguelike game Tyrant:
https://github.com/mikera/tyrant
Key ideas:
There is a Map class that is responsible for storing the data that represents the map. In Tyrant, the Map encapsulates storage of both the terrain and the objects places on the map.
There is a MapPanel class that shows the Map in the GUI. This is kept separate from the Map itself - it's generally a good idea to separate the GUI from your core engine data.
There is a Thing class that represents objects on the map. This includes everything from monsters, items, trees and clouds of smoke to the player character itself. Basically anything that isn't terrain.
As for refresh, the way this works is that the MapPanel repaints itself on demand, looking at the contents of the map. Check out MapPanel.paint(Graphics g) and the various methods that it calls.
I am making a game in android in which enemies are randomly spawned at the top of the screen and move down. I am able to create 1 enemy that does this, but I can't think of a good way to create many enemies that are all drawn on the same canvas. I have tried many things, and I could really use some help.
Thanks!
The easiest way to do this is to create a class Enemy (name it whatever you like) and instantiate as many as you need using a for loop. You could use an array to store each instance.
An example could be the following:
Enemy[] arrayOfEnemies = new Enemy[sizeOfArray];
for(int i = 0; i < arrayOfEnemies.length; i++) {
arrayOfEnemies[i] = new Enemy();
}
Then you can use an enhanced for (or for each) loop to display them wherever you'd like on your canvas.
Okay I have a game I'm working on that sets a 12x16 grid on the screen and then draws a pattern on the screen like so http://oi49.tinypic.com/53odih.jpg
I'm just wondering if there is a way using code to see if the box exists inside of the pattern or not?
This is how I'm looping though my grid boxes
//Set all blocks to default
for(int i=0;i<tilesX;i++){
for(int j=0;j<tilesY;j++){
blocks[i][j] = 0;
}
}
If a block is part of a pattern I set the block to 1. I want the blocks inside the pattern set to 2, but I can't think of a way to do this programmatically. The pattern will always be a complete shape and will always connect back to the starting point.
I hope that's not too confusing and I'm willing to provide you with what ever you need but I'm just lost on how to do it. Thanks
You need to implement the flood fill algorithm. Depending on how you draw the state of 2, you can flood fill the area starting at a known point inside the shape. Then check to see if its 0 (outside), 1 (border), or 2 (inside).
I think I'm grasping what you want here, but let me know if I'm off base.
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
I'm about to create a java crossword application but I am unsure of what packages to use to draw the crossword grid. I know you can manually draw grids with Graphics2D etc. but I'm not sure if this is the easiest way to do it as I'll need text fields in the grid squares.
Anyone have any suggestions as to creating the crossword grid.
Actually I don't think you need textfields in the grid squares but just to write down every single letter for every grid cell..
To allow editing you just catch keyboard strokes over the component you use and set crossword cells according to what the user writes.
Doing it this way would be quite easy because you can use a back 2-dimensional array that stores the whole grid, then when the user select a definition you just start filling single letters whenever keys are typed starting from the first cell of the definition.. your draw routine will need just to be able to draw the grid and center letters inside cells, nothing more..
A JTable could work but it think it's oversized for your problem, because you'll end up interfacing with a lot of things you don't need at all..
EDIT (for comment):
I did it something similar this way:
you can have a cell class
class Cell
{
boolean isBlank;
char value;
}
with an array of cells you obtain your grid:
Cell[][] gamefield = new Cell[15][15];
then inside paint() you can easily iterate:
for (int i = 0; i < Scheme.rows; ++i)
{
for (int j = 0; j < Scheme.cols; ++j)
{
g2.drawRect(i*32, j*32, 32, 32);
if (Scheme.scheme[i][j].isBlank)
g2.fillRect(i*32 + 3, j*32 + 3, 32 - 5, 32 - 5);
}
}
Just because I still have a screenshot result was something like
Maybe use a JTable and custom renderer for the cells. That should be at least a simple solution. Of course it takes a little time to get used to JTable, but eventually it's quite simple.
Did you consider JavaFX at all? JavaFX will let you create "scene-graphs" based on vector/graphics edited using Adobe Photoshop/Inkscape etc.
If not, most simple way would be to extend JTextField such that that will just hold 1 char and will be black/or whatever color to indicate non-editable and disabled. Also, add a custom Border to indicate puzzle question number. Put everything in to a GridLayout.