How to draw Sprites in different methods libgdx - java

Hi i created a button in my create method. I added an addlistener to the button and an inputevent. However how can i render a sprite in the create method where if the button is touch. A sprite is drawn how can i do that ?/
public void create () {
buttonStyle = new TextButtonStyle();
buttonStyle.up = skin.getDrawable("button");
buttonStyle.over = skin.getDrawable("buttonpressed");
buttonStyle.down = skin.getDrawable("buttonpressed");
buttonStyle.font = font;
button = new TextButton("START", buttonStyle);
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
button.addListener(new InputListener(){
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button ){
drawTile(200,50);
return true;
}
});
// method used to draw a sprite when passing certain coordinates
public void drawTile(int x , int y){
spriteBatch.draw(sprite, x , y );
}
public void render () {
Gdx.gl.glClearColor(1f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
spriteBatch.begin();
spriteBatch.draw(background, 0, 0);
drawGrid();
spriteBatch.draw(startButton, 0, 0);
stage.draw();
spriteBatch.end()
}

Usually I have a manager for my entities to control situations like this (not sure if best approach), you will have to modulate your code.
First, I have an abstract class Entity that will be parent of all my entities in my game, so if I have enemies or player for example, I will have 2 classes Enemy and Player that will extend from Entity. This abstract class have (with other things) two principal methods, update() and render():
public abstract class Entity {
...
public abstract void update(float delta); // <- to move, collisions, blablabla
public abstract void render(SpriteBatch spritebatch); // <- to draw
...
}
By having this, you just need a some-kind-of-manager to update properly your entities, a very VERY simple one is the following:
public class EntityManager{
// A list of ALL your entities in your game...
private static Array<Entity> myEntityList = new Array<Entity>();
/**
* A very simple add method... This is what you will call when you touch
* your button.
*/
public static void add(Entity newEntity){
myEntityList.add(newEntity);
}
public static void update(float delta) {
// Take care of those entities that are being updated or expired!
...
// Update each of my entities
for(Entity e : myEntityList){
e.update(delta); // <- I'll update all my entities
}
...
}
public static void render(SpriteBatch spritebatch){
// draw each of my entities
for(Entity e : myEntityList){
e.render(spritebatch); // <- I'll draw all my entities
}
}
// dispose and other things are here too (omitted for simplicity)
}
Because this class is a bunch of statics methods, you just need to call the update() and render() method in your main class without instantiate it...
#Override
public void render(float delta){
// code here
...
EntityManager.update(delta); // <- Update all your entities
spritebatch.begin();
EntityManager.render(spritebatch); // <- Draw all your entities
spritebatch.end();
...
// more code here
}
And for the last, wherever you have your button listener...
myButton.addListener(new InputListener() {
public boolean touchDown (...) {
Gdx.app.log("I'll add an entity");
EntityManager.add(new Enemy()); // <--- here, new entity added!
// EntityManager.add(new OtherEnemy()); <-- other example
return false;
}
public void touchUp (...) {
Gdx.app.log("blah");
}
});
I have to omit a lot of code but I hope you get the idea. By doing this, you will have more control of all your entities in your game. I repeat, not sure if best approach but works for me.

Related

Create monster and set position of tiledMap #java #libGDX

I've a problem with setting my monster on the map. Firstly I create a Knight with camera coordinates. Now I want to set a monster on the map independent of the camera coordinates, so that when I am moving the player using keys the monster stays at the one position. I tried to implemets this and all I got was that the monster stayed at the bottom left corner of the screen all the time. Here is my Person class
public abstract class Person implements Stats {
public Person(String pathToFile,Vector2 position) {
...
}
public void update(float delta) {
spriteBatch.begin();
sprite.draw(spriteBatch);
spriteBatch.end();
}
And my bot class
public class Bot extends Person {
public Bot() {
super(toFilePath,new Vector2(500,550));
super.position.set(500,550);
}
#Override
public void update(float delta) {
super.update(delta);
}
#Override
public void dispose() {
super.dispose();
}
}
The Knight class
public class Knight extends Person {
public Knight(OrthographicCamera camera) {
super(toFilePath, new Vector2(MapScreen.startPositionX, MapScreen.startPositionY));
super.sprite.setCenter(camera.viewportWidth / 2, camera.viewportHeight / 2);
this.camera = camera;
// animation
...
}
public void update(float delta, MapScreen mapScreen) {
camera.update();
walkBatch.begin();
// input handling
walkBatch.end();
}
#Override
public void dispose() {
...
}
And the class where I set up all classes
public class MapScreen implements Screen {
...
#Override
public void show() {
init(startPositionX, startPositionY);
}
// initialize variable
private void init(float posX, float posY) {
camera = new OrthographicCamera();
camera.setToOrtho(false, width, height);
tiledMap = new TmxMapLoader(new ExternalFileHandleResolver()).load(mapName);
setTiledMapRenderer(new OrthogonalTiledMapRenderer(tiledMap));
knight = new Knight(camera);
camera.zoom = ZOOM;
camera.position.set(posX, posY, 0);
camera.update();
}
#Override
public void render(float delta) {
camera.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
getTiledMapRenderer().setView(camera);
getTiledMapRenderer().render(layerBottom);
knight.update(delta, this);
getTiledMapRenderer().render(layerTop);
}
When using a SpriteBatch (which you probably don't use at all, when looking at your code), then you can use your camera's matrix to calculate the offsets correctly.
use it like:
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
// draw your sprites here
spriteBatch.end();
You should then also consider improve performances by not rendering sprites off the screen:
Consider implementing some of the tips
I find a solution. I created a object layer in Tiled and there I set my monsters. Then in MapScreen I render it. Thanks for your help.

problems with multiple cameras and viewports in libgdx

so I am doing what is suppose to be a simple game but I think I might be complicating things. I have a camera for the GameScreen and a viewPort which follow the position of the player and when it reaches to points on the sides, the camera stops following the player and stays in one point.
This by itself works fine, but then I wanted to add the pause menu and some other features in the game, creating a hud class with its own camera and viewport as well as a Stage and a shapeRenderer.
The problem comes when I create the instance of this hud inside my gameScreen, the camera that I am looking while I am playing looks like is the hudCam, which does not follow the player and basically does not let me see the player when it reaches the edges of the screen.
This is my GameScreen Class:
public class GameScreen implements Screen {
WowInvasion game;
ScrollingBackground background;
private OrthographicCamera gameCam;
private Viewport gameViewPort;
/*
Basically I wanna keep the same sprites running while in the menu, playing and till dead
therefore, I'll have a switch statement with cases on where the games at, inside the functions needed. That way I'll keep
the game has a background for the menu and there's no need for running a second screen.
*/
public static final int MAIN_MENU = 0;
public static final int GAME = 1;
private static int state = 1; //current state. starts with MAIN_MENU //DEBUGGING GAME SCREEN
//STAGES
private GameStage gameStage; //game ui
private menuStage mainMenu; //Main menu of the game
private Hud hud;
//Resources
private TextureAtlas atlas; //for the textures most
private Skin skin; //for the styles and fonts
//Sprites
private Player player;
//Shapes
private float progressPower; //for the power to build up
private final float POWER_CHARGED = 1000; //limit to get power
private final float DECREASING_POWER = 20; //limit to get power
public GameScreen(WowInvasion game){
this.game = game;
gameCam = new OrthographicCamera();
gameCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
gameViewPort = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, gameCam);
progressPower = 0f;
game.wowAssetManager.loadTexturesGameScreen(); // tells our asset manger that we want to load the images set in loadImages method
game.wowAssetManager.loadSkins(); //load the needed skins
game.wowAssetManager.manager.finishLoading(); // tells the asset manager to load the images and wait until finsihed loading.
skin = game.wowAssetManager.manager.get("ui/menuSkin.json");
}
#Override
public void show() {
game.batch.setProjectionMatrix(gameCam.combined);
background = new ScrollingBackground();
atlas = game.wowAssetManager.manager.get(WowAssetManager.GAME_ATLAS); //declaring atlas
mainMenu = new menuStage(gameViewPort, game.batch, skin, game); //pass it so that we only use one batch and one same viewport
gameStage = new GameStage(gameViewPort, game.batch, skin, game);
hud = new Hud(game.batch, skin);
player = new Player(atlas.findRegion("player"), (int) gameCam.viewportWidth / 2, (int) gameCam.viewportHeight / 2);
switch(state){
case MAIN_MENU:
Gdx.input.setInputProcessor(mainMenu);
break;
case GAME:
background.setFixedSpeed(false); //does not work in here
}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(state == GAME) {
background.setFixedSpeed(false);
player.update(delta, gameCam.viewportWidth, gameCam.viewportHeight); //updating player for movement
//really cheap way to charge power with velocity
if(progressPower != POWER_CHARGED) {
progressPower += Math.abs(player.getVelocity().x) + Math.abs(player.getVelocity().y);
progressPower -= DECREASING_POWER;
}
else
progressPower = POWER_CHARGED / 4;
}
mainMenu.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); //updating while making sure delta won't be more than 1/30f.
gameStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
game.batch.begin();
background.updateAndRender(delta, game.batch); //updating scrolling background
player.draw(game.batch);
game.batch.end();
mainMenu.draw(); //draw the menu stage
gameStage.draw(); //draw the ui stage for the game
hud.getStage().draw();
hud.renderRotateMeter();
updateCamera(0, WowInvasion.WIDTH);
System.out.println(player.getPosition().x);
}
public void updateCamera(float startX, float endX){
Vector3 position = gameCam.position;
//linear interpolation : a + (b - a) * lerp
//b = player position
//a = current camera position
//lerp = interpolation factor
position.x = gameCam.position.x + (player.getPosition().x - gameCam.position.x) * .1f;
//making the camera stay when the player gets to close to the sides
if(position.x < startX) {
position.x = startX;
}
if(position.x > endX){
position.x = endX;
}
gameCam.position.set(position);
gameCam.update();
}
#Override
public void resize(int width, int height) {
gameViewPort.update(width, height);
//hud.getViewport().update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
mainMenu.dispose();
gameStage.dispose();
game.dispose();
hud.dispose();
}
public static void setState(int state) {
GameScreen.state = state;
}
}
And this is my HUD:
public class Hud implements Disposable{
private Stage stage;
private Viewport viewport;
Button buttonPause, buttonResume;
private OrthographicCamera hudCam;
private ShapeRenderer sp; //like a batch for shapes
public Hud(SpriteBatch sb, Skin skin){
hudCam = new OrthographicCamera();
hudCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
viewport = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, hudCam);
stage = new Stage(viewport, sb);
sp = new ShapeRenderer();
Table table = new Table();
table.top();
//this makes the table the size of the stage
table.setFillParent(true);
buttonPause = new Button(skin, "pause");
buttonPause.setTransform(true);
buttonPause.addListener(new ClickListener(){ //listener to handle event
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
buttonResume = new Button(skin, "resume");
buttonResume.setTransform(true);
buttonResume.setScale(0.5f);
buttonResume.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
buttonResume.setVisible(false);
}
});
table.add(buttonPause);
table.row();
table.add(buttonResume);
stage.addActor(table);
}
public void renderRotateMeter(){
sp.setProjectionMatrix(hudCam.combined);
sp.begin(ShapeRenderer.ShapeType.Filled);
sp.setColor(Color.YELLOW);
sp.rect(hudCam.position.x,hudCam.position.y, WowInvasion.WIDTH / 2, 20);
sp.end();
}
public Viewport getViewport() {
return viewport;
}
public Stage getStage() {
return stage;
}
#Override
public void dispose() {
stage.dispose();
sp.dispose();
}
}
thanks in advance!
EDIT
so I tried passing the gameCam has a parameter to the hud and instead of making a new OrthographicCamera I used that one has the hudCamara as well and well, the movement with the player is perfect except now the thins from the Hud do not move at all..
It looks like you only set projectionMatrix to only HUD camera as seen in
sp.setProjectionMatrix(hudCam.combined);
Try to set it the same to other stuff outside of the HUD class prior to draw call too.
Another thing to keep in mind is that, when you involve using multiple Viewport and Camera in the game as most of the time it will be 1 Viewport matching with 1 Camera and work with another set as in your case. In draw call, you need to call apply() or apply(true) of Viewport class too to tell the system that you will draw based on which viewport thus in turn it will adhere to screen coordinate that was set up by viewport's attaching camera.
So assume you have 2 objects that needed to be called in different viewport consecutively, do it like the following code. The methods call is correct according to libgdx API but variable names are fictional.
// draw objA adhering to viewportA (thus cameraA) <-- assume it's player cam
sb.setProjectionMatrix(cameraA.combined);
viewportA.apply();
objA.draw();
// draw objB adhering to viewportB (thus cameraB) <-- assume it's HUD cam
sb.setProjectionMatrix(cameraB.combined);
viewportB.apply(true); // send in true as for HUD, we always want to center the screen
objB.draw();
In summary, 2 things to keep in mind when drawing objects that use multiple of camera and viewport in consecutive draw call.
Set projection matrix to either SpriteBatch or ShapeRenderer.
Call apply() or apply(true) of Viewport class to let it know you work with this viewport.

How can add a drawing function to a button in libgdx?

I am using Screen-2D to build a button. I want give the button a function when it is click a sprite will be drawn how can i do this. This isn't all all my code but enough to show what am talking about.
public void create () {
buttonStyle = new TextButtonStyle();
buttonStyle.up = skin.getDrawable("button");
buttonStyle.over = skin.getDrawable("buttonpressed");
buttonStyle.down = skin.getDrawable("buttonpressed");
buttonStyle.font = font;
button = new TextButton("START", buttonStyle);
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
button.addListener(new InputListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
drawTile(200,50);
return true;
}
});
}
// method used to draw a sprite when passing certain coordinates
public void drawTile(int x , int y) {
spriteBatch.draw(sprite, x , y );
}
public void render () {
Gdx.gl.glClearColor(1f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
spriteBatch.begin();
spriteBatch.draw(background, 0, 0);
drawGrid();
spriteBatch.draw(startButton, 0, 0);
stage.draw();
spriteBatch.end()
}
You got the right idea. See this example:
button.addListener(new ChangeListener() {
#Override
public void changed (ChangeEvent event, Actor actor) {
drawTile(200,50);
}
});
https://github.com/libgdx/libgdx/wiki/Scene2d.ui#changeevents
I think you need to read more tutorials about how LibGDX and Scene2D works : Event processing is done before your render method, so any drawing will be erased when you clear screen.
A right approach would be to add a sprite (as Drawable) to a widget group when click firing. Then stage rendering will renderer all your component including your sprites.
Comparaing to MVC pattern : The stage is your model, you modifiy your model when events occurs and the render method is the view of your model (draw your model).

Interaction between 2 classes maybe

I'm trying to make a mini game with 2 classes: the menu and the play. I am trying to randomly change the image of an object in the play class by clicking a button in the menu class.
So, in the menu class I add a button and add input listener so that when I click
playbutton.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
game.setScreen(new lessonclass (game));
lessonclass.currentlevel = MathUtils.random(2);
return true;
}
});
in the play class, I add static int level, an object
public grid ( Vector2 position, Vector2 size) {
texture0 = new Texture (Gdx.files.internal("zero.jpg"));
texture1 = new Texture (Gdx.files.internal("one.jpg"));
texture2 = new Texture (Gdx.files.internal("two.jpg"));
texture3 = new Texture (Gdx.files.internal("three.jpg"));
this.position = position;
this.size = size;
}
public void update(){
}
public void draw0(SpriteBatch batch) {
batch.draw(texture0, position.x, position.y, size.x, size.y);
}
public void draw1(SpriteBatch batch) {
batch.draw(texture1, position.x, position.y, size.x, size.y);
}
public void draw2(SpriteBatch batch) {
batch.draw(texture2, position.x, position.y, size.x, size.y);
}
if (TouchDown) {System.out.println ("" + level);}
When I run the program, the level value VARIES between 0 and 1 but the object always draw image batch.
If I change the code in the menu class so that it only brings me to play class and the in play class I change the level to
public static int level = MathUtils.random(1);
then my level value varies and the object randomly draws either batch image or batch1 image.
However, I want to do this from the menu class. Since the program runs and I cant think of the logic error, I am stuck now. Why can't I change my object image by clicking the button in the menu class?

LibGDX Scene2D: Applying Actions to Actors in separate class

I'm having trouble getting a MoveToAction to work on an Actor (menuBackground), when the Actor is in a separate class. I have attached relevant code below- which doesn't make the Actor move at all.
I have had success in apply other actions to the root stage in the MainMenuScreen class, and to a different Actor (Button) in the MainMenuScreen class, but have had no success applying actions to Actors in a separate class.
I've tried putting the MoveToAction in the act(float delta) method within the MenuBackground class, but that didn't work either. Neither did assigning the MoveToAction to the menuBackground from within the MainMenuScreen class.
Note that I am making a call to super.act(delta); within my MenuBackground class.
I would ultimately like to put the code for the MoveToAction within the Actor MenuBackground class, to make things neat and tidy.
Cheers.
Class containing stage:
public class MainMenuScreen implements Screen
{
private Stage stage;
public MainMenuScreen()
{
stage = new Stage(new FitViewport(800, 480));
Gdx.input.setInputProcessor(stage);
menuBackground = new MenuBackground();
MoveToAction moveToAction = new MoveToAction();
moveToAction.setPosition(242f, 276f);
moveToAction.setDuration(10f);
menuBackground.addAction(moveToAction);
stage.addActor(menuBackground);
#Override
public void render(float delta)
{
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
...
}
Actor Class:
public class MenuBackground extends Actor
{
private Texture menuBackgroundTexture;
private float actorX;
private float actorY;
public MenuBackground()
{
menuBackgroundTexture = new Texture(Gdx.files.internal("data/menuTitleTexture.png"));
actorX = 242f;
actorY = 350f;
setBounds(actorX,actorY,316,128);
}
#Override
public void draw(Batch batch, float alpha)
{
batch.draw(menuBackgroundTexture,actorX,actorY);
}
#Override
public void act(float delta)
{
super.act(delta);
}
...
}
The problem is inside your draw() method.
Look at code draws your texture, it uses actorX and actorY which are actually fields that don't change their values.
The proper way is:
batch.draw(menuBackgroundTexture, getX(), getY(), getWidth(), getHeight());
So, you should use actor's own fields and getters and don't manage yours.

Categories

Resources