Not sure why, I've done this sort of this a bunch of times, but this is giving me some issues. Making a project for Game AI, I have a whole bunch of stuff already done, now just making some turrets that if the player is in a certain range it will fire, which I have already. The turret fires the bullet and then for some reason they just start destroying themselves and they don't go towards my player. Wondering if anyone on here can help, thanks in advance!
Some details you may need to know:
I have a Base, a Gun nose and a Gun for my turret. My Gun has a GunLook.cs script that makes it look at the player (so when they shoot it should go towards them), I'm not sure if that has anything to do with why I'm having these issues, but I'll post that code as well just incase
How my Hierchy for my turret is
Turret_AI (Base)
Gun (child of Turret_AI)
bulletSpawn (child of Gun)
Gun_Nose (child of turret_AI)
bulletSpawn is an empty GameObject I created in hopes to solve my problem. I set it just off the Gun so that it wouldn't just collide with gun and destroy itself (what I thought it might be doing, but not correct).
That should be all the info needed, if anyone needs more I will be checking this every 2 seconds so let me know and I will get back to you with quick response.
TurretScript.cs
(I did set the GameObject to Player in Unity, before anyone asks)
using UnityEngine;
using System.Collections;
public class TurretScript : MonoBehaviour {
[SerializeField]
public GameObject Bullet;
public float distance = 3.0f;
public float secondsBetweenShots = 0.75f;
public GameObject followThis;
private Transform target;
private float timeStamp = 0.0f;
void Start () {
target = followThis.transform;
}
void Fire() {
Instantiate(Bullet, transform.position , transform.rotation);
Debug.Log ("FIRE");
}
void Update () {
if (Time.time >= timeStamp && (target.position - target.position).magnitude < distance) {
Fire();
timeStamp = Time.time + secondsBetweenShots;
}
}
}
GunLook.cs
// C#
using System;
using UnityEngine;
public class GunLook : MonoBehaviour
{
public Transform target;
void Update()
{
if(target != null)
{
transform.LookAt(target);
}
}
}
BulletBehavior.cs
using UnityEngine;
using System.Collections;
public class BulletBehavior : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (rigidbody.velocity.magnitude <= 0.5)
Destroy (gameObject);
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider)
{
if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyProjectile")
{
Physics.IgnoreCollision(rigidbody.collider,collision.collider);
//Debug.Log ("Enemy");
}
if(collision.gameObject.tag == "SolidObject")
{
Destroy(gameObject);
}
if(collision.gameObject.tag == "Player")
{
Destroy(gameObject);
}
}
}
}
You're never moving your bullet.
public class BulletBehavior : MonoBehaviour
{
private const float DefaultSpeed = 1.0f;
private float startTime;
public Vector3 destination;
public Vector3 origin;
public float? speed;
public void Start()
{
speed = speed ?? DefaultSpeed;
startTime = Time.time;
}
public void Update()
{
float fracJourney = (Time.time - startTime) * speed.GetValueOrDefault();
this.transform.position = Vector3.Lerp (origin, destination, fracJourney);
}
}
Then call it like so:
void Fire()
{
GameObject bullet = (GameObject)Instantiate(Bullet, transform.position , transform.rotation);
BulletBehavior behavior = bullet.GetComponent<BulletBehavior>();
behavior.origin = this.transform.position;
behavior.destination = target.transform.position;
Debug.Log ("FIRE");
}
Note: If you're trying to mix this approach with trying to use physics to move the bullet you may end up with strange results.
Related
So I'm developing my first game in Unity currently (following a series by Mister Taft on YouTube called "Make a game like Zelda using Unity and C#" and just finished the 19th video).
I've currently got a "Log" enemy and am working on a knockback feature. I've followed the way that it is approached in the series is by creating a state machine that changes the Log's state to "stagger" for a couple of seconds, then return it to "idle" so it can change itself to "walk."
Whenever I hit the Log, however, it gets stuck in the stagger state and drifts without stopping until it hits a collider (note it doesn't change back to idle/walk even when it does hit the collider). If I can hit the Log correctly, sometimes, the player will actually also drift in the opposite direction.
Relevant code:
public class Log : Enemy {
private Rigidbody2D myRigidBody;
public Transform target;
public float chaseRadius;
public float attackRadius;
public Transform homePosition;
public Animator anim;
// Use this for initialization
void Start () {
currentState = EnemyState.idle;
myRigidBody = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
target = GameObject.FindWithTag ("Player").transform;
}
// FixedUpdate is called by physics.
void FixedUpdate () {
CheckDistance ();
}
//Log finds and walks towards Player.
void CheckDistance(){
if (Vector3.Distance (target.position, transform.position) <= chaseRadius && Vector3.Distance (target.position, transform.position) > attackRadius
&& currentState != EnemyState.stagger)
{
Vector3 temp = Vector3.MoveTowards (transform.position, target.position, moveSpeed * Time.deltaTime);
myRigidBody.MovePosition (temp);
ChangeState (EnemyState.walk);
}
}
private void ChangeState(EnemyState newState){
if (currentState != newState)
{
currentState = newState;
}
}
}
public class Knockback : MonoBehaviour {
public float thrust;
public float knockTime;
private void OnTriggerEnter2D(Collider2D other){
if (other.gameObject.CompareTag ("breakable"))
{
other.GetComponent<Pot>().Smash();
}
if(other.gameObject.CompareTag("enemy"))
{
Rigidbody2D enemy = other.GetComponent<Rigidbody2D>();
if (enemy != null)
{
enemy.GetComponent<Enemy> ().currentState = EnemyState.stagger;
Vector2 difference = enemy.transform.position - transform.position;
difference = difference.normalized * thrust;
enemy.AddForce (difference, ForceMode2D.Impulse);
StartCoroutine (KnockCo (enemy));
}
}
}
private IEnumerator KnockCo(Rigidbody2D enemy){
if (enemy != null)
{
yield return new WaitForSeconds (knockTime);
enemy.velocity = Vector2.zero;
enemy.GetComponent<Enemy>().currentState = EnemyState.idle;
}
}
}
public enum EnemyState{
idle,
walk,
attack,
stagger
}
public class Enemy : MonoBehaviour {
public EnemyState currentState;
public int enemyHealth;
public string enemyName;
public int baseAttack;
public float moveSpeed;
}
I've tried to add an else statement after the void CheckDistance in Log.cs, but that resulted in the Log having jittery movement and jumping back along its path. I'm at a loss. Any help would be greatly appreciated!
I am trying to increase the damage of the players fireball when a power up is picked up. I am getting an object reference error, I'm pretty sure this is due to the code being linked tot he player for the collision and the fireballs have their own script detailing their speed, damage etc.
Essentially I need a way to reference my fireball prefab (Called Bullet) so the code can access the 'damage' stat and increase it for a period of time.
The code for the power-up is:-
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Pickup(other);
}
}
void Pickup(Collider2D player)
{
Instantiate(pickupEffect, transform.position, transform.rotation);
Fire stats = GetComponent<Fire>();
stats.damage *= 2;
Destroy(gameObject);
}
}
**The code for the fireball prefabs (known as Fire) is:-**
public class Fire : MonoBehaviour
{
public Animator animator;
public float speed = 20f;
public int damage = 30;
public Rigidbody2D rb;
public GameObject FireEmbers;
public float liveTime = 1f;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
void OnTriggerEnter2D(Collider2D hitInfo)
{
Enemy enemy = hitInfo.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
void Update()
{
liveTime -= Time.deltaTime;
if (liveTime <= 0)
{
Destroy(this.gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
}
}
I actually resolved this by using scriptable objects instead of hard coding things into prefabs.
So I am trying to make the player a child to the moving platform which is being moved by looking for waypoints and going to them. But when I make the player collide with the platform the collision enter is not detecting the player thus not making the player stay on it, it instead glides off.enter image description here
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movePlatform : MonoBehaviour
{
public GameObject[] waypoints;
float rotSpeed;
int current = 0;
public float speed;
float WPradius = 1;
private GameObject target = null;
private Vector3 offset;
public GameObject Player;
CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
//This will make the player a child of the Obstacle
controller.transform.parent = other.gameObject.transform;
}
}
void OnTriggerExit(Collider other)
{
controller.transform.parent = null;
}
// Update is called once per frame
void Update()
{
if (Vector3.Distance(waypoints[current].transform.position, transform.position) < WPradius)
{
current++;
if (current >= waypoints.Length)
{
current = 0;
}
}
transform.position = Vector3.MoveTowards(transform.position, waypoints[current].transform.position, Time.deltaTime * speed);
}
}
This will not make the player a child of the platform:
controller.transform.parent = other.gameObject.transform;
Because here controller is the CharacterController instance, and other refers to the player collider. So they both refers to the player transform in the end.
Replace it by something like
other.transform.parent = transform;
or
controller.transform.parent = transform;
(Here, transform refers to the platform transform.)
If the OnTriggerEnter() is not detecting, check if your collider has isTrigger enabled. Or change the method to OnCollisionEnter().
If you are making a 2D game, switch these methods to the 2D version (=> OnCollisionEnter2D or OnTriggerEnter2D).
I want the player to take damage whenever the enemy is near, the enemy will take damage but the player doesn't(i tried taking away the function that kills the enemy to check if it is too quick). I am quite new to unity and this is one of my first "independent" scripts, so it may be a quite obvious error. There are no errors or warnings however.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttackableScript : MonoBehaviour {
public float health;
public float attackSpeed;
public float damage;
public float radious = 3f;
public Transform enemyArea;
bool dead = false;
public GameObject player;
public float KillCount;
public void Die()
{
Debug.Log(health);
health = health - 0.04f;
if (health == 0f)
{
dead = true;
}
}
IEnumerator Attack()
{
GameObject thePlayer = GameObject.Find("player");
PlayerMovement playerScript = thePlayer.GetComponent<PlayerMovement>();
playerScript.playerHealth = playerScript.playerHealth - damage;
yield return new WaitForSeconds(attackSpeed);
Debug.Log("player health = " + playerScript.playerHealth);
}
void Update() {
float distance = Vector3.Distance(player.transform.position, enemyArea.position);
if (distance <= radious && dead != true)
{
Attack();
}
if (health <= 0)
{
health = 0;
Destroy(gameObject);
Destroy(this);
}
}
}
the game is 2d.
I asked a discord and they pointed out my misuse of coroutines, i forgot to start one when i called the attack function. So instead of Attack() , it was StartCoroutine(Attack());
im having a problem from my enemyDamage script in unity5 when i play it and stick to the enemy i died instantly even the enemy damage is 10 and my health was 100
well this is my first time to make this things on unity hope you helps me :(
heres my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemydmg : MonoBehaviour {
public float damage;
public float damagerate;
public float pushbackforce;
float nextdamage;
bool playerInRange = false;
GameObject theplayer;
playerHealth theplayerhealth;
// Use this for initialization
void Start () {
nextdamage = Time.time;
theplayer = GameObject.FindGameObjectWithTag ("Player");
theplayerhealth = theplayer.GetComponent<playerHealth> ();
}
// Update is called once per frame
void Update () {
if (playerInRange)
Attack ();
}
void OnTriggerEnter (Collider other)
{
if (other.tag == "Player")
{
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
if (other.tag == "Player")
{
playerInRange = false;
}
}
void Attack()
{
if (nextdamage <= Time.time)
{
theplayerhealth.addDamage(damage);
nextdamage = Time.time + damagerate;
pushback (theplayer.transform);
}
}
void pushback(Transform pushObject)
{
Vector3 pushDirection = new Vector3 (0, (pushObject.position.y - transform.position.y), 0).normalized;
pushDirection *= pushbackforce;
Rigidbody pushedRB = pushObject.GetComponent<Rigidbody> ();
pushedRB.velocity = Vector3.zero;
pushedRB.AddForce (pushDirection, ForceMode.Impulse);
}
}
and this was my playerhealth
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerHealth : MonoBehaviour {
public float fullhealth;
float currentHealth;
// Use this for initialization
void Start () {
currentHealth = fullhealth;
}
// Update is called once per frame
void Update () {
}
public void addDamage(float damage)
{
currentHealth -= damage;
if (currentHealth <= 0) {
makeDead ();
}
}
public void makeDead()
{
Destroy (gameObject);
}
}
theplayerhealth = theplayer.GetComponent<playerHealth> ();
I think this line of code fails you because the player is a GameObject. theplayerhealth is or should already be initialized in your other script. I think you could approach polymorphism in a better way.
public class enemydmg : playerHealth{
}
This will allow you to directly inherit everything you need from the playerHealth script without having to grab extra components. You can also use this technique for may other scripts in the future.
Another approach that you could use is calling your class directly:
playerHealth.addDamage(damage);
From now on when you name your scripts use capitalization. PlayerHealth, EnemyDamage, etc... That's just a pro-tip to make your code look a bit cleaner when you're doing things like this. (Optional)