I'm stuck on implementing touchDragged listener using libgdx.
Here is my code and can anyone suggest how to drag image when user touches it and than moves finger?
I use stage and actor and I want to catch touchDragged event on actor.
Thanks.
public void create () {
Texture.setEnforcePotImages(false);
stage = new Stage();
Gdx.input.setInputProcessor(stage);
// create a SpriteBatch with which to render the sprite
batch = new SpriteBatch();
// load the sprite's texture. note: usually you have more than
// one sprite in a texture, see {#see TextureAtlas} and {#see TextureRegion}.
texture = new Texture(Gdx.files.internal("ball3.png"));
Skin skin = new Skin();
skin.add("default", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
skin.add("ball", texture);
Image sourceImage = new Image(skin, "ball");
sourceImage.setBounds(50, 125, 100, 100);
stage.addActor(sourceImage);
// create an {#link OrthographicCamera} which is used to transform
// touch coordinates to world coordinates.
camera = new OrthographicCamera();
// we want the camera to setup a viewport with pixels as units, with the
// y-axis pointing upwards. The origin will be in the lower left corner
// of the screen.
camera.setToOrtho(false);
}
public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
Table.drawDebug(stage);
// if a finger is down, set the sprite's x/y coordinate.
if (Gdx.input.isTouched()) {
// the unproject method takes a Vector3 in window coordinates (origin in
// upper left corner, y-axis pointing down) and transforms it to world
// coordinates.
camera.unproject(spritePosition.set(Gdx.input.getX(), Gdx.input.getY(), 0));
}
}
Here are the steps:
You need to check if the finger is touching the object that you want to move. Here are some useful methods to get your finger's position:
Gdx.input.getX();
Gdx.input.getY();
You need to use a variable to track whether the finger is moving, when touching.
If the variable is true, you change the object's position to your finger's position.
You disable your variable when the finger is no longer touching the screen.
I suggest you to use InputProcessor:
public class MyInputProcessor implements InputProcessor{
#Override
public boolean keyDown(int keycode){
return false;
}
#Override
public boolean keyUp(int keycode){
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){
return false;
}
#Override
public boolean keyTyped(char character){
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;
}
}
Make it a Field:
MyInputProcessor inputProcessor;
And in onCreate():
inputProcessor = new MyInputProcessor();
Gdx.input.setInputProcessor(inputProcessor);
That way you can just implement your code in the touchDragged callback.
Related
I currently have an animation which runs as soon as I launch the app. Now I want to select another animation which plays in response to user input. e.g If I press left, the animation for walking left replaces the current sprite's animation. I've tried adding a new textureAtlas in the keyDown function but that doesn't work.
In other words I want the app to display the idle animation of the sprite when no Input is present. Then If I hit a button (left for example) It should change to walking animation.
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
private SpriteBatch batch;
private TextureAtlas textureAtlas;
private Animation animation;
private float elapsedTime = 0;
#Override
public void create() {
batch = new SpriteBatch();
textureAtlas = new TextureAtlas(Gdx.files.internal("spritesheet.atlas"));
animation = new Animation(1/7f, textureAtlas.getRegions());
}
#Override
public void dispose() {
batch.dispose();
textureAtlas.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
//sprite.draw(batch);
elapsedTime += Gdx.graphics.getDeltaTime();
batch.draw(animation.getKeyFrame(elapsedTime, true), 0, 0);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public boolean keyDown(int keycode) {
if (keycode == Input.Keys.LEFT) {
textureAtlas = new TextureAtlas(Gdx.files.internal("spritesheet2.atlas"));
}
return true;
}
#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) {
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;
}
}
Depending on how many different animations you have (maybe it is just idle, walk_right, walk_left, maybe a couple of others...), you could just load all the textureAtlases and create various animations - like you did in your create() method
//simple example ...
animationIdle = new Animation(1/7f, textureAtlas1.getRegions());
animationLeft = new Animation(1/7f, textureAtlas2.getRegions());
//etc
Then have code somewhere (not in the render method), determine what the "current animation" should be. Using your code as an example:
#Override
public boolean keyDown(int keycode) {
if (keycode == Input.Keys.LEFT) {
// Maybe check to make sure the currentAnimation is not already the
// left animation, if it isn't, swap it:
currentAnimation = animationLeft;
//set elapsedTime to 0 to "Restart the new animation" at its beginning
elapsedTime = 0;
}
Then your render() method just draws the current animation, and the elapsedTime was reset as needed(if you changed the animation you wanted):
batch.draw(currentAnimation.getKeyFrame(elapsedTime, true), 0, 0);
//increment elapsedTime after drawing animation at least once??
elapsedTime += Gdx.graphics.getDeltaTime();
The above code is rough, not necessarily syntax free or structured the best, but gives you an idea of what might work.
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.
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());
}
This is my code to add sprites on Scene.
for (int i = 3; i <= cage.getDirtMeter(); i++) {
Sprite dirtSprite = new Sprite(0, 0, Main.dirtTextureRegion,
mainActivity.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
removeDirt(this);
return true;
}
};
float x = Utility.getRandomXWithinCamera(dirtSprite);
float y = Utility.getRandomYWithinCamera(dirtSprite);
dirtSprite.setPosition(x, y);
this.registerTouchArea(dirtSprite);
attachChild(dirtSprite);
}
and here is my removeDirt method
public void removeDirt(final Sprite sprite) {
synchronized (this) {
if (CoolDown.getSharedInstance().checkValidity()) {
if (isCleanSelected) {
Log.d("detach", "Calling remove dirt");
cage.removeDirt();
mainActivity.runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Now it is save to remove the entity! */
if (MainMenuScene.this.detachChild(sprite)) {
Log.d("detach", "detached Successfuly!");
}
}
});
updateMetersUI();
}
}
}
}
After removeDirt is called sprite isn't visible on screen but sprites onAreaTouch is still being called even sprites is being deAttached successfully. Any idea how to completely remove sprite from scene. thanks. And I have also tried
sprite.setVisible(false);
sprite.clearEntityModifiers();
sprite.setIgnoreUpdate(true);
sprite.clearUpdateHandlers();
sprite.reset();
sprite.detachSelf();
But after that onAreaTouch is still being called.
You need to Unregister Touch Areas of your Sprite from the scene.
eg
yourScene.unregisterTouchArea(yourSprite);
I'm creating some little sprites with a bmp inside the constructor of another view as background. But when I click the sprites, that have their onClickListener, the view I'm clicking is the background view.
Some code:
My constructor:
public ToposGameView(Context context) {
super(context);
moles = new ArrayList<MoleSprite>();
setFocusable(true);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i(tag, "Click en GameView");
}
});
gameLoopThread = new GameLoopThread(this);
int id = 0;
for(int x = 0; x<3; x++){
for(int y = 0; y<4 ; y++){
MoleSprite mole = new MoleSprite(this, x*WIDTH/3, HEIGHT/6+y*HEIGHT/6, FRONT);
mole.setId(id);
id++;
moles.add(mole);
}
}
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry=true;
gameLoopThread.setRunning(false);
while(retry){
try{
gameLoopThread.join();
retry=false;
}catch(InterruptedException i){
}
}
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
});
}
Sprite's constructor:
public MoleSprite(ToposGameView gameView, int x, int y, int direction) {
super(gameView.getContext()); //TODO
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.bad1);
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.x=x;
this.y= y;
this.setClickable(true);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
setOnClickListener(this);
setOnTouchListener(this);
//I don't know what else to do!
}
It's my first question, please ask me for more info.
Edit1:
public class MoleSprite extends View implements OnClickListener, OnTouchListener{
public class ToposGameView extends SurfaceView{
Your mixing Surface drawing with View drawing. Surfaces are great for rapid asynchronous redraws (such as games), but they are not View containers. That is, there is no addView method on SurfaceView that is required for events and layouts.
As such, you will need to implement onClick handling on your SurfaceView and manually implement the detection of which Sprite is being clicked (e.g., is the click event within the sprite's x/y/width/height bounding box).
Also, it doesn't make sense for MoleSprite to extend View if used this way. I expect you'll want to make your own Sprite base class to support the bounding boxes and drawing callbacks. You can also add the onClick(..) interface to the Spirte base class, but you'll probably also want to keep separate lists for drawable/moveable/clickable items to optimize your list iterations as you develop your game.
Good luck!
i don't know what your GameLoopThread is doing, but it should be calling your surface's onDraw method, and updatePhysics method.
the update physics will loop through your sprites and give them information, like the current game time, so they can move the proper distance, change the animation frame, or whatever.
for a sprite base class I use something like this (but mine handles animations, accelerations and other stuff):
public class Sprite {
private Rect mScreenRect;
public Sprite() {
// init some stuff here, if you need it
// especially, somewhere in your init functions
// set your bounding rect
this.mScreenRect = Rect(xl, yt, xr, yb);
}
setStuff(int thing) {
// like setX(), setY()
}
// here is the good stuff
public boolean isTouched(int x, int y) {
if(mScreenRect.contains(x, y))
return true;
else
return false;
}
// also include a function to draw the graphic
public void drawGraphic(Canvas canvas) {
canvas.drawBitmap(mBitmap, mScreenRect.left, mScreenRect.top, null);
}
}
then, in your surface view you need to use the:
#Override
public boolean onTouchEvent(MotionEvent event) {
// this setup will move the sprite on the screen
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(sprite.isTouched(event.getX(), event.getY()) {
// do your stuff
}
break;
case MotionEvent.ACTION_MOVE:
// handle the moving pointer
sprite.setCoords(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
// handle the exiting pointer
sprite.setCoords(event.getX(), event.getY());
break;
}
}
then in the surface view again:
#Override
public void onDraw(Canvas canvas) {
sprite.drawGraphic(canvas)
}
there are other posts that cover this in a more detailed manner, but this will get you started.