I'm developing a Tower Defense game using libGDX. I've just started and I am able to display the path, the "environment" and the enemies walking along the path.
I displayed the environment using a SpriteBatch-Object, like this:
public LevelController(Level level) {
spriteBach = new SpriteBach();
atlas = new TextureAtlas(Gdx.files.internal("images/textures/textures.pack"));
}
public void setSize() {
spriteBatch.setProjectionMatrix(this.cam.combined);
}
public void render() {
spriteBatch.begin();
drawTowerBases();
spriteBatch.end();
}
private void drawTowerBases() {
// for each tower base (=environment square)
TextureRegion towerBaseTexture = atlas.findRegion("TowerBase");
if(towerBaseTexture != null) {
spriteBatch.draw(towerBaseTexture, x, y, 1f, 1f);
}
}
This is working properly and the textures are displayed well: Tower Defense using spriteBatch
Now, I was wondering if it is possible to cache the background. Because it stays the same, there is no need to calculate it every time. I've found the SpriteCache through Google-Search. So I changed the code as follows:
public LevelController(Level Level) {
spriteCache= new SpriteCache();
atlas = new TextureAtlas(Gdx.files.internal("images/textures/textures.pack"));
spriteCache.beginCache();
this.drawTowerBases();
this.spriteCacheEnvironmentId = spriteCache.endCache();
}
public void setSize() {
this.cam.update();
spriteCache.setProjectionMatrix(this.cam.combined);
}
public void render() {
spriteCache.begin();
spriteCache.draw(this.spriteCacheEnvironmentId);
spriteCache.end();
}
private void drawTowerBases() {
// for each tower base (=environment square)
TextureRegion towerBaseTexture = atlas.findRegion("TowerBase");
if(towerBaseTexture != null) {
spriteCache.add(towerBaseTexture, x, y, 1f, 1f);
}
}
And now the game looks like this: Tower Defense using spriteCache
For me it seems as if the transparency is not rendered properly. If I take images without transparency, everything works fine. Does anyone have an idea, why this happens and how I can fix this?
Thank you in advance.
Taken from the SpriteCache documentation:
Note that SpriteCache does not manage blending. You will need to enable blending (Gdx.gl.glEnable(GL10.GL_BLEND);) and set the blend func as needed before or between calls to draw(int).
I guess there is not much more to say.
Related
So I've recently started tinkering with LibGDX (desktop only, at the moment) in Java. I'm mildly experienced with other type of OGL libraries in other languages (namely SFML in C++) and quite experienced with the Java language itself, so I tackled LibGDX pretty confidently; and while the results were mostly positive, there's a bug that I just can't figure out.
What I want to achieve is simple: draw a map (Tiled .tmx), draw a Sprite (soon-to-be "player") inbetween layers 1 and 2, and render a couple of GUI widgets on top of all that, using a scene2D stage. I've managed to achieve this partially.
Here's my Game class, it's pretty messy from so much switching things around just to try, but it's pretty clear what it attempts to do:
public class Game extends ApplicationAdapter
{
private SpriteBatch batch;
private Texture img;
private Sprite playerSprite;
private TiledMap tiledMap;
private OrthographicCamera camera;
private OrthogonalTiledMapRenderer tiledMapRenderer;
private Stage stage;
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("trchar000.png");
playerSprite = new Sprite(img, 0, 0, 32, 48);
playerSprite.setPosition(32, 192);
InputHandler.init();
Gdx.input.setInputProcessor(new InputHandler());
stage = new TestStage(playerSprite);
// inputs
InputMultiplexer im = new InputMultiplexer(stage, new InputHandler());
Gdx.input.setInputProcessor(im);
// tiles
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.update();
tiledMap = new TmxMapLoader().load("map2.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap);
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
tiledMapRenderer.setView(camera);
int[] groundLayers = {0};
int[] topLayers = {1};
// render layer1 -> player -> layer 2
// the .tmx map doesn't have any other layers (just those 2)
tiledMapRenderer.render(groundLayers);
// removing these 3 lines solves the issue, but doesn't render the player
// I've also tried using my regular SpriteBatch instance; same results
// Also, I tried creating a class that extends OrthogonalTiledMapRenderer and overriding the render() method, so that it would draw the player inbetween layers, but again, same results.
tiledMapRenderer.getBatch().begin();
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
tiledMapRenderer.getBatch().end();
tiledMapRenderer.render(topLayers);
batch.begin();
// just to try, I'm rendering the stage here (not calling it's draw() method). Removing this for loop solves the issue, but doesn't render the GUI
for(Actor a : stage.getActors())
a.draw(batch, 1);
batch.end();
}
#Override
public void dispose () {
batch.dispose();
img.dispose();
tiledMapRenderer.dispose();
stage.dispose();
}
}
Also, here's my TestStage class:
public class TestStage extends Stage {
private Skin skin;
private BitmapFont newDefaultFont;
public TestStage(Sprite player)
{
super(new ScreenViewport());
// skin
FreeTypeFontGenerator freeTypeFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("segoeui.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = 14;
newDefaultFont = freeTypeFontGenerator.generateFont(parameter);
skin = new Skin();
skin.add("default-font", newDefaultFont, BitmapFont.class);
FileHandle fileHandle = Gdx.files.internal("uiskin.json");
FileHandle atlasFile = fileHandle.sibling("uiskin.atlas");
if (atlasFile.exists()) {
skin.addRegions(new TextureAtlas(atlasFile));
}
skin.load(fileHandle);
final TextButton button = new TextButton("This is a Button", skin, "default");
button.setPosition(250, 250);
button.setWidth(150);
button.setHeight(40);
final Label lbl = new Label("Test", skin);
this.addActor(lbl);
this.addActor(button);
}
}
Now here's the deal; this is what it looks like if a try to render everything (as shown in my Game class' render() method):
Image 1
The player, GUI, and layer 2 are rendered correctly, but the layer 1 is all bugged out, and I can't figure out why.
Now, here's how it looks like if a don't render the player, removing the line
tiledMapRenderer.getBatch().draw(playerSprite, playerSprite.getX(), playerSprite.getY());
Image 2
Everything renders fine.
Also, here's what it looks like if I decide not to render the stage actors, commenting this loop:
for(Actor a : stage.getActors())
a.draw(batch, 1);
Image 3
Again, everything renders fine.
The only other classes in my project are the default DesktopLauncher class, and an InputProcessor which I'm sure has nothing to do with this.
This is my first question here ever; I just can't figure this out.
Thanks in advance.
Im trying to implement a pause option for my following game. By pressing the back button my game should go to the updatePause() method. But instead it renders the latest 2-3 frames repeatedly. Making it look like it's "flickering".
By trying to prevent this I've added (in the comments) non-continously rendering which prevented the flickering. But then Im facing the problem that pressing the back-button more than once will render another frame. (one of those flickering frames). This is my code structure in short:
public class GameScreen implements Screen {
private static final int GAME_RUNNING = 0;
private static final int GAME_PAUSED = 1;
private static final int GAME_OVER = 2;
private static final int GAME_LEVEL_END = 3;
private int gameState;
private GdxGame game;
//create()
public GameScreen(final GdxGame game) {
//create all the stuff
}
#Override
public void render(float deltaTime) {
switch (gameState) {
case GAME_RUNNING:
updateRunning(deltaTime);
break;
case GAME_PAUSED:
updatePause(deltaTime);
break;
case GAME_OVER:
updateGameOver();
break;
}
}
public void updateRunning(float deltaTime) {
//draw section
if (gameState == GAME_RUNNING) {
game.batch.begin();
//Draw some stuff
game.batch.end();
//move section
handleInput();
}
}
public void updatePause(float deltaTime) {
//Gdx.graphics.setContinuousRendering(false);
//resume
if (Gdx.input.isTouched()) {
gameState = GAME_RUNNING;
//Gdx.graphics.setContinuousRendering(true);
return;
}
}
private void handleInput() {
//catch back button
Gdx.input.setCatchBackKey(true);
if (Gdx.input.isKeyJustPressed(Input.Keys.BACK)) {
gameState = GAME_PAUSED;
return;
}
}
}
Any tips to prevent the flickering?
The render() method is supposed to draw something to the screen. If it doesn't, then the contents of the back buffer will be undefined (so may contain a previous frame) and you get this flicker.
Disabling continuous rendering sounds like a good approach. Alternatively, continue drawing even if the game is paused.
As Thomas points out in his answer. It should be drawing every frame.
I haven't see you draw anything on screen yet, so backbuffer might just contain junk information. One way to solve this is to always clear the screen at the top of render(). This means when you switch immediately to another game state, it will make sure that screen is clear and no flickering result as you experienced.
public void render(float deltaTime) {
// clear screen
Gdx.gl.glClearColor(0f, 0f, 0f, 1.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
...
}
As Thomas said: continue drawing is a way to fix it. So I drew the latest frame and disabled continous rendering after that. The result is having no bug at all and giving the CPU a rest.
Is there a way to check if my sprite is visible? For instance I have a specific sprite I want to appear only IF this other sprite isn't visible. Example "You Win" will only appear if you win the game and the "You Lose" sprite isn't already on the screen. Thanks!
Visibility of sprite can be maintained by extending Sprite class. Add data member in your extended Sprite Class and at run-time check your sprite is visible of not.
you can also fulfill your requirement by this :
private Sprite win,loose;
private SpriteBatch spriteBatch;
private DialogType dialogType;
#Override
public void create () {
dialogType=DialogType.NONE;
spriteBatch=new SpriteBatch();
win=new Sprite(...);
loose=new Sprite(...);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
...
...
if(dialogType==WIN){
win.draw(spriteBatch);
}else if(dialogType==LOOSE){
loose.draw(spriteBatch);
}
spriteBatch.end();
}
public enum DialogType {
NONE,WIN,LOOSE
}
Seems like an overwhelm to do what you are trying to do, like I said in the comment with a simple boolean win,loose; you pretty much cover your example, or like other comment said you should not track the game state according with some sprite visibility make a enum and track the game state instead, like the other answer, BUT ima give you a solution
Use Image instead...
Image image = new Image(texture);
image.setBounds(0,0,100,100); // set x,y,width,height
stage.add(image); //add to stage
image.setVisible(false); //make it invisible
image.setVisible(true); //make it visible
image.isVisible(); //check if is visible
i'm making a game in libgdx but i'm new and i donĀ“t know if my code is the correct form or the best way to do it.
i'm trying to make the basis of the game:
a screen manager to implement a Menu,
an option screen
a loading screen
a game screen
a pause Screem
a game over screen
In the loading screen I like to do something like Dragon Ball when the loading screen allow us to make goku eat rice, the pause screen needs to draw some statistics and options something like Megaman or Castlevania, the menu do something when the player touch a button something like move the camera or open a door, or move to another "scenario" showing another options, and the game over screen needs to previously gives the player the opportunity to win some life to not lose the game.
I try to make this in this form:
I have the main class of the game with the constructor, and the overriden metods create(), render(), resize() and dispose(), the variables for a camera, a viewport, a Spritebatch, a int to store the current screen, and a manager for the screens.
public class BOS_Project extends Game {
OrthographicCamera camera;
Viewport viewport;
SpriteBatch batch;
AssetManager manager = new AssetManager();
int actualScreen = 0;
public BOS_Project(){
camera = new OrthographicCamera();
camera.setToOrtho(false, screenWidth, screenHeight);
viewport = new FitViewport(screenWidth, screenHeight);
}
#Override
public void create(){
batch = new SpriteBatch();
}
#Override
public void render(){
actualScreen = 1;
ScreenManager.getInstance().showScreen(1, this);
super.render();
}
#Override
public void resize(int width, int height){
viewport.update(width, height);
}
#Override
public void dispose(){
batch.dispose();
}
}
Also the class ScreenManager is singleton, and
public class ScreenManager{
private static ScreenManager instance;
private Game game;
Screen screen;
private ScreenManager(){
super();
}
public static ScreenManager getInstance(){
if(instance == null){
instance = new ScreenManager();
}
return instance;
}
public void initialize(Game game){
this.game = game;
}
public void showScreen(int currentscreen, BOS_Project game){
if(currentscreen == 1){
if(screen!=null)
screen.dispose();
screen = new LoadingScreen(game, game.actualScreen);
game.setScreen(screen);
}else if(currentscreen == 2){
if(screen!=null)
screen.dispose();
screen = new GameScreen(game);
game.setScreen(screen);
}else{
if(screen!=null)
screen.dispose();
screen = new MenuScreen(game);
game.setScreen(screen);
}
}
The other classes are the MenuScreen, GameScreen and Loading Screen.
Loading Screen:
public LoadingScreen(BOS_Project game2, int screen2){
game = game2;
screen = screen2;
game.manager.load("button.png", Texture.class);
game.manager.finishLoadingAsset("button.png");
sprite1 = new Sprite(game.manager.get("button.png", Texture.class));
sprite1.setPosition(0, 0);
//This is a method to load the assets for the especific screen
game.load(screen);
}
#Override
public void render(float delta){
if(game.manager.getProgress()==1) {
if (time < 3) {
Gdx.app.log("Loading: ", "90.0");
}
}else {
Gdx.app.log("Loading: ", String.valueOf(game.manager.getProgress() * 100));
}
game.manager.update();
batch = game.batch;
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
sprite1.draw(batch);
if(game.manager.getProgress()==1 && time > 3){
if(screen==1) {
ScreenManager.getInstance().showScreen(2, game);
}else{
ScreenManager.getInstance().showScreen(3, game);
}
}else{
time += delta;
}
batch.end();
super.render(delta);
}
The Menu and Game classes are similar to loading, only call the assets and draw some sprite on the render method.
This code function well to change screens but I don't know if is the correct form, and another big question is how to manage the pause screen, because I manage this only storing a variable if the variable is pause the render method draw something, if not draw the normal game, but if I want to change the options and images of the pause I need to check variables to know what the pause needs to draw.
if(pause){
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
spritePause.draw(batch);
batch.end();
}else if(game){
batch.begin();
spriteGame.draw(batch);
batch.end();
}
So, am i doing it right? or what would you recommend me? Some examples or maybe specific tutorials to achieve this would be great.
There is not only one correct way of managing screens. Libido gives you the freedom to do it exactly how you please. You can extend the Screen class to make screens for the different needs of your project. You can manage your screens as states and manage them with a state manager.
Regarding the Pause and Game Over screen, you can do that in different ways too.
You can have a dedicated screen to switch to or you can have a Pause and GameOver state in your Game state/screen and show the Pause/GameOver elements on top of your gamescreen while the game is still in the background.
So there is not a single correct way of doing it. The correct way is what works for your game.
For some inspiration:
pixnbgames.com : How to manage screens
Brent Aureli : Game State Manager
As #IronMonkey has answered, there is no "correct" way.
I do it with one GameScreen class only, and have a lot of different states inside the GameScreen class. The GameScreen class is very simple and short (100-200 LOC), and is responsible for switching between states. States are similar to the GameScreen class, but they can be entered and exited without the need to instantiate new objecs.
class GameScreen extends ScreenAdapter implements Disposable {
GameState menuState;
GameState playState;
GameState currentState;
public GameScreen(final MyGame game) {
menuState = new MenuState(this);
playState = new PlayState(this);
}
public void setState(GameState state) {
if(currentState == state) return;
// states have a method 'exit' where you can pause them or finalize something
if(currentState != null)
currentState.exit();
currentState = state;
// also states have 'enter' where you can unpause or init something when entering
currentState.enter();
}
public void render(float delta) {
currentState.render(delta);
}
}
First, this is very resource efficient, because the needed states are created only once when the game is started. Second, because you never destroy the states, but just change them and call enter/exit, they always retain perfectly their current state, i.e. variables, objects and everything and when you go back to a state, it is exactly as it was before you left it.
GameState is interface and you are free to implement it as you wish.
public interface GameState
{
public void enter();
public void exit();
public void update(float delta);
public void render(SpriteBatch batch, float delta);
public String toString();
public void dispose();
}
I'm new in libgdx and I'm trying to do some tutorials. I have problem with loading my own .png file.
Standard project contains libgdx.png file and it works. When I run it on desktop or android it works fine. Images display well.
The same code, just another file (also png).
Works fine on desktop version, but it cannot run on android.
I really dont understand what happens, because files (libgdx.png and my.png) are in the same folder and first one works on android but the second one doesnt...
public class AwesomeGame implements ApplicationListener {
SpriteBatch batch;
Texture man;
Texture abc;
Vector2 position;
#Override
public void create() {
batch = new SpriteBatch();
man = new Texture(Gdx.files.internal("my.png"));
position = new Vector2(50,50);
}
#Override
public void dispose() {
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
if(Gdx.input.isKeyPressed(Input.Keys.W)){
position.y+=1f;
}
if(Gdx.input.isKeyPressed(Input.Keys.S)){
position.y-=1f;
}
if(Gdx.input.isKeyPressed(Input.Keys.D)){
position.x+=1f;
}
if(Gdx.input.isKeyPressed(Input.Keys.A)){
position.x-=1f;
}
if(Gdx.input.getAccelerometerX()!=0){
position.x-=Gdx.input.getAccelerometerX();
}
if(Gdx.input.getAccelerometerY()!=0){
position.y+=Gdx.input.getAccelerometerY();
}
batch.setColor(position.x,position.y,10,10);
batch.begin();
batch.draw(man, position.y, position.x);
batch.end();
}
Can someone explain me that ? ;(
omg, I got it.
Texture width and height must be a power of 2.
but if I set
cfg.useGL20 = true;
everything works without power of 2.