Libgdx, Android, how to drag and move a texture - java

currently the method I used is to detect whether touch position (Gdx.input.getX() & Y()) is in the area whether the object texture is. If so I setPosition of the object texture to the mouse position as center. While this work but it is not robust. Because if my finger move faster than the update, as soon as the touched position is outside texture bound. It won't update any more.
There must be a more reliable way and please advice. Essentially, I want to touch on the texture and drag the texture to wherever my touch is moving.
Many thanks.
My current approach is like this:
public class PlayScreen implements Screen {
int scWidth, scHeight;
int playerWidth, playerHeight;
private SpriteBatch batch; // This is in the render.
Player player;
// Create a constructor
Game game;
public PlayScreen(Game game){
this.game = game;
}
#Override
public void show() {
batch = new SpriteBatch();
scWidth = Gdx.graphics.getWidth();
scHeight = Gdx.graphics.getHeight();
playerWidth = 180;
playerHeight = 240;
player = new Player("mario.png", new Vector2(250, 300),new Vector2(playerWidth, playerHeight)) ;
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
// Only draw if the mouse is hover on the image.
if (Gdx.input.getX() > player.getPosition().x && Gdx.input.getX() < player.getPosition().x + playerWidth){
if (scHeight - Gdx.input.getY() > player.getPosition().y && scHeight - Gdx.input.getY() < player.getPosition().y + playerHeight)
{
player.setPosition(new Vector2(Gdx.input.getX() - playerWidth/2,
scHeight - Gdx.input.getY() - playerHeight/2));
player.draw(batch);
} else{
player.draw(batch);
}
} else{
player.draw(batch);
}
batch.end();
player.update(); // Update the bound
}
}
Also the Player class is :
package com.jiajunyang.emosonicsgame;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
public class Player extends Image {
Vector2 position, size;
Texture player;
Rectangle bounds;
public Player(String fileName, Vector2 position, Vector2 size){
super(new Texture(Gdx.files.internal(fileName)));
this.position = position;
this.size = size;
bounds = new Rectangle(position.x, position.y, size.x, size.y);
// player = new Texture(Gdx.files.internal(fileName));
}
public void update(){
bounds.set(position.x, position.y, size.x, size.y);
}
public void draw(SpriteBatch batch){
batch.draw(player, position.x, position.y, size.x, size.y);
}
public Vector2 getPosition() {
return position;
}
public void setPosition(Vector2 position) {
this.position = position;
}
public Vector2 getSize() {
return size;
}
public void setSize(Vector2 size) {
this.size = size;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}

Jiajun, create a Stage and have your Player extend Image. Then call stage.addActor(player) in show. In render call stage.act() and stage.draw(). Use the Image's constructor to pass your Texture into. Finally, in Player's constructor, call this:
addListener(new DragListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
}
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
moveBy(x - getWidth()/2, y - getHeight()/2);
}
});

Related

LIBGDX - How to make the paddle not jumping in pong game?

I am making a Pong game and when I click on the screen the paddle jump to my cursor point. I want that I need to drag the cursor to move him and without jumping like normal Pong game. how can I do this?
This is my Paddle class:
public class Paddle {
private Vector3 position;
private int width, height;
private Texture texture;
public Paddle(int x, int y, int width, int height){
this.width = width;
this.height = height;
createTexture(width,height);
position = new Vector3(x, y, 0);
}
private void createTexture(int width, int height) {
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.BLACK);
pixmap.fillRectangle(0, 0, width, height);
texture = new Texture(pixmap);
pixmap.dispose();
}
public void update(int y){
position.add(0, y - position.y,0);
position.y = y;
position.set(position.x, HeadGuns.HEIGHT - position.y, position.z);
}
public void draw(SpriteBatch sb){
sb.draw(texture, position.x, position.y, width,height);
}
This is my PlayState class:
public class PlayState extends State {
private Paddle myPaddle;
public PlayState(GameStateManager gsm) {
super(gsm);
myPaddle = new Paddle(25, HeadGuns.HEIGHT/2, 25, 150);
}
#Override
public void handleInput() {
if (Gdx.input.isTouched()){
//when I touched the screen
myPaddle.update(Gdx.input.getY());
}
}
#Override
public void update(float dt) {
handleInput();
}
#Override
public void render(SpriteBatch sb) {
sb.begin();
myPaddle.draw(sb);
sb.end();
}
#Override
public void dispose() {
}
You are reading touch position:
Gdx.input.getY()
and using it directly to set pad position - you can't do that.
You should use InputLister to get events.
First you should listen to touchDown and see is user touching your pad or not (compare touch coordinates with pad coordinates)
Then, for dragging you should use touchDragged() event...to update pad position when dragging happen, but only if touchDown detected that touch:
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/scenes/scene2d/InputListener.html#touchDragged-com.badlogic.gdx.scenes.scene2d.InputEvent-float-float-int-

Player doesn't move when attempting to draw from a Player class

So I'm currently in the process of refactoring my code in my game for the player and started a player class:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class Player
{
protected String name;
protected float health, maxHealth;
protected Texture texture;
protected int xPos, yPos;
public Player(String name, float maxHealth, Texture texture) {
this(name, maxHealth, texture, 0, 0);
}
public Player(String name, float maxHealth, Texture texture, int xPos, int yPos) {
this.name = name;
this.health = this.maxHealth = maxHealth;
this.texture = texture;
this.xPos = xPos;
this.yPos = yPos;
}
public Texture getTexture() {
return this.texture;
}
public int getX() {
return xPos;
}
public int getY() {
return yPos;
}
public String getName() {
return name;
}
public void draw(SpriteBatch spriteBatch) {
spriteBatch.begin();
spriteBatch.draw(texture, xPos, yPos, 0.5f, 0.5f, 0, 0,
texture.getWidth(), texture.getHeight(), false, false);
spriteBatch.end();
}
public void update(float delta) {
processMovement(delta);
}
public void processMovement(float delta) {
if(Gdx.input.isKeyPressed(Input.Keys.A)) {
xPos -= 50 * delta;
}
if(Gdx.input.isKeyPressed(Input.Keys.D)) {
xPos += 50 * delta;
}
}
}
I'm using an orthographic camera, I haven't added any terrain yet as I'm going to do that next, however I want the player to always stay in the center but have the player move around the terrain when I draw it.
The code I have for creating the camera and drawing my player is as follows:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class GameState implements Screen
{
private PixelGame parent;
private OrthographicCamera camera;
private Player player;
private Texture playerTexture;
private SpriteBatch spriteBatch;
public GameState(PixelGame parent) {
this.parent = parent;
this.playerTexture = new Texture(Gdx.files.internal("player/sprite.png"));
this.player = new Player("Me", 20, playerTexture);
this.spriteBatch = new SpriteBatch();
}
#Override
public void render(float delta) {
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
player.draw(spriteBatch);
player.update(delta);
}
#Override
public void show() {
}
#Override
public void dispose() {
}
#Override
public void resize(int width, int height) {
float ratio = (float)width / (float)height;
camera = new OrthographicCamera(2f * ratio, 2f);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
}
The player sprite doesn't seem to move, but when i change the values to something >75 the player sprite sprints across the screen like no-ones business.
xPos and yPos in your class are ints. I would say that's the problem. Your processMovement() method is called like 100 times per second and 50 * delta is most likely smaller than 1 so it's rounded to 0 because value has to be stored in int variable. Try changing xPos and yPos to floats.
And if that doesn't help (can't be sure without trying out the code) do some debugging. Put break points. See if processMovement() is called at all and if it is then what value variable delta has. How calculation goes.

How do I reposition a moving animation during a gameplay?

I am using the Android Studio IDE, with the libGDX framework to develop a game. It is a clone of the Pac-Man game with a similar gameplay to flappy bird. The concept is that the pac man moves through the planks while avoiding the ghosts coming from the right direction, that are moving off straight into the left direction (not chasing the position of the player). I am not sure how I create a 'for loop' for the ghost animations, I want the ghosts to consistently reposition and re-appear from the right side after a few seconds, with the exception that they completely gone off the screen initially.
The class for one of the Ghosts.
public class Blinky {
private Vector3 position; //x y and z axis
private Rectangle bounds;
private Texture texture1;
private Animation blinkyAnimLeft;
public Blinky(int x, int y) {
position = new Vector3(x, y, 0);
Texture texture1 = new Texture("blinkyLeft.png");
blinkyAnimLeft = new Animation(new TextureRegion(texture1), 2, 0.5f);
//bounds = new Rectangle(x,y,texture1.getWidth() / 2, texture1.getHeight());
}
public void update(float dt) {
blinkyAnimLeft.update(dt);
//bounds.setPosition(position.x, position.y);
}
public Vector3 getPosition() {
return position;
}
public TextureRegion getTexture() {
return blinkyAnimLeft.getFrame();
}
//public Rectangle getBounds() {
return bounds;
}
public void dispose() {
texture1.dispose();
}
}
Ghosts and Player initialised in the GamePlayState Class
public class GamePlayState extends State {
//Variables
private float timePassed = 0;
private Texture background;
public static final int WALK = 1;
public static final double GHOST_WALK = 0.5;
private static final int PLANKS_SPACING = 125; //gap betwen the planks
private static final int PLANK_COUNT = 4;
private Array<Obstacle> planks;
private Player player;
private Blinky blinky;
private Inky inky;
private Texture missile;
public GamePlayState(GameStateManager gsm) {
super(gsm);
player = new Player(50, 100);
blinky = new Blinky(400, 220);
inky = new Inky(400, 240);
// missile = new Texture("missile.png");
background = new Texture("black.jpg");
cam.setToOrtho(false, PacMan.WIDTH/2, PacMan.HEIGHT/2);
planks = new Array<Obstacle>();
for (int i = 1; i<= PLANK_COUNT; i++) {
planks.add(new Obstacle(i * (PLANKS_SPACING + Obstacle.PLANK_WIDTH)));
}
}
#Override
public void handleInput() {
}
#Override
public void update(float dt) {
handleInput();
player.update(dt);
blinky.update(dt);
inky.update(dt);
cam.position.x = player.getPosition().x + 80; //update the position of the camera with the bird
//update when pacman cam viewport has passed plank
//make cam follow the player
for (Obstacle plank: planks) {
if (cam.position.x - (cam.viewportWidth/1) > plank.getPosTopPlank().x + plank.getTopPlank().getWidth()) {
plank.respositionPlanks(plank.getPosTopPlank().x + ((Obstacle.PLANK_WIDTH + PLANKS_SPACING * PLANK_COUNT )));
}
if (plank.collision (player.getBounds()))
gsm.set(new GamePlayState(gsm));
}
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(background, cam.position.x - (cam.viewportWidth/2), 0);
timePassed += Gdx.graphics.getDeltaTime();
//Moving Inky
sb.draw(inky.getTexture(), inky.getPosition().x, inky.getPosition().y);
inky.getPosition().x -= GHOST_WALK;
//Moving Blinky
sb.draw(blinky.getTexture(), blinky.getPosition().x, blinky.getPosition().y);
blinky.getPosition().x -= GHOST_WALK;
You should get x, y( and z) position from Vector3.
Then check for borders
if (inky.getPosition().x < 0){
Thread.sleep(/*a few sdeconds*/2000);/*Android studio would ask you about wrapping it with try - catch*/
inky.setPostion( x + /*screen x size*/,
inky.getPosition().y,inky.getPosition().z)/*add setter in ghost class*/
}
In fact, this is not the best way to do it, but the simplest one

what reason is there for non-smooth 2d sprite movement in this example

Just in process of making a space invaders style game for android.
I want the player to be able to touch the screen anywhere to right or left of character (at bottom of screen) to move him that direction.
The code compiles without error and the playe does move, but
A) he's moving much slower than I expected
B) The movement is 'jittery' even though I have multiplied the movement speed by deltatime in a few different ways.
Please could someone be kind enough to take a look at my code to say where I have gone wrong? :-
package com.moneylife.stashinvaders;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class StashInvaders extends ApplicationAdapter {
GameManager gameManager;
#Override
public void create () {
gameManager = new GameManager();
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gameManager.update();
gameManager.draw();
}
#Override
public void dispose () {
gameManager.spriteBatch.dispose();
}
}
GameManager class:
package com.moneylife.stashinvaders;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
/**
* Created by Dave on 12/08/2016.
*/
public class GameManager {
SpriteBatch spriteBatch;
Player player1;
public GameManager(){
spriteBatch = new SpriteBatch();
player1 = new Player();
}
public void update(){
player1.update();
}
public void draw(){
spriteBatch.begin();
player1.draw(spriteBatch);
spriteBatch.end();
}
}
Player class:
package com.moneylife.stashinvaders;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;
/**
* Created by Dave on 12/08/2016.
*/
public class Player {
Vector2 position;
Texture texture;
int speed = 50;
float deltaTime;
public Player(){
Gdx.input.setInputProcessor(new GestureDetector(new MyGestureDetector()));
texture = new Texture("bazookaman.png");
position = new Vector2(Gdx.graphics.getBackBufferWidth() / 2 - texture.getWidth() / 2, 0);
}
public void update(){
deltaTime = Gdx.graphics.getDeltaTime();
}
public void draw(SpriteBatch spriteBatch){
spriteBatch.draw(texture, position.x, position.y);
}
public class MyGestureDetector implements GestureDetector.GestureListener {
#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 pan(float x, float y, float deltaX, float deltaY) {
if (x > position.x){
position.x += speed * deltaTime;
}
if (x < position.x){
position.x -= speed * deltaTime;
}
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() {
}
}
}
Look closely at your logic.
if (x > position.x){
position.x += speed * deltaTime; //if close to touch point, position.x is now bigger than x
}
if (x < position.x){ //if we just moved right past the touch point, undo it
position.x -= speed * deltaTime;
}
Furthermore, this pan method will only be called on frames where the finger position was polled and was found to have moved. The finger position is not polled 60 times per second like your game is probably running, and movement will not always have occurred.
Instead, you should use the panning to modify a target position for your character. In the update() method you can always be moving towards that target position with some speed. It's up to you whether you should be using x or deltaX in the pan method to change your target X. Different types of gameplay.

LibGDX - GestureListener touch coords return in screen pixels, how convert to in-game world units?

How can the coords returned from GestureListener (TouchDown method for example) be converted into world-unit coords.
EG. My device screen is 1080p, my game is set up to use 540x960 (portrait).
In my current example project (code below) the paddle moves along x-axis twice as quickly as my finger, hence the position being set is given in screen-pixels.
Of course in this exact example, I could easily just divide it by 2 as I know the gameworld-units are exactly half of the device-pixels, however what if I wanted to make my world size 150x150 units --or if I was testing on a device with different screen sizes??
package com.moneylife.breakingass;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;
public class BreakingAss extends ApplicationAdapter {
SpriteBatch batch;
Sprite bgSprite, bgCoverSprite, menu1Sprite;
Paddle paddle;
enum ScreenState { StartScreen, PlayScreen, GameOverScreen }
ScreenState currentScreenState;
public int DeviceScreenWidth, DeviceScreenHeight;
public int WorldWidth = 540, WorldHeight = 960;
public OrthographicCamera camera;
int zAxis = 0;
MyGestureDetector myGestureDetector;
#Override
public void create () {
currentScreenState = ScreenState.StartScreen;
batch = new SpriteBatch();
DeviceScreenWidth = Gdx.graphics.getWidth();
DeviceScreenHeight = Gdx.graphics.getHeight();
myGestureDetector = new MyGestureDetector();
bgSprite = new Sprite(new Texture("bentoverass.jpg"));
bgCoverSprite = new Sprite(new Texture("half1080coverup.png"));
menu1Sprite = new Sprite(new Texture("menu1.jpg"));
menu1Sprite.setSize(WorldHeight * DeviceScreenWidth / DeviceScreenHeight,WorldHeight);
menu1Sprite.setPosition(0,0);
camera = new OrthographicCamera(WorldWidth, WorldHeight);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, zAxis);
camera.update();
paddle = new Paddle(WorldWidth, WorldHeight);
Gdx.input.setInputProcessor(new GestureDetector(myGestureDetector));
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
paddle.update();
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
if (currentScreenState == ScreenState.StartScreen){
menu1Sprite.draw(batch);
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.draw(batch);
}
batch.end();
}
#Override
public void dispose () {
batch.dispose();
}
public class MyGestureDetector implements GestureDetector.GestureListener {
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
if (currentScreenState == ScreenState.StartScreen) {
if (x > 0) {
currentScreenState = ScreenState.PlayScreen;
}
}
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
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 pan(float x, float y, float deltaX, float deltaY) {
if (currentScreenState == ScreenState.PlayScreen){
paddle.position = new Vector2(x - paddle.texture.getWidth() / 2, paddle.fixedYPosition);
}
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() {
}
}
}
Getting input coordinates always yields the coordinates of the screen. Logically because the input does not (need to) know about your game world. The camera is responsible for what is being drawn to the screen and the camera can be used to transform your screen coordinates to the coordinates of your world.
//Get screen coordinates
Vector3 mousePosition = new Vector3(Gdx.input.getX, Gdx.input.getY, 0);
//Transform to world coordinates using the correct camera
camera.unproject(mousePosition);
//The mousePosition vector is changed in the above method and now contains the game world coordinates of the camera you used.
PS.
For your paddle you can make a transform method so you can use the deltaX and deltaY in the pan method. Since the delta's hand you the change in "pan"there is no need at all to transform between screen and world.

Categories

Resources