I am trying to learn LibGdx and simulate a Spring Mass connection. I am able to define everything correctly and run the simulation but the spring defined seems to have an inherent damping dur to which the oscillations of the dynamic body die out.
I have set the damping ratio to zero but still get the decay.
Can some one explain if this is a bug or am i doing something wrong.
Below are my codes.
SpringMass class:
public class SpringMass implements Screen {
private void createScene() {
trackers = new ArrayList<Tracker>();
isTracking = new ArrayList<Boolean>();
world.setGravity(new Vector2(0, 0));
Vector2 boxPos = new Vector2(200, 200);
staticBox = new Box(world, boxPos, 10, 10, false);
dynBox = new Box(world, boxPos.add(150, 0), 10, 10, true);
new Spring(staticBox.body, dynBox.body, world, 100, 0.8f, 0);
}
}
Spring Class:
public class Spring {
private DistanceJointDef distanceJointDef;
public Spring(Body bodyA, Body bodyB, World world, float length, float stiffness, float dampingRatio) {
distanceJointDef = new DistanceJointDef();
distanceJointDef.bodyA = bodyA;
distanceJointDef.bodyB = bodyB;
distanceJointDef.length = length*CONSTANTS.WORLD_TO_BOX;
distanceJointDef.frequencyHz = stiffness;
distanceJointDef.dampingRatio=dampingRatio;
world.createJoint(distanceJointDef);
}
}
Related
Trying to place two buttons in a table row.
Right-most button appears slightly offscreen.
Adding to table with .add(btn).right() but seems not to have any effect.
Documentation says something about removing the Align.left and vise-versa but I'm not sure what they're saying.
Working from mobile.
Took pic, uploaded to ImageBucket but can't see whole thing so took two more (top + bottom of screen) just in case.
Top of screen:
https://i1161.photobucket.com/albums/q501/StudioGilliam/Screenshot_20190430-224041_TextBasedRPG.jpg
As you can see, the labels display fine.
Bottom of screen:
https://i1161.photobucket.com/albums/q501/StudioGilliam/Screenshot_20190430-224024_TextBasedRPG.jpg
The offending code:
public class TextBasedRPG implements ApplicationListener
{
private Stage stage;
private TextButton btnNext;
private TextButton btnItems;
private Label lblPlayer1;
private Label lblEnemy1;
private Label lblInfo;
#Override
public void create()
{
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
// UI STUFF
// Labels
Label.LabelStyle styleL = new Label.LabelStyle(new BitmapFont(), Color.BLACK);
lblPlayer1 = new Label("Player data", styleL);
lblPlayer1.setFontScale(3.5f);
lblEnemy1 = new Label("Enemy data", styleL);
lblEnemy1.setFontScale(3.5f);
lblEnemy1.setAlignment(Align.right);
lblInfo = new Label("Information", styleL);
lblInfo.setFontScale(4.0f);
// Buttons
TextButton.TextButtonStyle styleTB = new TextButton.TextButtonStyle();
styleTB.font = new BitmapFont();
styleTB.up = new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal("ButtonGreyUp.png")), 10, 10, 10, 10));
styleTB.down = new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal("ButtonGreyDown.png")), 10, 10, 10, 10));
btnNext = new TextButton("Next Turn", styleTB);
btnNext.setTransform(true);
btnNext.setScale(6.0f);
btnNext.setTouchable(Touchable.enabled);
btnNext.align(Align.right);
btnItems = new TextButton("Play", styleTB);
btnItems.setTransform(true);
btnItems.setScale(6.0f);
btnItems.setTouchable(Touchable.enabled);
// Table
Table table = new Table();
table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
table.setFillParent(true);
table.pad(50);
table.add(lblPlayer1).expandX().left();
table.add(lblEnemy1).expandX().right();
table.row();
table.add(lblInfo).expandY().colspan(2);
table.row();
table.add(btnItems).expandX().left();
table.add(btnNext).expandX().right();
table.debugAll();
stage.addActor(table);
}
#Override
public void render()
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void dispose(){stage.dispose();}
#Override
public void resize(int width, int height){}
#Override
public void pause(){}
#Override
public void resume(){}
I don't recommend using setScale() since it only affects the representation of the actor and causes problems with the actual dimensions within the table.
You should use a fitting width and height for your buttons and use a font with a bigger textsize.
You could use GDX Freetype to generate your fonts with the correct size on startup.
Here is an example approach for the solution:
I use the following approach for my UI elements here as an example for a Label:
This is in my static UIHelper Class:
public static Cell addToTable(Table table, Label label, float width) {
Label.LabelStyle style = new Label.LabelStyle(skin.get("default", Label.LabelStyle.class));
float aspectRatio = style.background.getMinWidth()/style.background.getMinHeight();
float height = width / aspectRatio;
style.font = Assets.font;
style.fontColor = Assets.font.getColor();
label.setStyle(style);
label.setAlignment(Align.center);
return table.add(label).width(width).height(height);
}
Then I can just call:
float width = (float)Gdx.graphics.getWidth()*0.8f; // I want my label to be 80% of the screen width
UIHelper.addToTable(table, levelLabel, width).colspan(3).pad(20);
For my fonts, I do this:
private static BitmapFont generateFont(){
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("skins/beemelon/passion-one-regular.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = (int) (38 * Gdx.graphics.getDensity()); // Change the 38 to a value fit for your game
parameter.color = new Color(255f / 255f, 165f / 255f, 23f / 255f, 1f); // Divide by 255f to get a value between 0 and 1
parameter.borderWidth = parameter.size / 10f;
parameter.borderColor = Color.BLACK;
BitmapFont bitmapFont = generator.generateFont(parameter);
generator.dispose();
return bitmapFont;
}
Hope this helps or pushes you in the right direction.
My game start freezing after some time (take too much ram), I want to try draw 3( later more) string using loop method. My code is this:
public class Simple implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private BitmapFont font;
private GlyphLayout layout;
String a1 = "aa";
String a2 = "bb";
String a3 = "cc";
int a = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (int i = 1; i < 4; i++) {
layout = new GlyphLayout();
font = new BitmapFont();
layout.setText(font, "a" + i);
font.draw(batch, layout, 200 + (15 * i), 200);
}
batch.end();
}
}
To visualize what EpicPandaForce mentioned in the comments:
public class Simple implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private BitmapFont font;
private GlyphLayout layout;
String a1 = "aa";
String a2 = "bb";
String a3 = "cc";
int a = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
//Initialize the fields in create()
layout = new GlyphLayout();
font = new BitmapFont();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (int i = 1; i < 4; i++) {
//Use them like you do.
layout.setText(font, "a" + i);
font.draw(batch, layout, 200 + (15 * i), 200);
}
batch.end();
}
}
I'm not sure if this is going to work. You are not specifying a bitmapfont anywhere so when you draw it using layout you probably get a nullPointerException. In the create method you probably want to initialize font with font = new BitmapFont(Gdx.files.internal("Path to bitmapfont"));.
Using new is a expensive operation. The update() method is being called every frame and you are creating new objects each time it is being called. On top of that BitmapFont() is not a small object. And each time you create a new object for font and layout the previous object it holded needs to be collected by the garbage collector. A basic rule is to never use the new keyword in the update() method but rather change it and/or use it like I did just now. To visualize this in a very simple way:
Object o; // <-- a simple container
new Object(); // <-- a object stored in memory in all it's glory
Object o = new Object(); // <-- container o is now pointing to the memory address of new Object()
Object o = new Object(); // container 0 is now pointing to a different object in memory
//But the old one is still chilling at it's own address and needs to be collected
The problem isn't necessarily that you're creating a new font every render call (though you certainly shouldn't be doing that for performance reasons,) but more that you're not releasing the font from memory via dispose.
Normally garbage collection will clean up after you, but in some cases you need to clean up after yourself. Libgdx utilizes some unmanaged code for performance reasons and so needs you to manually release it. The doc makes this clear, and expounds upon why.
The texture for a BitmapFont loaded from a file is managed. dispose()
must be called to free the texture when no longer needed. A BitmapFont
loaded using a TextureRegion is managed if the region's texture is
managed. Disposing the BitmapFont disposes the region's texture, which
may not be desirable if the texture is still being used elsewhere.
So call dispose when you're done with the font, and initialize your font in your constructor. Otherwise your program will use more and more RAM and performance will be terrible.
The Jmoneky Engine gives example code for endless randomly generated Terrain. My Problem is, the code has no comments or indicators to edit the View distance. I am trying to use this example code to build a game, but it looks really bad if the render distance is so short you can see the bottom of the world(void)
The Code:
public class TerrainFractalGridTest extends SimpleApplication {
private Material mat_terrain;
private TerrainGrid terrain;
private float grassScale = 64;
private float dirtScale = 16;
private float rockScale = 128;
public static void main(final String[] args) {
TerrainFractalGridTest app = new TerrainFractalGridTest();
app.start();
}
private CharacterControl player3;
private FractalSum base;
private PerturbFilter perturb;
private OptimizedErode therm;
private SmoothFilter smooth;
private IterativeFilter iterate;
#Override
public void simpleInitApp() {
this.flyCam.setMoveSpeed(100f);
ScreenshotAppState state = new ScreenshotAppState();
this.stateManager.attach(state);
// TERRAIN TEXTURE material
this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md");
// Parameters to material:
// regionXColorMap: X = 1..4 the texture that should be appliad to state X
// regionX: a Vector3f containing the following information:
// regionX.x: the start height of the region
// regionX.y: the end height of the region
// regionX.z: the texture scale for the region
// it might not be the most elegant way for storing these 3 values, but it packs the data nicely :)
// slopeColorMap: the texture to be used for cliffs, and steep mountain sites
// slopeTileFactor: the texture scale for slopes
// terrainSize: the total size of the terrain (used for scaling the texture)
// GRASS texture
Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
this.mat_terrain.setTexture("region1ColorMap", grass);
this.mat_terrain.setVector3("region1", new Vector3f(15, 200, this.grassScale));
// DIRT texture
Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
this.mat_terrain.setTexture("region2ColorMap", dirt);
this.mat_terrain.setVector3("region2", new Vector3f(0, 20, this.dirtScale));
// ROCK texture
Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");
rock.setWrap(WrapMode.Repeat);
this.mat_terrain.setTexture("region3ColorMap", rock);
this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale));
this.mat_terrain.setTexture("region4ColorMap", rock);
this.mat_terrain.setVector3("region4", new Vector3f(198, 260, this.rockScale));
this.mat_terrain.setTexture("slopeColorMap", rock);
this.mat_terrain.setFloat("slopeTileFactor", 32);
this.mat_terrain.setFloat("terrainSize", 513);
this.base = new FractalSum();
this.base.setRoughness(0.7f);
this.base.setFrequency(1.0f);
this.base.setAmplitude(1.0f);
this.base.setLacunarity(2.12f);
this.base.setOctaves(8);
this.base.setScale(0.02125f);
this.base.addModulator(new NoiseModulator() {
#Override
public float value(float... in) {
return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1);
}
});
FilteredBasis ground = new FilteredBasis(this.base);
this.perturb = new PerturbFilter();
this.perturb.setMagnitude(0.119f);
this.therm = new OptimizedErode();
this.therm.setRadius(5);
this.therm.setTalus(0.011f);
this.smooth = new SmoothFilter();
this.smooth.setRadius(1);
this.smooth.setEffect(0.7f);
this.iterate = new IterativeFilter();
this.iterate.addPreFilter(this.perturb);
this.iterate.addPostFilter(this.smooth);
this.iterate.setFilter(this.therm);
this.iterate.setIterations(1);
ground.addPreFilter(this.iterate);
this.terrain = new TerrainGrid("terrain", 33, 129, new FractalTileLoader(ground, 256f));
this.terrain.setMaterial(this.mat_terrain);
this.terrain.setLocalTranslation(0, 0, 0);
this.terrain.setLocalScale(2f, 1f, 2f);
this.rootNode.attachChild(this.terrain);
TerrainLodControl control = new TerrainGridLodControl(this.terrain, this.getCamera());
control.setLodCalculator(new DistanceLodCalculator(33, 2.7f)); // patch size, and a multiplier
this.terrain.addControl(control);
this.getCamera().setLocation(new Vector3f(0, 300, 0));
this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
}
#Override
public void simpleUpdate(final float tpf) {
}}
So following what J Atkin said about Terrain Grid, I found a endless terrain example that is a terrain grid. The Cells loaded class is protected, which means I have to extends it in the class to access it. In Jmonkey, the main class has to extend a simple application in order to run. Java doesn't allow multiple extensions, therefor I build a second class to allow access.
public class ViewTerrain extends TerrainGrid{
public void setView(int numberofcells){
super.cellsLoaded = numberofcells;
}
}
problem I am having with this class is that I don't know how to keep the original declaration IE.
this.terrain = new TerrainGrid("terrain", 65, 257, new ImageTileLoader(assetManager, new Namer() {
public String getName(int x, int y) {
return "Scenes/TerrainMountains/terrain_" + x + "_" + y + ".png";
}
}));
Looking at the source it seems TerrainGrid dynamically redefines an internal TerrainQuad tree based upon which grid the camera is in and the surrounding grid tiles. It would seem to me that you should define these tiles to be the size of the area you would like visible at any one time. Try updating patchSize in the constructor to be larger.
Alright so I would like to know why when i run this i cannot see the bullet collision objects Prob. a rookie mistake
public static PerspectiveCamera cam;
static btCollisionWorld collisionWorld;
DebugDrawer debugDrawer;
public ModelBatch modelBatch;
btCollisionConfiguration collisionConfig;
static btDispatcher dispatcher;
btBroadphaseInterface broadphase;
public static btCollisionShape voxelShape;
public static Model model;
public static ModelInstance test;
public static btCollisionShape collisiontest;
public static btCollisionObject collisiontestobject;
#Override
public void create () {
Bullet.init();
collisionConfig = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfig);
broadphase = new btDbvtBroadphase();
collisionWorld = new btCollisionWorld(dispatcher, broadphase, collisionConfig);
cam = new PerspectiveCamera(67, 1280, 720);
cam.position.set(10f,10f,10f);
cam.lookAt(0,0,0);
cam.near = 1f;
cam.far = 300f;
cam.update();
modelBatch = new ModelBatch();
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(3f, 3f, 3f,
new Material(ColorAttribute.createDiffuse(Color.BLUE)),
Usage.Position | Usage.Normal);
test = new ModelInstance(model);
test.transform.setTranslation(0,0,0);
collisiontest = new btBoxShape(new Vector3 (6f,6f,6f));
collisiontestobject = new btCollisionObject();
collisiontestobject.setCollisionShape(collisiontest);
collisiontestobject.setWorldTransform(new Matrix4());
debugDrawer = new DebugDrawer();
debugDrawer.setDebugMode(btIDebugDraw.DebugDrawModes.DBG_MAX_DEBUG_DRAW_MODE);
collisionWorld.setDebugDrawer(debugDrawer);
}
#Override
public void render () {
cam.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
debugDrawer.begin(cam);
collisionWorld.debugDrawWorld();
debugDrawer.end();
//modelBatch.begin(cam);
//modelBatch.render(test);
//modelBatch.end();
}
When i run this I expected to see the frames of the collision objects but instead I see nothing... This was a test program i created due to having alot of bullet issues..
You are doing everything correct, only a single thing is missing:
collisionWorld.addCollisionObject(collisiontestobject);
After creating the object, you still need to add it to the collision world. That's why the DebugDrawer does not render anything. It simply doesn't know about this object.
I am trying to render a Tiled Map on to an Android device. However, when I test it on my android phone, only the top layer is rendered on to the screen (out of two layers total). Is there a way to fix this? I am using Libgdx as well as Tiled Map Editor.
Below is some of the code for my project which implements the Screen interface. The omitted code is not necessary for the question but can be shown if needed.
public class Play implements Screen {
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.setView(cam);
renderer.render();
/*code ommited*/
renderer.getSpriteBatch().begin();
animateAgent(time);
sr.setProjectionMatrix(cam.combined);
try {
animateBullets(sr);
} catch(IndexOutOfBoundsException e) {}
renderer.getSpriteBatch().end();
}
public void show() {
cam = new OrthographicCamera();
cam.setToOrtho(false);
cam.position.set(0,0,0);
cam.zoom = 8.0f;
cam.update();
map = new TmxMapLoader().load("data/batMap.tmx");
blocked = (TiledMapTileLayer) map.getLayers().get(1);
renderer = new OrthogonalTiledMapRenderer(map);
atlas = new TextureAtlas("data/specOps.txt");
agent = atlas.createSprites("agent");
/* code ommitted */
player = new Player(agent,blocked,bullets);
Gdx.input.setInputProcessor(player);
}
}
Here's how it currently looks:
and here's how it should look:
You are only getting one layer at
blocked = (TiledMapTileLayer) map.getLayers().get(1);
or are you getting the other layer elsewhere?
Try:
map.getLayers().get(0).setVisible(true);
map.getLayers().get(1).setVisible(true);