I've written some code for my camera so that it follows my character (i'm making a 3D side-scrolling endless-runner/platform game).
It follows the player but its really jumpy and not smooth at all. How can i fix this?
I am avoiding parenting to the character because i don't want the camera to follow the player when it jumps upwards.
Here is my code:
using UnityEngine;
using System.Collections;
public class FollowPlayerCamera : MonoBehaviour {
GameObject player;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void LateUpdate () {
transform.position = new Vector3(player.transform.position.x, transform.position.y, transform.position.z);
}
}
I recommend using something like Vector3.Slerp or Vector3.Lerp instead of assigning the position directly. I included a speed variable, you can adjust it higher or lower to find the perfect speed for your camera to follow the player at.
using UnityEngine;
using System.Collections;
public class FollowPlayerCamera : MonoBehaviour {
public float smoothSpeed = 2f;
GameObject player;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void LateUpdate () {
transform.position = Vector3.Slerp(transform.position, new Vector3(player.transform.position.x, transform.position.y, transform.position.z), smoothSpeed * Time.deltaTime);
}
}
Hopefully this helps you get closer to your solution.
Related
So I made a script that should In theory make the Character Controller's Collider follow the Player camera. Here is the Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class CCCameraFollower : MonoBehaviour
{
public GameObject Camera;
public CharacterController character;
// Start is called before the first frame update
void Start()
{
character = GetComponent<CharacterController>();
}
// Update is called once per frame
void LateUpdate()
{
character.center = Camera.transform.position;
}
}
This works Fine/Okay when I try it out, however as soon as I enter Climb() In my Climber script:
void Climb()
{
InputDevices.GetDeviceAtXRNode(climbingHand.controllerNode)
.TryGetFeatureValue(CommonUsages.deviceVelocity, out Vector3 velocity);
character.Move(transform.rotation * -velocity * Time.fixedDeltaTime);
cachedVelocity = -velocity;
Debug.Log(cachedVelocity);
}
When this is Climb() Runs, this happens:
Image that Shows The Issue
I don't see a reason for this to happen, maybe its very obvious. I don't know... Anyways, my question is: "How do I make the Collider of the CC Follow the Player Camera?".
In the CCCameraFollower.LateUpdate() method you are actually moving the center of the character controller and not the position of the Camera. Change to this and it will probably work as you want.
void LateUpdate()
{
Camera.transform.position = character.center;
}
I've been trying to get this working using pretty much every method I can find (even using the dreaded transform.translate) but I just can't seem to get it working. This is just a draft of the code and if there are any other ways to go about it I'm down to change some stuff.
Currently, he barely moves (it looks like he's getting stuck on the floor somehow.) I'm fairly new to moving objects using rigid bodies so I'm pretty much in the dark on how to solve this issue.
Here's the script from my latest crack at it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerTest : MonoBehaviour
{
public float speed = 10.0f;
public Rigidbody rb;
public Vector3 movement;
// Start is called before the first frame update
void Start()
{
rb.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("w"))
{
movement = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
}
}
void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector3 direction)
{
rb.MovePosition(transform.position + (transform.forward * speed * Time.deltaTime));
}
}
In your code you have your moveCharacter function inside your Update function, enclosed is the fixed one, which should work now. Before your FixedUpdate was not getting called, therefore your moveCharacter function was not as well and your GameObject was not moving.
EDIT 1: You shoud also multiply with your movement direction as well, updated the script to fit that
EDIT 2: I misplaced the curly brackets, fixed that now
EDIT 3: You should also update your movement Vector3 every frame, not if W is pressed, fixed the script again.
EDIT 4: Fixed the movement bug (copy and paste entire script, since i changed more lines)
This is the updated script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerTest : MonoBehaviour
{
public float speed = 10.0f;
public Rigidbody rb;
public Vector3 movement;
// Start is called before the first frame update
void Start()
{
rb.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
movement = new Vector3(Input.GetAxis("Horizontal"), 1f, Input.GetAxis("Vertical"));
}
void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector3 direction)
{
Vector3 offset = new Vector3(movement.x * transform.position.x, movement.y * transform.position.y, movement.z * transform.position.z);
rb.MovePosition(transform.position + (offset * speed * Time.deltaTime));
}
}
References: Rigidbody.MovePosition
I am trying to make a basic platformer using Unity and my player has a sort of gun. My bullet is only shooting in one location, and I would like it to rotate with the player. I am quite new to C# and need some help.
I have tried using if and else statements and I have tried manually rotating it.
My code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class fire : MonoBehaviour
{
public Transform player;
public Rigidbody2D rb2d;
public Transform enemy;
public Transform myspawn;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Spawn"))
{
transform.position = player.position;
rb2d.velocity = new Vector2(10.0f, 0.0f);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.transform == enemy)
{
transform.position = myspawn.position;
}
}
}
I expect the output to rotate the bullet with the player, and using the if statements I got a lot of different errors. The actual output I got was the bullet just wouldn't move until you manually push the bullet.
If your gun is only shooting at one direction you can do something like this:
Create a new boolean variable, call it something like isLookingRight in your player controller script and set it to true if your player is initially looking at right. Whenever player moves left, change this variable to false and change your Update in the code you have provided to this:
void Update()
{
if (Input.GetButtonDown("Spawn"))
{
transform.position = player.position;
if(playerScript.isLookingRight){
rb2d.velocity = new Vector2(10.0f, 0.0f);
}
else{
rb2d.velocity = new Vector2(-10.0f, 0.0f);
}
}
What this code does is pretty simple, if your player is looking left, it just changes the velocity to the opposite of what it would normally be. But you need to be changing the isLookingRight correctly in your player movement script.
I am trying to create a ball hitting game in the baseball format. I create a ball as a prefab. I want to push the ball to the main scene within a certain period of time.
For example; when the first ball is in the scene, the second ball will spawn after 5-6 seconds, then the third, fourth etc. I am the beginner level of Unity and I am not good at C#. I am not sure whether I am using the true functions such as Instantiate. Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour {
public float RotateSpeed = 45; //The ball rotates around its own axis
public float BallSpeed = 0.2f;
public GameObject[] prefab;
public Rigidbody2D rb2D;
void Start() {
rb2D = GetComponent<Rigidbody2D>(); //Get component attached to gameobject
Spawn ();
}
void FixedUpdate() {
rb2D.MoveRotation(rb2D.rotation + RotateSpeed * Time.fixedDeltaTime); //The ball rotates around its own axis
rb2D.AddForce(Vector2.left * BallSpeed);
InvokeRepeating("Spawn", 2.0f, 2.0f);
}
public void Spawn ()
{
int prefab_num = Random.Range(0,3);
Instantiate(prefab[prefab_num]);
}
}
After I apply this script, the result is not what I want.
Add InvokeRepeating("Spawn", 2.0f, 2.0f); to the Start not the FixedUpdate.
InvokeRepeating invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
You can check the documentation here.
Use Coroutines
private IEnumerator SpawnBall() {
while(true) {
Instantiate(baseball);
yield return new WaitForSeconds(5);
}
}
Which can then be started with StartCoroutine() and terminated in one of three ways:
internally by breaking out of the while loop with break (the function would then have no more lines to execute and exit)
internally by yield break
externally by calling StopCoroutine() on a reference to the coroutine
Alternative to the other answers: Just use a countdown. This sometimes gives you more control
// Set your offset here (in seconds)
float timeoutDuration = 2;
float timeout = 2;
void Update()
{
if(timeout > 0)
{
// Reduces the timeout by the time passed since the last frame
timeout -= Time.deltaTime;
// return to not execute any code after that
return;
}
// this is reached when timeout gets <= 0
// Spawn object once
Spawn();
// Reset timer
timeout = timeoutDuration;
}
I updated my script by considering your feedbacks and it works like a charm. Thanks to all!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Threading;
public class Ball : MonoBehaviour {
public float RotateSpeed = 45; //The ball rotates around its own axis
public float BallSpeed = 0.2f;
public GameObject BaseBall;
public Transform BallLocation;
public Rigidbody2D Ball2D;
void Start() {
Ball2D = GetComponent<Rigidbody2D>(); //Get component attached to gameobject
InvokeRepeating("Spawn", 5.0f, 150f);
}
void FixedUpdate() {
Ball2D.MoveRotation(Ball2D.rotation + RotateSpeed * Time.fixedDeltaTime); //The ball rotates around its own axis
Ball2D.AddForce(Vector2.left * BallSpeed);
}
public void Spawn ()
{
Instantiate (BaseBall, BallLocation.position, BallLocation.rotation);
}
}
So I got this code to instantiate my gameobject Cannon, witch has a child "ball" attached to it. I'm trying to rotate the "ball" around the "cannon" when I use my left/right arrow keys.
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour {
public GameObject Cannon = null;
public float speed = 1.0f;
void Start () {
Cannon = Instantiate (Resources.Load ("Prefabs/Cannon")) as GameObject;
}
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.LeftArrow)){
Cannon.transform.Rotate(Vector3.left * speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.RightArrow)){
Cannon.transform.Rotate(Vector3.right * speed * Time.deltaTime);
}
}
}
There is no Vector3.left, that would be an inverse of Vector3.right so you would just write that as "-Vector3.right". But regardless, you shouldnt be passing the vector3 of the direction you want to rotate in, but the axis in which you want to rotate around. in this case, you would use Vector3.up for both arguments, and use "* speed" for one, and "* -speed" for the other.