Unity3d if statements for triggers not working as expected - c#

I'm making a 3d game and I want to have a counter add 1 for every trigger tile I walk over in a 2d top down sense. Example gameObject name is trigger1 and I have this trigger script on my player, when he walks onto the trigger it sets 2 ints(int1, int2) int 1 is the counter and int2 is just a flag so I know I am standing on the trigger1 tile. The way the script works now it will reset the counter almost every time I walk off one trigger to the next even tho the triggers are directly next to each other and my player is wide enough to not leave the trigger area entirely. I'm trying to figure out an if statement that would say if colliding with trigger1 int2 = 1 and when I'm not touching trigger 1 int2 = 0. then when int2 = 0 reset counter back to 0
example code
using UnityEngine;
using System.Collections;
public class TriggerScript : MonoBehaviour
{
public int in1 = 0;
public int int2 = 0;
void Start()
{
Debug.Log (int1);
}
void OnTriggerEnter (Collider trigger1)
{
int1++;
Debug.Log ("trigger1 Enter");
Debug.Log (int1);
}
void OnTriggerStay (Collider trigger1)
{
int2 = 1;
Debug.Log ("trigger1 Stay");
}
void OnTriggerExit (Collider trigger1)
{
if (collider.gameObject.tag == "trigger1") {
Debug.Log ("int2 = 1");
} else {
int2 = 0;
Debug.Log ("int2 = 0");
}
}
void Update (){
if (int2 == 0)
int1 = 0;
}
}

To put my comment into code:
public int score = 0;
public int triggerCounter = 0;
void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "trigger1")
{
score++;
triggerCounter++;
}
}
void OnTriggerExit(Collider other)
{
if(other.gameObject.tag == "trigger1")
{
triggerCounter--;
}
}
void Update()
{
if(triggerCounter <= 0)
{
score = 0;
triggerCounter = 0; // just for savety
}
}

Related

Pawn not moving on a board game

I have a board game project in unity, where six players roll a dice, and go forward using a waypoint system on a really basic board game (2d). I found some code on YouTube, and adapted it to my project. everything goes pretty well, except for the fact that the pawns don't move forward. They set correctly to the first waypoint, they are selected to move, but don't. I suspect that my transform.position don't work, but I can't understand why. I'm really new to c# and unity, so I can't find the problem.
Here is my pawn movement code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowThePath : MonoBehaviour
{
public Transform[] waypoints;
[SerializeField]
private float moveSpeed = 1f;
[HideInInspector]
public int waypointIndex = 0;
public bool moveAllowed = false;
// Start is called before the first frame update
private void Start()
{
transform.position = waypoints[waypointIndex].transform.position;
}
// Update is called once per frame
private void Update()
{
if (moveAllowed)
Move();
}
private void Move(){
if (waypointIndex <= waypoints.Length -1)
{
transform.position = Vector2.MoveTowards(transform.position,
waypoints[waypointIndex].transform.position,
moveSpeed * Time.deltaTime);
Debug.Log(transform.position);
if (transform.position == waypoints[waypointIndex].transform.position)
{
waypointIndex += 1;
}
}
}
}
I think the problem is at the end of this script.
I also have a dice script :
using System.Collections;
using UnityEngine;
public class Dice : MonoBehaviour {
// Array of dice sides sprites to load from Resources folder
private Sprite[] diceSides;
// Reference to sprite renderer to change sprites
private SpriteRenderer rend;
// Select the player's turn
private int whosturn = 1;
//Check if we can roll the dice
private bool coroutineallowed = true;
// Use this for initialization
private void Start () {
// Assign Renderer component
rend = GetComponent<SpriteRenderer>();
// Load dice sides sprites to array from DiceSides subfolder of Resources folder
diceSides = Resources.LoadAll<Sprite>("DiceSides/");
}
// If you left click over the dice then RollTheDice coroutine is started
private void OnMouseDown()
{
if (!GameControl.gameOver && coroutineallowed)
StartCoroutine("RollTheDice");
}
// Coroutine that rolls the dice
private IEnumerator RollTheDice()
{
// Turn coroutineallowed off
coroutineallowed = false;
// Variable to contain random dice side number.
// It needs to be assigned. Let it be 0 initially
int randomDiceSide = 0;
// Loop to switch dice sides ramdomly
// before final side appears. 10 iterations here.
for (int i = 0; i <= 10; i++)
{
// Pick up random value from 0 to 5 (All inclusive)
randomDiceSide = Random.Range(0, 6);
// Set sprite to upper face of dice from array according to random value
rend.sprite = diceSides[randomDiceSide];
// Pause before next iteration
yield return new WaitForSeconds(0.05f);
}
GameControl.diceSideThrown = randomDiceSide + 1;
if (whosturn == 1){
GameControl.MovePlayer(1);
}
if (whosturn == 2){
GameControl.MovePlayer(2);
}
if (whosturn == 3){
GameControl.MovePlayer(3);
}
if (whosturn == 4){
GameControl.MovePlayer(4);
}
if (whosturn == 5){
GameControl.MovePlayer(5);
}
if (whosturn == 6){
GameControl.MovePlayer(6);
whosturn -= 6;
}
if (whosturn <= 5){
whosturn += 1;
}
coroutineallowed = true;
}
}
and a Game control script :
using System.Collections;
using UnityEngine;
public class Dice : MonoBehaviour {
// Array of dice sides sprites to load from Resources folder
private Sprite[] diceSides;
// Reference to sprite renderer to change sprites
private SpriteRenderer rend;
// Select the player's turn
private int whosturn = 1;
//Check if we can roll the dice
private bool coroutineallowed = true;
// Use this for initialization
private void Start () {
// Assign Renderer component
rend = GetComponent<SpriteRenderer>();
// Load dice sides sprites to array from DiceSides subfolder of Resources folder
diceSides = Resources.LoadAll<Sprite>("DiceSides/");
}
// If you left click over the dice then RollTheDice coroutine is started
private void OnMouseDown()
{
if (!GameControl.gameOver && coroutineallowed)
StartCoroutine("RollTheDice");
}
// Coroutine that rolls the dice
private IEnumerator RollTheDice()
{
// Turn coroutineallowed off
coroutineallowed = false;
// Variable to contain random dice side number.
// It needs to be assigned. Let it be 0 initially
int randomDiceSide = 0;
// Loop to switch dice sides ramdomly
// before final side appears. 10 iterations here.
for (int i = 0; i <= 10; i++)
{
// Pick up random value from 0 to 5 (All inclusive)
randomDiceSide = Random.Range(0, 6);
// Set sprite to upper face of dice from array according to random value
rend.sprite = diceSides[randomDiceSide];
// Pause before next iteration
yield return new WaitForSeconds(0.05f);
}
GameControl.diceSideThrown = randomDiceSide + 1;
if (whosturn == 1){
GameControl.MovePlayer(1);
}
if (whosturn == 2){
GameControl.MovePlayer(2);
}
if (whosturn == 3){
GameControl.MovePlayer(3);
}
if (whosturn == 4){
GameControl.MovePlayer(4);
}
if (whosturn == 5){
GameControl.MovePlayer(5);
}
if (whosturn == 6){
GameControl.MovePlayer(6);
whosturn -= 6;
}
if (whosturn <= 5){
whosturn += 1;
}
coroutineallowed = true;
}
}

In Unity 2D editor, my UI text is not changing even though I told it to

So I'm making a 2D platformer game on Unity Editor. However, I've got stuck when it comes to point-scoring in the game. There is a coin / resource object, and whenever the Player touches it my UI text is supposed to change, however it does not. Here are the relevant parts of the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Player : MonoBehaviour {
public Text CountText;
private int count;
#Some irrelevant code...
void Start ()
{
myrigidbody = GetComponent<Rigidbody2D> ();
count = 0;
SetCountText();
}
#Some irrelevant code...
# Death or Win
void OnTriggerEnter2D (Collider2D col)
{
if(col.tag == "Saw")
{
Lose ();
}
if(col.tag == "Death")
{
Lose ();
}
if(col.tag == "Portal")
{
Finish ();
}
}
# Resource Gathering
void onTriggerEnter2D(Collider2D col)
{
if(col.tag == "isgem")
{
count = count + 1;
SetCountText();
col.gameObject.SetActive(false);
}
}
void SetCountText()
{
CountText.text = "Count: " + count.ToString();
}
}
Tell me if you want the whole script. Thanks!
Why do you have 2 onTriggerEnter2D methods?
You have to merge it:
void OnTriggerEnter2D (Collider2D col)
{
if(col.tag == "Saw" || col.tag == "Death")
{
Lose ();
}
else if(col.tag == "Portal")
{
Finish ();
}
else if(col.tag == "isgem")
{
count++;
SetCountText();
col.gameObject.SetActive(false);
}
}

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.

UnityException: Not allowed to call this function

Y'all remember that game where you had a wooden board and tried to get the ball through the maze w/o avoiding pitfalls? I am making a clone of that (except on the six sides of a cube). Instead of pitfalls, I added bombs that players have to actively disarm before they can progress. I recently added some code to make it more user friendly, but I keep on getting the error:
UnityException: You are not allowed to call this function when declaring a variable. Move it to the line after without a variable declaration. If you are using C# don't use this function in the constructor or field initializers, Instead move initialization to the Awake or Start function. UnityEngine.GameObject..ctor () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineGameObject.gen.cs:419) RandoLetter..cctor () Rethrow as TypeInitializationException: An exception was thrown by the type initializer for RandoLetter
RandoLetter is the script that creates the code for the player to destroy the bomb, but its acting up for some reason. Here is the code:
using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic;
public class RandoLetter : MonoBehaviour { //The array list of bombs public static GameObject Bombs = new GameObject();
//Array List of Particles
public static GameObject Particles = new GameObject();
//The list of colliders on the bombs
public static Collider Triggers = new Collider();
//The symbol that shows up
int LetterID;
//The speed at which a new symbol appears
int counter, CounterMax;
//The number of symbols that appear in one instance
int LetterCount;
//Which slot in the array that the player is accessing
public int entryID;
//The symbols that appear
public GameObject[] Arrows = new GameObject[4];
//The arrow buttons
public GameObject ArrowBN;
public static GameObject ArrowBTN;
//The randomly generated code
int[] PassCode = new int[4];
//The player game object to be destroyed
public GameObject player;
//The buttons that let the player rotate
public GameObject MoveUI;
//The particle effect when the player dies
public GameObject death;
//The timer before the player or bomb expires
int DeathCounter;
//The code that the player puts in
int[] YourCode = new int[4];
int CounterToMax = 0;
//Is the bomb currently being disarmed?
public static bool disarming = false;
void RestoreStart()
{
//How much longer until the next symbol appears
CounterToMax = 0;
//Is the player attempting to disarm the bomb
disarming = false;
//How many symbols show up
LetterCount = 4;
//Which slot in the array is the player accessing
entryID = 0;
//The UI that lets the player punch in part of the code
BallMoving.BombU.SetActive(false);
//Disabling the previous UI for the code
SetUIFalse();
}
// Use this for initialization
void Start()
{
//The timer until the player expires after failing to disarm a bomb
DeathCounter = 1000;
//The slot in the array that the player is accessing
entryID = 0;
//The amount of characters in the code being presented to the player
LetterCount = 4;
//Setting the static value to the public value
ArrowBTN = ArrowBN;
//The time between arrows
counter = 50;
//Setting CounterMax (the starting value of the counter) to the amount of time represented by counter
CounterMax = counter;
}
// Update is called once per frame
void Update()
{
//If the player is attempting to disarm the bomb
if (disarming)
{
//decrementing counter
counter--;
//Disabling the UI that allows the player to move
MoveUI.active = false;
//Special code for the last letter in the sequence
if (CounterToMax == LetterCount && counter == 0)
{
Arrows[LetterID].active = false;
}
//In the first 3 letters
if (counter == 5 && CounterToMax != LetterCount)
{
Arrows[LetterID].active = false;
}
//If the counter goes lower than zero somehow (just a catch in case the code above malfunctions)
if (counter < 0)
{
counter = CounterMax;
}
//Randomly Generating the letter
if (counter == 0 && CounterToMax != LetterCount)
{
LetterID = Random.Range(1, 4);
counter = CounterMax;
#region AssignLetter
//Assigning the letter to the value in the array slot
Arrows[LetterID].active = true;
PassCode[CounterToMax] = LetterID;
CounterToMax++;
#endregion
}
}
//Re-enabling the move UI
if (!disarming)
{
MoveUI.active = true;
}
//Enabling the UI that allows the player to punch in the code
if (CounterToMax == LetterCount && disarming == true)
{
ArrowBTN.active = true;
}
}
//Enabling the player to put in a code based off of a UI element
public void AddDirection(int number)
{
YourCode[entryID] = number;
entryID++;
//If the player is at the last letter, make sure that the player's code matches the randomly generated one
if (entryID == LetterCount)
{
//Resetting the entryID (slot in the array) for the next time a player defuses a bomb
entryID = 0;
CheckCorrect();
}
}
//Checking to make sure that the player entered in the correct code
public void CheckCorrect()
{
for (int i = 0; i < LetterCount; i++)
{
//If the player failed......
if (YourCode[i] != PassCode[i])
{
//Destroy the player
DestroyPlayer();
}
}
//Otherwise destroy the bomb
DestroyBomb();
}
//Re-enabling the player's UI that allows them to move
public void SetUIFalse()
{
disarming = false;
ArrowBTN.active = false;
}
//Destroying the player
public void DestroyPlayer()
{
print("Player Destroyed!");
SetUIFalse();
for (int i = 0; i < DeathCounter; i++)
{
Destroy(player);
if (i == DeathCounter - 1)
{
//Switching the levels after the player dies
switch (RotateBlock.level)
{
case 1:
Application.LoadLevel("Level1");
break;
case 2:
Application.LoadLevel("Level2");
break;
}
}
}
}
//Destroying the bomb
public void DestroyBomb()
{
//Resetting everything for the next time the player defuses a bomb
RestoreStart();
print("In DestroyBomb");
for (int i = 0; i < DeathCounter; i++)
{
if (i == DeathCounter - 1)
{
//Allowing the player to move again
Rigidbody rb;
rb = player.GetComponent<Rigidbody>();
rb.isKinematic = false;
//Disabling the bomb
Bombs.SetActive(false);
//Enabling the particle effect
Particles.active = true;
//Destroying the collider on the bomb
Triggers.enabled = false;
}
}
}
}
Sorry if it looks like a bunch of junk, I tried to comment it as best as I could. Anyways, it has been bugging me for a while and I really appreciate any help :D
You have to create a new instance of GameObject inside a function.
Replace public static GameObject Particles = new GameObject();
with
public static GameObject Particles;
void Awake()
{
Particles = new GameObject();
}

GetInt can only be called from main thread?

This question HAS been answered before but I tried everything and it didn't work.
I have this int in a flappy bird clone where you collect coins and it goes up by one kinda like a coin counter.
Every time you collect a coin it does
PlayerPrefs.SetInt("coin", coin);
coin+=1
PlayerPrefs.Save();
And when a new coin spawns I do this in the very start of the class (not in void Start() )
private int coin = PlayerPrefs.GetInt("coin");
And everything worked fine.
I even tested it by putting a print in console code and it counted down the coins just fine!
But I also have this other scene called Shop, where you can spend those coins. However I made like a little way to draw those integers, that should work fine, BUT I get an error that getInt can only be called from main thread, which is dumb because I cant put it in the start / awake / update method, because when I do so I get a ton more errors.
What do I do? I want to call the coin integer that I saved using playerprefs in that scene in order to draw the amount of coins
I try calling it like this: private int coin = PlayerPrefs.GetInt("coin");
but I get an error, even though I don't get one when I call it in the actual game scene.
Full code:
using UnityEngine;
using System.Collections;
public class SpriteScript : MonoBehaviour
{
private int coin = PlayerPrefs.GetInt("coin");
public Sprite num1;
public Sprite num2;
public Sprite num3;
public Sprite num4;
public Sprite num5;
public Sprite num6;
public Sprite num7;
public Sprite num8;
public Sprite num9;
public Sprite num0;
private int spritenum;
private SpriteRenderer spriteRenderer;
// Use this for initialization
void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>(); // we are accessing the SpriteRenderer that is attached to the Gameobject
if (spriteRenderer.sprite == null) // if the sprite on spriteRenderer is null then
spriteRenderer.sprite = num0; // set the sprite to sprite1
}
// Update is called once per frame
void Update()
{
if (coin < 10)
{
spritenum = coin;
if (coin > 10)
{
if (coin < 20)
{
spritenum = coin - 10;
}
if (coin > 20)
{
if (coin < 30)
{
spritenum = coin - 20;
}
if (coin > 30)
{
if (coin < 40)
{
spritenum = coin - 30;
}
if (coin > 40)
{
if (coin < 50)
{
spritenum = coin - 40;
}
if (coin == 50)
{
spritenum = coin - 50;
}
}
}
}
}
}
ChangeTheDamnSprite();
}
void ChangeTheDamnSprite()
{
if (spritenum == 0)
{
spriteRenderer.sprite = num0;
}
if (spritenum == 1)
{
spriteRenderer.sprite = num1;
}
if (spritenum == 2)
{
spriteRenderer.sprite = num2;
}
if (spritenum == 3)
{
spriteRenderer.sprite = num3;
}
if (spritenum == 4)
{
spriteRenderer.sprite = num4;
}
if (spritenum == 5)
{
spriteRenderer.sprite = num5;
}
if (spritenum == 6)
{
spriteRenderer.sprite = num6;
}
if (spritenum == 7)
{
spriteRenderer.sprite = num7;
}
if (spritenum == 8)
{
spriteRenderer.sprite = num8;
}
if (spritenum == 9)
{
spriteRenderer.sprite = num9;
}
}
}
By the way if you're wondering, it pretty much looks how many coins you have and replaces the sprite to match the number, please don't question the stupid way I used to draw the coin amount, can you please help me fix the problem? As I said I tried putting it in start method, nothing happens, instead more errors.
Oh and im building to android if that changes anything
I suspect you're approaching this problem the wrong way. May I suggest you create a new class called CoinController : Monobehaviour and attach it to your player.
public class CoinController: MonoBehaviour {
int coins;
public int Coins {
get {
return coins;
}
}
public Sprite GetSprite() {
//logic for determining sprite based on number of coins here
}
public void AddCoins(int num) {
coins += num;
}
public void SpendCoins(int num) {
coins -= num;
}
}
CoinController coinController = GetComponent<CoinController>();
coinController.AddCoins(5);
coinController.SpendCoins(2);
//in update method
Sprite thisSprite = coinController.GetSprite();
//draw sprite logic, not sure how you're doing this, but DrawCoinSprite would be some method that updates which sprite to draw
DrawCoinSprite(thisSprite);
I hope that helps!

Categories

Resources