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.
Related
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;
}
}
I have a 3D board game in Unity. I would like to move my character without having to press a key, but most importantly I would like to show a dynamic panel in canvas for whatever square the character lands on. So far I have the dice rolling and the character moving (after pressing a key) the correct amount of squares, but I am unable to figure out how to activate the panel based on the square color. Any help would be appreciated.
Here is my CharacterScript:
public class CharacterScript : MonoBehaviour
{
public Path currentPath;
public int squarePosition;
public int squares;
bool isMoving;
public GameObject PinkSquarePanel = GameObject.FindGameObjectWithTag("PinkSquare");
public GameObject CyanSquarePanel = GameObject.FindGameObjectWithTag("CyanSquare");
public GameObject WhiteSquarePanel = GameObject.FindGameObjectWithTag("WhiteSquare");
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape) && !isMoving)
{
squares = DiceNumberTextScript.diceNumber;
}
StartCoroutine(Move());
if (squares == 0)
{
ActivateSquarePanel();
}
}
IEnumerator Move()
{
if (isMoving)
{
yield break;
}
isMoving = true;
while (squares > 0)
{
Vector3 nextPosition = currentPath.squareList[squarePosition + 1].position;
while (MoveToNextSquare(nextPosition))
{
yield return null;
}
yield return new WaitForSeconds(0.1f);
squares--;
squarePosition++;
}
isMoving = false;
}
bool MoveToNextSquare(Vector3 goal)
{
return goal != (transform.position = Vector3.MoveTowards(transform.position, goal, 4f * Time.deltaTime));
}
void ActivateSquarePanel()
{
if (squarePosition.Equals(PinkSquarePanel))
{
PinkSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(CyanSquarePanel))
{
CyanSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(WhiteSquarePanel))
{
WhiteSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
}
}
And here is my PathScript:
public class Path : MonoBehaviour
{
Transform[] squareObjects;
public List<Transform> squareList = new List<Transform>();
GameObject[] PinkSquares = GameObject.FindGameObjectsWithTag("PinkSquare");
PinkSquare[] pinkList = new PinkSquare[1];
GameObject[] CyanSquares = GameObject.FindGameObjectsWithTag("CyanSquare");
CyanSquare[] cyanList = new CyanSquare[1];
GameObject[] WhiteSquares = GameObject.FindGameObjectsWithTag("WhiteSquare");
WhiteSquare[] whiteList = new WhiteSquare[1];
private void OnDrawGizmos()
{
Gizmos.color = Color.black;
FillSquares();
for (int i = 0; i < squareList.Count; i++)
{
Vector3 currentPosition = squareList[i].position;
if (i > 0)
{
Vector3 previousPosition = squareList[i - 1].position;
Gizmos.DrawLine(previousPosition, currentPosition);
if(currentPosition.Equals(PinkSquares))
{
pinkList[i] = new PinkSquare();
}
else if (currentPosition.Equals(CyanSquares))
{
cyanList[i] = new CyanSquare();
}
else if (currentPosition.Equals(WhiteSquares))
{
whiteList[i] = new WhiteSquare();
}
}
}
}
void FillSquares()
{
squareList.Clear();
squareObjects = GetComponentsInChildren<Transform>();
foreach (Transform square in squareObjects)
{
if (square != this.transform)
{
squareList.Add(square);
}
}
}
}
I believe your issue is in your comparisons, you are trying to use an Equals to compare your currentPosition which is a Vector3 type to a GameObject[] which is an array of gameObjects. As I mentioned in my comments, this comparison will always fail as an array of gameObjects can not be equal to a vector.
Instead of using these lines, try this line:
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
The full snippet of if else would look like
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
{
pinkList[i] = new PinkSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("CyanSquare")
{
cyanList[i] = new CyanSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("WhiteSquare")
{
whiteList[i] = new WhiteSquare();
}
Your CharacterScript is going to need to get the gameObject or Transform from the Path script as it is only keeping track of indexes. Your issue in this script is you are comparing an integer to a GameObject which would never be true. I would also recommend not using OnDrawGizmos() as it is an editor only script and should only be used to render editor debugging tools. The only reference to a Gizmo I see in the function is Gizmos.color = Color.black; which does nothing as you are not rendering a gizmo anywhere. I would move this code to a different function and call it from your CharacterScript. Have the return type be GameObject or Transform of the square you are on, so the CharacterSCript can check which color it lands on. Using an Integer nor Vector3 to compare to a GameObject[] will never work.
I am not sure if there are issues elsewhere in the code, but as this comparison would always fail, none of these statements would get broken into. What this means is your panels would never have the chance to get their alpha set nor get created.
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.
I am a bit of a noob to programming and I am trying to make a GameObject , deactivate and reactivate over a set amount of seconds.For example I want my star to slowly blink before it goes away, to create a cool looking effect. If there is a better way of using this method done with out using SetActive(false) and what not , please feel free to give me your method - This is my code , Sorry if its messy i gotta get better at this but i will in due time
Thanks guys
//Timers
public float ScoreTimer;
public float[] TimeMarkStamp;
//Scoring
public int totalCollStars;
[Space]
public int maxStars = 5;
public GameObject[] StarImages;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
ScoreTimer += Time.deltaTime;
if (ScoreTimer <= TimeMarkStamp[0])
{
Debug.Log("It works");
StarImages[0].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[1])
{
Debug.Log("It workds" + TimeMarkStamp[1]);
StarImages[1].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[2])
{
Debug.Log("It works" + TimeMarkStamp[2]);
StarImages[2].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[3])
{
//This is not working
InvokeRepeating("flickerEffect", 3f, 1f);
}
}
void flickerEffect()
{
bool flickCheck = false;
if (flickCheck == false)
{
StarImages[3].SetActive(true);
flickCheck = true;
}
else if (flickCheck == true)
{
StarImages[3].SetActive(false);
flickCheck = false;
}
}
}
If there is a better way of using this method done with out using
SetActive(false) and what not
Yes, there is a better way, other than using the SetActive function. You should change the alpha color of the GameObject from 0 to 1 back and forth. After that you can then disable the GameObject with SetActive. This saves how much garbage would have been generated when repeatedly calling the SetActive function.
If this is a 3D GameObject, change the Rendering Mode from Opaque(default) to Fade or Transparent.
A simple function that can do this:
void blink(GameObject obj, float blinkSpeed, float duration)
{
StartCoroutine(_blinkCOR(obj, blinkSpeed, duration));
}
IEnumerator _blinkCOR(GameObject obj, float blinkSpeed, float duration)
{
obj.SetActive(true);
Color defualtColor = obj.GetComponent<MeshRenderer>().material.color;
float counter = 0;
float innerCounter = 0;
bool visible = false;
while (counter < duration)
{
counter += Time.deltaTime;
innerCounter += Time.deltaTime;
//Toggle and reset if innerCounter > blinkSpeed
if (innerCounter > blinkSpeed)
{
visible = !visible;
innerCounter = 0f;
}
if (visible)
{
//Show
show(obj);
}
else
{
//Hide
hide(obj);
}
//Wait for a frame
yield return null;
}
//Done Blinking, Restore default color then Disable the GameObject
obj.GetComponent<MeshRenderer>().material.color = defualtColor;
obj.SetActive(false);
}
void show(GameObject obj)
{
Color currentColor = obj.GetComponent<MeshRenderer>().material.color;
currentColor.a = 1;
obj.GetComponent<MeshRenderer>().material.color = currentColor;
}
void hide(GameObject obj)
{
Color currentColor = obj.GetComponent<MeshRenderer>().material.color;
currentColor.a = 0;
obj.GetComponent<MeshRenderer>().material.color = currentColor;
}
Usage:
void Start()
{
blink(gameObject, 0.2f, 5f);
}
If this is a SpriteRender, you have to replace all the obj.GetComponent<MeshRenderer>().material.color code with obj.GetComponent<SpriteRenderer>().color.
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
}
}