MissingComponentException: There is no 'SpriteRenderer' attached to the "Balletjes(Clone)" game object, but a script is trying to access it - unity3d

I get this error:
"MissingComponentException: There is no 'SpriteRenderer' attached to the "Balletjes(Clone)" game object, but a script is trying to access it."
I would like to assign the name of a sprite to the variable goldCoinPopUp. I searched a lot but nothing worked. Can anyone help me please?
ItemDragHandler
public class ItemDragHandler : MonoBehaviour, IDragHandler, IEndDragHandler
{
public GameObject prefab;
Vector2 original;
public void OnDrag(PointerEventData eventData)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 100);
transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray.origin, ray.direction, out hit, 100))
{
if (hit.collider.gameObject.name == "Terrain")
{
transform.gameObject.SetActive(false);
GameObject obj = Instantiate(prefab,hit.point, Quaternion.EulerAngles(0f, 3f, 0f)); // 3d object
obj.AddComponent<GenerateResources>(); // link to GenerateResources script
Vector3 img = new Vector3(0, 8.66f, 0);
obj.transform.position += img;
}
else
{
transform.localPosition = original;
}
}
else
{
transform.localPosition = original;
}
}
void Start ()
{
original = transform.localPosition;
}
}
GenerateResources
public class GenerateRessources : MonoBehaviour
{
private int ressourcesInBuilding;
public int valueWhenCollect = 10;
private float timerExtraRessource;
public float generateRate = 4;
public SpriteRenderer goldCoinPopUp;
private GameObject currentGameObject;
private GameObject Inventory;
void Start ()
{
goldCoinPopUp = GetComponent<SpriteRenderer>();
goldCoinPopUp.enabled = false;
currentGameObject = gameObject.GetComponent<GameObject>();
Inventory = GameObject.Find("Inventory");
}
void Update ()
{
AddResource();
getResources();
}
private void AddResource()
{
timerExtraRessource += Time.deltaTime;
if (timerExtraRessource >= generateRate)
{
ressourcesInBuilding++;
timerExtraRessource = 0;
if (ressourcesInBuilding >= valueWhenCollect)
{
goldCoinPopUp.enabled = true;
}
}
}
private void getResources()
{
if (Input.touchCount > 0)
{
Touch touch = Input.touches[0];
if (touch.phase == TouchPhase.Began)
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100f))
{
if (hit.transform.gameObject != null)
{
}
}
}
}
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100f))
{
if (hit.transform.gameObject != currentGameObject)
{
if (goldCoinPopUp.enabled == true)
{
goldCoinPopUp.enabled = false;
Inventory.GetComponent<GameController>().Gold += ressourcesInBuilding;
ressourcesInBuilding = 0;
}
}
}
}
}
}

Your code depends on SpriteRenderer being present, while your prefab does not have one. You can work around this problem by adding the following attribute before your class definiton
[RequireComponent(typeof(SpriteRenderer))]
public class GenerateRessources : MonoBehaviour
However the automatically added SpriteRenderer will have no sprite attached, hence a better solution would be to make sure your prefab does indeed have a reasonable sprite attached

Related

Unity: When I instantiate my character, it instantiates twice

I'm working on a platformer game, and I instantiate my character after he gets hit by an enemy object. The problem is, my character is instantiating twice. Here's my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerMove : MonoBehaviour
{
public GameObject player;
private Rigidbody2D rb;
private SpriteRenderer sprite;
private BoxCollider2D coll;
private Animator anim;
public float Speed;
public float JumpForce;
private float dirX = 0f;
private float fJumpPressedRemember = 0f;
private float fJumpPressedRememberTime = 0.2f;
[SerializeField] private LayerMask jumpableGround;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sprite = GetComponent<SpriteRenderer>();
coll = GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * Speed, rb.velocity.y);
fJumpPressedRemember -= Time.deltaTime;
if (Input.GetButtonDown("Jump"))
{
fJumpPressedRemember = fJumpPressedRememberTime;
}
if ((fJumpPressedRemember > 0) && isGrounded())
{
fJumpPressedRemember = 0;
rb.velocity = new Vector2(rb.velocity.x, JumpForce);
}
UpdateAnimation();
}
private bool isGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
if (spikeCol.gameObject.tag.Equals("End") == true)
{
SceneManager.LoadScene("Level2", LoadSceneMode.Single);
}
if (spikeCol.gameObject.tag.Equals("End2") == true)
{
SceneManager.LoadScene("Level1", LoadSceneMode.Single);
}
}
private void UpdateAnimation()
{
if (dirX > 0f)
{
anim.SetBool("running", true);
sprite.flipX = false;
}
else if (dirX < 0f)
{
anim.SetBool("running", true);
sprite.flipX = true;
}
else
{
anim.SetBool("running", false);
}
}
}
It's supposed to instantiate once after dying. I don't know what's happening, but it only started after I added animation code, so I think that's the issue. Thanks to anyone who can help!
OnCollisionEnter2D is called twice.
Reasons why this can be described here: Why is OnCollisionEnter getting called twice?
You can add instantiate method double call check, like this:
private bool isInited;
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
if (isInited)
{
return;
}
isInited = true;
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
...
}

Unity Raycast has inconsistent behavior. Sometimes it collides with the collider it starts in and sometimes not

The text in this image pretty much explains everything.
This is the code that creates the rays. You may ignore Debug.DrawRay().
RaycastHit hitInfo;
RaycastHit wall;
RaycastHit backFace;
if(Physics.Raycast(barrelEnd.transform.position, barrelEnd.transform.forward, out hitInfo)) {
Debug.DrawRay(barrelEnd.transform.position, barrelEnd.transform.forward*5, Color.green, 5f, false);
Instantiate(rayOneHit, hitInfo.point, Quaternion.identity);
Enemy target = hitInfo.transform.GetComponent<Enemy>();
if(target != null) {
if(Physics.Raycast(hitInfo.point, barrelEnd.transform.forward, out wall)) {
Debug.DrawRay(hitInfo.point, (hitInfo.point - barrelEnd.transform.position)*2, Color.blue, 5f, false);
Instantiate(rayTwoHit, wall.point, Quaternion.identity);
if(Physics.Raycast(wall.point, ((hitInfo.point - wall.point)/Vector3.Distance(hitInfo.point,wall.point)), out backFace)) {
Debug.DrawRay(wall.point, (hitInfo.point - wall.point)*10, Color.red, 5f, false);
Vector3 hitLocation = new Vector3(backFace.point.x, backFace.point.y, backFace.point.z);
Instantiate(hitPoint, hitLocation, Quaternion.identity);
}
}
target.dealDamage(damage);
}
lineRenderer.SetPosition(0, aim.transform.position);
lineRenderer.SetPosition(1, hitInfo.point);
}
This is all inside of a function Shoot() which is called as follows:
void Update() {
if(Input.GetButtonDown("Fire1")) {
Shoot();
}
}
Full code if needed:
using System.Collections;
using UnityEngine;
public class Shooting : MonoBehaviour {
[SerializeField] Transform aim;
[SerializeField] LineRenderer lineRenderer;
public float damage = 30f;
public Transform barrelEnd;
public Transform crosshair;
public Light muzzleFlash;
public Object hitPoint;
public Object rayOneHit;
public Object rayTwoHit;
public LayerMask enemyLayer;
//public Light muzzleFlashSelf;
// public GameObject projectile;
public float force = 100f;
void Start() {
Cursor.visible = false;
muzzleFlash.enabled = false;
//muzzleFlashSelf.enabled = false;
}
void Update() {
if(Input.GetButtonDown("Fire1")) {
Shoot();
}
}
void Shoot() {
RaycastHit hitInfo;
RaycastHit wall;
RaycastHit backFace;
StartCoroutine(DrawLine());
StartCoroutine(Flash());
if(Physics.Raycast(barrelEnd.transform.position, barrelEnd.transform.forward, out hitInfo)) {
Debug.DrawRay(barrelEnd.transform.position, barrelEnd.transform.forward*5, Color.green, 5f, false);
Instantiate(rayOneHit, hitInfo.point, Quaternion.identity);
Enemy target = hitInfo.transform.GetComponent<Enemy>();
if(target != null) {
if(Physics.Raycast(hitInfo.point, barrelEnd.transform.forward, out wall)) {
Debug.DrawRay(hitInfo.point, (hitInfo.point - barrelEnd.transform.position)*2, Color.blue, 5f, false);
Instantiate(rayTwoHit, wall.point, Quaternion.identity);
if(Physics.Raycast(wall.point, ((hitInfo.point - wall.point)/Vector3.Distance(hitInfo.point,wall.point)), out backFace)) {
Debug.DrawRay(wall.point, (hitInfo.point - wall.point)*10, Color.red, 5f, false);
Vector3 hitLocation = new Vector3(backFace.point.x, backFace.point.y, backFace.point.z);
Instantiate(hitPoint, hitLocation, Quaternion.identity);
}
}
target.dealDamage(damage);
}
lineRenderer.SetPosition(0, aim.transform.position);
lineRenderer.SetPosition(1, hitInfo.point);
}
}
IEnumerator DrawLine() {
lineRenderer.enabled = true;
float t = 0;
float time = 0.01f;
Vector3 orig = lineRenderer.GetPosition(0);
Vector3 orig2 = lineRenderer.GetPosition(1);
lineRenderer.SetPosition(1, orig);
for (; t < time; t += Time.deltaTime) {
yield return null;
}
lineRenderer.SetPosition(1, orig2);
lineRenderer.enabled = false;
}
IEnumerator Flash() {
float t = 0;
float time = 0.1f;
muzzleFlash.enabled = true;
//muzzleFlashSelf.enabled = true;
for (; t < time; t += Time.deltaTime) {
yield return null;
}
muzzleFlash.enabled = false;
//muzzleFlashSelf.enabled = false;
}
}
I've tried to start the 2nd raycast slightly further inside of the enemy, because I thought maybe it is hitting the very edge of the collider but this changed nothing. I've also tried to use ~enemyMask to exclude the enemy, but this just made the second ray not fire at all.

How to select an object to be picked up whenever the camera is pointed to that object?

I'm trying to pick up objects in unity. I have a gameObject called LookObject. Whenever the camera points to an object, the name of that object will be stored in LookObject, then when I press Space the object gets picked up. it is working but not completely. The issue I'm facing is that when I look at an object then look at another direction, the lookObject still shows the name of the object I was looking at (it doesn't update).
please see this image:
as shown in the image, the reticle is not pointing to the object. but it is still showing Cube as the Look Object.
Here is PlayerInteractions class:
GameObject[] targetObjects;
List<GameObject> targetObjectsList;
[Header("InteractableInfo")]
public float sphereCastRadius = 0.5f;
public int interactableLayerIndex;
private Vector3 raycastPos;
public GameObject lookObject;
private PhysicsObjects physicsObject;
private Camera mainCamera;
public GameObject winUI;
private InteractiveObjects interactiveObjects;
[Header("Pickup")]
[SerializeField] private Transform pickupParent;
public GameObject currentlyPickedUpObject;
private Rigidbody pickupRB;
[Header("ObjectFollow")]
[SerializeField] private float minSpeed = 0;
[SerializeField] private float maxSpeed = 300f;
[SerializeField] private float maxDistance = 8f;
private float currentSpeed = 0f;
private float currentDist = 0f;
[Header("Rotation")]
public float rotationSpeed = 100f;
// Quaternion lookRot;
[SerializeField] GameObject TargetsCanvas;
static bool strikeThrough = false;
private void Start()
{
mainCamera = Camera.main;
targetObjects = GameObject.FindGameObjectsWithTag("TargetObj");
targetObjectsList = new List<GameObject>();
foreach (var obj in targetObjects)
{
var mytext = CreateText(TargetsCanvas.transform);
mytext.text = "• Find The " + obj.name;
Debug.Log(""+ obj.name);
}
}
//A simple visualization of the point we're following in the scene view
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
Gizmos.DrawSphere(pickupParent.position, 0.5f);
}
void Update()
{
//Here we check if we're currently looking at an interactable object
raycastPos = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, 0));
RaycastHit hit;
if (Physics.SphereCast(raycastPos, sphereCastRadius, mainCamera.transform.forward, out hit, maxDistance, 1 << interactableLayerIndex))
{
lookObject = hit.collider.transform.gameObject;
}
//if we press the button of choice
if (Input.GetKeyDown(KeyCode.Space))
{
//and we're not holding anything
if (currentlyPickedUpObject == null)
{
//and we are looking an interactable object
if (lookObject != null )
{
PickUpObject();
if (!targetObjectsList.Contains(lookObject.gameObject))
{
targetObjectsList.Add(lookObject.gameObject);
if (targetObjectsList.Count == targetObjects.Length)
{
// Time.timeScale = 0f;
// winUI.SetActive(true);
// SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
// Time.timeScale = 1f;
}
}
}
}
//if we press the pickup button and have something, we drop it
else
{
BreakConnection();
}
}
}
private void FixedUpdate()
{
if (currentlyPickedUpObject != null)
{
currentDist = Vector3.Distance(pickupParent.position, pickupRB.position);
currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
currentSpeed *= Time.fixedDeltaTime;
Vector3 direction = pickupParent.position - pickupRB.position;
pickupRB.velocity = direction.normalized * currentSpeed;
//Rotation//
// lookRot = Quaternion.LookRotation(mainCamera.transform.position - pickupRB.position);
// lookRot = Quaternion.Slerp(mainCamera.transform.rotation, lookRot, rotationSpeed * Time.fixedDeltaTime);
// pickupRB.MoveRotation(lookRot);
}
}
//Release the object
public void BreakConnection()
{
pickupRB.constraints = RigidbodyConstraints.None;
currentlyPickedUpObject = null;
lookObject = null;
physicsObject.pickedUp = false;
currentDist = 0;
}
public void PickUpObject()
{
physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
currentlyPickedUpObject = lookObject;
pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
physicsObject.playerInteractions = this;
}
Here is the code attached to objects:
public float waitOnPickup = 0.2f;
public float breakForce = 35f;
[HideInInspector] public bool pickedUp = false;
[HideInInspector] public PlayerInteractions playerInteractions;
private void OnCollisionEnter(Collision collision)
{
if (pickedUp)
{
if (collision.relativeVelocity.magnitude > breakForce)
{
playerInteractions.BreakConnection();
}
}
}
//this is used to prevent the connection from breaking when you just picked up the object as it sometimes fires a collision with the ground or whatever it is touching
public IEnumerator PickUp()
{
yield return new WaitForSecondsRealtime(waitOnPickup);
pickedUp = true;
}
Here is an image of the object inspector:
how can I make it accurately showing the objects I'm looking at?
A simple fix for this would be to set lookObject to null if the SphereCast returns false since that would indicate you are no longer looking at a valid object. Simply adding else lookObject = null; to the end of the first if statement in your Update() method should do the trick.

When I hit E,and the raycast doesnt hit an object,I get this error message:NullReferenceException:Object reference not set to an instance of an object [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Player : MonoBehaviour
{
[SerializeField] private DialogueUI dialogueUI;
public Vector3 raypositionup = new Vector3(5, 0, 0);
public Vector3 raypositiondown = new Vector3(5, 0, 0);
private float MoveSpeed = 7f;
public Animator animator;
public DialogueUI DialogueUI => dialogueUI;
public Interactable Interactable { get; set; }
bool move = false;
bool movefoward = false;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (DialogueUI.IsOpen) return;
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
if (Input.GetKeyDown(KeyCode.W))
{
move = true;
movefoward = false;
animator.SetBool("Lookingfoward", true);
}
if (Input.GetKeyDown(KeyCode.S))
{
movefoward = true;
move = false;
animator.SetBool("Lookingfoward", false);
}
if (Input.GetKey(KeyCode.LeftShift))
{
MoveSpeed = 10f;
}
else
{
MoveSpeed = 7f;
}
if (Input.GetKeyDown(KeyCode.Return))
{
if (Interactable != null)
{
Interactable.Interact(this);
}
}
if (move == true)
{
if (Input.GetKey(KeyCode.E))
{
Debug.DrawRay(transform.position + raypositionup, transform.up * 2f, Color.red);
RaycastHit2D hit = Physics2D.Raycast(transform.position + raypositionup , transform.up, 2f);
if (hit.collider.CompareTag("Object"))
{
Debug.Log("Poop");
hit.transform.GetComponent<SpriteRenderer>().color = Color.red;
}
if (hit.collider == null)
{
return;
}
}
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * MoveSpeed * Time.fixedDeltaTime);
}
}
Ive tried several different fixes and none seem to work, such as another if statement, else statements, and even reworking the entire raycast system. If anyone knows a solution that would be just great. Also, any criticism on my code is okay and endorsed, im new to coding and want any opportunity I can get to clean up my code as best as possible.
You have code for return if collider is null, but not catch if null on compare:
if (hit.collider == null)
{
return;
}
elseif (hit.collider.CompareTag("Object")) //No catched if null
{
Debug.Log("Poop");
hit.transform.GetComponent<SpriteRenderer>().color = Color.red;
}

Can't figure out how to stop zombie from dealing damage when no longer colliding with player

I am creating a top down zombie shooter and I have made the zombie do damage to the player when it is touching the player. However when the player backs away from the zombie after taking damage, the players health will continue to drop. Any ideas on how to fix this would be appreciated.
public float moveSpeed= 5f;
public Rigidbody2D rb;
public Camera cam;
public float playerHealth = 100;
public float enemyDamage = 25;
public GameObject gameOverScreen;
Vector2 movement;
Vector2 mousePos;
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
if(playerHealth == 0)
{
gameOverScreen.SetActive(true);
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
Vector2 lookDir = mousePos - rb.position;
float angle = Mathf.Atan2(lookDir.y, lookDir.x) * Mathf.Rad2Deg - 90f;
rb.rotation = angle;
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
StartCoroutine(DamagePlayer());
}
else
{
StopCoroutine(DamagePlayer());
}
}
IEnumerator DamagePlayer()
{
while(true)
{
yield return new WaitForSeconds(1);
playerHealth -= enemyDamage;
}
}
First of all for doing something if it is not colliding anymore you should use OnCollisionExit2D
Then you can either use it the way you did using
StopCoroutine(DamagePlayer());
Or if want to be sure you could either store a reference to your routine
private Coroutine routine;
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
if(routine == null)
{
routine = StartCoroutine(DamagePlayer());
}
}
else
{
if(routine != null) StopCoroutine(routine);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(routine != null) StopCoroutine (routine);
}
or use a bool flag in order to terminate it
private bool cancelRoutine = true;
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
if(cancelRoutine) routine = StartCoroutine(DamagePlayer());
}
else
{
cancelRoutine = true;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
cancelRoutine = true;
}
IEnumerator DamagePlayer()
{
cancelRoutine = false;
while(! cancelRoutine)
{
yield return new WaitForSeconds(1);
playerHealth -= enemyDamage;
}
}
In general you could solve this without a routine by directly using OnCollisionStay2D like e.g.
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
timer = 1;
}
}
void OnCollisionStay2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
timer -= Time.deltaTime;
if(timer <= 0)
{
timer = 1;
playerHealth -= enemyDamage;
}
}
}