I am currently following some tutorials to get introduced to andEngine and box2d and I would like to drag an object (sprite attached to body), whilst it is bouncing (it is registered to a physics world).
I would like to drag so I can see my character moving. It works only if I comment the code as below (the part where I am registering Physics connector). If I uncomment it, everything will work (e.g. even if I set other properties), except setPosition!! - I am sure the code is entering the ACTION_MOVE case
Question 1: why is this approach not working?
- maybe I have to drag the body and not the sprite?
Question 2: how can I refer to the body and make operations in it WITHIN THE onAreaTouched?
- I tried many different approaches, but it seams that you have to create the onAreaTouch when declaring the sprite only.
Reference: http://stuartmct.co.uk/2012/07/18/andengine-touch-events-with-sprites-and-shapes/ and AndEngine Book
Sprite sPlayer = new Sprite(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2,
playerTextureRegion,
this.mEngine.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
Log.i(this.getClass().getName(), "area touched");
switch (pSceneTouchEvent.getAction()) {
case TouchEvent.ACTION_DOWN:
break;
case TouchEvent.ACTION_UP:
break;
case TouchEvent.ACTION_MOVE:
this.setPosition(pSceneTouchEvent.getX() - this.getWidth()
/ 2, pSceneTouchEvent.getY() - this.getHeight() / 2);
break;
}
return true;
}
};
FixtureDef PLAYER_FIX = PhysicsFactory.createFixtureDef(10.0f, 0.75f,
0.0f);
// apply all forces, collisions to body - Dynamic
Body body = PhysicsFactory.createCircleBody(physicsWorld, sPlayer,
BodyType.DynamicBody, PLAYER_FIX);
The following code does not let me setPosition of Sprite:
/*
// relate to collisions after adding to scene
physicsWorld.registerPhysicsConnector(new PhysicsConnector(sPlayer,
body, true, true));
*/
this.scene.registerTouchArea(sPlayer);
this.scene.setTouchAreaBindingOnActionDownEnabled(true);
this.scene.attachChild(sPlayer);
You will need to go
myPad.setTransform(pSceneTouchEvent.getX() - (this.getWidth()
/ 2), pSceneTouchEvent.getY() - (this.getHeight() / 2), 0);//the zero at the end is for setting the angle
Because with box2d you need to move the body and the physics connector
physicsWorld.registerPhysicsConnector(new PhysicsConnector(sPlayer,
body, true, true));
will make the sprite follow the body.
Related
My game scene consist of four walls, which are static bodies, and one platform plate, which is of type kinematic and slides only horizontally, something like the picture below.
The platform body moves based on acceleration sensor, see this codes
#Override
public void onAccelerationChanged(AccelerationData pAccelerationData) {
mPlatformBody.setLinearVelocity(pAccelerationData.getX() * 10, 0);
}
My problem is when the platform goes off the boundary walls, which it should not. For resolving this issue, I've set its velocity to zero once it tries to break out the boundaries. see this codes
Rectangle rect = new Rectangle(camWidth / 2 - 40, camHeight / 2 - 5,
80, 10, mEngine.getVertexBufferObjectManager()) {
#Override
protected void onManagedUpdate(float pSecondsElapsed) {
if (this.getX() <= 1) {
mPlatformBody.setLinearVelocity(0, 0);
}
if ((this.getX() + 80 >= camWidth - 1)) {
mPlatformBody.setLinearVelocity(0, 0);
}
super.onManagedUpdate(pSecondsElapsed);
}
};
With the codes above, still this platform can goes off the screen.
Could anyone please help me out how can I overcome this issue?
As #LearnCocos2D stated, I should reset platform body to a legal position while it tries to leave the screen. For this, I should use setTransform method of Body class (as #iforce2d said).
For dealing with setTransform, there is two important points.
AndEngine uses top-left as anchor of sprites, but Box2d uses center as anchor of bodies.
Box2d uses meter as its units, so we must tranform all pixel units to meter unit.
Example: Suppose we want to move body body to (3, 4) point (in pixels).
float x = 3; // in pixels (AndEngine unit)
float y = 4; // in pixels (AndEngine unit)
float wD2 = sprite.getWidth() / 2;
float hD2 = sprite.getHeight() / 2;
float angle = body.getAngle(); // preserve original angle
body.setTransform((x + wD2) / PIXEL_TO_METER_RATIO_DEFAULT,
(y + hD2) / PIXEL_TO_METER_RATIO_DEFAULT,
angle);
Note that PIXEL_TO_METER_RATIO_DEFAULT is 32.
I have 2 sprites, I would like to move both of them, when I touched sprite A and moved it, sprite B will be moved also without touching sprite B at the same time. thanks for the help
here is the code
I have 2 sprites, I would like to move both of them, when I touched sprite A and moved it, sprite B will be moved also without touching sprite B at the same time. thanks for the help
here is the code
center = new AnimatedSprite(0, 0, resourcesManager.interact, vbom) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,final float pTouchAreaLocalX, final float pTouchAreaLocalY)
{
//SPrite A
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
//Sprite B
return true;
}
};
If you can post some code it would help in creating a more helpful answer.
In essence, when you handle the touch event and apply the movement to sprite A all you need to do is also apply the movement to sprite B.
If you post your code I will be able to edit and add an example.
You can change position of sprite B at the same moment with sprite A, inside spriteA's onAreaTouched method:
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,final float pTouchAreaLocalX, final float pTouchAreaLocalY)
{
//SPrite A
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
spriteB.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
};
I am working with andEngine the Open source game platform. I have a sprite that moves continuously on the screen and change direction when collides with screen boundary. Now, I wanna change its direction to the players touch point on the screen. I can't manage this part. I use PhysicsHandler to move the sprite with a velocity. I understand i have to implements IOnSceneTouchListener, to get touched point and set the direction on the sprite . But found nothing now. Here is my code goes:
Pilot aPilot;
PhysicsHandler mPhysicsHandler;
aPilot = new Pilot(222, 333, pilotTexures, vbom) {
#Override
protected void onManagedUpdate(float pSecondsElapsed) {
/*
* change direction when collides with boundary wall of Screen
*/
if (this.mX < 0) {
mPhysicsHandler.setVelocityX(AtomicEngine.DEMO_VELOCITY);
} else if (this.mX + this.getWidth() > ResourcesManager.CAMERA_WIDTH) {
mPhysicsHandler.setVelocityX(-AtomicEngine.DEMO_VELOCITY);
}
if (this.mY < 0) {
mPhysicsHandler.setVelocityY(AtomicEngine.DEMO_VELOCITY);
} else if (this.mY + this.getHeight() > ResourcesManager.CAMERA_HEIGHT) {
mPhysicsHandler.setVelocityY(-AtomicEngine.DEMO_VELOCITY);
}
super.onManagedUpdate(pSecondsElapsed);
}
};
/*
* initialize mPhysicsHandler
*/
mPhysicsHandler = new PhysicsHandler(aPilot);
registerUpdateHandler(this.mPhysicsHandler);
mPhysicsHandler.setVelocity(AtomicEngine.DEMO_VELOCITY,
AtomicEngine.DEMO_VELOCITY);
attachChild(aPilot);
aPilot.setScale(3f);
And my override onSceneTouchEvent method is like:
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if (pSceneTouchEvent.isActionDown()) {
// need some idea here
}else if (pSceneTouchEvent.isActionMove()) {
}
return false;
}
Wait for your super knock.
you have to calculate difference between the pilots current position (e.g. by calling getSceneCenterCoordinates() of your pilots sprite you get the coordinates in the scene) and the position of the the touch event - with that difference in mind, you can calculate the angle (measured on the UnitCircle) or use a factor that is a percentage between your max_velocity & distance length, then use your physicshandler and set a new velocity. the factor is used to limit the speed to a max speed.
so, your code should look like something like this (didn't test, ask if it didn't work)
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
MainActivity.this.mCamera.convertCameraSceneToSceneTouchEvent(touchEvent);//see edit
float touchX = touchEvent.getX();
float touchY = touchEvent.getY();
float[] pilotCoord = aPilot.getEntity.getSceneCenterCoordinates();
float pilotX = pilotCoord[0];
float pilotY = pilotCoord[1];
float xDiff = touchX - pilotX;
float yDiff = touchY - pilotY; // could be wrong with AnchorCenter branch
// use the max velo divided by the distance to get the velo factor for x & y,
// but perhaps calculating angles is faster, dunno
float veloFactor = MAX_VELO/sqrt(xDiff^2 + yDiff^2);
float xVelo = xDiff*veloFactor;
float yVelo = yDiff*veloFactor;
mPhysicshandler.setVelocityX(xVelo);
mPhysicshandler.setVelocityY(yVelo);
return true;
}
so far the calculation for setting the velocity into the direction of the finger. if you want some kind of (de)acceleration (like: as long as the finger is down, the pilot (de)accelerates into the direction of the finger, else he will stick with his speed, you have to setLinearVelocity(xVelo, yVelo) instead and set the current velocity as velocity (to maintain speed)
Edit
The conversion of the touchEvent from a CameraScene to a SceneTouchEvent is only usefull if you add your onSceneTouchListener to your HUD. it converts the events x/y values based on the current camera position (over the scene) to xy-values as they would have occured on the scene.
else, if you add the listener directly to your Scene, you don't need to convert the touch event and the line could be deleted.
I am new to andengine and even android game development. i have created sprite as a box. this box is now draggable by using this coding. it works fine.
but i want multitouch on this which i want to rotate a sprite with 2 finger in that box and even it should be draggable. .... plz help someone...
i am trying this many days but no idea.
final float centerX = (CAMERA_WIDTH - this.mBox.getWidth()) / 2;
final float centerY = (CAMERA_HEIGHT - this.mBox.getHeight()) / 2;
Box= new Sprite(centerX, centerY, this.mBox,
this.getVertexBufferObjectManager()) {
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth()/ 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
float pValueX = pSceneTouchEvent.getX();
float pValueY = CAMERA_HEIGHT-pSceneTouchEvent.getY();
float dx = pValueX - gun.getX();
float dy = pValueY - gun.getY();
double Radius = Math.atan2(dy,dx);
double Angle = Radius * 360 ;
Box.setRotation((float)Math.toDegrees(Angle));
return true;
}
Make sure you enabled multi touch in your game. You can use the same code used in the MultiTouchExample in the onLoadEngine method.
The algorithm is quite simple, similar to what you've posted here.
Keep track of up to 2 pointer IDs you get in onAreaTouched method. (You can get the pointer ID by calling pSceneTouchEvent.getPointerID()).
Keep track of the pointers' state (Currently touching/not touching) and location (pTouchAreaLocalX and pTouchAreaLocalY).
Whenever 2 pointers are touching (You received ACTION_DOWN for both), save the initial angle. (Math.tan2(pointer1Y - pointer2Y, pointer1X - pointer2X)).
As long as ACTION_UP is not called for the pointers, update the new angle in every ACTION_MOVE event of the pointers, and get the angle delta (delta = currentAngle - initialAngle). Then call setRotation(Math.toDegrees(delta)).
To make the sprite dragable with 2 pointers, you need to move your sprite the lesser of the distance each pointer has moved. For example, if:
pointer1.dX = 50;
pointer1.dY = -20;
pointer2.dX = 40;
pointer2.dY = -10;
the sprite should move +40 units in the X axis, and -10 units in the Y axis.
I want to limit the area to move the sprite object only on this area (for example a area dimensions 200x200).
I would to create a box2D 200x200 where the sprites can moved only on this area
How do you do that please?
#Override
public Scene onCreateScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
final float centerX = (CAMERA_WIDTH - this.mFaceTextureRegionLetterOne
.getWidth()) / 2;
final float centerY = (CAMERA_HEIGHT - this.mFaceTextureRegionLetterOne
.getHeight()) / 2;
final Sprite letterOne = new Sprite(centerX - centerX / 2, centerY
- centerY / 2, this.mFaceTextureRegionLetterOne,
this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
return true;
}
};
final Sprite letterTwo = new Sprite(centerX - centerX / 2, centerY,
this.mFaceTextureRegionLetterTwo,
this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
//int count = scene.getChildCount();
//for(int i = 0; i < count; i++) {
IEntity entity = scene.getChildByIndex(1);
if (entity instanceof Sprite) {
if (entity.getUserData().equals("sprite"))
if (((Sprite) entity).collidesWith(letterOne))
Log.v("colission", "face_box is collised on google plus -> letterTwo on letterOne");
}
//}
return true;
}
};
letterTwo.setUserData("sprite");
final Sprite boxArea = new Sprite(centerX, centerY,
this.mFaceTextureRegionBox, this.getVertexBufferObjectManager());
letterOne.setScale(2);
scene.attachChild(letterOne);
scene.registerTouchArea(letterOne);
letterTwo.setScale(2);
scene.attachChild(letterTwo);
scene.registerTouchArea(letterTwo);
boxArea.setScale(2);
scene.attachChild(boxArea);
scene.setTouchAreaBindingOnActionDownEnabled(true);
return scene;
}
Thank you.
I don't know box2D, but normally you would check the edges of the sprite on each movement, if they do not overlap the edges of the area.
If your sprite is represented by a Rectangle, and the area where you can move also represented by a Rectangle, this could be done easy.
But first, check the box2D API, maybe it has already some helper methods to ease this task, something like:
obect.overlaps(object)
You should create a Rectangle of 200X200 and then you should use create a body of the rectangle using the Box2D Physics. And for Fixture definition for rectangle you can set density, Elasticity and Friction so that your sprites will be treated accordingly when they collide with the boundary of the Rectangle.
To create a Rectangle you can refer the Examples of the Andengine.
With your code, you seem to try to do collision checking with your sprites ?!
It would be complicated and not nice when you try to do things without physics bodies. So lets use the physics bodies with your sprites.
But note that, DO NOT create a solid box body for your area (containing your sprites), lets use 4 separated body walls (left, top, right, bottom) to form a closed box; because game engine can only check collision with solid shapes.
The following is the code for reference:
/**
* #param pScene
* Sence of the game, get from class member
* #param pWorld
* physics world of the game, get from class member
*/
public void CreateSprites(final Scene pScene, final PhysicsWorld pWorld)
{
final FixtureDef mFixtureDef = PhysicsFactory.createFixtureDef(10, 1.1f, 0.0f);//should be placed as member of class
final Sprite letterTwo = new Sprite(centerX - centerX / 2, centerY,
this.mFaceTextureRegionLetterTwo,
this.getVertexBufferObjectManager());
final Body letterTwoBody = PhysicsFactory.createBoxBody(pWorld, letterTwo, BodyType.DynamicBody, mFixtureDef);
letterTwo.setUserData(letterTwoBody); // for later sprite-body attachment access
pScene.attachChild(letterTwo);
pWorld.registerPhysicsConnector(new PhysicsConnector(letterTwo, letterTwoBody, true, true));
}
/** Create the walls, in these boudaries sprites will move */
public void InitBoxWalls(Scene pScene, PhysicsWorld pWorld)
{
final float WALL_MARGIN_WIDTH = 5f;
final float WALL_MARGIN_HEIGHT = 10f;
final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
mWallGround = new Rectangle(-WALL_MARGIN_WIDTH, mCameraHeight + WALL_MARGIN_HEIGHT - 2, mCameraWidth + 2*WALL_MARGIN_WIDTH, 2, vertexBufferObjectManager);
mWallRoof = new Rectangle(-WALL_MARGIN_WIDTH, -WALL_MARGIN_HEIGHT, mCameraWidth + 2*WALL_MARGIN_WIDTH, 2, vertexBufferObjectManager);
mWallLeft = new Rectangle(-WALL_MARGIN_WIDTH, -WALL_MARGIN_HEIGHT, 2, mCameraHeight + 2*WALL_MARGIN_HEIGHT, vertexBufferObjectManager);
mWallRight = new Rectangle(mCameraWidth + WALL_MARGIN_WIDTH - 2, -WALL_MARGIN_HEIGHT, 2, mCameraHeight + 2*WALL_MARGIN_HEIGHT, vertexBufferObjectManager);
PhysicsFactory.createBoxBody(pWorld, mWallGround, BodyType.StaticBody, mWallFixtureDef);
PhysicsFactory.createBoxBody(pWorld, mWallRoof, BodyType.StaticBody, mWallFixtureDef);
PhysicsFactory.createBoxBody(pWorld, mWallLeft, BodyType.StaticBody, mWallFixtureDef);
PhysicsFactory.createBoxBody(pWorld, mWallRight, BodyType.StaticBody, mWallFixtureDef);
pScene.attachChild(mWallGround);
pScene.attachChild(mWallRoof);
pScene.attachChild(mWallLeft);
pScene.attachChild(mWallRight);
}
And the last thing you should do is to look up example of Physics/MouseJoint in AndEngine examples.