I'm making a third person sports game and I wish to shoot the ball straight forward from the player.
I have a working script for shooting the ball, however it is attached to the main camera so only shoots in the direction the camera is facing.
I would like to alter this code to attach it to the player instead of the camera.
PS: I am still very new to C#, I assume the problem is in the "camera.main.transform" section but I don't know the code to change it to player.
my code is below;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShootScript : MonoBehaviour
{
public GameObject bulletPrefab;
public float shootSpeed = 300;
Transform cameraTransform;
void Start()
{
cameraTransform = camera.main.transform;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
shootBullet();
}
}
void shootBullet()
{
//Get the Rigidbody that is attached to that instantiated bullet
Rigidbody projectile = GetComponent<Rigidbody>();
//Shoot the Bullet
projectile.velocity = cameraTransform.forward * shootSpeed;
}
}
First of all: You currently do GetComponent<Rigidbody> on that object itself .. this makes no sense since it would fire away "yourself" instead of a bullet. You have to Instantiate a bullet and apply forces/velocity here. You kind of missed the instantiation.
Then simply attach this script to your player Object instead and use transform.forward. transform returns the Transform component of the GameObject this script is attached to.
public class ShootScript : MonoBehaviour
{
// Hint: By making the prefab field Rigidbody you later can skip GetComponent
public Rigidbody bulletPrefab;
public float shootSpeed = 300;
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
shootBullet();
}
}
void shootBullet()
{
// Instantiate a new bullet at the players position and rotation
// later you might want to add an offset here or
// use a dedicated spawn transform under the player
var projectile = Instantiate (bulletPrefab, transform.position, transform.rotation);
//Shoot the Bullet in the forward direction of the player
projectile.velocity = transform.forward * shootSpeed;
}
}
Related
I have created a player prefab (called Tim in my project) and am trying to make all the references to gameObjects and transforms directly from the one of the players scripts which is actually attached to a gun object which is a child of the player prefab.
The issue is I cant manage to reference the camera in the script although I've looked and tried many different methods, none of them seemed to work. Unity prints this error in the console though : "NullReferenceException: Object reference not set to an instance of an object". And here is the script :
public class Gun_Control : MonoBehaviour
{
// References for GameObjects
[SerializeField] private Rigidbody2D rb;
private GameObject Player;
[SerializeField] private Transform PlayerTransform;
private GameObject Gun;
[SerializeField] private Transform GunTransform;
private Camera MainCamera;
private GameObject firePoint;
[SerializeField] private Transform firePointTransform;
[SerializeField] private GameObject bulletPrefab;
// Variables for Shooting
private Vector2 mousePos;
private float bulletForce = 20f;
// Start is called at the beginning
void Start()
{
Debug.Log("Starting");
Player = GameObject.FindWithTag("Player");
PlayerTransform = Player.transform;
Gun = GameObject.FindWithTag("PlayerGun");
GunTransform = Gun.transform;
MainCamera = GameObject.FindWithTag("Camera").GetComponent<Camera>();
firePoint = GameObject.FindWithTag("PlayerFirePoint");
firePointTransform = firePoint.transform;
}
// Update is called once per frame
void Update()
{
// Get mouse position
mousePos = MainCamera.ScreenToWorldPoint(Input.mousePosition);
// Run shoot function on left click
if(Input.GetButtonDown("Fire1"))
{
Shoot();
}
}
// Update is called on every physics frame
void FixedUpdate()
{
// Set gun position to player position
GunTransform.position = PlayerTransform.position;
// Set gun rotation to mouse position
Vector2 lookDir = mousePos - rb.position;
float angle = Mathf.Atan2(lookDir.y ,lookDir.x) * Mathf.Rad2Deg - 180f;
rb.rotation = angle;
}
void Shoot()
{
// Instantiate a bullet at the firepoint and give it force
GameObject bullet = Instantiate(bulletPrefab, firePointTransform.position, firePointTransform.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
rb.AddForce(firePointTransform.up * bulletForce, ForceMode2D.Impulse);
}
}
Right now I have a variable, MainCamera, and when the script starts I look for a camera which has "Camera" as its tag which is set correctly.
I can add on if anyone needs more details and thank you to everyone for taking the time to help.
Edit 1 :
I tried what thunderkill suggested but it doesnt seem to work.
Here is a picture of the new code.
And when I try to use Debug.Log(Camera.main); it prints null.
here is a good example to access your main camera :
Camera m_MainCamera;
void Start()
{
//This gets the Main Camera from the Scene
if(Camera.main != null){
m_MainCamera = Camera.main;
//This enables Main Camera
m_MainCamera.enabled = true;
}
}
Camera c = Camera.main;//get the camera Tagged "MainCamera"
So you have to Check if your Camera tag is "MainCamera".
or you try :
GameObject.FindObjectOfType<Camera>();
(I don't recommend the second solution)
So I ended up finding the answer.I just deleted the camera in my scene and created a new one and then ended up using : MainCamera = GameObject.FindWithTag("Camera").GetComponent<Camera>(); which worked this time. The issue could have also been caused by errors present before in my code.
Hey I just want my bullet to destroy itself when it touch Ground i tried to destroy after 2 seconds but it has the same problem That's My Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
GameObject target;
public float speed;
Rigidbody2D bulletRB;
void Start()
{
bulletRB = GetComponent<Rigidbody2D>();
target = GameObject.FindGameObjectWithTag("Player");
Vector2 moveDir = (target.transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2(moveDir.x, moveDir.y);
Destroy(this.gameObject, 2);
}
}
Destroy the bullet object using the Destroy method.The bullet is destroyed after flying a certain distance.
public float speed;
public float destoryDistance;
private Rigidbody2D rg2d;
private Vector3 startPos;
// Start is called before the first frame update
void Start()
{
rg2d = GetComponent<Rigidbody2D>();
rg2d.velocity = transform.right * speed;
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
float distance = (transform.position - startPos).sqrMagnitude;
if (distance > destoryDistance)
{
Destroy(gameObject);
}
}
Use OnCollisionEnter() to destroy to bullet
void OnCollisionEnter(Collision collider)
{
if (collider.GameObject.tag == "Ground")
{
Destroy (this.GameObject)
}
}
What's happening here is that this function gets called every time it collides with an object, so we put the destroy code here. It takes the collider as a parameter, and then checks if the GameObject has the tag "Ground", and if it does, destroy itself.
Note that you will also have to add a tag to your ground objects in the hiearchy. You can name them anything else too, but make sure to change "Ground" in the code when you do set the tag to anything other than it.
You will probably also have other colliders like walls in your game so you should make a universal tag that destroys bullets and name it something like "Destroy Projectiles" or something.
Edit: You can have multiple functions that destroy the GameObject.
I need some help with Unity.
I try to make an object to detect a collision, but for some reason, the OnColissionEnter function is not called.
Both my objects have rigidBody and Box Collider attached, isTrigger is unenabled as well.
I supposed it's because I have AddForce in my code, but I am not sure. Have anybody a clue what is going wrong there?
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cuplat2 : MonoBehaviour
{
public Vector3 Target = new Vector3();
private Rigidbody rb;
public float thrust;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 NewPosition = transform.position + Target;
Vector3 Position = transform.position;
if (transform.position.x < Target.x)
{
rb.AddForce(transform.position * thrust);
}
else
{
//rb.isKinematic = true;
}
}
public void OnCollisionEnter(Collision collision)
{
Debug.Log("stop");
if (collision.gameObject.name == "Cupla T2")
{
Debug.Log("stop");
}
}
}
One of your rigidbodies has to have isKinematic = false;
If it's not possible in your case I see they have workaround for that:
https://forum.unity.com/threads/collision-detection-for-kinematic-rigidbodies.885778/
Other option would be that the collision is disabled in collision layer mask, but that would cause objects to pass trough each other (I believe that's not the case)
Third option: your rigidbody does not have collider (maybe collider is on parent, has enabled = false, or inactive game object?)
Fourth option: If your object moves very fast you should change Collision Detection Mode to Continous Dynamic
How about the collision layer matrix? Go into Edit > Project Settings, then select the Physics. Check if the layers set to the GameObjects are actually having any collision between them. Collision Layer matrix
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.
This code is for an elevator-type platform, where once the player stands on it, it 'takes' the player up by adding force onto it.
The thing is, while the force is created, the rigidbody (the player) does not move when the elevator moves. The code was written in C#, using Unity 5. In the code, the player is assigned the public 'rb', and contains a rigidbody.
The animation is a simple animation clip that moves the elevator up. Any ideas? Thank you for your time and answers in advance.
The elevator is Kinematic, the Player is not.
using UnityEngine;
using System.Collections;
/*This script activates when the player steps on the elevator, as it takes them up a floor.*/
public class ElevatorMovementScript : MonoBehaviour
{
private bool elevatorUp = false;
public Animation anim;
public int elevatorDelay = 5;
public int force = 800;
public Rigidbody rb;
// Use this for initialization
void Start ()
{
anim = GetComponent<Animation>();
}
// Update is called once per frame
void Update ()
{
}
/*Checks if the player has stepped onto the elevator. If the player has, it waits five seconds, and then pushes the player up.*/
void OnTriggerStay(Collider other)
{
if (other.gameObject.tag == "Player" && !elevatorUp)
{
Invoke("AnimationPlay",elevatorDelay);
elevatorUp = true;
}
}
/*Plays the animation of the player going up. Used for the 'Invoke' method.*/
void AnimationPlay()
{
rb.AddForce(transform.up * force);
Debug.Log (transform.up * force);
anim.Play ("Up");
}
}
It looks like this script is on your elevator's game object, in which case this line:
rb.AddForce(transform.up * force);
Will try to apply a force to the elevator, not the player. You've got to keep track of the player's rigidbody or somehow get it on demand in AnimationPlay.
You said that
the player is assigned the public 'rb'
But rb = GetComponent<Rigidbody>(); will ignore this and use the rigidbody attached to the gameobject that ElevatorMovementScript is attached to.