I was on a roll last night, when I came across the issue of the ButtonSprite. I could have sworn I've done this before - it seems so simple - but using the code that AndEngineExamples provides doesn't really make sense and comes up with errors (for instance - why does a vague "run()" method create the response to every single touch event?).
So I did something that seemed to make sense.
private void loadScenes()
{
mainScene = new Scene();
menu = new Sprite(0, 0, menuTextureRegion, mEngine.getVertexBufferObjectManager()){
#Override
protected void preDraw(GLState pGLState, Camera pCamera)
{
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
};
newgamebutton = new ButtonSprite(25, 200, newgameTextureRegion, mEngine.getVertexBufferObjectManager());
multiplayerbutton = new ButtonSprite(25, 310, multiplayerTextureRegion, mEngine.getVertexBufferObjectManager());
menu.setScale(1.65f);
menu.setPosition((CAMERA_WIDTH - menu.getWidth()) * 0.5f, (CAMERA_HEIGHT - menu.getHeight()) * 0.5f);
mainScene.attachChild(menu);
mainScene.attachChild(newgamebutton);
mainScene.attachChild(multiplayerbutton);
mainScene.registerTouchArea(multiplayerbutton);
mainScene.setTouchAreaBindingOnActionDownEnabled(true);
multiplayerbutton.onAreaTouched(mButtonTouched, multiplayerbutton.getWidth(), multiplayerbutton.getHeight());
if(mButtonTouched.isActionDown()) {
mainScene.detachChild(menu);
mainScene.detachChild(multiplayerbutton);
}
}
It seems to make good sense. When the "multiplayer button" is pressed, it gives you the mButtonTouched, and when that's pressed down... it detaches the menu and multiplayer button. This is obviously just me testing things, and not part of any actual project because I'm just learning, but I get a null pointer exception and the app right closes before displaying the "Menu Scene", which obviously normally works. Also, on various sites it says that I should put "public boolean" before multiplayerbutton, but Eclipse won't have that.
I'm sure you guys have already figured this out, but I'm suuuuuuper new to AndEngine. Thanks for any help, guys!
After looking at the code I believe you wanted to do something like this:
ButtonSprite button = new ButtonSprite(25, 310, multiplayerTextureRegion, mEngine.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if(pTouchEvent.isActionDown()) {
mainScene.detachChild(menu);
mainScene.detachChild(multiplayerbutton);
}
return super.onAreaTouched(pTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
}
};
Your code doesn't work because the last if statement doesn't really make sense - it is checking whether the button is pressed when the method loadScenes() executes. I suggest you read up on anonymous inner classes, it took me a long time to figure out that using them is a valid and useful approach in AndEngine.
Here is a primitive example of a different way of managing buttons:
mScene.setOnAreaTouchListener(new IOnAreaTouchListener() {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, ITouchArea pTouchArea, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if (pTouchArea.equals(button) {
doSomething();
return true;
}
return false;
}
});
Please note that this only works when touching Shapes, if you want to detect touch events outside of Shapes, you need to use IOnSceneTouchListener instead.
Related
I have the following code:
Sprite sPlayer = new Sprite(800 / 2, 480 / 2,
playerTextureRegion,
engine.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent tEvent, final float X,
final float Y)
{
if ( tEvent.isActionDown() )
// Some code
return true;
};
};
gameScene.registerTouchArea(sPlayer);
gameScene.setTouchAreaBindingOnActionDownEnabled(true);
gameScene.attachChild(sPlayer);
When I run it, it gives me error and the app closes
I see most people using gameScene.setTouchBindingEnabled(True)
instead of gameScene.setTouchAreaBindingOnActionDownEnabled(true); but Eclipse doesn't recognize this one and I can't import any package for it. What exactly am I doing wrong?
Thanks in advance for your answers.
According to your comment, you need to use the function runOnUiThread
YourActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(YourActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
or, you can use the function toastOnUiThread :
YourActivity.toastOnUiThread(msg,Toast.LENGTH_SHORT);
where YourActivity is your activity in the game(just pass a reference to it)
I am creating a game using Andengine and in this I want an object flying in the sky to drop bombs below. Currently I am using a timehandler to create both the flying object and the bombs. But its not working properly. The problems I am facing are:
1) Sometimes instead of a single bomb 2 or 3 bombs are dropped.
2) And the bomb objects are also not getting recycled. The code for recycling the object is getting called, but it doesn't seem to work.
I have noticed one thing i.e. suppose, initially I have one flying object that drops a bomb. When the bomb leaves the screen, the recycling code for bomb object gets called once. And after sometime as the flying object leaves the screen it also gets recycled. Now when another flying object is created and it drops the bomb, the code for recycling the bomb is getting called twice. Then for third flying object, the code for recycling the single bomb is getting called thrice and so on.
The code to add flying object is as follows
private void createDragonHandler() {
TimerHandler spriteTimerHandler;
float mEffectSpawnDelay = 10f;
spriteTimerHandler = new TimerHandler(mEffectSpawnDelay, true,
new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
addDragon();
}
});
getEngine().registerUpdateHandler(spriteTimerHandler);
}
public void addDragon() {
Dragon dragon = (Dragon) dragonSpritePool.obtainPoolItem();
if (dragon.getParent() != mainScene)
mainScene.attachChild(dragon);
}
public synchronized Dragon obtainPoolItem() {
dragon = super.obtainPoolItem();
Random rand = new Random();
final int x = (int) (CAMERA_WIDTH + resourceManager.dragonTextureRegion
.getWidth());
int minY = (int) resourceManager.dragonTextureRegion.getHeight();
int maxY = (int) (CAMERA_HEIGHT / 2 - resourceManager.dragonTextureRegion
.getHeight());
int rangeY = maxY - minY;
final int y = rand.nextInt(rangeY) + minY;
dragon.reset();
dragon.setVisible(true);
dragon.setIgnoreUpdate(false);
dragon.animate(150);
dragon.setPosition(x, y);
MoveXModifier mod = new MoveXModifier(15, dragon.getX(),
-dragon.getWidth());
float mEffectSpawnDelay = 5f;
TimerHandler spriteTimerHandler = new TimerHandler(mEffectSpawnDelay,
true, new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
DragonFire dragonFire = BirdShoot.dragonFireSpritePool
.obtainPoolItem(dragon.getX(), dragon.getY());
BirdShoot.mainScene.attachChild(dragonFire);
}
});
dragon.registerEntityModifier(mod.deepCopy());
dragon.setNoHit(0);
PhysicsHandler mPhysicsHandler;
mPhysicsHandler = new PhysicsHandler(dragon);
dragon.setPhysicsHandler(mPhysicsHandler);
dragon.registerUpdateHandler(dragon.getmPhysicsHandler());
BirdShoot.engine.registerUpdateHandler(spriteTimerHandler);
return dragon;
}
`
Where are you writing the code for recycling the sprite objects? According to your problem, I see something fishy there. It might be possible that the code is not getting executed. The code to recycle the sprites must be something like this:-
public void onHandleRecycleItem(Sprite sprite){
super.onHandleRecycleItem(sprite);
// Your code to recycle the object
}
Also it should be called using the following line :
yourPool.recyclePoolItem(spriteObject);
Without seeing your code, it will be hard to help with this. But, this has the smell of things not being done on the updateThread.
Any time you do something that affects AndEngine, be sure you call it via
runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Do your AndEngine changes in here*/
}
});`
Hello everyone I'm trying to develop a game like Jetpack so i want to set a gravity that normally push down and when the user tap the screen the gravity change it push up. I searched for a week a tutorial that explain how to do that but I didn't find what I search. Someone can explain me how to do that or post a link to a tutorial ?
Thank you !!
main = new Sprite(sX, sY, mainTextureRegion);
main.setScale(1);
main.setFlippedHorizontal(true);
scene.attachChild(main);
mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
final Body body = PhysicsFactory.createBoxBody(mPhysicsWorld, main, BodyType.DynamicBody, objectFixtureDef);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(main, body, true, true));
final Vector2 gravity = new Vector2(0, 5f);
mPhysicsWorld.setGravity(gravity);
scene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(float pSecondsElapsed) {
}
#Override
public void reset() {
// TODO Auto-generated method stub
}});
When the user touches the screen, you shouldn't change the gravity because it is not suppose to be done like that.
When he touches the screen, just apply a LinearImpulse (check if it not already at maximum speed) or something like that to make it go upper. The gravity shouldn't change as it should always attract all of your physics objects down. If your change the gravity you change the behavior of all your objects, not only the player one.
EDIT
To have the physics engine to work you have to call the step() method of the PhysicsWorld class at each render. The problem with Andengine is that you don't directly access the render() method as Andengine handle it at all.
So what you have to do is to register a IUpdateHandler on the Engine object that you return in your onLoadEngine() method.
This way the onUpdate() method of the interface will be called at each render and here you can call the step() method to get the physics part to work. The float value tells you about how many seconds elapsed since last render but you don't have to take care of that. The method is called multiple times per second.
Hope it helps.
EDIT 2
I think this should work :
//on the Scene object or on the Engine one
scene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(float pSecondsElapsed) {
mPhysicsWorld.onUpdate(pSecondsElapsed);
}
#Override
public void reset() {}
});
I was trying to make the enemies in my game go up and down; since I'm using a physic body with a Sprite on it I can't use entity modifiers, so I decided give the body a little push using the .setLinearVelocity(float x, float y) method every time its sprite reach a certain point in the screen.
With just one body works great, but I need to have other enemeis (same sprite, different body) spawning every 5 seconds and doing the same thing, but I don't know how to track them... I mean, I don't know how to control if each body reaches the Y location independently from one another...
For example, right now the code is like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
final Sprite rectangle_face = new Sprite(random_x, this.y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face, BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
//I give the body a initial push
rectangle_face_body.setLinearVelocity(0, -5);
//I register an update handler to the sprite to control if it reaches a certain Y value
rectangle_face.registerUpdateHandler(new IUpdateHandler()
{
#Override
public void onUpdate(float pSecondsElapsed)
{
if (rectangle_face.getY() >= y-50)
{
//Here I just use a flag so that later on below I can do the push
MyApp.this.setLinearVelocity = true;
}
}
#Override
public void reset()
{
// TODO Auto-generated method stub
}
});
//Here I register the physic connector and if the flag permits it, I push the body up
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face, rectangle_face_body, true, false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
if(MyApp.this.setLinearVelocity)
{
rectangle_face_body.setLinearVelocity(0, -3);
MyApp.this.setLinearVelocity = false;
}
}
});
this.mscene.attachChild(rectangle_face);
}
With the code like this the first body do what is planned, it moves up and down but as soon as another body pops up, it falls down and the other body goes up because the boolean setLinearVelocity is always set to true, so there is a costant push upwards; when a third body comes in, the second body falls down as well and this last one takes its place going up
With this code I didn't expect much else... but I don't know what else I can try... how can I control this?
Thanks in advance :)
EDIT: Added working code in an anwser below
I suggest you separate the code for the enemy from the code for the update handler. Create a class Enemy that will contain the Sprite and Body, hold your Enemies in an array and override the onUpdate method of your PhysicsWorld so that it goes through the array of Enemies and does what you want to all of them.
Here's a code snippet showing a very simple way of doing this:
mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {}
#Override
public void onUpdate(float pSecondsElapsed) {
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
});
Please note that this may not a very good idea as this code will probably run on a thread different to the one of the physics engine, which could cause all sorts of problems. A better way would be overriding the onUpdate method of PhysicsWorld:
#Override
public void onUpdate(final float pSecondsElapsed) {
super.onUpdate();
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
If you are unsure of what the first snippet means, look up "anonymous inner class".
Ok, here's the final working code (I didn't create a method to check the position or a class for the enemies just because right now I'm just messing around with the mechanics; I'll create a new project when I'm ready to really start):
this.m_PhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
for(int i = 0; i <= MyApp.this.mSpriteCounter; i++)
{
if (rectangle_face[i].getY() >= y-50)
{
final PhysicsConnector spritePhysicsConnector = m_PhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(rectangle_face[i]);
spritePhysicsConnector.getBody().setLinearVelocity(0, -3);
}
}
};
In this code rectangle_face[] is an array of Sprites; each sprite is created like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
rectangle_face[this.mSpriteCounter] = new Sprite(random_x, y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face[this.mSpriteCounter], BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
rectangle_face_body.setLinearVelocity(0, -5);
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face[this.mSpriteCounter], rectangle_face_body, true, false));
this.mscene.attachChild(rectangle_face[this.mSpriteCounter]);
}
That's it, thanks again for the help :)
I'd have already post this question in the Andengine forum but there are already some questions regarding this topic, some have replies but the ones i want to know don't have any replies yet.
I'm trying to simulate a player jump like in Super Mario Bros. First, I used a simple contact listener to have a boolean value false when contact occurs but the contact occurs with walls grounds, everything. So, I'm now trying to attach another small body to the bottom of player as foot sensor using WeldJoint. But I couldn't achieve that. The WeldJoint wouldn't stick at all. I tried to create the WeldJoint on an update thread, nothing. I tried with the setposition method to update the sensor position with the player's, but it just positions the sensor below ground.
Any suggestions would be appreciated. Here is how i tried to create WeldJoint.
Player and sensor
mPlayer = new AnimatedSprite(100, 150, PlayerTextureRegion);
PlayerBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,mPlayer,BodyType.DynamicBody, PLAYER_FIXTURE_DEF);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mPlayer, PlayerBody, true, true));
mScene.getLastChild().attachChild(mPlayer);
final Shape mSensor= new Rectangle(mPlayer.getX()+4,mPlayer.getY()+mPlayer.getHeight(),10,4);
final Body SensorBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,mSensor,BodyType.DynamicBody, SENSOR_FIXTURE_DEF);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mSensor, SensorBody, true, true));
mScene.getLastChild().attachChild(mSensor);
mScene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() { }
#Override
public void onUpdate(final float pSecondsElapsed) {
this.createJoint(PlayerBody,SensorBody);
.......
Joint Method
private void createJoint(Body Anchor, Body Sensor){
final WeldJointDef join = new WeldJointDef();
join.initialize(Anchor,Sensor,Anchor.getWorldCenter());
this.mPhysicsWorld.createJoint(join);
}
Ok, instead of WeldJoint I used RevoluteJoint, without the motor configuration and it works fine now. Just initialize two bodies using revoluteJointDef and they are stuck like weldjoint. For time being I'm going with revoluteJoint to make two bodies as one.