I would like to remove the body when the item is clicked. As you see i have it set up as a wallfixture.
When the item is clicked the sprite is removed, now i just would like to remove the body also..
public void addSprites(Scene scene, int x,int y,int width,int height,String type,Body body){
Sprite sprite = null;
if(type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_WOOD)) {
sprite = new Sprite(x, y, width, height, this.wood, this.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
mScene.detachChild(this);
mPhysicsWorld.destroyBody(woodBody);
return true;
}
};
final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f);
woodBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld, sprite, BodyType.StaticBody, wallFixtureDef);
mScene.registerTouchArea(sprite);
Log.e("TYPE", "Wood");
}
scene.attachChild(sprite);
}
What i want to do is when the item is clicked i would like to remove the sprite & the body it is attached to. The code i have works but the only problem is it removes ALL of the bodies, i use the method to attach items to a level, so its a total of 3 items, and when one is clicked the body is removed from ALL of the sprites, when it should just be the one clicked.
Anyone know how to go about doing this?
I am not sure but probably that happens because you use the same variable for all bodies
woodBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld, sprite, BodyType.StaticBody, wallFixtureDef);
To do good connection between body and sprite I suggest you to extend Sprite and declare body variable inside your class. For example I do this in that way
public class Ball extends Sprite{
final FixtureDef ballFixtureDef = PhysicsFactory.createFixtureDef(1.0f, 0.0f, 0.0f, false, Main.CATEGORYBIT_BALL, Main.MASKBITS_BALL, (short)0);
Body body;
float velocityX, velocityY;
int type;
public Ball(float pX, float pY, TextureRegion pTextureRegion, PhysicsWorld pWorld, float velocityX, float velocityY, int type)
{
super(pX, pY, pTextureRegion);
this.type = type;
this.velocityX = velocityX;
this.velocityY = velocityY;
body = PhysicsFactory.createCircleBody(pWorld, this, BodyType.DynamicBody, ballFixtureDef);
body.setUserData(Ball.this);
pWorld.registerPhysicsConnector(new PhysicsConnector(this, body, true, true));
}
}
and method for destroy sprite with body
private void destroyBall(final Ball ball)
{
this.runOnUpdateThread(new Runnable(){
#Override
public void run() {
final Body body = ball.body;
mPhysicsWorld.unregisterPhysicsConnector(mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(ball));
mPhysicsWorld.destroyBody(body);
mScene.detachChild(ball);
ballsList.remove(ball);
}});
}
and you just create object in that way
Ball b = new Ball(float pX, float pY, TextureRegion pTextureRegion, PhysicsWorld pWorld, float velocityX, float velocityY, int type)
{
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY)
{
destroyBall(this);
}
}
I'm not exactly sure, but I think you need to flag items or objects that need to be removed first. Then when the game updates it should go through all of the objects and check which ones are flagged and then remove them. I'm new to this too but here goes nothing:
So a good way to do this in AndEngine is to first make an IUpdateHandler like so:
/**
* This wil get called every frame and is placed inside of your
* main game activity or where ever you want.
**/
public IUpdateHandler getCollisionUpdateHandler(){
return new IUpdateHandler(){
#Override
public void onUpdate(float pSecondsElapsed) {
// loop through all of your sprites
for(int i=0; i<GameActivity.this.spriteList.length; i++) {
//if sprite is flagged for deletion, begin removal
if( GameActivity.this.spriteList.get(i).isDelete()){
// get the next sprite to delete
final mSprite Object = GameActivity.this.spriteList.get(i);
// can remove it from the list now
Game.this.spriteList.remove(i);
final Scene scene = GameActivity.this.mEngine.getScene();
final Body body = GameActivity.this.mPhysicsWorld.getPhysicsConnectorManager().findBodyByShape(Object);
mPhysicsWorld.destroyBody(body);
//scene.getLayer(0).removeEntity(Object);
//scene.getLayer(1).removeEntity(Object);
scene.detachChild( Object );
}
}
}
}
}
Then simply register that update handler. Like so:
mScene.registerUpdateHandler( this.getCollisionUpdateHandler() );
So now whenever you want to delete a sprite (when it's pressed) then you simply change your method to:
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
MainActivity.spriteList.add( this );
this.delete = true;
return true;
}
Hope that helps. Here's where I got it from: (I simply tried to make it fit your problem :) )
www.andengine.org/forums/tutorials/box2d-collision-and-removal-t523.html
Related
I made a game in which a turtle had to collect StarFish but when I added walking animation it doesn't work. What happens is it only shows up the first frame and the whole animation doesn't play and I get no errors.
And I'm using diffrent images to load animation
Here is my animation method-
// used to load animation from multiple files
public Animation loadAnimationFromFiles(String[] fileNames, float frameDuration, boolean loop)
{
int fileCount = fileNames.length;
Array<TextureRegion> textureArray = new Array<TextureRegion>();
for (int n = 0; n < fileCount; n++)
{
String fileName = fileNames[n];
Texture texture = new Texture( Gdx.files.internal(fileName) );
texture.setFilter( TextureFilter.Linear, TextureFilter.Linear );
textureArray.add( new TextureRegion( texture ) );
}
Animation anim = new Animation(frameDuration, textureArray);
if (loop) {
//setAnimation(anim);
System.out.println("animation run");
anim.setPlayMode(Animation.PlayMode.LOOP);
}
else {
anim.setPlayMode(Animation.PlayMode.NORMAL);
}
if (animation == null) {
System.out.println("animation null");
setAnimation(anim);
}
return anim;
}
And here is my turtle class where I used animation-
public class Turtle extends BaseActor
{
public Turtle(float x, float y, Stage s)
{
super(x, y, s);
String[] fileNames = {
"turtle2.png",
"turtle.png",
};
loadAnimationFromFiles(fileNames, 0.1f, true);
}
public void act(float dt)
{
super.act(dt);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
this.moveBy(-5,0);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
this.moveBy(5,0);
if (Gdx.input.isKeyPressed(Input.Keys.UP))
this.moveBy(0,5);
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
this.moveBy(0,-5);
}
}
You just created the animation, but never used it. To make use of the animation you need to get the textures from it, by measuring the delta time, that passed.
Your turtle class should look more like this:
public class Turtle extends BaseActor
{
private Animation<TextureRegion> animation;//store the animation in a field to use it
private float time;//use a timer for the animation to be played
public Turtle(float x, float y, Stage s)
{
super(x, y, s);
String[] fileNames = {
"turtle2.png",
"turtle.png",
};
//store the animation to the field instead of just creating it
animation = loadAnimationFromFiles(fileNames, 0.1f, true);
//set the animations timer
time = 0;
}
public void act(float dt)
{
//increase the time since the animation was started by the delta time
time += dt;
//tell the animation how much time passed, so it can give you the current animation texture
TextureRegion texture = animation.getKeyFrame(time);
//TODO draw texture
//I assume the super.act call also draws a texture; that should be deleted to not draw over the already created texture
super.act(dt);
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
this.moveBy(-5,0);
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT))
this.moveBy(5,0);
if (Gdx.input.isKeyPressed(Input.Keys.UP))
this.moveBy(0,5);
if (Gdx.input.isKeyPressed(Input.Keys.DOWN))
this.moveBy(0,-5);
}
}
So I am using onDraw in a custom View class to draw shapes on a RelativeLayout + TableLayout all that works fine, and I have another class that I use to draw lines from Point A to Point B etc. example below:
My Goal:
If I drag my finger from Point A (objectA) to Point B(objectB), how can I delete those 2 View Objects from the canvas? I added a method:
objectA.delete();
objectB.delete();
that should delete both A and B when I drag my finger through MotionEvent, but it only deletes one and not the other, so i am thinking it's not retroactive?
Codes below:
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
/// get the child that corresponds to the first touch
DotView objectA = getChildForTouch((TableLayout) v, x, y);
return true;
case MotionEvent.ACTION_MOVE:
///used the x - y to get the object for every other shape the user`S finger passes over.
DotView objectB = getChildForTouch((TableLayout) v, x, y);
/// just update positions
line.setCoords(mStartX, mStartY, (int) x, (int) y);
objectA.delete(); ///Delete first shape
objectB.delete(); ///Delete second shape
break;
case MotionEvent.ACTION_UP:
///Gets the last shape where the user released their fingers
endView = getChildForTouch((TableLayout) v, x, y);
break;
Delete method inside the: DotView extends View class:
private static class DotView extends View {
private static final int DEFAULT_SIZE = 100;
private Paint mPaint = new Paint();
private Rect mBorderRect = new Rect();
private Paint mCirclePaint = new Paint();
private int mRadius = DEFAULT_SIZE / 4;
public DotView(Context context) {
super(context);
mPaint.setStrokeWidth(2.0f);
mPaint.setStyle(Style.STROKE);
mPaint.setColor(Color.RED);
mCirclePaint.setColor(Color.CYAN);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.parseColor("#0099cc"));
mBorderRect.left = 0;
mBorderRect.top = 0;
mBorderRect.right = getMeasuredWidth();
mBorderRect.bottom = getMeasuredHeight();
canvas.drawRect(mBorderRect, mPaint);
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2,
mRadius, mCirclePaint);
}
public void delete(){
mPaint.setColor(Color.TRANSPARENT);
}
}
Just something simple to fake delete the circles
Thanks in advance guys.. more codes can be provided if need be.
Edit: If I can accomplish this in any other way please feel free to share. (Draw circles on a Grid and delete the ones I used my finger to draw my line over)
First of all try changing your delete() method to this:
public void delete(){
mPaint.setColor(Color.TRANSPARENT);
invalidate();
}
You need to let your View know that you want it to redraw itself (that's why the invalidate() call).
For example a dynamic body is in a corner and is infinitely walking towards a wall (needs to be a static body) in that corner. If another body is walking towards the same direction, and is colliding with the first body, the collision will be completely ignored. It's the only situation where this happens.
Under here the photo:
By the next worldstep, the green rectangle overlaps the red ball. If there wasn't a static body, the collision works fine.
Thanks in advance.
It is specific of Box2D. If One dynamic body is moving towards another dynamic body perpendicularly and there's a static body on their path, dynamic bodies will overlap each other anyway.
To fix this bug, you can use contact listener to catch the moment when bodies collide and directly set the position of the green body according to the position of the red body. Something like that:
public class CoreClass extends Game {
Array<Body> bodies = new Array<Body>();
World world = new World(new Vector2(0.0f, 0.0f), true);
Body bodyRed;
Body bodyGreen;
private float prevX;
private float prevY;
#Override
public void create() {
BodyDef bodyBD = new BodyDef();
bodyBD.type = BodyType.DynamicBody;
FixtureDef bodyFD = new FixtureDef();
bodyFD.density = 1.0f;
bodyFD.friction = 1.0f;
bodyFD.restitution = 1.0f;
bodyRed = world.createBody(bodyBD);
bodyGreen = world.createBody(bodyBD);
bodyRed.createFixture(bodyFD);
bodyGreen.createFixture(bodyFD);
prevX = bodyGreen.getPosition().x; prevY = bodyGreen.getPosition().y;
world.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
world.getBodies(bodies);
bodies.get(contact.getChildIndexA()).getPosition().set(prevX, prevY);
}
#Override
public void endContact(Contact contact) {
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
}
#Override
public void render() {
super.render();
prevX = bodyGreen.getPosition().x;
prevY = bodyGreen.getPosition().y;
world.step(1/45f, 2, 6);
}
I have a screen with 8 different static buttons on it. I have written a class to make this easy:
public class TouchButton extends Actor{
Texture texture;
float actorX, actorY;
int actorWidth, actorHeight;
public boolean started = false;
public TouchButton(String argButtonID, float argActorX, float argActorY, int argWidth, int argHeight){
String file = argButtonID;
texture = new Texture(Gdx.files.internal(file));
this.actorX = argActorX;
this.actorY = argActorY;
this.actorWidth = argWidth;
this.actorHeight = argHeight;
setBounds(actorX, actorY, argWidth, argHeight);
addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
((TouchButton)event.getTarget()).started = true;
Gdx.app.debug("BUTTON", "pressed" );
Gdx.input.vibrate(100);
return true;
}
});
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(texture,actorX,actorY,this.actorWidth, this.actorHeight);
}
#Override
public void act(float delta){
if(started){
actorX+=5;
}
}
}
As you can see in the code above, I am writing out a message to the LogCat, but I have been unable to work out how to determine which of the buttons was pressed.
In my game, a bit like "simon", I wish to display a colour or shape, and then get the player to click the correct colour matching button - so I will need to know which button they have pressed.
My buttons are instantiated as follows, my main Game Screen which Implements Screen.
purpleButton = new TouchButton("shapes/purple.jpg", 0.0f, stage.getHeight() - 256, 256, 256);
purpleButton.setTouchable(Touchable.enabled);
stage.addActor(purpleButton);
pinkButton = new TouchButton("shapes/pink.jpg", stage.getWidth() - 256, 0.0f, 256, 256);
pinkButton.setTouchable(Touchable.enabled);
stage.addActor(pinkButton);
Any help would be appreciated here.
How can I listen in my main game class for these button touch events, and determine which one was pressed?
Many Thanks
James
You could pass a identifier index as a parameter when creating your TouchButton object.
Then when a button is pressed simply set the static int lastPressIndex to the index of the button being pressed.
public TouchButton(String argButtonID, float argActorX, float argActorY, int argWidth, int argHeight, int buttonIndex)
Define a static variable representing the button that was pressed:
public static int lastPressIndex = 0;
Then in your game loop (render method) you could check the value of lastButtonPressIndex and see which button pass pressed by it's index.
Your TouchButton class would look something like this:
public class TouchButton extends Actor{
Texture texture;
float actorX, actorY;
int actorWidth, actorHeight;
public boolean started = false;
private int buttonIndex = 0; // New stuff
public static int lastPressIndex = 0; // New stuff/
public TouchButton(String argButtonID, float argActorX, float argActorY, int argWidth, int argHeight, int buttonIndex){ // new parameter
String file = argButtonID;
texture = new Texture(Gdx.files.internal(file));
this.actorX = argActorX;
this.actorY = argActorY;
this.actorWidth = argWidth;
this.actorHeight = argHeight;
this.buttonIndex = buttonIndex; // new stuff
setBounds(actorX, actorY, argWidth, argHeight);
addListener(new InputListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
((TouchButton)event.getTarget()).started = true;
Gdx.app.debug("BUTTON", "pressed" );
TouchButton.lastPressIndex = this.buttonIndex; // new stuff
Gdx.input.vibrate(100);
return true;
}
});
}
#Override
public void draw(Batch batch, float alpha){
batch.draw(texture,actorX,actorY,this.actorWidth, this.actorHeight);
}
#Override
public void act(float delta){
if(started){
actorX+=5;
}
}
}
When creating your TouchButton instances you simply keep track of which button belongs to which index. A HashMap would be the way to go.
HashMap<Integer, TouchButton) holdsButtons = new HashMap<Integer, TouchButton>();
holdsButtons.put(1, new TouchButton("shapes/purple.jpg", 0.0f, stage.getHeight() - 256, 256, 256, 1)); // Created the TouchButton and made a relation between the object and an Integer value, in this case 1.
in your render method:
public void render() {
if(TouchButton.lastPressIndex > 0) { // Making sure a button is actually pressed.
TouchButton pressedButton = holdsButtons.get(TouchButton.lastPressIndex);
// Now you know which button was pressed.
TouchButton.lastPressIndex = 0; // Reset the value.
}
}
I'm having a hard time getting events working with my Actor in libgdx. I'm using nightly builds.
My stage is setup in the show() method of a Screen subclass:
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
Gdx.input.setInputProcessor(stage);
TestActor actor = new TestActor();
stage.addActor(actor);
And my actor class looks like:
class TestActor extends Actor {
private Sprite sprite;
private TextureAtlas atlas;
public TestActor() {
atlas = new TextureAtlas(Gdx.files.internal("textures/images-packed.atlas"));
sprite = atlas.createSprite("logo-96");
setTouchable(Touchable.enabled);
addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchDown()");
return true; // must return true for touchUp event to occur
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.debug(TestGame.TAG, "TestActor.touchUp()");
}
});
}
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(sprite, getX(), getY());
}
}
The events don't seem to fire. Oddly enough, I've used built-in UI widgets like the TextButton and can get those events to fire just fine. Can anybody see what I'm doing wrong?
You should also setBounds to your actor.
best way to do it (if you want the same size as your texture)
add these lines to your constructor :
setWidth(sprite.getWidth());
setHeight(sprite.getHeight());
setBounds(0, 0, getWidth(), getHeight());
notice you can also set the location of the bounds with the first 2 parameters.