How to rotate an object's child, when I flip the object? - c#

I am trying to make a game on unity3d, everything is going great so far and the game works perfectly. But I have one problem. I have add some kind of jetpack on my player, and when the player flips, the jetpack rotation flips as well. As you can see on the images bellow:
Normal jetpack
Upside-down jetpack
So what I need to do is to multiply the x axes of rotation of the jetpack. But I can't figure out on how to access and change the value from my code.

Look at the Quaternion documentation here for the available methods.
var rotation = jetpackGameObject.transform.rotation;
// edit the rotation here
jetpackGameObject.transform.rotation = rotation;

Ok I finally solved my problem:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EngineController : MonoBehaviour
{
private bool facingRight;
private float moveHorizontal;
void Start()
{
facingRight = true;
}
void Update()
{
moveHorizontal = Input.GetAxis ("Horizontal");
Vector3 rot;
if (GetFacing () == -1f) {
rot = new Vector3 (-90, 0, 0);
}
else
{
rot = new Vector3 (90, 0, 0);
}
transform.rotation = Quaternion.Euler(rot);
}
public float GetFacing()
{
if (facingRight) {
return 1;
}
else
{
return -1;
}
}
}

Related

How to create a camera that combines both forced movement and smooth player following

Context
So I'm making a clone of Crossy Roads where the camera follows the player. It does some linear interpolation (Lerp) after moving, and the camera starts moving away from the player in the positive direction (x-axis until camera reaches to a certain range where player is not visible enough). Things I have tried is by flagging it, but I think I'm doing it wrong.
Problem
I have done my camera movements accordingly, but I am having an issue where the conditions are not properly met. I'm get the offset camera after not moving, but it does not the Lerp, and vice-versa. I want both to happen after a certain condition after the game starts. When the player moves, the camera follows it in Lerp. However, once the player is "Idle", its still Lerping. I want the camera to continue by itself and at the same time focus at the player's object.
Example
Camera with Lerp, but not moving away from the player
Camera moving away, but not following player with lerp
Code
CameraController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
** Camera following player (Smoothing and angle): https://youtu.be/4HpC--2iowE
** Maximo: https://www.youtube.com/watch?v=bXNFxQpp2qk&ab_channel=iHeartGameDev
** Moving character relative to camera: https://forum.unity.com/threads/moving-character-relative-to-camera.383086/
** Camera follow v2: https://youtu.be/Jpqt2gRHXtc?list=PLq_nO-RwB516fNlRBce0GbtJSfysAjOgU
*/
public class CameraController : MonoBehaviour
{
public GameObject player;
public PlayerControl playerControlScript;
private Vector3 newCameraPos;
public bool stillIdle;
void Start()
{
stillIdle = false;
PlayerControl playerControlScript = GetComponent<PlayerControl>();
}
void LateUpdate()
{
player = GameObject.FindGameObjectWithTag("Player");
if (playerControlScript.GetfirstInput()) //True
{
stillIdle = true;
newCameraPos = Vector3.Lerp(transform.position, playerControlScript.transform.position, Time.deltaTime);
transform.position = new Vector3(newCameraPos.x, 1, newCameraPos.z);
}
if (stillIdle)
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z); //Moving camera away effect
}
}
PlayerControl.cs
public class PlayerControl : MonoBehaviour
{
bool firstInput;
Vector3 startPos;
Vector3 endPos;
public bool GetfirstInput() //I was learning how to have a Get function while my member was private from another script file
{
return firstInput;
}
void Update()
{
if (Input.GetButtonDown("up") || Input.GetButtonDown("left") || Input.GetButtonDown("right") || Input.GetButtonDown("down"))
{
//if game starts
{
//Other variables being initialized here
firstInput = true;
}
}
}
}
Hierarchy/Inspector
Main Camera
Player Object
Some help would be appreciate it. I feel I have been staring at this problem and I bet it is something minimal and small from just thinking it.
Let me know if you need clarifications. I'm happy to edit and answer them for everyone
If player in your game does not change, you don't have to find the player reference in each LateUpdate().
I notice that once stillIdle is set true, it never goes back to false, is this your intention to do that?
You call Lerp when playerControlScript.GetfirstInput() is true, so maybe we need to look at its implementation. Maybe it turns true in some conditions you do not intend it to.
Maybe Try this
public class PlayerControl : MonoBehaviour
{
private bool _hasFireFirstInput = false;
private bool _isIdle = true;
public bool IsIdle => _isIdle;
public bool HasFireFirstInput => _hasFireFirstInput;
private void Update()
{
if (Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
_hasFireFirstInput = true;
_isIdle = false;
Vector3 pos = transform.position;
pos = new Vector3(pos.x, pos.y, pos.z + .2f * Time.deltaTime);
transform.position = pos;
}
else
{
_isIdle = true;
}
}
}
I use Input.GetButton() rather than Input.GetButtonDown(), since the later only return true at the frame the button is pressed, meaning that if i long-press the button, it will return false after the next frame.
public class CameraController : MonoBehaviour
{
[SerializeField] PlayerControl _playerControlScript;
[SerializeField] Vector3 _offset;
[SerializeField] float _lerpSpeed;
bool _iskeepLerping = false;
float _lerpVal = 0f;
private void LateUpdate()
{
if (!_playerControlScript.HasFireFirstInput)
{
return;
}
if (_playerControlScript.IsIdle)
{
MoveAway();
}
else
{
Lerp();
}
}
private void MoveAway()
{
_iskeepLerping = false;
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z);
}
private void Lerp()
{
if (!_iskeepLerping)
{
_lerpVal = 0f;
}
Vector3 newCameraPos = Vector3.Lerp(transform.position, _playerControlScript.transform.position + _offset, _lerpVal);
transform.position = newCameraPos;
_lerpVal += _lerpSpeed * Time.deltaTime;
_iskeepLerping = true;
}
}

FPS Projectile firing from the wrong place

I'm trying to make a basic FPS game in Unity and I'm having an issue where the projectiles I shoot won't instantiate in the right place. From what I can tell, the projectile instantiates in roughly the same position relative to the player regardless of where I look (that position being a little to the left of the starting angle of the player).
Here's a 20 second video demonstration of what I'm talking about.
https://youtu.be/WLVuqUtMqd0
Even when I'm facing the exact opposite direction of where the projectile usually instantiates it still spawns in the same place, which means the projectile ends up spawning behind the player and hitting the player.
I tried using Debug.DrawRay() to see if maybe the firepoint itself is wrong (which would be shown by the ray starting somewhere other than the gun barrel). However it seems like the starting point of the ray is correct every time.
I'm not sure if this is related to the issue above, but I have noticed that the ray direction is wrong if I'm looking a little below the horizon. It seems like the projectile's direction is correct regardless though.
Ray directions when looking slightly above the horizon vs. lower
Here's my code for intantiating/shooting the projectile. I think the most relevant parts are probably shootProjectile() and instantiateProjectile(). This script is attached to the player character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
public Camera cam;
public GameObject projectile;
public Transform firePoint;//firePoint is set to the end of the barrel.
public float projectileSpeed = 40;
//private var ray;
private Vector3 destination;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
//Debug.DrawRay(ray.origin, ray.direction);
if(Input.GetButtonDown("Fire1")) {
//player is shooting
ShootProjectile();
}
}
void ShootProjectile() {
Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
//Debug.Log(ray.direction);
RaycastHit hit;
if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
{
destination = hit.point;
}
else {
destination = ray1.GetPoint(1000);
}
Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
InstantiateProjectile(firePoint);
}
void InstantiateProjectile(Transform firePoint) {
var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
}
}
Here's the location of firePoint.
firePoint (i.e. where the projectile should instantiate)
I would appreciate any help on this, as I've been trying to fix it (on and off) for several days, and really have no idea what the problem is.
Edit: Here's my player movement script(s) as well. The first one is PlayerController.cs, and it converts the player's inputs into the appropriate movement vectors and camera rotation. It then calls methods from PlayerMotor.cs, which actually performs the movements.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
[SerializeField]
public float speed = 10f;
[SerializeField]
private float lookSens = 3f;
private PlayerMotor motor;
void Start() {
motor = GetComponent<PlayerMotor>();
//Debug.Log("PlayerControllerStart");
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
//Debug.Log("PlayerControllerUpdate");
//calculate movement velocity as 3D vector.
float xMov = Input.GetAxisRaw("Horizontal");
float zMov = Input.GetAxisRaw("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
motor.move(velocity);
//speed*=(float)1.15;
//rotation
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;
motor.rotate(rotation);
float xRot = Input.GetAxisRaw("Mouse Y");
Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;
motor.rotateCamera(cameraRotation);
if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
motor.canJump=true;
}
if (Input.GetKey(KeyCode.W) == true) {
motor.accel=true;
}
else{
motor.accel=false;
}
}
}
PlayerMotor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
[SerializeField]
private Camera cam;
private Vector3 velocity = Vector3.zero;
private Vector3 rotation = Vector3.zero;
private Vector3 cameraRotation = Vector3.zero;
private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
private PlayerController pc;
private Rigidbody rb;
public bool canJump;
public bool accel;
public float acceleration;
int jumpCount;
void Start() {
rb = GetComponent<Rigidbody>();
pc = GetComponent<PlayerController>();
canJump=false;
jumpCount=0;
accel=false;
//acceleration = 1.0;
//distToGround = collider.bounds.extents.y;
//Debug.Log("PlayerMotorStart");
}
//sets velocity to a given movement vector.
public void move(Vector3 _velocity) {
velocity = _velocity;
}
public void rotate(Vector3 _rotation) {
rotation = _rotation;
}
public void rotateCamera(Vector3 _cameraRotation) {
cameraRotation = _cameraRotation;
}
public bool isGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
}
public void jump() {
rb.AddForce(transform.up * 250f);
//Debug.Log("Jump"+jumpCount);
jumpCount++;
canJump=false;
}
void FixedUpdate() {
performMovement();
performRotation();
if (canJump) {
jump();
}
//Debug.Log("PlayerMotorUpdate");
if(accel&&pc.speed<20f&&isGrounded())
{
//Debug.Log("W Pressed");
pc.speed*=(float)1.005;
}
else if(!accel) {
pc.speed=7f;
}
}
void performMovement() {
if(velocity != Vector3.zero) {
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//Debug.Log("Movement");
}
}
void performRotation() {
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
if(cam != null) {
cam.transform.Rotate(-cameraRotation);
}
}
}
Here are some pictures of my projectile prefab as well.
To solve one first confusion: The method Debug.DrawRay takes as paramters
a start position
a ray direction(!)
You are passing in another position which is not what you want.
This might only work "accidentally" as long as you stand on 0,0,0 so maybe it wasn't that notable but the debt ray definitely points into a wrong direction.
Rather do e.g.
Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);
Or instead rather use Debug.DrawLine which rather actually takes
start position
end position
Then you don't need to calculate the direction first
Debug.DrawLine(firePoint.position, destination, Color.white, 10f);
Then I suspect the following is happening: The spawned projectileObj actually is placed correctly but it is the visuals inside that projectile prefab that have a local offset against the parent prefab root.
Since you always spawn the projectile in world rotation Quaternion.identity that offset stays the same no matter where you look.
I guess a simple fix would already be to also apply the same rotation like
var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);

How can I make the camera to orbit also up and down?

Should I use Cinemachine for that or it's better to do it with a script from scratch ?
The script is attached to the Main Camera.
Now it's orbit only left right. I want it to orbit 360 degrees with clamp so it wont move down to the floor and to up back.
I should also the Y and not only the X but not sure how.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerFollow : MonoBehaviour {
public Transform PlayerTransform;
private Vector3 _cameraOffset;
[Range(0.01f, 1.0f)]
public float SmoothFactor = 0.5f;
public bool LookAtPlayer = false;
public bool RotateAroundPlayer = true;
public float RotationsSpeed = 5.0f;
// Use this for initialization
void Start () {
_cameraOffset = transform.position - PlayerTransform.position;
}
// LateUpdate is called after Update methods
void LateUpdate () {
if(RotateAroundPlayer)
{
Quaternion camTurnAngle =
Quaternion.AngleAxis(Input.GetAxis("Mouse X") * RotationsSpeed, Vector3.up);
_cameraOffset = camTurnAngle * _cameraOffset;
}
Vector3 newPos = PlayerTransform.position + _cameraOffset;
transform.position = Vector3.Slerp(transform.position, newPos, SmoothFactor);
if (LookAtPlayer || RotateAroundPlayer)
transform.LookAt(PlayerTransform);
}
}

I can not play animation on AI, unity 2d

I tried to make a firefly for my game, which is an AI.I wanted it to make across the map, for that I watched a tutorial on YT from BlackThornProd, but when I tried animating it, and played the game, it was terrible, the animation were playing bizarre, like when the firefly needs to go on the right, the animations are playing like this; Left-Right-Idle-Right-etc.Im using Blend Tree.
How can I solve it?
Thanks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPCRandomMoveing : MonoBehaviour
{
public float speed;
public Transform[] moveSpots;
private int randomSpot;
private float waitTime;
public float startWaitTime;
public Animator anim;
Vector2 movement;
void Start()
{
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Length);
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if(Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f){
if(waitTime <= 0){
randomSpot = Random.Range(0, moveSpots.Length);
waitTime = startWaitTime;
} else {
waitTime -= Time.deltaTime;
}
}
}
void FixedUpdate(){
anim.SetFloat("Horizontal", transform.position.x);
anim.SetFloat("Vertical", transform.position.y);
anim.SetFloat("Speed", transform.position.sqrMagnitude);
}
}
I think you move your fly and also try to animate its position right? Try maybe to just animate and dont change the transforms or even better rotate your fly with lookat vector and use animation controler to just adjust the speed of wings.
Try this script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateTowardsSpline : MonoBehaviour
{
// put the points from unity interface
public List<Transform> wayPointList = new List<Transform>();
public int currentWayPoint = 0;
Transform targetWayPoint;
public float speed = 0f;
public float turningRate = 1f;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
if (currentWayPoint < this.wayPointList.Count - 1)
{
if (targetWayPoint == null)
targetWayPoint = wayPointList[currentWayPoint];// hier put a random nr
RotateTowards();
}
}
void RotateTowards()
{
// rotate towards the target
transform.forward = Vector3.RotateTowards(transform.right, targetWayPoint.position - transform.position, 0.02f * (speed) * Time.deltaTime, 1.0f);
}
}

How can i make my prefab completely reverse (180 degrees) from it's spawnpoint? Unity 2D

So i made a little side scroller that uses a prefab to spawn bullets.
My problem is that it only shoots to one side... the Right.
I need it to fire to the left as well. I've already made a variable to see if the player is looking to the right or left.
I've tried to put the Speed to -20 and i've tried to rotate it 180 degrees on it's Z axis. I tested if the bullet script even picked up the change from the player movement script and it does.
Player Movement script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public GameObject bullet;
private Rigidbody2D myRigidbody;
private float speed = 15;
private bool facingRight;
private bool ground = false;
private float jump = 23;
// Start is called before the first frame update
void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
Movement(horizontal);
Flip(horizontal);
if (Input.GetKey("w"))
{
if (ground)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jump);
}
}
if(facingRight == false)
{
bullet.GetComponent<bullet>().left = true;
}
if (facingRight == true)
{
bullet.GetComponent<bullet>().left = false;
}
}
void OnTriggerEnter2D()
{
ground = true;
}
void OnTriggerExit2D()
{
ground = false;
}
private void Movement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * speed,myRigidbody.velocity.y);
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}
Weapon script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class weapon : MonoBehaviour
{
// Start is called before the first frame update
public bool right;
public Transform firepointR;
public GameObject bulletPrefab;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("space"))
{
Debug.Log("Oh well");
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firepointR.position, firepointR.rotation);
}
}
bullet script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bullet : MonoBehaviour
{
public bool left;
public float speed = 20;
public Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
// Update is called once per frame
void FixedUpdate()
{
Debug.Log(speed);
if (left == false)
{
transform.Rotate(0, 0, 180);
}
}
}
As i previously said i need my bullet (prefab) to go the opposite direction but whatever i do right now it will always go right.
Expanding on my comment:
Did you try reversing the velocity?
rb.velocity = -(transform.right * speed);
Note: There are instances when using a negative float wont return the opposite of the positive result. However, in this example, it will work just fine.
I imagine this will work also (and is probably the correct way of doing it):
rb.velocity = transform.left * speed;

Categories

Resources