Trying to get a variable changed on Collision - c#

I'm trying to make flappy bird and I'm trying to make it when the bird hits the "floor" a variable changes and then the script for the movement is not able to go.
Kinda hard for me to explain but here is the code i have:
void Update()
{
void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.tag == "floor") // || col.gameObject.tag == "Pipe")
{
active = 0;
}
}
if (active == 1)
if (Input.GetKeyDown("space"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 10, 0);
}
}
That is my code ^
Please help : )

void Update()
{
if (active == 1)
{
if (Input.GetKeyDown("space"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 10, 0);
}
}
}
void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.tag == "floor") // || col.gameObject.tag == "Pipe")
{
active = 0;
}
}
This code works fine for me, make sure you add Rigidbody2d to the player + add the box collider and the tag to the floor

First of all you have the OnCollisionEnter2D nested under Update as a local function. Unity doesn't find and call it this way, it needs to be at class level.
And then you set
active = 0;
but check for
active == 1
this seems odd. I would expect you check for the same value.
In general rather use a bool flag:
private bool active;
// reference via the Inspector if possible
[SerializeField] private Rigidbody2D _rigidbody;
private void Awake()
{
// as fallback get it ONCE on runtime
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (active)
{
if (Input.GetKeyDown("space"))
{
// only change the Y velocity, keep the rest
// that's needed e.g. if you are moving sideways currently
_rigidbody.velocity = new Vector3(_rigidbody.velocity.x, 10);
// immediately disable jumping
active = false;
}
}
}
private void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.CompareTag("floor") || col.gameObject.CompareTag("Pipe"))
{
active = true;
}
}
// also disable jumping when exiting just in case
void OnCollisionExit2D(Collider2D col)
{
if (col.gameObject.CompareTag("floor") || col.gameObject.CompareTag("Pipe"))
{
active = false;
}
}

Related

I have a bug where the player can still press x without in the triggerange of the Chest

The player spawns in a different location than the chest
1. So what it should do is first to go to Update Method which is obvious but it cant access the result of the first
if statement because TouchingChestBoxCollider is still false (at the beginning).
2. If the Player reaches the the trigger range of the Chest, then TouchingChestBoxCollider = true
3. Next it should go again to the Update() I know Update is called every frame but i want to make the order clear. The if Statement is now "valid" and xIsPressed = true so OnTriggerStay2D can go to DropDownItem and the rest is irelevant.
What the Problem looks like : i can still Press X outside the CircleCollider2D range of the Chest and when i already have reached the range the Chest, it drops the items even though it should do it when im in the in the range not outside (press x)
Do i have a mistake in the Code and if yes where pls help me
What the Code should do at the end: In the Range of The Chest you can press X and the items spawns
if not in range and you still press x and then go to the chest range it will not spawn BUT WHAT IT DOES XD.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChestOpener : MonoBehaviour
{
[SerializeField]
private GameObject ChestItSelf;
[SerializeField]
private GameObject[] itemsWeapon;
[SerializeField]
private GameObject[] itemsMedi;
[SerializeField]
private SpriteRenderer spriteRenderer;
[SerializeField]
private Sprite openSprite, closeSprite;
private int random;
private Vector2 destination;
private GameObject objectsWeapon;
private GameObject objectsWeapon2;
private GameObject objectsMedi;
private bool HasItDropped = false;
private bool MoveItemNow = false;
private bool xIsPressed = false;
private bool TouchingChestBoxCollider = false;
private void Update()
{
if (Input.GetKeyDown(KeyCode.X) && TouchingChestBoxCollider == true)
{
xIsPressed = true;
}
if (MoveItemNow == true ) //it should always stay at the Update function or else it will not render the move (lag)
{
objectsWeapon.transform.position = Vector2.Lerp(objectsWeapon.transform.position, new Vector2(transform.position.x, transform.position.y - 4),
Time.deltaTime * 1f);
objectsWeapon2.transform.position = Vector2.Lerp(objectsWeapon2.transform.position, new Vector2(transform.position.x-2, transform.position.y - 4),
Time.deltaTime * 1f);
}
}
private void OnTriggerStay2D(Collider2D collision)
{
TouchingChestBoxCollider = true;
if (collision.gameObject.tag == "Player" && HasItDropped == false && xIsPressed == true)
{
DropDownItem();
}
}
private void DropDownItem()
{
spriteRenderer.sprite = openSprite;
random = UnityEngine.Random.Range(0, itemsWeapon.Length);
objectsWeapon = Instantiate(itemsWeapon[random], transform.position, Quaternion.identity);
objectsWeapon2 = Instantiate(itemsWeapon[random], transform.position, Quaternion.identity);
MoveItemNow = true;
HasItDropped = true;
}
private void OnTriggerExit2D(Collider2D collision)
{
spriteRenderer.sprite = closeSprite;
Invoke("FareWellChest", 2f);
}
private void FareWellChest()
{
if (HasItDropped == true)
{
Destroy(ChestItSelf);
}
}
}
you seem to never ever reset TouchingChestBoxCollider and should probably do so in
private void OnTriggerExit2D(Collider2D other)
{
TouchingChestBoxCollider = false;
spriteRenderer.sprite = closeSprite;
Invoke("FareWellChest", 2f);
}
and also never reset xIsPressed and should do so in
private void OnTriggerStay2D(Collider2D collision)
{
TouchingChestBoxCollider = true;
if (collision.gameObject.CompareTag("Player") && !HasItDropped && xIsPressed)
{
DropDownItem();
}
xIsPressed = false;
}
Actually if instead of OnTriggerStay2D you rather used OnTriggerEnter2D in order to make relevant checks only once you could simplify the logic into
private void Update()
{
if (Input.GetKeyDown(KeyCode.X) && TouchingChestBoxCollider)
{
DropDownItem();
}
...
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Player") && !HasItDropped)
{
TouchingChestBoxCollider = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
TouchingChestBoxCollider = false;
}
}
so you wouldn't need the xIsPressed at all.
In genera when dealing with Physics and Collision detection you should avoid moving any object via Transform in Update but rather go through the Rigidbody2D in FixedUpdate.

Object doesn't appear using Sprite Renderer when triggered

I'm making a Mario replica in unity for my homework, and I'm trying to make the "Invisible" block, it starts off invisible, then when hit, it turns visible. I'm trying to use SpriteRenderer.enable to make it work, it works for turning it off in the start, but not when trying to make it visible.
I've tried to create a separate script for this particular block, but results are the same. All the tags are set correctly, I've tried using Debug.log to see if I enter the "if" where the sprite should be enabled, but the result is negative.
This is the start method turning off the sprite renderer for the particular block (it works):
private void Start()
{
//rendObject = this.gameObject.GetComponent<SpriteRenderer>();
if (gameObject.tag == "Invisible")
{
gameObject.GetComponent<SpriteRenderer>().enabled = false;
}
}
This is all the blocks script:
private void OnCollisionEnter2D(Collision2D collision)
{
if (timesToBeHit > 0)
{
if (collision.gameObject.tag == "Player" && IsPlayerBelow(collision.gameObject))
{
if (gameObject.tag == "Invisible")
{
gameObject.GetComponent<SpriteRenderer>().enabled = true;
}
collision.gameObject.GetComponent<PlayerController>().isJumping = false; //Mario can't jump higher
Instantiate(prefabToAppear, transform.parent.transform.position, Quaternion.identity); //instantiate other obj
timesToBeHit--;
anim.SetTrigger("GotHit"); //hit animation
}
}
if (timesToBeHit == 0)
{
anim.SetBool("EmptyBlock", true); //change sprite in animator
}
}
We've found a solution in chat, but for all people who may run or have run on this kind of problem will need to check for the next things:
Must have 2 Colliders of any type, 1 per gameObject.
At least 1 Rigidbogy.
Appropriately Collider setup.
Appropriate Tags.
Appropriate Layer Collision Matrix.
The code below will work.
public SpriteRenderer render;
void Start()
{
render.enabled = false;
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag == "Player")
{
render.enabled = true;
}
}
public class InvisibleBlock : MonoBehaviour
{
public SpriteRenderer rendObject;
private void Start()
{
if (gameObject.tag == "Invisible")
{
rendObject.enabled = false;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
rendObject.enabled = true;
}
}
}
Separate script, sprite is attached in inspector, same results.

How can I respawn pickups in an array and through a coroutine?

I'm having difficulty getting my gold pickups to respawn after they've been destroyed on death. The idea is, if the player fails to pick up the 5 gold bars, activates a checkpoint, and dies, the current gold is destroyed and it resets once the screen has faded from black.
I currently have a Coroutine in my Health Manager that runs correctly if the player dies and resets them. I have a Gold Pickup script that destroys the gold if they haven't been picked up. I just can't seem to get them to re-instantiate. I've tried adding the instantiate code within the Health Manager's coroutine and within the Gold Pickup script. Nothing seems to work. If I'm not getting errors saying 'Array index is out of range' it's 'object reference not set to an instance of an object' etc.
public class GoldPickup : MonoBehaviour{
public int value;
public GameObject pickupEffect;
public GameObject[] goldBarArray;
public HealthManager healthManager;
public Checkpoint checkpoint;
private Vector3 goldRespawnPoint;
private Quaternion goldStartPosition;
void Start()
{
//To destroy multiple objects at once, use FindGameObjectsWithTag.
//GetComponent is considered more efficient than FindObjectOfType, but the latter avoids any errors saying an object reference hasn't been set.
goldBarArray = GameObject.FindGameObjectsWithTag("Gold");
healthManager = FindObjectOfType<HealthManager>();
//FindObjectOfType<Checkpoint>();
checkpoint = FindObjectOfType<Checkpoint>();
goldRespawnPoint = transform.position;
goldStartPosition = transform.rotation;
}
public void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
FindObjectOfType<GameManager>().AddGold(value);
Instantiate(pickupEffect, transform.position, transform.rotation);
Destroy(gameObject);
}
}
public void DestroyGold()
{
//For Statics, an object reference isn't necessary. Use the FindObjectOfType to find the appropriate script and reference the Type, such as HealthManager.
if (checkpoint.checkpoint1On == false)
{
foreach (GameObject Gold in goldBarArray)
{
Destroy(Gold);
Instantiate(goldBarArray[5], goldRespawnPoint, goldStartPosition);
goldRespawnPoint = transform.position;
goldStartPosition = transform.rotation;
//healthManager.RespawnCo();
}
}
}
/*public void GoldReset()
{
if (healthManager.isRespawning == true)
{
if (checkpoint.checkpoint1On == false)
{
StartCoroutine("GoldRespawnCo");
}
}
else if (_respawnCoroutine != null)
{
StopCoroutine(_respawnCoroutine);
_respawnCoroutine = StartCoroutine("GoldRespawnCo");
}*/
/*public IEnumerator GoldRespawnCo()
{
if (checkpoint.checkpoint1On == false)
{
Instantiate(goldPrefab, goldRespawnPoint, goldStartPosition);
transform.position = goldRespawnPoint;
transform.rotation = goldStartPosition;
}
else
{
yield return null;
}
}*/
/*if (thePlayer.gameObject.activeInHierarchy == false)
{
Destroy(gameObject);
Instantiate(goldBar, transform.position, transform.rotation);
}
else
{
if (thePlayer.gameObject.activeInHierarchy == true)
{
transform.position = respawnPoint;
transform.rotation = startPosition;
}
}*/
}
public class HealthManager : MonoBehaviour
//The counters will count down and will keep counting down based on the length variables
public int maxHealth;
public int currentHealth;
public PlayerController thePlayer;
//public GoldPickup goldPickup;
//public GoldPickup[] goldPickup;
public float invincibilityLength;
public Renderer playerRenderer;
public float flashLength;
public float respawnLength;
public GameObject deathEffect;
public Image blackScreen;
public float fadeSpeed;
public float waitForFade;
public bool isRespawning;
//public GameObject goldBar;
//To reference another script's function, such as in the DeathTrigger script, make a public DeathTrigger, give it a reference name, and put it into the Start function. Use the reference name and assign it using GetComponent. Call another script's method by using the reference name, followed by a dot and the name of the method. Eg: deathTrigger.DestroyGold().
private Quaternion startPosition;
//private Quaternion goldPosition;
private float flashCounter;
private float invincibilityCounter;
private Vector3 respawnPoint;
//private Vector3 goldRespawnPoint;
private bool isFadetoBlack;
private bool isFadefromBlack;
//private Coroutine _respawnCoroutine;
//private Vector3 goldRespawnPoint;
//private Quaternion goldStartPosition;
void Start()
{
currentHealth = maxHealth;
respawnPoint = thePlayer.transform.position;
startPosition = thePlayer.transform.rotation;
//goldPickup = GetComponent<GoldPickup>();
//goldRespawnPoint = goldBar.transform.position;
//goldStartPosition = goldBar.transform.rotation;
//goldRespawnPoint = transform.position;
//goldStartPosition = transform.rotation;
//goldPickup = FindObjectOfType<GoldPickup>();
//goldRespawnPoint = goldBar.transform.position;
//goldPosition = goldBar.transform.rotation;
}
void Update()
{
//These functions are checked every frame until the player takes damage
if (invincibilityCounter > 0)
{
invincibilityCounter -= Time.deltaTime;
flashCounter -= Time.deltaTime;
if (flashCounter <= 0)
//The Flash Counter is currently set at 0.1 and will be within the 0 region as it counts down. During this period, the playerRenderer will alternate between on and off
{
playerRenderer.enabled = !playerRenderer.enabled;
//The Flash Counter will keep counting down and reloop depending on the Flash Length time
flashCounter = flashLength;
}
//This makes sure after the flashing and invincibility has worn off that the player renderer is always turned back on so you can see the player
if (invincibilityCounter <= 0)
{
playerRenderer.enabled = true;
}
}
if (isFadetoBlack)
{
blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 1f, fadeSpeed * Time.deltaTime));
if (blackScreen.color.a == 1f)
{
isFadetoBlack = false;
}
}
if (isFadefromBlack)
{
blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 0f, fadeSpeed * Time.deltaTime));
if (blackScreen.color.a == 0f)
{
isFadefromBlack = false;
}
}
}
public void HurtPlayer(int damage, Vector3 direction)
{
//If the invincibility countdown reaches zero it stops, making you no longer invincible and prone to taking damage again
if (invincibilityCounter <= 0)
{
currentHealth -= damage;
if (currentHealth <= 0)
{
Respawn();
}
else
{
thePlayer.Knockback(direction);
invincibilityCounter = invincibilityLength;
playerRenderer.enabled = false;
flashCounter = flashLength;
}
}
}
public void Respawn()
{
//A StartCoroutine must be set up before the IEnumerator can begin
if (!isRespawning)
{
StartCoroutine("RespawnCo");
}
}
//IEnumerators or Coroutines will execute the code separately at specified times while the rest of the code in a codeblock will carry on executing as normal.
//To prevent an error appearing below the name of the Coroutine, be sure to place a yield return somewhere within the code block. Either yield return null or a new WaitForSeconds.
public IEnumerator RespawnCo()
{
if (GameManager.currentGold < 5)
{
isRespawning = true;
thePlayer.gameObject.SetActive(false);
Instantiate(deathEffect, respawnPoint, startPosition);
yield return new WaitForSeconds(respawnLength);
isFadetoBlack = true;
yield return new WaitForSeconds(waitForFade);
//To reference another script's function quickly and just the once, use the FindObjectOfType function. This is considered to be slow however.
FindObjectOfType<GoldPickup>().DestroyGold();
//GetComponent<GoldPickup>().DestroyGold();
//Instantiate(goldBar, goldRespawnPoint, Quaternion.identity);
isFadefromBlack = true;
//goldRespawnPoint = goldBar.transform.position;
//goldStartPosition = goldBar.transform.rotation;
isRespawning = false;
thePlayer.gameObject.SetActive(true);
thePlayer.transform.position = respawnPoint;
thePlayer.transform.rotation = startPosition;
currentHealth = maxHealth;
invincibilityCounter = invincibilityLength;
playerRenderer.enabled = false;
flashCounter = flashLength;
GameManager.currentGold = 0;
GetComponent<GameManager>().SetCountText();
StopCoroutine("RespawnCo");
/*isRespawning = true;
thePlayer.gameObject.SetActive(false);
yield return new WaitForSeconds(respawnLength);
isFadetoBlack = true;
yield return new WaitForSeconds(waitForFade);
isFadefromBlack = true;
invincibilityCounter = invincibilityLength;
playerRenderer.enabled = false;
flashCounter = flashLength;
SceneManager.LoadScene("Level 1");
GameManager.currentGold = 0;*/
}
else if(GameManager.currentGold >= 5)
{
isRespawning = true;
thePlayer.gameObject.SetActive(false);
Instantiate(deathEffect, respawnPoint, startPosition);
yield return new WaitForSeconds(respawnLength);
isFadetoBlack = true;
yield return new WaitForSeconds(waitForFade);
isFadefromBlack = true;
isRespawning = false;
thePlayer.gameObject.SetActive(true);
thePlayer.transform.position = respawnPoint;
thePlayer.transform.rotation = startPosition;
currentHealth = maxHealth;
invincibilityCounter = invincibilityLength;
playerRenderer.enabled = false;
flashCounter = flashLength;
}
}
/*public void HealPlayer(int healAmount)
{
currentHealth += healAmount;
if(currentHealth > maxHealth)
{
currentHealth = maxHealth;
}
}*/
public void SetSpawnPoint(Vector3 newPosition)
{
respawnPoint = newPosition;
}
public class Checkpoint : MonoBehaviour
public HealthManager theHealthManager;
public Renderer cpRenderer;
public Renderer postRenderer;
public SpriteRenderer pcRenderer;
public Material cpOff;
public Material cpOn;
public Material postOff;
public Material postOn;
public GameObject[] infoPanels;
public bool checkpoint1On;
//Make sure to assign a value to a bool with '=' and in an 'if' statement somewhere in the code to prevent warnings.
//private bool checkpoint1IsActivated;
private bool infoPanel1Activated;
void Start()
{
theHealthManager = FindObjectOfType<HealthManager>();
}
void Update()
//Key presses are better handled in the Update function and will recognise keys being pressed once every frame.
{
if (checkpoint1On == true)
{
if (infoPanel1Activated == false)
{
if (Input.GetKeyDown(KeyCode.Space))
{
infoPanels[0].SetActive(true);
infoPanel1Activated = true;
}
}
else
{
if (infoPanel1Activated == true)
{
if (Input.GetKeyDown(KeyCode.Space))
{
infoPanels[0].SetActive(false);
infoPanel1Activated = false;
}
}
}
}
}
public void Checkpoint1On()
{
cpRenderer.material = cpOn;
postRenderer.material = postOn;
pcRenderer.color = new Color(1f, 1f, 1f, 1f);
checkpoint1On = true;
}
//[] makes a variable an Array (a list). The 'foreach' loop will check through all the Checkpoint objects
//Checkpoint[] checkpoints = FindObjectsOfType<Checkpoint>();
//For each Checkpoint Array called 'checkpoints', look for 'cp' and turn the others in the list off
/*foreach (Checkpoint cp in checkpoints)
{
cp.CheckpointOff();
}
theRenderer.material = cpOn;*/
public void Checkpoint1Off()
{
cpRenderer.material = cpOff;
postRenderer.material = postOff;
pcRenderer.color = new Color(1f, 1f, 1f, 5f);
checkpoint1On = false;
}
public void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (GameManager.currentGold >= 5)
{
if (Input.GetKeyDown(KeyCode.Return))
{
theHealthManager.SetSpawnPoint(transform.position);
Checkpoint1On();
checkpoint1On = true;
}
}
else if (GameManager.currentGold <= 5)
{
checkpoint1On = false;
}
}
}
In your DestroyGold() function, you instantiate the gold like this:
foreach (GameObject Gold in goldBarArray)
{
Destroy(Gold);
Instantiate(goldBarArray[5], goldRespawnPoint, goldStartPosition);
goldRespawnPoint = transform.position;
goldStartPosition = transform.rotation;
//healthManager.RespawnCo();
}
But transform.position and transform.rotation only get the position and rotation of the current object (i.e. whatever your script is attached to). So not only are you spawning all the gold in the same spot, it's spawning the gold at the location of the object that holds your script, not where you actually want it to go!
Without knowing much about the objects in your scene, here's what I can tell you: try creating a Transform[] to store the locations where you want to respawn the gold. Also, make sure you assign the goldRespawnPoint and goldStartPosition BEFORE you call Instantiate() in your foreach loop. Finally, just a general tip: you should never use variable == true or variable == false in an if statement. You can just use if(variable) or if(!variable), respectively. It will work just the same while being more readable and reducing the amount of code you need to write.
EDIT 1: In response to comments, I've added specific code examples for implementing these suggestions.
To start, you're probably getting the out of range error because of goldBarArray[5]. Since arrays start at index 0, you can only access up to element n-1 in a size n array. More on how to fix this in the next step.
Now for the Transform array. In the area where you declare your public variables (at the top of the script), add the line
public Transform[] spawnPoints;
Then, back in Unity you will be able to assign those spawn points in the Inspector.
EDIT 2: Additionally, in the foreach loop you're trying to instantiate one of the gold bars from the scene, but those are getting deleted with the Destroy(Gold); statement. Instead, you should be instantiating from the prefab which won't get destroyed. To do this, add
public GameObject goldPrefab;
up with the rest of your public variables. Then, in the Editor create a prefab by dragging one of the gold bars from the Hierarchy into your Assets folder. Finally, set that prefab to be the value of goldPrefab in the Inspector.
Now, you actually can clean up your foreach loop a little bit. You can get rid of the goldRespawnPoint and goldStartPosition lines because the respawn locations will be contained in the Transform array we just created. Again, without knowing how your scene is structured I've needed to just make an educated guess about what will work. Give this loop a try:
int spawnPointCounter = 0;
foreach(GameObject Gold in goldBarArray){
Destroy(Gold);
Transform currentSP = spawnPoints[spawnPointCounter];
Instantiate(goldPrefab, currentSP.position, currentSP.rotation);
spawnPointCounter++;
}

Why is it that sometimes my code runs and other times I get a argument is out of range?

Some times my code runs but then without changing any of the code it stops working and says I have the error argument is out of range exception?
it says it is on the line, "if (gameObject.transform.localPosition.y == finP[1].transform.localPosition.y)".
here is my code:
public class enemy : MonoBehaviour
{
List<GameObject> finP = new List<GameObject>();
public Node nodeScript;
Vector2 direction = Vector2.zero;
bool trigger = false;
public float Speed = 1.0f;
// Use this for initialization
void Start()
{
nodeScript = GameObject.Find("P16").GetComponent<Node>();
}
// Update is called once per frame
void Update()
{
apple();
MovePosition();
//nodeScript.FinalPath.ForEach(x => Debug.Log(x));
//Debug.Log(nodeScript.FinalPath.Count);
}
void apple()
{
if (gameObject.transform.localPosition.y == finP[1].transform.localPosition.y)
{
if (gameObject.transform.localPosition.x > finP[1].transform.localPosition.x)
{
Debug.Log("left");
direction = Vector2.left;
}
else
{
Debug.Log("right");
direction = Vector2.right;
}
}
else
{
if (gameObject.transform.localPosition.y > finP[1].transform.localPosition.y)
{
direction = Vector2.down;
}
if (gameObject.transform.localPosition.y < finP[0].transform.localPosition.y)
{
direction = Vector2.up;
}
}
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "pallet")
{
finP.Clear();
foreach(string var in nodeScript.FinalPath)
{
Debug.Log("en script " + var);
finP.Add(GameObject.Find(var));
}
Debug.Log(finP[1]);
}
}
void MovePosition()
{
transform.localPosition += (Vector3)(direction * Speed) * Time.deltaTime;
}
}
When you hit the "pallet" gameobject you're clearing the list, while also trying to access elements of that list every frame. Although you're adding to the list immediately after, there is probably a frame or two where the list is lacking the required elements. In your apple() function, I'd throw a if (finP.Count < 1) return; and that should fix your problem.

UNITY - Attack Hit Combo Code Error. Help needed

There's something wrong with my code. When I press the assigned keycode "Z", the CurrentState does not change to 1 and proceed with the whole combo. I tried putting a debug.log and found that the box collider does activate on pressing Z but the number does not increment by 1. Can anyone please help me out? Here's the code.
public class Fighter : MonoBehaviour {
public Collider[] attackhitboxes;
public Animator art;
public int CurrentState = 0;
bool activateTimertoreset = false;
public float currentcombotimer;
float origTimer = 50f;
private void Start()
{
art = gameObject.GetComponent<Animator>();
origTimer = currentcombotimer;
}
void Update()
{
art.SetInteger("currentstate", CurrentState);
NewComboSystem();
ResetComboState(activateTimertoreset);
}
void ResetComboState(bool resettimer)
{
if(resettimer)
{
currentcombotimer -= Time.deltaTime;
if(currentcombotimer <= 0)
{
CurrentState = 0;
activateTimertoreset = false;
currentcombotimer = origTimer;
}
}
}
private void LaunchAttack(Collider col)
{
Collider[] cols = Physics.OverlapBox(col.bounds.center, col.bounds.extents, col.transform.rotation, LayerMask.GetMask("Hitbox"));
foreach(Collider c in cols)
{
if(c.transform.parent.parent == transform)
{
continue;
}
}
}
void NewComboSystem()
{
if (Input.GetKeyDown(KeyCode.Z))
{
activateTimertoreset = true;
CurrentState++;
if (CurrentState == 1)
{
LaunchAttack(attackhitboxes[0]);
}
if (CurrentState == 2)
{
LaunchAttack(attackhitboxes[0]);
}
if (CurrentState >= 3)
{
LaunchAttack(attackhitboxes[0]);
}
}
}
}
Try putting your if (input.keydown) in the update function and have it call your attack. With the way you have it I believe it's calling your attack function many times a second because update runs every frame. Also try debugging the value of currentstate .
Edit:
Are you assigning currentcombotimer a value in the editor since it's public? In the script it has no starting value. In the start function you assign it to the origTimer. If this value is zero then you have zero combo time.

Categories

Resources