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.
}
}
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'm trying to create a game and it's my first time. My game is a 2D side scroller and is about the player in space avoiding the incoming meteors. I have successfully managed to get the meteors spawning randomly on the x and y axis off screen and re position once it has gone pass the screen.
But the problem I face now is sometimes the spawn of the meteors will clump together which I don't want. How do I get the meteors to spawn at a certain distance from each other so they don't clump together. I couldn't find any good tutorials or if anyone can point me to the right direction. Below are my codes so far.
Meteor Class
public class Meteors {
private Texture bigMeteor;
private Vector2 posBigMeteor;
private Random yrand;
//Constructor
public Meteors(float x){
bigMeteor = new Texture("meteor.png");
yrand = new Random();
//Spawn location of meteor
posBigMeteor = new Vector2(x, yrand.nextInt(AstroDemo.HEIGHT/2 - bigMeteor.getHeight()));
}
public Texture getBigMeteor() {
return bigMeteor;
}
public Vector2 getPosBigMeteor() {
return posBigMeteor;
}
//Reposition the meteors
public void reposition(float x){
posBigMeteor.set(x, yrand.nextInt(AstroDemo.HEIGHT/2 - bigMeteor.getHeight()));
}
}
PlayState Class
public class PlayState extends State {
//Total meteor count on screen
private static final int METEOR_COUNT = 8;
private Naught naught;
private Texture bg;
private Random xrand;
private Array <Meteors> meteors;
public PlayState(GameStateManager gsm) {
super(gsm);
//Starting co-ordinates of main character (Naught)
naught = new Naught(50, 100);
//Setting viewport of the camera
cam.setToOrtho(false, AstroDemo.WIDTH/2, AstroDemo.HEIGHT/2);
bg = new Texture("bg.png");
xrand = new Random();
meteors = new Array <Meteors>();
//Spawn meteors randomly off screen
for (int i = 1; i <= METEOR_COUNT; i++){
meteors.add(new Meteors(AstroDemo.WIDTH/2 + (xrand.nextInt(300))));
}
}
#Override
protected void handleInput() {
//If screen/mouse is held
if(Gdx.input.isTouched()){
//Main Character jumps/flys
naught.jump();
}
}
#Override
public void update(float dt) {
handleInput();
naught.update(dt);
//If meteors are left side of the screen, re-position to the right side of the screen
for(Meteors meteor : meteors){
if (cam.position.x - (cam.viewportWidth/2) > meteor.getPosBigMeteor().x + meteor.getBigMeteor().getWidth()){
meteor.reposition(meteor.getPosBigMeteor().x + (AstroDemo.WIDTH/2 + 20 + (xrand.nextInt(300))));
}
}
cam.position.x = naught.getPosition().x + 80;
cam.update();
}
#Override
public void render(SpriteBatch sb) {
//Adjust the spritebatch for co-ordinate system in relation to camera
sb.setProjectionMatrix(cam.combined);
sb.begin();
//Draw background where the camera is
sb.draw(bg, cam.position.x - (cam.viewportWidth/2), 0);
sb.draw(naught.getTexture(), naught.getPosition().x, naught.getPosition().y);
for (Meteors meteor : meteors) {
sb.draw(meteor.getBigMeteor(), meteor.getPosBigMeteor().x, meteor.getPosBigMeteor().y);
}
sb.end();
}
#Override
public void dispose() {
}
}
create a array of predefined value for your y position and then get value randomly from that array.
or
Divide height into sub portion then get random value from that portion so that each random value not collide with other value.
I’m trying to make a scrollwheel component like this in LibGDX:
I’m using ScrollPane since it has input and fling handling built in. I have an image for the scrollwheel that is divided into 14 sections, the scrollpane itself is two sections shorter so that there will be one section on the right and left sides that it can scroll to in either direction. Once the scroll position reaches the end in either direction I want to reset the scroll position back to the center. Doing this over and over again should create the illusion of an infinite scrolling wheel (hopefully).
The problem I’m having is how to position the ScrollPane in code to reset the image once it reaches either end. So far nothing I have tried to set the scroll position has worked. I’ve tried setScrollX() and scrollTo() methods. I’ve also tried setting the size of the scrollpane to be various sizes (same size as image and two sections smaller than the image). I’ve tried calling layout, invalidate, and pack on the scrollpane to make sure it is laid out correctly before I set the scroll value. I thought that updateVisualScroll() might force it to update the scroll position, but this also has no effect.
No matter what I do it simply ignores all of my calls to change the scroll position so I’m clearly missing something. In my code below I'm trying to get the scrollwheel to start in the center of the image and instead it's starting position is all the way at the left.
I also need to be able to get the current scroll position to detect when it has reached either end. I tried overriding the act() method and printing out scrollPane.getX(), but this value was always “0” even when I manually clicked and dragged it to scroll the ScrollPane.
The scrolling does work when manually clicking and dragging, so I believe the ScrollPane is set up correctly, I just can’t get it to scroll within the code.
Here is my code, and for simplicity I took all of my experimentation code out because none of my experimenting worked.
public class MyScrollWheel extends Container<ScrollPane> {
private ScrollPane scrollPane;
private Image image;
private int scrollOffset;
public MyScrollWheel(){
Texture texture = new Texture(Gdx.files.internal("internal/scrollwheel.png"));
image = new Image(texture);
scrollOffset = (int)(image.getWidth()/14);
scrollPane = new ScrollPane(image);
scrollPane.setOverscroll(false, false);
setActor(scrollPane);
size(image.getWidth()-(scrollOffset*2), image.getHeight());
scrollPane.setScrollX(scrollOffset); // << this doesn't scroll
scrollPane.updateVisualScroll();
}
}
Well, I hopefully managed to get something you can build upon. What I simply did was extending actor and have it accept a Texture so I could use Texture.wrap and have it draw with SpriteBatch.draw(). I am able to keep scrolling it now and based on the scroll delta you can figure out how far it has been scrolled. I don't see any need to reset the wheel but if you really want to you can just do wheel.setScroll(0);.
One limitation is that it is not a Drawable so it cannot be scaled like a NinePatch. You have to give it a plain wheel texture draw it the size you want it to spear, you can add normal scaling however and keep aspect ratio manually. Then add the sides to it and perhaps overlay a gradient on those to create depth.
ScrollWheel:
public class ScrollWheel extends Actor {
Texture wheelTexture;
private int scroll = 0;
public int getScroll() {
return scroll;
}
public void setScroll(int scroll) {
this.scroll = scroll;
}
public ScrollWheel(Texture texture)
{
wheelTexture = texture;
wheelTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
setWidth(texture.getWidth());
setHeight(texture.getHeight());
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
batch.draw(wheelTexture, getX(), getY(), scroll, 0,
wheelTexture.getWidth(), wheelTexture.getHeight());
}
}
usage in a Screen:
public class TestScreen implements Screen {
Stage stage;
ScrollWheel wheel;
public TestScreen() {
stage = new Stage();
Table t = new Table();
t.setFillParent(true);
stage.addActor(t);
wheel = new ScrollWheel(new Texture("hud/wheel_part.png"));
wheel.addListener(new DragListener() {
#Override
public void drag(InputEvent event, float x, float y, int pointer) {
super.drag(event, x, y, pointer);
wheel.setScroll(wheel.getScroll() + (int)getDeltaX());
}
});
t.add(wheel);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(.3f, .36f, .42f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
//...Other mandatory screen methods...
}
So just create a wheel texture that is tillable and include that with the ScrollWheel constructor. It will draw the wheel in the center of the screen if you use this exact code.
The scroll variable essentially holds the amount of scroll so if you you want limit this between 0 and 100 you would just add this functionality in setScroll().
if (scroll > 100) scroll = 100;
else if (scroll < 0) scroll = 0;
You could then add a step to it. So if you want to rotate a image with the slider you could set the rotation by scroll * 3,6f or scroll * (maxScroll / maxStep)
I really liked the way this turned out, I will be using this for my slider in the future :D. I have extended and altered it a bit already and you can see my implementation here: https://youtu.be/RNLk5B-VfYg
Expanding on Menno Gouw's scroll wheel, I've added some more features:
Fling support with setting for fling time
Precision setting to adjust sensitivity of the wheel
Takes a Drawable
Compatible for use inside of a ScrollPane
NOTE: For my purposes I have it take in a Label in the constructor, but this can easily be changed if you don't want it tied to a Label.
Here is a video I recorded on phone demoing the scroll wheel.
https://www.youtube.com/watch?v=RwVrez4BZsY&feature=youtu.be
- EDIT 1: Layout bugs have now been fixed (hopefully). It now updates its position when moved in a ScrollPane and the Drawables are clipped to the border of the Actor.
- EDIT 2: Added support for a stationary drawable for shading and a method to change the wheel's direction (setRightPositiveDirection()).
public class ScrollWheel extends Actor {
private Drawable wheelDrawable, wheelShading;
private Label label;
private int unscaledScrollValueX=0, scrollValueX=0;
private boolean isNotEdge;
private int precision=40;
private int direction=1;
private int minValue=Integer.MIN_VALUE, maxValue=Integer.MAX_VALUE;
// MANUAL SCROLL
private int separator;
private int wheelWidth;
// FLING
private float flingTimer, flingTime=1f;
private float velocityX;
public ScrollWheel(Drawable wheelDrawable, Drawable wheelShading, Label label) {
this.wheelDrawable = wheelDrawable;
this.wheelShading = wheelShading;
this.label = label;
wheelWidth = (int)wheelDrawable.getMinWidth();
separator = wheelWidth;
setWidth(wheelDrawable.getMinWidth());
setHeight(wheelDrawable.getMinHeight());
// stops ScrollPane from overriding input events
InputListener stopTouchDown = new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
event.stop();
return false;
}
};
addListener(stopTouchDown);
ActorGestureListener flickScrollListener = new ActorGestureListener() {
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
updateScroll(deltaX);
}
public void fling (InputEvent event, float x, float y, int button) {
if (Math.abs(x) > 150) {
flingTimer = flingTime;
velocityX = x;
}
}
public boolean handle (Event event) {
if (super.handle(event)) {
if (((InputEvent)event).getType() == InputEvent.Type.touchDown) flingTimer = 0;
return true;
}
return false;
}
};
addListener(flickScrollListener);
}
private void updateScroll(float delta){
unscaledScrollValueX += (delta * direction);
scrollValueX = (int)(unscaledScrollValueX / precision);
isNotEdge = true;
if (scrollValueX <= minValue){
scrollValueX = minValue;
unscaledScrollValueX = minValue * precision;
isNotEdge = false;
}
else if (scrollValueX >= maxValue){
scrollValueX = maxValue;
unscaledScrollValueX = maxValue * precision;
isNotEdge = false;
}
if (isNotEdge){
separator += delta;
if (separator <= 0){
separator = wheelWidth;
}
else if (separator >= wheelWidth) {
separator = 0;
}
}
updateLabel();
}
private void updateLabel(){
label.setText("" + scrollValueX);
}
public void setMinValue(int minValue){ this.minValue = minValue; }
public void setMinValueToNone(){ minValue=Integer.MIN_VALUE; }
public void setMaxValue(int maxValue){ this.maxValue = maxValue; }
public void setMaxValueToNone(){ minValue=Integer.MAX_VALUE; }
public void setFlingTime(float flingTime){ this.flingTime = flingTime; }
public void setPrecision(int precision){ this.precision = precision; }
public void setRightPositiveDirection(boolean rightPositive){ direction = (rightPositive) ? 1 : -1; }
#Override
public void act(float delta){
super.act(delta);
boolean animating = false;
if (flingTimer > 0) {
float alpha = flingTimer / flingTime;
updateScroll(velocityX * alpha * delta);
flingTimer -= delta;
if (flingTimer <= 0) {
velocityX = 0;
}
animating = true;
}
if (animating) {
Stage stage = getStage();
if (stage != null && stage.getActionsRequestRendering()){
Gdx.graphics.requestRendering();
}
}
}
#Override
public void draw(Batch batch, float parentAlpha){
super.draw(batch, parentAlpha);
batch.flush();
if (clipBegin(getX(), getY(), getWidth(), getHeight())){
wheelDrawable.draw(batch, getX() + separator - wheelWidth, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelDrawable.draw(batch, getX() + separator, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelShading.draw(batch, getX(), getY(), wheelShading.getMinWidth(), wheelShading.getMinHeight());
batch.flush();
clipEnd();
}
}
}
I am creating an Android Game using LibGdx. It is a platformer and the map is tiled based. To test the movements of the player I used Key inputs and the desktop version of the game works fine. I created some buttons in scene2d and added them as an actor to the scene so that the game has movement buttons when played on Android devices. The buttons work as "System.out.print" shows. Problem is: the buttons and the player are each created in a different class. I can't seem to modify the velocity (and so the movement) of the Player from the class that holds the buttons. For that I need to change the velocity and speed etc. to static, which gives me strange errors on an Android device (Player won't show, or disappears after a frame). I am not sure how to fix this and what is the actual cause of this error. Here is some of the code of the different Classes:
Main Class (MyGdxGame) only included one button as an example.
public class MyGdxGame extends Game implements ApplicationListener {
private Skin skin;
private Stage stage;
#Override
public void create() {
setScreen(new Play());
skin = new Skin(Gdx.files.internal("ui/defaultskin.json"));
stage = new Stage();
Gdx.input.setInputProcessor(stage);
//Button Right
TextButton buttonRight = new TextButton("Right", skin, "default");
buttonRight.setWidth(50f);
buttonRight.setHeight(50f);
buttonRight.setPosition(Gdx.graphics.getWidth() /2 - 250f, Gdx.graphics.getHeight()/2 - 200f);
buttonRight.addListener(new ClickListener(){
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Hold");
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.print("Released");
}
});
stage.addActor(buttonRight);
}
Play Class
public class Play implements Screen {
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera;
private Player player;
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.position.set(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 0);
camera.update();
renderer.setView(camera);
renderer.render();
renderer.getSpriteBatch().begin();
player.draw(renderer.getSpriteBatch());
renderer.getSpriteBatch().end();
}
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
}
#Override
public void show() {
map = new TmxMapLoader().load("maps/map.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
camera = new OrthographicCamera();
player = new Player(new Sprite(new Texture("data/jack2.png")), (TiledMapTileLayer) map.getLayers().get(0));
player.setPosition(2 * player.getCollisionLayer().getTileWidth(), 10 * player.getCollisionLayer().getTileHeight());
}
Player Class
public class Player extends Sprite implements InputProcessor{
// the movement velocity //
public Vector2 velocity = new Vector2();
public float speed = 60 * 2, gravity = 60 * 1.8f;
private boolean canJump;
private TiledMapTileLayer collisionLayer;
private String blockedKey = "blocked";
public Player(Sprite sprite, TiledMapTileLayer collisionLayer){
super(sprite);
this.collisionLayer = collisionLayer;
}
#Override
public void draw(SpriteBatch spriteBatch) {
update(Gdx.graphics.getDeltaTime());
super.draw(spriteBatch);
}
So the button has a working ClickListener, but I don't know how it can modify the players velocity. Any help is welcome.
You just need to have some way to access that player instance from the class containing the button. In my games I make a static World class which can be accessed from anywhere in the program. Through the world class I can access the player instance. That's just how I do it, you may find another way. You say your program has errors on android device when making certain parameters static? Do you mean it compiles but it just doesn't work the way you expect? If that's the case, there is probably just a bug in how you're modifying the position or velocity of the player.
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