I am making an iphone app with cocos2d and box2d and I am having trouble, I followed this tutorial on how to use the b2ContactListener because I need it very badly for my app... http://www.raywenderlich.com/505/how-to-create-a-simple-breakout-game-with-box2d-and-cocos2d-tutorial-part-22 I am trying to detect when two objects collide
It has been one of the hardest things for me to figure out... not nessecarally what he is doing in the game but how to use the b2contactlistener... However, I want to use what he did in that tutorial within my code
this is how I updated my tick method so it would check for collisions every time
-(void) update: (ccTime) dt
{
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
if ((contact.fixtureA == _bottomFixture && contact.fixtureB == _ballFixture) ||
(contact.fixtureA == _ballFixture && contact.fixtureB == _bottomFixture)) {
NSLog(#"Ball hit bottom!");
}
}
}
However, I don't know how to change it to work with my two b2Bodies, eggBody and locations.platform...
I believe it is these few lines I must change...
if ((contact.fixtureA == _bottomFixture && contact.fixtureB == _ballFixture) ||
(contact.fixtureA == _ballFixture && contact.fixtureB == _bottomFixture)) {
NSLog(#"Ball hit bottom!");
}
where it says _bottomFixture and _ballFixture I thought I would plug in my b2Bodies... but now I feel like _bottomFixture isn't even a b2body
:) any help would be great sorry if I confused anybody just post any questions and I will clarify thankyou
_bottomFixture is a b2Fixture object.
It is created when you create the fixturedef of the body by
bottomBody->CreateFixture(&_fixturedef);
the above line returns a b2Fixture.
so you can write
b2Fixture *_bottomFixture = bottomBody->CreateFixture(&_fixturedef);
normally we don't track this b2Fixture object. But in collision detection, we need to use it.
Related
Though I begin with a very nicely, oriented globe:
After a lot of manual intervention and spinning, the globe may look like this:
Obviously, I should be implementing some sort of restoration function that will restore the globe on a certain axis to a point.
I have naively created the following code:
if(transform.parent.rotation.eulerAngles.y != 0)
{
goalRotation.eulerAngles = new Vector3(transform.parent.rotation.eulerAngles.x, transform.parent.rotation.eulerAngles.y, 0);
transform.parent.rotation = Quaternion.Slerp(transform.parent.rotation, goalRotation, Time.deltaTime);
}
However, this obviously does not work. It is definitely rotating the globe, but it's not moving as expected...
Is there anyone with more experience with Slerp or something similar that can rotate my globe to a 0 point?
As always, any help or advice is much appreciated.
EDIT: In case I wasn't clear before, I am looking to achieve something like this: https://gfycat.com/PeacefulJubilantCottontail (This is my solution to the problem). I did try to use other solutions here, but I guess there was a misunderstanding because they did not work.
While, the following naive code sorta works, I still feel there is a better way to do it...
if (fix && (lastControlled + 5f < Time.time))
{
goalRotation.eulerAngles = new Vector3(90, transform.parent.rotation.eulerAngles.y, 0);
transform.parent.rotation = Quaternion.Slerp(transform.parent.rotation, goalRotation, Time.deltaTime);
}
if (fix && (transform.parent.rotation.eulerAngles.x == 90) && (transform.parent.rotation.eulerAngles.z == 0))
{
fix = false;
}
The only real remaining issue I am having is that Slerp works towards the desired point, but it does not take the quickest path. Any further help would be appreciated.
Is this what you are trying to do?
quaternion defaultRotation = transform.parent.rotation;
bool returnToDefault = false;
void Update()
{
if(returnToDefault)
{
Vector 3 rot = new Vector 3 (transform.parent.rotation.x, Quaternion.Slerp(transform.parent.rotation, defaultRotation, Time.deltaTime).Euler.y, transorm.parent.rotation.y);
transform.parent.EulerAngles = rot;
}
}
And just change the variable returnToDefault to true whenever you want it to go back. Otherwise, you are constantly fighting your code, which as your wrote it is always rotating it back to default.
I am trying to destroy a gameObject once it has collided with two other objects with the following code but it does not work.
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "Sphere" && col.gameObject.tag == "Pyramid")
{
Destroy (GameObject.FindWithTag("Pentagon"));
}
}
Can someone offer a correction of my code because I can't seem to figure out how to destroy my "Pentagon"?
The problem is in your first line:
if (col.gameObject.tag == "Sphere" && col.gameObject.tag == "Pyramid")
You cant have 2 tags on a gameObject. I assume what you want to say is || instead of &&.
What are you trying to achieve in that second block of code? Instead of deleting the rigidbody, maybe just set RigidBody.Enabled = false.
Please Guys help, I am new to Unity and programming:
I have a two Bouncing Ball, tag as BouncingBall1 and BouncingBall2, I want when a bullet hit both to destroy and if the time have not exceeded displaySecond and you have destroy the balls you win, but my problem is the OnCollisionEnter is not working. The part of wining is not working the rest are, my code fragment is below.
function OnCollisionEnter(col.collision) {
if ((displaySecond < 30) && (
col.gameObject.tag ==
BouncingBall1 == null &&
col.gameObject.tag ==
BouncingBall1 == null)) {
print("You have won");
}
}
col.gameObject.tag == BouncingBall1 == null
I think the problem is with the way you check if an object is destroyed. This isn't the way to do it. Also, you're checking if two identical lines of code are identical. So this will always return true if the display second is lower than 30.
Try changing it to
if ( (displaySecond < 30) &&
(col.gameObject.tag == "BouncingBall1") ) {
Debug.Log("You have won!")
}
It sounds like you want keep track of whether each ball has been destroyed and display "You have won" when both have been destroyed. This code is a little crude but should achieve this:
var ball1Destroyed = false;
var ball2Destroyed = false;
...
function OnCollisionEnter(col : Collision) {
if (col.gameObject.tag == "BouncingBall1") {
ball1Destroyed = true;
}
if (col.gameObject.tag == "BouncingBall2") {
ball2Destroyed = true;
}
if (displaySecond < 30 && ball1Destroyed && ball2Destroyed) {
Debug.Log("You have won");
}
}
This code assumes that the only collisions will be between bullets and balls (not between one ball and another), this can be done with collision layers.
Ok lets get into it.
I've got 2 colliders whose purpose it is to determine the hit type of the ball. If it is GoodHit or NiceHit (Nice is like Perfect).
The GoodHit collider2d has a much larger area than NiceHit.
The NiceHit on the other hand overlaps to a portion of GoodHit in its center.
Using this code I can determine whether the ball enters the area of GoodHit and NiceHit
void OnTriggerEnter2D(Collider2D other) {
if (other.name == "HitNice") {
hitType = 2;
} else if(other.name == "HitGood") {
hitType = 1;
}
}
void OnTriggerStay2D(Collider2D other) {
if (other.name == "HitNice") {
hitType = 2;
} else if(other.name == "HitGood") {
hitType = 1;
}
}
void OnTriggerExit2D(Collider2D other) {
hitType = 0;
}
The problem is it doesn't triggers the NiceHit and the hitType is still valued 1 regardless if the ball is in NiceHit area.
I first created the Goodhit object, that in a sense gives it a priority than NiceHit. I could swap them by names and values that way I can achieve the thing that I wanted but that doesn't really solved it.
Any workaround or tweaks I can do? Thanks!
You have two overlapping triggers, one of which is in the middle of a larger trigger.
Here's something to remember: if an object is inside the inner trigger, it is also inside the larger trigger!
So in your code, you use OnTriggerStay to determine if the object is in one of those triggers. Let's take a look at that:
void OnTriggerStay2D(Collider2D other) {
if (other.name == "HitNice") {
hitType = 2;
} else if(other.name == "HitGood") {
hitType = 1;
}
}
This function is executed once per trigger that the object is inside of. So this function is executed twice if it is inside of the HitNice trigger. So let's say Unity calls this function for each trigger. What is probably happening is that it's calling the handlers in a bad order (pseudocode):
OnTriggerEnter(HitNice) //hitType is 2
OnTriggerEnter(HitGood) //hitType is now 1!
Unity is calling the collider handlers from inside out, causing the result from a HitGood trigger to always override the HitNice value. I don't know for sure if that's how it works, but looking at your code it's totally a possibility of why it's not working correctly.
Now, I can't say this for sure, but I think just using your OnTriggerEnter handler will suffice. It will only trigger the hitType detection when it enters a collider rather than when it stays. Since the object must enter the outer trigger before entering the inner trigger, this means that it should always evaluate in the correct order. In that case, your code is probably working as is, but I would say that your logic should be like this:
void OnTriggerEnter2D(Collider2D other) {
if(other.name == "HitNice") {
hitType = 2;
} else if(other.name == "HitGood" && hitType != 2) {
hitType = 1;
}
}
The only caveat of this approach is that you would need to reset the value of hitType manually. Not sure exactly how your game works, but this should give you an idea of how to approach this. Your HitNice should always override a HitGood. So when OnTriggerEnter is called for HitGood, check that you haven't yet hit HitNice yet. Or even better, record both hit types in separate variables, and then resolve which type of hit it was later on when doing scoring or whatever.
I dont know how to use this metnod in my application
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
b2PointState state1[2], state2[2];
b2GetPointStates(state1, state2, oldManifold, contact->GetManifold());
//NSLog(#"Presolving");
if (state2[0] == b2_addState)
{
const b2Body* bodyA = contact->GetFixtureA()->GetBody();
const b2Body* bodyB = contact->GetFixtureB()->GetBody();
b2Vec2 point = worldManifold.points[0];
b2Vec2 vA = bodyA->GetLinearVelocityFromWorldPoint(point);
b2Vec2 vB = bodyB->GetLinearVelocityFromWorldPoint(point);
b2Vec2 rV = vB - vA;
float32 approachVelocity = b2Dot(rV, worldManifold.normal);
if (-1.5f < approachVelocity && approachVelocity < 0.0f)
{
//MyPlayCollisionSound();
NSLog(#"Not Playing Sound");
}
else
{
NSLog(#"playing the sound");
}
}
}
How can I use this code in my HelloWorldLayer.mm Please help me...
I have a problem here, I have a scene where some bodies falls and hit a static body, edges alike, I implemented the b2ContactListener, and in my tick method Im checking for contacts and play the sound, the problem with this approach is that when a body is constantly in contact with the static body, the sound plays indefinitely overlaying the previous one, so at the end I have huge noise..
What can I do to avoid this situation?
Please help me thanks......
You just used following method into your update method and declare its object before schedule update method call.
Like in HelloWorldLayer.h
MyContactListener *contactListener;
And in HelloworldLayer.mm
Before
[self scheduleupdate];
contactListener=new MyContactListener();
world->setContactListener(contactListener);
Than this type of error not occur.
When two bodies collide, the b2ContactListener methods are called in the following sequence:
BeginContact
PreSolve
PostSolve
PreSolve
PostSolve
...etc
EndContact
So if you want to detect collision between the bodies once for each collision, use BeginContact or EndContact instead. These methods only take a single b2Contact parameter though so you might need to do away with using the oldManifold value in your calculation.