Libgdx - touchDown/touchUp vs. Gdx.input.isKeyPressed/Gdx.input.isKeyJustPressed - java

Here is my dilemma. I am having problems animating my lightning attack by using my GamePad class (I made this class for a game controller for android devices).
I found out that if using the Gdx.input.isKeyPressed(keyname), the code produces a lightning attack every frame, which stack on top of each other. So, I then used the Gdx.input.isKeyJustPressed() and it only creates one attack, that is animated, which is perfect.
So when making the GamePad class, I made images with listeners to handle touch events. For each button I have a touchDown and touchUp method. When running my character from left to right, these touch events work fine. However, similar to Gdx.input.isKeyPressed(), the lightning attack is created each frame and the attacks get layered on top of each other. I tried a workaround to fix the creation of an attack each frame, and now the image is just static, and does not animate. This is better than the 60 fps, but doesn't solve my problem.
is there a touchDown event similar to Gdx.input.isKeyJustPressed()? How could I fix the GamePad class to work similarly to the Config class?
GamePad.java
public class GamePad implements Disposable{
private Viewport viewport;
public Stage stage;
boolean leftPressed, rightPressed, pausePressed, aPressed, bReleased, bPressed, bPreviouslyPressed;
private Config config = Config.getInstance();
private Table table;
public GamePad(){
viewport = new FitViewport(EIUGame.V_WIDTH, EIUGame.V_HEIGHT, new OrthographicCamera());
stage = new Stage(viewport);
table = new Table();
table.setFillParent(true);
table.bottom();
bPreviouslyPressed = false;
// "Left" Button
Image leftImg = new Image(new Texture("controller/leftButton.png"));
leftImg.setSize(35, 35);
leftImg.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
leftPressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
leftPressed = false;
}
});
// "Right" Button
Image rightImg = new Image(new Texture("controller/rightButton.png"));
rightImg.setSize(35, 35);
rightImg.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
rightPressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
rightPressed = false;
}
});
// "Pause" Button
Image pauseImg = new Image(new Texture("controller/pauseButton.png"));
pauseImg.setSize(15, 15);
pauseImg.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
pausePressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
pausePressed = false;
}
});
// "A" Button
Image aImg = new Image(new Texture("controller/aButton.png"));
aImg.setSize(35, 35);
aImg.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
aPressed = true;
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
aPressed = false;
}
});
// "B" Button
Image bImg = new Image(new Texture("controller/bButton.png"));
bImg.setSize(35, 35);
bImg.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
bPressed = true;
setBReleased(false);
return true;
}
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
setBReleased(true);
bPreviouslyPressed = false;
bPressed = false;
}
});
table.add(leftImg).size(leftImg.getWidth(), leftImg.getHeight());
table.add().size(5,35);
table.add(rightImg).size(rightImg.getWidth(), rightImg.getHeight());
table.add().size(100, 35);
table.add(pauseImg).size(pauseImg.getWidth(), pauseImg.getHeight()).bottom();
table.add().size(100, 35);
table.add(bImg).size(bImg.getWidth(), bImg.getHeight());
table.add().size(5,35);
table.add(aImg).size(aImg.getWidth(), aImg.getHeight());
stage.addActor(table);
}
// Returns the stage object so that it can be added to a multiplexer
public Stage getStage() {
return stage;
}
public void draw(){
stage.draw();
}
public boolean isLeftPressed(){
return leftPressed;
}
public boolean isRightPressed(){
return rightPressed;
}
public boolean isPausePressed(){
return pausePressed;
}
public boolean isAPressed(){
return aPressed;
}
public boolean isBPressed(){
return bPressed;
}
public boolean isBPreviouslyPressed(){
return bPreviouslyPressed;
}
public boolean isBReleased(){
return bReleased;
}
public void setBReleased(boolean released){
bReleased = released;
}
public void resize(int width, int height){
viewport.update(width, height);
}
public void animateChamp(Champion champ, PauseState pause){
// Move Champion Right
if (isRightPressed() && champ.b2body.getLinearVelocity().x <= 2)
config.runRight(champ);
// Move Champion left
if (isLeftPressed() && champ.b2body.getLinearVelocity().x >= -2)
config.runLeft(champ);
// If A button is pressed and we are not jumping or falling, then Jump.
if (isAPressed() && (champ.getState() != champState.JUMPING && champ.getState() != champState.FALLING)){
config.jump(champ);
aPressed = false;
}
// Toggle Pause Menu
if (isPausePressed())
pause.togglePause();
// Precondition for next else-if statement
if (isBPressed() && champ.b2body.getLinearVelocity().x == 0 && champ.b2body.getLinearVelocity().y == 0){
bPressed = false;
bPreviouslyPressed = true;
}
// If b was pressed down but not released, and champion is not moving, use lightning attack
else if (bPreviouslyPressed && !isBReleased() && champ.b2body.getLinearVelocity().x == 0 && champ.b2body.getLinearVelocity().y == 0){
champ.setMobileTrigger(true); // Sets champion state to attacking region
config.setMLightningActive(true);
config.lightningAttack(champ);
}
// Exit lightning attack if moved
else if (!isBReleased() && (champ.b2body.getLinearVelocity().x != 0 || champ.b2body.getLinearVelocity().y != 0)){
champ.setMobileTrigger(false);
config.setMLightningActive(false);
bReleased = true;
}
// Exit lightning attack if button released
else if (isBReleased() && config.getMLightningActive()){
champ.setMobileTrigger(false); // Does not alter champion state
config.setMLightningActive(false);
bReleased = true;
}
// Attack when moving
else if (isBPressed()){
config.attack(champ);
bPressed = false;
}
}
#Override
public void dispose(){
stage.dispose();
}
}
Config.java
public final class Config {
private static final Config instance = new Config();
private int moveLeft;
private int moveRight;
private int jump;
private int attack;
private String lStr;
private String rStr;
private String jStr;
private String aStr;
private boolean lightningActive = false;
private boolean MlightningActive = false; // Mobile Game
// Default constructor sets the keys to a default schema
private Config() {
moveLeft = Input.Keys.A;
moveRight = Input.Keys.D;
jump = Input.Keys.L;
attack = Input.Keys.J;
lStr = "A";
rStr = "D";
jStr = "L";
aStr = "J";
}
// Return the instance of the class
public static Config getInstance() {
return instance;
}
public void animateChamp(Champion champ){
// Jump!
if(Gdx.input.isKeyJustPressed(jump) && (champ.getState() != champState.JUMPING && champ.getState() != champState.FALLING))
jump(champ);
// Run Right (and make sure character is not moving faster than 2)
if(Gdx.input.isKeyPressed(moveRight) && champ.b2body.getLinearVelocity().x <= 2)
runRight(champ);
// Run Left (and make sure character is not moving faster than 2)
if(Gdx.input.isKeyPressed(moveLeft) && champ.b2body.getLinearVelocity().x >= -2)
runLeft(champ);
// Lightning Attack
if(Gdx.input.isKeyJustPressed(attack) && champ.b2body.getLinearVelocity().x == 0 && champ.b2body.getLinearVelocity().y == 0){
setLightningActive(true);
lightningAttack(champ);
}
else if (getlightningActive() && (champ.b2body.getLinearVelocity().x != 0 || champ.b2body.getLinearVelocity().y != 0 || !Gdx.input.isKeyPressed(attack)))
setLightningActive(false);
else if (Gdx.input.isKeyJustPressed(attack))
attack(champ);
}
public void runRight(Champion champ){
champ.b2body.applyLinearImpulse(new Vector2(0.1f,0), champ.b2body.getWorldCenter(), true);
}
public void runLeft(Champion champ){
champ.b2body.applyLinearImpulse(new Vector2(-0.1f,0), champ.b2body.getWorldCenter(), true);
}
public void jump(Champion champ){
champ.b2body.applyLinearImpulse(new Vector2(0, 4.5f), champ.b2body.getWorldCenter(), true);
}
public void attack(Champion champ){
champ.attack();
}
public void lightningAttack(Champion champ){
champ.lightningAttack();
}
public boolean getlightningActive(){
return lightningActive;
}
public void setLightningActive(boolean value){
lightningActive = value;
}
// For Mobile Version
public boolean getMLightningActive(){
return MlightningActive;
}
// For Mobile Version
public void setMLightningActive(boolean value){
MlightningActive = value;
}
// sets the key to move left
public void setMoveLeft(String n){
moveLeft = Input.Keys.valueOf(n.toUpperCase());
lStr = n;
}
// sets the key to move right
public void setMoveRight(String n) {
moveRight = Input.Keys.valueOf(n.toUpperCase());
rStr = n;
}
// sets the key to jump
public void setJump(String n) {
jump = Input.Keys.valueOf(n.toUpperCase());
jStr = n;
}
// sets the key to attack
public void setAttack(String n) {
attack = Input.Keys.valueOf(n.toUpperCase());
aStr = n;
}
// Returns the string representation of the move left key
public String getMoveLeft(){
return lStr;
}
// Returns the string representation of the move right key
public String getMoveRight() {
return rStr;
}
// Returns the string representation of the jump key
public String getJump() {
return jStr;
}
// Returns the string representation of the attack key
public String getAttack() {
return aStr;
}
// Returns the int representation of the attack key
public int getAttackInt(){
return attack;
}
}

If I might suggest an alternative approach, it sounds like what you really want is to apply a cooldown to your lightning attack- a cooldown keeps it from firing repeatedly if the player holds the button down, and it gives you some control over how fast the player can fire it if they pound the keyboard (you may want to let the player "upgrade" their lightning attack to something faster in the future).
I threw together an example below:
public class Cooldown {
private float cooldownTime = 0;
private float length = 0;
private Action action;
public Cooldown(float length, Action action) {
this.length = length;
this.action = action;
}
public boolean update(float delta) {
// Subtract the delta until we hit 0
this.cooldownTime = this.cooldownTime - delta <= 0 ? 0 : this.cooldownTime - delta;
// The boolean tells you that the cooldown has expired- useful for special effects
return this.cooldownTime == 0;
}
public void execute() {
if(this.cooldownTime > 0) return;
this.cooldownTime = this.length;
this.action.execute();
}
public interface Action {
void execute();
}
}
To use this class, simply add something like the following somewhere under your player's constructor:
this.lighteningAttack = new Cooldown(0.25f, new LightningAttack());
Then in your gameloop somewhere:
this.lighteningAttack.update(deltaTime);
Finally, in your eventlistener:
this.lighteningAttack.execute();
No matter how many times you press the button, it should only execute four times a second.

Related

Libgdx Input don't working on Android

I'm new in Libgdx and I'm trying to make a map that can be explored using Camera. Fo that I implements GestureListener in my own Map class.
public class Map extends Stage implements GestureListener {
public String mapName;
private Sprite background;
public LocationPoint points[];
private OrthographicCamera camera;
private Batch batch;
public Music anbientSound;
public int numOfPoints;
public int locationsX[];
public int locationsY[];
public Map(Sprite background) {
this.background = background;
}
public Sprite getBackground() {
return background;
}
public void activate() {
InputMultiplexer inputChain = new InputMultiplexer();
if(points==null) {
points = new LocationPoint[numOfPoints];
for(int i = 0; i < numOfPoints; i++) {
points[i] = new LocationPoint(locationsX[i], locationsY[i]);
addActor(points[i]);
}
}
batch = GameUtils.batch;
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(camera.viewportWidth/2, camera.viewportHeight/2, 0);
camera.update();
Music music = GameUtils.addMusic(anbientSound);
music.setLooping(true);
music.play();
inputChain.addProcessor(this);
inputChain.addProcessor(new GestureDetector(this));
Gdx.input.setInputProcessor(inputChain);
}
public void draw() {
Gdx.gl20.glClearColor(0, 0, 0, 1);
Gdx.gl20.glClear(Gdx.gl20.GL_COLOR_BUFFER_BIT);
Batch batch = this.batch;
batch.setProjectionMatrix(camera.combined);
batch.begin();
background.draw(batch);
batch.end();
batch.begin();
for(int i = 0; i < numOfPoints; i++) {
points[i].draw(batch, 1);
addActor(points[i]);
}
batch.end();
}
public void dispose() {
GameUtils.stopMusic();
background.getTexture().dispose();
anbientSound.dispose();
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
camera.translate(-deltaX, deltaY);
float initialX = camera.viewportWidth / 2;
float initialY = camera.viewportHeight / 2;
GameUtils.limitBound(camera, initialX, initialY, background.getWidth(), background.getHeight());
camera.update();
return true;
}
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2,
Vector2 pointer1, Vector2 pointer2) {
return false;
}
#Override
public void pinchStop() {}
}
The method activate() is used to activate the resources of the Map class. The class Map also have a ImageButtons called LocationPoints.
public class LocationPoint extends ImageButton {
private Monster monster;
private Trap trap;
public boolean occuped;
public boolean isTrap;
public int f = 20;
public int k = 20;
public LocationPoint(float x, float y) {
super(GameUtils.getLocationDrawable());
this.setSize(46, 46);
setPosition(x, y);
addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
setPosition(f, k);
f += 10;
k += 10;
return super.touchDown(event, x, y, pointer, button);
}
});
}
public void occup(Monster monster) {
this.monster = monster;
occuped = true;
if(isTrap)
captured();
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
}
public void empty() {
monster = null;
occuped = false;
}
public void captured() {
monster.capture();
}
public Monster getMonster() {
return monster;
}
}
In LocationPoint class I add a InputListener to make a thing when that LocationPoint is touched.
When a play the game on android both LocationPoints event and the Map pan event. But after I move the camera, when I touch on LocationPoint it don't fires that point event.
But when I return the camera to initial position the LocationPoints events works fine! Can you help me? (And sorry for my broken english...)
Actor is already a child so remove redundant call from draw() method.
for(int i = 0; i < numOfPoints; i++) {
points[i].draw(batch, 1);
addActor(points[i]); // <-- Not Should be in draw() call
}
Stage having own SpriteBatch that created by default constructor, use that one or pass own batch in Stage constructor.
Use getBatch() method of Stage if you want to draw something by yourself.
Creating camera in Map class also redundant, use getViewport().getCamera() that return camera of stage, you can typecast to OrthographicCamera
call super.dispose(); inside your dispose() method
Drawing all your Actor by yourself ? If you're not doing something beyond the scope, no need to override draw() method of Stage.

jump() gets called but doesn't make the sprite actually jump (only 1 line in the method) - android game development

What the title says basically.
The jump worked perfectly until I decided to make my game more object-oriented by adding a GameObject class. The sprite should jump whenever you tap the screen (added a print statement in jump() to verify that this method DOES get called). Can anyone spot the mistake?
The way I've coded the jump:
player is constantly decelerating until he reaches the ground
if the screen is tapped, the players ySpeed is increased by accelerationJump, then decreased slowly by g while he's in the air
Player:
public class Player extends GameObject implements InputProcessor {
private float g;
private float accelerationJump = 9f;
private boolean allowJump = true;
public Player(Sprite spr) {
super(spr);
setxPos(0);
setyPos(getHeight() / 6);
setxSpeed(5.5f);
setySpeed(0);
spr.setX(getxPos());
spr.setY(getyPos());
g = 0.2f;
accelerationX = 0.02f;
}
public void update() {
setySpeed(-g);
//have the sprite constantly moving
moveBy(getxSpeed(), getySpeed());
//if sprite reaches end of screen, move it to the start of the screen again
if (getxPos() > getWidth()) {
setxPos(0);
}
if (getyPos() < getHeight() / 6) {
moveTo(getSprite().getX(), getHeight() / 6);
}
//the player can only jump if he is on the ground. once player is on the ground, he must stop decelerating
if (onGround()) {
allowJump = true;
setySpeed(0);
}
}
public void jump() {
System.out.println("dasdasddadsdasd");
setySpeed(getySpeed() + accelerationJump);
}
// checks whether or not player is on the ground
public boolean onGround() {
return (getSprite().getY() == getHeight() / 6);
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
//if (allowJump && isDragged == false) {
//System.out.println("dsdasdasd");
if(allowJump){
allowJump = false;
jump();
}
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
/*if (isDragged == false) {
isDragged = true;
}*/
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
GameObject
public abstract class GameObject {
private Sprite spr;
private float xSpeed;
private float ySpeed;
public GameObject(Sprite spr) {
this.spr=spr;
}
public void moveTo(float xPos2, float yPos2) {
setxPos(xPos2);
setyPos(yPos2);
}
public void moveBy(float dx, float dy) {
spr.setY(spr.getY() + dy);
spr.setX(spr.getX() + dx);
}
public float getxPos() {
return spr.getX();
}
public float getyPos() {
return spr.getY();
}
public void setxPos(float xPos2) {
spr.setX(xPos2);
}
public void setyPos(float yPos) {
spr.setY(yPos);
}
public float getxSpeed() {
return xSpeed;
}
public float getySpeed() {
return ySpeed;
}
public void setxSpeed(float xSpeed2) {
xSpeed = xSpeed2;
}
public void setySpeed(float ySpeed2) {
ySpeed = ySpeed2;
}
public int getWidth() {
return Gdx.graphics.getWidth();
}
public int getHeight() {
return Gdx.graphics.getHeight();
}
public void draw(SpriteBatch batch) {
spr.draw(batch);
}
public Sprite getSprite() {
return spr;
}
}
Any help is HIGHLY appreciated.
You are setting ySpeed to -g every update()

Rotate effect adding image group (libgdx)

public void FillTableValueGrid(int[] Arr)
{
grp = new Group();
grp.setHeight(AssetsHelper.convertHeight(4*187));
grp.setWidth(AssetsHelper.convertWidth(124));
grp.setPosition(680, AssetsHelper.convertHeight(180));
for(int i=0;i<Arr.length;i++)
{
ActualPieceArray[i]=ImagesPieceArray2[set1Array[i]];
ImagesAnswerArray[Arr[i]].setVisible(false);
ActualIntArray[i]=Arr[i];
}
ActualPieceArray[0].setPosition(AssetsHelper.convertWidth(0), AssetsHelper.convertHeight(100));
grp.addActor(ActualPieceArray[0]);
for(int i=1;i<9;i++)
{
ActualPieceArray[i].setPosition(AssetsHelper.convertWidth(0), ActualPieceArray[i-1].getY()- ActualPieceArray[i-1].getHeight());
grp.addActor(ActualPieceArray[i]);
//System.out.println("trace herer :::"+ grp.getY());
}
stage.addActor(grp);
Mask=new Image(AssetsHelper.Mask);
Mask.setPosition(AssetsHelper.convertWidth(656/2),AssetsHelper.convertHeight((552)/2));
Mask1=new Image(AssetsHelper.Mask1);
Mask1.setPosition(AssetsHelper.convertWidth(656/2),0);
stage.addActor(Mask);
stage.addActor(Mask1);
ArrowUper = new Image(AssetsHelper.ArrowUp);
ArrowUper.setPosition(AssetsHelper.convertWidth(368),AssetsHelper.convertHeight(280));
stage.addActor(ArrowUper);
//ImageCliked(ArrowUper);
ArrowDowner = new Image(AssetsHelper.ArrowDown);
ArrowDowner.setPosition(AssetsHelper.convertWidth(368),AssetsHelper.convertHeight(14));
stage.addActor(ArrowDowner);
ImageCliked1(ArrowDowner);
ImageCliked(ArrowUper);
}
public void ImageCliked(Actor actor)
{
actor.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
grp.addAction(Actions.sequence(
Actions.fadeOut(0),
Actions.parallel(
Actions.fadeIn(1.0f),
Actions.moveTo(grp.getX(), grp.getY()+AssetsHelper.convertHeight(100/2)))));
Counter--;
EnableAndDisable(Counter);
System.out.println("Please ImageClikedS Counter grp.getY() :::"+Counter+ grp.getY());
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
// return false;
}
});
}
Added a brief code,where FillTableValueGrid is used to add the images and imageclicked used for moving up/down.I am new to java libgdx;i want rotating effect of that group,when i clicked down button after last image;first image should come.Can anyone help to resolve .

libgdx how to zoom & rotate 3d model on touch

I am trying to create a simple app which allows you to load 3d model from .obj and zoom/rotate it by touching the screen.
I managed to write code which loads 3d model from file and detect gestures but now I am not sure what to do to enable zoom/rotate features by touching the screen.
Here is my code for now:
public class RenderObjApp implements ApplicationListener, GestureDetector.GestureListener {
public static int SCREEN_WIDTH = 800;
public static int SCREEN_HEIGHT = 600;
private static final String TAG = RenderObjApp.class.getSimpleName();
private Mesh model;
private PerspectiveCamera camera;
private float scale = 1f;
#Override
public void create() {
model = ObjLoader.loadObj(Gdx.files.internal("data/cessna.obj").read(), true);
Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
Gdx.input.setInputProcessor(new GestureDetector(this));
}
#Override
public void dispose() {
}
#Override
public void pause() {
}
#Override
public void render() {
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
camera.update();
camera.apply(Gdx.gl10);
model.render(GL10.GL_TRIANGLES);
}
#Override
public void resize(int arg0, int arg1) {
float aspectRatio = (float) arg0 / (float) arg1;
camera = new PerspectiveCamera(75, 2f * aspectRatio, 2f);
camera.near = 0.1f;
camera.translate(0, 0, 0);
}
#Override
public void resume() {
}
#Override
public boolean touchDown(float x, float y, int pointer) {
Gdx.app.log(TAG, "touchDown: ");
return false;
}
#Override
public boolean tap(float x, float y, int count, int pointer, int button) {
Gdx.app.log(TAG, "tap: ");
return false;
}
#Override
public boolean longPress(float x, float y) {
Gdx.app.log(TAG, "zoom: ");
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int pointer, int button) {
Gdx.app.log(TAG, "fling: ");
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
Gdx.app.log(TAG, "pan: ");
return false;
}
#Override
public boolean zoom(float initialDistance, float distance) {
Gdx.app.log(TAG, "zoom: initialDistance=" + initialDistance + ", distance=" + distance);
return false;
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
Gdx.app.log(TAG, "pinch: ");
return false;
}
}
So I am looking how to rotate the PerspectiveCamera and Mesh itself.
I have been working on a "Blender-style" camera that has pinch-to-zoom capability as well as (on desktop) most of the functionality you get with Blender's camera. It is a work in progress — it doesn't perfectly imitate the behavior of Blender's camera (yet). I think this will get you pointed in the right direction. Some things you should know:
You may have to translate your model so it sits on the origin. The camera remains pointed at the origin unless you translate it. (You can only translate on desktop and not on android so far);
I got most of the pinch-to-zoom handling code here: https://code.google.com/p/libgdx-users/wiki/PinchToZoom.
Sorry for the magic numbers. I will make those constants in the future.
If you or anyone else improves this code, I would love if you shared a copy with me.
The Abstract class:
/* Author: Christopher Grabowski, yourchristopher6334 gmail.com */
package ...;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.input.GestureDetector.GestureListener;
import com.badlogic.gdx.math.Vector2;
abstract public class ControllableCamera extends PerspectiveCamera implements InputProcessor{
abstract public void resize(int width, int height);
abstract public void render();
public ControllableCamera(int fieldOfView, int width, int height) {
super(fieldOfView, width, height);
}
#Override
public boolean keyDown(int keyCode) {
return false;
}
#Override
public boolean keyTyped(char arg0) {
return false;
}
#Override
public boolean keyUp(int arg0) {
return false;
}
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean touchUp(int x, int y, int pointer, int button) {
return false;
}
#Override
public boolean mouseMoved(int arg0, int arg1) {
return false;
}
#Override
public boolean scrolled(int direction) {
return false;
}
}
The concrete class:
/* Author: Christopher Grabowski, yourchristopher6334 gmail.com */
package ...;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.math.Vector3;
/*
* the pause, resize, and render methods must be called within their corresponding
* methods in the ApplicationListener
*/
public class BlenderStyleCamera extends ControllableCamera {
public static final Vector3 ORIGIN = new Vector3(0, 0, 0);
private static boolean shiftIsPressed = false, controlIsPressed = false,
isScrollingUp = false, isScrollingDown = false,
isSingleTouched = false, justSingleTouched = false;
private float aspectRatio;
private int x = -1, y = -1;
private float dx = 0.0f, dy = 0.0f;
private final Vector3 tmp = new Vector3();
// fields related to pinch-to-zoom
private int numberOfFingers = 0;
private int fingerOnePointer;
private int fingerTwoPointer;
private float lastDistance = 0;
private final Vector3 fingerOne = new Vector3();
private final Vector3 fingerTwo = new Vector3();
public BlenderStyleCamera(int fieldOfView, int width, int height) {
super(fieldOfView, width, height);
aspectRatio = viewportHeight / viewportWidth;
Gdx.input.setInputProcessor(this);
up.set(0.0f, 1.0f, 0.0f);
position.set(0.0f, 0.0f, 30.0f);
far = 300.0f;
lookAt(0, 0, 0);
translate(0.0f, 0.0f, 2.1f);
lookAt(0, 0, 0);
update();
}
public void pause() {
numberOfFingers = 0;
}
#Override
public void resize(int width, int height) {
viewportWidth = width;
viewportHeight = height;
aspectRatio = viewportHeight / viewportWidth;
update();
}
#Override
public void render() {
if (isSingleTouched) {
// This gets the change in touch position and
// compensates for the aspect ratio.
if (x == -1 || y == -1 || justSingleTouched) {
x = Gdx.input.getX();
y = Gdx.input.getY();
} else {
dx = (x - Gdx.input.getX());
dy = (y - Gdx.input.getY()) / aspectRatio;
}
// This zooms when control is pressed.
if (controlIsPressed && dy > 0) {
scrollIn();
} else if (controlIsPressed && dy < 0) {
scrollOut();
}
// This translates the camera blender-style
// if shift is pressed.
// Note that this will look weird with a
// perspective camera.
else if (shiftIsPressed) {
translateTangentially();
}
// Default is to rotate the object
// (actually rotate the camera about a sphere
// that surrounds the object).
else {
travelAround();
}
x = Gdx.input.getX();
y = Gdx.input.getY();
justSingleTouched = false;
}
// this zooms when the mouse wheel is rotated
if (isScrollingUp) {
scrollIn();
isScrollingUp = false;
} else if (isScrollingDown) {
scrollOut();
isScrollingDown = false;
}
// Some key controls
if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A)) {
translateTangentially(1, 0);
} else if (Gdx.input.isKeyPressed(Keys.RIGHT)
|| Gdx.input.isKeyPressed(Keys.D)) {
translateTangentially(-1, 0);
}
if (Gdx.input.isKeyPressed(Keys.UP) || Gdx.input.isKeyPressed(Keys.W)) {
translateTangentially(0, 1);
} else if (Gdx.input.isKeyPressed(Keys.DOWN)
|| Gdx.input.isKeyPressed(Keys.S)) {
translateTangentially(0, -1);
}
update();
}
// These methods create the pinch zoom
// and set some flags for logic in render method.
#Override
public boolean touchDown(int x, int y, int pointer, int button) {
// for pinch-to-zoom
numberOfFingers++;
if (numberOfFingers == 1) {
isSingleTouched = true;
justSingleTouched = true;
fingerOnePointer = pointer;
fingerOne.set(x, y, 0);
} else if (numberOfFingers == 2) {
isSingleTouched = false;
fingerTwoPointer = pointer;
fingerTwo.set(x, y, 0);
float distance = fingerOne.dst(fingerTwo);
lastDistance = distance;
}
return true;
}
#Override
public boolean touchDragged(int x, int y, int pointer) {
if (numberOfFingers > 1) {
if (pointer == fingerOnePointer) {
fingerOne.set(x, y, 0);
}
if (pointer == fingerTwoPointer) {
fingerTwo.set(x, y, 0);
}
float distance = fingerOne.dst(fingerTwo);
if (lastDistance > distance) {
scrollOut();
} else if (lastDistance < distance) {
scrollIn();
}
lastDistance = distance;
update();
}
return true;
}
#Override
public boolean touchUp(int x, int y, int pointer, int button) {
isSingleTouched = false;
if (numberOfFingers == 1) {
Vector3 touchPoint = new Vector3(x, y, 0);
unproject(touchPoint);
}
numberOfFingers--;
// just some error prevention... clamping number of fingers (ouch! :-)
if (numberOfFingers < 0) {
numberOfFingers = 0;
}
lastDistance = 0;
return false;
}
// These methods set flags for logic in render method.
#Override
public boolean keyDown(int keycode) {
switch (keycode) {
case (Keys.SHIFT_LEFT):
case (Keys.SHIFT_RIGHT):
shiftIsPressed = true;
break;
case (Keys.CONTROL_LEFT):
case (Keys.CONTROL_RIGHT):
controlIsPressed = true;
break;
case (Keys.O):
this.up.set(0.0f, 1.0f, 0.0f);
this.position.set(0.0f, 0.0f, 30.0f);
this.lookAt(0, 0, 0);
this.update();
}
return true;
}
#Override
public boolean keyUp(int arg0) {
shiftIsPressed = controlIsPressed = false;
return true;
}
#Override
public boolean scrolled(int direction) {
if (direction == -1) {
isScrollingUp = true;
} else if (direction == 1) {
isScrollingDown = true;
}
return true;
}
// The rest of the methods translate the camera.
public void scrollIn() {
float magnitude = 1.0f;
scrollIn(magnitude);
}
public void scrollIn(float magnitude) {
if (position.dst2(ORIGIN) > 2.0f) {
tmp.set(position);
tmp.nor();
this.translate(-tmp.x * magnitude, -tmp.y * magnitude, -tmp.z
* magnitude);
update();
}
}
public void scrollOut() {
float magnitude = 1.0f;
scrollOut(magnitude);
}
public void scrollOut(float magnitude) {
tmp.set(position);
tmp.nor();
this.translate(tmp.x * magnitude, tmp.y * magnitude, tmp.z * magnitude);
update();
}
private void travelAround() {
tmp.set(up);
rotateAround(ORIGIN, tmp, dx);
tmp.crs(position).nor();
rotateAround(ORIGIN, tmp, dy);
}
private void translateTangentially() {
translateTangentially(dx, dy);
}
private void translateTangentially(float dx, float dy) {
tmp.set(up);
tmp.crs(position);
if (dx > 0) {
translate(tmp.x / 15.0f, tmp.y / 15.0f, tmp.z / 15.0f);
} else if (dx < 0) {
translate(-tmp.x / 15.0f, -tmp.y / 15.0f, -tmp.z / 15.0f);
}
if (dy > 0) {
translate(-up.x, -up.y, -up.z);
} else if (dy < 0) {
translate(up);
}
}
}
Please take a look at this: Mesh rendering issue libgdx.
Method render contains the code you need.
You either need to rotate the camera, or rotate the model.
I believe the libGDX Camera.rotateAround method does what you need. Leave the "point" as the center of your model and set the "axis" parameter based on which way the user is flinging/panning. The "angle" can either be a fixed value, or relative to the intensity of the fling/pan.

Libgdx sliding pause menu

So in my Gameplay screen user has posibillity to click on menu button and then that menu button will pause the game and show the menu.
I tried to impelement menu as a new stage, but that just opens a new screen, sets the graphics of the menu like I want to and leaves the rest of the screen black.
Here's the image so you can see what I'm talking about:
I want this green part to smoothly slide into Gameplay scene and I wan't to get rid of this black part of the screen and instead leave that part transparent (I want it to show only the green part of a Image).
Tried to find some good tutorials about pause menus, but no luck.
Here's the code of my pause screen:
public class Menu implements Screen{
Stage menuStage = null;
private Image menu_bg = null;
private Main game = null;
public Menu(Main gm){
game = gm;
}
#Override
public void show() {
menuStage = new Stage(new StretchViewport(1920, 1080));
Gdx.input.setInputProcessor(menuStage);
menu_bg = new Image(new Texture(Gdx.files.internal("menuProba.png")));
menuStage.addActor(menu_bg);
menuButtons();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
menuStage.draw();
menuStage.act();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
private void menuButtons(){
Table menuButtons = new Table();
menuButtons.setFillParent(true);
final Image resumeGame = new Image(new Texture(Gdx.files.internal("playbutton.png")));
final Image retryGame = new Image(new Texture(Gdx.files.internal("retrybutton.png")));
final Image homeButton = new Image(new Texture(Gdx.files.internal("homebutton.png")));
final Image exitButton = new Image(new Texture(Gdx.files.internal("exitbutton.png")));
resumeGame.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){
resumeGame.addAction(Actions.scaleTo(1, 1.1f,.1f));
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button){
resumeGame.addAction(Actions.scaleTo(1, 1,.1f));
}
});
retryGame.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){
retryGame.addAction(Actions.scaleTo(1, 1.1f,.1f));
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button){
retryGame.addAction(Actions.scaleTo(1, 1,.1f));
}
});
homeButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){
homeButton.addAction(Actions.scaleTo(1, 1.1f,.1f));
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button){
homeButton.addAction(Actions.scaleTo(1, 1,.1f));
game.setScreen(new MainMenu(game));
}
});
exitButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){
exitButton.addAction(Actions.scaleTo(1, 1.1f,.1f));
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button){
exitButton.addAction(Actions.scaleTo(1, 1,.1f));
}
});
/*HorizontalGroup horizontalGroup = new HorizontalGroup();
horizontalGroup.addActor(resumeGame);
horizontalGroup.addActor(retryGame);
horizontalGroup.addActor(homeButton);
horizontalGroup.addActor(exitButton);
menuButtons.add(horizontalGroup);*/
menuButtons.add(resumeGame).expand().left().padLeft(40);
menuButtons.row();
menuButtons.add(retryGame).expand().left().padLeft(40);
menuButtons.row();
menuButtons.add(homeButton).expand().left().padLeft(40);
menuButtons.row();
menuButtons.add(exitButton).expand().left().padLeft(40);
menuStage.addActor(menuButtons);
}
}
And the Gameplay screen:
public class GameScreen implements Screen, InputProcessor {
boolean menuScreen;
private Texture menuImage = null;
public boolean buttonMenuTouched = false;
public InputMultiplexer multiplexer = null;
BitmapFont font;
//SCORE-------------------------------------
private SpriteBatch batch = null;
private OrthographicCamera mCamera = null;
private BitmapFont scoreFont = null;
private int score = 0;
//--------------------------------------------
Main game = null;
public Texture font_texture;
public GameScreen(Main gm){
game = gm;
}
Stage gameStage = null;
private Image game_bg = null, menu_bg = null;
private GameManager manager = null;
#Override
public void show() {
mCamera = new OrthographicCamera(1920, 1080);
font_texture = new Texture(Gdx.files.internal("font.png"));
font_texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
scoreFont = new BitmapFont(Gdx.files.internal("font.fnt"), new TextureRegion(font_texture), false);
batch = new SpriteBatch();
multiplexer = new InputMultiplexer();
gameStage = new Stage(new StretchViewport(1920, 1080));
multiplexer.addProcessor(this);
multiplexer.addProcessor(gameStage);
Gdx.input.setInputProcessor(multiplexer);
game_bg = new Image(new Texture(Gdx.files.internal("pozadinaGameScreen.png")));
gameStage.addActor(game_bg);
menuImage = new Texture("menuProba.png");
manager = new GameManager(game, this, gameStage);
manager.createPlayer();
manager.createBlueMonster();
manager.createHUDButtons();
manager.createGameOverStage();
gameScreenButtoni();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gameStage.draw();
gameStage.act();
manager.checkButtons();
manager.checkCollisions();
batch.setProjectionMatrix(mCamera.combined);
batch.begin();
this.scoreFont.draw(batch, ""+manager.score, Gdx.graphics.getWidth() - 1070, Gdx.graphics.getHeight() - 580);
batch.end();
if (manager.gameOver == true){
manager.gameOverStage.draw();
manager.gameOverStage.act();
Gdx.input.setInputProcessor(manager.gameOverStage);
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
manager.gameOverStage.dispose();
gameStage.dispose();
manager.dispose();
game.setScreen(game.mainMenu);
}
// METODE INPUT PROCESORA
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
manager.shootBullet();
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
public void gameScreenButtoni(){
//menuImage = new Image(new Texture(Gdx.files.internal("menuProba.png")));
Table buttoni = new Table();
buttoni.setFillParent(true);
final Image menuButton = new Image(new Texture(Gdx.files.internal("menubutton.png")));
menuButton.addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button){
menuButton.addAction(Actions.scaleTo(1, 1.1f,.1f));
buttonMenuTouched = true;
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button){
menuButton.addAction(Actions.scaleTo(1, 1,.1f));
buttonMenuTouched = false;
game.setScreen(new Menu(game));
}
});
final Image scoreText = new Image(new Texture(Gdx.files.internal("score.png")));
buttoni.add(menuButton).expand().top().left().padLeft(20).padTop(20);
buttoni.add(scoreText).expand().top().right().padTop(30).padRight(140);
gameStage.addActor(buttoni);
}
public void menuScreen(){
Stage menu = new Stage(new StretchViewport(400,400));
menu_bg = new Image(new Texture(Gdx.files.internal("logoMali.png")));
menu.addActor(menu_bg);
}
}
I know that I'm doing this wrong, but how should I do it? Draw a rectangle when button is pressed or what?
In my game I make NavigationDrawer in libgdx as you can see:
You can make this with sample code, just follow a few steps:
1- Copy NavigationDrawer class into your project:
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.Timer.Task;
/**
* Created by Crowni on 10/6/2015.
*/
public class NavigationDrawer {
// this value is suitable
private static final float INTERVAL_SEC = 0.001f;
// Some attributes for {#link NavigationDrawer}
private static float CAM_MAIN_POSITION;
public static float WIDTH;
public static float SPEED;
private static OrthographicCamera camera;
/**
* To ensure the {#link NavigationDrawerListener#onFinish()} called one time
**/
private static boolean isFinish = true;
private static Task task;
private static Timer timer = new Timer();
private static NavigationDrawerListener listener;
public interface NavigationDrawerListener {
public void onStart();
// May be you want to make some Actions here during sliding
public void onRun();
public void onFinish(float camX);
}
public static void initialize(Stage stage, NavigationDrawerListener listener) {
NavigationDrawer.listener = listener;
camera = ((OrthographicCamera) stage.getCamera());
setNavigationDrawerDefault(stage);
initializeTimerTask(false);
}
private static void setNavigationDrawerDefault(Stage stage) {
WIDTH = stage.getWidth() - stage.getWidth() / 3;
CAM_MAIN_POSITION = stage.getWidth() / 2;
SPEED = 2f;
}
private static Task initializeTimerTask(boolean show) {
task = new Task() {
public void run() {
if (!timer.isEmpty()) {
if (show)
camera.position.x -= SPEED;
else
camera.position.x += SPEED;
listener.onRun();
} else if (isFinish) {
listener.onFinish(setDefaultCameraEndPostion(show));
}
}
};
return task;
}
/**
* #param show
* : I passed it here because I know it is correct choice
**/
private static float setDefaultCameraEndPostion(boolean show) {
isFinish = false;
if (show)
return camera.position.x = CAM_MAIN_POSITION - WIDTH;
else
return camera.position.x = CAM_MAIN_POSITION;
}
private static boolean isOpened() {
return camera.position.x != CAM_MAIN_POSITION;
}
public static void show(boolean show) {
if ((isOpened() && !show) || (!isOpened() && show))
startTask(show);
}
private static void startTask(boolean show) {
if (timer.isEmpty()) {
isFinish = true;
listener.onStart();
timer.scheduleTask(initializeTimerTask(show), 0f, INTERVAL_SEC,
((int) (WIDTH / SPEED)));
}
}
}
2- In your Screen write the following:
#Override
public void show() {
stage = new Stage(new StretchViewport(1080, 1920));
// May be you want to make some Actions with NavigationDrawer state
NavigationDrawerListener listener = new NavigationDrawerListener() {
#Override
public void onStart() {
System.out.println("onStart");
}
#Override
public void onRun() {
System.out.println("onRun");
}
#Override
public void onFinish(float camX) {
System.out.println("onFinish: " + camX);
}
};
// You must be initialize NavigationDrawer Firstly
NavigationDrawer.initialize(stage, listener);
// This image is sample to show how navigationDrawer look like on the screen
Image background= new Image(new Texture(Gdx.files.internal("background.jpg")));
background.addListener(new ClickListener() {
private int clicked = 0;
public void clicked(InputEvent event, float x, float y) {
if (clicked % 2 == 0) {
clicked++;
NavigationDrawer.show(true);
} else {
clicked++;
NavigationDrawer.show(false);
}
}
});
background.setFillParent(true);
stage.addActor(background);
Gdx.input.setInputProcessor(stage);
}
3- The result of sample code look like that:
4- Finally you can create images, labels, ... actors in navigation width which their positions into off-screen i.e. with negative positions. Enjoy!
UPDATE
This Navigation Drawer More performance and beauty sliding.

Categories