I use LibGDX and I have a moving solid object (Fixture B) and a sensor object (Fixture A).
In my ContactListener I can check if a solid object and a sensor collide, but I can't tell where the first contact point was (I need to know that point, for using it as center point on the next phase).
I have this code:
#Override
public void beginContact(Contact contact)
{
Fixture fa = contact.getFixtureA();
Fixture fb = contact.getFixtureB();
LogMessage("World points: "+contact.getWorldManifold().getPoints().length);
float contactX = contact.getWorldManifold().getPoints()[0].x; //always 0.0
float contactY = contact.getWorldManifold().getPoints()[0].y; //always 0.0
LogMessage("Contact X: "+contactX);
LogMessage("Contact Y: "+contactY);
}
Unfortunately, this manifold does not contain any collision point, as one of the fixtures is a sensor. I'm pretty sure they wouldn't miss the implementation of such an important task as sensor contact point detection, I just couldn't find the proper method yet.
Is there any built-in method to detect the contact point?
You have to setUserData("region1") on fixture in the two bodies
//Class platform
b2body.createFixture(fdef).setUserData("region1");
//Class Player
b2body.createFixture(fdef).setUserData("foot");
and in Contact Listener check if the contact was in that region like this:
public void beginContact(Contact contact) {
Fixture fixA = contact.getFixtureA();
Fixture fixB = contact.getFixtureB();
if(fixA.getUserData() == "region1" || fixB.getUserData() == "region1"){
Fixture foot = fixA.getUserData() == "foot" ? fixA : fixB;
Fixture object = foot == fixA ? fixB : fixA;
//
Gdx.app.log("foot touched","region1");
}
Updated 11/05/16
understood. You are doing correctly
i did a simple example to check:
the collision points and mouse detect
but try to check if your fixture has density. if you are creating a EdgeShape for example, it will not be detected
Related
I am working on a LibGdx running game.I have collectibles/coins in the game.
I have created a coin array,and spawned it throughout the game.
To improve the play,I want to make patterns of coins.Like 2 coins or 3 coins together , coins in vertical or diagonal arrangements etc.
I tried to implement this,but found it a difficult task as a fresher.
Please suggest me some code to implement patterns like triangle with an array of objects.
Like this:triangle with 3 coins in equal distance:
My coin array and method are included here:
I am adding new coins on the basis of last coin passes a particular distance on the screen.
Array<Coin> coins = new Array<Coin>();
private void createCoin() {
coinObj = objectFactory.createCoin(CoinEnum.random());
coinObj.isCollided = false;
coins.add(coinObj);
}
private void spawnCoin() {
if (coins.size == 0) {
createCoin();
} else {
Coin c = coins.peek();
if (c.getY() > (Constants.WORLD_HEIGHT / 8))
createCoin();
}
// remove out of screen coins
if (coins.size > 0) {
Coin cc = coins.first();
if (cc.getY() > Constants.WORLD_HEIGHT) {
coins.removeValue(cc, true);
}
}
}
Also hope someone can tell me the mistakes in my approach if any!
Thanks in advance!
First of all, try to model the CoinPattern:
- What is a CoinPattern?
It is just a pattern, describing an arrangement of multiple coins.
- What do I need to describe it?
As it is just a pattern, you don't need no Coins yet.
In my opinion, a list of Points (or Vector2) should be enough.
Each of these Points could describe the relative Position of the Object (in your case Coin) inside the Pattern.
Now you could create constants for your Patterns. The triangle could look something like this:
public static final PATTERN_TRIANGLE = new Vector2[] {
new Vector2(0,0),
new Vector2(1,0),
new Vector2(0,1),
};
Then you could create a method spawnPattern(Vector2[] pattern, int x, int y). This method should then create a Coin for every Vector2 in the pattern.
The position of each Coin could be calculated like this:
int posX = x + pattern[i].x;
int posY = y + pattern[i].y;
Note, that using this methode, the positions of the Coins are relative to the lower, left corner of the Pattern position.
I have an entity Actor defined by next code:
this.world = world;
this.texture = texture;
// Create the body.
BodyDef def = new BodyDef(); // (1) Give it some definition.
def.position.set(x, y + 0.5f); // (2) Position the body on the world
def.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(def); // (3) Create the body.
// Now give it a shape.
PolygonShape box = new PolygonShape(); // (1) We will make a polygon.
Vector2[] vertices = new Vector2[6];
vertices[0] = new Vector2(0.04f , 0.24f );
vertices[1] = new Vector2(0.64f , 1.18f );
vertices[2] = new Vector2(1.66f , 1.8f);
vertices[3] = new Vector2(1.92f , 1.52f);
vertices[4] = new Vector2(1.18f , 0.66f);
vertices[5] = new Vector2(0.26f , 0.03f);
box.set(vertices); // (4) And put them in the shape.
fixture = body.createFixture(box, 3); // (5) Create the fixture.
fixture.setUserData("actor"); // (6) And set the user data to enemy.
box.dispose(); // (7) Destroy the shape when you don't need it.
// Position the actor in the screen by converting the meters to pixels.
setPosition((x - 0.5f) * PIXELS_IN_METER, y * PIXELS_IN_METER);
setSize(PIXELS_IN_METER, PIXELS_IN_METER);
this.setDebug(true);
When I add last line setDebug my Actor abject is surrounded by a squared shape and my hits affect to this square and not the REAL shape defined by my poligon. This hit detection is catch by touchDown (InputProcessor) event:
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector2 coord = stage.screenToStageCoordinates(new Vector2((float)screenX,(float)screenY));
Actor hitActor = stage.hit(coord.x,coord.y,false);
if(hitActor != null) {
Gdx.app.log("myapp", "hit!!!!!");
}
return true;
}
What am I doing wrong? I just only want to detect hit on my game actor items.
Thank you in advance!!
Scene2D actor and Box2D body are not the same - if you want to see your body being debug you have to use Box2D's DebugRenderer
//creating debug renderer in show method or as class'es field
Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer();
//render() method
debugRenderer.render(world, camera.combined);
Then you'll see that your body's shape and actor's shape are not the same. What's more they probably won't have same position since you are not updateing your actor's position due to body (you should do this in actor's act overriden method by using something like setPosition(body.getPosition().x, body.getPosition().y); - remember that origin for actor is on its left bottom corner when the body has it's origin at the center!).
Unfortunately actor can be rectangular only so it is not possible to create same shape as for body. However you can use you actor as bounding box and set it's size to overlap whole body (it will be changing if body will rotate!).
Another solution is not to catch listener on body but to implement some mechanism like creating a body after click and check collision
I am using Category_bits for detecting collision in LIBGDX. I have used all the values ranging from 0 to 16384 . Since we have to use the power of 2 while initializing the values, I have exceeded the limit and I am not able to initialize any bits anymore. The range for short_ bit is 0 to 16384 and if I use the next multiple of that number, after type casting it to a short value, the Category_bits doesn't detect collision between objects. Nothing happens when the object collides when I set the value greater than 16384.
Here is how I initialize the values,
public static final short x = 0;
public static final short y = 1;
public static final short z = 2;
public static final short a = 4;
public static final short b = 8;
public static final short c = 16;
.....
public static final short d = 16384;
public static final short e = (short) 32768; // exceeded the limit so type casted the number to short
When I type cast and use it, nothing collision detection happens. I have to detect collision in many things in my game so I need the solution to get rid of this problem. Please help. Thanks in advance.
I would strongly advise re-checking over your code and decide whether you actually need that many different categories. Even if you have that many different types of objects I suspect you could group together those which have the same collision filters into just one bit, you can then use other ways of identifying which "type" of entity is involved in a collision.
If you do really need to use that many different objects then the Box2d World class has a method setContactFilter(ContactFilter filter) which will allow you to specify a custom ContactFilter. This contains a shouldCollide(Fixture a, Fixture b) which returns true if a and b should collide and vice versa.
short also worked for me with minus numbers, because it reaches from -32768 till 32767 so you can also use
-32678, -16384 and so on.
I don't know how to use the contact filters, but I work with UserData which also works pretty good for me.
when you create your body I wrote something like this:
b2body.createFixture(fdef).setUserData("something");
and in my collision detection I used something like this:
public class WorldContactListener implements ContactListener{
#Override
public void beginContact(Contact contact) {
Fixture fixA = contact.getFixtureA();
Fixture fixB = contact.getFixtureB();
int cdef = fixA.getFilterData().categoryBits | fixB.getFilterData().categoryBits;
switch(cdef) {
case BreedingSeason.HERO_BIT | BreedingSeason.TRAMPOLIN_BIT:
if(fixA.getUserData() == "somethingElse" && fixB.getUserData() == "something") {
...
} else if(fixB.getUserData() == "somethingElse" && fixA.getUserData() == "something") {
...
}
break;
}
and don't forget the break after each case in the switch ;)
i hope this helps you
Point 1, say it is (0, 0) and I have another point that should turn around at a distance of 10f. Then I'll adding degrees angle to make it rotate. I be wanting to know how to calculate that point that this turning around each other ..
I will use the raycasting, I need to rotate the ray (clockwise) to detect collisions
So you say you have point1 and point2, both separated by a distance of 10f where point2 will be rotating around point1, and you want to know if between this separation an object at some point is intersecting them, something like the following image:
There are tutorials to get the maths for rotate a point arount another one in internet, like this one, and since you can't specify an origin for a Vector2, a translated version of the code proposed in the previews link to java should be something similar to:
public Vector2 rotatePoint(Vector2 center, Vector2 point, float angle) {
angle = angle * MathUtils.degreesToRadians; // Convert to radians
float rotatedX = MathUtils.cos(angle) * (point.x - center.x)
- MathUtils.sin(angle) * (point.y - center.y) + center.x;
float rotatedY = MathUtils.sin(angle) * (point.x - center.x)
+ MathUtils.cos(angle) * (point.y - center.y) + center.y;
// rotated new position:
return new Vector2(rotatedX, rotatedY);
}
As for the rest of the code (the intersection between objects), I guess you are looking for the RayCastCallback interface:
// initial position
Vector2 point1 = new Vector(0, 0);
// Max lenght of view
Vector2 point2 = new Vector(0, 10);
// Position of collision if occur
final Vector2 collisionPoint = new Vector();
#Override
public void render(float delta) {
//...
point2 = rotatePoint(point1, point2, 10); // rotate 10ยบ
// to detect if object at position point1 is seeing something
world.rayCast(new RayCastCallback(){
#Override
public float reportRayFixture(Fixture fixture, Vector2 point,
Vector2 normal, float fraction) {
// what do the object saw? -> fixture
// where do the object saw it? -> point
collisionPoint.set(point);
return 0; // <- return 0 to stop raycasting
}
}, point1, point2);
//... rotation and other stuffs...
}
The return parameter of reportRayFixture have this documentation:
Called for each fixture found in the query. You control how the ray cast proceeds by returning a float: return -1: ignore this fixture and continue return 0: terminate the ray cast return fraction: clip the ray to this point return 1: don't clip the ray and continue. The Vector2 instances passed to the callback will be reused for future calls so make a copy of them!
** Emphasis added.
Basically it says that you can check for all the intersections one by one, but if you care only for the first one, return 0 immediately. This is useful when you want to know if an object is being blocked by another one. In this case, I return 0 and copy the value of point to collisionPoint to let you do whatever you want to do with this value.
A very nice example can be found in this video.
Hope you find this useful.
You should consider using Intersector class to check if the line from your actor intersects with the body shape.
To calculate end of "sight" line use Vector2 that you will be rotating according to your actor rotation (which is actually answer for your question)
It should looks like:
Vector2 sightVector = new Vector2(10f, 0); //the 10f is actually your sight max distance
sightVector.rotate(actor.getRotation());
...
#Override
pblic void render(float delta) //it can be also act of the actor
{
sightVector.rotate(actor.getRotation());
Vector2 endOfLine = new Vector2(actor.getX() + sightVector.x, actor.getY() + sightVector.y); //here you are calculating the end of line
Polygon bodyShape = getBodyShape( theBody ); //you should create a method that will return your body shape
if( Intersector.intersectLinePolygon(new Vector2(actor.getX(), actor.getY()), endOfLine, bodyShape) )
{
//do something
}
...
}
Intersector has method to check intersection with circles etc also so your body Shape doesn't need to be polygon
I am animating some text in my libgdx application and would like a label text to fade-in and move (e.g. similar to this jsfiddle).
I can move, and change alpha of other objects (e.g. Sprites) and can move BitmapFontCaches. However I can't get alpha of the BitmapFontChage to change.
Declaration:
message = new BitmapFontCache(messageFont, true);
message.setWrappedText("some text", 10.0f, 10.0f, 10.0f);
message.setAlphas(0.0f);
In my screen class, I override the render method, and call .draw() on a renderer class, which is (among other things) essentially just a message.draw(batch); call.
#Override
public void render(float delta) {
...
try{
batch.begin();
feedbackRenderer.draw(batch);
tweenManager.update(delta);}
finally{
batch.end();
}
}
Then as a part of a timeline I call these two Tweens. (yes, they are wrapped in .push( ) and I do start my tweenManager:)
Tween.to(message, BitmapFontCacheAccessor.POSITION_X, animationDuration)
.target(35.0f)
Tween.to(message, BitmapFontCacheAccessor.ALPHA, animationDuration)
.target(1.0f)
The BitmapFontCacheAccessor tries to setAlphas() of the BitmapFontCache as such:
public class BitmapFontCacheAccessor implements TweenAccessor<BitmapFontCache> {
public static final int POSITION_X = 1;
public static final int ALPHA = 2;
#Override
public void setValues(BitmapFontCache target, int tweenType, float[] newValues) {
switch (tweenType) {
case POSITION_X:
float y = target.getY();
target.setPosition(newValues[0], y);
break;
case ALPHA:
target.setAlphas(newValues[0]);
break;}
}...
It moves the label (==> .setPosition(x, y) works!), but does not even touch the alpha. This exact same approach works for Sprites, which fade in nicely.
Is there perhaps some catch when tweening alpha for the BitmapFontCache? Is it possible?
Many thanks!
After a good hour of debugging I have found the reason for this funny behavior.
Libgdx's BitmapFontCache does not have a getAlphas() method
Therefore, to get the alpha channel I used getColor().a
However, these two are not always synced. The behavior is quite random, I myself am not quite sure when it syncs and when it doesn't (f.ex. in the question above, the fade-outs would work, but fade-ins wouldn't)
The solution is to change and declare BOTH alpha channels.
Definition of BitmapFontCache:
message = new BitmapFontCache(messageFont, true);
message.setColor(1,1,1,0);
message.setAlphas(0);
and inside TweenAccessor:
case ALPHA:
//first alpha channel
target.setAlphas(newValues[0]);
//second alpha channel
Color c = target.getColor();
c.a = newValues[0];
target.setColor(c);
break;
To you, hopeless SO wanderer, I address this answer so that you can spend some of the finite number of minutes of your life better than I did.