Character does not "see" the player (3D Game) - c#

I am following this unity 3D course. I followed every single step of the part called "Enemies Part 1: Static Observers", and after re-checking the code and doing researches for a day, I still did not find the problem. The scope of this part of the tutorial is to make that when the "Gargoyle" sees the player, when passing in front of him, should restart the game.
These are the two scripts that should make this work, but don't.
Observer (Gargoyle):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Observer : MonoBehaviour
{
public Transform player;
public GameEnding gameEnding;
bool m_IsPlayerInRange;
void OnTriggerEvent(Collider other)
{
if (other.transform == player)
{
m_IsPlayerInRange = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.transform == player)
{
m_IsPlayerInRange = false;
}
}
void Update()
{
if (m_IsPlayerInRange)
{
Vector3 direction = player.position - transform.position + Vector3.up;
Ray ray = new Ray(transform.position, direction);
RaycastHit raycastHit;
if (Physics.Raycast(ray, out raycastHit))
{
if (raycastHit.collider.transform == player)
{
gameEnding.CaughtPlayer();
}
}
}
}
}
And this is the GameEnding script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameEnding : MonoBehaviour
{
public float fadeDuration = 1f;
public float displayImageDuration = 1f;
public GameObject player;
public CanvasGroup exitBackgroundImageCanvasGroup;
public CanvasGroup caughtBackgroundImageCanvasGroup;
bool m_IsPlayerAtExit;
bool m_IsPlayerCaught;
float m_Timer;
void OnTriggerEnter(Collider other)
{
if (other.gameObject == player)
{
m_IsPlayerAtExit = true;
}
}
public void CaughtPlayer()
{
m_IsPlayerCaught = true;
}
void Update()
{
if (m_IsPlayerAtExit)
{
EndLevel(exitBackgroundImageCanvasGroup, false);
}
else if (m_IsPlayerCaught)
{
EndLevel(caughtBackgroundImageCanvasGroup, true);
}
}
void EndLevel(CanvasGroup imageCanvasGroup, bool doRestart)
{
m_Timer += Time.deltaTime;
imageCanvasGroup.alpha = m_Timer / fadeDuration;
if (m_Timer > fadeDuration + displayImageDuration)
{
if (doRestart)
{
SceneManager.LoadScene(0);
}
else
{
Application.Quit();
}
}
}
}
Back to the unity editor, I set the variables (player, gameending, exitimagebackground and caught imagebackground.
Does anybody know what the problem is and could help me out?
Thank you!
Edit:
these are the components of the Player Character:
and these of the Gargoyle:
Which has these as children:
which have these other components:

On your Observer class,
void OnTriggerEvent(Collider other)
{
if (other.transform == player)
{
m_IsPlayerInRange = true;
}
}
The function name is OnTriggerEvent(Collider), it should be OnTrigger**Enter**(Collider) instead.
Otherwise, it should work as intended.

Related

I want to enable my collider again after disabling it

When my character hits the gameobject collider, an enemy will be spawned and the collider is disabled, cuz I do not want to spawn multiple enemies. When my character dies and I have to start from the beginning, the collider should be enabled again to spawn the enemy again.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerSpawner : MonoBehaviour
{
public EnemySpawn enemyspawn;
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
enemyspawn.SpawnEnemy();
gameObject.GetComponent<BoxCollider2D>().enabled = false;
}
}
}
//in other class
private void SetHealth(float health)
{
var actualNextHealth = Mathf.Min(m_maxHealth, health);
m_currentHealth = actualNextHealth;
if (m_healthBar != null && m_maxHealth > 0f)
m_healthBar.SetHealth(actualNextHealth / m_maxHealth);
if (m_currentHealth <= 0f)
{
UpdateHighscore();
Die();
}
}
private void Die()
{
m_character.NotifyDied();
if (m_canRespawn)
{
SetVulnerable();
RemovePoison();
m_hazards.Clear();
gameObject.transform.position = m_spawnPosition;
SetHealth(m_maxHealth);
}
else {
Destroy(gameObject);
}
}
You can create a static variable in the trigger script that you assign the Collider value to it.
When an enemy is spawned it deactivates, as in your code.
public class TriggerSpawner : MonoBehaviour
{
public static Collider2D spawnCollider;
public EnemySpawn enemyspawn;
void Start() => spawnCollider.GetComponent<Collider2D>();
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
enemyspawn.SpawnEnemy();
spawnCollider.enabled = false;
}
}
}
When you die, it will reactivate.
private void Die()
{
m_character.NotifyDied();
if (m_canRespawn)
{
TriggerSpawner.spawnCollider.enabled = true;
SetVulnerable();
RemovePoison();
m_hazards.Clear();
gameObject.transform.position = m_spawnPosition;
SetHealth(m_maxHealth);
}
else {
Destroy(gameObject);
}
}
With minimal changes on your code, I'd suggest this:
private void Die()
{
m_character.NotifyDied();
if (m_canRespawn)
{
SetVulnerable();
RemovePoison();
m_hazards.Clear();
gameObject.transform.position = m_spawnPosition;
SetHealth(m_maxHealth);
gameObject.GetComponent<BoxCollider2D>().enabled = true; // add this line
}
else {
Destroy(gameObject);
}
}

The Spawned enemy only moves, but not shoots in unity

I am new to unity. Recently, I have started making a survival fps game, there, I have 1 enemy, when I kill him, it will spawn more enemies. However, the spawned only move, but not shoot. Although, I have attached a script to it. here are all my code.
prefab_shooting-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class prefab_shooting : MonoBehaviour
{
public float damage = 1f;
public float range = 100f;
public GameObject player;
public GameObject enemy;
private void Start()
{
player = GameObject.FindWithTag("Player");
enemy = GameObject.FindWithTag("PBR");
}
private void Update()
{
if (Vector3.Distance(transform.position, player.transform.position) < 25.0f)
{
Debug.Log(damage);
}
}
void Shoot()
{
RaycastHit hit;
if (Physics.Raycast(enemy.transform.position, enemy.transform.forward, out hit, range))
{
if (hit.transform.tag == "Player")
{
swat_death swat = hit.transform.GetComponent<swat_death>();
// Debug.Log(damage);
}
}
}
}
PBR_shooting (the enemy shooting)-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PBR_shooting : MonoBehaviour
{
public float damage = 1f;
public float range = 100f;
public GameObject player;
public GameObject enemy;
private void Start()
{
player = GameObject.FindWithTag("Player");
enemy = GameObject.FindWithTag("PBR");
}
private void Update()
{
if (Vector3.Distance(transform.position, player.transform.position) < 25.0f)
{
Shoot();
}
}
void Shoot()
{
RaycastHit hit;
if(Physics.Raycast(enemy.transform.position, enemy.transform.forward, out hit, range))
{
if(hit.transform.tag == "Player")
{
swat_death swat = hit.transform.GetComponent<swat_death>();
// Debug.Log(swat.health);
swat.TakeDamage(damage);
}
}
}
Swat_death (player_death) -
using UnityEngine;
using UnityEngine.SceneManagement;
public class swat_death : MonoBehaviour
{
static float health = 250f;
public GameObject player;
public void TakeDamage(float amount)
{
health -= amount;
Debug.Log(health);
if (health <= 0f)
{
Debug.Log("STOP");
SceneManager.LoadScene("death_scene");
}
}
void Die()
{
}
private void OnCollisionEnter(Collision collision)
{
if(collision.transform.tag == "enemy_bullet")
{
//SceneManager.LoadScene("death_scene");
}
}
}
And the PBR_Death (from where the spawning starts) -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PBR_death : MonoBehaviour
{
public GameObject player;
Animator anim;
public int XPos;
public int ZPos;
public GameObject TheEnemy;
public int enemyCount = 0;
public int points = 1;
public GameObject enemyGameObject;
void Start()
{
anim = GetComponent<Animator>();
enemyGameObject = GameObject.FindWithTag("PBR");
}
// Update is called once per frame
void OnCollisionEnter(Collision collision)
{
if (collision.transform.tag == "bullet")
{
anim.SetTrigger("isDying");
enemy_movement enemy = GetComponent<enemy_movement>();
enemy.enabled = false;
PBR_shooting shoot = GetComponent<PBR_shooting>();
shoot.enabled = false;
scoreManager.score += points;
GameObject go = Instantiate(enemyGameObject, new Vector3(Random.Range(34, 0), Random.Range(34, 0), 0), Quaternion.identity) as GameObject;
go.AddComponent<prefab_movement>();
go.AddComponent<prefab_death>();
go.AddComponent<prefab_shooting>();
// StartCoroutine(EnemySpawner());
Destroy(collision.gameObject);
}
}
Pls help me, I am stuck in this for almost 3 days..
You didn't call the function
In your first script (prefab_shooting-) You didn't call the Shoot() function.

Unity 2d game Player and enemy not moving

I have been following a tutorial on a unity 2d game. The player and the enemy inherit from a base class known as MovingObject. Everything in the game works fine except that the player and the enemy can't move. Here are the scripts. The movement happens in a gridlike tile system.
This is the original tutorial series. Try going over the moving object, player, and enemy tutorials.
https://www.youtube.com/playlist?list=PLX2vGYjWbI0SKsNH5Rkpxvxr1dPE0Lw8F
Base MovingObject class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class MovingObject : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockinglayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start () {
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2(xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast(start, end, blockinglayer);
boxCollider.enabled = true;
if (hit.transform == null)
{
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
while (sqrRemainingDistance > float.Epsilon)
{
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemainingDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected virtual void AttemptMove<T>(int xDir, int yDir)
where T : Component
{
RaycastHit2D hit;
bool canMove= Move(xDir, yDir, out hit);
if (hit.transform == null)
{
return;
}
T hitComponent = hit.transform.GetComponent<T>();
if(!canMove && hitComponent != null)
{
OnCantMove(hitComponent);
}
}
protected abstract void OnCantMove<T>(T component)
where T : Component;
// Update is called once per frame
}
Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MovingObject {
public int wallDamage = 1;
public int pointsPerFood = 10;
public int pointsPerSoda = 20;
public float restartLevelDelay = 1f;
private Animator animator;
private int food;
// Use this for initialization
protected override void Start () {
animator = GetComponent<Animator>();
food = GameManager.instance.playerFoodPoints;
base.Start();
}
private void OnDisable()
{
GameManager.instance.playerFoodPoints = food;
}
// Update is called once per frame
void Update () {
if (GameManager.instance.playersTurn)
{
return;
}
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw("Horizontal");
vertical = (int)Input.GetAxisRaw("Vertical");
if (horizontal != 0)
{
vertical = 0;
}
if(horizontal!=0 || vertical != 0)
{
AttemptMove<Wall>(horizontal, vertical);
}
}
protected override void OnCantMove<T>(T component)
{
Wall hitwall = component as Wall;
hitwall.damageWall(wallDamage);
animator.SetTrigger("playerChop");
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
food--;
base.AttemptMove<T>(xDir, yDir);
RaycastHit2D hit;
CheckIfGameOver();
GameManager.instance.playersTurn = false;
}
public void LoseFood(int loss)
{
animator.SetTrigger("playerHit");
food -= loss;
CheckIfGameOver();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Exit")
{
Invoke("Restart", restartLevelDelay);
enabled = false;
}
else if (other.tag == "Food")
{
food += pointsPerFood;
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
food += pointsPerSoda;
other.gameObject.SetActive(false);
}
}
private void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
private void CheckIfGameOver()
{
if (food <= 0)
{
GameManager.instance.GameOver();
}
}
}
Enemy Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MovingObject {
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipmove;
// Use this for initialization
protected override void Start () {
GameManager.instance.AddEnemyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
base.Start();
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
if (skipmove)
{
skipmove = false;
return;
}
base.AttemptMove<T>(xDir, yDir);
}
public void MoveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
{
yDir = target.position.y > transform.position.y ? 1 : -1;
}
else
{
xDir = target.position.x > transform.position.x ? 1 : -1;
AttemptMove<Player>(xDir,yDir);
}
}
protected override void OnCantMove<T>(T component)
{
Player hitplayer = component as Player;
animator.SetTrigger("enemyAttack");
hitplayer.LoseFood(playerDamage);
}
}
I'm not sure which whether the player or enemy have an issue of the base script. Can anyone help.
A few Observations (Hopefully it helps):
MovingObject.cs - Inside of Update(), should it not be this?
if (!GameManager.instance.playersTurn)
Note I added a "!" before GameManager
Player.cs - in AttemptMove(), you need to call Move()... like this
Move (xDir, yDir, out hit);
Enemy.cs
1) At the end of AttemptMove(), there should be:
skipMove = true;
2) In MoveEnemy(), at the end, this code should NOT be in the else, but after the else:
AttemptMove<Player>(xDir,yDir);

Unity2D: Fixing colliding for inventory

My goal was to make my character pickup item on collider (2D) didn't work.
So here is what I've tried:
Player Controller Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 2f;
public Inventory inventory;
void Start()
{
}
public bool isGrounded;
public LayerMask groundLayers;
void Update()
{
// isgrounded?
isGrounded = Physics2D.OverlapArea(new Vector2(transform.position.x -
0.2f, transform.position.y - 0.2f),
new Vector2(transform.position.x + 0.2f, transform.position.y -
0.21f), groundLayers);
Jump();
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * moveSpeed;
}
void Jump()
{
if(Input.GetButtonDown("Jump") && isGrounded)
{
gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f,
2.5f), ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(ControllerColliderHit hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
}
HUD SCRIPT:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HUD : MonoBehaviour
{
public Inventory Inventory;
void Start ()
{
Inventory.ItemAdded += InventoryScript_ItemAdded;
}
private void InventoryScript_ItemAdded(object sender, InventoryEventArgs
e)
{
Transform inventoryPanel = transform.Find("InventoryPanel");
foreach(Transform slot in inventoryPanel)
{
// Border... Image
Image image = slot.GetChild(0).GetChild(0).GetComponent<Image>();
// We found empty slot!
if (!image.enabled)
{
image.enabled = true;
image.sprite = e.Item.Image;
// Todo store a reference;
break;
}
}
}
}
Inventory Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
private const int SLOTS = 7;
private List<IInventoryItem> mItems = new List<IInventoryItem>();
public event EventHandler<InventoryEventArgs> ItemAdded;
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider collider = (item as MonoBehaviour).GetComponent<Collider>
();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
}
Inventory Item Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IInventoryItem
{
string Name { get; }
Sprite Image { get; }
void OnPickup();
}
public class InventoryEventArgs : EventArgs
{
public InventoryEventArgs(IInventoryItem item)
{
Item = item;
}
public IInventoryItem Item;
}
Rock Script (The object):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rock : MonoBehaviour, IInventoryItem
{
public string Name
{
get
{
return "Rock";
}
}
public Sprite _Image = null;
public Sprite Image
{
get
{
return _Image;
}
}
public void OnPickup()
{
// TODO: ADD LOGIC THAT WILL MAKE THE ROCK A 'WEAPON' TO CUT DOWN THE
TREE
gameObject.SetActive(false);
}
}
All of those scripts work, but whenever I join my game and Collide the player with the object (all 2d, 2D Box colliders, etc.) the character wont pick the item up and put it in it's inventory?
The scripts are referenced to each other.
What did I do wrong?
Physics 2D Screenshot:
Player inspector screenshot:
Rock (Object that needs to join his inventory)
One thing I noticed is that you are mixing the syntax of two events to create one that doesn't exist. void OnCollisionEnter2D(ControllerColliderHit hit) is not a built-in event in Unity. You probably mean to use void OnCollisionEnter2D(Collision2D hit):
private void OnCollisionEnter2D(Collision2D hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
Another thing is that BoxCollider2D does not inherit from Collider. So, in AddItem, you should look for a Collider2D component instead:
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider2D collider = (item as MonoBehaviour).GetComponent<Collider2D>();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
Consider this to be a partial solution because this may not capture all the changes needed... Let me know if this alone doesn't fix the problem in the comments below.

Wanting to make a 2D bouncy floating island In Unity c#

I'm new to coding and I am currently wanting to create a floating island that bounces up and down on collision with the player. Note, currently in order for the island to go down on collision, I have a rigidbody on both the player and the island, with the island's gravity scale set to 0 and mass to about 5. This is what I have so far: using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class island : MonoBehaviour
{
public Rigidbody2D rb;
public bool GroundTouch = false;
private void OnCollisionEnter2D(Collision2D collision)
{
GroundTouch = true;
}
private void OnCollisionExit2D(Collision2D collision)
{
GroundTouch = false;
}
private void FixedUpdate()
{
if (GroundTouch == false) {
StartCoroutine(canGoUp());
}
}
IEnumerator canGoUp()
{
functionCalled = false;
yield return new WaitForSeconds(1);
functionCalled = true;
}
bool functionCalled = false;
void Update()
{
if (!functionCalled)
{
Bounce();
}
}
void Bounce()
{
rb.AddForce(transform.up * 20);
}
}

Categories