Libgdx ScaleToAction not resizing - libgdx

I am trying to make a sprite move, rotate and resize by using MoveToAction, RotateToAction and ScaleToAction. The first two works fine, but I have a problem with ScaleToAction.
I add the action to the Actor just like I do with the two that works. I think the problem might be in the #Override? When I run the code the sprite moves and rotates but no scaling is done.
I tried to use sprite.setscale as suggested in the answer below, but still no luck. I add the code from the class here:
public class Prizes extends Actor {
private LearnToRead game;
private TextureAtlas atlas;
private TextureRegion prizepic;
private Sprite sprite;
private RotateToAction rta;
private ScaleToAction sta;
private MoveToAction mta;
public Prizes(LearnToRead game) {
this.game = game;
atlas = new TextureAtlas("prizes.pack");
prizepic = atlas.findRegion("haxhatt");
sprite = new Sprite(prizepic);
sprite.setPosition(450 - sprite.getWidth() / 2, 450 * Gdx.graphics.getHeight() / Gdx.graphics.getWidth() - sprite.getHeight() / 2);
//setBounds(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
setTouchable(Touchable.enabled);
rta = new RotateToAction();
sta = new ScaleToAction();
mta = new MoveToAction();
rta.setRotation(180f);
sta.setScale(2f);
mta.setPosition(0, 0);
mta.setDuration(5f);
rta.setDuration(5f);
sta.setDuration(5f);
Prizes.this.addAction(rta);
Prizes.this.addAction(sta);
Prizes.this.addAction(mta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
sprite.draw(batch);
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void positionChanged() {
sprite.setPosition(getX(), getY());
}
#Override
protected void rotationChanged() {
sprite.setRotation(getRotation());
}
#Override
protected void sizeChanged() {
sprite.setScale(getScaleX(), getScaleY());
}
}
If also tried to remove sprite and just use the TextureRegion, but didn't get it to work. The texture is drawn, but not moving. I post that code as well, but I do confess that I am quite uncertain about this code:
public class Prizes extends Actor {
private LearnToRead game;
private TextureAtlas atlas;
private TextureRegion prizepic;
private RotateToAction rta;
private ScaleToAction sta;
private MoveToAction mta;
public Prizes(LearnToRead game) {
this.game = game;
atlas = new TextureAtlas("prizes.pack");
prizepic = atlas.findRegion("haxhatt");
Prizes.this.setBounds(450 - Prizes.this.getX(), Prizes.this.getY(), Prizes.this.getWidth(), Prizes.this.getHeight());
setTouchable(Touchable.enabled);
rta = new RotateToAction();
sta = new ScaleToAction();
mta = new MoveToAction();
rta.setRotation(180f);
sta.setScale(2f);
mta.setPosition(0, 0);
mta.setDuration(5f);
rta.setDuration(5f);
sta.setDuration(5f);
Prizes.this.addAction(rta);
Prizes.this.addAction(sta);
Prizes.this.addAction(mta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
game.batch.begin();
game.batch.draw(prizepic, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
game.batch.end();
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
protected void positionChanged() {
Prizes.this.setPosition(getX(), getY());
}
#Override
protected void rotationChanged() {
Prizes.this.setRotation(getRotation());
}
#Override
protected void sizeChanged() {
Prizes.this.setScale(getScaleX(), getScaleY());
}
}
Maybe someone has a good idea about what I am doing wrong?

Use sprite.setScale instead of sprite.scale. The difference is that you are setting it a specific value instead of multiplying the current scale by some value.
But it is redundant to use Sprite with Actor because both classes store position, rotation, scale, and color. It makes more sense to use a TextureRegion with Actor. Or you can use the Image class, which already handles this for you.
Edit:
I see the other part of the issue. You are overriding sizeChanged, but it's the scale, not the size, that you are changing with a ScaleToAction. Actor doesn't have a callback for the scale changing. You could override the setScale methods to apply your change to the Sprite, but like I said above, it doesn't make sense to be using a Sprite for this. You should reference a TextureRegion, and draw it with all the appropriate parameters in the draw() method.

Related

rendering texture from other class in libgdx

i am making a game in libgdx. I have a super class Monster with child classes of that monster (warrior,mage,..). I would like to render this Monster class (actually his child) in playScreen class. Each class has its own animaton and textures, damage/health values. How do i do that? In which class do i define position for rendering, animation of that monster? in child classes, super class or in playScreen? My current code is here:
public class Monster {
public Animation monster;
public TextureAtlas atlas;
public int health;
public int damage;
public Monster(){
atlas = new TextureAtlas(Gdx.files.internal("mons1.txt"));
monster = new Animation(1/15f, atlas.getRegions());
}
Child class:
public class Mage extends Monster {
public Mage(int health,int damage, Animation animation){
super(health, damage, animation);
}
PlayScreen class:
public class PlayScreen implements Screen, InputProcessor {
private SpriteBatch batch;
public TextureAtlas atlas;
TextureRegion region;
private int height;
private Viewport viewport;
private Camera camera;
private int width;
private float elapsedTime = 0;
private Handler h;
private Stage stage;
private InputProcessor processor;
public PlayScreen(Handler h){
this.h = h;
batch = h.batch;
camera = h.camera;
viewport = h.viewport;
height = h.height;
width = h.width;
region = new TextureRegion();
stage = new Stage(viewport,batch);
stateTime = 0f;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.end();
}
Create base class that will have methods for all entities in your world.
For example let's give in name Entity. It will have only fields and methods that base for all monsters, creatures, player also, etc.
class Entity {
protected int x; // use getters/setters to get/change these fields
protected int y;
protected int width;
protected int height;
protected Texture texture;
public Entity(Texture texture, int x, int y, int width, int height) {
this.texture = texture;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
void draw(SpriteBatch batch) {
batch.draw(texture, x, y, width, height);
}
}
Now you can create base entity that will simple draw one texture always.
How to animate it? Create inheritor.
class AnimatedEntity extends Entity{
protected float stateTimer = 0f; // use getters/setters to get/change these fields
protected Animation animation;
public AnimatedEntity(Animation animation, int x, int y, int width, int height) {
super(animation.getKeyFrames(0), x, y, width, height); // calls parent constructor
this.animation = animation;
}
#Override
void draw(SpriteBatch batch) {
texture = animation.getKeyFrame(stateTimer); // texture from parent visible here
super(batch); // calls draw method from Entity
}
}
Now you can extend Monster from AnimatedEntity class. To add attack method for example. Hope you got it. I mean principe.
How to draw all my entities?
Outside constructor :
ArrayList<Entity> entities;
In constructor :
entities = new ArrayList<>();
AnimatedEntity mage = new AnimatedEntity(someAnimation, x, y, width, height);
entities.add(mage);
In render(..) :
for (e in entities) {
e.draw(batch);
}
You could make a render method in the monster and/or child class. It depends if all monsters are going to be rendered the same way, either way it is useful to make an empty render method in the monster class nonetheless (so we do not have to cast classes in future).
public class Monster {
public Animation monster;
public TextureAtlas atlas;
public int health;
public int damage;
public Monster(){
atlas = new TextureAtlas(Gdx.files.internal("mons1.txt"));
monster = new Animation(1/15f, atlas.getRegions());
}
public void render(SpriteBatch batch) {
// here you will use your animation and textureAtlas to render
}
You then call the render method in your main render in PlayScreen, make sure to put the batch as parameter.
If you have one monster you wish to render differently, you could override the monster's render method like this:
public class Mage extends Monster {
public Mage(int health,int damage, Animation animation){
super(health, damage, animation);
}
#Override
public void render(SpriteBatch batch) {
// your mage specific render
// calling super.render(batch) will call its superclass' render
}
I hope you know how to use your animation to actually render it now, otherwise here is a useful link. Good luck!

Actor in Stage Does Not Update the MoveTo XY Location

I am creating a game wherein an apple is being shot with an arrow. The apple's location is the XY location of the user input and the arrow actor has to move to that location using the code actor.moveto. The problem is the arrow only moves only once to the user input's direction. I know that the moveTo action of the actor is updated many times per second when I called stageArrow.act in the update method so I am wondering why the arrow only moves once. Here's my code:
appleclass.java
public class AppleClass implements Screen {
Arrow arrow;
private final MainApp app;
public Image ShotImage;
public AppleClass(final MainApp app){
this.app = app;
this.stageApple = new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
this.stageArrow =new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
arrow = new ArrowClass(app);
}
#Override
public void show() {
InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stageApple);
inputMultiplexer.addProcessor(stageArrow);
Gdx.input.setInputProcessor(inputMultiplexer);
arrow();
}
public void arrow(){
arrow.isTouchable();
stageArrow.addActor(arrow);
arrow.addAction((moveTo(Gdx.input.getX(),Gdx.input.getY(),0.3f))); //===> only executes once.
arrow.addListener(new InputListener(){
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){
if (Gdx.input.isTouched()){
ShotImage.setVisible(true);
}
}
});}
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update(delta);
}
public void update(float deltaTime){
stageApple.draw();
stageArrow.draw();
stageApple.act(deltaTime);
stageArrow.act(deltaTime);
}
ArrowClass.java
public class ArrowClass extends Actor {
MainApp app;
AppleClass appleClass;
public Texture arrowTexture;
public ArrowClass(final MainApp app){
this.app = app;
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
final float delta = Gdx.graphics.getDeltaTime();
this.act(delta);
app.batch.begin();
app.batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
app.batch.end();
}
}
Any help will be highly appreciated. Thanks.
I think the problem is because you are calling this.act(delta) in your ArrowClass' draw method. When you call Stage#act(), it will call the act method on all of its actors for you. Since you're calling it once when you draw and again when you update the stage, it's moving at twice the normal speed and that could be causing it to reach its destination prematurely.
A few other comments about your code, if I may:
First, you probably don't want two separate stages- unless you're using Scene2D.UI, you would normally have a single stage with Arrow and Apple added to it as actors.
Second, when you override Actor#draw(), you should use the batch it passes you to do the rendering instead of using the one from app. You also don't want to call begin() and end() inside your draw method- these are 'expensive' and you only want to call them once per frame. However, if you just use the batch that is passed to draw(), the Stage class will handle beginning and ending for you and you won't need to call them explicitly.
Third, you actually don't need to call super.draw(batch, parentAlpha) because it's an empty method in the Actor class.
Thus, your class could be simplified to the following:
public class ArrowClass extends Actor {
AppleClass appleClass; // You never set this; you may not need it
Texture arrowTexture;
public ArrowClass(MainApp app, arrowWidth, arrowHeight) {
arrowTexture = new Texture("medievalarrow.png");
this.setSize(arrowWidth, arrowHeight);
this.setTouchable(Touchable.enabled);
this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
this.setOrigin(0,0);
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
}
}

Couldn't load tmx

I'm using libgdx in my 2D platformer game project for college task. For now I'm confused with loading tiledmap in libgdx. I have a big tmx map with size of 11400x1500 pixels and 30x30 tile size. Also an image with same pixel size which I load it in image layer. I try to load it but libgdx shows nothing.
My question is how to load single big tmx map or should I divide the map into several segment/section? Because I've tried other small tmx (3000x1500). If the tmx is divided then how to load them as one stage?
public class Layarloh implements Screen{
private JumatUtama game;
private TiledMap map;
private TmxMapLoader mapLoader;
private OrthographicCamera kamera;
private OrthogonalTiledMapRenderer mapRenderer;
private Viewport viewport;
public Layarloh(JumatUtama utama) {
float l=Gdx.graphics.getWidth(),t=Gdx.graphics.getHeight();
this.game = utama;
loadstage();
kamera = new OrthographicCamera();
kamera.setToOrtho(false,l,t);
kamera.update();
viewport = new FitViewport(l/3,t/3,kamera);
}
public void loadstage(){
mapLoader = new TmxMapLoader();
map = mapLoader.load("stage/s11.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map);
}
public void stik(float dt){
if (Gdx.input.isKeyPressed(Input.Keys.ANY_KEY))
kamera.position.x +=100*dt;
}
#Override
public void render(float delta) {
stik(delta);
kamera.position.set(550,550,0);
kamera.update();
mapRenderer.setView(kamera);
mapRenderer.render();
}
#Override
public void resize(int width, int height) {
kamera.viewportWidth = viewport.getScreenWidth();
kamera.viewportHeight = viewport.getScreenHeight();
kamera.update();
}
Unitscale does nothing, the code above works on smaller size of tmx map.
EDIT
Code above isn't working, and the below is working, notice the maploader is loading different tmx file, above code trying to load 11400x1500 pixel with 30x30 tile size, while code below trying to load 3800x1500 with 30x30 tile size, but I try to use the code below to load bigger tmx, its not working,
public class Layarloh implements Screen{
private JumatUtama game;
private TiledMap map;
private TmxMapLoader mapLoader;
private OrthographicCamera kamera;
private OrthogonalTiledMapRenderer mapRenderer;
public Layarloh(JumatUtama utama) {
float l=Gdx.graphics.getWidth(),t=Gdx.graphics.getHeight();
this.game = utama;
loadstage();
kamera = new OrthographicCamera();
kamera.setToOrtho(false,l,t);
kamera.position.set(550,550,0);
kamera.update();
}
public void loadstage(){
mapLoader = new TmxMapLoader();
map = mapLoader.load("stage/segmen1.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map);
}
public void stik(float dt){
if (Gdx.input.isKeyPressed(Input.Keys.ANY_KEY))
kamera.position.x +=100*dt;
}
#Override
public void render(float delta) {
stik(delta);
kamera.update();
mapRenderer.setView(kamera);
mapRenderer.render();
}
Try this code and this should fix it.
#Override
public void render(float delta) {
kamera.position.set(x, y, z);
kamera.update();
mapRenderer.setView(kamera);
mapRenderer.render();
}
#Override
public void resize(int width, int height) {
kamera.viewportWidth = width;
kamera.viewportHeight = height;
kamera.update();
}
EDIT
In the original code, OP was missing kamera.update() statement. And also the resize method. That is something which causes trouble when displaying the tiled map properly as you need to update the camera at every iteration of render.

LibGDX Stage and Actor, Events and Actor properties

I'm just starting android game development with LibGdx framework.
I read many online tutorial so far and the more I read the more I got confused: ApplicationListener, ApplicationAdapter, Stages, Game, Screens, Actors, Sprites, Images... not mentioning Input and Gesture listeners of all king).
I finally understood what kind of "model" I should use for the game I have in mind (a kind of puzzle game): Game, Screens, Stage and Actor.
So here is my first code.
This is the main application (Game):
package com.my.game1;
import com.badlogic.gdx.Game;
public class MyGame extends Game {
#Override
public void create () {
setScreen(new StarterScreen());
}
}
This is the main screen class:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.scenes.scene2d.Stage;
public class StarterScreen implements Screen {
private Stage stage;
private float screenW, screenH;
private Tess tessera;
#Override
public void show() {
tessera = new Tess("image.png");
stage = new Stage();
screenW = stage.getViewport().getWorldWidth();
screenH = stage.getViewport().getWorldHeight();
Gdx.input.setInputProcessor(stage);
stage.addActor(tessera);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
dispose();
}
#Override
public void dispose() {
stage.dispose();
}
}
And the following is the class that extends Actor:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
public class Tess extends Actor {
private Texture texture;
private boolean selected = false;
public Tess (String img) {
this.texture = new Texture(Gdx.files.internal(img));
this.setBounds(0f, 0f, this.texture.getWidth(), this.texture.getHeight());
this.setOrigin(this.texture.getWidth() / 2, this.texture.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
public void tap(InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
((Tess)event.getTarget()).setColor(0.5f, 0f, 0.5f, 1f);
}
});
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(texture, 0, 0);
}
public void finalize() {
this.texture.dispose();
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
this.setColor(0.5f, 0f, 0.5f, 1f);
else
this.setColor(0f, 0f, 0f, 0f);
}
}
The screen shows correctly the actor, but I cannot set the Actor's position or its scale, nor the "tap" event seems to get detected; and the color doesn't change.
What I did wrong?
Several things were wrong. First, just on the side, you don't want to call dispose() from the Screen's hide() method. hide() can be called simply when the screen is turned off, or when the app is switched to the background, and disposing of the Screen during that would cause serious issues on resume.
With that out of the way, here's what your Actor should have looked like:
package com.my.game1;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Touchable;
public class Tess extends Actor {
private Sprite sprite;
private boolean selected = false;
public Tess (String img) {
this.sprite = new Sprite(new Texture(Gdx.files.internal(img)));
this.setTouchable(Touchable.enabled);
this.setBounds(this.sprite.getX(), this.sprite.getY(), this.sprite.getWidth(), this.sprite.getHeight());
this.setOrigin(this.sprite.getWidth() / 2, this.sprite.getHeight() / 2);
this.setScale(0.25f);
this.addListener(new ActorGestureListener() {
#Override
public void tap (InputEvent event, float x, float y, int pointer, int button) {
((Tess)event.getTarget()).toggleSelect();
}
});
}
#Override
public void draw(Batch batch, float alpha){
sprite.draw(batch);
}
#Override
public void positionChanged(){
sprite.setPosition(getX(), getY());
}
public void toggleSelect(){
this.selected = !this.selected;
if (this.selected == true)
sprite.setColor(0.5f, 0f, 0.5f, 1f);
else
sprite.setColor(0f, 0f, 0f, 0f);
}
}
First thing changed: you should use a Sprite, not a Texture, to handle color, drawing and transformations easily. Texture is possible, but is not as straightforward as Sprite is.
Next, you need to call setTouchable(Touchable.enabled) inside the actor to actually enable hit detection. Without this, no touch events are passed to the Actor.
After that, with setBounds(), you need to use sprite.getX() and sprite.getY(), to utilize the Sprite's positional values. Setting them to any arbitrary number seems to disable any touch capacity for that Actor.
Another thing, if all of that had been OK, is that you were setting the color twice for each touch, once based on the selected field, and then immediately after straight to the dark purple, so I removed the second set and just used your toggle method.
Next, since we have a Sprite now, we can use the draw() method attached to the Sprite itself and feed it the Batch, instead of calling the Batch's draw.
Finally, when you want to change the position of the image, call setPosition on the actor itself, and utilize an override of the positionChanged() method to set the Sprite's position based on the Actor's new position.

libgdx-html5 : texture dispose generate a bufferunderflowexception

I'm developping games with LIBGDX on ANDROID. Today, i've tried to generate one of my project in a HTML5 version. I put the content of the WAR folder on my server. All is fine except 2 things. I'll present you here just one of these 2 issues.
The problem : when a texture has to be disposed (by the call of its method dispose()), i get a BufferUnderflowException. It happens everytime.
Here is the sample code which is automatically generated when you create a new project :
public class TexDispose implements ApplicationListener
{
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
Gdx.input.setInputProcessor(this);
}
#Override
public void dispose() {
batch.dispose();
texture.dispose(); // HERE IS THE ERROR
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.end();
}
#Override
public void resize(int width, int height) {
}
}
Has one of you already met this issue..? If yes, how can i avoid that (except by not disposing anything lol) ?
Thank you ! ;)