Search Unity

Marble physics scripting

Discussion in 'Scripting' started by CryingRaven, May 22, 2006.

  1. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    Hi people

    I am new to Unity and trying to make a real simple game that relies almost exclusively on the physics engine and have found that the physics engine is without my understanding.

    Please allow me to post my problems and please see if you can help me out.

    The game I want to make is almost like the rolling levels on i-Ninja on Xbox (or Sonic 2 on the Genesis) where you are a ball rolling through a track, sometimes at breakneck speeds. Your controll over the PC (player character) is simply left and right force additions for direction changing and forward and backward for speed adjustments. The levels would be something like i-Ninja with various obstacles to overcome except the PC should never be able to actually roll backwards except on a flat surface and the PC should never be able to move up a slope.

    The PC is a simple sphere created using Unity. When I place it in the game and place it above the track, it falls down VERY slowly indeed, no matter how much mass it has. To solve this I changed the gravity field to 30. So that is the first problem solved.

    :?: The second one is the relationship between force and mass. If I make the force strong enough to actually move the ball at a reasonably fast speed, then the force is so strong that when I hold down the backwards movement key, it goes up the slope for the level. It should not be able to move up the slope at all. The method I use to stop this from happening is to increase the mass, but then the force is not strong enough to move the marble except at crawling speed... What's up? How do I solve this?

    Lastly, and more importantly, my ball doesn't behave like I would have expected it to. I simply decided to build this game to test the physics engine and so far it doesn't seem to do what I expect. When I set the ball in motion, I want it to move forward at the speed at which it is being pushed, then when it reaches the slope, it should start rolling down and gain speed/velocity/momentum/whatever. At the moment, when it reaches the slope, it goes down the slope without the need for me to press any buttons, but the speed of the marble stays constant throughout. How do i create more lifelike physics here?

    :?: And lastly, for movement I use the script from the tutorial. The one where the guy builds the level with his son and then scripts the movement for the marble. Forward speed is calculated by using the "vertical" keys, yet when the ball gets to the end of the slope, I press the backwards movement key and the ball just keeps going. Slowly like ever, but forward non the less, for about 10 to 20 seconds, then it changes direction and comes back, ever so slowly still, before moving up the slope still ever so slowly.... Because it moves up the slope I assume my force is immence. So why does the slow moving ball not stop for 10 to 20 seconds?

    Also, the camera is all wierd using this script. It uses the marble's forward vector, without the y and then places itself behind the marble. Problem is, the marble is constantly rolling so it's forward vector changes with every frame. As a result, the camera is forever rotating around the ball, rotating on it's own y axis. This makes me dizzy.

    :?: How do I place a camera behind and above a marble that is always rolling on a track that is winding and curving? For the y aspect, I assume I get the ball's y transform and then simply add my height to it, fine. But how do I tell the camera which way is forward if the marble's forward vector changes every frame and the level itself takes a few turns as well?

    I never thought a simple game like this could have so many problems... Sheesh! :)

    :!: What i would like from you fine people, is if you could tell me what settings I need to set to what to create physics that can emulate the effect of throwing a marble into a round glass bowl with enough force to send it rolling up the side, but not enough to send it flying out the other end. It should be rather fast as you would expect in real life and make zig-zag motions while gradually decreasing the radius of movement before finally coming to a stand still in the centre. The physics should be set up to do this all automatically and the actual movement should be dictated by the confining shape.

    :?: Is the included physics engine capable of doing this or is it just a rudamentary physics engine that requires me to build this functionality via complex scripting?

    If it can be done and if you could tell me what setting needs to be what, would you please explain to me why one settings has to be something rather than another setting sommething else, please?

    Your assistance in this regard would be most appreciated indeed!

    Sincerely
    Jacco
     
  2. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    Welcome to!

    Let's have a look, that's a lot of questions there ;)

    There's nothing inherently difficult in what you propose, but any fine tuning of controls takes a while to get right. Try out GooBall (the free demo available). That game probably has some examples of how to finely control a marble ... and possibly some examples of how not to do it :)

    This one's a classic mistake to make... and easy to fix. Here's a link to the working version of the docs... search for the headline "Use the right size":

    http://tikiwiki.otee.dk/tikiwiki/tiki-index.php?page_ref_id=183

    This is tricky. Imagine what you're doing: pushing the ball with an invisible finger. If you push it hard enough it'll go up slopes. That's not surprising. It won't if you only push it very softly, but then it'll roll ever so slowly.

    The first thing I'd try is to figure out if the ball is moving up a slope, and then turn off the force.

    The code for this could be something like:
    Code (csharp):
    1.  
    2. var canSteer = true;
    3. // Check if the ball is moving upwards, then disallow pushing it
    4. if (Vector3.Dot(rigidbody.velocity, Vector3.up) > 0.0) {
    5.    canSteer = false;
    6. }
    7.  
    8. if (canSteer) {
    9.    // apply forces to the ball here
    10. }
    11.  
    Does that make sense? Simply stop pushing if pushing uphill. It might not end up feeling right though, in which case you'll have to try other approaches.

    In fact I can see a potential problem with this solution: you lose all control when the ball is rolling upwards: I can see this being annoying. Try to formulate a solution in words and then we can try to think of a script to solve it.

    This sounds like a heavy marble. A ball that rolls has a lot of energy stored in it's rotation, and can negotiate obstacles without slowing down significantly. This is probably what you are seeing.

    This would be stored energy and a too-heavy ball. Try to tune the variables.

    You'll want another object which stays upright. Make an empty game object a child of the marble, and add this script to it. Then make the camera follow it instead of the marble.

    Depends. If you are content with the camera just staying behind the ball,

    Unity allows you to focus on the non-technical aspects of game development. Gameplay can still be tricky :)

    There's no magical values for this... tune-try-tune-try is the only advice here.

    Oh, and if you can't get the settings right, maybe cheating is the road: a script that'll pull the ball down if it gets to close to the edge, a script that gives the ball an extra shove when starting to move it (so that it's more responsive). This is all things that we had in GooBall.

    Oh, absolutely. It's the Ageia physX engine, world class, fast and realistic. The problem is that it tries to mimic reality, while often games don't want too much reality. So you end up having to tune things to make them "feel right".

    I assume this won't be the last questions from you (and you're ever so welcome to keep asking). My advice would be for you to ask one question per message and keep it short and simple. That way it's easier for people to give you bite-size advice. A long message like this one can be a little daunting.

    d.
     
  3. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    Okay, I have to go to work now so I will try this out later.

    How about I start with a single thank you with a capital VERY VERY MUCH to begin with and then I'll let you know how things go from there :p

    Question: you said look at goobal. does this mean you give away the source or does the source come with the commercial purchase or did you mean just see what it does while playing?

    Eiter way thanks again for your help. I look forward to trying this out :D
     
  4. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    Just play it to begin with. I can't share the source code with out, but I'll be happy to give specific advice.

    You may also want to play other marble rolling games such as Super Monkey Ball and Balance just to see how other people did it.

    Good luck with it,

    d.
     
  5. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    regarding the snippet you gave me, I think it would work out for my purposes if I say:

    if (!cansteer)
    {
    if (verticalForce)
    {
    verticalForce *= 0.10;
    if (verticalForce < 2) verticalForce = 0;
    }
    } else
    {
    //calculate normal vertical force for the frame
    }

    //calculate horizontalForce normally

    Do this after the conditional since I want the physics engine to always influence the marble, but at all times the player must be able to effect horizontal movement. The above conditional would then simply serve to cut down any applied force gradually when moving upward since , like you said, in the snippet above, you will loose all controll including horizontal control as soon as the marble moves up a slope... This would solve that little problem :)

    Now the problem comes with bumps in the track where the player has to go up a slight curve before taking a plunge again... Hmmm... I think this is more to do with level design than the physics engine so this is not a problem :)

    It was the "are you moving upward" code above that will really prove helpful. I was actually thinking of doing it this way but my 3d maths skills are rather lacking and I didn't know how to do it, so thanks for that :)
     
  6. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    It seems to me that the mass of your marble is too high. Once you get it moving it will have lots of inertia to overcome. What is your mass set to right now? Tweaking the mass, drag, and angular drag values can have a big effect. You might want to play around with them some. Instead of increasing the mass of your marble to slow it down you might want to increase the drag and angular drag. You might look at adding a physics material to your marble after you have played with the other variables.

    For the Otee guys. What does a mass of 1 mean? Is it 10x more massive than something with a mass of .1? And does any mass value have correspondence to the real world, such as a mass of .01 = 1 kg? It seems to me this would make tweaking easier since you would know your ballpark.
     
  7. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    I just played Monkey Ball this week and it was a great influence for this game... Still is, actually! That and Marble Blast Gold.... Liked monkey ball better though...

    Loved it when the monkeys said "Monkeee" :)

    i actually began to think that it was a problem with physics engines that prevented marbles from moving fast and that I would have to abandon physics in favour of normal translation code if I wanted to make the marble move fast. Then I rememberred how fast the marbles moved in those two games and decided to make the post.

    It was dumb of me, I know, but heck, what do I know... I failed science in highschool :p
     
  8. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    A mass of 1 is really anything you decide i to be. The physics engine is most accurate if the most typical unit of mass in your game is in the range 0.1 - 10, so if you're doing a car-game you want to make 1 be 500 kg or so.

    Another trick which we employed in GooBall is to have nearly no friction on the ball. That reduces the problem of slow acceleration (while your push mostly goes towards making the ball rotate) and deceleration (while the rotation of the ball pulls it onwards).

    d.
     
  9. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    Physics is hard to avoid if you want your level to be complex, and in some ways it handles most of the maths for you.... you just say: push this way, and the physics engine figures out what happens.

    On the other hand, as mentioned, you probably don't want the ball to be purely physical, so you end up doing an good amount of code to "massage" the ball to feel right.

    d.
     
  10. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    David, thank you for the information. I think your explanation should be in the docs :) (or did I just miss it?). It was clear and easy to understand. Just to complete my undertanding, in your example of a mass of 1 = 500 kg, would a mass of .1 = 50 kg?
     
  11. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    Okay, I got the marble to move forward a lot easier now and currently use a force of 50, gravity of 38, all drag set to 0, mass and scale of 1. The marble moves fine when I apply forces to it, but the slope still causes me problems since it rolls down and gathers momentum and when it reaches the bottom, instead of continuing to run at the new speed, it virtually grinds to a halt almost immediately after the track flattens out... This is causing me grey hairs...

    On another note, the number format is causing me more grief at the moment.

    I declare the following:
    private var forwardForce;
    and when I say:
    if (forwardForce < 0.0) forwardForce = 0.0;
    I get the runtime error:
    cannot find method op_LessThan

    But by defining:
    private var forwardForce = 0.0;
    I get a compile time error saying the function rigidbody.AddForce(forwardForce); cannot accept a "single" as a parameter.

    How do I declare this variable as a float and will that allow me to use the op_LessThan function as I tried to above?

    Code (csharp):
    1.  
    2. var power = 50.0;
    3. var drag = 2.0;
    4.  
    5. private var grounded = false;
    6. private var forwardForce;
    7.  
    8. function FixedUpdate ()
    9. {
    10.     //always allow for direction change
    11.     var right = Camera.main.transform.TransformDirection(Vector3.right);
    12.     right.y = 0;
    13.     right = right.normalized;
    14.    
    15.     var rightForce = right * Input.GetAxis("Horizontal") * power;
    16.     rigidbody.AddForce(rightForce);
    17.  
    18.     //only adjust speed when on a surface
    19.     if (grounded)
    20.     {
    21.         var forward = Camera.main.transform.TransformDirection(Vector3.forward);
    22.         forward.y = 0;
    23.         forward = forward.normalized;
    24.  
    25.         if (Vector3.Dot(rigidbody.velocity, Vector3.up) > 0.0)
    26.         {
    27.             if(forwardForce != 0)
    28.             {
    29.                 forwardForce *= 0.1;
    30.                 if (forwardForce < 0.0) forwardForce = 0.0;
    31.             }
    32.         }
    33.         else
    34.         {
    35.             forwardForce = forward * Input.GetAxis("Vertical") * power;
    36.             rigidbody.AddForce(forwardForce);
    37.         }
    38.        
    39.         // Apply drag only if the user is not pressing any keys
    40.         if (Mathf.Approximately (Input.GetAxis("Horizontal"), 0)  Mathf.Approximately(Input.GetAxis("Vertical"), 0))
    41.             rigidbody.drag = drag;
    42.         else
    43.             rigidbody.drag = 0;
    44.     }
    45.     else
    46.     {
    47.         rigidbody.drag = 0;
    48.     }
    49.  
    50.     // Every frame set grounded to false. OnCollisionStay will enable it again if
    51.     // the rigidbody collides with anything
    52.     grounded = false;
    53. }
    54.  
    55. function OnCollisionStay() {
    56.     grounded = true;   
    57. }
     
  12. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    rigidbody.AddForce() takes a vector, not a float. If you are trying to check your forward force I think you might want
    Code (csharp):
    1.  
    2. if (forwardForce.z < 0.0)
    3.    forwardForce.z = 0.0
    4.  
    [/code]
     
  13. CryingRaven

    CryingRaven

    Joined:
    May 3, 2006
    Posts:
    26
    How did I NOT see that?!?!?!?!?!
    jeez!
    i made such progress yesterday, even got the camera to stabalize (although that was a clear hack which I will HAVE to revise later on, but it works at least). So much progress and then a silly little listake like that... sheesh!

    Well, now it's back to the tutorials to try and figure out how to call a parent object to use it's properties...

    It's coming along... It's coming along... :)