I have a question about speed and efficiency whilst coding a game. I would like to know what the best way would be to have lots of enemies on screen at once. Do I use a single sprite, move it and draw it for every enemy? Or do I have an instance of a Sprite for each Enemy (of which there could be 50 on screen at once). I am wondering about the speed impact of having lots of instances of Sprite (and in turn, Texture). Which of the above would be best for efficiency and overall good practice?
Id recommend having an instance of a Sprite for every Monster. All sprites have the same reference to a single texture, so it's easier to have lots of sprites without moving a single texture around.
Here is a example of my code;
public ArrayList<Monster> createMonsters(int count, int maxlevel,
int minlevel, MonsterTypes type) {
ArrayList<Monster> monsters = new ArrayList<Monster>();
// just one texture but multiple sprites
// save memory :)
Texture monster = getTextureByType(type);
for (int i = 0; i < count; i++) {
// create random level inside the area
int level = (int) ((Math.random() * maxlevel) + minlevel);
// create a default monster
Monster mon = new Monster(level, new Sprite(monster), screen,
new RandomAI());
monsters.add(mon);
}
return monsters;
}
private Texture getTextureByType(MonsterTypes typ) {
return this.screen.game.manager.get("monster/" + typ.getFileName()
+ ".png");
}
As you can see it gives every monster a new instance of a sprite with the same texture. All of the sprites refer to the same texture to save memory. Hope this helps.
Related
I'm pretty new to libGDX and java in general so I've been following a plethora of tutorials. so FEEL FREE TO CORRECT ME AT EVERY TURN! (yes even in code inefficiencies as well!!)
I currently have the issue of rotating all of the sprites of a single type instead of just a single sprite.
I'll show you how I mean:
libGDX sprite rotation issue
Here are the specifics:
There are 3 different size of sprites.
I use a hashmap to store the 3 sprites so I don't have to Sprite sprite = new Sprite(); every time (supposedly it's a heavy task)
I create a sprite by referencing the one from the hashmap(I think?)
PROBLEM: When I tell a specific sprite to rotate, it rotates each other
sprite of its size.
I have a suspicion that I'm rotating the hashmap reference... If that's the right way to say it.
This is the process I've been using:
hashpmap:
final HashMap<String, Sprite> spriteMap = new HashMap<String, Sprite>();
texture atlas:
spriteAtlas = new TextureAtlas("sprites.txt");
fill hashmap with regions from texture atlas:
private void init spriteMap() {
Array<AtlasRegion> regions = spriteAtlas.getRegions();
for (int i = 0; i < regions.size; i++) {
AtlasRegion region = regions.get(i);
Sprite sprite = spriteAtlas.createSprite(region.name);
float width = sprite.getWidth() / SCALE;
float height = sprite.getHeight() / SCALE;
sprite.setSize(width, height);
sprite.setOrigin(0, 0);
sprite.scale(1f);
spriteMap.put(region.name, sprite);
}
}
create sprite "instance" from hashmap:
private void createNewSprite() {
Sprite sprite;
sprite = spriteMap.get(name);
sprite.setPosition(x, y);
sprite.rotate(rotation);
spriteArray.add(sprite);
}
Maybe I'm not actually extrapolating the sprite from the hashmap well enough?
Let me know if you need anything else to figure out this conundrum.
Thank you so much!
You have only created a single sprite for each region name, referencing it multiple times in spriteArray. Create a new one each time:
private void createNewSprite() {
Sprite sprite = new Sprite(spriteMap.get(name)); //creates a new sprite that is a copy of the one in your map.
sprite.setPosition(x, y);
sprite.rotate(rotation);
spriteArray.add(sprite);
}
They are only slightly heavy. Each Sprite instance has an array of 20 floats for the vertex data, which contains redundant UV data for the underlying TextureRegion, and a redundant Color object and Rectangle object. So it is heavier than creating your own class that references all these things without the redundancies.
They are too heavy to be creating and destroying many of them during game play without using pooling.
What would really be heavy is loading new Textures to create your Sprites instead of them all sharing a single Texture instance.
In my opinion Libgdx Sprites are generally not good for game design because they conflate state with drawing too much, aside from the redundancies. They are useful for particles (and maybe UI elements) where the conflation is not really a design issue. In fact, I think these are the only two places Sprites are used internally in Libgdx.
I am having a problem with my images in my game. I am using an ImageLoader class which was written by my teacher. I create the two Image variables like this:
private static Image healthPic = ImageLoader.loadCompatibleImage("Health.gif");
private static Image enemyRocket = ImageLoader.loadCompatibleImage("EnemyShip2Rocket.png");;
To create the health powerup, I use an arraylist, and populate it using this code:
if (frameCount % 951 == 0){
Random r = new Random();
int randX = r.nextInt(width - 20)+10;
healthP.add(new GameObject(randX, -400, 20,20,healthPic,8,0));
}
enemyWH is one variable used for both the width and height. It is equal to 35.
I populate the enemy rocket arraylist using this code
if (frameCount % 300 == 0){
for (int i = army.size()-1;i>=0;i--){
EnemyShip curEnemy = army.get(i);
rocketP.add(new GameObject(curEnemy.getR().x, curEnemy.getR().y, 20,20, enemyRocket,5,d));
}
}
The 20 and 20 are the width and height, the x and y are where the enemy is at that exact location and time, enemyRocket is the Image variable, 5 is the ySpeed (how fast it moves down the screen), and d is the damage that it does to the playership. My problem is that as the game progresses, randomly, about a second or so after the enemies all fire their rockets, the picture variable that is associated with the rocket suddenly switches to the health powerup picture, so it seems like a health powerup is coming, but it is really an enemy rocket. The picture is switching from rocket to health powerup
Fixed me own problem by re-writing method and using a different object, not GameObject
I would like to know if anybody can help me with a better method of drawing a Tile map for my android game.
Currently, I use a for loop to draw the required Bitmaps to the screen but when doing this for the amount of tiles I need to render at once (enough to cover the screen and a bit more), when the map scrolls, you can notice the map become jolty with its movement, because of the for loop having to loop through all the tiles. The tiles are drawn simular to this:
for(int i = 0; i < 170; i++) {
canvas.drawBitmap(bitmap, x + i * bitmap.getWidth(), y, null);
}
The method I am currently using uses a few bitmaps to save memory, and draws them in different locations.
A different method i can think of to draw the map would be to create a larger Bitmap from the tiles and move the position of that larger bitmap to create movement. The problem with this is that is does require lots of memory and gets out of memory errors.
So, i need to try and find out a method of drawing multiple tiles preferably without the use of a for-loop (I believe the for-loop is causing the jolty, un-smooth movement of the map).
For more details just ask, thanks.
The for loop is the correct way to draw it, your problem is probably the amount of data you are trying to draw in one frame and/or the number of pixels you are trying to push through the system.
If you want good performance on Android your best bet will be to use the graphics hardware it provides. There are various game frameworks available that will make that easier for you and give you much better performance than you will get otherwise.
If not then you will need to break up the drawing and still run the same effective logic but spread out so you draw a few tiles per frame.
is it really required to draw ALL tiles at once?
if it is possible for you, maybe you can determine the 'visible view port' and then just draw those tiles, which need to be drawn?!?
int width = getWidth()/Tiles.width; // do it once before any rendering
// thats the amount of tiles per line
int height = getHeight()/Tiles.height; // do it once before any rendering
// thats the amount of tiles per row
Point pos = ...; // you should know the position of your 'figure' within the map
// could as well be the scroll position
//now draw only those tile from the 'viewport':
for (int dy = 0; dy < width; dy++){
for (int dx = 0; dy < height; dy++){
int xOnMap = pos.x + x;
int yOnMap = pos.y + dy;
int index = yOnMap*height+yOnMap; //index in list
canvas.drawBitmap(bitmap,
x * bitmap.getWidth(), y * bitMap.getHeight(), null);
}
}
so you just have to draw some tile and that would always be the same amount...
i must confess i wrote that code onstackoverflow so there is a chance i did a syntax terror ^^
The thing is that i'm helping a friend with a java project for the universty, and we have to create a remake of MSX's Knightmare. The game is pretty developed already but we don't know how to create the collision with the scenary's stuff, like the columns and the bridge over the river. In order to do this i thought that we could just create a logical "grid-mapping" over the png (the whole level is this image, invoked on the game like a plain image) and do the logic on it, just a boolean logic.
So the basic way, that i suggest to do, is a 2D array with this grid calculated on our minds. Is there some tool that we could use in order to do this easier or automated somehow?
Knightmare original version video
And this is the image that we are using on the game
I am going to try answering the title question, which seemed like the important one.
I wrote a little platform game in Java some time ago, and there I wrote a method called comprobarColisiones() (check collisions) which I call everytime
// Check collisions
comprobarColisiones();
h.mover(pasadas); //Move hero
// Moving enemies
if (h.x > en.getX()){
en.mover(h.getdx(), h.getIzq(),pasadas);
}
if (h.x> en2.getX()){
en2.mover(h.getdx(), h.getIzq(),pasadas);
}
// Moving static objects (rocks)
roca1.mover(h.getdx(),h.getIzq());
roca2.mover(h.getdx(),h.getIzq());
roca3.mover(h.getdx(),h.getIzq());
// REPAINTING
repaint();
// A time calculation that I use to control the game speed somewhere
tiempoAnteriorTipito = System.currentTimeMillis();
When I mean "static objects" it's just to differentiate objects with self-movement with those that just scroll as long as the hero moves, in your game (as in mine's) there probably will not be any static object (well, probably the scores and stuff), even rocks will scroll.
public void comprobarColisiones(){
// Getting bounds
Rectangle r1 = en.getBounds();
Rectangle r2 = en2.getBounds();
Rectangle rec_roca1 = roca1.getBounds();
Rectangle rec_roca2 = roca2.getBounds();
Rectangle rec_roca3 = roca3.getBounds();
// Getting bounds and resolving collisions with shooting objects
ArrayList martillos = Heroe.getMartillos();
for (int i = 0; i < martillos.size(); i++) {
Martillo m = (Martillo) martillos.get(i);
Rectangle m1 = m.getBounds();
if (r1.intersects(m1) && en.vive())
{
en.setVive(false);
m.visible = false;
}
else if (r2.intersects(m1)&& en2.vive())
{
en2.setVive(false);
m.visible = false;
}
}
// Checking if hero touches enemies
Rectangle heroecuad = h.getBounds();
if (heroecuad.intersects(r1)&&en.vive()){
perdio = true;
System.out.println("PERDIO CON EL ENEMIGO 1");
}
if (heroecuad.intersects(r2)&&en2.vive()){
perdio = true;
System.out.println("PERDIO CON EL ENEMIGO 2");
}
// Checking if hero touches static objects
if(heroecuad.intersects(rec_roca1)){
System.out.println("CHOCO ROCA 1");
}
if(heroecuad.intersects(rec_roca2)){
System.out.println("CHOCO ROCA 2");
}
if(heroecuad.intersects(rec_roca3)){
System.out.println("CHOCO ROCA 3");
}
}
I created enemies and static stuff and placed them when I load the escenario, just like this:
en = new Enemigo(800, ALTURA_PISO+8);
en2 = new Enemigo(900, ALTURA_PISO+8);
roca1 = new Roca(1650, ALTURA_PISO+17);
roca2 = new Roca(2200, ALTURA_PISO+17);
roca3 = new Roca(3400, ALTURA_PISO+17);
// Being the first number the initial X-Pos and the second the initial Y-Pos, this will change everytime the hero moves, of course
Probably in your game, you'll define any area of the map as explorable, and add some ghost objects to check intersection with the hero and stop his movement. For what I could see, water and columns should NOT be explorable by your hero.
Hope this would give you some ideas.
I am using slick for java since a few days and got a serious problem.
If i run a completely empty apllication (it just shows the fps) with a solution of 800x600 i get a fps count between 700 and 800.
If I now draw an array with 13300 entries as a grid of green and white rectangles, the fps drop to something around 70.
With more entries in the array it becomes really slow.
For example in a solution of 1024x768 and an array with 21760 entries the fps drop to 40.
How i draw a single entry:
public void draw(Graphics graphics){
graphics.setColor(new Color(getColor().getRed(), getColor().getGreen(), getColor().getBlue(), getColor().getAlpha()));
graphics.fillRect(getPosition().x, getPosition().y, getSize().x, getSize().y);
Color_ARGB white = new Color_ARGB(Color_ARGB.ColorNames.WHITE);
graphics.setColor(new Color(white.getRed(), white.getGreen(), white.getBlue(), white.getAlpha()));
}
And this is how I draw the complete array:
public void draw(Graphics graphics) {
for (int ix = 0; ix < getWidth(); ix++) {
for (int iy = 0; iy < getHeight(); iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
In my opinion 21760 is not that much.
Is there anything wrong with my code or is slick just too slow to draw so much rectangles?
You only want to draw rectangles that are on the screen. If your screen bounds go from 0 to 1024 in the x direction and from 0 to 768 in the y direction, then you only want to loop through rectangles that are inside those bounds and then only draw those rectangles. I can't imagine you are trying to draw 21760 rectangles inside those bounds.
If you are, then try creating one static rectangle and then just try drawing that ONE in all of the different positions you need to draw it at rather than creating a new one every time. For example, in a game I am making, I might have 1000 tiles that are "grass" tiles, but all 1000 of those share the same static texture. So I only need to reference one image rather than each tile creating its own.
Each rectangle can still have a unique state. Just make your own rectangle class and have a static final Image that holds a 5*5 image. Each rectangle will use this image when it needs to be drawn. You can still have unique properties for each rectangle. For example, private Vector2f position, private boolean isAlive, etc
You're probably not going to be able to draw individual rectangles any faster than that.
Games that render millions of polygons per second do so using vertex buffer objects (VBO). For that, you'll probably need to code against the OpenGL API (LWJGL) itself, not a wrapper.
Not sure if Slick will allow it, but if this thing looks anything like a chessboard grid... you could draw just 4 rectangles, grab them and use the resulting image as a texture for your whole image. I'm not even a java programmer just trying to come up with a solution.
Since you're only repeatedly using just a few colors creating a new Color object for every single one is bound to be slow... use new only once for each different color used and store the re-usable colors somewhere in your class, than call the functions with those, constantly allocating and freeing memory is very slow.
And while this might not be as much a benefit as not using new each time but have you considered caching the results of all those function calls and rewriting code as
public void draw(Graphics graphics) {
int ixmax = getWidth();
int iymax = getHeight();
for (int ix = 0; ix < ixmax; ix++) {
for (int iy = 0; iy < iymax; iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Or if you'd prefer not to declare new variables
public void draw(Graphics graphics) {
for (int ix = getWidth() - 1; ix >= 0; ix--) {
for (int iy = getHeight() - 1; iy >= 0; iy--) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Just noticed in another answer you have an integral size grid (5x5) ... in this case the fastest way to go about this would seem to be to draw each item a single pixel (you can do this directly in memory using a 2-dimensional array) and scale it to 500% or use it as a texture and draw a single rectangle with it the final size you desire ... should be quite fast. Sorry for all the confusion caused by previous answers, you should have said what you're doing more clearly from the start.
If scaling and textures are not available you can still draw in memory using something like this (written in c++, please translate it to java yourself)
for( int x = 0; x < grid.width(); x++ ) {
for( int y = 0; y < grid.height(); y++ ) {
image[x*5][y*5] = grid.color[x][y];
image[x*5][y*5 + 1] = grid.color[x][y];
image[x*5][y*5 + 2] = grid.color[x][y];
image[x*5][y*5 + 3] = grid.color[x][y];
image[x*5][y*5 + 4] = grid.color[x][y];
}
memcpy(image[x*5+1], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+2], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+3], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+4], image[x*5], grid.height() * sizeof(image[0][0]) );
}
I'm not sure, but perhaps for graphics the x and y might be represented in the reversed order than used here, so change the code accordingly if it that's the case (you'll figure that out as soon as a few iterations run), also your data is probably structured a bit differently but I think the idea should be clear.