My game sets this screen and I see the actor that I create.
However can anyone tell me why the camera doesn't seem to be moving? I would expect the actor to move to the right as I pressed the Left key.
The Gdx.input.isKeyPressed(Input.Keys.LEFT) does resolve to true and the translate function does get called.
public class MainScreen implements Screen {
private Stage mainStage;
private Camera orthCamera;
#Override
public void show() {
orthCamera = new OrthographicCamera();
mainStage = new Stage(new ScreenViewport());
mainStage.getViewport().setCamera(orthCamera);
MyGameActorObject s = new MyGameActorObject();
s.setPosition(100, 100);
mainStage.addActor(s);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1); //sets clear
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
processKeyboardInput();
mainStage.act(delta);
mainStage.draw();
}
private void processKeyboardInput()
{
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
orthCamera.translate(-30, 0, 0);
orthCamera.update();
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
mainStage.dispose();
}
}
I am trying to acheieve being able to pan around the 2d game world using keyboard input.
This is the contents of the custom Actor object:
public class MyGameActorObject extends Actor
{
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
ShapeRenderer r = new ShapeRenderer();
r.begin(ShapeRenderer.ShapeType.Filled);
r.setColor(Color.RED);
r.circle(this.getX() - 50.0f, this.getY() - 50.0f, 100.0f);
r.end();
}
}
I believe I have to add something like
r.setProjectionMatrix(batch.getProjectionMatrix());
in my custom actor object. So the draw function on my object would now be.
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
ShapeRenderer r = new ShapeRenderer();
r.setProjectionMatrix(batch.getProjectionMatrix());
r.begin(ShapeRenderer.ShapeType.Filled);
r.setColor(Color.RED);
r.circle(this.getX() - 50.0f, this.getY() - 50.0f, 100.0f);
r.end();
}
I think your problem is that you haven't set the InputProcessor.
Gdx.input.setInputProcessor(...) is the method you're looking for. Put it in your show() method and pass it an InputProcessor reference. InputProcessor is an interface that goes through all the different types of click-based input and allows you to determine what happens in them. So for instance:
#Override
public boolean keyDown(int keycode)
{
switch(keycode)
{
case Keys.D:
screen.universe.entity_handler.player.moving_right = true;
break;
case Keys.A:
screen.universe.entity_handler.player.moving_left = true;
break;
case Keys.SPACE:
screen.universe.entity_handler.player.jumping = true;
break;
...
}
...
}
The above code is part of an InputProcessor-implementing class for a game I'm making. When the input in-question is pressed (keyDown in this case), the game looks at your input button (the keycode) and sends it through the switch statement.
Keep in mind that you must return true for all the input events that you want to use. That's what the boolean return value for this method is.
Related
I'm using Scene2D and have 2 actors. When MyActor1 is touched, it should fire an event which should be handled by MyActor2. I've tried several different variants on how to fire and even from MyActor1, but it is still not being handled by MyActor2. The full code is below.
Game class which just forwards to a Screen
public class MyGdxGame extends Game {
#Override
public void create() {
setScreen(new MyGdxScreen());
}
}
Screen class (empty methods ommited)
public class MyGdxScreen implements Screen {
private Stage stage;
#Override
public void show() {
stage = new Stage(new ScreenViewport());
stage.addActor(new MyActor1());
stage.addActor(new MyActor2());
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta);
stage.draw();
}
#Override
public void dispose() {
stage.dispose();
}
}
First Actor (fires custom event when touched)
public class MyActor1 extends Actor {
private Texture image;
public MyActor1() {
this.image = new Texture("badlogic.jpg");
setPosition(0, 0);
setBounds(0, 0, image.getWidth(), image.getHeight());
setTouchable(Touchable.enabled);
addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("touched", "First actor touched!");
MyActor1.this.fire(new ActorTouchedListener.ActorTouchedEvent());
MyActor1.this.getParent().fire(new ActorTouchedListener.ActorTouchedEvent());
return true;
}
});
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(image, 0, 0, image.getWidth(), image.getHeight());
}
}
Second Actor (should handle an Event fired by Actor1)
public class MyActor2 extends Actor {
public MyActor2() {
addListener(new ActorTouchedListener());
}
}
Event listener
public class ActorTouchedListener implements EventListener {
#Override
public boolean handle(Event event) {
if (event instanceof ActorTouchedEvent) {
Gdx.app.log("fired", "Second actor got event!");
return true;
}
return false;
}
public static class ActorTouchedEvent extends Event {
public ActorTouchedEvent() {
}
}
}
These two lines do nothing.
MyActor1.this.fire(new ActorTouchedListener.ActorTouchedEvent());
MyActor1.this.getParent().fire(new ActorTouchedListener.ActorTouchedEvent());
To call Actor from another Actor you should create instance of it.
public class MyActor1 extends Actor {
private Texture image;
private Actor actor2; // instance of MyActor2
public MyActor1(actor2: Actor) {
this.image = new Texture("badlogic.jpg");
this.actor2 = actor2;
setPosition(0, 0);
setBounds(0, 0, image.getWidth(), image.getHeight());
setTouchable(Touchable.enabled);
addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log("touched", "First actor touched!");
actor2.fire(event); // Here we fire event on MyActor2
return true;
}
});
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(image, 0, 0, image.getWidth(), image.getHeight());
}
}
Intercomponent events
LibGDX does not provide embeded intercomponent event system, but you can use additional frameworks. For example LibGDX Autumn. You can use two type events:
text event - to notify components about changing of some state
object event - this mechanism deliver your event object to observers
This framework have documentaion and examples, it will help to do what you want
Delayed actor update
For actor's update purposes LibGDX have actions mechanism. In your case I suggest to attach DelayAction to MyActor2 with wrapped MyRedrawAction
DelayAction delayAction = new DelayAction();
// set wrapped action dellay (in sec.)
delayAction.setDuration(1F);
// set wrapped action. It will be invoked after 1 sec. of stage drawing
delayAction.setAction(new MyRedrawAction());
actor2.addAction(delayAction);
You can do this in touchDown() method as #icarumbas suggest
I am a newbie in libgdx and I have a little problem with screens and main menu.
I have a mainmenu class and it work with click on actors. The code for click is:
pulsanteplay.addListener(
new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, `float y, int pointer, int button) {
System.out.println("click play");
game.setScreen(new GameClass());
return false;
}
});
and it works. If I call Gdx.app.exit(); it works. If I call the next class, works
public class SplashScreen implements Screen {
private SpriteBatch batch;
private Texture ttrSplash;
private Timer timer;
private MainMenu mainMenuScreen;
public SplashScreen() {
super();
batch = new SpriteBatch();
ttrSplash = new Texture("quadrato.png");
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(ttrSplash, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.end();
}
#Override
public void hide() { }
#Override
public void pause() { }
#Override
public void resume() { }
#Override
public void show() { }
#Override
public void resize(int width, int height) { }
#Override
public void dispose() {
ttrSplash.dispose();
batch.dispose();
}
When I call a class that extends game and have a render method don't work. The screen don't change but the events of the game class are really generated.
Someone could explain me why this? How do I fix this bad behavior?
Thanks for your attention
Have that class that extends Game just implement Screen and put your code in it's corresponding methods. A screen offers everything a Game does so you should have no trouble converting. your onCreate code can be put in the show method or the constructor of your new Screen class. Now just call setScreen() to show this screen.
So, this is too hard for me to explain this in short, so the title looks so creepy. Well, I am writing a small android application and i have like three screens: the main-menu one, and two in-game screens. I can switch between the last two ones with a switch button. The problem is, that when i switch back to the last screen I've been to, all its acting stuff starts again from the very beginning. I have also seen a similar question here, but i did not work for me(( So, is there any way to keep the screen rendering, while I am using the other one?
Thank you!
The first screen:
public class InGameScreen implements Screen {
TinyBattles game;
public static OrthographicCamera camera;
public static Button switchButton1;
public InGameScreen(TinyBattles game) {
this.game = game;
}
#Override
public void show() {
camera = new OrthographicCamera(Global.VIEWPORT_WIDTH, Global.VIEWPORT_WIDTH*Global.actualHeight/Global.actualWidth);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
switchButton1 = new Button();
switchButton1.create(10, 800, 150, 150);
Assets.loadSwitchButton();
}
#Override
public void render(float delta) {
Global.cleanScreen();
touchHandler(camera, Global.touch);
switchButton1.act();
switchButton1.render(Assets.buttonSwitchStateUpSprite, Assets.buttonSwitchStateDownSprite);
Global.debugRender();
localDebugRender();
leaveScreen();
Global.batch.getProjectionMatrix().setToOrtho2D(0, 0, Global.actualWidth, Global.actualHeight);
Global.batch.setProjectionMatrix(camera.combined);
Global.shapeRenderer.setProjectionMatrix(camera.combined);
}
public void localDebugRender(){
switchButton1.debugRender();
}
public void touchHandler(OrthographicCamera camera, Vector3 touch){
if (Gdx.input.isTouched()){
touch.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touch);
Global.finger.bounds.x = touch.x - 64;
Global.finger.bounds.y = touch.y - 64;
}else{
Global.finger.bounds.x = 10000;
Global.finger.bounds.y = 10000;
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
public void leaveScreen(){
if (switchButton1.isPressed == true){
game.setScreen(TinyBattles.inGameVirtualScreen);
}
}
}
The second screen:
public class InGameVirtualScreen implements Screen {
TinyBattles game;
public static World world;
public static OrthographicCamera camera;
public static Button switchButton2;
public static Balls balls;
public InGameVirtualScreen(TinyBattles game) {
this.game = game;
}
#Override
public void show() {
world = new World(new Vector2(0, 0), true);
camera = new OrthographicCamera(Global.VIEWPORT_WIDTH, Global.VIEWPORT_WIDTH*Global.actualHeight/Global.actualWidth);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
camera.update();
switchButton2 = new Button();
switchButton2.create(10, 800, 150, 150);
balls = new Balls();
Assets.loadBallSprites();
balls.create();
balls.setup();
}
#Override
public void render(float delta) {
Global.tweenManager.update(1 / 60f);
Global.cleanScreen();
world.step(1 / 60f, 10, 10);
touchHandler(camera, Global.touch);
switchButton2.act();
balls.act();
renderLayerOne();
renderInterfaceLayer();
renderDebugLayer();
leaveScreen();
Global.batch.getProjectionMatrix().setToOrtho2D(0, 0, Global.actualWidth, Global.actualHeight);
Global.batch.setProjectionMatrix(camera.combined);
Global.shapeRenderer.setProjectionMatrix(camera.combined);
}
public void renderLayerOne(){
balls.render();
}
public void renderInterfaceLayer(){
switchButton2.render(Assets.buttonSwitchStateUpSprite, Assets.buttonSwitchStateDownSprite);
}
public void renderDebugLayer(){
Global.debugRender();
localDebugRender();
}
public void localDebugRender(){
switchButton2.debugRender();
}
public void touchHandler(OrthographicCamera camera, Vector3 touch){
if (Gdx.input.isTouched()){
touch.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touch);
Global.finger.bounds.x = touch.x - 64;
Global.finger.bounds.y = touch.y - 64;
}else{
Global.finger.bounds.x = 10000;
Global.finger.bounds.y = 10000;
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
public void leaveScreen(){
if (switchButton2.isPressed){
game.setScreen(TinyBattles.inGameScreen);
}
}
}
There is a leaveScreen() method at the bottom of the each class
You should move all your code in each screen from show() to the constructor. show() is called every time the screen becomes the active screen, so you don't want to do initialization there.
By the way, you should never keep static references to anything that implements Disposable, such as SpriteBatch, or anything that keeps a reference to something that implements Disposable, such as Button or Stage. If you do, when the user backs out of your game activity and reopens it, there will be memory leaks and incorrect textures, etc.
Its been a while since I used libgdx, but it seems you are creating a new screen on each leaveScreen function.
See here for a better approach, where when you create the Game class you create the screens as well:
public class MyGame extends Game {
MainMenuScreen mainMenuScreen;
AnotherScreen anotherScreen;
#Override
public void create() {
mainMenuScreen = new MainMenuScreen(this);
anotherScreen = new AnotherScreen(this);
setScreen(mainMenuScreen);
}
}
Then, you change the screens like this:
public void leaveScreen(){
if (switchButton2.isPressed){
game.setScreen(game.anotherScreen);
}
}
As I said it's been a while, but give it a shot :)
I am using the Libgdx framework along with Spine to do Skeleton animation using Atlas and exported Json file. In the file there are many animations. I am able to load animations from the json file. But there are 2 issues :
Lag when animation starts : there is a lag of 3-4 seconds before the animation starts. I see a black screen and then the animation works.
Delta - i have some issues with the delta time. Only some animations are running from the default delta value, however if i change ( increment or decrease the delta value), different animations give different results.
Cant understand what to do ? I have searched thoroughly in the internet but haven't found the solution.
I am posting my code below:
This is my Main Class
public class AndroidLauncher extends AndroidApplication
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
View spine_view;
private Screen curScreen; // the current screen
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
//initialize(new Main(20), config);
spine_view=initializeForView(new ApplicationListener()
{
#Override
public void resume()
{
curScreen.resume();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void render()
{
curScreen.render((Gdx.graphics.getDeltaTime()/(1.5f))); //call the rendermethod with the delta time as parameter
}
#Override
public void pause()
{
curScreen.pause();
}
#Override
public void dispose()
{
curScreen.dispose();
}
#Override
public void create()
{
Gdx.graphics.getWidth();
Gdx.graphics.getHeight();
Firstscreen temp = new Firstscreen();//just an example of the first screen to load up
setScreen(temp);
}
}, config);
LinearLayout l1 = (LinearLayout) findViewById(R.id.container);
l1.addView(spine_view);
}
public void setScreen(Screen s) {
if (curScreen != null) {
curScreen.hide();
curScreen.dispose();
}
curScreen = s;
curScreen.show();
}
}
...............................................
And this is the screen Iam rendering
public class Firstscreen implements Screen
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
int count =0;
#Override
public void render(float delta)
{
// track
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
time += delta;
animation.apply(skeleton,delta,time, false, null);
SkeletonRenderer render = new SkeletonRenderer();
batch.begin();
render.draw(batch, skeleton);
skeleton.updateWorldTransform();
batch.end();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void show()
{
batch = new SpriteBatch();
renderer = new ShapeRenderer();
atlas = new TextureAtlas(Gdx.files.internal("abc.atlas"));
SkeletonJson json = new SkeletonJson(atlas);
// set the scale of skeleton
json.setScale(0.3f);
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("skeleton.json"));
skeleton = new Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.setSkin("Carla");
// set the position of the skeleton to render( here middle)
skeleton.setPosition((Gdx.graphics.getWidth()/2)-(x/2),( Gdx.graphics.getHeight()/2)-(y/2));
//animation = skeletonData.findAnimation("KID-LEVEL 2 - Couch potato");
animation = skeletonData.findAnimation("LEVEL 91- Around a world");
//animation = skeletonData.findAnimation("KID-LEVEL 7 - Super Hero");
}
#Override
public void hide()
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
#Override
public void dispose()
{
batch.dispose();
}
}
That's happens beacuse you are managing a timeline manually.
Use AnimationState instead:
Skeleton skeleton = new Skeleton(skeletonData);
// sctruct for mix animations
AnimationStateData stateData = new AnimationStateData(skeletonData);
// and state
AnimationState state = new AnimationState(stateData);
In some update method (or render, if you prefer update while rendering) call something like this:
state.update(delta);
And in the actual render method:
// apply the state to skeleton
state.apply(skeleton);
// update transformations
skeleton.updateWorldTransform();
// draw then
render.draw(batch, skeleton);
So, AnimationState isn't designed not for managing the delta only, you can play&mix animations using it:
state.setAnimation(0, "LEVEL 91- Around a world", isLoop);
To change animation speed use setTimeScale:
state.setTimeScale(0.5f); // set any time scale you want
Also, you may have some perfomance issues because you calling new SkeletonRenderer() in render method. To fix that, move this code to constructor.
I'm trying to scale my Actor using actions.
But it does not work. I just want my actor to increase/decrease its size over a given time.
The Actor will just wait for the 2 seconds duration I have given the ScaleTo. It correctly moves based on the MoveTo action I gave it.
public class SpriteTest extends Actor {
private Sprite sprite;
private TextureAtlas atlas;
Rectangle boundsd = new Rectangle();
public SpriteTest(FirstGame game) {
//super(game);
Gdx.app.log( FirstGame.LOG, "spritetest's costructor" );
atlas = new TextureAtlas(Gdx.files.internal("pages-info.atlas"));
sprite = atlas.createSprite("Plus");
}
public void draw(SpriteBatch batch,float parentAlpha) {
batch.draw(sprite, x, y);
}
// We are adding the actor to the stage in another class
public class LevelScreen extends AbstractScreen {
private Jumper2D jumper2d;
SpriteTest obstacled = new SpriteTest(game);
public LevelScreen(FirstGame game) {
super(game);
}
#Override
protected boolean isGameScreen() {
return true;
}
#Override
public void show() {
super.show();
stage.addActor(obstacled);
obstacled.action
(Forever.$
(Sequence.$
(ScaleTo.$(1.4f, 1.4f, 2),(MoveTo.$(100,120, 3f) ))
));
jumper2d = Jumper2D.create(getAtlas());
stage.addActor(jumper2d);
stage.draw();
}
public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
stage.draw();
}
}
Any help is appreciated
Your draw() method for SpriteTest is ignoring any scale or rotation settings on the Actor. You need to draw the sprite scaled/rotated/sized appropriately. (You may also need to set the Actor's x, y, width, and height --- see
setBounds)
public void draw(SpriteBatch batch, float parentAlpha)
{
final Color c = getColor();
batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);
batch.draw(sprite, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
}