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.
Related
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.
My goal is to create a game that is always displayed with an aspect ratio of 9:16 (basically 16:9, but upright) using FitViewport; it should be independet of a target device's resolution. In order to test this setup, I created the following minimal working example. A small green square indicates the origin of the coordinate system:
MyGame.java
public class MyGame extends ApplicationAdapter {
final int WORLD_WIDTH = 900;
final int WORLD_HEIGHT = 1600;
Stage stage;
Viewport vp;
public void create() {
stage = new Stage();
vp = new FitViewport(WORLD_WIDTH, WORLD_HEIGHT, stage.getCamera());
stage.setViewport(vp);
stage.addActor(new MySquare());
}
public void render() {
stage.act();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
// dispose...
}
MySquare.java
public class MySquare extends Actor {
ShapeRenderer renderer = new ShapeRenderer();
#Override
public void draw(Batch batch, float alpha){
batch.end();
renderer.begin(ShapeRenderer.ShapeType.Filled);
renderer.setColor(Color.GREEN);
renderer.rect(0, 0, 50, 50);
renderer.end();
batch.begin();
}
}
Unfortunately, the result is not as expected: As you can see, the green square is actually not a square. This behavior is the same for both Windows and Android (in landscape mode):
However, when setting the size of the window programmatically and explicitly via LwjglApplicationConfiguration in DesktopLauncher.java to a valid 9:16 resolution, the green square is displayed correctly. Why is that and how can I avoid this workaround (which does not work for Android anyway)?
Your problem is that your shape renderer is ignoring the camera. Update it like this:
public void draw(Batch batch, float alpha){
batch.end();
renderer.setProjectionMatrix(batch.getProjectionMatrix()); // <<<<< Add this
renderer.begin(ShapeRenderer.ShapeType.Filled);
renderer.setColor(Color.GREEN);
renderer.rect(0, 0, 50, 50);
renderer.end();
batch.begin();
}
If you are planning to eventually use sprites, and you're simply wanting rectangle placeholders for your actors, you don't need a custom actor for this. You can use a generic Actor and call setDebug(true) on it, and Stage will automatically draw its outline using an internal ShapeRenderer. Of course, you must first set a size and position on the Actor.
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.
I have a render method and I can't figure out why it isn't happening. Here's the code I have so far:
public class DevMaze extends Game {
SpriteBatch batch;
BitmapFont font;
public void create() {
...
this.setScreen(new MainMenuScreen(this));
...
}
public void render() {
super.render();
}
...
}
The MainMenuScreen gets set and renders just fine, here's the code:
public class MainMenuScreen implements Screen {
final DevMaze game;
OrthographicCamera camera;
public MainMenuScreen(final DevMaze g) {
this.game = g;
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
public void render(float delta) {
...
if (Gdx.input.isTouched()) {
game.setScreen(new GameScreen(game)); // This line runs
dispose();
}
}
But when I set the screen to my GameScreen, the Constructor runs just fine, but the render method never fires:
public class GameScreen implements Screen {
final DevMaze game;
OrthographicCamera camera;
...
public GameScreen(final DevMaze g) {
this.game = g;
// Create Camera
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// Load assets
...
System.out.println("ONE MORE LINE!"); // This prints
}
public void render() {
System.out.println("MADE IT TO GAME SCREEN"); // This does not prints
...
}
I need to know why the render method is not firing.
I really don't know where to go from here. Every other resource I can find tells me to make sure I have super.render() in my game extending class - which I do. I tried to remove the code I thought would be irrelevant and leave the pertinent stuff, but if there is any other information that you would need to figure out what's going on here just let me know.
This is also one of my first projects with LibGDX, so if this is a stupid question sorry in advance!
Thanks.
public void render() needs to be public void render(float deltaTime) in your GameScreen class. I assume that you have another method with the deltaTime in your GameScreen, which gets fired instead, because otherwise it wouldn't compile.
I'm developing a game using libGDX and I would like to know how I can drag and drop an Actor. I've made my stage and drawn the actor, but I don't know how to trigger that event.
Please try to help me using my own architecture.
public class MyGame implements ApplicationListener
{
Stage stage;
Texture texture;
Image actor;
#Override
public void create()
{
texture = new Texture(Gdx.files.internal("actor.png"));
Gdx.input.setInputProcessor(stage);
stage = new Stage(512f,512f,true);
actor = new Image(texture);
stage.addActor(actor);
}
#Override
public void render()
{
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.draw();
}
}
If you don't want to use DragAndDrop class, you can use this:
actor.addListener(new DragListener() {
public void drag(InputEvent event, float x, float y, int pointer) {
actor.moveBy(x - actor.getWidth() / 2, y - actor.getHeight() / 2);
}
});
Edit: method drag instead touchDragged
Take a look at the Example in the libgdx examples. Here is the drag and drop test from the libgdx test classes: DragAndDropTest
If you just want to drag/slide your Actor around you need to add a GestureListener to it and pass your Stage to the Inputprocessor like this:Gdx.input.setInputProcessor(stage);.
Here is the GestureDetectorTest from libgdx.
For drag events its the Flinglistener.
In your main gamescreen class add a multiplexer so you can access events from different classes:
private InputMultiplexer inputMultiplexer = new InputMultiplexer(this);
After the gamescreen constructor add as an example:
inputMultiplexer = new InputMultiplexer(this);
inputMultiplexer.addProcessor(1, renderer3d.controller3d);
inputMultiplexer.addProcessor(2, renderer.controller2d);
inputMultiplexer.addProcessor(3, renderer3d.stage);
Gdx.input.setInputProcessor(inputMultiplexer);
In your class that is using the actors use a DragListener as and example:
Actor.addListener((new DragListener() {
public void touchDragged (InputEvent event, float x, float y, int pointer) {
// example code below for origin and position
Actor.setOrigin(Gdx.input.getX(), Gdx.input.getY());
Actor.setPosition(x, y);
System.out.println("touchdragged" + x + ", " + y);
}
}));