- Home /
Restrict player movement to circle's circumference and rotate to lookat
I have a gameObject that I would like to keep restricted to the perimeter of a circle. I want to be able to move the object around the edge of the circle (image example 1) and look in towards the circle (maybe this can be done with SmoothLookAt script) but I do not want the player to be able to enter or leave the circle. Also, I want to prevent the player from looking away from the circle. How can this be done?
I'm using the following script, but the gameobject get away from the circle's edge as the player move (image example 2).
using UnityEngine;
using System.Collections;
public class SpiralMovement : MonoBehaviour {
public float walkSpeed;
Rigidbody playerRigidBody;
Transform playerTransform;
public Transform playerPivot;
Vector3 inputMovement;
// Use this for initialization
void Awake () {
playerRigidBody = this.rigidbody; //just caching the rigidbody for speed reasons, rather than calling rigidbody.velocity later, which is much slower.
playerTransform = this.transform; //same with the transform, caching it for performance reasons
}
// Update is called once per frame
void Update () {
playerPivot.position = new Vector3(playerPivot.position.x,playerTransform.position.y,playerPivot.position.z); //make the pivot object the same y height as the player, so it doesn't stay down on the ground
playerPivot.LookAt(playerTransform,Vector3.up); //make the pivot look at the player
Quaternion pivotRotation = playerPivot.localRotation; //get the rotation of the pivot, so that we can adjust the inputs below to be relative to that
inputMovement = Vector3.zero; //resetting the inputMovement vector which will hold all our input information
if(Input.GetKey(KeyCode.W)){
inputMovement += pivotRotation * Vector3.back;
}
if(Input.GetKey(KeyCode.S)){
inputMovement += pivotRotation * Vector3.forward;
}
if(Input.GetKey(KeyCode.A)){
inputMovement += pivotRotation * Vector3.right;
}
if(Input.GetKey(KeyCode.D)){
inputMovement += pivotRotation * Vector3.left;
}
inputMovement = inputMovement.normalized * walkSpeed; //normalising the inputMovement vector so it's not too large and then we can cleanly multiply it by whatever walk speed we desire
playerRigidBody.velocity = new Vector3(inputMovement.x,playerRigidBody.velocity.y,inputMovement.z); //apply the inputMovement vector to the players velocity, but not on the y axis otherwise it will overwrite gravity.
playerTransform.localRotation = pivotRotation; //keep the player rotated the same as the pivot so it doesn't start walking backwards
}
}
Edit
This is the working code:
using UnityEngine;
using System.Collections;
public class SpiralMovement : MonoBehaviour {
public float walkSpeed;
Rigidbody playerRigidBody;
Transform playerTransform;
public Transform playerPivot;
Vector3 inputMovement;
Vector3 circleCenter;
float radius = 1.787921f;
public Transform circleCenterObject;
// Use this for initialization
void Awake () {
playerRigidBody = this.GetComponent<Rigidbody>(); //just caching the rigidbody for speed reasons, rather than calling rigidbody.velocity later, which is much slower.
playerTransform = this.transform; //same with the transform, caching it for performance reasons
}
// Update is called once per frame
void Update () {
playerPivot.position = new Vector3(playerPivot.position.x,playerTransform.position.y,playerPivot.position.z); //make the pivot object the same y height as the player, so it doesn't stay down on the ground
playerPivot.LookAt(playerTransform,Vector3.up); //make the pivot look at the player
Quaternion pivotRotation = playerPivot.localRotation; //get the rotation of the pivot, so that we can adjust the inputs below to be relative to that
inputMovement = Vector3.zero; //resetting the inputMovement vector which will hold all our input information
/*if(Input.GetKey(KeyCode.W)){
inputMovement += pivotRotation * Vector3.back;
}
if(Input.GetKey(KeyCode.S)){
inputMovement += pivotRotation * Vector3.forward;
}*/
if(Input.GetKey(KeyCode.A)){
inputMovement += pivotRotation * Vector3.right;
}
if(Input.GetKey(KeyCode.D)){
inputMovement += pivotRotation * Vector3.left;
}
inputMovement = inputMovement.normalized * walkSpeed; //normalising the inputMovement vector so it's not too large and then we can cleanly multiply it by whatever walk speed we desire
circleCenter = circleCenterObject.position;
Vector3 offset = transform.position - circleCenter;
offset = offset.normalized * radius;
transform.position = offset;
playerRigidBody.velocity = new Vector3(inputMovement.x,playerRigidBody.velocity.y,inputMovement.z); //apply the inputMovement vector to the players velocity, but not on the y axis otherwise it will overwrite gravity.
playerTransform.localRotation = pivotRotation; //keep the player rotated the same as the pivot so it doesn't start walking backwards
}
}
You could make a circular corridor from Unity cubes. Then you could turn off(or delete) the $$anonymous$$esh renders so you cannot see the colliders that are restricting the movement of the player... just an idea...
If I understand correctly you want the player to stick to the perimeter of a circle, then you should just be able to create a DummyObject, place your player a a child of this DummyObject, then offset the PlayerObject inside this DummyObject, then for movement, just rotate the DummyObject,. You wouldn't even need to a have a lookAt script, as it would be looking at the centre anyway.
Answer by Kiwasi · Oct 15, 2014 at 08:04 AM
To constrain an object to a circle you simply force the object to remain a set distance (the radius) from centre of the circle. Here is a code example.
Vector3 circleCentre;
Vector3 radius;
void Update (){
// Do all other movement first
// Constrain to a circle with the following
Vector3 offset = transform.position - circleCenter;
offset.Normalise();
offset = offset * radius;
transform.position = offset;
}
Answer by Namey5 · Oct 15, 2014 at 07:41 AM
The problem may be the fact that you are using a smoothLokAt script. If you use something like transform.LookAt, the object will constantly be snapped looking at the object you set it to. If you use this alone, however, you will have no control over the camera. Then you would simply need to change the movement to left or right instead of pivoting around that point. As far as I can tell, that is what you want.
Answer by oakshiro · Nov 21, 2017 at 04:41 PM
float maxRadius = 2.0f var allowedPos = mousePos - initialPos; allowedPos = Vector3.ClampMagnitude(allowedPos, maxRadius); transform.position = initialPos + allowedPos;
Answer by iuripujol · Jan 17, 2018 at 07:31 PM
Use Vector3.Cross to get the tangent Vector3 relative to the Radius (circumference radius - transform.position) and the transform.up of the player.