Rotating a child gameobject relative to immediate parent - unity3d

Hi everybody, I'm trying to rotate a child game object relative to another child game object. For example, as shown in this heirarchy below, I'm trying to rotate PA_DroneBladeLeft (and PA_DroneBladeRight) with respect to their immediate parents PA_DroneWingLeft (and PA_DroneWingRight) respectively. I want these blades to spin in place. Instead I'm getting them to spin globally in the y-direction relative to the main parent (Air Drone). I would think that the line in Update method that I commented out should have worked, and it did but it still rotated relative to Air Drone and not in place. The second line, RotateAround method I've tried to create an empty game object called Left Pivot and put it approximately in the center of the left wing and have the left blade rotate around that, but it was no use.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LeftBladeRotation : MonoBehaviour
{
GameObject leftBlade;
private float speed;
private float angle;
GameObject leftPivot;
// Start is called before the first frame update
void Start()
{
speed = 10f;
leftBlade = transform.Find("PA_DroneBladeLeft").gameObject;
angle = 0f;
leftPivot = GameObject.FindGameObjectWithTag("Air Drone").transform.Find("PA_Drone").transform.Find("PA_DroneWingLeft").transform.Find("Left Pivot").gameObject;
}
// Update is called once per frame
void Update()
{
angle += speed * Time.deltaTime;
Quaternion rotation = Quaternion.Euler(new Vector3(0f, angle, 0f));
//leftBlade.transform.localRotation = rotation;
leftBlade.transform.RotateAround(leftPivot.transform.localPosition, Vector3.up, angle);
}
}

This is your script with some little changes. It actually works when I attached it on the blade gameObject.
using UnityEngine;
public class BladeRotate : MonoBehaviour
{
private float _speed;
private float _angle;
private void Start()
{
_speed = 400f;
_angle = 0f;
}
private void Update()
{
_angle += _speed * Time.deltaTime;
var rotation = Quaternion.Euler(new Vector3(0f, _angle, 0f));
transform.localRotation = rotation;
}
}
The second line does not work because you rotate the blade around global y-axis by Vector3.up
Here is an alternative. Attach the following script on your blades.
using UnityEngine;
public class BladeRotate : MonoBehaviour
{
[SerializeField] private int speed = 400;
private Transform _transform;
private void Start()
{
_transform = transform;
}
private void Update()
{
transform.RotateAround(_transform.position, _transform.up, speed * Time.deltaTime);
}
}

Related

How do I make this piece of c# go vertical instead of horizontal?

I have been trying to make an infinitely repeating background. Found this piece below but it goes horizontally instead of vertically. I tried rotating my sprites but it didn't work, also changed the x values with y and the loop stopped happening.
I'm stuck trying to figure out a solution.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RepeatBg : MonoBehaviour
{
private BoxCollider2D boxCollider;
private Rigidbody2D rb;
private float width;
private float speed = -3f;
// Start is called before the first frame update
void Start()
{
boxCollider = GetComponent<BoxCollider2D>();
rb = GetComponent<Rigidbody2D>();
width = boxCollider.size.x;
rb.velocity = new Vector2(speed,0);
}
// Update is called once per frame
void Update()
{
if (transform.position.x<-width)
{
Reposition();
}
}
private void Reposition()
{
Vector2 vector = new Vector2(width * 2f, 0);
transform.position = (Vector2)transform.position + vector;
}
}
You need to change all "vertical stuff" to horizontal.
Add a member variable
private float height;
In method Start set
height = boxCollider.size.y;
rb.velocity = new Vector2(0, speed);
In method Update change the condition to
if (transform.position.y < -height)
In method Reposition set
Vector2 vector = new Vector2(0, height * 2f);

How to control player camera on angled surface/independent of xyz axis in Unity?

An illustration of my issue/what I'm trying to achieve
I managed to have my player move around the inside surface of a cylinder using gravity but an issue comes up when trying to rotate the camera to look around.
First, there's a script that simulates gravity by pushing the player against the inside walls of the cylinder. This script also keeps the player upright by changing the "up" direction of the player to always be facing the center of the cylinder. I know this keeps my player from looking up so for now I'm just working on getting them to look left and right.
Second, when the player is on the bottom of the cylinder and parallel with the Y-axis I can look left and right without issue because the camera rotates using the x-axis (see circle on the left side of the image). However when the player moves around the side of the cylinder the camera is still trying to rotate based on the X-axis even though they are not aligned resulting in the camera not accurately rotating (see the circle on the right side of the image), and by the time the player is 90deg around the cylinder cannot rotate at all (thanks I think to the gravity keeping the player perpendicular to the sides of the cylinder), and at 180deg around the rotation is inverted.
I assume there are two possible solutions that I have not been able to successfully implement:
ignore the world xyz axis' and rotate relative to the player's xyz.
do some math to figure out the proper angles when you take into account the player's rotation around the cylinder and the angle of the current "left" direction.
The problem with the first solution is I have not been able to successfully rotate the player independent of the world xyz. I tried adding the Space.Self to the Rotate() method but no success. The problem with the second is math scares me and I've managed to avoid Quaternions & Euler angles so far so I'm not even sure how to begin figuring that out.
If anyone has had a similar issue I would greatly appreciate any insight or suggestions on how to figure it out.
Here's my code for controlling the play movement/camera direction and my code for the gravity:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
InputManager inputActions;
InputManager.PlayerMovementActions playerMovement;
public GravityAttractor GravityAttractor;
public float moveSpeed = 15;
public float jumpHeight = 10f;
public float sensitivityX = 1f;
public float sensitivityY = 1f;
float mouseX, mouseY;
Vector2 mouseInput;
private bool isJumping = false;
private Vector3 moveDir;
private Vector2 moveInput;
private Rigidbody rbody;
private void Awake()
{
inputActions = new InputManager();
playerMovement = inputActions.PlayerMovement;
playerMovement.Movement.performed += context => moveInput = context.ReadValue<Vector2>();
playerMovement.Jump.performed += ctx => Jump();
//playerMovement.MouseX.performed += context => mouseInput = context.ReadValue<Vector2>();
playerMovement.MouseX.performed += context => mouseInput.x = context.ReadValue<float>();
playerMovement.MouseY.performed += context => mouseInput.y = context.ReadValue<float>();
rbody = GetComponent<Rigidbody>();
isJumping = false;
}
private void Update()
{
moveDir = new Vector3(moveInput.x, 0, moveInput.y).normalized;
if (rbody.velocity.y == 0)
isJumping = false;
}
private void FixedUpdate()
{
rbody.MovePosition(rbody.position + transform.TransformDirection(moveDir) * moveSpeed * Time.deltaTime);
MouseLook(mouseInput);
}
void Jump()
{
//use brackeys method of checking for contact with ground
if(isJumping == false && rbody.velocity.y == 0)
{
isJumping = true;
rbody.velocity = transform.up * jumpHeight;
Debug.Log("player jumped");
}
}
void MouseLook(Vector2 mouseInput)
{
mouseX = mouseInput.x * sensitivityX;
mouseY = mouseInput.y * sensitivityY;
var upTransform = GravityAttractor.transform.position - transform.position;
Vector3 relativeLook = upTransform - transform.forward;
Vector3 qLook = transform.forward - transform.position;
transform.Rotate(transform.up * mouseX * Time.deltaTime, Space.Self);
//transform.Rotate(relativeLook.normalized);
//transform.rotation = Quaternion.LookRotation(qLook);
//transform.Rotate(relativeLook.normalized, mouseX);
}
private void OnEnable()
{
inputActions.Enable();
}
private void OnDisable()
{
inputActions.Enable();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GravityAttractor : MonoBehaviour
{
public float gravityMultiplier = -10f;
private float radius;
public float gravity;
public float distance;
private void Awake()
{
radius = transform.localScale.x/2;
}
public void Attract(Transform body)
{
Vector3 centerOfGravity = new Vector3(transform.position.x, transform.position.y, body.position.z);
distance = Vector3.Distance(centerOfGravity, body.position);
//gravity will match multiplier no matter the radius of cylinder
gravity = gravityMultiplier * (distance/radius);
Vector3 gravityUp = (centerOfGravity - body.position).normalized;
Vector3 bodyUp = body.up;
body.GetComponent<Rigidbody>().AddForce(gravityUp * gravity);
Quaternion targetRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * body.rotation;
body.rotation = Quaternion.Slerp(body.rotation, targetRotation, 50 * Time.deltaTime);
}
}
Problem is that you are trying to Rotate in local space around transform.up, which is in world space.
try to use just Vector3.up, instead of transform.up.
Or you can transform any vector from world to local space with transform.InverseTransformDirection()
transform.Rotate(Vector3.up * mouseX * Time.deltaTime, Space.Self);
I don't know hierarchy of your GameObjects. In order for this to work, you shuld rotate Player GameObject to face up to center of cilinder. And camera should be child of Player GameObject

Unity 3D jump and movement conflict

I wanted to make an endless runner game where the player can jump and he moves forward automatically, so, for the forward movement i wanted to use the rigidbody velocity function in order to make the movement smoother and for the jump i made a custom function. My problem is, when i use in my update method the velocity function alone, it works, when i use it with my jump function it stops working. What can i do?. I tried changing the material of the floor and of the player's box collider to a really slippery one but nothing
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePrima : MonoBehaviour
{
[SerializeField]
private float _moveSpeed = 0f;
[SerializeField]
private float _gravity = 9.81f;
[SerializeField]
private float _jumpspeed = 3.5f;
public float speedAccel = 0.01f;
private CharacterController _controller;
private float _directionY;
public float startSpeed;
public float Yspeed = 10f;
private int i = 0;
public float touchSensibility = 50f;
public int accelTime = 600;
[SerializeField]
Rigidbody rb;
// Start is called before the first frame update
void Start()
{
startSpeed = _moveSpeed;
_controller = GetComponent<CharacterController>();
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
rb.velocity = new Vector3(0f, 0f, 1f) * _moveSpeed;
touchControls();
}
public void touchControls()
{
if (SwipeManager.swipeUp && _controller.isGrounded)
{
_directionY = _jumpspeed;
print("Entrato");
}
_directionY -= _gravity * Time.fixedDeltaTime;
_controller.Move((new Vector3(0, _directionY, 0)) * Time.fixedDeltaTime * Yspeed);
i += 1;
if (i % accelTime == 0)
{
_moveSpeed += startSpeed * speedAccel;
i = 0;
}
}
private void OnControllerColliderHit(ControllerColliderHit hit) //Checks if it collided with obstacles
{
if(hit.transform.tag == "Obstacle")
{
GameOverManager.gameOver = true;
}
}
}
You should either use the CharacterController or the Rigidbody. With the CharacterController you tell Unity where to place the character and you have to check yourself if it is a valid position. With the Rigidbody you push it in the directions you want, but the physics around the character is also interfering.
You can use Rigidbody.AddForce to y when jumping instead of _controller.Move.

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.

Unity, Stop Moving Player when he hits obstacle or bounds [duplicate]

I just started learning Unity. I tried to make a simple box move by using this script. The premise is, whenever someone presses 'w' the box moves forward.
public class PlayerMover : MonoBehaviour {
public float speed;
private Rigidbody rb;
public void Start () {
rb = GetComponent<Rigidbody>();
}
public void Update () {
bool w = Input.GetButton("w");
if (w) {
Vector3 move = new Vector3(0, 0, 1) * speed;
rb.MovePosition(move);
Debug.Log("Moved using w key");
}
}
}
Whenever I use this, the box doesn't move forward on a 'w' keypress. What is wrong with my code? I thought it might be the way I have my Vector 3 move set up so I tried replacing the z-axis with speed, but that didn't work. Could someone tell me where I am messing up?
You move Rigidbody with Rigidbody.MovePosition and rotate it with Rigidbody.MoveRotation if you want it to properly collide with Objects around it. Rigidbody should not be moved by their position, rotation or the Translate variables/function.
The "w" is not predefined like SherinBinu mentioned but that's not the only problem. If you define it and use KeyCode.W it still won't work. The object will move once and stop.
Change
Vector3 move = new Vector3(0, 0, 1) * speed;
rb.MovePosition(move);
to
tempVect = tempVect.normalized * speed * Time.deltaTime;
rb.MovePosition(transform.position + tempVect);
This should do it:
public float speed;
private Rigidbody rb;
public void Start()
{
rb = GetComponent<Rigidbody>();
}
public void Update()
{
bool w = Input.GetKey(KeyCode.W);
if (w)
{
Vector3 tempVect = new Vector3(0, 0, 1);
tempVect = tempVect.normalized * speed * Time.deltaTime;
rb.MovePosition(transform.position + tempVect);
}
}
Finally, I think you want to move your object with wasd key. If that's the case then use Input.GetAxisRaw or Input.GetAxis.
public void Update()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
Vector3 tempVect = new Vector3(h, 0, v);
tempVect = tempVect.normalized * speed * Time.deltaTime;
rb.MovePosition(transform.position + tempVect);
}
"w" is not predefined unless you explicitly define it. Use KeyCode.W
Try this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMover : MonoBehaviour {
public float speed;
private Rigidbody rb;
void Start () {
rb = GetComponent<Rigidbody>();
}
void Update () {
bool w = Input.GetKey(KeyCode.W);
if (w) {
Vector3 move = new Vector3(0, 0, 1) * speed *Time.deltaTime;
rb.MovePosition(move);
Debug.Log("Moved using w key");
}
}
}
Use Input.GetKey(KeyCode.W) for getting input.
EDIT NOTE:
To move the object relative to its initial position use rb.MovePosition(transform.position+move) rather than rb.MovePosition(move)
Instead of making w a bool, you can use axis, also, in unity editor you should make it so the rigidbody movement is frozen
here is some code
void update()
{
rb.AddForce(Input.GetAxis("Horizontal"));
}
bool w = Input.GetKeyDown(KeyCode.W);