I have been trying to find a way for the Enemy to shoot at multiple players or Objects and I don't know where to start.
I'm currently using Unity 2017
Here's the bullet script
Much Appreciated
using UnityEngine;
using System.Collections;
public class MultiBulletScript:
MonoBehaviour {
GameObject[] target;
public float speed;
Rigidbody2D bulletRB;
GameObject destroyObject;
Vector3 respawn = new Vector3(-36, 0, 0);
public GameObject blood;
// Use this for initialization void Start () {
bulletRB = GetComponent < Rigidbody2D > ();
target = GameObject.FindGameObjectsWithTag("Player");
Vector2 moveDir = (target.transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2(moveDir.x, moveDir.y);
Destroy(this.gameObject, 2);
}
private void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Player") {
Instantiate(blood, transform.position, Quaternion.identity);
other.gameObject.transform.position = respawn;
}
if (other.CompareTag("Bullet")) {
Destroy(other.gameObject);
Destroy(gameObject);
}
}
}
You can create a List for objects you want to shoot at. Something like this:
public List<Transform> targets = new List<Transform>();
After this, you need to calculate the direction for all of them. Such as this (where gunPosition is where you want to spawn the bullet and shootRotation is the rotation of your bullet when you shoot it):
public void Start()
{
foreach(Transform target in targets)
{
Vector3 shootDirection = (target.position - transform.position).normalized;
GameObject newBullet = Instantiate(bulletPrefab, gunPosition, shootRotation)
newBullet.GetComponent<RigidBody>().velocity = shootDirection * shootSpeed;
}
}
However, this goes into your enemy controller script. Bullets should only have a small amount of code. They only need to detect the TriggerEnter.
But be aware! Too much OnTriggerEnter calculation in the scene can have an impact on your performance (dropping fps).
So I would create one script on each player with an OnTriggerEnter so they detect if a bullet hits them. They can destroy the bullet as well.
public void OnTriggerEnter(Collider other)
{
if(other.tag == "Bullet")
{
//Do blood effect
//Damage player
Destroy(other.transform.root.gameObject);
}
}
It is better, because there always be less player then bullet, so your game is more optimized. Hope I could help!
Related
I have a physics enabled sphere in my scene and a character that i can move around using WASD. now what i want is that as soon as player hits the ball it should not be physics enabled anymore and move along with player as like the player is holding it in the hands.
What i have tried so far:
i was able to do it but not at all perfect how i want it to be. i tried OnCollisionEnter to detect the collision, i made the sphere a child of the player, i used isKinematic = true as soon as collision is detected and i used Vector3.MoveTowards for the object to follow the position as the player.
I have attached two reference videos below
Reference Clip(The style i am aiming for):https://www.youtube.com/watch?v=fi-GB0RwLr0
MyVersion(This is what i am able to do):https://www.youtube.com/watch?v=JtV11KHY4pU
overall, if you watch the clips you can see how my version is very rigid, stucky, buggy, not so light weight feeling at all. Cut me a slack as well if i did anything way wrong, i started unity like just in the previous month.
This is my Player script through which i am controlling it all
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
public float MoveSpeed;
[SerializeField]private Rigidbody playerRig;
[SerializeField] private Rigidbody ballRig;
[SerializeField] private GameObject Ball;
[SerializeField] private GameObject heldObj;
private bool isTouching = false;
private Vector3 offset = new Vector3(0, 1, 3);
private Vector3 force;
public float jump;
private bool isGrounded = true;
private void Start()
{
Ball = GameObject.FindGameObjectWithTag("Ball");
ballRig.GetComponent<Rigidbody>();
playerRig.GetComponent<Rigidbody>();
}
void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
playerRig.velocity = new Vector3(x*MoveSpeed, playerRig.velocity.y,z*MoveSpeed);
Vector3 vel = playerRig.velocity;
vel.y = 0;
if (vel.x != 0 || vel.z != 0)
{
transform.forward = vel;
}
if(transform.position.y < -10)
{
GameOver();
}
ReleaseTheBall();
if (isTouching == true)
{
ballRig.transform.position = Vector3.MoveTowards(ballRig.transform.position, playerRig.transform.position, 5f);
}
}
void Jump()
{
force = new Vector3(0, jump, 0);
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
isGrounded = false;
playerRig.AddForce(force, ForceMode.Impulse);
}
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "Ball" && heldObj == null)
{
ballRig.isKinematic = true;
// ballRig.constraints = RigidbodyConstraints.FreezeRotation;
ballRig.transform.parent = playerRig.transform;
isTouching = true;
Debug.Log(" BALL PICKED UP AND MOVING ");
heldObj = Ball;
}
}
public void ReleaseTheBall()
{
if (Input.GetKeyDown(KeyCode.Space) && heldObj != null)
{
isTouching = false;
heldObj = null;
ballRig.transform.parent = null;
//ballRig.constraints = RigidbodyConstraints.None;
ballRig.isKinematic = false;
//Vector3 forceDirection = new Vector3(playerRig.transform.position.x, 0, playerRig.transform.position.z);
Vector3 rotationDirection = new Vector3(playerRig.transform.rotation.x, playerRig.transform.rotation.y, playerRig.transform.rotation.z);
ballRig.AddForce(new Vector3(transform.position.x,0,transform.position.z) * 5, ForceMode.Impulse);
ballRig.AddTorque(rotationDirection * 1);
Debug.Log("BALL RELEASED");
}
}
public void GameOver()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
i know there could be some very inefficient lines of code here, feel free to call out those lines as well.
So, basically what i want is that i want my player to pick up the ball as soon as it hits it and the ball should move exactly like player as if he is holding the ball in his hands and when i hit the spacebar i want the ball to be released into the direction i am looking(this part is also very tricky for me), what i am trying to do is i want to do exactly like in the refrence clip. Thanks a lot in advance.
one more thing, when i stop pressing any key to move(WASD), my player transform keeps changing values up and down and it slightly starts moving. i mean when i dont press any key, it still kinda moves.
First of all, you have indeed quite a lot of lines that aren't useful in here and that could be optimized.
Anyway, I hope this will do what you want it to do:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(Rigidbody))]
public class Player : MonoBehaviour {
[Header("Movement Setup")]
[Tooltip("Translation speed in m/s")]
[SerializeField] float _TranslationSpeed;
[Tooltip("Rotation speed in °/s")]
[SerializeField] float _RotationSpeed;
[Tooltip("Interpolation speed [0;1]")]
[SerializeField] float _InterpolationSpeed;
[Tooltip("Strength for jumps")]
[SerializeField] float _JumpingStrength;
[Tooltip("Strength for shoots")]
[SerializeField] float _ShootingStrength;
[Header("Other Settings")]
[Tooltip("Where the helded item will be placed")]
[SerializeField] Transform _ContactPoint;
[Tooltip("Which layers should be considered as ground")]
[SerializeField] LayerMask _GroundLayer;
// The player's rigid body
Rigidbody _Rigidbody;
// Is the player on the ground
bool _IsGrounded;
// Rigidbody of what's the player is helding. Null if the player isn't holding anything
Rigidbody _HeldedItemRigidbody;
// Getter to _IsGrounded, return true if the player is grounded
public bool IsGrounded { get { return _IsGrounded; } }
private void Start() {
_Rigidbody = GetComponent<Rigidbody>(); // The player's rigidbody could be serialized
}
void FixedUpdate() {
float horizontalInput, verticalInput;
// Getting axis
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
// Moving toward the x
Vector3 moveVect = transform.forward * _TranslationSpeed * Time.fixedDeltaTime * verticalInput;
_Rigidbody.MovePosition(_Rigidbody.position + moveVect);
// Rotating the player based on the horizontal input
float rotAngle = horizontalInput * _RotationSpeed * Time.fixedDeltaTime;
Quaternion qRot = Quaternion.AngleAxis(rotAngle, transform.up);
Quaternion qRotUpRight = Quaternion.FromToRotation(transform.up, Vector3.up);
Quaternion qOrientationUpRightTarget = qRotUpRight * _Rigidbody.rotation;
Quaternion qNewUpRightOrientation = Quaternion.Slerp(_Rigidbody.rotation, qOrientationUpRightTarget, Time.fixedDeltaTime * _InterpolationSpeed); // We're using a slerp for a smooth movement
_Rigidbody.MoveRotation(qRot * qNewUpRightOrientation);
// This prevents the player from falling/keep moving if there is no input
if (_IsGrounded) _Rigidbody.velocity = Vector3.zero;
_Rigidbody.angularVelocity = Vector3.zero;
if (transform.position.y < -10) GameOver();
if (Input.GetKey(KeyCode.Mouse0) && _HeldedItemRigidbody != null) ShootTheBall();
if (!_IsGrounded) return; // What's below this won't be executed while jumping
if (Input.GetKey(KeyCode.Space)) Jump();
}
void Jump() {
_IsGrounded = false;
_Rigidbody.AddForce(_JumpingStrength * transform.up, ForceMode.Impulse);
}
private void OnCollisionEnter(Collision collision) {
// Checking if the player encountered a ground object
if ((_GroundLayer & (1 << collision.gameObject.layer)) > 0) _IsGrounded = true;
if (collision.gameObject.tag == "Ball") { // this can be improved as tags are error prone
// Setting the item position to contact point
collision.gameObject.transform.position = _ContactPoint.position;
// Getting the rigidbody
_HeldedItemRigidbody = collision.gameObject.GetComponent<Rigidbody>();
// Setting the parent
_HeldedItemRigidbody.transform.parent = transform;
// Setting the body to be kinematic
_HeldedItemRigidbody.isKinematic = true;
// Stopping any movement or rotation
_HeldedItemRigidbody.velocity = Vector3.zero;
_HeldedItemRigidbody.angularVelocity = Vector3.zero;
}
}
public void ShootTheBall() {
// Reverting what's done in OnCollisionEnter
_HeldedItemRigidbody.transform.parent = null;
_HeldedItemRigidbody.isKinematic = false;
// Adding force for the shoot
_HeldedItemRigidbody.AddForce(transform.forward * _ShootingStrength, ForceMode.Impulse);
// Resetting helding item to null
_HeldedItemRigidbody = null;
}
public void GameOver() {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
You have to add a layer, and set the ground to this new layer.
Set up the variable as you like, don't hesitate to mess up with it a little bit to find what suits you (and don't forget to set up the player's mass (in rigidbody) as well!!)
Exemple of setup for the player script
Last things, you have to add an empty game object to your player which will be where the ball will be placed. I know it's a little bit dirty but place it a bit far from the player (more than the ball's radius) or it will bug. We could do something programatically to fix the ball at a spot and adapt this spot to the ball's radius.
This is an example of player
As you can see, I have the empty "player" gameobject which has the rigidbody, the collider and the player script.
The GFX item which is just the capsule.
If you don't know about this: the player game object is actually on the floor (at the player's feet) so it's better for movements. If you do this, don't forget to adjust the player's capsule collider to fit the GFX.
I also have the contact point.
Forget about the nose stuff, it's just a way to see where the player is facing when you just have a capsule.
If you have any question, feel free to ask.
So basically I want so that the enemy, which is shooting the player, to deal some damage.
I just don't know how to combine the two to make it work. I'll be thankful for your help.
..............................................................................................................................................
Here are my Heath and bullet scripts:
Health:
public class Health : MonoBehaviour
{
public Image healthBar;
public float healthAmount = 100;
public GameObject bullet;
private void Update()
{
if (healthAmount <= 0)
{
Application.LoadLevel(Application.loadedLevel);
}
if (Input.GetKeyDown(KeyCode.E))
{
TakeDamage(20);
}
if (Input.GetKeyDown(KeyCode.T))
{
Healing(10);
}
if (bullet.)
}
public void TakeDamage(float Damage)
{
healthAmount -= Damage;
healthBar.fillAmount = healthAmount / 100;
}
public void Healing(float healPoints)
{
healthAmount += healPoints;
healthAmount = Mathf.Clamp(healthAmount, 0, 100);
healthBar.fillAmount = healthAmount / 100;
}
}
Bullet:
public class Bullet : MonoBehaviour {
float moveSpeed = 25f;
public GameObject effect;
public GameObject player;
[SerializeField] private float attackDamage = 1f;
Rigidbody2D rb;
Player target;
Vector2 moveDirection;
// Use this for initialization
void Start() {
rb = GetComponent<Rigidbody2D>();
target = GameObject.FindObjectOfType<Player>();
moveDirection = (target.transform.position - transform.position).normalized * moveSpeed;
rb.velocity = new Vector2(moveDirection.x, moveDirection.y);
Destroy(gameObject, 1f);
}
void OnCollisionEnter2D (Collision2D col)
{
if(col.gameObject.tag.Equals("Player"))
{
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
In the Bullet script, get the Health Script from the player and call the function:
if(col.gameObject.tag.Equals("Player"))
{
if (col.transform.TryGetComponent<Health>(out Health health))
{
health.TakeDamage(50); // deal damage to player
}
Instantiate(effect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
But I have to add some Notes that I think beginners should know:
Physics in Unity is always updating in FixedUpdate ~60 times per second, independent of the framerate. You could change the physics timestep, but it's fine for most things. However if you have really fast bullets, they may pass though the player, because in one frame the bullet ist "in front of", and in the next frame "behind" the player. So you should look into raycasts to check for the next pixels in front of the bullet (depending on velocity etc.)
Also, I use "tryGetComponent<>" which is recommended, because if you use "getComponent<>" and hit an object that doesn't have a "health" component attached, you get an error. So this is the safe way to do it.
I'm assuming you have the Health script attached to the player game object. The easiest way that you can add damage to the player would be to get a reference to the Health script you have attached to the player and use your TakeDamage function. You can do this in the OnCollisionEnter2D function attached to the bullet as follows:
playerhealth = col.GetComponent<Health>();
playerhealth.TakeDamage(5);
The end result should look something like this:
void OnCollisionEnter2D (Collision2D col)
{
if(col.gameObject.tag.Equals("Player"))
{
Instantiate(effect, transform.position, Quaternion.identity);
playerhealth = col.GetComponent<Health>();
playerhealth.TakeDamage(5);
Destroy(gameObject);
}
}
I'm having an issue instantiating Prefabs in Unity.
I'm working on a game where you have enemies moving towards you and you have to kill them. My original enemy game object moved towards the player with little to no problem, but the instantiations of that object wouldn't move.
To make matters more confusing, when I copied the game object and added it to the scene without instantiation, both game objects would move towards the player just fine.
Enemy script:
public class EnemieController : MonoBehaviour
{
[SerializeField]
float moveSpeed = 1;
[SerializeField]
private Rigidbody2D rb;
public Transform player;
public float health = 50;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Debug.Log(player);
}
// Update is called once per frame
void Update()
{
MoveTowardsPlayer();
}
void MoveTowardsPlayer()
{
Vector3 mousepos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = (player.position - transform.position).normalized;
rb.velocity = new Vector2(direction.x * moveSpeed, direction.y * (moveSpeed * 1));
}
}
Instantiation Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using System;
[System.Serializable]
public class GameManagement : MonoBehaviour
{
public GameObject circleEnemie;
public Transform player;
[SerializeField]
float moveSpeed = 1;
// Start is called before the first frame update
void Start()
{
//Get random position to spawn ball
Vector3 screenPosition = Camera.main.ScreenToWorldPoint(new Vector3(Random.Range(0, Screen.width), Random.Range(0, Screen.height), Camera.main.farClipPlane / 2));
GameObject enemie = Instantiate(circleEnemie, screenPosition, Quaternion.identity) as GameObject;
enemie.name = "enemiecircle";
enemie.tag = "Enemie";
}
// Update is called once per frame
void Update()
{
}
}
And if wanted, here are the enemies inspector specifications
Inspector Specifications
Sorry about the link, my reputation points are yet to reach 10 so I can't post images directly.
My guess would be that the Player referenced in your enemy prefab is a prefab itself that never moves.
You should make the prefab field itself of type EnemyController. This makes sure you only can reference a prefab here that actually has an EnemyController attached.
Then after Instantiate you can pass in the player reference of the GameManagement script like
public class GameManagement : MonoBehaviour
{
// Give this field the correct type
public EnemyController circleEnemie;
public Transform player;
[SerializeField]
float moveSpeed = 1;
// Start is called before the first frame update
void Start()
{
//Get random position to spawn ball
Vector3 screenPosition = Camera.main.ScreenToWorldPoint(new Vector3(Random.Range(0, Screen.width), Random.Range(0, Screen.height), Camera.main.farClipPlane / 2));
// Instantiate returns the same type as the given prefab
EnemyController enemy = Instantiate(circleEnemie, screenPosition, Quaternion.identity);
enemy.name = "enemiecircle";
enemy.gameObject.tag = "Enemie";
// Now pass in the player reference
enemy.player = player;
}
// NOTE: When not needed better remove Unity message methods
// It would just cause overhead
//void Update()
//{
//}
}
Sidenote: In your EnemyController in MoveTowardsPlayer what do you need this for?
Vector3 mousepos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Then whenever dealing with Rigidbody do the things in FixedUpdate otherwise it might break the physics and collision detection!
Then also don't use the Transform values but again the Rigidbody
private void FixedUpdate ()
{
MoveTowardsPlayer();
}
private void MoveTowardsPlayer ()
{
var direction = ((Vector2)(player.position - rb.position)). normalized;
rb.velocity = direction * moveSpeed;
}
I have a game object called "Player" and my map is made up of short grasses and long grasses. If my player is on the long grass, I want it to slow down. One additional problem is that there are multiple Long grasses game objects in my game. Here is a screenshot of them :
https://imgur.com/hUq4baV
This is what my current movement code looks like :
public class PlayerMovement : MonoBehaviour
{
public Sprite Up;
public Sprite Down;
public Sprite Right;
public Sprite Left;
public float speed;
private SpriteRenderer sr;
// Update is called once per frame
void Update()
{
Vector3 move;
if (Input.GetKey(KeyCode.W))
{
GetComponent<SpriteRenderer>().sprite = Up;
move = new Vector2(0, speed * Time.deltaTime);
transform.position += move;
}
if (Input.GetKey(KeyCode.A))
{
GetComponent<SpriteRenderer>().sprite = Left;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position -= move;
}
if (Input.GetKey(KeyCode.D))
{
GetComponent<SpriteRenderer>().sprite = Right;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position += move;
}
if (Input.GetKey(KeyCode.S))
{
GetComponent<SpriteRenderer>().sprite = Down;
move = new Vector2(0,speed * Time.deltaTime);
transform.position -= move;
}
}
}
// All my code does is that on each WASD, it changes to a different sprite and moves it.
An explanation would be appreciated because I'm a beginner to this.
use colliders, eg. boxcolliders to detect if player is touching the grass.
Use a tag on you player
use the oncollisionenter2d() method on the grass
void OnCollisionEnter2D(Collision2D col) {
if(col.tag == "PlayerTag") {
playerScriptWhereSpeedIsLocated.speed = 1 //the speed you want
} }
One solution to this would be to use 2D Trigger Colliders.
Assuming your player has some sort of 2D collider attached to it, you may attach trigger colliders to your grass objects which can then send a message to the PlayerMovement script when the player enters/leaves the trigger by adding the OnTriggerEnter2D and OnTriggerExit2D methods to your PlayerMovement class. Here's an example of how this might work:
void OnTriggerEnter2D(Collider2D col)
{
// You can use gameObject.tag to determine what type of object we're colliding with
if(col.gameObject.tag == "LongGrass"){
speed = .8f;
}
}
void OnTriggerExit2D(Collider2D col)
{
if(col.gameObject.tag == "LongGrass"){
speed = 1f;
}
}
I would encourage you to look into the Collision action matrix if you are having
trouble detecting collisions in this way. You'll also make sure you tag your grass correctly for this method to work.
I stumbled across a problem while working with the book "Unity in Action". At the end of chapter 3 you'd end up with the basics for a simple fps game. It's basically a player (camera attached to it) in a simple and small level which only exists out of a number of cubes forming walls and the floor etc. These cubes all have box collider on them. Now the player is also able to shoot at moving enemies which are also able to shoot. This was done by Raycast/RaycastHit. All this worked perfectly so I wanted to add something that reassembles bullet holes, simply by instantiating a black sphere object on the wall where the fireball (this is the object the enemy and the player shoot) hits it. This works BUT sometimes the fireball object just goes through the wall. In case there is another wall behind it, the fireball object gets destroyed by this second wall and the desired sphere is created on the second wall instead of on the first wall.
I changed the speed in the fireball from 20 to 10 and then back to 20 and at a speed of 10, the success rate is around 19/20, while at a speed of 20 it's around 6/10.
Here is the code of the fireball which is supposed to check whether it hits the player (then health is deducted, that works fine) or hits the enemy (then the enemy falls over, also works fine) or hits the wall in which case the sphere should be created.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fireball : MonoBehaviour {
public float speed = 10.0f;
public int damage = 1;
[SerializeField] private GameObject wallHit;
private GameObject _wallHit;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.Translate(0,0, speed * Time.deltaTime);
}
void OnTriggerEnter(Collider other){
RaycastHit hit;
PlayerCharacter player = other.GetComponent<PlayerCharacter>();
ReactiveTarget target = other.GetComponent<ReactiveTarget>();
WallBehavior wall = other.GetComponent<WallBehavior>();
if(player != null){
player.Hurt(damage);
}
if(target != null){
target.ReactToHit();
}
if(wall != null){
if(Physics.Raycast(transform.position, transform.forward, out hit)){
wall.WallWasHit(hit);
}
}
Destroy(this.gameObject);
}
}
As you can see one thing I tried was to give each wall a WallBehavior script, which looks like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallBehavior : MonoBehaviour {
[SerializeField] private GameObject wallHit;
private GameObject _wallHit;
static int count = 0;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void WallWasHit(RaycastHit hit){
count++;
Debug.Log("Wall was hit: " + count);
_wallHit = Instantiate(wallHit) as GameObject;
_wallHit.transform.position = hit.point;
}
}
But none of my attempts to understand why this happens so infrequently was successful so far and I hope someone can help me with this because I feel like might be crucial for my learning before I continue with the book! Thanks in advance. if further information are needed, I am happy to provide them. See the following picture for a better visualization of the issue.
EDIT:
As mentioned in the answers, I replaced the fireball script accordingly but I am not sure how to change the following script likewise. This script is on my camera which is on my player object. In the Update function the Fireball is instantiated and also given a movement, so I guess this causes the problems?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RayShooter : MonoBehaviour {
private Camera _camera;
[SerializeField] private GameObject fireballPrefab;
private GameObject _fireball;
void Start () {
_camera = GetComponent<Camera>();
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void OnGUI(){
int size = 12;
float posX = _camera.pixelWidth/2 - size/4;
float posY = _camera.pixelHeight/2 - size/2;
GUI.Label(new Rect(posX, posY, size, size), "X");
}
// Update is called once per frame
void Update () {
if(Input.GetMouseButtonDown(0)){
Vector3 point = new Vector3(_camera.pixelWidth/2, _camera.pixelHeight/2, 0);
_fireball = Instantiate(fireballPrefab) as GameObject;
_fireball.transform.position = transform.TransformPoint(Vector3.forward * 1.5f);
_fireball.transform.rotation = transform.rotation;
Ray ray2 = _camera.ScreenPointToRay(point);
RaycastHit hit;
if(Physics.Raycast(ray2, out hit)){
GameObject hitObject = hit.transform.gameObject;
ReactiveTarget target = hitObject.GetComponent<ReactiveTarget>();
if(target !=null){
target.ReactToHit();
}
}
}
}
}
This is not how to move a Rigidbody Object and moving it like this could cause so many issues including the one mentioned in your question. Objects with Rigidbody should be moved with the Rigidbody component and with the functions like Rigidbody.MovePosition, Rigidbody.AddForce and Rigidbody.velocity not by the transform or transform.Translate.
Also, you should move the Rigidbody Object in the FixedUpdate function instead of the Update function. If you are moving your other Rigidbody Objects by their transform then you must fix them too. The example below replaces transform.Translate with Rigidbody.MovePosition in the Fireball script:
public float speed = 10.0f;
public int damage = 1;
[SerializeField]
private GameObject wallHit;
private GameObject _wallHit;
public Rigidbody rb;
// Use this for initialization
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
//Move to towards Z-axis
Vector3 pos = new Vector3(0, 0, 1);
pos = pos.normalized * speed * Time.deltaTime;
rb.MovePosition(rb.transform.position + pos);
}
void OnTriggerEnter(Collider other)
{
RaycastHit hit;
PlayerCharacter player = other.GetComponent<PlayerCharacter>();
ReactiveTarget target = other.GetComponent<ReactiveTarget>();
WallBehavior wall = other.GetComponent<WallBehavior>();
if (player != null)
{
player.Hurt(damage);
}
if (target != null)
{
target.ReactToHit();
}
if (wall != null)
{
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
wall.WallWasHit(hit);
}
}
Destroy(this.gameObject);
}
If you still run into issues, use Rigidbody.velocity instead:
void FixedUpdate()
{
Vector3 pos = Vector3.zero;
pos.z = speed * Time.deltaTime;
rb.velocity = pos;
}
Sometimes, depending on the size of the object and the speed it is moving by, you many need to set its Rigidbody Interpolate from None to Interpolate and Collision Detection to Continuous.
Don't forget to remove the code in the Update function.
EDIT:
I looked at your project and found new problems:
1.You enabled IsTrigger on your "Fireball" GameObject. Please uncheck the IsTrigger on the collider.
2.You just want to shoot a bullet. The force should be added once only not every FixedUpdate. Add the force in the Start function instead of the FixedUpdate function. Use Rigidbody.velocity instead of Rigidbody.MovePosition.
Remove the FixedUpdate function and the code inside it.
This should be your new Start function:
void Start()
{
rb = GetComponent<Rigidbody>();
Vector3 pos = transform.forward * speed * Time.deltaTime;
rb.velocity = pos;
}