I need to restrict my Players hand inside a radius around the character.
The game is 2D and the hand movement is basically exactly the same as: Madness Interactive (https://www.newgrounds.com/portal/view/118826)
[SerializeField] private float speed = 2f;
[SerializeField] private GameObject radiusCenter;
[SerializeField] private float radius = 0.5f;
void Start()
{
Cursor.visible = false;
}
void Update()
{
Vector3 playerPos = radiusCenter.transform.position;
Vector3 playerToHand = this.transform.position - playerPos;
var moveDirection = new Vector3(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"), 0);
float DistanceToRadius = Vector3.Distance(playerPos, playerToHand);
transform.position += moveDirection * speed * Time.deltaTime;
float angle = Mathf.Atan2(playerToHand.y, playerToHand.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
I cant figure out the way to keep my players hand inside a set radius around my player, see pictures below for further explanation:
I thought maybe I could get a float value from playerPos and playerToHand and create a IF-statement that restricts the hand from going outside the set radius float, but I didnt get it to work...
EDIT 1: The hand is a child of my player. I use a gameObject in the center of my player as radiusCenter which my hand rotates around.
One very simple way to check if the hand is too far away is to use this line of code:
<movement code here>
if (Vector3.distance(playerPos, transform.position) > radius)
{
transform.localPosition = transform.localPosition.normalized * radius;
{
This will make it so if the hand will be outside the circle after the move, it will just put the hand on the circle.
Related
Consider this working script, that handles a FPS camera movement:
using UnityEngine;
public class CameraHandler : MonoBehaviour {
public Transform target;
float dragSpeed = 10f;
float lookAtSensitivity = 200f;
float xRot;
Transform parentGO;
private void Start() {
parentGO = transform.parent;
}
void goToPivot(Transform pivot) {
parentGO.position = Vector3.Lerp(transform.position, pivot.position, 0.05f);
transform.rotation = Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f);
}
void resetCamRot() {
xRot = 0;
float yRot = transform.localEulerAngles.y;
parentGO.transform.eulerAngles += new Vector3(0, yRot, 0);
transform.localEulerAngles -= new Vector3(0, yRot, 0);
}
void LateUpdate() {
if (Input.GetKey(KeyCode.Mouse1)) {
float touchX = Input.GetAxis("Mouse X") * lookAtSensitivity * Time.deltaTime;
float touchY = Input.GetAxis("Mouse Y") * lookAtSensitivity * Time.deltaTime;
xRot -= touchY;
xRot = Mathf.Clamp(xRot, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f);
parentGO.transform.Rotate(Vector3.up * touchX);
}
if (Input.GetKey(KeyCode.Space)) {
goToPivot(target);
}
if (Input.GetKeyUp(KeyCode.Space)) {
resetCamRot();
}
}
}
Check how the rotations take place in different gameobjects in their respective axis, so that each of rotations are kept independent and everything works.
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f); //camera GO only rotates in local x
parentGO.transform.Rotate(Vector3.up * touchX); //parent GO only rotates in global y
Problem comes when I need to "force" the camera look a certain direction without the inputs, to the FPS movement rules break, and for example the camera gameobject rotates also in the Y xis. That is why I need to call the resetCamRot() method, and traspass the local rotation from the camera object to the parent so that the situation meets the the FPS movement requirements (no local Y axis rotation).
Without calling the resetCamRot() method, when the FPS movement starts on right mouse button click, the camera abruptly changes to the direction it was facing before "forcing" it with goToPivot that sets the position and the rotation.(Just commentinf the resetCamRot method out)
Although resetCamRot() does the work it feels a bit hacky, so is there another way to set the camera to a forced rotation maintaining the local rotation of the child object (where the camera is) to 0?
I thought of decomposing the next step rotation given by Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f); in the goToPivot() method in each of their respective axis and gameObjects as its done when the rotation is set from the input, to have a clean local Y rot in he camera gameobject each step. Seems to be the over-complicated thing in this case, but was not able to figure that out.
I you wish to try the script out for the challenge just need to add a parent gameobject to the camera and the attach the target in the editor.
This will make the camera look in the direction, the parent transform look in the direction, only flattened, and finally update the internal state (xRot) in accordance with the difference between the two:
void LookTowards(Vector3 direction) {
Vector3 flattened = direction;
flattened.y = 0f;
parentGo.rotation = Quaternion.LookRotation(flattened);
transform.rotation = Quaternion.LookRotation(direction);
xRot = Vector3.SignedAngle(flattened, direction, parentGo.right);
}
This is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Tweekable move speed
public float MoveSpeed = 4;
// Set what distance it should be from the target
int MaxDist = 10;
int MinDist = 5;
// This is the target
public Transform Mouse;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// Keep looking at an object
transform.LookAt();
// Turn off gravity
Physics2D.gravity = Vector2.zero;
// When distance is over minimun
if (Vector3.Distance(Mouse.position, Mouse.position) >= MinDist)
{
// Keep distance
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
// When it's between max and minimun
if (Vector3.Distance(transform.position, Mouse.position) <= MaxDist)
{
}
}
}
// I imported this code from another project so the enemy keeps looking at the player, and keeps his distance. it was a 3D project, so there may be more errors, and this is also my first time creating a game. Be gentle
I am working on a similar project right now.
Here is the code I use to rotate the player (first part) and then move it into that direction (second part):
public Rigidbody2D rb;
public float speed;
void Update()
{
//get mouse position
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//calculating the angle
float AngleRad = Mathf.Atan2(mousePos.y - transform.position.y, mousePos.x -
transform.position.x);
float AngleDeg = (180 / Mathf.PI) * AngleRad;
//rotating the player
Player.transform.rotation = Quaternion.Euler(0, 0, AngleDeg);
//second part
Vector3 mouseDir = mousePos - transform.position;
mouseDir.z = 0f;
mouseDir = mouseDir.normalized;
rb.AddForce(mouseDir * speed);
}
If the player rotates, but it is looking in the wrong way (in my case), then play around with the the last line of the first part. The following code worked fine for me:
transform.rotation = Quaternion.Euler(0, 0, AngleDeg - 90);
If you want the player to move at a constant speed, then you can use
rb.velocity = mouseDir * speed;
instead of
rb.AddForce(mouseDir * speed);
in the last line of the second part.
Your Player-Gameobject needs a Rigidbody2D component. I also added an if-statement around the second part, so the player only moves to the wanted direction when (for example) space is pressed, but always looks to the mouse.
I am working on controls for a bipedal tank, that has a boost/dash feature.
When the boost/dash mode is activated by holding a button the tank changes from a traditional WASD strafing movement to something like a jet fighter but on ground.
Now when the player tries to turn while boosting the camera needs to tilt with the turning direction to make it feel smoother.
Here is a video clip showing my problem
This is the script added to the main camera
public class PlayerCameraTilt : MonoBehaviour
{
private Camera viewCam;
private CharacterController characterController;
public float tiltAmount = 10f;
private void Start()
{
viewCam = GetComponent<Camera>();
characterController = GetComponentInParent<CharacterController>();
}
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, -inputValue, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
else
{
Vector3 euler = transform.localEulerAngles;
euler.z = Mathf.Lerp(euler.z, 0f, 5f * Time.deltaTime);
transform.localEulerAngles = euler;
}
}
}
It kind of works, BUT only in one rotation direction, namely the positive one. If i turn the other way the angle becomes negative and does a whole 360 degree rotation until it ends up at 0 degrees.
I tried around with the built in Quaternion methods like Quaternion.Rotate() or Quaternion.AngleAxis()
but they didn't work because Quaternion.Rotate() doesn't tilt the Camera but completely rotates it. Quaternion.AngleAxis() works with the whole tilt angle limit but also does something to the other axis which i don't want to modify.
Is there a way to prevent the camera from doing a complete 360° rotation when the axis input becomes negative and just tilt in a slight angle?
Wraparound issues aside, the z component is "applied" first among the euler components, so I wouldn't modify it directly like that in this application.
Instead, I would convert the input to an angle to lean, rotate the direction of the local up before localRotation is applied (Quaternion.Inverse(transform.localRotation) * transform.up) by that angle, then use Quaternion.LookRotation to find a rotation with the current forward and that up, then use Quaternion.Slerp to slerp toward that rotation:
private void Update()
{
if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Vector3 upDir = Quaternion.AngleAxis(-inputValue, transform.forward) * upOfParent;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upDir);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
else
{
float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;
Quaternion goalRot = Quaternion.LookRotation(transform.forward, upOfParent);
transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
}
}
Just keep in mind that using t = 5f * Time.deltaTime for lerp/slerp operations does not always guarantee that the output will ever equal the to parameter.
Does any one know how to control the camera view with only a single joystick? Currently im using a joystick from the switch.
Heres my current code.
public class MoveCamera : MonoBehaviour
{
public float speed = 1.0f;
Camera cameraMovement;
void Update ()
{
float xRot = speed * Input.GetAxis("JoyStickX");
float yRot = speed * Input.GetAxis("JoyStickY");
transform.Rotate(xRot, yRot, 0.0f);
}
}
In the editor, create an empty game object called "Pivot"
Make your camera a child of Pivot.
Move the camera away from Pivot, whatever distance you need.
Now attach a script to Pivot.
Something like this :
void Update(){
float speed = 3.0f;
float xRot = speed * Input.GetAxis("Vertical");
float yRot = speed * Input.GetAxis("Horizontal");
transform.Rotate(xRot, yRot, 0.0f);
}
Assign your camera to the camera var in the script attached to Pivot
Now you do the messing around of the rotation
I am trying to make a simple game where I am shooting a projectile when the user touches the screen, I first spawn 8 projectiles (sprites) and when the user touches the screen I would like the top projectile to fly in the touch direction. I was able to do this; However, every time I shoot, the projectile goes in the wrong direction, here is an image which will illustrate the issue.
Obviously the image is still here but the object will continue flying until it goes out of the screen and then gets destroyed.
Here is the code snippet that handles this
GameplayController.cs
if (Input.GetMouseButtonDown(0))
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
position = Camera.main.ScreenToWorldPoint(position);
GameObject target;
target = new GameObject();
target.transform.position = position;
Arrow comp = currentArrows[0].GetComponent<Arrow>();
comp.setTarget(target.transform);
comp.GetComponent<Arrow>().arrowSpeed = 12;
comp.GetComponent<Arrow>().shoot = true;
currentArrows.RemoveAt(0);
Destroy(target);
}
I know I am getting the mouse input here and not the phone touch and that's fine for me, later I will convert it to the touch input.
Arrow.cs
public bool shoot = false;
public float arrowSpeed = 0.0f;
public Vector3 myDir;
public float speed = 30.0f;
private Transform target;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(shoot)
{
transform.position += transform.right * arrowSpeed * Time.deltaTime;
}
}
public void setTarget(Transform targetTransform)
{
this.target = targetTransform;
Vector3 vectorToTarget = target.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
}
private void OnBecameInvisible()
{
print("Disappeared");
Destroy(gameObject);
Gameplay.instance.isShooting = false;
}
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
I think that your problem is that you're getting the screen coordinates by click, not the world coordinates, which is actually two different things. In order to direct your projectile correctly you need to convert your screen coordinates to world like it's done here.
The next thing is how you move the projectile:
transform.position += transform.right * arrowSpeed * Time.deltaTime;
You're moving the projectile to the right and then rotating it somehow. Maybe you should try to move it with Vector3.Lerp, which will be easier and rotate it with Transform.LookAt.