gimymblert
|
|
« on: March 14, 2013, 12:11:43 AM » |
|
https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine.htmlI had digested difficulties and advices in the old thread, broke down things, solve some on my own and finally tossed everything to start again but focused on relevant aspect. There is two problem: 1. relative cam a - I should be able to make the camera turn around the local up vector of the avatar. This at any angle this up vector might be. b - I should be able to keep the relative camera direction constant when the character move on a sphere (arbitrary surface angles) but not dependent of the character direction (local XZ plane). c - I should be able to turn the independent character direction in the direction of the input based on local XZ plane of the camera. 2. air ground transition: I will not get into this just yet but it's kinda related. Let's solve one thing at a time. Now 1.a should not be a problem at all, I use a specific algorithm i just need to apply it to the camera, instead of picking the ground normal I need to pick the character up vector to align to, BRILLIANT, I thought ... except the camera stay hopelessly flat for unknown reason that drive me made (see the link above). Point b and c depend on solving a. In short, how the hell I get the camera orbiting the main character at any angle this character is, but in relative cam control (not 3PS always behind cam)? Wait this small unity indie game does it, how is that I can't?
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #1 on: March 14, 2013, 08:15:01 PM » |
|
Here are the reduce code: This one if for movement, magic happen in the updateOrientation() methods, anything else is fairly conventional strafe/forward code with raycast detection. In this sample the rotation code has been deleted has i'm simply trying to get the camroot to align itself with the character up with no success at all! using UnityEngine; using System.Collections;
public class MovementController : MonoBehaviour { public float deadZoneValue = 0.1f, acceleration = 50.0f;
//-------------------------------------------------------------------------------------------- void OnGUI() { GUILayout.Label( "transform.rotation : " + transform.rotation ); GUILayout.Label( "transform.position : " + transform.position ); } void FixedUpdate () { Ray ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up ); RaycastHit raycast_result; Rigidbody rigid_body = gameObject.rigidbody; if ( Physics.Raycast( ground_check_ray, out raycast_result ) ) { Vector3 next_position; UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); next_position = GetNextPosition( raycast_result.point ); rigid_body.MovePosition( next_position ); } } //-------------------------------------------------------------------------------------------- private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } private Vector3 GetNextPosition( Vector3 current_ground_position ) { float input_vertical_movement = Input.GetAxisRaw( "Vertical" ), input_horizontal_movement = Input.GetAxisRaw( "Horizontal" ); Vector3 camera_forward = this.transform.forward, camera_right = this.transform.right, next_position; next_position = current_ground_position + gameObject.transform.up * 0.5f; if( Mathf.Abs( input_vertical_movement ) > deadZoneValue ) { next_position += camera_forward * acceleration * input_vertical_movement * Time.deltaTime; } if( Mathf.Abs( input_horizontal_movement ) > deadZoneValue ) { next_position += camera_right * acceleration * input_horizontal_movement * Time.deltaTime; } return next_position; } }
Here is the camera code, the faulty nasty beast who refuse to submit, I have try different things and result are always faulty, I'll try to redo the variation and compile playable. Basically this code run on camera, it takes as parameter a root object where a pivot (camera hook) and a target are parented (where the camera look). The idea was to place the root object at the character position and rotate it, the camera position itself on the pivot. using UnityEngine; using System.Collections;
public class CameraDrive : MonoBehaviour { public GameObject targetObject; public Transform camPivot, camTarget, camRoot; float rot = 0; //---------------------------------------------------------------------------------------------------------- void Start() { this.transform.position = targetObject.transform.position; this.transform.rotation = targetObject.transform.rotation; } void FixedUpdate() { //the pivot system camRoot.position = targetObject.transform.position; //input on pivot orientation float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); // rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); // wrapAngle( rot ); // //align camroot with target object up
camRoot.rotation.SetLookRotation(targetObject.transform.forward,targetObject.transform.up); //this camera this.transform.position = camPivot.position; //set the camera to the pivot this.transform.LookAt( camTarget.position ); // } //---------------------------------------------------------------------------------------------------------- public float wrapAngle ( float Degree ) { while (Degree < 0.0f) { Degree = Degree + 360.0f; } while (Degree >= 360.0f) { Degree = Degree - 360.0f; } return Degree; } private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } float GetOffsetAngle( float targetAngle, float DestAngle ) { return ((targetAngle - DestAngle + 180)% 360) - 180; } //---------------------------------------------------------------------------------------------------------- void OnDrawGizmos() { Gizmos.DrawCube( camPivot.transform.position, new Vector3(1,1,1) ); Gizmos.DrawCube( camTarget.transform.position, new Vector3(1,5,1) ); Gizmos.DrawCube( camRoot.transform.position, new Vector3(1,1,1) ); } void OnGUI() { GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString());
} }
Now let's look at different implementation and effects of the part where it should have work: camRoot.rotation.SetLookRotation(targetObject.transform.forward,targetObject.transform.up); Okay fine, transform.forward/up might be local so let's do better: camRoot.rotation.SetLookRotation( this.transform.TransformDirection(targetObject.transform.forward), this.transform.TransformDirection(targetObject.transform.up) ); Still not working, let's try to go random: camRoot.rotation.SetLookRotation( this.transform.InverseTransformDirection(targetObject.transform.forward), this.transform.InverseTransformDirection(targetObject.transform.up) ); Duh, the result is just the same, let's try the secret sauce which allow perfect movement on a sphere: UpdateOrientation(targetObject.transform.forward,targetObject.transform.up); Result ... result never change ... It's totally non sense and bullshit any kind of way I slice it. I know I get data from targetObject.transform, position is out rightfully, something should happen anything, broken thing, but no, just nothing, it sit down upright and do nothing!
|
|
« Last Edit: March 14, 2013, 08:43:42 PM by Gimym TILBERT »
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #2 on: March 15, 2013, 08:25:37 PM » |
|
I change the UpdateOrientation code and now problem a is solved private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } Turns out the mistake was a silly mistake: I applied the orientation to transform.rotation instead of camRoot.transform.rotation since the camera hold the code but apply it to the root of the cam setup. The reason I have the camera and a separate setup is that it allow me to free the camera for more contextual code from the character itself. The camera can now pick any target. It also allow to decouple camera reference from character reference, as the camera is free I don't need to express the character in term of camera, I express the character direction relative to the setup. The camera is not always align to the character but the setup is, therefore sharing the same reference. My previous mistake was to try to lower the number of DOF in the code, I should have increase it which is what I'm doing now. Since the camera is now aligning correctly I had simple support for camera rotation. void FixedUpdate() { //the pivot system camRoot.position = targetObject.transform.position; //input on pivot orientation float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); // rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); // wrapAngle( rot ); // //when the target object rotate, it rotate too, this should not happen
UpdateOrientation(targetObject.transform.forward,targetObject.transform.up);
camRoot.transform.RotateAround(camRoot.transform.up,rot); //this camera this.transform.position = camPivot.position; //set the camera to the pivot this.transform.LookAt( camTarget.position ); // } Simply adding camRoot.transform.RotateAround(camRoot.transform.up,rot); after the orientation update since I was already computing the rotation according to input. Works pretty good ^^ . here is the new build: https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine2.htmlarrow to move/strafe, mice to rotate around the character. Now point c should be a formality, I have to express input relative to local camroot and then compare it to actual character direction, then slowly normalize lerp the too.
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #3 on: March 18, 2013, 08:47:45 PM » |
|
Instead of trying to implement relative movement I have done a visualization first: First I made this function which is trivial relative cam: Vector3 RelativeCamDirection() { float input_vertical_movement = Input.GetAxisRaw( "Vertical" ), input_horizontal_movement = Input.GetAxisRaw( "Horizontal" ); Vector3 relative_forward = camRoot.transform.forward, relative_right = camRoot.transform.right, relative_direction = ( relative_forward * input_vertical_movement ) + ( relative_right * input_horizontal_movement ); return relative_direction.normalized; } Then I added this with a new public transform ( a huge cylinder showing where the direction point at): //debug the relcam dir relcamdirDebug.transform.localPosition = RelativeCamDirection()*6; and here is the build: https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine3.htmlAnd oups it's all wrong I feel stupid, it's wrong even on flat surface not sure what's wrong! I'm stupid, I'm going to fix it asap.
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #4 on: March 22, 2013, 11:01:28 PM » |
|
So I have a bit of burnout and even simple code was flying over my head, I took a rest and came back. As soon as my eyes land on this, I could see what was wrong. Vector3 relative_forward = camRoot.transform.forward, relative_right = camRoot.transform.right, The correct way to do it is that! Vector3 relative_forward = Vector3.forward, relative_right = Vector3.right, I don't even need to check to know it works: https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine4.htmlOkay now let's effectively put it in with motion...
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #5 on: April 05, 2013, 10:06:25 PM » |
|
I'm still failing at the same point That is I have the correct input, I have the correct translation in the camera direction ... but whenever I attempt to slowly lerp the direction of the character in direction of the input, all I get is wild spin! Also discovered that strafing to the right has major singularity trapping on the equator!!
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #6 on: April 05, 2013, 10:14:05 PM » |
|
The lastest working code: Movement code using UnityEngine; using System.Collections;
public class MovementController : MonoBehaviour { public float deadZoneValue = 0.1f, angle, acceleration = 50.0f; public Vector3 motion ;
//-------------------------------------------------------------------------------------------- void OnGUI() { GUILayout.Label( "transform.rotation : " + transform.rotation ); GUILayout.Label( "transform.position : " + transform.position ); GUILayout.Label( "angle : " + angle ); } void FixedUpdate () { Ray ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up ); RaycastHit raycast_result; Rigidbody rigid_body = gameObject.rigidbody; if ( Physics.Raycast( ground_check_ray, out raycast_result ) ) { Vector3 next_position; //UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); next_position = GetNextPosition( raycast_result.point ); rigid_body.MovePosition( next_position ); } } //-------------------------------------------------------------------------------------------- private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } private Vector3 GetNextPosition( Vector3 current_ground_position ) { Vector3 next_position;
// //-------------------------------------------------------------------- // angle = 0; // Vector3 dir = this.transform.InverseTransformDirection(motion); // angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime; // // if(angle > 0) this.transform.Rotate(0,angle,0); // //-------------------------------------------------------------------- next_position = current_ground_position + gameObject.transform.up * 0.5f + motion ; return next_position; } }
camera code using UnityEngine; using System.Collections;
public class CameraDrive : MonoBehaviour { public GameObject targetObject; public Transform camPivot, camTarget, camRoot, relcamdirDebug; float rot = 0; //---------------------------------------------------------------------------------------------------------- void Start() { this.transform.position = targetObject.transform.position; this.transform.rotation = targetObject.transform.rotation; } void FixedUpdate() { //the pivot system camRoot.position = targetObject.transform.position; //input on pivot orientation rot = 0; float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); // rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); // wrapAngle( rot ); // //when the target object rotate, it rotate too, this should not happen
UpdateOrientation(this.transform.forward,targetObject.transform.up);
camRoot.transform.RotateAround(camRoot.transform.up,rot); //debug the relcam dir RelativeCamDirection() ; //this camera this.transform.position = camPivot.position; //set the camera to the pivot this.transform.LookAt( camTarget.position ); // } //---------------------------------------------------------------------------------------------------------- public float wrapAngle ( float Degree ) { while (Degree < 0.0f) { Degree = Degree + 360.0f; } while (Degree >= 360.0f) { Degree = Degree - 360.0f; } return Degree; } private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } float GetOffsetAngle( float targetAngle, float DestAngle ) { return ((targetAngle - DestAngle + 180)% 360) - 180; } //---------------------------------------------------------------------------------------------------------- void OnDrawGizmos() { Gizmos.DrawCube( camPivot.transform.position, new Vector3(1,1,1) ); Gizmos.DrawCube( camTarget.transform.position, new Vector3(1,5,1) ); Gizmos.DrawCube( camRoot.transform.position, new Vector3(1,1,1) ); } void OnGUI() { GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());
} //---------------------------------------------------------------------------------------------------------- void RelativeCamDirection() { float input_vertical_movement = Input.GetAxisRaw( "Vertical" ), input_horizontal_movement = Input.GetAxisRaw( "Horizontal" ); Vector3 relative_forward = Vector3.forward, relative_right = Vector3.right, relative_direction = ( relative_forward * input_vertical_movement ) + ( relative_right * input_horizontal_movement ) ; MovementController MC = targetObject.GetComponent<MovementController>(); MC.motion = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime; MC.motion = this.transform.TransformDirection( MC.motion ); //MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime); } }
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #7 on: April 05, 2013, 10:33:33 PM » |
|
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #8 on: April 06, 2013, 01:36:29 PM » |
|
I made a new demo, and it's totally broken ... https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine5a.htmlI have toss the problem at internet for 3 years, and it is still scratching is head. So I asked the only person I knew who had solve the problem: What's "the move"? is there some secret trick I don't know about? o__o ah right, how I *coded* it, gotcha! well... it's been a while but I'll try to explain my hazy memory of the system! raycast down to find the floor, whatever normal that ray hit then has, is "up" convert (vector that is input*cam directions) relative to the plane determind by "up", move sarah along that plane... then raycast again to find new 'up'. I realise the middle step is more or less voodoo, but that's where my memoryis hazy IIRC things I tried were unity's own Plane class or some such, quite handy, and also making empty reference gameobjects there was also some degree of rotating stuff in another thing's local space so that 'forward' and 'left' never jumped 180 otherwise you could get sarah to go jittery the moment you cross odd angles ya, even with the right approach if you use the transformpoint when you want inverse or have a bad lookat it all breaks can't remember how I used it, but I think it solved some problems http://docs.unity3d.com/Documentation/ScriptReference/Plane.html … ...though it might have been for a different game entirely... sorry if that's the case, hazy memory really is hazy ^__^; Now I need to parse the clue ...
|
|
|
Logged
|
|
|
|
moi
|
|
« Reply #9 on: April 06, 2013, 01:51:38 PM » |
|
send me the unity source file, I'll fix it for you
|
|
|
Logged
|
subsystems subsystems subsystems
|
|
|
gimymblert
|
|
« Reply #10 on: April 06, 2013, 02:05:53 PM » |
|
|
|
|
Logged
|
|
|
|
moi
|
|
« Reply #11 on: April 06, 2013, 02:17:01 PM » |
|
I'll take a look
|
|
|
Logged
|
subsystems subsystems subsystems
|
|
|
gimymblert
|
|
« Reply #12 on: April 06, 2013, 03:41:58 PM » |
|
Thanks
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #13 on: April 07, 2013, 05:22:50 PM » |
|
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #14 on: April 07, 2013, 07:39:36 PM » |
|
Movement using UnityEngine; using System.Collections;
public class MovementController : MonoBehaviour { public float deadZoneValue = 0.1f, angle, acceleration = 50.0f; public Vector3 motion ;
//-------------------------------------------------------------------------------------------- void OnGUI() { GUILayout.Label( "transform.rotation : " + transform.rotation ); GUILayout.Label( "transform.position : " + transform.position ); GUILayout.Label( "angle : " + angle ); } void FixedUpdate () { Ray ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up ); RaycastHit raycast_result; Rigidbody rigid_body = gameObject.rigidbody; if ( Physics.Raycast( ground_check_ray, out raycast_result ) ) { Vector3 next_position; //UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); next_position = GetNextPosition( raycast_result.point ); rigid_body.MovePosition( next_position ); } } //-------------------------------------------------------------------------------------------- private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } private Vector3 GetNextPosition( Vector3 current_ground_position ) { Vector3 next_position;
// //-------------------------------------------------------------------- // angle = 0; // Vector3 dir = this.transform.InverseTransformDirection(motion); // angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime; // // if(angle > 0) this.transform.Rotate(0,angle,0); // //-------------------------------------------------------------------- next_position = current_ground_position + gameObject.transform.up * 0.5f + motion ; return next_position; } }
Camera using UnityEngine; using System.Collections;
public class CameraDrive : MonoBehaviour { public GameObject targetObject; public Transform camPivot, camTarget, camRoot, relcamdirDebug; float rot = 0; //---------------------------------------------------------------------------------------------------------- void Start() { this.transform.position = targetObject.transform.position; this.transform.rotation = targetObject.transform.rotation; } void FixedUpdate() { //the pivot system camRoot.position = targetObject.transform.position; //input on pivot orientation rot = 0; float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); // rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); // wrapAngle( rot ); // //when the target object rotate, it rotate too, this should not happen
UpdateOrientation(this.transform.forward,targetObject.transform.up);
camRoot.transform.RotateAround(camRoot.transform.up,rot); //debug the relcam dir RelativeCamDirection() ; //this camera this.transform.position = camPivot.position; //set the camera to the pivot this.transform.LookAt( camTarget.position ); // } //---------------------------------------------------------------------------------------------------------- public float wrapAngle ( float Degree ) { while (Degree < 0.0f) { Degree = Degree + 360.0f; } while (Degree >= 360.0f) { Degree = Degree - 360.0f; } return Degree; } private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } float GetOffsetAngle( float targetAngle, float DestAngle ) { return ((targetAngle - DestAngle + 180)% 360) - 180; } //---------------------------------------------------------------------------------------------------------- void OnDrawGizmos() { Gizmos.DrawCube( camPivot.transform.position, new Vector3(1,1,1) ); Gizmos.DrawCube( camTarget.transform.position, new Vector3(1,5,1) ); Gizmos.DrawCube( camRoot.transform.position, new Vector3(1,1,1) ); } void OnGUI() { GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());
} //---------------------------------------------------------------------------------------------------------- void RelativeCamDirection() { float input_vertical_movement = Input.GetAxisRaw( "Vertical" ), input_horizontal_movement = Input.GetAxisRaw( "Horizontal" ); Vector3 relative_forward = Vector3.forward, relative_right = Vector3.right, relative_direction = ( relative_forward * input_vertical_movement ) + ( relative_right * input_horizontal_movement ) ; MovementController MC = targetObject.GetComponent<MovementController>(); MC.motion = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime; MC.motion = this.transform.TransformDirection( MC.motion ); //MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime); if (MC.motion.sqrMagnitude > 0) { Quaternion target = Quaternion.LookRotation( relative_direction, MC.transform.up ); MC.transform.rotation = Quaternion.Slerp(MC.transform.rotation, target, 0.5f); } } }
I didn't provide the modified code for the 5a version, only the camera was changed, 2 lines of code added
|
|
« Last Edit: April 07, 2013, 08:01:32 PM by Gimym TILBERT »
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #15 on: April 07, 2013, 09:17:24 PM » |
|
Okay I'm norrowing the problem!
In movement code, I should project the motion vector, not the forward vector, this get the relative cam direction great!
However it seems there is a bug with motion itself, side input are not correctly projected along the curvature, Forward move bend, but side move does not ...
|
|
|
Logged
|
|
|
|
gimymblert
|
|
« Reply #16 on: April 07, 2013, 09:47:42 PM » |
|
Solved! I was converting the motion to global space from local camera space instead of local camera "root" space. Silly error is silly! https://dl.dropbox.com/u/24530447/flash%20build/litesonicengine/LiteSonicEngine6.htmlArrow to move, mouse to turn the camera around ... movement code using UnityEngine; using System.Collections;
public class MovementController : MonoBehaviour { public float deadZoneValue = 0.1f, angle, acceleration = 50.0f; public Vector3 motion ; public Vector3 ground_direction ;
//-------------------------------------------------------------------------------------------- void OnGUI() { GUILayout.Label( "transform.rotation : " + transform.rotation ); GUILayout.Label( "transform.position : " + transform.position ); GUILayout.Label( "angle : " + angle ); GUILayout.Label( "ground_direction : " + ground_direction ); GUILayout.Label( "motion : " + ground_direction ); } void FixedUpdate () { Ray ground_check_ray = new Ray( gameObject.transform.position, -gameObject.transform.up ); RaycastHit raycast_result; Rigidbody rigid_body = gameObject.rigidbody; if ( Physics.Raycast( ground_check_ray, out raycast_result ) ) { Vector3 next_position; //UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); UpdateOrientation( gameObject.transform.forward, raycast_result.normal ); next_position = GetNextPosition( raycast_result.point ); rigid_body.MovePosition( next_position ); ground_direction = raycast_result.normal; } } //-------------------------------------------------------------------------------------------- private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_motion_to_normal_surface = motion - ( Vector3.Dot( motion, ground_normal ) ) * ground_normal; Quaternion target; if (motion.sqrMagnitude > 0) { target = Quaternion.LookRotation( projected_motion_to_normal_surface, ground_direction ); } else { target = Quaternion.LookRotation( transform.forward, ground_direction ); } transform.rotation = target;//Quaternion.Slerp( transform.rotation, target, 0.1f ); //transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); Debug.DrawRay(this.transform.position,motion*10,Color.yellow,0.0f,false); } private Vector3 GetNextPosition( Vector3 current_ground_position ) { Vector3 next_position;
// //-------------------------------------------------------------------- // angle = 0; // Vector3 dir = this.transform.InverseTransformDirection(motion); // angle = Vector3.Angle(Vector3.forward, dir);// * 1f * Time.fixedDeltaTime; // // if(angle > 0) this.transform.Rotate(0,angle,0); // //-------------------------------------------------------------------- next_position = current_ground_position + gameObject.transform.up * 0.5f + motion ; return next_position; } } camera code using UnityEngine; using System.Collections;
public class CameraDrive : MonoBehaviour { public GameObject targetObject; public Transform camPivot, camTarget, camRoot, relcamdirDebug; float rot = 0; //---------------------------------------------------------------------------------------------------------- void Start() { this.transform.position = targetObject.transform.position; this.transform.rotation = targetObject.transform.rotation; } void FixedUpdate() { //the pivot system camRoot.position = targetObject.transform.position; //input on pivot orientation rot = 0; float mouse_x = Input.GetAxisRaw( "camera_analog_X" ); // rot = rot + ( 0.1f * Time.deltaTime * mouse_x ); // wrapAngle( rot ); // //when the target object rotate, it rotate too, this should not happen
UpdateOrientation(this.transform.forward,targetObject.transform.up);
camRoot.transform.RotateAround(camRoot.transform.up,rot); //this camera this.transform.position = camPivot.position; //set the camera to the pivot //Quaternion target = Quaternion.LookRotation(targetObject.transform.position - this.transform.position, targetObject.transform.up); //this.transform.rotation = Quaternion.Slerp(this.transform.rotation, target, 0.1f); //debug the relcam dir RelativeCamDirection();
this.transform.LookAt( camTarget.position ); // } //---------------------------------------------------------------------------------------------------------- public float wrapAngle ( float Degree ) { while (Degree < 0.0f) { Degree = Degree + 360.0f; } while (Degree >= 360.0f) { Degree = Degree - 360.0f; } return Degree; } private void UpdateOrientation( Vector3 forward_vector, Vector3 ground_normal ) { Vector3 projected_forward_to_normal_surface = forward_vector - ( Vector3.Dot( forward_vector, ground_normal ) ) * ground_normal; camRoot.transform.rotation = Quaternion.LookRotation( projected_forward_to_normal_surface, ground_normal ); } float GetOffsetAngle( float targetAngle, float DestAngle ) { return ((targetAngle - DestAngle + 180)% 360) - 180; } //---------------------------------------------------------------------------------------------------------- void OnDrawGizmos() { Gizmos.DrawCube( camPivot.transform.position, new Vector3(1,1,1) ); Gizmos.DrawCube( camTarget.transform.position, new Vector3(1,5,1) ); Gizmos.DrawCube( camRoot.transform.position, new Vector3(1,1,1) ); } void OnGUI() { GUI.Label(new Rect(0,80,1000,20*10), "targetObject.transform.up : " + targetObject.transform.up.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "target euler : " + targetObject.transform.eulerAngles.y.ToString()); GUI.Label(new Rect(0,100,1000,20*10), "rot : " + rot.ToString());
} //---------------------------------------------------------------------------------------------------------- void RelativeCamDirection() { Vector3 relative_direction = ( Vector3.forward * Input.GetAxisRaw( "Vertical" ) ) + ( Vector3.right * Input.GetAxisRaw( "Horizontal" ) ) ; MovementController MC = targetObject.GetComponent<MovementController>(); Vector3 direction = relative_direction.normalized * MC.acceleration * Time.fixedDeltaTime; Vector3 abs_direction = camRoot.transform.TransformDirection( direction ); MC.motion = abs_direction; Debug.DrawRay (camRoot.position, camRoot.right,Color.red,0.0f,false); Debug.DrawRay (camRoot.position, camRoot.up,Color.green,0.0f,false); Debug.DrawRay (camRoot.position, camRoot.forward,Color.blue,0.0f,false); //MC.transform.Rotate(Vector3.up, input_horizontal_movement * 10f * Time.fixedDeltaTime);
} } Okay now on: 1. adding momentum relative to surface 2. correct jump transition from ground and air (relative to gravity) with correct momentum conservation
|
|
|
Logged
|
|
|
|
|
gimymblert
|
|
« Reply #18 on: April 14, 2013, 08:49:50 PM » |
|
Okay, I'm moving to coding momentum, I was doing a bit of paper testing, to see if there was any problem before diving on the code.
The routine should be: 1 - Accumulate all force in _momentum in global space 2 - convert it into local space and remove local Y component to obtain a tangent projection 3 - Apply the projection the body ... 4 - ... 5 - Profit?
Well duh not! Paper prototyping show that curvature would chip away a bit of the momentum which would dies completely off once the curvature accumulation got over 90° from the initial normal on which it was applied. It is a violation of the pseudo Newtonian physics I want to reproduce on arbitrary surface. I need to keep momentum constant in local space, therefore I must correct the momentum at each step to the new normal before applying new force.
Then I ran in a new problem, which magic would allow me to keep momentum constant in direction and strength when the reference are always shifting. The solution is to make it it's own reference! I will had a GO which would be oriented in the momentum direction and apply alignment correction like the body and camera and leave it independent.
So: 1 - Correct the current momentum GO alignment 2 - accumulate force in global space 3 - convert the global force to local and projecting it to tangent plane 4 - resolve the new momentum direction and strength 5 - apply the new momentum 6 - ... 7 - PROFIT!
Now let make it a reality
|
|
|
Logged
|
|
|
|
|