Pooling Box2d Bodies? - java

I'm trying to spawn chunks by pooling box2d Bodies, I don't know if libgdx pooling is applicable to bodies but if it is please someone explain me how to do it and what's wrong with my code.
first I created the BodyDef and Body on seperate methods:
public BodyDef createDef(){
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.StaticBody;
def.fixedRotation = true;
def.position.set(6, 6);
return(def);
}
public Body createBody(){
Body body = world.createBody(createDef());
PolygonShape shape = new PolygonShape();
shape.setAsBox(1, 1);
body.createFixture(shape, 1.0f);
shape.dispose();
return(body);
}
public void createPlatform(){
Body platform = Pools.obtain(Body.class); //then use pooling
platform = createBody(); //here I set the value equal to the return value of createBody() method
bodies.add(platform);//adding platform to the ArrayList
}
then to spawn chunks I simply call this method:
public void spawnChunk(){
createPlatform();
}
I'm so new to this I don't know what's the meaning of chunk but I know that is used on side scrolling game for spawning terrain, I get this error message:
Exception in thread "LWJGL Application" java.lang.RuntimeException: Class cannot be created (missing no-arg constructor): com.badlogic.gdx.physics.box2d.Body
at com.badlogic.gdx.utils.ReflectionPool.<init>(ReflectionPool.java:41)
at com.badlogic.gdx.utils.Pools.get(Pools.java:29)
at com.badlogic.gdx.utils.Pools.get(Pools.java:38)
at com.badlogic.gdx.utils.Pools.obtain(Pools.java:48)
at com.nivekbryan.ragingpotato.Physics.createPlatform(Physics.java:53)
at com.nivekbryan.ragingpotato.Physics.spawnChunk(Physics.java:59)
at com.nivekbryan.ragingpotato.WorldController.update(WorldController.java:17)
at com.nivekbryan.ragingpotato.MainClass.render(MainClass.java:27)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)

Don't use pooling for box2d bodies or joints, from the box2d wiki:
So when you create a b2Body or a b2Joint, you need to call the factory
functions on b2World. You should never try to allocate these types in
another manner.
So you only should use Body body = world.createBody(bodyDef); to create bodies.
Next you add the bodies in some kind of list, which one should never do! If you need to access all bodies in your world, then do it like this:
// Global field
Array<Body> bodies = new Array<>();
// When you want to access the bodies.
world.getBodies(bodies);
for(Body body : bodies)
{
// Do something
}
The error means that the Body class has no constructor that looks like
public Body() {}
And thus can not be created by the generic pool class implementation, since it tries to call this constructor.
To solve this you could implement the pool yourself, but as stated above, you should not do this.
Another error with your current code is that you seem to misunderstand variable assignment in java.
// gets a body from your pool, arbitrary method
Body pooledBody = getFromPool();
// assigns a new body to pooledBody, so your pooling is "voided".
pooledBody = world.createBody(createDef());
As you can see in this example the getFromPool(); has no effect, since you assign a new value to pooledBody in the next line.
A more simple example, on why it does not work as you wish:
int a = getFromPool(); // lets says this assigns 4 to a
a = 5;
System.out.println(a);
Will always print 5, never 4!
What you can pool is BodyDef, FixutureDef and the Shape classes, since these have no argument constructors.

Related

How can I correctly set a Dye into an ItemStack?

I'm trying to apply a Dye color into an existing ItemStack, how can I do this without using deprecated methods and creating an new stack?
I tried the following code but it's resulting in a normal ink sack.
ps: I'm creating an stack in the first line only as example.
final ItemStack stack = new ItemStack(Material.INK_SACK);
Dye dye = new Dye();
dye.setColor(DyeColor.LIME);
stack.setData(dye);
edit: Added final to stack variable to show that it cannot be replaced by a new stack.
I've found a way to do this, but it is nowhere near as efficient as using a deprecated method. Here it is with my own personal thought process along the way.
The problem with your current attempt is the interior of the setData(MaterialData) method.
public void setData(MaterialData data) {
Material mat = getType();
if (data == null || mat == null || mat.getData() == null) {
this.data = data;
} else {
if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) {
this.data = data;
} else {
throw new IllegalArgumentException("Provided data is not of type " + mat.getData().getName() + ", found " + data.getClass().getName());
}
}
}
This method works as a simple setter that handles null values and prevents incorrect data types. The problem here should be quite visible though. Wools and dyes don't store their info in MaterialData, they store it in their durability. The durability of a Colorable object determines its color. Being that this is the case, you will need to modify the durability in order to do anything to the color. The only place you can set the durability outside of the constructor is the setDurability method. This doesn't take a MaterialData, only a short. Thus our options are the following: Construct a new ItemStack, or gain non-deprecated access to a usable short value. By your criteria, we move to the latter.
First point of entry, the DyeColor class. If we can't find the short value here, it will at least be supplied from here to another class. Looking at the source gives us a grim reminder of just how rooted in deprecation the problem is.
There is one hacky solution using DyeColor alone, but it's not version proof incase of changes. The Enum.ordinal() method will return the ordinal value of an enum. This is the numerical value of the order it was defined. Starting from index zero, it will match the wool data values, but needs to be inverted for dyes, something you are trying to make universal. The option is there though.
So DyeColor is out of the question, but it got me thinking. The Dye class as a MaterialData works perfectly fine when using the toItemStack() method. Maybe we could use that. Turns out you can! It will require creating a new Itemstack, but we will use the new ItemStack to access data for the original one. Firstly, we create the MaterialData like you did above.
Dye dye = new Dye();
dye.setColor(DyeColor.LIME);
Next, convert the Dye into an Itemstack using the toItemStack() method.
ItemStack tempStack = dye.toItemStack();
Now hold on, why does this work? Well you see, the Dye.setColor(DyeColor) method has an internal implementation of the following:
public void setColor(DyeColor color) {
setData(color.getDyeData());
}
It uses a deprecated method, but because it's wrapped in a DyeColor call, it's not deprecated to the plugin user. Please note: THIS IS PERFECTLY ACCEPTABLE! Many of Bukkit's calls using Material as a parameter actually just call the deprecated method with the type id associated to it. It's perfectly valid to call those methods though. Also note that the setData(byte) method is just a simple setter.
Next up, the toItemStack() method.
public ItemStack toItemStack(int amount) {
return new ItemStack(type, amount, data);
}
We can see here that the DyeColor that was converted to a byte is now sent to the ItemStack constructor ItemStack(Material, int, short) as the durability (it automatically casts to a short). This means, we now have the short we require! It's stored in the durability of tempStack. To top it all off, we do the following.
stack.setDurability(tempStack.getDurability());
stack.setData(dye);
It's over. You have a modified ItemStack with no exposed deprecated methods. You may be asking though why I still call ItemStack.setData(MaterialData). This just ensures that if someone tries to access the DyeColor from the ItemStack's MaterialData it will match up with the durability.
I hope you are satisfied with the fact that it is possible, but I still just recommend using the deprecated methods until they are listed as broken (which usually doesn't happen with Bukkit).
You could try using the Dye(Material) constructor, then appying your DyeColor, and converting the Material to an ItemStack.
Dye dye = new Dye(Material.INK_SACK);
dye.setColor(...);
ItemStack coloredInkSack = dye.toItemStack();
DyeColor.* actually uses wool colors, and Mojang decided to switch dye colors and wool colors around. So, DyeColor.LIME.getData() returns 5, which is lime wool, but lime dye is 10. So you need to use byte data = (byte) (15 - DyeColor.COLOR.getData());
So, here's what your code should look like:
DyeColor color = DyeColor.LIME //or whatever dye color you want
byte data = (byte) (15 - color.getData()); //use byte data = (byte) (color.getData()) if you're coloring wool
ItemStack itm = new ItemStack(Material.INK_SACK, 1, data);
This would give you an ItemStack with 1 lime dye.
If you would really like to use a non-deprecated method, you could make your own enum with their ID's:
public enum CustomDyeColor{
BLACK(0), //ink sack
RED(1),
GREEN(2),
BROWN(3),
BLUE(4), //lapis lazuli
PURPLE(5),
CYAN(6),
LIGHT_GRAY(7),
GRAY(8),
PINK(9),
LIME(10),
YELLOW(11),
LIGHT_BLUE(12),
MAGENTA(13),
ORANGE(14),
WHITE(15); //bonemeal
private byte data;
CustomDyeColor(int i){
this.data = (byte) i;
}
public byte getData(){
return this.data;
}
}
And then you could use your new, non-depricated, custom code to get the data values like this:
CustomDyeColor color = CustomDyeColor.LIME;
byte customData = color.getData();
ItemStack item = new ItemStack(Material.INK_SACK, 1, customData)l
I did it like so:
new ItemStack(Material.STAINED_GLASS_PANE, 1, DyeColor.BLACK.getData()));
With the 1.8.8 Spigot it actually creates 1 black glass pane, although it says the getData() on the color is deprecated.
I think it also works with wool and clay.

Setting the value of a variable from another class in Java

I was wondering if it is possible to reset the value of a variable from another class. For example I have this variable in a HillClimber (hc) class:
public int ballWeight = 200;
What I want to do is run a simulation of a game with the ball weighting at this value. When it is finished I want to set the value to 201 from another class and begin the simulation again, and after that increase to 202 and start another and so on. My problem is that every time I restart the simulation the ballWeight variable is reset to 200. I have tried using a setter method in the HillClimber class:
public int setBallWeight(int ballWeight) {
return this.ballWeight = ballWeight;
}
and called it from another class at the end of a simulation:
hc.setBallWeight(hc.ballWeight+1);
but this does not seem to work as the variables stored value is not changed. Does anyone know how I can do this so the stored value of ballWeight will be increased by 1 each time a simulation ends? Or is this even possible? Thanks.
Usually in a POJO you have what are called a getter and a setter method for every variable of the object. In your case:
public class HillClimber{
private int ballWeight;
public HillClimber(){
this.ballWeight = 200;
}
public void setBallWeight(int ballWeight){
this.ballWeight = ballWeight;
}
public int getBallWeight(){
return this.ballWeight;
}
}
In this way you can access the variable ballWeight via get and set method. You don't access it directly like in hc.ballWeight, which is possible but is a bad practice, and prevent this access type declaring your variable as private (meaning that only the class in which it is declared can directly access it).
To fullfill your request of adding one at every run of the game you can therefore call
hc.setBallWeight(++hc.getBallWeight()); //Equivalent to hc.setBallWeight(hc.getBallWeight() + 1);
I usually don't use this approach if the class isn't automatically generated (as in an Hibernate context), but instead declare another method in the HillClimber class
public void incrementBallWeight(int ballWeightToAdd){
this.ballWeight += ballweiGhtToAdd; //Equivalent to this.ballWeight = this.ballWeight + ballweiGhtToAdd;
}
or if I always need to add only one to my variable
public void incrementBallWeight(){
this.ballWeight++;
}
and then simply call incrementBallWeight after every game run.
NB: to have this working you will have to use always the same instance of HillClimber. In your main
public class Game{
private HillClimber hc = new HillClimber(); //Create the instance and sets ballWeight to 200
public static void main(String[] args){
playGame();
hc.incrementBallWeight(); //ballWeight == 201
playAnotherGame()
hc.incrementBallWeight(); //ballWeight == 202 -> Always the same instance of HillClimber (hc)
.
.
.
}
}
EDIT
I think your problem is greater than that. You are asking to save the state of a variable ( meaning that this value should be available also if you turn off and on your pc) without using a permanent storage. This is simply unachievable.
You should rethink your program (and I mean java program, not a "game run") to not stop after every game run. You can do this in different ways: via Swing GUI, via user input from stdin and so on. If you want some help on this topic, we need to know more of your code (maybe putting the whole of it is best).
OR you can use a file to store your value, which is not as difficult as you think. (Also).

Reuse Box2D objects in LibGDX game (pooling)

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.

Adding Objects to a Vector in Java

I'm trying to add a Objects to a vector be when I use the Code Pasted below I get errors that says "Syntax error on token(s), misplaced construct(s)." and "Syntax error on token "gamePaddle", VariableDecloratorID Expected after this token." I've looked everywhere and can't find what I'm doing wrong they all tell me to construct the Vector like this. The error happens on the line that starts ListOfGameObjects.add(...
class GameWorld {
/**
* Code that instantiate, hold, and manipulate GameOobjects and related game state data.
* #author Tyler Thomas
*
*/
Paddle gamePaddle = new Paddle();
Ball gameBall = new Ball();
Edge topEdge = new Edge(50, 150);
Edge bottomEdge = new Edge(50, 0);
Edge leftEdge = new Edge(0, 75);
Edge rightEdge = new Edge(100, 75);
Vector<GameObject> ListOfGameObjects = new Vector<GameObject>();
ListOfGameObjects.add(gamePaddle);
}
You're trying to add a statement within a class declaration.
You need to put this inside a code block, e.g. inside a constructor:
class Gameworld {
....
public GameWorld() {
ListOfGameObjects.add(gamePaddle);
}
}
If you do the above, the padde will be added to the ListOfGameObjects when the GameWorld object is constructed.
P.S. you should also probably rename it "listOfGameObjects". The initial capital letter is usually reserved for class names. This is a useful convention that will make your code easier to read / understand.
P.P.S. You should also consider replacing the Vector with ArrayList. Vector is considered a bit outdated nowadays.
Any non-instantiating code, like ListOfGameObjects.add(gamePaddle); needs to be inside a method.
For a simple example like this one, put all your code inside public static void main

Java Greenfoot, cannot link method between files

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;

Categories