- Home /
Better Point to Point Movement
I'm working on a script to move a unit around (RTS style camera/movement) and using CharacterController but I'm finding the CharacterController doesn't quite provide for realistic movement of a unit.
Below is my FixedUpdate method which is handling the units movement, and I've commented the pieces where I'm having some trouble - could I get a second pair of eyes on this to see if theres a better way for each point (almost certainly) and/or if I'm missing something already provided by unity3d to make this easier?
@script RequireComponent( CharacterController ) function FixedUpdate( ) { if( travelTo != null ) { var controller : CharacterController = gameObject.GetComponent( CharacterController ); var forward = transform.TransformDirection( Vector3.forward );
// 1: This works well enough, but I'd like to "stick" to the ground, I find steep hills seem to defeat this controller and he starts to "float" up from terrain
// 2: Also, how to I keep a model upright so that it will be parallel to the y-axis? rigidbody does not seem to work nor Freeze Rotation here.
controller.SimpleMove( forward * unitSpeedValue );
move( );
// 3: how can I reliably stop my object since if the check below is too small I can "jump over" it and never stop running! should I be subtracting vectors and checking for <= 0.0?
var distance = Vector3.Distance( controller.transform.position, travelTo );
if( distance < 0.5 )
{
// 4: translate the rigidbody the rest of the distance? or will solving 2 well make this uneccessary?
travelTo = null;
stay( );
}
}
}
Answer by StephanK · Apr 16, 2010 at 08:06 AM
transform.TransformDirection( Vector3.forward ) = transform.forward
1: what happens in move() ? 2: Calculate the rotation between the normal beneath your vehicle and your Transform's up vector. Apply that rotation to you transform.
3: You can use unitSpeedValue instead of the constant 0.5f to determine if you will overshoot. 4: If you perform the check before you move the unit you could just decrease your speed on the last frame of the movement:
var speed = 0; var distanceToTarget = Vector3.Distance( transform.position, travelTo ); if (distanceToTarget < unitSpeedValue) speed = distanceToTarget; else speed = unitSpeedValue;
controller.SimpleMove(transform.forward * speed);
Hope that helps.
move() is just a wrapper for my animation clip, nothing that impacts transformation or physics on the object, same with stay().
Your idea for using distanceToTarget is simple and elegant, I like it - thanks :) - will try that out tonight.
For calculating the rotation etc, how do I get the normal under my object? I guess I could cast a ray from the middle of my vehicle down the Y axis and filter the collider for the vehicles layer out on that one? Is the code fairly straight forward for that? Sorry if it seems lazy of me, I'm working in GWT/J2EE/Grails all day and making the context switch to math/physics at home is a real bugger ;).
I'm guessing (1) is due to my using a box collider perhaps, ins$$anonymous$$d of capsule.
Normal under object: do a Physics.Raycast() downwards. The RaycastHit has a member "normal" which is the normal of the surface that was hit.
Ok will try that now, the solution above has a couple problems for me, mainly that when speed is adjusted my unit does not reach the spot I clicked (it's off by a bit) and, predictably, their speed changes close to the destination which isn't what I'm looking for ... I'll work on it and post what I come up with. Will try the raycast here, IIRC last time I tried it would cast from the bottom of my unit and "miss" the terrain, but I'll try a filter and find a different reference point to go from here to avoid this.
$$anonymous$$y thought was to start from a point under the ground at units x,z and get a height which would not be impacted by other colliders or poss bugs where the unit somehow gets clipped by another image ... anyhow, fun fun, will try again.
Answer by Lypheus · Apr 17, 2010 at 06:25 PM
Ok, i took another approach here and am using a distance delta to account for when i'm done moving, like so (see below). This works great so far. For the sake of brevity I have removed some state that i'm going to need for course correction/pathfinding coming up , but this should give somebody an easy start to this problem if needed.
@script RequireComponent( CharacterController ) function FixedUpdate( ) { if( distance > 0.0 ) { controller.SimpleMove( transform.TransformDirection( Vector3.forward ) * spd ); distance -= spd * Time.deltaTime; } }
function moveTo( destination ) { distance = Vector3.Distance( controller.transform.position, destination ); }
Your answer
Follow this Question
Related Questions
RTS Movement - I'm doing it wrong 2 Answers
3rd-person RPG movment on uneven terrain? 1 Answer
vehicle moveing on the terrain 0 Answers
RTS Units; Wheel Colliders 2 Answers
Motion over sloped terrain 0 Answers