Unity3D Clamping cursor to circle to imitate a gamepad joystick - unity3d

I am working on a 3D, top-down, voxel, spaceship arena shooter (mnk, gamepad) with a static camera.
I am moving the spaceship with WASD and want it to rotate with my mouse input on its Y-axis.
For that, I want to create an invisible circle that stays in the middle of the screen that the cursor can't leave. Based on the position of the cursor in the circle I want to rotate my spaceship independent from where the ship is.
Diagram for clarification
I don't know how to calculate this angle and apply it to the rotation of my ship or even how to create such circle with the limited cursor movement. I want to add a crosshair in the end and I use the new input system (if that's relevant).
So far my code for the movement looks like this:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class MovementBehaviour : MonoBehaviour
{
private Rigidbody sphereRigbod;
private PlayerInput playerInput;
private PlayerInputActions playerInputActions;
private Camera mainCamera;
public WeaponBehaviour weapon;
public Vector3 playerRotation;
[SerializeField] private float speed = 70f;
private void Awake()
{
sphereRigbod = GetComponent<Rigidbody>();
playerInput = GetComponent<PlayerInput>();
playerInputActions = new PlayerInputActions();
playerInputActions.PlayerMovement.Enable(); //Enables EVERY Action map set up!
mainCamera = FindObjectOfType<Camera>();
}
private void FixedUpdate()
{
//X Z Movement WASD
Vector2 inputVector = playerInputActions.PlayerMovement.Movement.ReadValue<Vector2>();
sphereRigbod.AddForce(new Vector3(inputVector.x, 0, inputVector.y) * speed, ForceMode.Force);
}
}
This is what my movement looks like at the moment.
Edit: made this ugly animation for further clarification.

Related

How do I rotate an object's parent without the child being moved along?

In my game on unity 2d I have spaceship and a planet. The planet is orbiting a star so I made a script that parents the planet to the player when I get within a range so the planet doesn't fly past or into the player. This script makes the player move with the planet so they land on it and fly around it easily.
Here is the script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParentPlayer : MonoBehaviour
{
[SerializeField] GameObject Player;
private float Dist;
[SerializeField] float Threshold;
private CircleCollider2D ParentTrigger;
// Start is called before the first frame update
void Start()
{
ParentTrigger = GetComponents<CircleCollider2D>()[1];
ParentTrigger.isTrigger = true;
ParentTrigger.radius = Threshold / transform.localScale.x;
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject == Player)
{
collider.gameObject.transform.SetParent(transform);
}
}
private void OnTriggerExit2D(Collider2D collider)
{
if(collider.gameObject == Player)
{
collider.gameObject.transform.SetParent(null);
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, Threshold);
}
}
The problem is that as the planet rotates it ends up moving the player that has been parented to it. How can I make the planet's rotation not affect the position and rotation of the player, but still make the planets position affect the position of the player?
This might not be what you're looking for but I'm going to add it reguardless. Given that the Child-object will follow the parent, I would suggest putting the planet and spaceship as a child of the empty gameobject. Then you could rotate the the planet object, and if planets are in movement, you could add the movement to the parent object.
How about instead of parenting the player, write a script to set its position to the planets + some offset, and then the rotation wouldn't be an issue. Alternatively, if the player doesn't rotate at all, add constraints to its Rigidbody. Maybe something like this:
player.transform.position = planet.transform.position + offset;
Hope that works!

Object won fall of the platform in Unity

So i made an ball(player) which moves forward on it's own with script. I want to make that ball act like a normal ball. when it riches the edge of platform it won't fall off. Basicaly it stops on the edge. Here's my image:
Here's my controller script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwerveInputSystem : MonoBehaviour
{
private float _lastFrameFingerPositionX;
private float _moveFactorX;
public float MoveFactorX => _moveFactorX;
void Start(){
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButton(0))
{
_moveFactorX = Input.mousePosition.x - _lastFrameFingerPositionX;
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButtonUp(0))
{
_moveFactorX = 0f;
}
}
}
This is Second script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour{
private SwerveInputSystem _swerveInputSystem;
[SerializeField] private float swerveSpeed = 5f;
[SerializeField] private float maxSwerveAmount = 1f;
[SerializeField] private float verticalSpeed;
void Start(){
_swerveInputSystem = GetComponent<SwerveInputSystem>();
}
void Update(){
float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
float verticalDelta = verticalSpeed * Time.deltaTime;
transform.Translate(swerveAmount, verticalDelta, 0.1f);
}
}
EDITED: Adjusted the answer since we now have some source code.
You are positioning the player directly (using its transform) which will mess up the physics. The purpose of a rigidbody is to let Unity calculate forces, gravity, and so on for you. When you are using physics, and you want to move an object you have three main options:
Teleporting the object to a new position, ignoring colliders and forces like gravity. In this case use the rigidbody's position property.
_ourRigidbody.position = new Vector3(x, y, z);
Moving the object to the new position, similar to teleporting but the movement can be interrupted by other colliders. So, if there is a wall between the object and the new position, the movement will be halted at the wall. Use MovePosition().
_ourRigidbody.MovePosition(new Vector3(x, y, z));
Adding some force to the object and letting the physics engine calculate how the object is moved. There are several options like AddForce() and AddExplostionForce(), etc... see the Rigidbody component for more information.
_ourRigidbody.AddRelativeForce(new Vector3(x, y, z));
In your case you can simply remove the transsform.Translate() calls and instead add some force like this:
//transform.Translate(swerveAmount, 0, 0);
//transform.Translate(swerveAmount, verticalDelta, 0.1f);
Vector3 force = new Vector3(swerveAmount, verticalDelta, 0);
_ourRigidbody.AddForce(force);
We can get the _ourRigidbody variable in the Awake() or Start() method as normal. As you can see I like the Assert checks just to be safe, one day someone will remove the rigidbody by mistake, and then it is good to know about it...
private SwerveInputSystem _swerveInputSystem;
private Rigidbody _ourRigidbody;
void Start()
{
_swerveInputSystem = GetComponent<SwerveInputSystem>();
Assert.IsNotNull(_swerveInputSystem);
_ourRigidbody = GetComponent<Rigidbody>();
Assert.IsNotNull(_ourRigidbody);
}
One likely reason your Rigidbody is not being affected by gravity is due to having the field isKinematic checked to on. From the Rigidbody docs, when toggling on isKinematic,
Forces, collisions or joints will not affect the rigidbody anymore.
The rigidbody will be under full control of animation or script
control by changing transform.position
As gravity is a force and no forces act on the object when this setting is checked, your object will not fall when it is no longer on the platform. A simple solution is to uncheck this box.

LookAt is centering at feet of player

When I use LookAt the camera seems to look at the targets feet. I would like the target to be closer to the bottom of the screen. (e.g. look at the head instead).
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThirdPersonCamera : MonoBehaviour
{
private GameObject player;
private void Start()
{
player = GameObject.FindWithTag("Player");
}
private void LateUpdate()
{
Vector3 offset = new Vector3(0,2.0f,-4.0f);
transform.position = player.transform.position + offset;
transform.LookAt(player.transform.position);
}
}
How can I make it so the camera stop centering at the feet?
I created an empty game object as a child of the player, and then adjusted the position of that. Then in my script I set it to look at that empty object instead of the player. This gives me full control of what position the camera looks at on the player.

Smooth Walking Inside a Sphere

I'm moving a player around the inside of a hollow sphere equipped with a non-convex mesh-collider. The player is meant to walk along the inner surface of the sphere with a gravitational pull towards the ship hull (away from the center). For the gravity, I've attached a modified version of this script to the player:
using UnityEngine;
using System.Collections;
public class Gravity : MonoBehaviour
{
//credit some: podperson
public Transform planet;
public bool AlignToPlanet;
public float gravityConstant = -9.8f;
void Start()
{
}
void FixedUpdate()
{
Vector3 toCenter = planet.position - transform.position;
toCenter.Normalize();
GetComponent<Rigidbody>().AddForce(toCenter * gravityConstant, ForceMode.Acceleration);
if (AlignToPlanet)
{
Quaternion q = Quaternion.FromToRotation(-transform.up, -toCenter);
q = q * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
}
}
}
Unity's default movement controllers don't seem to work with this Gravity script, so I fashioned a simple one (forward/backward movement only):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class NewController : MonoBehaviour {
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
private void FixedUpdate()
{
GetComponent<Rigidbody>().AddForce(transform.forward * CrossPlatformInputManager.GetAxis("Vertical"), ForceMode.Impulse);
}
}
It works in that I'm able to walk around the inside of the sphere. It's very bumpy though, presumably because the forward force causes the player to constantly run into the corners/edges of the sphere polygon, and because these incongruities are not corrected quickly enough by the "AlignToPlanet" Quaternion in the gravity script.
To sum up, I need a way to move smoothly along the inside of the sphere. I'm not sure if this needs to be solved with code or values in the Unity Editor (regard drag, etc.).

Unity camera following rolling ball. No rotation and no moving in Z-axis on camera

So, i'm building a 3D runner and i've got a lot of problems making the camera following the ball. I've been on google for a few hours and can't find anything that's not outdated or fills in the things I need. I want a camera that follows my ball but goes straight in the X-axis. When there are the stairs the camera needs to follow on Y axis.
I just don't want my camera to rotate (since my object is a rolling ball) and to move in the Z-axis.
var myPos : Vector3;
var myPlay : Transform;
function Update()
{
transform.position = myPlay.position + myPos;
}
This is what I already have. It doesn't rotate, but it follows on the Z-axis. I don't want that.
http://prntscr.com/9pmypz This is what it looks like in the Inspector.
As per Unity3D's Roll-A-Ball tutorial:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}
I can't comment #HDL_CinC_Dragon answer because of my low reputation, but I wanted to add that using the public access modifier is a really bad habit. Instead you should use the private access modifier with the SerializeField attribute on the field, like this:
public class CameraController : MonoBehaviour
{
[SerializeField]
private GameObject player;
private Vector3 offset;