I was following a tutorial for creating an enemy in Unity, but they didn't teach how to flip the enemy in case the Player goes to the other side of the map, oppose to where the enemy is.
So I tried to increase the raycast area, so when the Player collides with it from behind, the enemy will know that it has to flip. But something isn't working, cause it goes fine to the Player when it's facing the left side of the map, but once it flips, it totally stops working, and I can't figure it out why.
Anyone have any idea what should I do?
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Skeleton : MonoBehaviour
{
#region Public Variables
public Transform rayCast;
public LayerMask raycastMask;
public GameObject target;
public float rayCastLength;
public float attackDistance; //Mininum distance to attack
public float moveSpeed;
public float timer; // Cooldown b/w attacks
public bool inRange; //check if the player is near
#endregion
#region Private Variables
private RaycastHit2D hit;
private Animator anim;
private float distance; //Distance b/w enemy and player
public bool attackMode;
private float intTimer;
#endregion
void Awake() {
intTimer = timer;
anim = GetComponent<Animator>();
}
void Update() {
if (inRange)
{
hit = Physics2D.Raycast(rayCast.position, Vector2.left, rayCastLength, raycastMask);
}
//When the player is detected
if(hit.collider != null)
{
EnemyLogic();
}
// If it's not inside the raycast
else if(hit.collider == null)
{
inRange = false;
}
// If the player leaves the range
if (inRange == false)
{
anim.SetBool("canWalk", false);
StopAttack();
anim.SetInteger("Idle", 0);
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player")
{
target = col.gameObject;
inRange = true;
Flip();
}
}
void EnemyLogic()
{
distance = Vector2.Distance(transform.position, target.transform.position);
if(distance > attackDistance)
{
Move();
StopAttack();
}
else if(attackDistance >= distance)
{
Attack();
}
}
void Move()
{
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", true);
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("attack"))
{
Vector2 targetPosition = new Vector2(target.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
void Attack()
{
timer = intTimer; //reset timer
attackMode = true;
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", false);
anim.SetBool("Attack", true);
}
void StopAttack()
{
attackMode = false;
anim.SetBool("Attack", false);
}
// Detects if the player is on the other side
void Flip()
{
Vector3 rotation = transform.eulerAngles;
if(target.transform.position.x < transform.position.x)
{
rotation.y = 180f;
}
else
{
rotation.y = 0f;
}
transform.eulerAngles = rotation;
}
}
You can flip the enemy using localScale. Do this:
if (Player.transform.position.x < this.transform.position.x)
{
transform.localScale = new Vector3(-1, 1, 1);
}else
{
transform.localScale = new Vector3(1, 1, 1);
}
This detects whenever the player's x position is greater or lower than the enemy and flips the whole object.
Related
When shooting a bullet or making a bomb explode, the player doesn't move as a projectile. Instead, they just move an unusually little distance. The players move as expected - a projectile, after reassigning groundCheck to "none", but the players themselves can't be moved any more. When colliding with a bullet or is in the range of a bomb, how can I change the code so that the player can move as a projectile without assigning groundCheck to "none" ?
Code of player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveWASDPlayer1 : MonoBehaviour
{
public float speed = 5;
public float jumpForce = 10;
private float moveInput;
private Rigidbody2D rb;
private bool facingRight = true;
private bool isGrounded;
public Transform groundCheck;
public float checkRadius = 0.5f;
public LayerMask whatIsGround;
private int extraJumps;
public int extraJumpsValue = 1;
public Sprite Player1Shoot;
public Sprite Player1idle;
public GameObject Player2;
public GameObject PistolBulletToRight, PistolBulletToLeft;
Vector2 PistolBulletPos;
public float fireRate;
public int remainingBullet = 10;
private void Start()
{
extraJumps = extraJumpsValue;
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
Physics2D.IgnoreLayerCollision(6, 7);
Shoot();
CheckJumps();
Flip();
StartCoroutine(Fire());
moveInput = Input.GetAxis("Horizontal1");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if (Input.GetKeyDown(KeyCode.S))
{
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.25f);
}
}
void CheckJumps()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);
if (isGrounded == true)
{
extraJumps = extraJumpsValue; ;
}
if (Input.GetKeyDown(KeyCode.W) && extraJumps > 0)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
extraJumps--;
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.48f);
}
else if (Input.GetKeyDown(KeyCode.W) && extraJumps == 0 && isGrounded == true)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
}
void Flip()
{
if (facingRight == false && moveInput > 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
else if (facingRight == true && moveInput < 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
void StopCollidingIntoGround()
{
Physics2D.IgnoreLayerCollision(3, 6, false);
}
void Shoot()
{
if (Input.GetKeyDown(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1Shoot;
}
if (Input.GetKeyUp(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1idle;
}
}
IEnumerator Fire()
{
PistolBulletPos = transform.position;
if (remainingBullet < 1)
{
yield return new WaitForSeconds(2);
remainingBullet = 10;
}
if (Input.GetKeyDown(KeyCode.Z) && remainingBullet > 0)
{
if (facingRight)
{
PistolBulletPos += new Vector2(+1f, -0.1f);
Instantiate(PistolBulletToRight, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
else
{
PistolBulletPos += new Vector2(-1f, -0.1f);
Instantiate(PistolBulletToLeft, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
}
}
}
Code of bomb:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bomb : MonoBehaviour
{
Collider2D[] inExplosionRadius = null;
[SerializeField] private float ExplosionForceMulti = 5;
[SerializeField] private float ExplosionRadius = 5;
private void Update()
{
if(Input.GetKeyDown(KeyCode.X))
{
Explode();
}
}
void Explode()
{
inExplosionRadius = Physics2D.OverlapCircleAll(transform.position, ExplosionRadius);
foreach(Collider2D o in inExplosionRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if(distanceVector.magnitude > 0)
{
float explosionForce = ExplosionForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, ExplosionRadius);
}
}
Code of bullet:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PistolBullet : MonoBehaviour
{
public float velX = 5f;
float velY = 0f;
Rigidbody2D rb;
Collider2D[] inShootRadius = null;
[SerializeField] public float ShootForceMulti = 5;
[SerializeField] public float ShootRadius = 5;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
rb.velocity = new Vector2(velX, velY);
Destroy(gameObject, 3f);
Shoot();
}
public void Shoot()
{
inShootRadius = Physics2D.OverlapCircleAll(transform.position, ShootRadius);
foreach (Collider2D o in inShootRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if (distanceVector.magnitude > 0)
{
float explosionForce = ShootForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
}
If I understand correctly: When getting hit by a bullet or explosion the player is not flung as expected?
I would argue this is the culprit: rb.velocity = new Vector2(moveInput * speed, rb.velocity.y); as you are overriding the player velocity every frame without taking in account the current velocity, unless moveInput has that calculated into.
As to why it works when GroundCheck is unassigned, because the script stops executing due to the missing reference beforehand and the Rigidbody will only be modified from the other scripts.
I Have been trying to figure out how the Enemy doesn't return multiple GameObjects it only returns one.Im not sure whether it is my Bullet script that it allows only one object to return. I'm currently trying to develop a Game with multiple players like Slither.io so I'm not sure if the performance is affected I would like to use (List Function) but dont know where to start and I'm using a later version Unity 2017.3.1f1. Much Appreciated for your help.The scripts are below.
public class RandomAIProjectile
{
private GameObject[] target;
public float speed;
Rigidbody2D bulletRB;
public GameObject explosionEffect;
// Find Targets Section.
void Start ()
{
if (target == null)
target = GameObject.FindGameObjectsWithTag("Player");
for (int i = 0; i < target.Length; i++)
{
bulletRB = GetComponent<Rigidbody2D> ();
Vector2 moveDir = (target[i].transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2 (moveDir.x, moveDir.y);
Destroy (this.gameObject, 2);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
// Decoy Script To Destroy Players.
if (other.gameObject.GetComponent<BlackthronpodDiePlayer>() != null)
{
Destroy (other.gameObject);
Destroy (gameObject);
}
// Damage Effect.
if (other.gameObject.tag == "Player") {
Instantiate (explosionEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
// Player (Bullet) Destroy Enemy.
if (other.CompareTag ("Bullet"))
{
Destroy (other.gameObject);
Destroy (gameObject);
}
}
}
Here is the Player Script
public class RandomAIEnemy
{
//Random Movement
public float speed;
public float waitTime;
public float startWaitTime;
public Transform moveSpots;
public float minX;
public float minY;
public float maxX;
public float maxY;
//Enemy AI Shooting
public float lineOfSite;
public float shootingRange;
public float fireRate = 1f;
private float nextFireTime;
public GameObject bullet;
public GameObject bulletParent;
// My Current Player
private BlackthronpodPlayerX playerX;
// Player AI
private GameObject[] player;
public GameObject blood;
Vector3 respawn = new Vector3 (-34f,0,0);
//Additional Info
void FixedUpdate ()
{
EnemyS ();
}
// Use this for initialization
void Start ()
{
//My Player AI Tag.
player = GameObject.FindGameObjectsWithTag("Player");
waitTime = startWaitTime;
//My Current Player Tag.
playerX = GameObject.FindGameObjectWithTag ("Player").GetComponent<BlackthronpodPlayerX>();
//Random Movement Reference
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
}
//Closest (My Player Including Player AI.)
private bool TryGetClosestPlayer(out GameObject closest)
{
var playersSortedByDistance = player.OrderBy(p => ((Vector2)p.transform.position - (Vector2)transform.position).sqrMagnitude);
closest = playersSortedByDistance.FirstOrDefault();
return closest;
}
void EnemyS ()
{
GameObject closestPlayer = null;
if(TryGetClosestPlayer (out closestPlayer))
{
var distanceFromPlayer = Vector2.Distance (closestPlayer.transform.position, transform.position);
if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}
// Range And Shooting Boundary For Player Including Player AI.
private void OnDrawGizmosSelected ()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere (transform.position, lineOfSite);
Gizmos.DrawWireSphere (transform.position, shootingRange);
}
// Random Movement (I).
void RandomMove ()
{
//Rotate Movement Of Enemy.
transform.position = Vector2.MoveTowards (transform.position, moveSpots.position, speed * Time.deltaTime);
if (Vector2.Distance (transform.position, moveSpots.position) < 0.2f)
{
if(waitTime <= 0)
{
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
waitTime = startWaitTime;
} else {
waitTime -= Time.deltaTime;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
// Damage Effect On Enemy.
if (collision.gameObject.tag.Equals ("Player"))
{
Instantiate(blood,transform.position, Quaternion.identity);
}
// My Players Health.
if (collision.CompareTag ("Player"))
{
playerX.health --;
Debug.Log(playerX.health);
Destroy(gameObject);
}
// Player Score Manager.
if (collision.tag == "Bullet")
{
Game.AddToScore(1);
Destroy(gameObject);
}
}
}
Make sure that you have Rigidbody2d attached on your enemy and player. And also, is there any error coming in the code?
The Setup
I have a basketball player with an animator and 5 assigned animations to that animator as followed:
PlayerIdle
PlayerWalk
PlayerJump
PlayerBend
PlayerShoot
Setup_FruitHoops
Player Animation Window with Parameters
The Problem
In PlayMode, the player is able to move and jump successfully. The issue comes when the player attempts to grab the apple that is on the ground. The desired game design that I wanted was for the player to bend over and grab the apple by pressing the G key and then press G again to throw the apple towards the hoop to score a point. However, when I run it and after I first press G, the player can no longer jump, grab, or throw. The below section is the code for PlayerMovement and GrabberScript. Any advice is greatly appreciated.
PlayerMovement.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed = 5f;
private Rigidbody2D rb;
private Animator anim;
private bool isGrounded, jumped;
private float jumpshotPower = 6f;
public Transform groundCheck;
public LayerMask groundLayer;
private void Awake()
{
rb = GameObject.Find("Player Parent").GetComponent<Rigidbody2D>();
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
CheckIfGrounded();
PlayerJump();
}
private void FixedUpdate()
{
PlayerWalk();
}
void PlayerWalk()
{
float h = Input.GetAxisRaw("Horizontal");
if (h > 0)
{
//going right
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(speed, rb.velocity.y);
ChangeDirection(-1);
}
else if (h < 0)
{
//going left
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(-speed, rb.velocity.y);
ChangeDirection(1);
}
else
{
//standing still
anim.SetBool("isWalking", false);
rb.velocity = new Vector2(0f, rb.velocity.y);
}
}
void ChangeDirection(int d)
{
Vector3 temp = transform.localScale;
temp.x = d;
transform.localScale = temp;
}
void CheckIfGrounded()
{
isGrounded = Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f, groundLayer);
if (isGrounded)
{
if (jumped)
{
jumped = false;
anim.SetBool("isJumping", false);
}
}
}
void PlayerJump()
{
if (isGrounded)
{
if (Input.GetKey(KeyCode.UpArrow))
{
jumped = true;
rb.velocity = new Vector2(rb.velocity.x, jumpshotPower);
anim.SetBool("isJumping", true);
}
}
}
}
GrabberScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrabberScript : MonoBehaviour
{
private bool grabbed, throwObject;
private RaycastHit2D hit;
public float distance;
public Transform holdpoint;
public float throwForce;
public LayerMask notFruitLayer;
private Animator anim;
private void Awake()
{
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
if (!grabbed)
{
//grab fruit
anim.Play("PlayerBend");
Physics2D.queriesStartInColliders = false;
hit = Physics2D.Raycast(transform.position, Vector3.down * transform.localScale.x, distance);
if(hit.collider != null && hit.collider.tag == "Apple")
{
grabbed = true;
}
}
else if(!Physics2D.OverlapPoint(holdpoint.position, notFruitLayer))
{
//throw fruit
grabbed = false;
if(hit.collider.gameObject.GetComponent<Rigidbody2D>() != null)
{
PlayerShooting();
}
}
if (grabbed)
{
hit.collider.gameObject.transform.position = holdpoint.position;
}
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * transform.localScale.x * distance);
}
void PlayerShooting()
{
if (grabbed == true)
{
if (Input.GetKey(KeyCode.G))
{
throwObject = true;
hit.collider.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(transform.localScale.x, 1) * throwForce;
anim.Play("PlayerShoot");
}
}
}
}
Below script uses a function whereas there first is a check if there is a object in range and if it, it is.
On pressing mouse key, the projectile is shooting towards the pivot point of that said object. I want the projectile to
always being able to fire (indifferent if the object is in range) and
shoot towards the crosshair (to the screen midpoint) and NOT towards the object pivot point.
I am a novice at coding and I can't see what code to remove and what to add.
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Events;
public struct ShootHit
{
public GameObject gameObject;
public Vector3 point;
}
[System.Serializable]
public class UnityEventShootHit : UnityEvent<ShootHit> { }
[DisallowMultipleComponent, AddComponentMenu("(つ♥v♥)つ/Useables/Shoot")]
public class ShootComponent : MonoBehaviour
{
[Header("Input")]
[Tooltip("Data that determines the input of player actions")]
[SerializeField] private InputProfile _inputProfile;
// [SerializeField] private float _range = 100.0f;
/* [Header("Sight Values")]
[Tooltip("How far the the sight can reach")]
public float sightRadius = 1f;
[Range(0f, 360f)]
public float fieldOfViewAngle = 100f;*/
[Header("Charge-up")]
[SerializeField] private float _chargeupTime = 0.5f;
private bool _isChargingPrimary = false;
private bool _isChargingSecondary = false;
[Header("Aim Assist")]
[SerializeField] private LayerMask _aimAssistLayerMask;
public float aimAssistRadius = 30.0f; // radius
[Range(0.0f, 360.0f)]
public float aimAssistMaxAngleToAssist = 45.0f; // angle
private ShootHit? _target;
//publics
public Transform shootOrigin;
[Header("Events")]
public UnityEventShootHit OnPrimaryFire;
public UnityEvent OnPrimaryFireStart;
public UnityEvent OnPrimaryFireStop;
public UnityEventShootHit OnSecondaryFire;
public UnityEvent OnSecondaryFireStart;
public UnityEvent OnSecondaryFireStop;
private void Start()
{
if (_inputProfile == null) Debug.LogError(gameObject.name + " does not
have a player input");
}
private void Update()
{
// Remove target if object is too far away
if (_target.HasValue)
{
if (Vector3.Distance(_target.Value.gameObject.transform.position,
transform.position) > aimAssistRadius)
{
_target = null;
}
}
if (_inputProfile.GetPrimaryFireButtonDown())
{
StopCoroutine(ChargeUpBeforeFireSecondary());
if (!_isChargingPrimary)
{
StartCoroutine(ChargeUpBeforeFirePrimary());
}
}
else if (_inputProfile.GetSecondaryFireButtonDown())
{
StopCoroutine(ChargeUpBeforeFirePrimary());
if (!_isChargingSecondary)
{
StartCoroutine(ChargeUpBeforeFireSecondary());
}
}
if (_inputProfile.GetPrimaryFireButton() ||
_inputProfile.GetSecondaryFireButton())
{
if (!_target.HasValue) _target = GetObjectClosestToAim();
if (_inputProfile.GetPrimaryFireButton())
{
OnPrimaryFire.Invoke(_target.Value);
}
if (_inputProfile.GetSecondaryFireButton())
{
OnSecondaryFire.Invoke(_target.Value);
}
}
else
{
_target = null;
}
if (_inputProfile.GetPrimaryFireButtonUp())
OnPrimaryFireStop.Invoke();
if (_inputProfile.GetSecondaryFireButtonUp())
OnSecondaryFireStop.Invoke();
}
/// <summary>
/// Finds the object within range closest to the players forward-vector
using _aimAssistLayerMask.
/// </summary>
/// <returns>Returns object closest to aim if any object is found, else
returns null.</returns>
ShootHit? GetObjectClosestToAim()
{
// Raycast
RaycastHit hit;
if (Physics.Raycast(shootOrigin.position, Camera.main.transform.forward,
out hit, aimAssistRadius, _aimAssistLayerMask))
{
if (hit.transform?.GetComponent<IShootTarget>() != null)
{
Debug.Log(hit.transform.name);
return new ShootHit { gameObject = hit.transform.gameObject,
point = hit.point };
}
}
float _closestDot = -2f;
GameObject _closestDotObject = null;
RaycastHit[] _hit = Physics.SphereCastAll(transform.position,
aimAssistRadius, transform.forward, 0, _aimAssistLayerMask,
QueryTriggerInteraction.Ignore);
// Get best dot from all objects within range
for (int i = 0; i < _hit.Length; i++)
{
if (_hit[i].transform.gameObject == this.gameObject ||
_hit[i].transform.GetComponent<IShootTarget>() == null)
continue;
Vector3 _dif = _hit[i].transform.position - transform.position;
float _newDot = Vector3.Dot(transform.forward.normalized,
_dif.normalized);
if (_newDot > _closestDot)
{
_closestDot = _newDot;
_closestDotObject = _hit[i].transform.gameObject;
}
}
if (!_closestDotObject)
return null;
// Make sure there are no object in the way of our best-dot-object
Collider[] colliders = _closestDotObject.GetComponents<Collider>();
Vector3 point = colliders[0].ClosestPoint(shootOrigin.position);
float distanceToPoint = Vector3.Distance(shootOrigin.position, point);
// Get closest collider
for (int i = 1; i < colliders.Length; i++)
{
Vector3 newPoint = colliders[i].ClosestPoint(shootOrigin.position);
float newDistanceToPoint = Vector3.Distance(shootOrigin.position,
newPoint);
if (distanceToPoint > newDistanceToPoint)
{
point = newPoint;
distanceToPoint = newDistanceToPoint;
}
}
RaycastHit _rayhit;
if (Physics.Raycast(shootOrigin.position, point - transform.position,
out _rayhit, aimAssistRadius, _aimAssistLayerMask))
{
if (_rayhit.transform.gameObject != _closestDotObject)
{
return null;
}
}
Vector3 _vecToClosest = _closestDotObject.transform.position -
transform.position;
if (Vector3.Angle(transform.forward, _vecToClosest) <=
aimAssistMaxAngleToAssist)
{
return new ShootHit { gameObject = _closestDotObject, point = point
};
}
else
{
return null;
}
}
IEnumerator ChargeUpBeforeFirePrimary()
{
_isChargingPrimary = true;
yield return new WaitForSeconds(_chargeupTime);
_isChargingPrimary = false;
OnPrimaryFireStart.Invoke();
}
IEnumerator ChargeUpBeforeFireSecondary()
{
_isChargingSecondary = true;
yield return new WaitForSeconds(_chargeupTime);
_isChargingSecondary = false;
OnSecondaryFireStart.Invoke();
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (!Application.isPlaying) return;
Color oldColor = Gizmos.color;
float halfFeildOfView = aimAssistMaxAngleToAssist * 0.5f;
float coneDirection = -90f;
Quaternion leftRayRotation = Quaternion.AngleAxis(-halfFeildOfView + coneDirection, Vector3.up);
Quaternion rightRayRotation = Quaternion.AngleAxis(halfFeildOfView + coneDirection, Vector3.up);
Vector3 leftRayDirection = leftRayRotation * transform.right * aimAssistRadius;
Vector3 rightRayDirection = rightRayRotation * transform.right * aimAssistRadius;
// Green Arc
Handles.color = new Color(0f, 1f, 0f, 0.25f);
Handles.DrawSolidArc(transform.position, Vector3.up, leftRayDirection, aimAssistMaxAngleToAssist, aimAssistRadius);
Gizmos.color = oldColor;
}
#endif
}
`
This is the code attached to the projectile
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Rigidbody))]
public class ProjectileScript : MonoBehaviour
{
public GameObject Explosion;
public Transform Target;
Rigidbody _rigidbody;
public float speed = 1.0f;
void Start()
{
_rigidbody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
// _rigidbody.AddForce((Target.position - transform.position).normalized, ForceMode.Impulse);
Collider targetCollider = Target.GetComponent<Collider>();
Vector3 targetDirection;
if (targetCollider)
targetDirection = targetCollider.ClosestPoint(transform.position) - transform.position;
else
targetDirection = Target.position - transform.position;
_rigidbody.velocity = targetDirection.normalized * speed;
if (Vector3.Distance(transform.position, Target.position) < 1.0f)
{
//make the explosion
GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;
//destory the projectile
Destroy(gameObject);
}
}
public void SetTarget(GameObject target)
{
this.Target = target.transform;
}
public void SetTarget(ShootHit hit) => SetTarget(hit.gameObject);
}
This script is how and where the Projectile Spawns. It is attached to an empty gameobject located on the muzzle of the gun.
public class ProjectileSpawner : MonoBehaviour
{
public GameObject projectileInsert;
public GameObject projectileExtract;
public float projectileSpeed = 1.0f;
GameObject projectile;
public void Insert(GameObject target)
{
if (projectile) return;
projectile = Instantiate(projectileInsert, transform.position, Quaternion.identity);
ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
projectileScript.SetTarget(target);
projectileScript.speed = projectileSpeed;
// Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
// projectileSpawn.parent.GetComponent<Collider>());
}
public void Extract(GameObject target)
{
if (projectile) return;
projectile = Instantiate(projectileExtract, target.transform.position, Quaternion.identity);
ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
projectileScript.SetTarget(gameObject);
projectileScript.speed = projectileSpeed;
// Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
// projectileSpawn.parent.GetComponent<Collider>());
}
}
In the ProjectileSpawner, add a LayerMask field to filter out invalid collisions (set it in the inspector) for the non-homing projectile. You'll set this in the inspector to make the non-homing projectiles collide with the desired layers:
public LayerMask collisionLayers;
In Insert, find the ray going from the screen's center, and use it and the LayerMask as a parameter to SetTarget:
public void Insert(GameObject target)
{
if (projectile) return;
Ray centerRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width/2, Screen.height/2, 0f));
projectile = Instantiate(projectileInsert, transform.position, Quaternion.identity);
ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
projectileScript.SetTarget(centerRay, collisionLayers);
projectileScript.speed = projectileSpeed;
// Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
// projectileSpawn.parent.GetComponent<Collider>());
}
public void Extract(GameObject target)
{
if (projectile) return;
projectile = Instantiate(projectileExtract, target.transform.position, Quaternion.identity);
ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
projectileScript.SetTarget(gameObject);
projectileScript.speed = projectileSpeed;
// Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
// projectileSpawn.parent.GetComponent<Collider>());
}
Then in the ProjectileScript, add a bool field to remember if the projectile homes on a gameObject or if it follows a ray, a Ray field to remember such a ray, and a LayerMask field to remember what to collide with:
public bool isHoming;
public Ray TargetRay
public LayerMask collisionLayers;
Then, in public void SetTarget(GameObject target), set that bool to true:
public void SetTarget(GameObject target)
{
this.Target = target.transform;
isHoming = true;
}
And make a new public void SetTarget(Ray shootRay) that remembers a Ray and LayerMask and sets the bool to false:
public void SetTarget(Ray shootRay, LayerMask collisionLayers)
{
this.TargetRay = shootRay;
this.collisionLayers = collisionLayers;
isHoming = false;
}
Also, in ProjectileScript, you will need to change the FixedUpdate method to check if the bool is true, and if it is, then do the same as before. Otherwise, move along the ray and destroy it if it travels too far:
public float maxDistanceBeforeDestroy = 100f;
...
void FixedUpdate()
{
if (isHoming)
{
// _rigidbody.AddForce((Target.position - transform.position).normalized, ForceMode.Impulse);
Collider targetCollider = Target.GetComponent<Collider>();
Vector3 targetDirection;
if (targetCollider)
targetDirection = targetCollider.ClosestPoint(transform.position) - transform.position;
else
targetDirection = Target.position - transform.position;
_rigidbody.velocity = targetDirection.normalized * speed;
if (Vector3.Distance(transform.position, Target.position) < 1.0f)
{
//make the explosion
GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;
//destory the projectile
Destroy(gameObject);
}
}
else
{
_rigidbody.velocity = TargetRay.direction.normalized * speed;
// Check if it has traveled too far
if ((transform.position - TargetRay.origin).magnitude > maxDistanceBeforeDestroy )
{
Destroy(gameObject);
}
}
}
Then, add an OnCollisionEnter method that doesn't do anything if the projectile is homing. But if it isn't, it checks if the collision matches the LayerMask, and if it does, it makes the explosion and destroys the projectile:
void OnCollisionEnter(Collision other)
{
if (isHoming)
{
return;
}
if( && ((1<<other.gameObject.layer) & collisionLayers) != 0)
{
//make the explosion
GameObject ThisExplosion = Instantiate(Explosion,
gameObject.transform.position,
gameObject.transform.rotation) as GameObject;
//destroy the projectile
Destroy(gameObject);
}
}
Your question is a bit vague and doesn't look like you have put a lot of effort into understanding the code and trying to alterate it. Anyway I'll do my best.
always being able to fire (indifferent if the object is in range)`
probably simply set aimAssistRadius = 0; or entirely remove the check
if (Vector3.Distance(_target.Value.gameObject.transform.position, transform.position) > aimAssistRadius)
{
_target = null;
}
shoot towards the crosshair (to the screen midpoint) and NOT towards the object pivot point.
The script you posted (probably not yours) seems to have the entire purpose of doing what you not want to do: Aim assist. Removing it probably changes a lot of things but the simpliest would be to simply set the ProjectileScript._rigidbody.velocity in the moment the projectile is instantiated. Unfortunately you didn't provide the code where this happens.
I don't see in which moment your ShootComponent interacts with the ProjectileScript but probably in one of those UnityEvents ... ?
But in general it would maybe simply look like
public class ProjectileScript : MonoBehaviour
{
public float speed = 1.0f;
private RigidBody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<RigidBody>();
}
public void SetDirection(Vector3 direction)
{
_rigidbody.velocity = direction.normalized * speed;
}
}
and whereever you Instantiate the projectile do
var projectile = instantiatedObject.GetComponent<ProjectileScript>();
var direction = Camera.main.transform.forward;
projectile.SetDirection(direction);
as you can see you will have to make the
if (Vector3.Distance(transform.position, Target.position) < 1.0f)
{
//make the explosion
GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;
//destory the projectile
Destroy(gameObject);
}
happen somewhere else since the code will not be target based anymore ... I would probably use OnCollisionEnter instead something like e.g.
private void OnCollisionEnter(Collision collision)
{
// maybe only collide with a certain tag
if(collision.gameObject.tag != "Target") return;
//make the explosion
GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;
//destory the projectile
Destroy(gameObject);
}
So I have enemy gameobjects attacking a user in a small base. The enemies have an OnCollisionEnter method where it checks to see what it collides with. If it's tagged as the base, it sets an attack boolean to true, where the fixedupdate is supposed to check for that flag. When true, it calls a coroutine in which I try and call the method that removes health from the wall (this script is attached to the wall). The walls health is then displayed on a HUD I have elsewhere in the room Code Below
Problem is, enemies can't do damage to the base and the HUD remains unchanging. Any tips/help? Here is the enemy behaviour script
public class EnemyBehaviour : MonoBehaviour {
private GameObject target;
private Vector3 targetPos;
private WallBehaviour wallBehaviour;
public GameObject collisionObject;
private bool attackMode;
public float speed = 0.1f;
public int hp = 100;
public float attackCooldown = 1.0f;
public int attackPoints = 1;
public float killThreshhold = 1.5f;
public Color defaultColor;
//Use this for initialization
void Start() {
target = GameObject.FindGameObjectWithTag("MainCamera");
targetPos = target.transform.position;
attackMode = false;
}
void FixedUpdate() {
targetPos = target.transform.position;
transform.LookAt(target.transform);
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPos, step);
if (attackMode)
{
StartCoroutine("attemptAttack");
}
else
{
GetComponent<Renderer>().material.color = defaultColor;
}
}
void OnCollisionEnter(Collision collision)
{
collisionObject = collision.gameObject;
if (collision.gameObject.tag == "Bunker") {
wallBehaviour = collision.gameObject.GetComponent<WallBehaviour>();
attackMode = true;
}
}
public IEnumerator Attack()
{
attackMode = false;
GetComponent<Renderer>().material.color = Color.red;
wallBehaviour.ProcessDamage(attackPoints);
yield return new WaitForSeconds(attackCooldown);
attackMode = true;
}
void ProcessDamage(int attackPoints)
{
hp -= attackPoints;
if (hp <= 0)
{
Die();
}
}
public int getHitPoints()
{
return hp;
}
public void Damage(DamageInfo info)
{
hp -= info.damage;
if (hp <= 0) {
Die();
}
}
public void Die()
{
Destroy(gameObject);
}