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.
Related
I am trying to render an OrthogonalTiledMap I created using the map editor Tiled however for some reason nothing is showing up in my game screen; all I get is a black image being shown. I am using the Libgdx framework which has features for exactly these kinds of maps already built in however they won't work for me.
Libdgx also provides an example of rendering OrthogonalTiledMaps however it is outdated but I adjusted it to current Libdgx version but as already stated it doesn't work.
There are no errors nor exceptions being thrown. The .tmx file does also not contain any errors. All the used tileset are present and do not cause any errors.
This is my code:
`
public class My_Game extends ApplicationAdapter {
private TiledMap map;
private TiledMapRenderer renderer;
private OrthographicCamera camera;
private CameraInputController cameraController;
#Override
public void create () {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera();
camera.setToOrtho(true, w/8f, h/8f);
camera.update();
cameraController = new CameraInputController(camera);
Gdx.input.setInputProcessor(cameraController);
map = new TmxMapLoader().load("map.tmx");
renderer = new OrthogonalTiledMapRenderer(map, 1f / 8f);
}
#Override
public void render () {
camera.update();
renderer.setView(camera);
renderer.render();
}
#Override
public void dispose () {
map.dispose();
}
}`
Was a while since I did Libgdx so I might be thinking of something else, but don't you have to do some clearing in the render() function?
Try adding:
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
as the first three lines there and let me know if that helps.
Am trying to reduce number of calls being made everytime a Screen is called on my game in a bid to make my game faster and I noticed I do alot the same calculation on every screen..how can i avoid this?
I do this in practically every screen
public class ****Screen implements Screen {
#Override
public void show() {
float screenWidth = Gdx.graphics.getWidth();
float screenHeight = Gdx.graphics.getHeight();
float gameWidth = 360;
float gameHeight = screenHeight / (screenWidth / gameWidth);
midPointY = (int) (gameHeight / 2);
cam = new OrthographicCamera();
cam.setToOrtho(true, gameWidth, gameHeight);
viewport = new FitViewport(gameWidth, gameHeight, cam);
viewport.apply();
stage = new Stage(viewport);
Gdx.input.setInputProcessor(stage);
yet I have a GameClass..How can I implement the above in my gameclass(below) and only have to call it once?...
public class Start extends Game {
#Override
public void create() {
float screenWidth = Gdx.graphics.getWidth();
float screenHeight = Gdx.graphics.getHeight();
float gameWidth = 360;
float gameHeight = screenHeight / (screenWidth / gameWidth);
assets = new AssetLoader();
assetManager = new AssetManager();
camera = new OrthographicCamera();
camera.setToOrtho(true, gameWidth, gameHeight);
//initialize screens here
mainMenu = new MenuScreen(this);
loadingScreen = new LoadingScreen(this);
gameScreen = new GameScreen(this);
.......
//call assets
AssetLoader.load();
//start mainmenu...
this.setScreen(mainMenu);
}
First i have to tell you actualy this wont speed up your game.
If you change screen every 20 seconds then that means game does calculations 1 frame per 1200 frames.
However i am same like you and really looking for most optimize ways while doing game.
I found a solution for this case.
You can pass objects that you use in all screens, from game class to screen class.
Screen class
public class MainMenuScreen implements Screen {
public MainMenuScreen(OrthographicCamera camera) {
this.camera=camera;
}
//...Rest of class omitted for succinctness.
}
Game class
public class Starts extends Game {
OrthographicCamera camera;
public void create() {
camera=new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
this.setScreen(new MainMenuScreen(camera));// change screen and pass camera to new screen.
}
}
Or you can even pass the whole game class like this.
public class MainMenuScreen implements Screen {
final Starts game;
public MainMenuScreen(final Starts game) {
this.game = game;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.camera.update();
game.batch.setProjectionMatrix(game.camera.combined);
game.batch.begin();
game.font.draw(...);
game.font.draw(...);
game.batch.end();
if (Gdx.input.isTouched()) {
game.setScreen(new AnotherScreen(game));
dispose();
}
}
}
just need to call like this in game class. So you can use stage batches fonts etc. of game in all screens.
this.setScreen(new MainMenuScreen(this));
I assume you mean you want to shorten the little hiccup you get when switching screens. (Your game's frame rate is not affected by this.)
Easy way: move that code from show to the constructor of each screen class.
However, it is wasteful to be creating a new Stage for each Screen without passing it a SpriteBatch, because you are essentially instantiating three separate SpriteBatches, which are heavy objects (they have a big array for the mesh data, a big mesh on the GPU, and have to compile a shader).
You can instantiate shared objects in your Game class and pass them into the constructors of your Screens like this:
public class Start extends Game {
SpriteBatch spriteBatch;
#Override
public void create() {
//...
//initialize screens here
spriteBatch = new SpriteBatch(); //must be disposed in dispose()
mainMenu = new MenuScreen(this, spriteBatch);
loadingScreen = new LoadingScreen(this, spriteBatch);
gameScreen = new GameScreen(this, spriteBatch);
//...
}
}
Update your Screens' constructors accordingly and pass the sprite batch into the stage constructors. Viewports and cameras are lightweight, so I wouldn't bother with moving those up to the Game class unless it helps make your code more maintainable.
By the way, you're kind of abusing FitViewport by pre-calculating the aspect ratio. The point of Viewports is that you don't need to calculate anything when setting up. Use new ExtendViewport(360, 1, cam) to get the same thing you're doing without the calculations. And make sure you're updating it in resize().
I'm trying to draw simple text with libGDX on the screen. The thing that I want to consider is the size of the text. I would like to draw score of the player on the screen which i would like it to be big. But even i use the freetype fonts, it's not looking smooth. Here is the code:
SpriteBatch batch;
String string;
FreeTypeFontGenerator generator;
FreeTypeFontParameter parameter;
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
generator = new FreeTypeFontGenerator(Gdx.files.internal("arial.ttf"));
parameter = new FreeTypeFontParameter();
parameter.size = 100;
font = generator.generateFont(parameter);
string = "0123456";
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
batch.begin();
font.draw(batch, string, 50, 400);
batch.end();
}
Am i on the right path to draw the score or some HUD screen to the viewport? Is there a nicer way or is there a way to do this with the fonts easily? (For starting to learn from scratch?)
EDIT: Here is how it looks like
Try setting the minFilter and magFilter of FreeTypeFontGeneratorParameter to Linear, like this:
#Override
public void create () {
batch = new SpriteBatch();
generator = new FreeTypeFontGenerator(Gdx.files.internal("arial.ttf"));
parameter = new FreeTypeFontParameter();
parameter.size = 100;
parameter.minFilter = Texture.TextureFilter.Linear;
parameter.magFilter = Texture.TextureFilter.Linear;
font = generator.generateFont(parameter);
string = "0123456";
}
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.
as the title says I'm trying to display a timer in my game that starts from 0 (and ideally, I want it to be on the top left of the screen)
I have the logic for the timer here:
public class Timer {
SpriteBatch batch;
private BitmapFont font;
private float deltaTime = 0;
CharSequence str;
public Timer() {
font = new BitmapFont();
batch = new SpriteBatch();
}
public void drawTime() {
deltaTime += Gdx.graphics.getDeltaTime();
str = Float.toString(deltaTime);
font.draw(batch, str, 0, 0);
}
}
I call this timer in my main class (Game) in the render() method like so:
public void render() {
player.update();
platform1.update();
platform2.update();
batch.begin();
Gdx.gl.glClearColor(135/255f, 206/255f, 235/255f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
flag.drawS(batch);
flag.draw(batch);
player.draw(batch);
platform1.draw(batch);
platform2.draw(batch);
timer.drawTime();
batch.end();
}
}
I get the error "SpriteBatch begin must be called before draw", so I tried moving the timer.drawTime() method in different places in render() but still no luck.
Anyone know what could be wrong? Any help is highly appreciated :)
You should not create SpriteBatch() inside your Timer object. SpriteBatch should be created once and used by multiple elements to draw themselves. Your Timer draw() method should look more like this:
public void drawTime(SpriteBatch batch) {
deltaTime += Gdx.graphics.getDeltaTime();
str = Float.toString(deltaTime);
font.draw(batch, str, 0, 0);
}
The specific error you are encountering is caused by the fact that you call batch.begin(); on a different SpriteBatch object then the one that gets used in drawTime().