At the moment I’m using DashPathEffect with hardcoded intervals to draw a circle as next:
float[] intervals = new float[]{ 3, 18 };
DashPathEffect path = new DashPathEffect(intervals, 0);
paint.setPathEffect(path);
… … … …
canvas.drawCircle(x, y, radius, paint);
But this produces a non-equidistant dash where the circle starts and ends, as shown in the image below:
I can of course adjust it manually, but this would only work for one specific device density, and produce again the same problem in a different display density.
What would the formula to calculate equidistant dashes?
You need n dashes plus n gaps to have the same total length as the circumference of the circle. The below code assumes you've correctly determined both the center point and the radius you want to use.
double circumference = 2 * Math.PI * radius;
float dashPlusGapSize = (float) (circumference / NUM_DASHES);
intervals[0] = dashPlusGapSize * DASH_PORTION;
intervals[1] = dashPlusGapSize * GAP_PORTION;
DashPathEffect effect = new DashPathEffect(intervals, 0);
paint.setPathEffect(effect);
canvas.drawCircle(center, center, radius, paint);
For instance, I've used NUM_DASHES = 20, DASH_PORTION = 0.75f, and GAP_PORTION = 0.25f, and I see:
You can use different values for these constants to change how many dashes you chop the cirlce into, or how big the dash/gap are relative to each other (as long as DASH_PORTION + GAP_PORTION adds up to 1).
In case you have a different figure you can use this method to measure your custom path length:
val measure = PathMeasure(path, false)
val length = measure.getLength()
Using AndEngine for Android, I would like to have my scene look like this:
The red box is the world which must be limited to a given size, say 2000px*450px.
The blue box is the Camera, which is limited as well (as usual), for example to 750px*450px.
For the whole scene, I have a background image that is exactly 450px high. So my Camera can be scaled to whatever size is appropriate, but the background must exactly fit to the height. The width of the Camera may be variable.
The player (circle) must always be in the center (horizontally) but may not leave the world's boundaries.
To achieve this, I've tried adding two types of sizes:
camera size (CAMERA_WIDTH, CAMERA_HEIGHT)
world size (WORLD_WIDTH, WORLD_HEIGHT)
And this function was to add boundaries to the world so that the physics engine prevents the player from leaving those boundaries:
private void createWorldBoundaries() {
Body body;
final Rectangle wall_top = new Rectangle(0, WORLD_HEIGHT-5, WORLD_WIDTH, 10, mVertexManager);
final Rectangle wall_bottom = new Rectangle(0, 5, WORLD_WIDTH, 10, mVertexManager);
final Rectangle wall_left = new Rectangle(5, 0, 10, WORLD_HEIGHT, mVertexManager);
final Rectangle wall_right = new Rectangle(WORLD_WIDTH-5, 0, 10, WORLD_HEIGHT, mVertexManager);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_top, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_top.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_bottom, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_bottom.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_left, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_left.setUserData(body);
body = PhysicsFactory.createBoxBody(mPhysicsWorld, wall_right, BodyType.StaticBody, new PhysicsFactory.createFixtureDef(0.0f, 0.5f, 0.5f));
wall_right.setUserData(body);
attachChild(wall_top);
attachChild(wall_bottom);
attachChild(wall_left);
attachChild(wall_right);
}
But this is not working, unfortunately. (see edit)
Setting the camera to chase the player has the wrong result for me: The player does really stay in the center of the screen all time, but I want the player only to stay in the center horizontally, not vertically.
What am I doing wrong and what can I change? And the basic question is: How can I make the world wider than the camera view, while the height is equal to the camera view. The result should be that you can horizontally walk through your world (moving camera) and you can always see the full height.
Edit:
As you define the coordinates of the Rectangle's center and not its top-left corner, you have to do it like this, it seems:
final Rectangle wall_top = new Rectangle(WORLD_WIDTH/2, WORLD_HEIGHT-1, WORLD_WIDTH, 2, mVertexManager);
final Rectangle wall_bottom = new Rectangle(WORLD_WIDTH/2, FIELD_BASELINE_Y+1, WORLD_WIDTH, 2, mVertexManager);
final Rectangle wall_left = new Rectangle(1, WORLD_HEIGHT/2, 2, WORLD_HEIGHT, mVertexManager);
final Rectangle wall_right = new Rectangle(WORLD_WIDTH-1, WORLD_HEIGHT/2, 2, WORLD_HEIGHT, mVertexManager);
However, I had found the other solution in several tutorials. Are these authors not testing their code before writing the tutorials or did the behaviour change from GLES1 to GLES2 or with any recent version?
i think your question about the world boundaries is self answered, isn't it?
PhysicsWorld Boundaries
for further research you can download nicolas' AndEngine Examples App from the Play Store and look up the different examples here (GLES_2, didn't look for AnchorCenter yet): https://github.com/nicolasgramlich/AndEngineExamples/tree/GLES2/src/org/andengine/examples
Taken from the PhysicsExample, the code for the rectangles should look like this, if the bounds are set to the camera bounds. in your case, you can extend width like you want (3 times CAMERA_WIDTH?)
final Rectangle ground = new Rectangle(0, CAMERA_HEIGHT - 2, WORLD_WIDTH, 2, vertexBufferObjectManager);
final Rectangle roof = new Rectangle(0, 0, WORLD_WIDTH, 2, vertexBufferObjectManager);
final Rectangle left = new Rectangle(0, 0, 2, CAMERA_HEIGHT, vertexBufferObjectManager);
final Rectangle right = new Rectangle(WORLD_WIDTH - 2, 0, 2, CAMERA_HEIGHT, vertexBufferObjectManager);
Camera following player
for the Camera to follow your player, you can lookup the code of the BoundCameraExample https://github.com/nicolasgramlich/AndEngineExamples/blob/GLES2/src/org/andengine/examples/BoundCameraExample.java
the interesting part for you should be the addFace method at the bottom
private void addFace(final float pX, final float pY) {
final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
final AnimatedSprite face = new AnimatedSprite(pX, pY, this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager()).animate(100);
final Body body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, face, BodyType.DynamicBody, objectFixtureDef);
this.mScene.attachChild(face);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(face, body, true, true));
this.mBoundChaseCamera.setChaseEntity(face);
}
this method creates a physics body + sprite for "your player" (in this case, a boxed face) and sets the sprite as a chaseEntity for the camera to follow. Since the camera has bounds, that it can't exceed and your camera will have the height of your PhysicWorld boundaries, you can use this to let your camera follow the player in x, but not in y direction.
if you (i don't know why) don't want to use these boundaries, you can overwrite the onUpdate method of your Sprite and re-locate your camera only in x-direction, instead of xy coords
face.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(final float pSecondsElapsed) {
float[] coord = face.getSceneCenterCoordinates();
this.mBoundChaseCamera.setCenter(sceneCenterCoordinates[0], CAMERA_Y_POSITION);
}
}
where the CAMERA_Y_POSITION is a static final field with the y-position.
I hope this answers your question(s). :-)
edit: oops, i forgot to mention, how to achieve the camera to be bound and i will edit the world width above:
this.mBoundChaseCamera.setBounds(0, 0,
WORLD_WIDTH, CAMERA_HEIGHT);
all settings are like your image given (except the exact position of the face, that has to be given to the addFace(px, py))
Edit: Difference between scene boundaries in Andengine GLES2 vs GLES2-AnchorCenter
As far as i understood the question, i thought you would use GLES2, i thought of the (older) default GLES2 branch of AndEngine and posted the boundaries. As you found out yourself before and stated in the comments, you use another approach to set the rectangles - where you need to set the rectangles center as pX and pY. The reason for this is in fact, that with the AnchorCenter branch, you won't set the upper left position of an entity anymore and instead use it's center position.
I was trying to change the velocity of a Physics Body that is attached to a rectangle with the movement of the accelerometer. I cannot get the body to change velocity, is it a permanent property once it is set?
this is in my populateScene:
rect = new Rectangle(220, -200, 24, 24, this.getVertexBufferObjectManager());
rect.setColor(Color.GREEN);
mScene.attachChild(rect);
ball = PhysicsFactory.createBoxBody(mPhysicsWorld, rect, BodyType.DynamicBody, droppingBoxDef);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
rect, ball));
and this is where I try to change the velocity:
#Override
public void onAccelerationChanged(AccelerationData pAccelerationData) {
int accellerometerSpeedX = (int)pAccelerationData.getX();
// accellerometerSpeedY = (int)pAccelerometerData.getY();
//Log.v("Accelerometer X Y Z: ", ""+pAccelerationData);
ball.setLinearVelocity(accellerometerSpeedX, 0);
}
Without the second portion above the rectangle loads fine and has its physics body working correctly. It seems to disappear when I try to use:
ball.setLinearVelocity.
The Body object is a global variable in the class so it can be referenced in both methods. I have tried using a update handler inside of Populatescene and setting ball.setLinearVelocity in there, however that gave the same results.
Essentially my question is: Can the velocity of a Body be changed after it has been connected to the physics world?
Typicly in Box2D you do not setVelocities, but rather apply impulses or forces to a body to cause it to accelerate or decelerate.
For what you are describing above, you should not be using setLinearVelocity. Try using
ball.applyForce(new Vector2(accellerometerSpeedX, 0), ball.getWorldCenter());
or
boxBody.applyAngularImpulse(new Vector2(accellerometerSpeedX, 0));
I am trying to develop a live wallpaper using andengine gles2 anchor center , with some physics.But when i add a physics object it was moving upwards.instead of moving downward due to gravity
what are the mistakes i am making
please help me to sort out the issue
Here is my code
FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f,
0.5f);
mPhysicsWorld = new PhysicsWorld(new Vector2(0,
SensorManager.GRAVITY_EARTH), false);
final AnimatedSprite animatedSprite;
animatedSprite = new AnimatedSprite(500, 250,
this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager());
body = PhysicsFactory.createBoxBody(this.mPhysicsWorld, animatedSprite,
BodyType.DynamicBody, FIXTURE_DEF);
scene.attachChild(animatedSprite);
animatedSprite.animate(200);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(
animatedSprite, body, true, true));
Just multiply SensorManager.GRAVITY_EARTH by -1.
Setting negative gravity did not respond properly to sensor data. By adding acceleration to the sensor data in the overridden method **onAccelerationChanged()**, could make the bject falling down with sensor flat.
public void onAccelerationChanged(final AccelerationData pAccelerationData) {
/* Add constant value for vertical gravity*/
final Vector2 gravity = Vector2Pool.obtain(pAccelerationData.getX(), pAccelerationData.getY() + 4.0);
this.mPhysicsWorld.setGravity(gravity);
Vector2Pool.recycle(gravity);
}
This will make your phy world in real gravity experience and you will get objects influenced by sensor data properly
I am try
MassData md = mBody.getMassData();
md.center.set(2f, 0); mBody.setMassData(md);
But this is not working properly. Help me do this correctly.
I want add a bit more weight to the bottom half of my body.
Instead of trying to change mass directly, what you want to do is to add an extra fixture to the bottom of your body. You can do it e.g. like this (this is a snippet, not complete code; create your textures, scene etc).
Sprite sprite = new Sprite(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, 32, 32, mDTextureRegion, vbom);
Body body = PhysicsFactory.createCircleBody(mPhysicsWorld, sprite, BodyType.DynamicBody, PhysicsFactory.createFixtureDef(0.5f, 0.5f, 0.5f)); // create a simple circle body from the sprite
scene.attachChild(sprite);
Debug.i("ORIG MASS Y: " + body.getMassData().center.y); // this is just generated info
FixtureDef fd = PhysicsFactory.createFixtureDef(10f, 1f, 1f, true); // high density fixture; it is a sensor, i.e. it won't affect collisions
CircleShape cs = new CircleShape();
cs.setRadius(0.1f); // make it very small
fd.shape = cs;
cs.setPosition(new Vector2(0, -0.5f)); // attach below the current centre
body.createFixture(fd); // attach to body
Debug.i("NEW MASS Y: " + mDBody.getMassData().center.y); // the generated info changed
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(sprite, body, true, true));
This example body will behave like a spintop, it will try to reposition itself so the bottom of the sprite will touch the ground. When you rotate it, it will try to get to that position again.