Creating a scatter behaviour in C# - c#

Hi I am practising my coding for my university course and I have built a virtual Aquarium.
I have currently got some sea horses in there and have made a chicken leg to appear when I click. I have written some code to say when the chicken leg appears they move vertically. However I want them to scatter and not go near the chicken leg or at least bump of it. my vertical swim behaviour code is:
` private void VerticalSwimBehaviour() //Verticle Swim scatter
{
Vector3 tokenPosition = this.PossessedToken.Position;
tokenPosition.Y = tokenPosition.Y + mSpeed * mFacingDirection;
if (tokenPosition.Y > 300 || tokenPosition.Y < -300) // Responds if fish goes to the top or bottom of screen
{
mFacingDirection = -mFacingDirection;
}
this.PossessedToken.Orientation = new Vector3(mFacingDirection, this.PossessedToken.Orientation.Y, this.PossessedToken.Orientation.X);
this.PossessedToken.Position = tokenPosition;
}
private void RandomNumberMethod()
{
Random random = new Random();
int randomNumber1 = random.Next(1, 5);
int randomNumber2 = random.Next(1, 150);
}`
I want to make a behaviour that work like this but runs from the chicken leg.
here is my leg calling upon the behaviour when chicken leg appears
public override void Update(ref GameTime pGameTime)
{
Vector3 tokenPosition = this.PossessedToken.Position;
HorizontalSwimBehaviour();
velocidadMax();
if (mAquarium.ChickenLeg != null)
{
VerticalSwimBehaviour();
}
}
Any help is appreciated.

Write a method to check if the seahorses are facing the chicken. If they are, reverse their facing (do this just once). Have them keep a certain distance away from the chicken. Use the distance formula with the origin of the chicken and the origin of each seahorse. If they are within that distance have them run straight in one direction until they hit a wall. When they hit the wall, have them turn 90 degrees right or left and do it again. Do this behavior until they are far enough away from the chicken. I would probably make the distance about 40% of the tank size (as a diameter) to ensure that they can find a corner to hide. Hopefully this helps, I haven't used Unity so I don't know specific methods to call. It should be simple object manipulation though. I would also add some effects to your vertical oscillation, perhaps increasing its frequency with a multiplier based on closeness to the chicken (lower oscilation distance, higher velocity). As for avoiding the running in the the chicken, You can set a minimum distance to the chicken (this one much closer) which will cause your seahorse to turn around if it gets too close, in which case it will resume its running to a wall and turning. All of this checking should run while the chicken leg exists.

Related

Transform EulerAngles Error

I have a condition that makes a check. Like this:
if (moveDown)
{
Debug.Log("hit1");
if (RightTowers[rightIndex].transform.GetChild(2).transform.eulerAngles.z <= -40f)
{
moveDown = false;
moveUp = true;
}
else
{
RightTowers[rightIndex].transform.GetChild(0).gameObject.GetComponent<SpriteRenderer>().sprite = Mirrors[mirrorIndex++];
rotateAngle = Quaternion.Euler(0f, 0f, RightTowers[rightIndex].transform.GetChild(2).eulerAngles.z - angle);
RightTowers[rightIndex].transform.GetChild(2).transform.rotation = rotateAngle;
}
}
if (moveUp)
{
Debug.Log("hit2");
if (RightTowers[rightIndex].transform.GetChild(2).transform.eulerAngles.z >= 40f)
{
moveDown = true;
moveUp = false;
}
else
{
RightTowers[rightIndex].transform.GetChild(0).gameObject.GetComponent<SpriteRenderer>().sprite = Mirrors[mirrorIndex--];
rotateAngle = Quaternion.Euler(0f, 0f, RightTowers[rightIndex].transform.GetChild(2).eulerAngles.z + angle);
RightTowers[rightIndex].transform.GetChild(2).transform.rotation = rotateAngle;
}
}
The problem is that when the object is rotated to -40 degrees, and the condition is checked it does not deactivate moveDown and activate moveUp. He further rotates the object with angle index.
I do this rotation when I click on a button. He must, when he reaches -40 degrees, deactivate me moveDown. Why not disable it?
First things first, create some intermediate fields, your code is really heavy, and you're actually accessing the data each time because of all the nested calls you are making, and it's really making it unclear, especially for anyone outside of your project.
Secondly, I don't see the point of having 2 booleans which are the exact opposite value of each other.. you'd get the same result having just one since they are inversed.
That being said, I believe (from what I got from your snippet) that you're probably not in the degree range you might think ? I don't know if you have verified that but, your character could look totally normal, exactly like you have place him originally, but he might have a 360, 720 etc... degree rotation applied(can be negative too), so if you are not looking at the rotation between initial position and desired, you might not get the right values, maybe do a RotationDifference() func, or if (rotation == 360 or -360) rotation = 0 I'm just throwing out ideas, you really have many ways of doing it.
Lastly, your code seems quite heavy for a seemingly mundane task, you should look into that. Try to abstract your tasks, you are trying to do everything at once, instead of having sturdy systems taking care of it.
(new answer after comments)
The logic you want is not appearing "clearly" while reading the code, this makes difficult to debug and understand what is wrong !
As per your comment, I understand that you need move back and forth from -40 to 40.
First, we need to clearly separate the tasks
The two separate tasks are :
Decide in which direction tower is moving next step.
Move the tower up or down. This is basically the two 3-lines blocks of code. Let's call these blocks "MoveUp()" and "MoveDown()"
Now, write some pseudo code for it
// pseudo code
// First, decide in which direction to go
if current angle is 40° (or more),
set direction to down for next move.
else if current angle is -40 (or less),
set direction to up for next move.
else
just continue in the current direction
// Second, move the tower
if direction is down, move down
else move up.
Let's translate this to real C# code
// suppose you have a private bool variable in your class
// called "isMovingDown"
private bool isMovingDown = false; // inital value, could be true if you want
// call this in your Update or FixedUpdate logic
private void MoveYourTowerLogic() {
// First : decide in which direction to go :
var currentAngle = RightTowers[rightIndex].transform.GetChild(2).transform.eulerAngles.z;
if (currentAngle >= 40f)
{
isMovingDown = false;
}
else if (currentAngle <= -40f)
{
isMovingDown = true;
}
// else current angle is between 40 and -40
// we simply need to o nothing, because we want to keep the previous direction set.
// remember, the variable movingDown is declared at the class level,
// so it 'remembers' the last value set from last call
// Second : Move the tower
if (isMovingDown)
{
MoveDown();
}
else // tower is moving up
{
MoveUp();
}
// NOTE : I would simply create one function Move(int angle)
// to simplify this much further and avoid to write all this mostly useless code before
// but I want to keep this simple to understand for now
}
private void MoveDown()
{
// logic to move tower down
}
private void MoveUp()
{
// logic to move tower up
}
Notice how reading this is much more "human-friendly" now, you can now, I hope, read this more easily, and that will help you modify it if you want to do more complex things later.
I strongly suggest you to avoid writing the same code several time. You can notice how I simplified and wrote only once the logic to get the angle into a variable named exactly like what I was thinking in my pseudo code.
Also, to write the methods "MoveUp" and "MoveDown", you can simply copy paste your actual code into them. But then after, you could even refactor them to avoid code repetition.
Like this :
(Edit)
Let's refactor this further
Basically, the moving logic is a completely separate task, and the only difference between moving up and down is the + or - angle.
Also, maybe you want to move your towers with a different angle later. It make sense to say that the rotation of tower depends only on the angle.
So let's create a method for that has only the angle as parameter.
With something like, instead of MoveUp() and MoveDown() :
private void MoveTower(int angle)
{
RightTowers[rightIndex].transform.GetChild(0).gameObject.GetComponent<SpriteRenderer>().sprite = Mirrors[mirrorIndex++];
rotateAngle = Quaternion.Euler(0f, 0f, RightTowers[rightIndex].transform.GetChild(2).eulerAngles.z + angle);
RightTowers[rightIndex].transform.GetChild(2).transform.rotation = rotateAngle;
}
The second part will be greatly simpler :
// Second, move the tower
MoveTower(isMovingDown ? angle : -angle);

Moving an enemy back and forth in Monogame / XNA

I am trying to achieve a very basic 2D game right now where an enemy is on the screen and it bounces back and forth between set points (50 and 500) kind of like a space invaders sort of thing. My issue is I can only get it to go right, but then not come back towards the left and repeat.
I was messing around with coding it myself before bothering to look into it and actually figure it out but I thought I had something that would work, but well it doesn't, my issue is I don' get why.
My code is supposed to work like a switch, two if statements within the Update loop, one comes on the other goes off, one moves it right the other moves it left, I thought that was fine but it doesn't do that. It moves it right just fine but then the left part just doesn't work.
So, why does the following code not work?
namespace _2D_game_num1
{
class Enemy
{
int health;
Vector2 enemy_location = new Vector2(50, 50);
Vector2 enemy_speed = new Vector2(1, 1);
Player player = new Player("dummy");
public Enemy()
{
health = 100;
}
public void UpdateLocation()
{
//Vector2 player_pos = player.GetLocation();
//if (player_pos.X < 200)
// Using the players location to figure out where the enemy should move
bool right = true;
bool left = false;
if (right)
{
enemy_location.X += enemy_speed.X;
if (enemy_location.X == 500)
{
right = false;
left = true;
}
}
if (left)
{
enemy_location.X -= enemy_speed.X;
if (enemy_location.X == 50)
{
right = true;
left = false;
}
}
}
public Vector2 GetLocation()
{
return enemy_location;
}
}
}
And then in the main Game class I have it so enemy1.UpdateLocation(); is within the Update section correctly (along with my players movement which works fine).
Try this:
public void UpdateLocation()
{
enemy_location.X += enemy_speed.X;
if (enemy_location.X <= 50 || enemy_location.X >= 500)
{
enemy_speed.X = new Vector2(-enemy_speed.X, enemy_speed.Y);
}
}
What we are doing here is moving the enemy based on it's current speed. Then if the location is on the left or right of the screen, change direction.
Sometimes it pays to keep things simple. Get rid of the left and right flags, as they are just confusing things. When you're dealing with Update methods you're typically changing the state of something. The way you had it before, the left and right state was getting reset every time UpdateLocation is called.
Btw, you might want to consider passing in GameTime to your Update methods. Typically, when you're moving things around in real-time you'll want to multiply movement by some kind of deltaTime to keep things smooth on all devices. You're probably getting away with it because by default it'll be a fixed frame rate, but that may not always be the case, so it's a good habit to get into.

Make GameObject “attach” properly?

This script makes a cube "stick" to whatever it collided with. The problem is that when it's going at relatively high or medium speeds (or when the device itself is slow), the cube tends to "get a bit inside" what it collided with and then stick to it. What changes do I have to make to fix this?
In order for this script to work, one GameObject must have bool _sticksToObjects = true; and the other bool _sticksToObjects = false;
I have tried turning the Rigidbody's Collision Detection mode to either Continuous or Continuous Dynamic
I think my script depends on frame rate. That may be where the problem lies.
Normal "Attach":
Abnormal "Attach":
Rigidbody _rigidBody;
Transform _meshTransform;
bool _sticksToObjects = true;
public Transform _stuckTo = null;
protected Vector3 _offset = Vector3.zero;
void Awake()
{
GameObject CubeMesh = GameObject.FindWithTag ("CubeMesh");
GameObject Cube = GameObject.FindWithTag ("Cube");
_rigidBody = Cube.GetComponent<Rigidbody> ();
_meshTransform = CubeMesh.GetComponent<Transform> ();
}
void Update()
{
if (_stuckTo != null)
{
transform.position = _stuckTo.position - _offset;
}
}
void OnCollisionEnter(Collision collision)
{
if (!_sticksToObjects) {
return;
}
_rigidBody.isKinematic = true;
// Get the approximate collision point and normal, as there
// may be multipled collision points
Vector3 contactPoint = Vector3.zero;
Vector3 contactNormal = Vector3.zero;
for (int i = 0; i < collision.contacts.Length; i++) {
contactPoint += collision.contacts [i].point;
contactNormal += collision.contacts [i].normal;
}
// Get the final, approximate, point and normal of collision
contactPoint /= collision.contacts.Length;
contactNormal /= collision.contacts.Length;
// Move object to the collision point
// This acts as setting the pivot point of the cube mesh to the collision point
transform.position = contactPoint;
// Adjust the local position of the cube so it is flush with the pivot point
Vector3 meshLocalPosition = Vector3.zero;
// Move the child so the side is at the collision point.
// A x local position of 0 means the child is centered on the parent,
// a value of 0.5 means it's to the right, and a value of -0.5 means it to the left
meshLocalPosition.x = (0.5f * contactNormal.x);
_meshTransform.localPosition = meshLocalPosition;
if (_stuckTo == null || _stuckTo != collision.gameObject.transform) {
_offset = collision.gameObject.transform.position - transform.position;
}
_stuckTo = collision.gameObject.transform;
}
Here are some screenshots of the Unity editor:
This is a well-known category of problem in game engineering and you'll be pleased to know the solution is relatively simple. You'll be pleased to hear there are similar, but much more complicated, problems that are actually solved in the same way. I'll try to explain.
Now here's the thing. It's quite often that the following question comes up...
So I'm working on GTA. I have a humanoid, H, running around. She approaches vehicle V. She opens the door and gets in and drives off. After that everything goes to hell in Mecanim and all the code stops working. What to do?
Surprisingly, the way that is done in games is:
Surprisingly: you actually swap to totally different models at that point!!!!!
You have H and V in the game. But then you have an animation (say) for H climbing in to V. But then, you literally destroy the game objects of H and V, and you Instantiate (or just awake) a new, totally different, game object, which is D ("a car being driven around by a lady").
(If you think about it, you can see that when you do this, you carefully adjust all the stuff in D, so that it matches what was "just then happening" in the frame, in relation to both H and V. So for example, literally, you copy the transform, twist etc of the car V, to the new car-inside-D, if lady H has the SmearedMakeupEffect, you put the same SmearedMakeupEffect on the lady-within-D, you position all the bones identically, and so on.)
Another simple example of this is, you often get people asking, "my character C gets killed and I want it to become a ragdoll, how to?" In fact you just swap to a totally new game object you have all set up for that passage of the game. Indeed, if you have a character A ("Arnie") in a game, it's normal that you have 4 or 5 "different As" sitting offside the stage, so, there's "ragdoll A", "A who can dance" "A with weapon". And indeed many of these are combos, you know "A on the horse" "A in the car" and so on.
So interestingly, the "real" solution here is,
once they become a new connected thing, destroy them both and swap to a new game object altogether!
if you have made games "until you are blue in the face" from making games, this is just what you would do as a matter of course. Even though its' a simple situation, it's just easier in the long run. After all, consider all the stuff you have to do when this happens:
make hitting object child of the other
turn off physics on the child
change the way your physics works for the whole thing
turn off or change the collider on the hitting object, perhaps making it part of the overall object
you'll likely have some sort of new "separation" physics where it can be knocked-off - you'd have to turn all that on
likely change minor issues like sound effects, colors etc
As you can see it's a huge chore doing all this stuff, and indeed it's one of those things it's just "easier to do properly" and change to a new model.
All that being said, I know you want a Quick Script Solution you can Paste In :) Here it is...
Step 0, You'll create "YourScript" which goes on the "main" cube. it will "catch" another cube moving around.
YourScript will look basically like this ...
[System.NonSerialized] public bool isConnectedNow;
void OnCollisionEnter(Collision collision)
GameObject theThingWeCaught = collision.gameObject
Debug.Log("We caught this thing .. " + theThingWeCaught.name)
// make it a child of us......
theThingWeCaught.transform.parent = transform
theThingWeCaught ... set kinematic
theThingWeCaught ... probably disable the rigidbody
theThingWeCaught ... probably disable the collider
isConnectedNow = true;
That's really all you have to do.
Step 1, YOUR script must have a public bool like this
[System.NonSerialized] public bool isConnectedNow;
Step 2, Here's MyScript which goes on the hitting cube, first we'll unit-test that your isConnectedNow bool is working
public Class MyScript:MonoBehaviour // attach to the "child" cube
{
public float correctXDistance;
public float correctYDistance;
public Transform bigCube;
public YourScript yourScript;
void Update()
{
string message = yourScript.isConnectedNow ? "free" : "stuck";
Debug.Log("I am " + message);
}
}
attach, debug, and run. Make the little cube stick and unstick from the big cube .. Watch the console. it works? So add this to MyScript
private void DistanceCorrectionX()
{
float xDistance = bigCube.position.x - transform.position.x;
float xSign = Mathf.Sign(xDistance);
float xDelta = Mathf.Abs(xDistance);
float closenessPercentage = (xDelta/correctXDistance)*100f;
if ( closenessPercentage<90f || closenessPercentage>110f)
{
// they are not close enough to quantize on this axis
// this comes in to play when you have multiple axes
return; // do nothing.
}
float xShouldBe = bigCube.position.x + xSign * correctXDistance;
Vector3 p = transform;
p.x = xShouldBe; // be careful it's .y, .z etc for other axes
transform.position = p;
}
for now call that in Update() in MyScript like this
void Update()
{
Debug.Log("I am " yourScript.isConnectedNow ? "free" : "stuck");
if (yourScript.isConnectedNow) DistanceCorrectionX();
}
Now actually Play and make it stick. Now, since it's running in Update simply while Play look at the Inspector for MyScript and adjust the value of correctXDistance to get the exact look you want. When yo have decided on a value, unPlay and put that in as the final value you wish.
Next, in DistanceCorrectionX simply duplicate all the code and do it again for the Y axis DistanceCorrectionX. If you also do Z, do that.
Finally. Note you will have a lot of messy code, like this...
void Update()
{
// handle all the DistanceCorrectionX etc as seen above.
if (yourScript.isConnectedNow)
{
.. turn off the collider on me
}
else
{
.. turn on the collider on me
}
}
and so on, there's "many little things" you'll need to do.
Don't forget also, overwhelmingly you may want to make the hitting object a child of the big object, depending on your situation. (Then of course they would move around together as a unit.)
Note that in the positioning code above I just showed it as position, not local position, for pedagogic clarity. If you want to do them flinging around, and spinning and so on, you'd make the hitting object a child of the other and you would use localPosition in the same way. Enjoy.
One possible way that comes to my mind is:
Inside of the "collision enter" check the distance between these objects and move the one that should stick to the other one a bit away.
As you see in the picture the distance between A and B should be equal to the sum of the widths divided by 2 (with a small threshold of course).
If the distance is less than the sum of the widths / 2 then you have an abnormal "attach" and you have to move one of the objects away. Its not really difficult to accomplish that.

Jump animation using animation class

I need a little help in my little 2D game I want to create in XNA. I had almost no knowledge of programming before I got interested in XNA and C#, so maybe my problem is simple, but I just can't figure it out.
So basically, I have a base class, and I created an additional class Animation for animating sprites. I implemented some methods so that when the player presses "right" it would change the animation's current texture and increment X by a number of xf; anyway, the main idea is that I'm using just one instance of my class (basically, one object of type animation which changes its texture and properties based on what key is pressed).
So, I had no problems making it run right or left. Works out pretty well. The big problem started when I wanted to implement the jump sprite. So I created the 6 frames necessary for the sprite, but to animate it I have virtually no idea how to do it.
The only thing it does right now is to loop through the frames of the sprite, but the position (both .X and .Y) remain the same. The thing is, I have a Vector2 position which holds the animation's current position, and it's fine with running because I simply increment it. However, when it comes to jumping, I want it to increment .X, but the .Y should be decremented (thus going up) until frame number 3; after frame number 3, until the last frame, I want the .Y position to go down (thus fall) with the corresponding animations (erm, frames).
So, basically, I don't know how to modify the .X and .Y so that it would display the frames that I need in the time I need. I don't know if you really understood what I'm trying to say; basically when I press the "up" key, it loops through the frames but the position remains the same.
My idea was to use a reference to the actual Vector2 position which holds the animation's current position and pass it to the method in the other Animation.cs class, namely the PlayAnimJump, and modify the position after each frame and return it to the actual Game1.cs by reference. Even if I would do that (though I fail to see what good it would be), it wouldn't be updating the position as it should. So, any ideas?
Here is the code for the PlayAnimJump method from the Animation class:
public void PlayAnimJump(GameTime gameTime)
{
elapsed += (float)gameTime.ElapsedGameTime.Seconds;
sourceRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
currentFrame = 0;
if (elapsed >= frameTime)
{
if (currentFrame <=3)
{
if (looping)
{
currentFrame++;
}
}
else if (currentFrame > 3)
{
currentFrame++;
}
elapsed = 0;
}
}
The default constructor for that class:
public Animation(ContentManager Content,string asset,float frameSpeed, int numbOfFrames, bool looping,Vector2 positionIT)
{
this.assetName = asset;
this.frameTime = frameSpeed;
this.numbOfFrames = numbOfFrames;
this.looping = looping;
this.animation = Content.Load<Texture2D>(asset);
frameWidth=(animation.Width / numbOfFrames);
frameHeight=animation.Height;
position = positionIT;
}
Here is the code (from the main) when the up key is pressed:
else if (up)
{
check = animation1.GetAsset();
if (check == "eright")
{
animation1.SetFrameSpeed(0.8f);
animation1.SetNumbOfFrames(6);
animation1.ChangeTexture(Content, "SarimCumVreJiorjica");
animation1.PlayAnimJump(gameTime);
/*position1.x +=2f;
position1.Y -=2f;
*/
}
So, I'm not sure how, but I'm supposed to change position1 according to the frame that's displayed by the animation in that second. Am I missing something?
If your animation class had a reference to the object that you wanted to move (i.e the object holding the position field) then you could modify it within the animation class, within the PlayAnimJump method.
Or, to reduce coupling, you could just have PlayAnimJump return a variable indicating how far into the jump you are (maybe a percentage of the jump, from 0 to 1). Then, you could use the percentage outside to set the objects position. So, if the jump is halfway done, the return value would be 0.5f, which you could use in an equation to determine the players y position. An example equation would be:
float percent = animation1.PlayAnimJump(gameTime);
float y = Math.Sin(percent * Math.PI) * maxJumpHeight;
player.positon.y = y;
This uses a sine wave to determine the players height throughout the jump animation. You would just need to write the code that determines the percentage of the way through the jump (currentFrame) in the PlayAnimJump method and return it.
Formula of the frуefall for Y coordinate is
y = g * t ^ 2 / 2 + v0 * t + y0
Characters jump from height y0 vith start velocity v0 by Y axis and gravity gradually slows down and starts to fall.
Calculate deltaY using following formula
deltaY = g * t ^ 2 / 2 + v0 * t
First show the frame on which the character is pushed off the ground, then the frame on which it rises until it reaches the peak of the jump. Once the sign change deltaY from + to - show how the character change pose for fall. Something like that.

OnCollision event handler problems in C# XNA with Farseer Physics

I have this working ok(ish) in my game at the moment, but i'm not fantastic at maths. When two primatives collide, I want them to smash up into tiny bits if the force applied to a primative was over a set threshold. My collision event handler at present looks like this.
public bool Collision(Fixture fixtureA, Fixture fixtureB, Manifold manifold)
{
Vector2 position = manifold.LocalNormal;
float angle = (float)Math.Atan2(position.Y, position.X);
Vector2 force = Vector2.Zero;
if (angle < 0)
force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi + angle) * fixtureA.Body.LinearVelocity.Y);
else
force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi - angle) * fixtureA.Body.LinearVelocity.Y);
double XForce = Math.Sqrt(force.X * force.X);
double YForce = Math.Sqrt(force.Y * force.Y);
double totalForce = XForce + YForce;
if ((Breakable) && (totalForce > BreakForce))
{
Breakable = false;
Active = false;
BreakUp(fixtureA, fixtureB);
}
return true;
}
I put that in a LONG time ago when I was just playing around. This causes a bit of a problem in certain situations. For example, if a primative is stationary on the floor and another primative falls onto it from a decent height, almost always, the falling box blows up and the resting box survives. Also if two boxes are falling side by side and give each other the tinyest of touches, then both boxes blow up mid air. Hmmmmm, not really perfect that. Does anyone have any idea how to improve my collision handler? Thanks in advance.
Ok, so my other answer is viable. But I've looked at Farseer 3.0 (the current SVN version) more closely and found that it already implements almost exactly what you are trying to do.
Look for "BreakableBody.cs". You may be able to directly use that - but otherwise you could just copy out the functionality you want.
Specifically: Instead of attaching a function to your fixture's OnCollision you want to attach one to PostSolve. It takes a ContactConstraint which you can dive into and find the impulses from the collision.
This is the implementation of that function used by BreakableBody:
private void PostSolve(ContactConstraint contactConstraint)
{
if (!Broken)
{
float maxImpulse = 0.0f;
for (int i = 0; i < contactConstraint.manifold.PointCount; ++i)
{
maxImpulse = Math.Max(maxImpulse,
contactConstraint.manifold.Points[0].NormalImpulse);
maxImpulse = Math.Max(maxImpulse,
contactConstraint.manifold.Points[1].NormalImpulse);
}
if (maxImpulse > Strength)
{
// Flag the body for breaking.
_break = true;
}
}
}
Apparently the impulse data in the manifolds is only set correctly in PostSolve, not in OnCollision.
(While this is currently the accepted answer - I would direct anyone to my other answer for a potentially superior approach.)
Your calculation of impact force is completely wrong. You need to get the relative velocity at the contact point(s) - you're getting something quite strange...
Your code looks like it's using Farseer 3.0 (you should specify, because that's more of a fork of Box2DX than Farseer 2.1). What I did in Farseer 2.1 (where you've got ContactList contacts instead of a Manifold) to get the impact velocity was:
foreach(Contact contact in contacts)
{
Vector2 position = contact.Position;
Vector2 v0;
me.Body.GetVelocityAtWorldPoint(ref position, out v0);
Vector2 v1 = new Vector2();
if(!hit.Body.IsStatic)
hit.Body.GetVelocityAtWorldPoint(ref position, out v1);
v0 -= v1;
float hitVelocity = v0.Length();
// To then get the force, you need the mass of the two objects
}
From a brief look at the Farseer 3.0 source, it seems that Manifold has a member:
public FixedArray2<ManifoldPoint> Points;
And both Manifold and ManifoldPoint have members:
public Vector2 LocalPoint;
It should be fairly simple to modify my Farseer 2.1 code to use those instead.
Also: I recommend simply marking the two objects as needing to break, and then actually breaking them after your physics update finishes running (rather than in the collision handler).
I haven't used XNA, but as a physics problem, why not just subtract the linear velocity of A from the linear velocity of B, and get the 'force' as the square of the resulting vector (sum the squares of the components)? That should harmonize with the kinetic energy involved according to `E=(mv^2)/2', for a very simple physical model, even if we are ignoring the masses (or, for that matter, elasticity or the distinction between energy and momentum). If the objects are moving in the same general direction at the same speed, you get a small value; if one is approaching (or, of course, departing!) at high speed, you get a large value.

Categories