A Few questions

Topics: Developer Forum, User Forum
Mar 9, 2010 at 5:32 PM

I'm working on making a game where 4 players use sound waves to navigate a ball through a maze towards a goal. I'm using Farseer to handle all of my physics and so far it's been wonderful. There are a few things that I can't get worked out.  

Just some setup info, players emit a soundwave body/geom/texture from their respective speakers to move the ball body/geom/texture;

I want the soundwaves to move at a constant velocity. So far I've been using waveBody.ApplyImpulse() in the update() method. This works pretty well but when the wave object collides with our ball it slows down momentarily. 

Also, and this may be tough to explain, but I want our ball to collide with the wave, but I don't want the wave to collide with the ball. In other words, I want the ball to react the collision normally, but I want the wave to just continue on like nothing happened. Is this possible? Setting waveGeom.IgnoreCollisionWith(ballGeo) doesn't work.

Thanks.

Mar 10, 2010 at 3:47 PM

I've been trying my best to work around this.

I've figured that if I can come up with a way to test for collision between my wave and ball then I can disable it after words and allow it to continue forward.

I've been looking at the OnCollision method. I've found a few examples here on the discussions such as http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=204039 and BramDeMoors post in this thread (http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=82517).

Both appear that they would always return true. Am I missing something? 

Mar 11, 2010 at 11:46 PM
Edited Mar 12, 2010 at 11:01 PM

Edit: my bad, i read the post too quick. My solution was for making the ball to not react.

Maybe you can try to rewrite the OnCollision method on both: in the waveBody side to return false if the geom.Tag=="ball", and in the ball side to apply and impulse manually if the geom.Tag==""wave".

Mar 12, 2010 at 2:59 PM

oooh that's a crazy one.

I suggest creating a clone upon collision.

One will collide and the other will keep on going.
Remember, if there's a one sided collision it would keep on colliding causing what I would call, EXTREEEEME collision- which is scary.

Let's see here... I can think of 2 ways:
This method creates a clone of the wave after the impact

private bool OnCollision(Geom geom1, Geom geom2, ContactList contacts){

if(!wave.collided)

{
wave.collided = true;
clonedWave = new Wave(collidingWave);
collidingWave.Kill();
clonedWave.collided = false;
return true;
}
return false;

}

 

This isn't exactly the most elegant solution as it creates a new wave for each collision (so it'll be called once every time you use a wave that hits the ball)
So here's method 2:

private bool OnCollision(Geom geom1, Geom geom2, ContactList contacts){

 

if(!wave.collided){

geom2.body.ApplyImpulse(new Vector2(calculate direction of wave and force here. Most likely just the direction of the force));

wave.collided; //This is so the wave doesn't pierce the ball causing multiple collisions (especially because impulses stack upon each other and cause unpredictable collisions this way)
}
return false; //this indicates the normal collision is disabled, but allows the oncollision to be called when contact points collide

}

This method kills the collision of the wave upon impact- it means the wave cannot hit another object during its lifetime. But method 1 has the same drawback. I guess method2 is just superior
Instead of using the bool you can set geom1.IsCollisionEnabled of the wave to off as well. Be sure to reenable upon each iteration of the wave though.
These are merely suggestions and have not been used in any prototype.

Cheers,

-Casey

 

Mar 14, 2010 at 8:48 PM

Yeah, that's a really good suggestion Casey. I actually got something similar working, but I have a new problem related to the OnCollision method.

Like I suggested in my second post, I'm not all that clear on how the OnCollision method works, but I've been toying around with it. I have a ball class where I create the ball Body and ball Geom. When the ball comes in contact with any item I want it to play a bouncing sound effect. The problem I'm having now is that when the game starts and the ball is stationary it constantly plays the sound until the ball actually comes into contact with something.

 

Here's what I've got so far.

 

 

        public Ball(ContentManager Content, PhysicsSimulator physSim, Rectangle LevelArea)
        {
            content = Content;
            sim = physSim;
            levelArea = LevelArea;
            bounce = content.Load<SoundEffect>("Sound Effects/BallBounce");
            ballTexture = content.Load<Texture2D>("Ball/BALL");
            ballOrigin = new Vector2(ballTexture.Width / 2, ballTexture.Height / 2);
            ball = BodyFactory.Instance.CreateCircleBody(ballTexture.Width/2, 1);
            ball.Position = new Vector2(1280 / 2, 720 / 2);
            ballGeo = GeomFactory.Instance.CreateCircleGeom(ball, ballTexture.Width/2, 48);
            ballGeo.CollisionGroup = 2;
            sim.Add(ball);
            ballGeo.FrictionCoefficient = 0.5f;
            ballGeo.RestitutionCoefficient = 0.5f;            
            sim.Add(ballGeo);
            ballGeo.OnCollision += OnCollision;
        }
        public bool OnCollision(Geom geom1, Geom geom2, ContactList list)
        {
            bounce.Play();
            return true;
        }

 

 

Mar 14, 2010 at 9:18 PM

Something this simple is magically ridiculously hard because of physics.

A good solution would be to have a boolean that says the ball is on the ground.

               float lastCollided = 0;
               bool grounded = false;

        public Ball(ContentManager Content, PhysicsSimulator physSim, Rectangle LevelArea)
{
grounded = true;
content = Content;
sim = physSim;
levelArea = LevelArea;
bounce = content.Load<SoundEffect>("Sound Effects/BallBounce");
ballTexture = content.Load<Texture2D>("Ball/BALL");
ballOrigin = new Vector2(ballTexture.Width / 2, ballTexture.Height / 2);
ball = BodyFactory.Instance.CreateCircleBody(ballTexture.Width/2, 1);
ball.Position = new Vector2(1280 / 2, 720 / 2);
ballGeo = GeomFactory.Instance.CreateCircleGeom(ball, ballTexture.Width/2, 48);
ballGeo.CollisionGroup = 2;
sim.Add(ball);
ballGeo.FrictionCoefficient = 0.5f;
ballGeo.RestitutionCoefficient = 0.5f;
sim.Add(ballGeo);
ballGeo.OnCollision += OnCollision;
}
public bool OnCollision(Geom geom1, Geom geom2, ContactList list)
{
if(!grounded) bounce.Play();
grounded = true;

lastCollided = gametime; //this is a float to keep track of the last time this ball has collided
return true;
}

in my game (a platformer) grounded = false; whenever I jump. I need this because I only call jump if my character is on the ground. Obviously I need checks to see if he is touching a sidewall (or use a completely different geom set for walls).

In your game however, I suggest setting grounded to false if the ball has not collided with anything for 1/10 of a second. This means if the ball is in the air for 1/10 of a second it will know that it is in the air. If the ball touches two objects within 1/10 of a second, the second bounce will not play a sound.
Since the micro collisions (separate, collide, separate, collide, separate, collide) happens every other frame, it can't possibly be triggered while on ground unless the framerate of the person playing is 10 frames per second.
Some pseudo code:

public void Update(GameTime gametime)
{
if(gametime.milliseconds - lastCollided > 100)
{
grounded = false;
}
}

I suck at formatting code in my responses as i just type them out...
I'm not sure if this works, as I haven't tested it.
I also suggest scaling the ball bouncing sound's volume depending on its LinearVelocity (just add together the absolute values of the X and Y velocities and scale it). But that's just aesthetics.

-Casey
Mar 14, 2010 at 9:27 PM

You're right, it was because of physics. It was working as I had coded it.

I initially place the ball within a wall and it kept repositioning itself there until play actually started. 

I fixed it though.

Mar 14, 2010 at 10:03 PM

oh oh, I thought the problem was for every bounce, not just the initialization (which i assume was fixed by just disabling collision for a bit).

awwwkward.