I am new to programming in LibGDX and I'm currently working on a simple arcade game. And I would like to know how should I properly create a main character who just has to run and jump? Should I create a new class for him and implement some method? As for now, I have only two classes, MyGame where I handle the other game states and PlayState where I draw the background and objects.
Just create a Sprite, you can control it easily.
SpriteBatch batch;
Sprite sprite;//Main character
#Override
public void create(){
batch = new SpriteBatch();
sprite = new Sprite(new Texture(Gdx.files.internal("data/text.png")));
}
#Override
public void render(){
//Add logic to control the main character...
batch.begin();
sprite.draw(batch);
batch.end();
}
If you want to create more methods you could try extending the Actor class too, this way it can be reused.
public class MyActor extends Actor{
Texture texture = new Texture(Gdx.files.internal("data/tex.png"));
float actorX = 0, actorY = 0;
public MyActor(){
addListener(new InputListener(){//Receive events
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){//Check your run and jump buttons
//...
}
}
#Override
public void draw(Batch batch, float alpha){//Draw it
batch.draw(texture,actorX,actorY);
}
#Override
public void act(float delta){//Update it
}
}
Related
I'm currently making a 2d infinite runner esque game that has a release date of Halloween. I've nearly finished the game itself and I've just added a main menu and am currently in the process of making a pause menu. I'm having a big issue with setting the screens though. Setting the screen from my main menu into the game works perfectly fine but when I set the screen back to the main menu a few weird things happen:
Nothing in the spriteBatch renders, everything is just a black box (MainMenuScreen)
If I choose to go back to the game I find that not everything is reset like when the screen is initially set to GameScreen
Here's a video of the issue
Here's the code for how I switch screens:
From when the game is first opened to main menu:
public class RadiationPigeon extends Game {
public static final float PPM = 100;
public static SpriteBatch batch;
#Override
public void create () {
batch = new SpriteBatch();
setScreen(new MainMenuScreen(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose () {
batch.dispose();
}}
From MainMenuScreen to GameScreen:
private RadiationPigeon radiationPigeon;
public MainMenuScreen(RadiationPigeon radiationPigeon){
this.radiationPigeon = radiationPigeon;
}
playButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
radiationPigeon.setScreen(new GameScreen(radiationPigeon));
//I give GameScreen radiationpigeon so that the screen can be set back to MainMenu
}
});
From GameScreen to MainMenu:
private RadiationPigeon radiationPigeon;
public GameScreen(RadiationPigeon radiationPigeon){
world.setContactListener(new ContactListener());
Timer timer = new Timer();
timer.schedule(new BatAttackChanceCounter(), 0, 1000);
this.radiationPigeon = radiationPigeon;
}
pauseButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
//paused = true;
radiationPigeon.setScreen(new MainMenuScreen(radiationPigeon));
}
});
Just for reference, here's my render method of both screens:
MainMenuScreen:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
RadiationPigeon.batch.begin();
stage.draw();
RadiationPigeon.batch.end();
}
GameScreen:
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0,0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
RadiationPigeon.batch.setProjectionMatrix(pigeoncam.combined);
RadiationPigeon.batch.begin();
//RadiationPigeon.batch.draw(pausedScreen, pigeoncam.position.x - (250 / RadiationPigeon.PPM), pigeoncam.position.y - pigeoncam.viewportHeight / 2, 5, 5);
RadiationPigeon.batch.end();
b2dr.render(world, pigeoncam.combined);
stage.draw();
hud.stage.draw();
}
After lots of trial and error I finally resolved my issue. There was nothing wrong with how I set my screens (for anyone having trouble with setting screens the code I provided works). The problem was with the actual buttons and images. I had made some of them static because I needed to use the same buttonstyles and fonts in GameScreen. I thought that would save memory, however, once they were accessed outside the screen in which they were created (MainMenuScreen) they would lose all their values essentially making them empty without making them null.
A lack of understanding on how buttons worked is what caused the issue
EDIT:
Turns out a lack of understanding on how static variables work was the real issue. On android when you minimize an android app the java cycle doesn't stop and as such the items are "kept alive"
So I've got a class which extends ApplicationAdapter implements InputProcessor and does the following when you drag around on the screen.
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
float x = Gdx.input.getDeltaX();
float y = Gdx.input.getDeltaY();
if (Store.isGameState) {
Store.Entity.player.setxMove(x);
Store.Entity.player.setyMove(-y);
}
return true;
}
In my player class I have a update method which does the following:
#Override
public void update() {
x += xMove;
y += yMove;
Store.Camera.Camera.position.set(Store.Entity.player.getXPos() + Store.Entity.player.getWidth() / 2, Store.Entity.player.getYPos() + Store.Entity.player.getHeight() / 2, 0);
Store.Camera.Camera.update();
}
and a render method which is:
public void render(SpriteBatch SB) {
SB.begin();
Store.Entity.sprite.setPosition(Store.Entity.player.getXPos(), Store.Entity.player.getYPos());
Store.Entity.sprite.draw(SB);
SB.end();
}
Which all-in-all works, the camera will move around as will my sprite. However my sprite does not move at the same speed as my camera and I can't for the life of me figure out why this is the case. The sprite moves roughly twice as fast as the camera does, and isn't centered on the player which I'd like ideally.
EDIT:
So in my GameState I have the following:
package com.imjoshscott.dataria.states;
import com.imjoshscott.dataria.Game;
import com.imjoshscott.dataria.Store;
public class GameState extends State {
public GameState(Game game) {
super(game);
Store.isGameState = true;
Store.Entity.getPlayer(game, Store.Entity.getSprite());
Store.Graphics.getSpriteBatch();
Store.Graphics.getTiledMap();
Store.Graphics.getTiledMapRenderer();
Store.Camera.getCamera();
Store.Camera.getHudCamera();
Store.Camera.Camera.setToOrtho(false, Game.GAME_WIDTH, Game.GAME_HEIGHT);
Store.Camera.HudCamera.setToOrtho(false, Game.GAME_WIDTH, Game.GAME_HEIGHT);
Store.Camera.Camera.viewportHeight = Game.GAME_HEIGHT / 2.5f;
Store.Camera.Camera.viewportWidth = Game.GAME_WIDTH / 2.5f;
}
#Override
public void update() {
Store.Graphics.tiledMapRenderer.setView(Store.Camera.Camera);
Store.Entity.player.update();
}
#Override
public void render() {
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
}
The Camera stuff in the Store class:
public static class Camera {
public static OrthographicCamera Camera;
public static OrthographicCamera HudCamera;
public static OrthographicCamera getCamera() {
if(Camera == null)
Camera = new OrthographicCamera();
return Camera;
}
public static OrthographicCamera getHudCamera() {
if(HudCamera == null)
HudCamera = new OrthographicCamera();
return HudCamera;
}
}
EDIT: Showing update & render methods
public void update() {
moveCreature();
Store.Entity.sprite.setPosition(Store.Entity.player.getXPos(), Store.Entity.player.getYPos());
Store.Camera.Camera.position.set(Store.Entity.player.getXPos(), Store.Entity.player.getYPos(), 0);
Store.Camera.Camera.update();
xMove = 0f;
yMove = 0f;
}
public void render(SpriteBatch SB) {
SB.begin();
Store.Entity.sprite.draw(SB);
SB.end();
}
Updated My previous answer is not correct, upon seeing and checking the project I saw this render() method for GameState class (after looked around for several places but no dice, if ever found this very weird problem again I would direct to this).
public void render() {
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
Just one thing we need to add to fix very weird problem is to add the following code
Store.Graphics.SB.setProjectionMatrix(Store.Camera.Camera.combined);
so we would have
public void render() {
Store.Graphics.SB.setProjectionMatrix(Store.Camera.Camera.combined);
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
That means we need to set projection matrix to current active SpriteBatch to properly render stuff. It's also safe to set it before even render the tile as it uses the same camera as of player.
I am trying to make an object that extends the Actor class. but whenever I have call the Stage's draw() method, it only draws the button I added to it. Here is my code, maybe someone here can help me?
Code for my Screen class (Assume that I had overridden all necessary methods and that I imported all necessary classes):
public class PlayScreen implements Screen{
SpriteBatch batch;
Game game;
Table table;
Skin skin;
Stage stage;
BitmapFont font;
TextButton button;
TextDisplay display;
public PlayScreen(MyGdxGame game, SpriteBatch batch){
this.game = game;
this.batch = batch;
//instantiating Stage, Table, BitmapFont, and Skin objects.
font = new BitmapFont(Gdx.files.internal("MyTruefont.fnt"));
table = new Table();
stage = new Stage();
skin = new Skin(Gdx.files.internal("Test.json"));
button = new TextButton("Start!", skin, "default");
display = new TextDisplay(font, this);
//Setting table properties
table.setWidth(stage.getWidth());
table.align(Align.center|Align.top);
table.setPosition(0, Gdx.graphics.getHeight());
table.padTop(30);
//Adding actors to table
table.add(button).padBottom(50);
table.add(display);
//Adding table to stage and setting stage as the input processor
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
stage.draw();
batch.end();
}
And here is My Textdisplay class that extends Actor (Again assume all other methods have been overriden, and all necessary classes have been imported):
public class TextDisplay extends Actor implements Drawable {
Texture texture;
BitmapFont font;
String str;
public TextDisplay(BitmapFont font, Screen screen){
this.font = font;
texture = new Texture(Gdx.files.internal("TextArea.png"));
str = "";
setLeftWidth(texture.getWidth());
setRightWidth(texture.getWidth());
setBottomHeight(texture.getHeight());
setTopHeight(texture.getHeight());
}
#Override
public void draw(Batch batch, float x, float y, float width, float height) {
batch.draw(texture, x, y);
}
You overrode the wrong draw method. Actor's draw method signature is:
public void draw (Batch batch, float parentAlpha)
You overrode the one from Drawable. Not sure why you're implementing Drawable. There's already an Actor available for drawing text anyway, called Label.
Also, if you want to put your Actor in a table, you need to set its width and height, or the width and height of its cell in the table.
I am creating an Android Game using LibGdx. It is a platformer and the map is tiled based. To test the movements of the player I used Key inputs and the desktop version of the game works fine. I created some buttons in scene2d and added them as an actor to the scene so that the game has movement buttons when played on Android devices. The buttons work as "System.out.print" shows. Problem is: the buttons and the player are each created in a different class. I can't seem to modify the velocity (and so the movement) of the Player from the class that holds the buttons. For that I need to change the velocity and speed etc. to static, which gives me strange errors on an Android device (Player won't show, or disappears after a frame). I am not sure how to fix this and what is the actual cause of this error. Here is some of the code of the different Classes:
Main Class (MyGdxGame) only included one button as an example.
public class MyGdxGame extends Game implements ApplicationListener {
private Skin skin;
private Stage stage;
#Override
public void create() {
setScreen(new Play());
skin = new Skin(Gdx.files.internal("ui/defaultskin.json"));
stage = new Stage();
Gdx.input.setInputProcessor(stage);
//Button Right
TextButton buttonRight = new TextButton("Right", skin, "default");
buttonRight.setWidth(50f);
buttonRight.setHeight(50f);
buttonRight.setPosition(Gdx.graphics.getWidth() /2 - 250f, Gdx.graphics.getHeight()/2 - 200f);
buttonRight.addListener(new ClickListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Hold");
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.print("Released");
}
});
stage.addActor(buttonRight);
}
Play Class
public class Play implements Screen {
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera;
private Player player;
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.position.set(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
camera.update();
renderer.setView(camera);
renderer.render();
renderer.getSpriteBatch().begin();
player.draw(renderer.getSpriteBatch());
renderer.getSpriteBatch().end();
}
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
}
#Override
public void show() {
map = new TmxMapLoader().load("maps/map.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
camera = new OrthographicCamera();
player = new Player(new Sprite(new Texture("data/jack2.png")), (TiledMapTileLayer) map.getLayers().get(0));
player.setPosition(2 * player.getCollisionLayer().getTileWidth(), 10 * player.getCollisionLayer().getTileHeight());
}
Player Class
public class Player extends Sprite implements InputProcessor{
// the movement velocity //
public Vector2 velocity = new Vector2();
public float speed = 60 * 2, gravity = 60 * 1.8f;
private boolean canJump;
private TiledMapTileLayer collisionLayer;
private String blockedKey = "blocked";
public Player(Sprite sprite, TiledMapTileLayer collisionLayer){
super(sprite);
this.collisionLayer = collisionLayer;
}
#Override
public void draw(SpriteBatch spriteBatch) {
update(Gdx.graphics.getDeltaTime());
super.draw(spriteBatch);
}
So the button has a working ClickListener, but I don't know how it can modify the players velocity. Any help is welcome.
You just need to have some way to access that player instance from the class containing the button. In my games I make a static World class which can be accessed from anywhere in the program. Through the world class I can access the player instance. That's just how I do it, you may find another way. You say your program has errors on android device when making certain parameters static? Do you mean it compiles but it just doesn't work the way you expect? If that's the case, there is probably just a bug in how you're modifying the position or velocity of the player.
I'm having a hard time getting events working with my Actor in libgdx. I'm using nightly builds.
My stage is setup in the show() method of a Screen subclass:
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
Gdx.input.setInputProcessor(stage);
TestActor actor = new TestActor();
stage.addActor(actor);
And my actor class looks like:
class TestActor extends Actor {
private Sprite sprite;
private TextureAtlas atlas;
public TestActor() {
atlas = new TextureAtlas(Gdx.files.internal("textures/images-packed.atlas"));
sprite = atlas.createSprite("logo-96");
setTouchable(Touchable.enabled);
addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchDown()");
return true; // must return true for touchUp event to occur
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchUp()");
}
});
}
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(sprite, getX(), getY());
}
}
The events don't seem to fire. Oddly enough, I've used built-in UI widgets like the TextButton and can get those events to fire just fine. Can anybody see what I'm doing wrong?
You should also setBounds to your actor.
best way to do it (if you want the same size as your texture)
add these lines to your constructor :
setWidth(sprite.getWidth());
setHeight(sprite.getHeight());
setBounds(0, 0, getWidth(), getHeight());
notice you can also set the location of the bounds with the first 2 parameters.