Please forgive me for what is likely an incredibly cringeworthy question (I am quite new to both Java and Android Studio). I come from a C background and am currently developing a mobile app for Google Play using Android Studio. The application will require a number of enemy objects to be created for the game.
Consider the following method of creating a Bitmap for an enemy object;
Within the GamePanel class (parent is SurfaceView, implements SurfaceHolder.Callback);
enemy = new Enemy(BitmapFactory.decodeResource(getResources(), R.drawable.enemy_pic));
Within the Enemy class, our image is declared as an instance variable;
private Bitmap image;
And then we initialise it in the constructor (picResource is the first argument into the constructor);
image = picResource;
My question is the following - if I create a list of enemy objects (there are lots of enemies!), will this result in the duplication of the Bitmap data? I am not sure from the docs whether it's lower level implementation will emulate pointer behaviour in C, and as such result in only minimal overhead from structuring it this way, or whether I am chewing up memory because I am essentially duplicating all the data in the picture file.
I create a list of enemy objects (there are lots of enemies!), will this result in the duplication of the Bitmap data?
Every call to decodeResource() will result in result in a new in-memory bitmap. If you create all your enemies as in your question:
enemy = new Enemy(
BitmapFactory.decodeResource(getResources(), R.drawable.enemy_pic)
);
every Enemy object will have its own unique bitmap.
That is, if you put this in a loop
List<Enemy> enemies = new ArrayList<>();
for (int i = 0; i < nEnemies; ++i) {
enemy = new Enemy(
BitmapFactory.decodeResource(getResources(), R.drawable.enemy_pic)
);
enemies.add(enemy);
}
You will get nEmemies bitmaps, i.e. each Enemy object has its own (in-memory) bitmap.
If you decode your enemy bitmap only once and pass the resulting reference to the Enemy constructor, you just create new reference to the single existing bitmap. That is, rewriting the above as (for example)
List<Enemy> enemies = new ArrayList<>();
Bitmap enemyBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.enemy_pic);
for (int i = 0; i < nEnemies; ++i) {
enemy = new Enemy(enemyBitmap);
enemies.add(enemy);
}
results in only a single bitmap to be shared by all enemies (unless Enemy does something to the bitmap to create a copy).
To refer back to your answer. In Java, assignments of the form
image = picResource;
do not create copies, but only create additional references (to be precise, this is only true for reference types, i.e. objects).
Side note: if you use Context.getDrawable(), you can make use of use of Android's drawable cache and get the same drawable even for repeated calls.
Related
hey am a beginner in Libgdx. i am a bit confused about disposing the stuff.
Texture brickTexture;
Array<Brick> bricks;
public Game {
brickTexture = new Texture("brick.png");
bricks = new Array<Brick>();
for (int i = 0; i < 10; i++) {
Brick brick = new Brick(i, brickTexture);
bricks.add(brick);
}
}
void dispose () {
brickTexture.dispose(); // brick texture loaded in this class
for (Brick brick : bricks) brick.brickTexture.dispose(); // disposing the public texture which was earlier passed on to the brick class
}
Should both of the lines be in the dispose method or only the first one ?
You only have to do this once. It's the same Texture object so when you dispose it on any reference no other object can use it anymore. It's disposed.
Also you might want to check out AssetManager class, which handles disposing stuff for you.
You are using "bricktexture" for every "Brick" in the ArrayList, so you are basically pointing to the same object so you should only dispose "bricktexture" once.
If you also want to "free" the array, probably you should call
bricks.clear();
Which will become empty (as with no elements inside).
I have a JList that is displaying a custom object (Frog) using a custom cell renderer.
frogList = new JList<Frog>();
frogModel = new DefaultListModel<Frog>();
frogList.setModel(frogModel);
frogList.setCellRenderer(new FrogBrowserCellRenderer());
//add frogs...
The frog objects contains a list of images, and I have my list pick the latest one to display. It's in a thumbnail file, so I can read it into memory and display it. However I know that the JList re-renders every time the window moves or the window needs redrawn which is really bad for performance and just not good design. The issue I have is that this list is dynamic so I cannot simply load all images at startup because users can add them at runtime and it'll auto update the list.
Some people mentioned loading the image into memory in the constructor and setting it in the getListCellRendererComponent() method but that doesn't appear to be possible because it only creates one cell renderer and uses it for everything in the list. I also verified this by printing out the constructor method. Since I will have a list of frogs with all different images this doesn't really make sense.
Here is the code I am using to create the thumbnail right now.
public Image createListThumbnail() {
try {
Image returnImg = null;
//get latest frog image
SiteImage img = frog.getLatestImage();
BufferedImage src = ImageIO.read(new File(XMLFrogDatabase.getImagesFolder()+img.getImageFileName()));
BufferedImage thumbnail = Scalr.resize(src, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH, 200, 150, Scalr.OP_ANTIALIAS);
if (!frog.isFullySearchable()){
ImageFilter filter = new GrayFilter(true, 30);
ImageProducer producer = new FilteredImageSource(thumbnail.getSource(), filter);
returnImg = Toolkit.getDefaultToolkit().createImage(producer);
}
return returnImg;
} catch (IOException e) {
IdentiFrog.LOGGER.writeExceptionWithMessage("Unable to generate thumbnail for image (in memory).", e);
}
return null;
}
I call this method in my getListCellRendererComponent() which I know causes terrible performance but I don't understand how to cache it in memory for multiple frogs and also use only one object. Perhaps an image map? I can't seem to find any solid evidence of a proper way to do this.
I'm working in a game in which I spawn an object every 1-3 seconds. This game object contains some assets for renderization purposes and a Box2D body. The thing is that I don't want to create thousands of objects. Instead, I would like to reuse them, resetting its properties (position, friction, etc.) and not creating a brand new object. I think that the best way to do this is implementing a pool of this objects but I'm concerned about it because after search for some info I've found several developers reporting memory leaks because all the objects created by Box2D internally.
What do you think is the best way to do this?
This is the class that I use to represent each game object:
public class GameObject extends Box2dGameObject {
private static final float WIDTH = 0.85f;
private static final float HEIGHT = 1;
private Animation animationDying;
private Animation animationFalling;
private Animation animationIdle;
private Animation animationJumping;
private Animation animationRunning;
private Body body;
public GameObject(Vector2 position, World world) {
super(position, world);
init();
}
private void init() {
super.init();
dimensions.set(WIDTH, HEIGHT);
/* Get assets */
animationDying = Assets.instance.pirate.animationDying;
animationFalling = Assets.instance.pirate.animationFalling;
animationIdle = Assets.instance.pirate.animationIdle;
animationJumping = Assets.instance.pirate.animationJumping;
animationRunning = Assets.instance.pirate.animationRunning;
/* Set default animation */
setAnimation(animationIdle);
body = createBox2dBody();
}
private Body createBox2dBody() {
BodyDef bodyDef = new BodyDef();
bodyDef.fixedRotation = true;
bodyDef.position.set(position);
bodyDef.type = BodyType.DynamicBody;
PolygonShape shape = new PolygonShape();
shape.setAsBox(WIDTH / 2, HEIGHT / 2);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.density = 1;
fixtureDef.friction = 1;
fixtureDef.shape = shape;
Body body = world.createBody(bodyDef);
fixture = body.createFixture(fixtureDef);
shape.dispose();
return body;
}
/* More code omitted */
}
This seems like a case of early optimization and may not yield the results you are looking for.
Consider:
All those objects sitting your "pool" are still registered internally in Box2D as objects. Will collision checking be performed on them? Will collision response? Will their usertag be pointing to an object in the "pool" (user tags are often used to reference the "owner" of the body)?
There are life cycle issues associated with all the values in an
object...you will have to be careful to manage the values (position is easy, but collision flags etc. gets deeper) for each object you take into and pull out of the pool. That sounds error prone.
If you are really only creating/destroying a single object every second, that does not seem like much of a performance/memory hit. If you are creating hundreds, that is a different story. I wrote a game where I had bullets being generated at a rate of 10-20 per second...each was derived from an "Entity" base class which is a composite (I called the class "Slug" I think). The "Slug" class held the body, the sprite, the collision handling logic, etc. When it collided or after a few seconds, it "died" and went into the pool. Pulling it from the pool caused it to re-create the body and I did not see this as a performance or memory bottleneck.
It did not recreate the parts that may cause larger allocation or were not necessary (e.g. the sprite). These don't need to be reclaimed until it is actually deleted from the pool because it is really just a reference to a sprite sheet that is shared. A specific "Init(...)" method was associated with the class so that the memory allocation could be separate from the initialization.
Your mileage may vary, of course. But I think you should look to see if it is really a problem (i.e. prototype it) before you build infrastructure to fix it.
I'm creating a small game in android. Anything that needs to be drawn on screen extends my VisibleObject class, I then have a Manager class that i can add all my visible game objects to and each frame i tell the manager to call the draw function of everything within it.
Here's were objects are initialised and added to the manager:
#Override
public void surfaceCreated(SurfaceHolder holder) {
fps = new TextDrawable(Color.BLACK, 14, 100, 40, 40);
player = new Player();
map = new Map();
leftTouch = new TouchCircle(Color.GRAY);
manager.add("fpsText", fps);
manager.add("leftTouch", leftTouch);
manager.add("player", player);
manager.add("map", map);
gameloop = new GameLoop(getHolder(), this, fps);
gameloop.setRunning(true);
gameloop.start();
}
Now the problem i'm having is with the draw order, if you look at the order the objects are added to the manager for reference..
I can tell you for certain that the player is being drawn on top of
the map! These are both drawn by drawing there respective bitmaps with drawBitmap(..).
However the fpsText and leftTouch are being drawn underneath the map! These are drawn using drawText(..) and drawOval(..) respectively.
Even though they implement different Canvas.draw.. functions, I would expect them all to be drawn in order as I just pass the canvas object i have to my manager class and then let the manager cycle through each object passing it that canvas to draw with.
Can anyone clear up for me why bitmaps seem to be drawn on top and what the solution should be to get my fps and touch area drawn above the player and map bitmaps? I'd Appreciate it.
EDIT: I am using private ConcurrentSkipListMap<String, VisibleObject> objectMap; within my manager to store the objects and drawing like so..
public void draw(Canvas c){
for (Map.Entry<String, VisibleObject> object : objectMap.entrySet()){
synchronized(object){
object.getValue().draw(c);
}
}
}
Bitmaps are not drawn on top of the text unless you draw Bitmap after you drawn text (and position overlaps).
You haven't disclose onDraw method so I can't be sure, but I suspect that you are not calling drawing methods in right order.
How does you manager stores the values added to it? Maybe you use Map implementation that doesn't maintain order of elements added (most implementations don't, LinkedHashmap does).
Working on a project in school, I'm a beginner to programming and I have big problems with the making of Bubble Shooter, I need to get all of the balls of the map before it changes to map2..
Trying to make it with listing all of the balls but the program crashes at the end of the first map and gives us the error-report that it can't load a negative value. I figured it was when it was trying to load the gun and wanted to put an if-statement that says that if "allowedBallTypes != null" or zero, as it might be, than it should load the gun.
cannot find symbol - getAllowedBallTypes();
greenfoot java method class
The bubbleworld class:
public BubbleWorld()
{
super(Map.MAX_WIDTH*Map.COLUMN_WIDTH, Map.MAX_HEIGHT*Map.ROW_HEIGHT, 1,false);
// Max speed. We use time-based animation so this is purely for smoothness,
// because Greenfoot is plain stupid. I can't find a way to get 60 Hz so this is
// what we have to do. Note: Exporting the game seems to cap this to some value < 100. :(
Greenfoot.setSpeed(100);
// Load the map.
map = new Map(this, testMap1);
// Update the allowed ball types. (i.e. we don't want to spawn a
// certain color of balls if the map doesn't contain them!)
map.updateAllowedBallTypes();
// Create the cannon.
Cannon cannon = new Cannon();
addObject(cannon, getWidth()/2, getHeight());
The map class:
public int[] getAllowedBallTypes()
{
return allowedBallTypes;
}
public void updateAllowedBallTypes()
{
int allowedCount = 0;
boolean[] allowed = new boolean[Ball.typeCount];
// Only ball types that exist in the map RIGHT NOW as attached balls will be allowed.
for(Cell c : cells)
{
if(c != null && c.getBall() != null && c.isAttached())
{
int type = c.getBall().getType();
if(!allowed[type])
allowedCount++;
allowed[type] = true;
}
}
allowedBallTypes = new int[allowedCount];
int writeIndex = 0;
for(int type = 0; type < Ball.typeCount; ++type)
{
if(allowed[type])
{
allowedBallTypes[writeIndex++] = type;
}
}
}
The Cannon class:
private void prepareBall()
{
// Get a random ball type from the list of allowed ones. Only balls currently in the map
// will be in the list.
int[] allowedBallTypes = ((BubbleWorld)getWorld()).getMap().getAllowedBallTypes();
int type = allowedBallTypes[Greenfoot.getRandomNumber(allowedBallTypes.length)];
// Create it and add it to the world.
ball = new Ball(type);
getWorld().addObject(ball, getX(), getY());
}
Assuming you are getting that error in the pasted snippet of the Cannon class, the error suggests that there is a problem with the getMap() method of BubbleWorld -- can you paste that in so we can see it? It might not be returning the correct type. In general, you need to paste in more code, including complete classes, and say exactly where the error occurs. An easier way might be to upload your scenario with source code to the greenfoot website (www.greenfoot.org -- use the share function in Greenfoot, and make sure to tick the source code box) and give a link to that.
Based on your code, your map class doesn't seem to have a class-level variable declaration of int[] allowedBallTypes;