Announcement

Collapse
No announcement yet.

Relative Physics Problem

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Relative Physics Problem

    Greetings,

    I have developed rough code for controlling a biplane vehicle; however, it doesn't function correctly. It seems as if the modifiers I have applied are acting on it globally, not locally. In-game, when I enter the vehicle, it initially seems to control as I wish it to, but further testing reveals it's not controlling how it should.

    I think my main issue is that I am unfamiliar with UnrealScript and UDK - I believe I am using the wrong methods to manipulate the biplane's physics.

    Any help? This is rather urgent. Code attached below.

    Code:
    class AR_Aircraft extends UTAirVehicle;
    
    /* etc */ 
    
    var float AR_Lift, AR_Forward, AR_MaxLift, AR_TurnSpeed;
    var Vector AR_UpwardsNormal;
    var Rotator AR_Rotation;
    
    /* etc */ 
    
    // Code in development; exact values to be tweaked.
    simulated function AirRaidKinematics(float DeltaTime)
    {
    	local Vector AR_ForceApplication, AR_ForceRotation, AR_ForwardsNormal;
    
    	// While there is a player in the biplane:
    	if (PlayerController(Controller) != None)
    	{
    		AR_ForwardsNormal = Normal(Vector(Rotation));
    
    		// Calculate UpwardsNormal of the plane so I can lift it in that direction:
    		AR_UpwardsNormal.X = - AR_ForwardsNormal.Z;
    		AR_UpwardsNormal.Y =  AR_ForwardsNormal.Y;
    		AR_UpwardsNormal.Z =  AR_ForwardsNormal.X;
    		
    
    		// Calculate AR_Rotation so we know how the plane lifts:
    		AR_ForceRotation.X = 35 * Steering; // Steering is between -1 and 1	
    		AR_ForceRotation.Y = 30 * Throttle; // Throttle is between -1 and 1
    		AR_ForceRotation.Z = 12 * Steering; // Rise is between -1 and 1
    
    		AR_Forward = 500; // Will allow variable forwards speed later
    		
    		// Calculate lift for the biplane:
    		AR_Lift = AR_Forward * 1.5 * Abs(Cos(Rotation.Pitch));
    		if (AR_Lift > AR_MaxLift) AR_Lift = AR_MaxLift;
    
    		// This is meant to calculate the applied force for the biplane,
    		// to give it lift upwards relative to its normal:
    		AR_ForceApplication.X = AR_UpwardsNormal.X * AR_Lift + AR_Forward;
    		AR_ForceApplication.Y = AR_UpwardsNormal.Y * AR_Lift;
    		AR_ForceApplication.Z = AR_UpwardsNormal.Z * AR_Lift;
    		
    		// Propel the biplane
    		AddForce(AR_ForceApplication);
    
    		// Rotate the biplane
    		AddTorque(AR_ForceRotation);
    	}
    	else
    	{
    		AR_Lift = 0;
    		AR_Rotation.Pitch = 0;
    		AR_Rotation.Yaw = 0;
    		AR_Rotation.Roll = 0;
    	}
    }
    
    
    simulated function Tick(float DeltaTime)
    {
    	AirRaidKinematics(DeltaTime);
    	Super.Tick(DeltaTime);
    }
    
    /* etc */
    Thanks.

    #2
    It would help greatly if you could tell us what that does, how it behaves and how it's meant to behave, otherwise its difficult to know what to look for.

    However, from a quick once-over, a few possibilities arise:

    For one, on this line:
    AR_ForceRotation.Z = 12 * Steering
    The comment would make it seem as though you meant to type:
    AR_ForceRotation.Z = 12 * Rise

    Secondly, Rotation values are not stored in Radians OR Degrees, but UnrealRot values. I'm not certain that Cos works on UnrealRots though, so something to look into, you mave have to convert units.

    Comment


      #3
      Try replacing this:

      Code:
      // Calculate AR_Rotation so we know how the plane lifts:
      		AR_ForceRotation.X = 35 * Steering; // Steering is between -1 and 1	
      		AR_ForceRotation.Y = 30 * Throttle; // Throttle is between -1 and 1
      		AR_ForceRotation.Z = 12 * Steering; // Rise is between -1 and 1


      with...

      Code:
      // Calculate AR_Rotation so we know how the plane lifts:
      		AR_ForceRotation.X = 100 * 35 * Steering; // Steering is between -1 and 1	
      		AR_ForceRotation.Y = 100 * 30 * Throttle; // Throttle is between -1 and 1
      		AR_ForceRotation.Z = 100 * 12 * Steering; // Rise is between -1 and 1
      Because while I was working with some camera tilting functionality, I wanted to rotate it on the X axis to roll by 15 degrees... I noticed that when I scale it up to 1500, it gives me the rotation I wanted... I don't know why this is happening, it may not help your case, but you could try and perhaps you have a similar issue to mine.

      Comment


        #4
        rotators have a range of 65535 units

        Comment


          #5
          Apologies, the steering of the biplane is as follows:
          The biplane will roll (and yaw slightly) upon pressing 'A' and 'D' keys.
          The biplane will pitch up and down by pressing the 'W' and 'S' keys.

          This works, using the values from Steering and Throttle.
          Code:
          AR_ForceRotation.Z = 12 * Steering
          This line is deliberate (at least for now), imitating the slight yaw the biplane will have when it rolls. Sorry for the confusion, that was my fault.

          Every tick, the biplane is to be pushed forward based on its propulsion, and upwards based off its lift.
          Now, this all appears to be working somewhat; however, the problem is that the forces are apparently being applied from a global perspective.

          For example: its forward-push is always in the global x-axis, instead of being pushed forward in the direction of the plane's heading. The pitch and roll is also applied globally, so that when the biplane is facing another direction, the pitch will still rotate it in global angles, thus meaning it can't turn and then pitch down properly.

          I hope this makes sense. Sorry Seenooh, that just made the rotation super duper fast. I'm looking at these lines to be the culprit:

          Code:
          		// Propel the biplane
          		AddForce(AR_ForceApplication);
          
          		// Rotate the biplane
          		AddTorque(AR_ForceRotation);
          However, I'm not sure. Would it be more beneficial to include all my scripts in a link?

          Comment


            #6
            I'm not sure, but I think your problem is here:

            Code:
            AR_ForwardsNormal = Normal(Vector(Rotation));
            and here

            Code:
            // Calculate UpwardsNormal of the plane so I can lift it in that direction:
            AR_UpwardsNormal.X = - AR_ForwardsNormal.Z;
            AR_UpwardsNormal.Y =  AR_ForwardsNormal.Y;
            AR_UpwardsNormal.Z =  AR_ForwardsNormal.X;

            You are trying to get the forward vector that the plane is facing in a wrong way. Also AR_UpwardsNormal calculation is incorrect. This is basically the up vector relative to the plane. I think you should try this instead:

            Code:
            local vector Y; 
            
            GetAxes(Rotation,AR_ForwardsNormal,Y,AR_UpwardsNormal);
            Hope that helps.

            Comment


              #7
              Id have to agree seenooh, when they posted earlier I double checked over this and the normalized vector rotation is the only major difference between this force application and that of the scorpions booster. That leads me to believe this is whats causing your local vs world coordinate system problem

              Comment


                #8
                Originally posted by MonsOlympus View Post
                Id have to agree seenooh, when they posted earlier I double checked over this and the normalized vector rotation is the only major difference between this force application and that of the scorpions booster. That leads me to believe this is whats causing your local vs world coordinate system problem
                Yeah I think that's the issue.

                Anyways I editted my previous post because I think I found another problem...

                Comment


                  #9
                  Thanks Seenooh, and MonsOlympus, that fix was very helpful and has fixed the movement considerably.

                  However, I still have the particular problem where the rotations are being applied globally. Let me try to illustrate:



                  Similarly, if I rotate the biplane around so it is facing down the negative x-axis: it continues backwards, still going forward in the global x-axis.

                  Comment


                    #10
                    You welcome. =)

                    Look here:

                    Code:
                    // Calculate lift for the biplane:
                    AR_Lift = AR_Forward * 1.5 * Abs(Cos(Rotation.Pitch));
                    Do you see in my previous post where I declared local Y ? Then GetAxes? Y becomes the Y axis relative to your object... So try this out:

                    Code:
                    AR_Lift = AR_Forward * 1.5 * Abs(Cos(Y.Pitch));
                    I believe wherever you use Rotation in your calculations it'll give you that global issue. I hope this helps you out.

                    Comment


                      #11
                      Code:
                      AR_Lift = AR_Forward * 1.5 * Abs(Cos(Y.Pitch));
                      That piece of code doesn't compile, as Y is a Vector. Rotation.Pitch does work for that piece of code, but your contribution is still appreciated, thanks.

                      (I have previously noted to myself that it would be more correct to check the current Pitch against the Pitch of the plane's Velocity-Vector; however, I'm happy with the responsiveness of the movement that this code simulates, for the purposes of the cartoon-ish game I am attempting to create.)


                      I did have a fresh look at the rest of my code though, and determined this replacement:
                      Code:
                      // This gives lift upwards relative to its up-axis and push forwards relative to its forward-axis:
                      AR_ForceApplication.X = AR_UpwardsNormal.X * AR_Lift + AR_ForwardsNormal.X * AR_Forward;
                      AR_ForceApplication.Y = AR_UpwardsNormal.Y * AR_Lift + AR_ForwardsNormal.Y * AR_Forward;
                      AR_ForceApplication.Z = AR_UpwardsNormal.Z * AR_Lift + AR_ForwardsNormal.Z * AR_Forward;
                      That fixes the "always travels forward along the global x-axis" issue. Of course, I should have seen it before.

                      (Incidentally, does anyone know why UDK decided to swap all the axes around, so that the x-axis in UDK is actually the z-axis for most normal 3D systems?)


                      Regardless, the main issue is still how rotation is applied. Everything else works now, save for the issue demonstrated in my crude diagram above: if I spin the plane around in one axis, it no longer rotates correctly when rotating about another axis. It treats the current orientation of the plane as global orientation. I think it has to do with the following line but I am not sure exactly why it would be wrong, apart from the fact it just seems to apply the values globally:

                      Code:
                      // Rotate the biplane
                      AddTorque(AR_ForceRotation);
                      Thank you for all your help so far. I'm still looking at the code; I'll post back here if I solve it. Thanks.

                      Comment


                        #12
                        in any system i've ever worked with (admittedly not many), up/down is Z ...

                        Comment


                          #13
                          Current Solution

                          As I said, "AddTorque" does apply globally, so my workaround has been to manually calculate the relative torque-add components, then apply them in that global sense. I used the normals from the "GetAxes" method that Seenooh gave me.

                          Apropos, Vector "Y" is now renamed "AR_SidewardsNormal":

                          Code:
                          GetAxes(Rotation, AR_ForwardsNormal, AR_SidewardsNormal, AR_UpwardsNormal);
                          
                          // It's probably unnecessary to normalise these:
                          AR_ForceRotationVectX = Normal(AR_ForwardsNormal);
                          AR_ForceRotationVectY = Normal(AR_SidewardsNormal);
                          AR_ForceRotationVectZ = Normal(AR_UpwardsNormal);
                          
                          // Calculate the XYZ components of the relative steering:
                          AR_ForceRotationVectX.X *= 35 * Steering; // Steering is between -1 and 1	
                          AR_ForceRotationVectX.Y *= 35 * Steering; // Steering is between -1 and 1	
                          AR_ForceRotationVectX.Z *= 35 * Steering; // Steering is between -1 and 1	
                          
                          AR_ForceRotationVectY.X *= 30 * Throttle; // Throttle is between -1 and 1
                          AR_ForceRotationVectY.Y *= 30 * Throttle; // Throttle is between -1 and 1
                          AR_ForceRotationVectY.Z *= 30 * Throttle; // Throttle is between -1 and 1
                          
                          AR_ForceRotationVectZ.X *= 12 * Rise; // Rise is between -1 and 1
                          AR_ForceRotationVectZ.Y *= 12 * Rise; // Rise is between -1 and 1
                          AR_ForceRotationVectZ.Z *= 12 * Rise; // Rise is between -1 and 1
                          
                          // Add them together to get final global rotation vector:
                          AR_ForceRotation.X = AR_ForceRotationVectX.X + AR_ForceRotationVectY.X + AR_ForceRotationVectZ.X;
                          AR_ForceRotation.Y = AR_ForceRotationVectX.Y + AR_ForceRotationVectY.Y + AR_ForceRotationVectZ.Y;
                          AR_ForceRotation.Z = AR_ForceRotationVectX.Z + AR_ForceRotationVectY.Z + AR_ForceRotationVectZ.Z;
                          I probably could have used a better naming convention... Anyway, now there's mainly tweaking to do. I'll post back here with the final script (if I ever finalise it). I'll probably start other threads as I find separate issues.

                          Thanks for all your help!

                          PS: Strange, in basically all my studies, Y-axis is up and Z-axis faces outwards/forwards. I come less from a game-engine-user perspective and more from Mathematics, but maybe I'm wrong. I guess it doesn't matter either way, as long as I know which is which for UDK.

                          Comment


                            #14
                            Finalised Code, somewhat.

                            Using the below key bindings, my AR_Aircraft class has the following code:

                            Code:
                            class AR_Aircraft extends UTAirVehicle;
                            
                            /* etc */ 
                            
                            var float AR_MaxLift, AR_TurnSpeed, AR_Speed, AR_CurrentForward, AR_AddedLiftSpeed, AR_Acceleration;
                            
                            /* etc */
                            
                            simulated function AirRaidKinematics(float DeltaTime)
                            {
                            	local Vector AR_ForceApplication, AR_ForceRotation, AR_ForwardsNormal, AR_UpwardsNormal, AR_SidewardsNormal;
                            	local Vector AR_ForceRotationVectX, AR_ForceRotationVectY, AR_ForceRotationVectZ;
                            	local float AR_Lift, AR_ForwardSpeed, AR_NewRise;
                            
                            	// While there is a player in the biplane:
                            	if (PlayerController(Controller) != None)
                            	{
                            		GetAxes(Rotation, AR_ForwardsNormal, AR_SidewardsNormal, AR_UpwardsNormal);
                            		
                            		// It's probably unnecessary to normalise these:
                            		AR_ForceRotationVectX = Normal(AR_ForwardsNormal);
                            		AR_ForceRotationVectY = Normal(AR_SidewardsNormal);
                            		AR_ForceRotationVectZ = Normal(AR_UpwardsNormal);
                            
                            		// Rise is NOT between -1 and 1, like it said it was
                            		AR_NewRise = 0;
                            		if (Rise != 0) AR_NewRise = Rise / Abs(Rise); // Avoid divide by 0
                            
                            		// Calculate the XYZ components of the relative steering:
                            		// Generic controls Steering, Throttle and Rise are set by the controller
                            
                            		// Roll
                            		AR_ForceRotationVectX.X *= 35 * -AR_NewRise; // Steering is between -1 and 1	
                            		AR_ForceRotationVectX.Y *= 35 * -AR_NewRise; // Steering is between -1 and 1	
                            		AR_ForceRotationVectX.Z *= 35 * -AR_NewRise; // Steering is between -1 and 1	
                            
                            		// Pitch
                            		AR_ForceRotationVectY.X *= 30 * Throttle; // Throttle is between -1 and 1
                            		AR_ForceRotationVectY.Y *= 30 * Throttle; // Throttle is between -1 and 1
                            		AR_ForceRotationVectY.Z *= 30 * Throttle; // Throttle is between -1 and 1
                            
                            		// Yaw
                            		AR_ForceRotationVectZ.X *= 25 * -Steering; // AR_NewRise is between -1 and 1
                            		AR_ForceRotationVectZ.Y *= 25 * -Steering; // AR_NewRise is between -1 and 1
                            		AR_ForceRotationVectZ.Z *= 25 * -Steering; // AR_NewRise is between -1 and 1
                            
                            		// Add them together to get final global rotation vector:
                            		AR_ForceRotation.X = AR_ForceRotationVectX.X + AR_ForceRotationVectY.X + AR_ForceRotationVectZ.X;
                            		AR_ForceRotation.Y = AR_ForceRotationVectX.Y + AR_ForceRotationVectY.Y + AR_ForceRotationVectZ.Y;
                            		AR_ForceRotation.Z = AR_ForceRotationVectX.Z + AR_ForceRotationVectY.Z + AR_ForceRotationVectZ.Z;
                            
                            		AR_CurrentForward += AR_Acceleration * Throttle;
                            		AR_ForwardSpeed = AR_CurrentForward * 2.2;
                            		// AR_ForwardSpeed is not necessarily true - I'd optimally need to use some 
                            		// calculation based off Velocity and current forwards direction Vector...
                            
                            		// Calculate lift for the biplane:
                            		AR_Lift = (AR_ForwardSpeed + AR_AddedLiftSpeed) * Abs(Cos(Rotation.Pitch));
                            		if (AR_Lift > AR_MaxLift) AR_Lift = AR_MaxLift;
                            		
                            		// This gives lift upwards relative to its up-axis and push forwards relative to its forward-axis:
                            		AR_ForceApplication.X = AR_UpwardsNormal.X * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.X;
                            		AR_ForceApplication.Y = AR_UpwardsNormal.Y * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.Y;
                            		AR_ForceApplication.Z = AR_UpwardsNormal.Z * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.Z;
                            		
                            		// Add forces and rotations
                            		Mesh.AddForce(AR_ForceApplication);
                            		Mesh.AddTorque(AR_ForceRotation);
                            	}
                            	else
                            	{
                            		AR_CurrentForward = AR_Speed; // Biplane propellor thrust sets to default
                            	}
                            }
                            
                            
                            simulated function Tick(float DeltaTime)
                            {
                            	AirRaidKinematics(DeltaTime);
                            	Super.Tick(DeltaTime);
                            }
                            
                            /* etc */
                            Note, to implement the aircraft 'properly' as UDK does, I have three classes: AR_Aircraft (extends UTAirVehicle), AR_AircraftContent (extends AR_Aircraft), and AR_AircraftFactory (extends UTVehicleFactory). For more information, look at the Cicada. The code for the AR_Aircraft class above should help anyone implement (very) rough aircraft physics.

                            As mentioned, I changed the key bindings for my specific game inside UTInput.ini:
                            Code:
                            Bindings=(Name="SpaceBar",Command="GBA_Jump")
                            Bindings=(Name="W",Command="GBA_MoveForward")
                            Bindings=(Name="S",Command="GBA_Backward")
                            Bindings=(Name="A",Command="GBA_StrafeLeft")
                            Bindings=(Name="Q",Command="GBA_Duck")
                            Bindings=(Name="E",Command="GBA_Jump")
                            Bindings=(Name="D",Command="GBA_StrafeRight")
                            Bindings=(Name="LeftControl",Command="GBA_Use")
                            Q, E to roll.
                            A, D to yaw.
                            W, S to pitch (also gains speed).
                            LeftControl to hop in or out (replaces E).
                            (Without changing bindings, the normal controls would be C, Spacebar to roll)

                            By all means, take the code, extend it, and reply to me with what you've done with it.

                            Thanks; enjoy.

                            Comment


                              #15
                              where is the AR_AircraftContent and AR_AircraftFactory code... can not get this to work...

                              Comment

                              Working...
                              X