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);
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
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 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.
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());
}
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.