Unity Vector3 Slerp on wanted axis - unity3d

Hi I'm making a little 3D platformer with a player controller like zelda/mario64.
I want to add the possibility to reset the camera behind the player. It ok, not really hard, but I wanted to do this smoothly and with the camera rotating around the player.
I discovered the Slerp method of Vector3 that almost do what I want. But I don't know if it's possible to force the Slerp method to make a trajectory only on the x,z plan. I dont want the camera to go above the player but turn arround it.
Someone know of it's possible to Vector3.Slerp() only on some axis ?
Or maybe Vector3.Slerp() is not the solution, so what can I do ?

My guess is your looking for Transform.localEulerAngles (you can find out more about it here). What I would do in your situation is keep the axis you don't want to move and use Slerp on this other(s) :
Vector3 currentLocalEulerAngles = transform.localEulerAngles;
Vector3 targetLocalEulerAngles = /*What you want*/ Vector3.zero;
float slerpSpeed;
transform.localEulerAngles = Vector3.Slerp(transform.localEulerAngles, new Vector3(currentLocalEulerAngles.x, targetLocalEulerAngles.y, targetLocalEulerAngles.z), slerpSpeed * Time.deltaTime);
EDIT : To be clear I suggested this way of doing things having in mind that in those kind of situations, the Camera is often placed as a child of a GameObject located on the player. This way you simply have to rotate what can be called the CameraHolder : Player (doing what you want) > CameraHolder (rotating along local axis) > Camera (fixed or getting shaked or what you want) :)
EDIT2 : Here's a small script that will do what you're looking for (hopefully) : you simply have to set your Camera as child of your Player, place it so it "looks" at your Player with desired distance/angle, and finally add this CameraHolder script to your Camera.
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class CameraHolder : MonoBehaviour
{
[Range(0.0f, 10.0f)]
[SerializeField]
private float m_CameraResetSpeed = 4.0f;
[Range(0.0f, 10.0f)]
[SerializeField]
private float m_MinAngleToStopReseting = 2.0f;
private Transform m_CameraHolderTransform;
private Vector3 m_CameraHolderWorldEulerAngles;
private bool m_ResetingCamera;
void Start()
{
GameObject cameraHolder = new GameObject("CameraHolder");
m_CameraHolderTransform = cameraHolder.transform;
m_CameraHolderTransform.SetParent(transform.parent);
m_CameraHolderTransform.localPosition = Vector3.zero;
m_CameraHolderTransform.localRotation = Quaternion.identity;
m_CameraHolderTransform.localScale = Vector3.one;
transform.SetParent(cameraHolder.transform);
m_CameraHolderWorldEulerAngles = m_CameraHolderTransform.eulerAngles;
m_ResetingCamera = false;
}
void LateUpdate()
{
if(m_ResetingCamera)
{
m_CameraHolderTransform.localEulerAngles = new Vector3(0.0f,
Mathf.LerpAngle(m_CameraHolderTransform.localEulerAngles.y, 0.0f, m_CameraResetSpeed * Time.deltaTime), 0.0f);
if(Mathf.Abs(m_CameraHolderTransform.localEulerAngles.y) < m_MinAngleToStopReseting)
{
Debug.Log("Reset done...");
m_ResetingCamera = false;
m_CameraHolderWorldEulerAngles = m_CameraHolderTransform.eulerAngles;
}
}
else
{
m_CameraHolderTransform.eulerAngles = m_CameraHolderWorldEulerAngles;
}
}
public void ResetCamera()
{
Debug.Log("Reseting camera...");
m_ResetingCamera = true;
}
}

Related

In Unity3d how can I move a gameobject with mouse while interacting with physics engine?

I would like to develop a 3d game. An "air hockey" simulator. I would like to control the paddle with the mouse but at the same time, I would like to use the physics engine to handle collisions with the puck and the borders of the table.
I tried the following:
If I use a Kinematic paddle I lose the property to handle the physics by the engine.
If I use static object the same.
If I use a dynamic rigidbody I am not able to control smoothly the paddle.
What is the best way to handle this scenario?
Thank you.
What makes a air-puck feel good is the sliding effect it has. Ofcourse it doesn't continue forever, but still feels nice.
Here is what you can do:
Create an Paddle & Puck
Create two physics materials for both.
Decrease the friction on the material that both feels slidey, the puck a little more than the paddle.
For both:
Freeze the x & z rotation
Freeze the y position
Now the part that makes the paddle use physics & RigidBody correctly. Create a new script for moving the paddle:
public class PaddleMovement : MonoBehaviour
{
private RigidBody rb;
public float speed = 5;
public float minDist = 0;
public float maxDist = 5;
public LayerMask layers;
void Start()
{
rb = GetComponent<RigidBody>();
}
void Update()
{
// Paddle will only move if we hold down the mouse button
paddleGrabed = Input.GetInput(KeyCode.Mouse0);
}
void FixedUpdate()
{
if (paddleGrabed)
{
HandleMovement();
}
}
void HandleMovement()
{
Ray ray = Camera.main.ScreenToWorldPoint(Input.MousePosition);
RaycstHit hit;
if (Physics.Raycast(ray, out hit, 100f, layers))
{
// Calculate the slow effect as paddle comes close to the point;
float dist = Vector3.Distance
(
new Vector3(transform.position.x, 0 transform.position.z),
new Vector3(hit.point.x, 0, hit.point.z)
);
dist = Mathf.Clamp(dist, minDist, maxDist);
var slowEffect = dist / maxDist;
// Now move move the rigid body appropriately
var dir = new Vector3(hit.point.x, 0, hit.point.z) -new Vector3(transform.position.x, 0 transform.position.z);
dir.Normalize();
rb.MovePosition(transform.position + dir * slowEffect * speed * Time.deltaTime);
}
}
}
That should move the Paddle to a certain position with a bit of a lag and sliding effect.

Sibling sprite doesn't appear to follow main GameObject sprite even when transform.position updates

Following this question How to align sprites of smaller sizes to a moving gameobject sprite?, I'm trying to redraw my sprites to avoid rendering transparent pixels and try to maximize performance, and as I try starting this process with the sword sprites, I need to change the way the Sword game object follows the Player, which before was handled simply by using transform.position = hero.transform.position; because since both objects use sprites that are perfect squares they would have the same pivot point despite their size difference.
At first, it seemed to me the problem lied in how the pivots are different, thus I would need to update the transform position of the Sword every time its attack animation changes sprites. For that, I made a function which updates variables that influence the position as that gets updated:
here, heroTransform is a variable which gets sent the Player's transform property on the script's Start function as heroTransform = hero.transform;, where hero is defined right above it as hero = GameObject.Find("Hero");.
I would have expected this to make the Sword which is equipped with this script, called WieldablePosition to follow the player position, but it seems stuck in the same position as it starts:
I'm not sure, but I don't think I changed anything that would stop the Sword from moving. In what cases could a GameObject remain in a single place even as the transform.position is modified? For reference, please view the script:
using UnityEngine;
public class WieldablePosition : MonoBehaviour {
GameObject hero;
HeroMovement heroMovementScript;
private Transform heroTransform;
protected Animator anim;
private bool isAirAttackSingle;
private bool isFacingLeft;
private float x = 0;
private float y = 0;
void Start() {
hero = GameObject.Find("Hero");
heroTransform = hero.transform;
heroMovementScript = hero.GetComponent<HeroMovement>();
anim = GetComponent<Animator>();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
}
void Update() {
UpdatePosition();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
anim.SetBool("isAirAttackSingle", isAirAttackSingle);
if (isFacingLeft) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
public void SetPosition(AnimationEvent eventParams) {
string[] eventPositions = eventParams.stringParameter.Split(',');
x = float.Parse(eventPositions[0]);
y = float.Parse(eventPositions[1]);
}
private void UpdatePosition() {
transform.position = new Vector2(heroTransform.position.x + x, heroTransform.position.y + y);
}
}

How to move 2d Rigidbody Smoothly to Mouse on Click

Vector2 mousePos = Input.mousePosition;
// motion core
if (GameObject.Find("Camera").GetComponent<room>().playerNum == 1)
{
if (Input.GetMouseButtonDown(0))
{
// move script not working
}
}
So, I have mostly every possible solution I could find but none of them worked. I cannot get it to smoothly move with AddForce because I could not figure out a working algorithm to make the force move toward the MousePosition.
The position you're getting out of Input.mousePosition are the coordinates on the screen, not the position in the world. To transform between the two, you can use Camera.ScreenToWorldPoint().
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition
mousePos = new Vector3(mousePos.x, mousePos.y, Camera.main.nearClipPlane)
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3())
// move script
}
You might need to edit the z coordinate in the mousePos to the current transform.position.z of the object you're trying to move, or another value that makes most sense here. It acts as a kind of wall, where it'll create the point exactly that far from the camera on your mouse position. This should be a lot cheaper than raycasting, and still works if there's nothing to hit where you're clicking.
I have a script that did this same movement to the handle of a wrecking ball, but I don't have the code with me at the moment. I can't remember exactly how it worked, but I think the idea was that when the mouse was clicked, drag would be set to a very high number and gravity would be set to 0. Then an extremely strong force would be added to counter the drag so that the object would fly towards the mouse without orbiting. When the mouse was released, the drag and gravity would be set back to normal.
I can't test this at the moment because I'm on a chromebook and my PC with Unity on it is in another building, but this code should do the trick if I don't make any errors.
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
float prevDrag, prevGrav;
bool mousedown;
Plane plane;
Rigidbody2D r;
void Start()
{
r = GetComponent<Rigidbody2D>(); // assuming this script is attached to the object being moved.
plane = new Plane(Vector3.up, Vector3.zero);
}
void Update()
{
if(mousedown)
{
float enter;
if (plane.Raycast(ray, out enter))
{
var hitPoint = ray.GetPoint(enter);
var mouseDir = hitPoint - gameObject.transform.position;
rb.AddForce(mouseDir * 9999999);
}
}
}
void OnMouseDown()
{
mousedown = true;
prevDrag = r.drag;
prevGrav = r.gravity;
r.drag = 99999;
r.gravity = 0;
}
void OnMouseUp()
{
mousedown = false;
r.drag = prevDrag;
r.gravity = prevGrav;
}
}

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.

AddRelativeForce doesnt add Relative force

First of all. I am pretty much a blank beginner and was trying to make a little game in unity.
It's a stick that gets addforced up and rotated at the same time.
Now the problem is that when I add the transform.up force, it is bound to the objects z rotate and not the global
Is there any way around that?
using UnityEngine;
public class LaunchCAR : MonoBehaviour
{
public Rigidbody2D rb2D;
public float thrust = 10.0f;
public float torque = 1f;
private void Start()
{
transform.position = new Vector3(0.0f, -2.0f, 0.0f);
}
void FixedUpdate()
{
if (Input.GetMouseButtonDown(0))
{
rb2D.AddRelativeForce(-(transform.up) * thrust, ForceMode2D.Impulse);
// float turn = Input.GetAxis("Horizontal");
rb2D.AddTorque(torque, ForceMode2D.Impulse);
}
}
}
AddRelativeForce expects object-space (local) coordinates, but you're passing transform.up which is in world-space coordinates.
Use either Vector3.up or AddForce instead.