How to add collisions in Unity with character controller? - unity3d

I am currently working on a Unity game and I was having some trouble with it.
I created the movement of my character watching a tutorial and implementing the new input system. I now need to implement collisions so my character can shoot at enemies but I can not add a rigid body or a box collider because it uses character controller for the movement. Any ideas on how to resolve this? I tried watching some tutorials but I couldnt solve my problem and as I am new to this, I do not know what else to do.
This is the code I have at the moment for the movement. Controller.Move() is commented because I was having trouble with it but it is what makes my character move:
void playerMovement()
{
Vector2 inputVector = move.ReadValue<Vector2>();
finalVector.x = inputVector.x;
finalVector.y = inputVector.y;
//Vector3 currentPos = transform.position;
if (finalVector != Vector3.zero)
{
if (move.ReadValue<Vector2>().y == -1)
{
Quaternion target = Quaternion.Euler(180, 0, 0);
transform.rotation = target;
//controller.Move(finalVector * Time.deltaTime * speed);
}
else
{
if (move.ReadValue<Vector2>().y == 1)
{
Quaternion target = Quaternion.Euler(0, 0, 0);
transform.rotation = target;
//controller.Move(finalVector * Time.deltaTime * speed);
}
else
{
if (move.ReadValue<Vector2>().x == 1)
{
Quaternion target = Quaternion.Euler(0, 0, -90);
transform.rotation = target;
//controller.Move(finalVector * Time.deltaTime * speed);
}
else
{
if (move.ReadValue<Vector2>().x == -1)
{
Quaternion target = Quaternion.Euler(0, 0, 90);
transform.rotation = target;
//controller.Move(finalVector * Time.deltaTime * speed);
}
}
}
}
}
}
This is how I shoot:
void playerShoot() {
if (!canShoot) return;
GameObject b = Instantiate(bullet, bulletDirection.position, bulletDirection.rotation);
bullet.SetActive(true);
StartCoroutine(canPlayerShoot());
}

You should add a child game object, and then add the box collider to that. When using OnCollisionEnter(), it uses all the collider in child game objects too.

Related

How to make camera follow to clone player not first production?

I made the code which can follow the clone player in unity. But It worked only the first clone player. If join room second or later, It can't find clone player and doesn't work. How can I fix that ? Thanks for anything your helps.
follow.cs:
private void Awake()
{
mainCam = this;
}
void Start()
{
height = Camera.main.orthographicSize;
width = height * Screen.width / Screen.height;
}
void LateUpdate()
{
if (player == null)
{
player = GameObject.Find("Player(Clone)");
}
else
{
//transform.position = new Vector3(target.position.x, target.position.y, -10f);
transform.position = Vector3.Lerp(transform.position, target.position, Time.deltaTime * speed);
float lx = size.x * 0.5f - width;
float clampX = Mathf.Clamp(transform.position.x, -lx + center.x, lx + center.x);
float ly = size.y * 0.5f - height;
float clampY = Mathf.Clamp(transform.position.y, -ly + center.y, ly + center.y);
transform.position = new Vector3(clampX, clampY, -10f);
}
}
player spawn script:
public void Spawn()
{
GameObject PI = PhotonNetwork.Instantiate("Player", Vector3.zero, Quaternion.identity);
Follow.mainCam.target = PI.transform;
Debug.Log("I'm in the room.");
}
I guess that player stay null, maybe when you are trying to GameObject.Find() by his name, that method returns null.
Maybe you can try it with a tag or use another name?
The simplest solution is to make the camera the child of the player object and then change it's position accordingly through the script
You could also potentially use CineMachine which has some built-in follow methods
In order to change the parent of an object in the hierarchy through code you basically need to do something like this
public Transform camera
public Transform player
camera.parent = player;
and you can then set the camera position like this
camera.position = new Vector3(0, 0, -10);
Since the camera is the child of the player 0, 0, -10 basically means that the camera will be -10 in the Z axis away from the player (which should be behind the player). Whenever the player moves, because the camera is now attached as a child, it will follow the player.

Unity camera rotation around object to a smooth stop

I have a script that makes my camera rotate around a target when right click is pressed. Currently, when the right click is released, the rotation comes to a full stop, which is fully expected behavior. I want it to keep rotating for a little while after the mouse button is up, before it comes to a full stop, like if it was decelerating. Here is the code that handles the rotation around the given target:
if (!target)
return;
if (Input.GetMouseButtonDown(1))
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
if (Input.GetMouseButton(1))
{
Vector3 nextDirection = previousPosition - cam.ScreenToViewportPoint(Input.mousePosition);
direction = Vector3.SmoothDamp(direction, nextDirection, ref smoothVelocity, smoothTime);
cam.transform.position = target.position;
cam.transform.Rotate(new Vector3(1, 0, 0), direction.y * 180);
cam.transform.Rotate(new Vector3(0, 1, 0), -direction.x * 180, Space.World);
cam.transform.Translate(new Vector3(0, 0, -distanceFromSphere));
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
}
Here are the needed references:
public Camera cam;
public Vector3 previousPosition;
public Transform target;
public float distanceFromSphere = 100;
public Vector3 direction;
public Vector3 smoothVelocity = Vector3.zero;
public float smoothTime = 3f;
Is there a way to make the camera rotation be accelerated when the mouse button is down, and when the mouse is up, to be decelerated?
What you need is inertia, get the Rotate and Translate calls outside the if statement, and at the end multiply the direction with 0.98 or 0.99 depending on how much intertia you need.
public float inertia = 0.98f;
direction *= inertia;
Chris Ch's solution works fine, but I had already done something different, here is my solution to the original question:
void UpdateWorldRotation()
{
if (!target)
return;
if (Input.GetMouseButtonDown(1))
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
Vector3 currentSmoothVelocity = new Vector3();
if (Input.GetMouseButton(1))
{
nextDirection = previousPosition - cam.ScreenToViewportPoint(Input.mousePosition);
currentSmoothVelocity = smoothVelocity;
}
if (Input.GetMouseButtonUp(1))
{
StartCoroutine(SmoothStop());
currentSmoothVelocity = smoothVelocity / 2;
}
direction = Vector3.SmoothDamp(direction, nextDirection, ref currentSmoothVelocity, smoothTime, 100, 10f * Time.deltaTime);
cam.transform.position = target.position;
cam.transform.Rotate(new Vector3(1, 0, 0), direction.y * 180);
cam.transform.Rotate(new Vector3(0, 1, 0), -direction.x * 180, Space.World);
cam.transform.Translate(new Vector3(0, 0, -distanceFromSphere));
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
}
IEnumerator SmoothStop()
{
yield return new WaitForSeconds(smoothStopTime);
nextDirection = Vector3.zero;
}
This way, the sphere keeps rotating for a specific amount of time with a slower velocity before it comes to a full stop.

How to keep player momentum after jumping (2D)?

I'm creating a Mario clone and I need to keep the player's forward momentum into the jump and then onward into the landing. I can't figure out how to achieve this. Every time I land, the player has to build up momentum again. Any Idea how to fix this? I've tried several solutions to no avail. I'm thinking it has something to do with how I'm adding force and acceleration to the player when holding left or right. Not sure though any help would be much appreciated. thanks in advance.
Here's my code:
Animator animator;
Rigidbody2D rb;
bool isGrounded;
public float moveSpeed;
public Vector2 acceleration;
public float jumpHeight;
public float lowjumpMultiplier;
public Transform groundCheckM;
public Transform groundCheckL;
public Transform groundCheckR;
public float storedValue;
void Start()
{
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
transform.eulerAngles = new Vector3(0, 0, 0);
}
private void Update()
{
if
((Physics2D.Linecast(transform.position,groundCheckM.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) || //Check if grounded
(Physics2D.Linecast(transform.position, groundCheckL.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) ||
(Physics2D.Linecast(transform.position, groundCheckR.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))))
{
isGrounded = true;
animator.SetBool("Jump", false);
}
else
{
isGrounded = false;
}
animator.SetFloat("Walk", rb.velocity.x); //Set animation float to x velocity
if (rb.velocity.x <= 0.03f && rb.velocity.x >= -0.03f && isGrounded) //Play "Idle" animation
{
animator.Play("Mario_Idle");
}
if (rb.velocity.x >=4 || rb.velocity.x <=-4)
{
animator.speed = Mathf.Abs(rb.velocity.x / 5.5f); //Increase speed of walking animation with player's walking speed
}
}
void FixedUpdate()
{
if (Input.GetKey("d") || Input.GetKey("right")) //Move player to the right
{
rb.AddForce(acceleration * rb.mass);
transform.rotation = Quaternion.Euler (0, 0, 0);
}
else if (Input.GetKey("a") || Input.GetKey("left")) //Move player to the left
{
rb.AddForce(-acceleration * rb.mass);
transform.rotation = Quaternion.Euler(0, 180, 0);
}
if (rb.velocity.x >= 10)
{
rb.velocity = new Vector2(10, rb.velocity.y); //Cap player speed at 10 when moving right
}
else if (rb.velocity.x <= -10)
{
rb.velocity = new Vector2(-10, rb.velocity.y); //Cap player speed at 10 when moving left
}
if (Input.GetKey("space") && isGrounded) //Player jump
{
rb.velocity += new Vector2(rb.velocity.x, jumpHeight);
animator.SetBool("Jump", true);
}
}
}
I feel dumb but the answer was in the physics material. Once I lowered the friction, it allowed momentum from the jump to carry into the player's run speed. I guess it's a good reminder to tinker directly inside Unity and its built in physics system.
If you want to keep your momentum when jumping, you could store it in a variable that will increase until it reaches the max, or you let go of the key.
float acceleration;
float accelFactor = 0.6f;
float deAccelFactor = 1f;
bool jumping; //you should set it to true when jumping and false, when not.
Rigidbody2D rb;
void Start(){
rb = GetComponent<Rigidbody2D>();
}
void Update(){
if (Input.GetKeyDown(KeyCode.D))
{
Accelerate();
rb.AddForce(acceleration * rb.Mass);
}
else if (jumping)
{
rb.AddForce(acceleration * rb.Mass);
}
else
{
DeAccel();
}
}
void Accelerate(){
acceleration += accelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
void DeAccel(){
acceleration -= deAccelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
This is what I would recommend using, that is, if I understand what you mean.

Cameras rotation is too slow

I have a game object that moves and rotates. I want the camera to stay behind the object all the time, so when the user presses w, it will look like the gameobject moves forward.
This is my skript for the camera movement.
public Transform target;
public Vector3 offset;
public void FixedUpdate()
{
transform.position = target.TransformPoint(offset);
transform.LookAt(target);
}
But I camera is not rotating around the player fast enough, so it looks like he is moving sidewards.
This is my player movement script, but I don't see any mistake in there.
public float smoothSpeed = 0.125f;
public float forwardSpeed;
public float sideSpeed;
// Start is called before the first frame update
void Start()
{
}
void FixedUpdate()
{
if (Input.GetKey("w"))
{
Vector3 movement = transform.rotation * Vector3.forward / (100 / forwardSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("s"))
{
Vector3 movement = transform.rotation * Vector3.back / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("a"))
{
Vector3 movement = transform.rotation * Vector3.left / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("d"))
{
Vector3 movement = transform.rotation * Vector3.right / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("e"))
{
transform.Rotate(0, 1, 0);
}
else if (Input.GetKey("q"))
{
transform.Rotate(0, -1, 0);
}
}
Thanks for your help]1
When the object moves sidewards it should move forwards.
Here are my settings in Unity:

how do i script to show the car dashing effect?

Actually, I'm developing an endless 3d car runner game made a city view where I'm showing some parked cars so basically what I want is when my player car collides with the parked car I want the parked car to rotate some degree and get back to 0 degree or original position how it was before.
I just wanted to lift the parked car and again should touch the ground back to normal. So this will show some realistic effect in game view.
since I'm new in unity development your help could really help me alot.
what I tried so far is :
void OnTriggerStay(Collider other)
{
if (gameObject.CompareTag("ParkedCar"))
{
Debug.Log("ParkedCar");
Quaternion from, to;
float inputValue = 0;
inputValue += Input.GetAxis("Vertical") * 10 * 1;
from = transform.rotation;
to = Quaternion.Euler(0, inputValue, 0);
gameObject.transform.rotation = Quaternion.Lerp(from, to, Time.deltaTime * 10f);
}
}
even i have tried this
void OnTriggerStay(Collider other)
{
if (gameObject.CompareTag("ParkedCar"))
{
gameObject.GetComponent<Rigidbody>().AddForce(transform.right * 100, ForceMode.Impulse);
}
}
trying this but i cant get my parked car collide again on ground. pls help me here.
If i understood you correctly you can implement this with a coroutine and OnTriggerEnter instead of OnTriggerStay like this:
private bool isDashed = false;
float time = 1.0f;
void OnTriggerEnter(Collider other)
{
//Assuming your to quaternion is correct
if (gameObject.CompareTag("ParkedCar") && !isDashed)
{
Debug.Log("ParkedCar");
Quaternion from, to;
float inputValue = 0;
inputValue += Input.GetAxis("Vertical") * 10 * 1;
from = transform.rotation;
to = Quaternion.Euler(0, inputValue, 0);
StartCoroutine(DashingCar(from, to));
}
}
IEnumerator DashingCar(Quaternion from, Quaternion to)
{
float elapsedTime = 0.0f;
while (elapsedTime < time)
{
gameObject.transform.rotation = Quaternion.Lerp(from, to, elapsedTime / time);
elapsedTime += Time.deltaTime;
yield return null;
}
isDashed = true;
}