Search Unity

Bubble Shooting, how to stop bullet at exact contact point?

Discussion in 'Physics' started by Tiles, Jun 4, 2015.

  1. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    I work at a little bubble clone. The game is nearly finished. You can find it at my page, including the source code. But from time to time i get wrong positioned coins. Rare enough that it took me quite a while to find the cause. But often enough to make the game unplayable.

    I use physics for shooting. Timestep is at 0.005. Bullet physics is at continuous dynamics. And i calculate the position of the bullet compared to the hit coin to calculate where the new coin has to be positioned then.

    I have logged the position of the bullet to find out what turns wrong, and to my surprise the bullet tunneled through by a really really big amount. It's more than a bullet width. The bullet itself has a size of 1.The other hundrets of logs before just shows a inaccuracy of maximum 0.1 or so. So no wonder the calculation fails then, and i get a wrong positioned coin. See shot 1.

    And there i am, looking for a method where the bullet really stops at the target, by just touching it. And not sticking in the target, nor staying half a kilometer before but trigger already a contact, as you can see in shot 2. Some bullets sticks in the coins, some bullets are far away from it.

    This shot 2 is made in a test project. I have attached it too, so that you can see the problem more clearly and toy around with it. 480 Kb: http://www.reinerstilesets.de/ext/unity/shootingproblem.rar

    Any ideas how i can get a more accurate result? :)
     

    Attached Files:

  2. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Well for one, .005 timestep seems a big overkill.
    I do not know how you have things set up, or how you want the game to play out, but instead of shooting a physical object, why not just use Physics.SphereCast and get the hitpoint. With this, you could significantly lower the timestep, and no need for continuous dynamic lowering performance either.

    You shoot the spherecast, check for a collision, on collision you grab the collider that the spherecast provides and check its tag, or a component you placed on the object to determine what object you hit and than you can decide what to do next.

    If you want, you can keep the physics doing its thing while the spherecast does its thing in the background for accuracy. However, it would be more efficient if you just smoothly transform your bubble object from your start position to the hitpoint the spherecast gives.

    For the bubble bouncing off walls, you can do a spherecast, determine if you hit a wall, and determine the new direction for your spherecast from the hitpoint of the wall.

    Or (probably easier) have your physics do its thing, but get the direction your bubble bullet is going, and every frame shoot a spherecast in front of it (or even a sweepcast).
     
    Last edited: Jun 4, 2015
  3. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Thanks for your ideas HiddenMonk :)

    Well, i'm also unhappy that i need to set the timestep to 0.005. I would be happy to have other working solutions. And boucing off walls works fine. So no need to change this bit really.

    It's exactly this "what to do next" why i need accurate results.

    From what i can see, the problem with the spherecast method stays the same. The bullet position is still wrong at contact. And so the calculation will fail again. That's why i need accurate results at all. I have four possible contact points relative to the hit coin. A bit downwards, and side, for both left and right. The new coin gets placed dependand where the bullet hits the hit coin. And when the position of the bullet is not accurate, then i will get wrong positioned coins.

    Or do i miss a bit here?
     
  4. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Depends on what you mean by the bullet being wrong. You said the bullet "tunneled through", does this mean the bullet goes to the right place, but just goes through the coin to much, or do you mean the bullet is just completely off? Either way, From what I see from these bubble games on youtube, the bullet just goes straight or bounces off the walls but stays straight. A spherecast will just go straight, so if you bullet is completely off, than spherecast can handle it. If your bullet is just not stopping in time at its collision, than shooting a spherecast or raycast or sweepcast every frame from the bullets current position to its forward direction at x distance (could be infinity even) should fix the problem. You would get the hitpoint, which is basically the bullets goal position before the bullet even gets there. You can see what it is going to hit and do what is desired next. You can even make sure the bullet doesnt go past the hit point so the visuals stay nice (although the bubble is going to pop anyways, so no one would notice it isnt 100% accurate).

    If you are lazy and want to try something else out, maybe go to project settings physics and make min penetration amount to a smaller number, like .01 or .001
    You can also try scaling up your objects. Im not sure if small objects have harder time colliding. If you are going to scale though, people advise doing your models in a 3d program, scaling it there, applying the scale, and then importing it into unity. People say to keep scale at 1, 1, 1 for better results, though since you will probably be scaling uniformly, Idk if it would matter.
     
  5. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    I thought about scaling too. But that doesn't solve the problem really since i need to make the speed higher then too. And so i will run into the same inaccuracies again :)

    I also tried using contact.point. But that one failed as great as the simple ontriggerenter method. It simply has to fail when the bullet tunnels through by a whole bullet radius as it does.

    Well, my bullet position is the start of the whole calculation. And when the bullet is at the wrong position, then the calculation fails. It's about the bullet penetrating the hit coin at all. Or stopping ways too early. As shown in the second shot.

    I need a method that stops the bullet at exactly that point where it just touches the target coin at one point. As precise as possible. Working physics would be great here :)

    Hm, min penetration, not sure if it will be of help, since it tunneled through by a whole wall of coins as the shot shows. But thanks for this. Still, i cannot find that setting. Where is it? Do you mean default contact offset? :)

    EDIT says, accuracy with a lower Default Contact value is as bad as with default value :/
     
    Last edited: Jun 4, 2015
  6. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    http://docs.unity3d.com/Manual/class-PhysicsManager.html
    the Min Penetration For Penalty
    I see default contact offset though in the unity engine. Same thing I guess.

    Also, you have a material "bouncy" on your circle things. Is this the problem?

    With bounce set to 0 I get these results...
    BounceDisabled.png
    The circles all are very close to each other now.

    So, take bounce material off the bullet, and instead give it a material with everything 0, but set bounce combine to maximum.
     
    Last edited: Jun 4, 2015
  7. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Replace your bullet script with this ;)
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class BulletSphereCast : MonoBehaviour
    5. {
    6.     public float speed = 500;
    7.     public float positionX;
    8.     public float positionY;
    9.     public bool hasHitSomething;
    10.  
    11.     Rigidbody myRigidbody;
    12.     float radius;
    13.     Vector3 previousPosition;
    14.  
    15.     void Awake()
    16.     {
    17.         myRigidbody = gameObject.GetComponent<Rigidbody>();
    18.         radius = gameObject.GetComponent<SphereCollider>().radius * transform.localScale.x; //expects scale to be uniform.
    19.         myRigidbody.AddForce(transform.forward * speed);
    20.         previousPosition = transform.position;
    21.     }
    22.  
    23.     void FixedUpdate()
    24.     {
    25.         CollisionCheck();
    26.     }
    27.  
    28.     void Update()
    29.     {
    30.         CollisionCheck();
    31.     }
    32.  
    33.     void CollisionCheck()
    34.     {
    35.         if(!hasHitSomething)
    36.         {
    37.             RaycastHit hitInfo;
    38.             Physics.SphereCast(previousPosition, radius, (transform.position - previousPosition).normalized, out hitInfo, Vector3.Distance(transform.position, previousPosition) * 2);
    39.             if(hitInfo.collider && hitInfo.collider.gameObject.CompareTag("Bullet") && hitInfo.collider.transform != transform) //making sure it doesnt somehow hit ourselves
    40.             {
    41.                 Vector3 velocity = myRigidbody.velocity.normalized;
    42.                 myRigidbody.isKinematic = true;
    43.                 transform.position = ExtPhysics.SphereCastCenterOnCollision(transform.position, radius, velocity, hitInfo.point);
    44.                 positionX = transform.position.x;
    45.                 positionY = transform.position.y;
    46.                 hasHitSomething = true;
    47.             }
    48.             previousPosition = transform.position;
    49.         }
    50.     }
    51. }
    52.  
    53.  
    54. public partial class ExtPhysics
    55. {
    56.     public static Vector3 SphereCastCenterOnCollision(Vector3 origin, float radius, Vector3 directionCast, Vector3 hitPoint)
    57.     {
    58.         Vector3 localOrigin = Vector3.zero;
    59.         Vector3 localHitPoint = hitPoint - origin;
    60.      
    61.         float originHitPointDistance = Vector3.Distance(localOrigin, localHitPoint);
    62.      
    63.         Vector3 localEndPoint = localOrigin + (directionCast * originHitPointDistance);
    64.      
    65.         Vector3 sphereCastCenter = ExtMathf.SphereLineIntersect(localOrigin, localEndPoint, localHitPoint, radius)[1];
    66.         sphereCastCenter = origin + sphereCastCenter;
    67.         return sphereCastCenter;
    68.     }
    69. }
    70.  
    71. public partial class ExtMathf
    72. {
    73.     public static Vector3[] SphereLineIntersect(Vector3 lineStartPoint, Vector3 lineEndPoint, Vector3 sphereCenterPoint, float sphereRadius)
    74.     {
    75.         Vector3[] intersectPoints = new Vector3[2];
    76.      
    77.         Vector3 startPointEndPointDifference = lineEndPoint - lineStartPoint;
    78.      
    79.         float a = Vector3.Dot(startPointEndPointDifference, startPointEndPointDifference);
    80.         float b = 2f * Vector3.Dot(startPointEndPointDifference, lineStartPoint - sphereCenterPoint);
    81.         float c = Vector3.Dot(sphereCenterPoint, sphereCenterPoint) + Vector3.Dot(lineStartPoint, lineStartPoint) - 2f * Vector3.Dot(sphereCenterPoint, lineStartPoint) - (sphereRadius * sphereRadius);
    82.      
    83.         float delta = b * b - (4f * a * c);
    84.      
    85.         //Find the two intersections.
    86.         if (delta > 0)
    87.         {
    88.             float SquareRootDelta = Mathf.Sqrt(delta);
    89.          
    90.             float intersect1 = (-b + SquareRootDelta) / (2f * a);
    91.             float intersect2 = (-b - SquareRootDelta) / (2f * a);
    92.          
    93.             intersectPoints[0] = (startPointEndPointDifference * intersect1);
    94.             intersectPoints[1] = (startPointEndPointDifference * intersect2);
    95.         }
    96.      
    97.         return intersectPoints;
    98.     }
    99. }

    The math in the SphereLineIntersect wasn't done by me. I got no idea whats going on there.

    You can keep the fixedtimestep at .02 as it was in the scene you gave me. If you want it even lower than the speed of things will change unless if you use Time.DeltaTime in your addforces.

    Let me know if this works out for ya.

    Note that it might be possible for the spherecast to not catch a collision its first try cuz of how I am doing the distance for the spherecast. I kindof hacked that math in, so it could probably be done better. If you set the distance to something large (or add a safety offset like .1f), than there should be no issues, but the bullet will just teleport to the point. So the larger the distance of the spherecast, the larger the teleport.

    Overall I hope this gives you an idea of what I was mentioning at the start in regards to using a spherecast.

    Also keep note that anything that starts inside the spherecast will not be caught by the spherecast. So if something spawns inside the spherecast, it wont detect it (you'll notice this if you spam click the bullets).
     
    Last edited: Jun 7, 2015
  8. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Thanks HiddenMonk :)

    Well, i can't remove the bounce part. With bounce zero it doesn't bounce at the walls anymore ^^

    But interesting that it gives better results without bounce material. Shouldn't happen, since i remove every force and stop the bullet immediately. Can it really be that it first bounces off for a little bit, and then calculates its position?

    I will have a look at your script now :)
     
  9. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    "So, take bounce material off the bullet, and instead give it a material with everything 0, but set bounce combine to maximum"
    By letting the wall only have the bounce material, while giving the bullets a new material that has everything 0 but combine bounce is set to maximum, this basically means that when the bullet hits an object that has a bounce set on it, it will take the highest bounce value between the objects and use it whole. So if the walls bounce is 1, the bullets bounce when hitting the wall will be 1. If you instead set combine bounce to minimum, it will take the minimum bounce value between the wall and bullet, which is 0 since the bullet is 0, which will lead to no bounce.
    I was able to get bullets bouncing off walls just fine with this. In fact, the results should look exactly the same.
     
  10. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Ah, cool, you never stop learning. Just this bit was worth the thread. Thanks :)

    EDIT: looks like that alone this issue has fixed alot. The game play feels more reliable. The positions that i record are ways more accurate now. Seems that the physics really first bounces off and then calculates the position. Which could even explain the very big tunnel effect from shot 1 where possibly the physics went wonky with the try to escape the overlapping. And the bullet ended somewhere in the field then.

    Good thing is, i wasn't able to produce overlapping coins so far. I am even back to the standard timestep settings with 0.02 to provoke it. Nothing. Still not sure here, since the nagger needed lots of shots in the past to appear. But looking good. Fingers crossed!

    Hmm, i have meanwhile tried to understand your code. But i am still lost. Which is nothing dramatic. The parts that i have understood gave me definitely an idea how the precision problem could be solved. Even when it seems that it isn't longer necessary to implement it. So thanks again for that :)
     
    Last edited: Jun 5, 2015
  11. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    The SphereLineIntersect Method is some algorithm I found on the internet that checks to see where a line intersects a given sphere. (I don't understand the math behind this ;))
    "SphereLineIntersect(Vector3 lineStartPoint, Vector3 lineEndPoint, Vector3 sphereCenterPoint, float sphereRadius)"
    lineStartPoint - is the start of the line we want to check, which in our case is the origin of our spherecast.
    lineEndPoint - is the end of the line we want to check, which in our case can be anything longer than or equal to the spherecast distance from the origin to the hitpoint.
    sphereCenterPoint - is basically the spheres position that we want to check for a line intersect, which in our case is the hitpoint.
    sphereRadius is the radius of our sphere we want to check, which in our case is the radius of your bullet.

    We use the SphereCastCenterOnCollision method to get the center of the sphere relative to the hitpoint so we can place our bullet properly. If we just placed our bullet on the hitpoint, then the bullet will be half inside whatever it hit.
    "SphereCastCenterOnCollision(Vector3 origin, float radius, Vector3 directionCast, Vector3 hitPoint)"
    origin - is the origin (start) of our spherecast.
    radius - is the radius of our spherecast.
    directionCast - is the direction of our spherecast.
    hitPoint - is the resulting hitpoint of our spherecast.
    We put all these values into a local space in order to reduce floating point inaccuracies (I advise you to do this for anything that requires lots of precision. If you don't, then when you go out to a far area in the world, such as x = 99999, y = 99999, z = 99999, you will notice a great deal of inaccuracies. I struggled with this and had to put things into local space when doing calculations).
    We then use the SphereLineIntersect method. The line we want to check for sphere intersection is the line created by the start of our spherecast to the direction of the spherecast past or equal to the hitPoint. The sphere we are checking against, is a sphere created at the hitpoint. By checking where the line first intersects the hitpoint sphere, we can get the center of the spherecast on collision.
    We than put this back into world space.

    In Update we do a SphereCast
    "Physics.SphereCast(transform.position, radius, myRigidbody.velocity, out hitInfo, ((myRigidbody.velocity.magnitude*(2/(radius*2))))*Time.deltaTime);"
    We start at our position, our radius was calculated by getting our spherecolliders radius and multiplying it by our scale (needs to be a uniform scale), the direction of the spherecast is our current rigidbodies velocity, we out a hitInfo, and we calculate the distance.
    The distance calculation I did may not be the best, but it tries to predict ahead enough of the rigidbody so that when we get a hit and move the rigidbody to the new position, it doesn't look like it is being teleported since the distance was small.
     
  12. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Thanks for the explanation :)
     
  13. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Okay, still no luck. Thought it was fixed by the non bouncy material. But the problems remains. I still get wrong positioned coins. The problem zone is the bouncy walls. And even in the field i get inaccurate results here and there.

    I tried your script. And got problems too. Three shots later a bullet was already stuck in another bullet. The by your mentioned problem with first triggering striked back. It tunneled through the first bullet. And was stopped at the second one then.

    So i am nearly back at zero with my problem. Am at experimenting with the by you used spherecasts now ...

    Just curious, am i even at the right track with using physics here?
     
  14. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Out of curiosity, by changing this line...
    Code (CSharp):
    1. Physics.SphereCast (transform.position, radius, myRigidbody.velocity, out hitInfo, ((myRigidbody.velocity.magnitude * (2 / (radius * 2)))) * Time.deltaTime);
    to
    Code (CSharp):
    1. Physics.SphereCast (transform.position, radius, myRigidbody.velocity, out hitInfo, 1000);
    Do you get accurate results?
    Your bullets will teleport, but does it at least give accurate results?

    And in regards to using physics, its overkill imo. The SphereCast should in theory be enough. You will just have to manually handle the transform of your bullet, as well as the bounce off walls mechanic (which you could probably do by doing some vector3.cross)
     
  15. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Your input is highly appreciated. I have to test your changing. Give me a few hours :)

    Mh, physics overkill? Maybe. But it should nevertheless work ^^

    That i have to use manual methods to get a better result as with physics is the problematic part. That's why i have physics at all. But yeah, i am more and more close to the point to use transform for the movement. Never thought that the Unity physics is so inaccurate :/

    I did some experiments with CapsuleCast meanwhile to avoid tunneling with graze shots. But the results were everything but promising. The hit point was once more too far inside of the target coin. Which is crazy. Not sure if my breadboard was wrong here. Still experimenting ...
     
  16. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Tested, and yes. That's promising =)

    At least with straight shots. The trouble arrives when i shoot across the border. Then i get sometimes overlapping coins again.
     
    Last edited: Jun 7, 2015
  17. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Ye, my math for the spherecast distance was kinda just thrown in there without much testing ^^.
     
  18. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Crossposting with an edit, see above ^^

    So my trouble is the borders. And most probably again the bouncing material ...
     
  19. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Is your fixedtimestep still at .005? If so, maybe it is possible that the update method is being called less than the physics update, causing it some trouble. Try making the physics something less, and also go to project settings quality and click on fastest. This mode has vsync turned off so that you can get a lot of frames (After testing, take it off fastest as all those extra frames arent needed all the time and is just extra work for your computer)
     
  20. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    No. It's back at 0.02.

    I am completely lost at the moment how to work around the border problem and with the shooting in general. Your method with calculations works with a direct shot. But makes again trouble with the border.

    I work since several years with Unity, means i am not this unexperienced really. And i know of course the tricks with turning Vsync off for example to get maximum fps. But this "little" shooting problem gives me really massive headache. It's a can of worms, and the deeper i dig the more worms i find. Well, i know that this kind of games can be done. There are several ones in the asset store. So there must be a way. But which one? ^^
     
  21. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Im playing around with it, in the mean time, try setting Interpolation on your rigidbody to none. It might be trying to interpolate for 1 final frame before it turns back to kinematic, which might be causing issues.
    When Interpolation is on, It seems as if the bullet might jiggle a bit when it teleports, but when I disable it I dont see it doing that anymore.

    You could probably turn off continous dynamic collision detection as well.

    As long as we keep using physics, the physics will be fighting against us =)

    EDIT - I updated the script in my previous post. I made some changes to how I am doing the spherecast and I am also checking in both fixedupdate and update. This combined with disabling interpolation on the rigidbody, I think things should be all good.
    You might think there is no point in doing it in both fixedupdate and update, and while it seems 90% of the time it is in update that the collision is caught, from my testing, every now and then the collision is indeed caught in fixedupdate. Now it seems that if I did catch it in fixedupdate, but didn't do anything about it, than update also catches the collision. However, I wonder if theoretically the fixedupdate did a double fixedupdate, so in 1 of the fixedupdates it collides, and then instead of update, another fixedupdate happens. If we dont check for a collision between those 2 fixedupdates, maybe we will miss the collision, causing the rigidbody to bounce.
    Maybe you could set a bool in update such as didUpdate = true; than in fixedupdate check if didUpdate is true, if yes, dont do a check for collision and set didUpdate to false. If a double fixedupdate happens than didUpdate will be false and you can do a collision check.

    Ill let you play around with it though.
     
    Last edited: Jun 7, 2015
  22. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Ah, i didn't notice your edit :)

    May i ask which file you have changed? I don't see an attachment, and the script with the spoiler doesn't seem to be changed.

    I came to the same conclusion. Unity Physics is unreliable for what we want to do here. That's why i am back at experimenting with Transform.Translate now.

    And thinking at that you should never implement what you don't understand (still in trouble with the math part of your code, heh) , i have then had an idea for a much easier method to come close to my target coin by using transform.translate.

    The trick is to choose a relative short spherecast, a bit longer than the longest possible distance traveled by transform.translate, and couple the movement speed to the distance to the target then when it triggers. So that the jump for the last movement isn't this visible. When it's in reach and triggering, then we start a for loop, in which the bullet becomes slower and slower, and getting closer and closer. That way i am very close to the target coin after 10 steps already. And is so simple.

    Means when it triggers. Which still seems to be a problem sometimes. Sometimes the bullet lands at the coin behind. And i have yet to find out why it triggers the coins just fine, but fails to trigger at the borders in my example file. I still hope that i have overlooked a setting.

    Anyways, here comes my method for shooting directly at a coin. The method itself is working.

    I am just not sure if fixed update is necessary here. And maybe we could optimize it by recalculating the remaining distance by measure the distance we moved already, and substract it from the remaining value. I cast a spherecast with every iteration here. But also here i am unsure which calculation is less computing heavy. Calculating the already traveled distance, or simply cast a new spherecast. And i don't see any impact at the performance yet. So i'll leave it the spherecast way for now.

    It's Javascript, but you should get the idea. And this few lines should be easily transferable to C#

    Code (JavaScript):
    1. #pragma strict
    2.  
    3. var radius:float=0.48; // the radius of our casted sphere
    4. var distanceToObstacle:float=0.0; // distance to hit object
    5. var speed:float=5.0;
    6. var inreach:boolean;
    7. var laststep:boolean;
    8.  
    9. function FixedUpdate () {
    10.     var hit:RaycastHit;
    11.     if (!inreach){  //Trigger just the first hit
    12.         if (Physics.SphereCast (transform.position, radius, transform.forward, hit, 0.5)) {
    13.             distanceToObstacle = hit.distance;
    14.             inreach=true;
    15.         }
    16.     }
    17.  
    18.     if (!inreach){ // our spherecast does not trigger, so normal movement
    19.         transform.Translate(Vector3.forward * speed * Time.deltaTime);
    20.     }
    21.     // our spherecast has hit something. Now we getting closer with every movement step.
    22.     // This is done by coupling the movement speed with the distance to the target. The closer we get, the slower we are.
    23.     // Ten steps should give us already enough accuracy. That's already 0.01 close to the target coin.
    24.     else {
    25.         if (!laststep){
    26.             for(var i: int = 0; i < 10; i++) {
    27.                 if (Physics.SphereCast (transform.position, radius, transform.forward, hit, 0.5)) {
    28.                     distanceToObstacle = hit.distance;
    29.                     Debug.Log(distanceToObstacle.ToString("F6"));
    30.                 }
    31.                 transform.Translate(Vector3.forward * speed * distanceToObstacle * Time.deltaTime);
    32.             }
    33.             laststep=true; // put the bullet to rest. We have reached our target position
    34.         }
    35.     }
    36. }
    EDIT, found the baddie. I had Vector3.up instead transform.forward in the spherecast ...
     
    Last edited: Jun 9, 2015
  23. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    The script was update, it was just very minor stuff so you probably didn't notice. Test it out and see if it gives you the desired results. However if what you have up there works, then of course you are free to use what you like ;)

    But now you need to do the bounce manually, no?

    You could probably use this.
    http://docs.unity3d.com/ScriptReference/Vector3.Reflect.html
    With your script you can check with the spherecast if you hit a wall, get its normal, use the reflect and assign the new transform as well as changing the bullets transform.up to face the new direction since your script seems to rely on that.
     
    Last edited: Jun 9, 2015
  24. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Ah cool, Thanks. Will have a very close look at the script. And many thanks for all of your efforts so far. I've really learned quite a bit again :)

    Yes, i need to bounce manually then. But first i need to trigger the walls and to stop there like with the coins. Which does not work for unknown reason O_O

    You don't have a few minutes to have a look at the file and tell me what goes wrong here? Why does the walls not trigger? 400 Kb http://www.reinerstilesets.de/ext/unity/nospherecastatborders.rar

    Thanks for the link to the reflect code. I have never managed to get this reflect code to work. But i have yet to find a simple working and easy understandable example in the Unity manual anyways. There's a whole bunch of scripts that throws errors in Unity 5, and doesn't work at all. And quite a few scripts have stuff in the example code that doesn't belong there. What for example has a character controller to do with spherecast? Obfuscation ...

    For my method, i have a flaw to fix first. Some coins doesn't land where it should. Still at thinking here what's the cause. Maybe the for - loop grabs the wrong result, the sphere behind. Hmm, then i need to calculate with the traveled distance instead of a new spherecast. Ah developing ^^

    castfail.png
     
    Last edited: Jun 9, 2015
  25. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Kk, no more physics ;)
    This script should be the last you need (hopefully ^^)
    Handles bounce and what not.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class BulletPhysics : MonoBehaviour
    5. {
    6.     public float speed = 10;
    7.     public bool hasHitSomething;
    8.  
    9.     float radius;
    10.      
    11.     void Awake()
    12.     {
    13.         radius = gameObject.GetComponent<SphereCollider>().radius * transform.localScale.x; //expects scale to be uniform.
    14.     }
    15.  
    16.     void Update()
    17.     {
    18.         CollisionCheck();
    19.     }
    20.  
    21.     void CollisionCheck()
    22.     {
    23.         if(!hasHitSomething)
    24.         {
    25.             Vector3 targetPosition = transform.position + (transform.forward * (speed * Time.deltaTime));
    26.             Vector3 targetDirection = (targetPosition - transform.position).normalized;
    27.             float targetDistance = Vector3.Distance(transform.position, targetPosition);
    28.          
    29.             RaycastHit hitInfo;
    30.             Physics.SphereCast(transform.position, radius, targetDirection, out hitInfo, targetDistance);
    31.             if(hitInfo.collider && hitInfo.collider.transform != transform) //making sure it doesnt somehow hit ourselves
    32.             {
    33.                 if(hitInfo.collider.gameObject.CompareTag("Walls") || hitInfo.collider.gameObject.CompareTag("Bullet"))
    34.                 {
    35.                     transform.position = ExtPhysics.SphereCastCenterOnCollision(transform.position, radius, targetDirection, hitInfo.point);
    36.  
    37.                     if(hitInfo.collider.gameObject.CompareTag("Walls"))
    38.                     {
    39.                         transform.localRotation = NewDirection(hitInfo.normal);
    40.                     }
    41.  
    42.                     if(hitInfo.collider.gameObject.CompareTag("Bullet"))
    43.                     {
    44.                         hasHitSomething = true;
    45.                     }
    46.                 }
    47.  
    48.             }else{
    49.                 transform.position = targetPosition;
    50.             }
    51.         }
    52.     }
    53.  
    54.     Quaternion NewDirection(Vector3 normal)
    55.     {
    56.         normal.Normalize ();
    57.         Vector3 newDirection = Vector3.Reflect(transform.forward, normal);
    58.  
    59.         return Quaternion.LookRotation(newDirection);
    60.     }
    61. }
    62.  
    63.  
    64. public partial class ExtPhysics
    65. {
    66.     public static Vector3 SphereCastCenterOnCollision(Vector3 origin, float radius, Vector3 directionCast, Vector3 hitPoint)
    67.     {
    68.         Vector3 localOrigin = Vector3.zero;
    69.         Vector3 localHitPoint = hitPoint - origin;
    70.      
    71.         float originHitPointDistance = Vector3.Distance(localOrigin, localHitPoint);
    72.      
    73.         Vector3 localEndPoint = localOrigin + (directionCast * originHitPointDistance);
    74.      
    75.         Vector3 sphereCastCenter = ExtMathf.SphereLineIntersect(localOrigin, localEndPoint, localHitPoint, radius)[1];
    76.         sphereCastCenter = origin + sphereCastCenter;
    77.         return sphereCastCenter;
    78.     }
    79. }
    80.  
    81. public partial class ExtMathf
    82. {
    83.     public static Vector3[] SphereLineIntersect(Vector3 lineStartPoint, Vector3 lineEndPoint, Vector3 sphereCenterPoint, float sphereRadius)
    84.     {
    85.         Vector3[] intersectPoints = new Vector3[2];
    86.      
    87.         Vector3 startPointEndPointDifference = lineEndPoint - lineStartPoint;
    88.      
    89.         float a = Vector3.Dot(startPointEndPointDifference, startPointEndPointDifference);
    90.         float b = 2f * Vector3.Dot(startPointEndPointDifference, lineStartPoint - sphereCenterPoint);
    91.         float c = Vector3.Dot(sphereCenterPoint, sphereCenterPoint) + Vector3.Dot(lineStartPoint, lineStartPoint) - 2f * Vector3.Dot(sphereCenterPoint, lineStartPoint) - (sphereRadius * sphereRadius);
    92.      
    93.         float delta = b * b - (4f * a * c);
    94.      
    95.         //Find the two intersections.
    96.         if (delta > 0)
    97.         {
    98.             float SquareRootDelta = Mathf.Sqrt(delta);
    99.          
    100.             float intersect1 = (-b + SquareRootDelta) / (2f * a);
    101.             float intersect2 = (-b - SquareRootDelta) / (2f * a);
    102.          
    103.             intersectPoints[0] = (startPointEndPointDifference * intersect1);
    104.             intersectPoints[1] = (startPointEndPointDifference * intersect2);
    105.         }
    106.      
    107.         return intersectPoints;
    108.     }
    109. }
     
    Last edited: Jun 9, 2015
    Tiles likes this.
  26. Tiles

    Tiles

    Joined:
    Feb 5, 2010
    Posts:
    2,481
    Many Thanks :)
     
    Last edited: Jun 9, 2015
    HiddenMonk likes this.