I'm having trouble counting the points of my AI Paddle Player and the user Paddle Player each time they miss colliding the ball. I tried using a boolean method and loops to count points, but to no avail as the program keeps on stating that the label in which my points are to be displayed, is "stack overflowed" due to an infinite loop which I am unable to recognize. So can you please help me.
Here is my code:
private void resetShiruken()
{
if ((reset == false) && (AIPoints < MAXPoints))
{
picShiruken.Location = new Point(ClientSize.Width / 2 - picShiruken.Width / 2, ClientSize.Height / 2 - picShiruken.Height / 2); //puts the picShiruken Picturebox in the middle anytime the picPlayerPaddle or picAIPaddle miss and is useful for counting the points of the computer and the player.
reset = true;
}
TheWinner();
}
private void TheWinner()
{
while (reset == true)
{
AIPoints += 1;
reset = false;
}
if (AIPoints >= AIPoints)
{
lblAIPoints.Text = AIPoints.ToString();
}
resetShiruken();
}
. resetShiruken() is a method that resets the ball to the middle each time any player misses.
. TheWinner() is a method that determines the winner of the game after either one of the players reach 5 points.
Thank You very Much,
Kai
As comments says:
you have recursive call of methods which lasts forever. resetShiruken calls TheWinner which calls resetShiruken and so on....
private void resetShiruken()
{
if ((reset == false) && (AIPoints < MAXPoints))
{
picShiruken.Location = new Point(ClientSize.Width / 2 - picShiruken.Width / 2, ClientSize.Height / 2 - picShiruken.Height / 2); //puts the picShiruken Picturebox in the middle anytime the picPlayerPaddle or picAIPaddle miss and is useful for counting the points of the computer and the player.
reset = true;
}
TheWinner();
}
private void TheWinner()
{
while (reset == true)
{
AIPoints += 1;
reset = false;
}
if (AIPoints >= AIPoints)
{
lblAIPoints.Text = AIPoints.ToString();
}
//resetShiruken(); <--- if you get rid of that call, should be fine.
}
Please note if you need to do reset after show the Winner, you should add additional parameter to reset method, or create separated method for post-winning reset.
Regular answer:
Your functions keep calling each other. Thats probably where the overflow is coming from.
From the functions given I'm unable to deduce exactly what your program flow would look like so I can't provide you with a fix which will do what you expect it to do.
To get rid of the overflow however simply remove either the call to "TheWinner" from "resetShiruken" or remove the call to "resetShiruken" from "TheWineer".
I suspect you should remove the latter.
Code style:
You're mixing upercase and lowercase function names which is a bad habit.
The default case for method names is "PascalCase" in c# (as depicted by the documentation).
Related
I have a joystick display picture for my game. Currently, when the player touches the screen the image disappears and when the player is not touching the screen, it reappears. I wrote that using an if else statement.
if (indicator.inputIndicator.x != 0)
{
joystick.SetActive(false);
}
else
{
joystick.SetActive(true);
}
The problem is, I want the image to reappear after some time like 2 seconds. I want to delay the "else", but I do not want to use a coroutine. I want "else" to work after 2 seconds since the player takes his hand off the screen but I couldn't figure out how to do it. any help will be great.
Setting a timer is a pretty common problem you have to solve in Unity. One basic approach is to have a variable that you add Time.deltaTime every update. That way you can tell how long it has been since some condition was met.
Every Update iteration that meets the condition, add Time.deltaTime to the variable. If at some point the condition fails, reset the variable to 0. Then you can just base your joystick.SetActive() call on the value of your variable.
For example, your script might become:
float thresholdTimeToShowPrompt = 2;
// By starting at the threshold, the image is hidden at the start until a touch
float timeSincePlayerTouch = 2;
void Update()
{
// Rather than calling SetActive directly, just update the timer
if (indicator.inputIndicator.x != 0)
{
timeSincePlayerTouch = 0;
}
else
{
timeSincePlayerTouch += Time.deltaTime;
}
// Now we can base visibility on the time since the last user touch
bool shouldShowIcon = timeSincePlayerTouch >= thresholdTimeToShowPrompt;
// Only call SetActive when needed, in case of overhead
if (shouldShowIcon && !joystick.activeSelf)
{
joystick.SetActive(true);
}
else if (!shouldShowIcon && joystick.activeSelf)
{
joystick.SetActive(false);
}
}
I want to be able to flash stuff at a certain frequency. For an example, let's say 2Hz. I also want to be able to specify a ratio, where I can have the thing displayed for let's say 2/3 of the cycle and have it hidden for 1/3, so the ratio would be 2:1. It's a wild bunch of flashing, so I Need to stay flexible in the way I do it. There might be some flashing with a ratio of 3:5 and a frequency of 2Hz, and some other flashing at 4Hz with ratio 1:1, and so on.
Also, I need to be able to flash in sync. So if one object is flashing already and I start flashing another one, they need to be in sync (or rather their cycles need to be in sync, the flashing may vary as the ratio may be different). But if at the same frequency, they need to "turn on" at the same time, even if their ratios are different. Also, they all need to turn on at the same time the slowest turns on.
My current approach: I have a GameObject FlashCycle, that essentially in it's update method calculates a progress for the 3 frequency's I have (2Hz, 4Hz and 8Hz).
float time = Time.time;
twoHerzProgress = (time % twoHerzInSeconds) / twoHerzInSeconds;
fourHerzProgress = (time % fourHerzInSeconds) / fourHerzInSeconds;
eightHerzProgress = (time % eightHerzInSeconds) / eightHerzInSeconds;
I have tried different times, but that didn't really matter so let's just stick to that one if you don't think it's a bad idea!
Now, whenever I want to flash an object, in it's own Update() I do this:
switch (flashRate.herz)
{
case FlashRateInterval.twoHerz:
show = flashCycle.oneHerzProgress <= onTimePercentage;
case FlashRateInterval.fourHerz:
show =flashCycle.twoHerzProgress <= onTimePercentage;
case FlashRateInterval.eightHerz:
show =flashCycle.fourHerzProgress <= onTimePercentage;
default:
show =true;
}
and then just continue and have the object displayed if show == true.
Unfortunately this doesn't flash the objects at a nice smooth and regular interval. I measured the 2Hz interval and got differences in the ratio of up to 48ms, and though it seems like not much it really makes a difference on the screen.
So the question boils down to: How can I get quick, reqular flashes while maintaining the flexibility (ratio and frequency wise) and have a syncronized flash?
Thanks for your help!
You could use Coroutines and WaitForSeconds to achieve that
// onRatio and offRatio are "optional" parameters
// If not provided, they will simply have their default value 1
IEnumerator Flash(float frequency ,float onRatio = 1, float offRatio = 1)
{
float cycleDuration = 1.0f / frequency;
float onDuration = (onRatio/ (onRatio + offRatio)) * cycleDuration;
float offDuration = (offRatio/ (onRatio + offRatio)) * cycleDuration;
while(true)
{
show = true;
yield return new WatForSeconds(onDuration);
show = false;
yield return new WatForSeconds(offDuration);
}
}
so you can call it either with a frequency e.g. 8Hz
StartCoroutine(Flash(8.0f));
this is actually equal to any call where you set onRatio = offRatio e.g.
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 1));
StartCoroutine(Flash(8.0f, onRatio = 2, offRatio = 2));
....
or with a frequency and ratios e.g. 1(on):2(off) with 8Hz
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 2));
With this setup the Coroutine runs "forever" in the while(true)-loop. So, don't forget before you start a new Coroutine with different parameters to first stop all routines with
StopAllCoroutines();
Now if you want to change that dynamically in an Update method, you would have to add some controll flags and additional variables in roder to make sure a new Coroutine is only called when something changed:
FlashRateInterval currentInterval;
float currentOnRatio = -1;
float currentOffRatio = -1;
void Update()
{
// if nothing changed do nothing
if(flashRate.herz == currentInterval
//todo && Mathf.Approximately(<yourOnRatio>, currentOnRatio)
//todo && Mathf.Approximately(<yourOffRatio>, currentOffRatio)
) return;
StopAllCoroutines();
currentInterval = flashRate.herz;
//todo currentOnRatio = <yourOnRatio>;
//todo currentOffRatio = <yourOffRatio>;
switch (flashRate.herz)
{
case FlashRateInterval.twoHerz:
StartCoroutine(2.0f);
//todo StartCoroutine(2.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
case FlashRateInterval.fourHerz:
StartCoroutine(4.0f);
//todo StartCoroutine(4.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
case FlashRateInterval.eightHerz:
StartCoroutine(8.0f);
//todo StartCoroutine(8.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
default:
show =true;
}
}
Notes:
I dont know your FlashRateInterval but if you need to use it for some reason you could make it like
public enum FlashRateInterval
{
AllwaysOn,
twoHerz = 2,
fourHerz = 4,
eightHerz = 8
}
in order to directly use the correct values.
I would call a frequency variable flashRate.herz. You also wouldn't call a size value cube.meters. I'ld recommend to rename it to flashRate.frequency.
To archieve that syncing you would somehow need access to all Behaviours and compare their values (so I'ld say some static List<YourBehavior>) and than e.g. in the Coroutine wait until all bools are e.g. set to true before continuing with your own one. For that you would need an additional bool since it is possible that show is true permanently on one component.
public bool isBlinking;
IEnumerator Flash(float frequency ,float onRatio = 1, float offRatio = 1)
{
//todo: You'll have to set this false when not blinking -> in Update
isBlinking = true;
float cycleDuration = 1.0f / frequency;
float onDuration = (onRatio/ (onRatio + offRatio)) * cycleDuration;
float offDuration = (offRatio/ (onRatio + offRatio)) * cycleDuration;
// SYNC AT START
show = false;
// wait until all show get false
foreach(var component in FindObjectsOfType<YOUR_COMPONENT>())
{
// skip checking this component
if(component == this) continue;
// if the component is not running a coroutine skip
if(!component.isBlinking) continue;
// Now wait until show gets false
while(component.show)
{
// WaitUntilEndOfFrame makes it possible
// for us to check the value again already before
// the next frame
yield return new WaitForEndOfFrame;
}
}
// => this line is reached when all show are false
// Now lets just do the same but this time wating for true
// wait until all show get false
foreach(var component in FindObjectsOfType<YOUR_COMPONENT>())
{
// skip checking this component
if(component == this) continue;
// if the component is not running a coroutine skip
if(!component.isBlinking) continue;
// Now wait until show gets false
while(!component.show)
{
// WaitUntilEndOfFrame makes it possible
// for us to check the value again already before
// the next frame
yield return new WaitForEndOfFrame;
}
}
// this line is reached when all show are getting true again => begin of loop
while(true)
{
.........
Instead of using FindObjectsOfType<YOUR_COMPONENT>() which is kind of slow you could also do something like
public static List<YOUR_COMPONENT> Components = new List<YOUR_COMPONENT>();
private void Awake()
{
if(!Components.Contains(this)){
Components.Add(this);
}
}
so you also get currently disabled components and objects
You got some diferences because you are doing everything in an Update() cycle with <= condition. On slower/faster machines you will have more/less differences because the frame's duration will never be equal to your frequency.
Try doing everything in a Corotine: unity coroutine docs
//bad code below but i think its more understandable like this
IEnumerator Flash()
{
while(true)
{
BlinkOn();
Sync();//sync here another cicle if you want to sync when on starts
yield return new WaitForSeconds(yourDuration);// yourDuration*multiplier/something+0.5f....ecc
BlinkOff()
Sync();//sync here another cicle if you want to sync when of starts
yield return new WaitForSeconds(yourDuration);
}
}
im trying to build Pong Game with Microphone Input as controls for the paddles. the following part of the code (c#) is moving the paddle.
void Update ()
{
loudness=GetAveragedVolume() * sensitivty;
if (loudness>=8)
{
this.GetComponent<Rigidbody2D>().velocity=new Vector2(this.GetComponent<Rigidbody2D>().velocity.y,4);
}
shouldn´t this code below do the job? however its not working
else (loudness<=8)
{
this.GetComponent<Rigidbody2D>().velocity=new Vector2(this.GetComponent<Rigidbody2D>().velocity.y,-4);
}
Its obviously an easy problem but im kinda stuck in here with this noob question
Thanks in advance
EDIT// what i want to do:
Move the paddle up when the microphone receives Sound and drop back down if there is no sound, just like an value from an visual amp.
Daniel
Given that Update () is called correctly and GetAveragedVolume() returns meaningful values, it would have to look like this:
void Update () {
loudness = GetAveragedVolume() * sensitivty;
if (loudness > 8) {
this.GetComponent<Rigidbody2D>().velocity = new Vector2(this.GetComponent<Rigidbody2D>().velocity.x, 4);
}
else {
this.GetComponent<Rigidbody2D>().velocity = new Vector2(this.GetComponent<Rigidbody2D>().velocity.x, -4);
}
}
Your mistakes:
else (...) is invalid. Use else if(...).
You used this.GetComponent<Rigidbody2D>().velocity.y instead of this.GetComponent<Rigidbody2D>().velocity.x for the x-component of the two new vectors.
Some tips:
Wether you use >= or > does not really matter for floating point numbers in most cases, and definitely not in your one.
else is sufficient here. You don't need to check else if (loudness <= 8), because if it isn't > 8, then it is always <= 8.
Conventionally, you write a = b; / a, b and not a=b; / a,b, to make your code more readable.
I hope that works for you!
I have a "datapack" hidden in each of my levels, the system remembers per level if the artifact has been taken and if so it disables the artifact when a player replays it but i also want to keep track of the total amount taken, the system almost works there's just 1 small issue:
When i finish the level with the first datapack, in the menu it says: 1, this is correct.
but when i do it with the 2nd, it says 3, with the 3rd it says 4, 4th says 5 etc
i don't understand why and thus can't fix it
here's the code:
function OnTriggerEnter(other : Collider) {
if(other.CompareTag("DataPacket")){
pickedUpDataPacket = 1;
Destroy(other.gameObject);
gameObject.Find("DatapackFound").guiText.enabled = true;
yield WaitForSeconds (1.5);
gameObject.Find("DatapackFound").guiText.enabled = false;
}
if(other.CompareTag("Finish") && pickedUpDataPacket == 1){
PlayerPrefs.SetInt("DataPackLevel" + levelindex.ToString(), 1);
//if(!PlayerPrefs.HasKey("totalDatapacks")){
//PlayerPrefs.SetInt("totalDatapacks", 1);
//} else {
PlayerPrefs.SetInt("totalDatapacks", (PlayerPrefs.GetInt("totalDatapacks")+1));
}
}
//}
i already commented a part out, i believe this was also part of the issue.
and part of a 2nd script:
if(datapacktotal){
if(PlayerPrefs.GetInt("totalDatapacks") > 0){
findText.text = "Collected:" + PlayerPrefs.GetInt ("totalDatapacks");
}
Thanks in advance :)
From the described behaviour it seems that, in some occasions, the collision is triggered multiple times, before the datapack is being destroied. As in level 2, where the counter passes from 1 to 3.
My though is that your collider has multiple contact points, so that - if you touches n of them - the collision is triggered n times.
I would try a simple experiment, just use a flag to determine if that's the first time you "touch" the collider; then, you'll update the PlayerPref just in that case:
function OnTriggerEnter (other : Colliderstrong text){
if (collisionAlreadyConsidered) return;
collisionAlreadyConsidered = true;
// your code here...
}
function Update(){
collisionAlreadyConsidered = false;
}
, where collisionAlreadyConsidered is a global variable.
I've written code to reset the x position of the ufo when it moves off the screen. I have taken into consideration everything that could happen with the ufo.
Below is the code which says if the ufo travels off the screen, then the x position of the ufo is set back to 0, and it is killed off by means of false. I don't know what more i could add. The ufo travels off the screen, not to be seen ever again (poor thing) :( Any help?
if (ufo.alive == false)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);
{
if (randomNumber == 1)
{
ufo.alive = true;
}
}
{
if (ufo.XPos > 1000)
{
// kill the ufo if it goes off th
ufo.alive = false;
ufo.XPos = 0;
}
}
//make a new one
// here you want to do it randomly .
// so
//int random = random number (you have to do some code to make a random number google it.
//if (random number == 1)
// ufo = new ufo();
// so if you tell it to make a random number between 1 and 1000, then every now and then, 1 will be the number it makes
// fo when it amkes one, and randomnumber is equal to 1, it will make a new ufo.
// i will let you figure out how to do the random bit.
// i guess haha
}
//if ufo is alive
// check for collision
if (ufo.alive == true)
{
// also, we need to make it move
ufo.XPos = ufo.XPos + 1;
if (MissileFired != null)
{
// if you miss, and the ufo carries on, it will go forever.
//so
Rectangle rectMissile = new Rectangle((int)MissileFired.GetPosition().X, (int)MissileFired.GetPosition().Y, MissileImg.Width, MissileImg.Height);
Rectangle rectUFO = new Rectangle(ufo.XPos, 30, UFOImage.Width, UFOImage.Height);
if (rectMissile.Intersects(rectUFO))
{
PlayerScore = PlayerScore + 1000;
// we needed to kill the missile, other wise it gives you a point for every time it goes through.
MissileFired = null;
//now only 1000 points for winning
ExplosionSoundInstance.Play();
ufo.alive = false;
}
}
}
}
EDITED CODE: above
the error you have is easy to debug and fix, you should learn to use a debugger, it is very useful.
here is a debugging tutorial
Basically the check to see if the position of the UFO > 1000 is never being run when the UFO is alive because it's inside the scope of the first IF statement.
if (ufo.alive == false)
{
if (ufo.XPos > 1000)
{
}
}
if the UFO is moving shouldn't you be checking for the position while it's alive?
I'm not sure that your brackets are well-formed. The open bracket { on line 5 doesn't make any sense there. Plus you dont' have a closing bracket at the very end.
Maybe the code is dying not the UFO?