How to have an Coroutine Act like an Update - c#

I have been told I should not be using Updates when I don't need to use them. I am not sure when to not use them, but I am trying to figure it out.
I want to have an event, "Wave", run for 20 seconds and then switch to a random "Wave" and run for another 20 seconds and keep repeating this cycle.
Game Manager:
void Start()
{
StartFireWaves();
}
public void StartFireWaves()
{
StartCoroutine(wm.SelectWave());
}
Wave Manager:
public IEnumerator SelectWave()
{
float waitFor;
float diff = 0;
diff = nextWaveAT - Time.time;
if (diff <= 0f)
{
SpawnFlames();
waitFor = Random.Range(15, 20);
}
nextWaveAT = nextWaveAT + waitFor;
yield return new WaitForSeconds(waitFor);
}
SpawnFlames:
void SpawnFlames()
{
float val = Random.value;
if (val < .25f)
{
Wave1();
}
if (val >= .25f && val < .5f)
{
Wave2();
}
if (val >= .5f && val < .75f)
{
Wave3();
}
else
{
Wave4();
}
}
I am assuming this is how it should work, but it doesn't seem to keep "updating" or running. It just runs once and then nothing happens.

Use Coroutine with multiple nested while loops to do this. The first while loop is to make it run forever until stopRunningWaves() function is called. The second while loop is used to run the wave for x amount of time then jumps back to the first while loop.
bool keepRunningWaves = false;
IEnumerator startingRunningWaves(float second = 20)
{
if (keepRunningWaves)
{
yield break;
}
keepRunningWaves = true;
while (keepRunningWaves)
{
float timer = 0;
int randWave = Random.Range(1, 5);
while (timer < second)
{
if (!keepRunningWaves)
{
yield break;
}
if (randWave == 1)
{
Debug.Log("Running Wave 1");
Wave1();
}
else if (randWave == 2)
{
Debug.Log("Running Wave 2");
Wave2();
}
else if (randWave == 3)
{
Debug.Log("Running Wave 3");
Wave3();
}
else if (randWave == 4)
{
Debug.Log("Running Wave 4");
Wave4();
}
timer += Time.deltaTime;
yield return null;
}
//Reset Timer for next run
timer = 0;
yield return null;
}
keepRunningWaves = false;
}
void stopRunningWaves()
{
keepRunningWaves = false;
}
To test it, use 3 seconds to do it so that you will save your time:
StartCoroutine(startingRunningWaves(3));

Related

Anti-System time cheat not fully working

Whats Happening:
It works for the most part except after some time after using the offline coin count is always 0. Im am trying to make it so the player cant just change their system time to try to get more money faster. I also am not trying to do this by connection to server for time check. Does anyone see whats going wrong?
If statement is in awake:
if (PlayerPrefs.GetInt("offlineCheck").Equals(1))
{
ButtonCanvas.gameObject.SetActive(false);
OfflineCanvas.gameObject.SetActive(true);
PlayerPrefs.SetInt("offlineCheck", 0);
// year not the same
if (!PlayerPrefs.GetInt("year").Equals(System.DateTime.Now.Year))
{
// Add 24 Hour Coins
if (PlayerPrefs.GetInt("year") < System.DateTime.Now.Year)
{
offlineCoinCount = PlayerPrefs.GetInt("OfflineCoinsVal") * (24 * 60);
} else {
offlineCoinCount = 0;
}
}
else
{ // same Year
// month not the same
if (!PlayerPrefs.GetInt("month").Equals(System.DateTime.Now.Month))
{
// Add 24 Hour Coins
if (PlayerPrefs.GetInt("month") < System.DateTime.Now.Month)
{
offlineCoinCount = PlayerPrefs.GetInt("OfflineCoinsVal") * (24 * 60);
} else {
offlineCoinCount = 0;
}
}
else
{ // Same Month
// day not the same
if (!PlayerPrefs.GetInt("day").Equals(System.DateTime.Now.Day))
{
// Add 24 hours?
if (PlayerPrefs.GetInt("day") < System.DateTime.Now.Day)
{
offlineCoinCount = PlayerPrefs.GetInt("OfflineCoinsVal") * (24 * 60);
} else {
offlineCoinCount = 0;
}
}
else
{ // Same Day
// hour not the same
if (!PlayerPrefs.GetInt("timeHour").Equals(System.DateTime.Now.Hour))
{
// Add Coins
if (PlayerPrefs.GetInt("timeHour") < System.DateTime.Now.Hour)
{
offlineCoinCount = PlayerPrefs.GetInt("OfflineCoinsVal") * (((System.DateTime.Now.Hour - PlayerPrefs.GetInt("timeHour")) * 60) - (System.DateTime.Now.Minute - PlayerPrefs.GetInt("timeMin")));
} else {
offlineCoinCount = 0;
}
}
else
{ // Same hour
// min not the same
if (!PlayerPrefs.GetInt("timeMin").Equals(System.DateTime.Now.Minute))
{
// Add coins
offlineCoinCount = PlayerPrefs.GetInt("OfflineCoinsVal") * (System.DateTime.Now.Minute - PlayerPrefs.GetInt("timeMin"));
}
else
{ // Same min
}
}
}
}
}
}
Rest of Code for this anti-time cheat
private void OnApplicationQuit()
{
saveDateTime();
PlayerPrefs.SetInt("offlineCheck", 1);
//offlineCoinCount = 0;
}
private void OnApplicationFocus(bool focus)
{
saveDateTime();
PlayerPrefs.SetInt("offlineCheck", 1);
//offlineCoinCount = 0;
}
private void OnApplicationPause(bool pause)
{
saveDateTime();
PlayerPrefs.SetInt("offlineCheck", 1);
//offlineCoinCount = 0;
}
public void saveDateTime()
{
//Player Restart Game
//////
/// Check Time for coin bonus
////
if (PlayerPrefs.GetInt("year").Equals(System.DateTime.Now.Year))
{ // Same Year
if (PlayerPrefs.GetInt("month").Equals(System.DateTime.Now.Month))
{ // Same Month
if (PlayerPrefs.GetInt("day").Equals(System.DateTime.Now.Day))
{ // Same Day
if (PlayerPrefs.GetInt("timeHour").Equals(System.DateTime.Now.Hour))
{ // Same Hour
if (PlayerPrefs.GetInt("timeMin").Equals(System.DateTime.Now.Minute))
{ // Same Minute
}
else
{ // Different Minute
// Update if new Minute is higher than old
if (PlayerPrefs.GetInt("timeMin") < System.DateTime.Now.Month)
{
PlayerPrefs.SetInt("timeMin", System.DateTime.Now.Minute);
}
}
}
else
{ //Different Hour
// Update if new hour is higher than old
if (PlayerPrefs.GetInt("timeHour") < System.DateTime.Now.Month)
PlayerPrefs.SetInt("timeHour", System.DateTime.Now.Hour);
PlayerPrefs.SetInt("timeMin", System.DateTime.Now.Minute);
}
}
else
{ // Different Day
// Update if new day is higher than old
if (PlayerPrefs.GetInt("day") < System.DateTime.Now.Month)
{
PlayerPrefs.SetInt("day", System.DateTime.Now.Year);
PlayerPrefs.SetInt("timeHour", System.DateTime.Now.Hour);
PlayerPrefs.SetInt("timeMin", System.DateTime.Now.Minute);
}
}
}
else
{ // Different Month
// Update if new month is higher than old
if (PlayerPrefs.GetInt("month") < System.DateTime.Now.Month)
{
PlayerPrefs.SetInt("month", System.DateTime.Now.Year);
PlayerPrefs.SetInt("day", System.DateTime.Now.Year);
PlayerPrefs.SetInt("timeHour", System.DateTime.Now.Hour);
PlayerPrefs.SetInt("timeMin", System.DateTime.Now.Minute);
}
}
}
else
{ // Different Year
// Update if new year is higher than old
if (PlayerPrefs.GetInt("year") < System.DateTime.Now.Year)
{
PlayerPrefs.SetInt("year", System.DateTime.Now.Year);
PlayerPrefs.SetInt("month", System.DateTime.Now.Year);
PlayerPrefs.SetInt("day", System.DateTime.Now.Year);
PlayerPrefs.SetInt("timeHour", System.DateTime.Now.Hour);
PlayerPrefs.SetInt("timeMin", System.DateTime.Now.Minute);
}
}
}

Unity c# Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration

Hello i got this error wen i updated unity
Assets/TCG/Scripts/card.cs(1232,71): error CS1622: Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration
I looked at the code a bunch of times played around with it and i cant fix it i looked for a fixes but there non i can understant that good so can someone help me heres the code if you need the hole code tell me i will add it this is the part that the error shows .
IEnumerator PayAdditionalCostAndPlay()
{
if (DiscardCost > 0 && ValidSpell())
{
Player.ActionCancelled = false;
Player.targets.Clear();
Debug.Log("this card has an additional discard cost");
for (int i = 0; i < DiscardCost; i++)
{
Player.NeedTarget = 21; // a card in hand to discard
while (Player.NeedTarget > 0)
{
yield return new WaitForSeconds(0.1f);
}
if (Player.ActionCancelled)
{
Debug.Log("action cancelled");
return false;
}
}
foreach (GameObject target in Player.targets) //discard
{
target.GetComponent<card>().Discard();
}
}
}
A single method cannot both yield return and return. You must choose one or the other.
You cannot use return inside co-routine, if you want to stop the co-routine execution use yield break instead of return false as follows -
IEnumerator PayAdditionalCostAndPlay()
{
if (DiscardCost > 0 && ValidSpell())
{
Player.ActionCancelled = false;
Player.targets.Clear();
Debug.Log("this card has an additional discard cost");
for (int i = 0; i < DiscardCost; i++)
{
Player.NeedTarget = 21; // a card in hand to discard
while (Player.NeedTarget > 0)
yield return new WaitForSeconds (0.1f);
if (Player.ActionCancelled) {
Debug.Log("action cancelled");
yield break;
}
}
foreach (GameObject target in Player.targets) //discard
target.GetComponent<card>().Discard();
}
}
My suspicion is that you are simply trying to exit the co-routine when the ActionCancelled is set to true, A slight modification and you end up with this.
You cannot return a value in a co-routine but what you can do is call an external method and BREAK the (stops the forloop in it's tracks)
IEnumerator PayAdditionalCostAndPlay()
{
if (DiscardCost > 0 && ValidSpell())
{
Player.ActionCancelled = false;
Player.targets.Clear();
Debug.Log("this card has an additional discard cost");
for (int i = 0; i < DiscardCost; i++)
{
Player.NeedTarget = 21; // a card in hand to discard
while (Player.NeedTarget > 0) yield return new WaitForSeconds(0.1f);
if (Player.ActionCancelled)
{
Debug.Log("action cancelled");
OnPlayerActionCancelled(); // optional, obviously
break; // stop processing the for-loop
}
}
if (!Player.ActionCancelled)
{
foreach (GameObject target in Player.targets) //discard
target.GetComponent<card>().Discard();
}
}
}
private void OnPlayerActionCancelled()
{
// Do something when a player action is cancelled
}

How can I improve this logic? C#

I have a library that returns CS:GO stats in real-time from the game. I'm making a program that stores the stats and analyse it.
I have this function:
private void UpdateKills(GameState gs)
{
int currentKills = -1;
if (lastKills == -1) // first time getting player info
{
int temp = gs.Player.MatchStats.Kills;
currentKills = temp;
lastKills = temp;
}
else
{
currentKills = gs.Player.MatchStats.Kills;
int dif = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else
{
if (dif != 0 && dif > 0) // player killed someone AND it was not teamkill
{
ps.Kills += dif; // add the kills to the main variable
lastKills = currentKills;
dif = 0;
playSimpleSound();
}
}
}
}
This is my function that handles the kills. The most of the time it works very well, but sometimes it just freaks out, and I don't know if the problem is my logic or if it is a library problem.
Note: I'm using this library: github.com/rakijah/CSGSI
My logic is:
Get the player kills
Increment those kills in the PlayerStats object.
Is my code logically correct? Can my code be more "correct"?
I'm still not entirely sure what this function is supposed to be doing, but I simplified it for you:
private void UpdateKills(GameState gs)
{
lastKills = currentKills;
int currentKills = gs.Player.MatchStats.Kills;
int diff = currentKills - lastKills;
if (currentKills == 0 && lastKills != 0) // maybe changed server/map/whatever
{
lastKills = -1;
}
else if (diff > 0) // player killed someone AND it was not teamkill
{
ps.Kills += diff; // add the kills to the main variable
playSimpleSound();
}
}
Well, after some research in finally undertand your problem. You DON'T have to do anything!, the API does all the work for you, watch the next image:
As you can see, the console app shows my steam name, the map and kills. I start with zero kills, then I kill a teammate and after that an enemy. The API created by #rakijah autoupdates those values.
Now the code:
static void Main(string[] args)
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += new NewGameStateHandler(OnNewGameState);
if (!gsl.Start())
{
Environment.Exit(0);
}
System.Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gs)
{
System.Console.WriteLine("Map: {0}", gs.Map.Name);
System.Console.WriteLine("Player Name: {0}", gs.Player.Name);
System.Console.WriteLine("Player Kills: {0}", gs.Player.MatchStats.Kills);
}
UPDATE: The OP needs to store the total kills even when the map changes. I experimented with paper and pencil, please try running the program and tell me if it worked or not
private static void Main()
{
CsGoIntegration();
}
private static void CsGoIntegration()
{
var gsl = new GameStateListener(3000);
gsl.NewGameState += OnNewGameState;
if (!gsl.Start())
{
Environment.Exit(0);
}
Console.WriteLine("Listening...");
}
private static void OnNewGameState(GameState gameState)
{
SaveMatchsData(gameState);
}
private static int? _totalKillScore;
private static string _lastMapName;
private static int? _lastKillScore;
private static void SaveMatchsData(GameState gameState)
{
const string undefinedString = "Undefined";
// If the SaveMatchsData is running and the CSGO server is offline
if (gameState.Map.Name == undefinedString && string.IsNullOrEmpty(_lastMapName))
return;
// When the match is not started, the Round is -1
if (gameState.Map.Name != undefinedString && gameState.Map.Round > -1)
{
if (string.IsNullOrEmpty(_lastMapName))
{
UpdateData(gameState, true);
}
else
{
// Same map
if (_lastMapName == gameState.Map.Name)
{
// Check if the Score Changes
if (_lastKillScore == gameState.Player.MatchStats.Kills) return;
UpdateData(gameState);
}
// The Map Changes
else
{
UpdateData(gameState, true);
}
}
}
}
private static void UpdateData(GameState gameState, bool updateMap = false)
{
if (updateMap)
_lastMapName = gameState.Map.Name;
_lastKillScore = gameState.Player.MatchStats.Kills;
_totalKillScore += gameState.Player.MatchStats.Kills;
}
Cheers.

How to make Image pop up when my ball hits STRIKE or SPARE?

Hello guys here I am trying to make a bowling game. What I want is to pop up image of Strike when ball hits strike or spare image when hits spare.
please help me out your help will be appreciated.
please answer me as soon as possible.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class ScoreDisplay : MonoBehaviour {
public Image strick;
public Text[] rollTexts, frameTexts;
public void FillRolls (List<int> rolls) {
string scoresString = FormatRolls (rolls);
for (int i = 0; i < scoresString.Length; i++) {
rollTexts[i].text = scoresString[i].ToString();
}
}
public void FillFrames (List<int> frames) {
for (int i = 0; i < frames.Count; i++) {
frameTexts[i].text = frames[i].ToString();
}
}
public static string FormatRolls (List<int> rolls) {
string output = "";
for (int i = 0; i < rolls.Count; i++) {
int box = output.Length + 1; // Score box 1 to 21
if (rolls[i] == 0) { // Always enter 0 as -
output += "-";
strick.enabled = true;
Debug.LogError("Better Luck Next Time");
} else if (box % 2 == 0 && rolls[i-1]+rolls[i] == 10) { // SPARE anywhere
output += "/";
Debug.LogError("Its Spare");
} else if (box >= 19 && rolls[i] == 10) { // STRIKE in frame 10
output += "X";
Debug.LogError("Congo you got Strick");
} else if (rolls[i] == 10) { // STRIKE in frame 1-9
output += "X ";
Debug.LogError("Its Strick");
} else {
output += rolls[i].ToString(); // Normal 1-9 bowl
Debug.LogError("Try Your Hard");
}
}
return output;
}
}
What you could do is put the image as a child of an empty gameobject,
this will turn it into a gameObject which you can easily instantiate in your code using the Instantiate(object,position,rotation) function.
You can declare a public GameObject, drag your prefab (Gameobject with your image as child) into the inspector then use Instantiate on it, I recommend doing this because then you have more control over your gameobject after it's been instantiated.
for (int i = 0; i < rolls.Count; i++) {
int box = output.Length + 1; // Score box 1 to 21
if (rolls[i] == 0) { // Always enter 0 as -
output += "-";
Instantiate(GameObjectYouWantToInstantiate, location, rotation);
//strick.enabled = true;
Debug.LogError("Better Luck Next Time");
} else if (box % 2 == 0 && rolls[i-1]+rolls[i] == 10) { // SPARE anywhere
output += "/";
Debug.LogError("Its Spare");
} else if (box >= 19 && rolls[i] == 10) { // STRIKE in frame 10
output += "X";
Debug.LogError("Congo you got Strick");
} else if (rolls[i] == 10) { // STRIKE in frame 1-9
output += "X ";
Debug.LogError("Its Strick");
} else {
output += rolls[i].ToString(); // Normal 1-9 bowl
Debug.LogError("Try Your Hard");
}
}
Use Destroy(Strick) when you want to destroy it.

Playing 30 sound effects at the same time repeatedly

I'm trying to play about 30 piano notes at the same time in my XNA application on Windows Phone 7.
I have imported and loaded the wave files like below
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
sound3 = Content.Load<SoundEffect>("1");
sound5 = Content.Load<SoundEffect>("3");
sound6 = Content.Load<SoundEffect>("4");
sound7 = Content.Load<SoundEffect>("5");
sound8 = Content.Load<SoundEffect>("6");
}
Every sound effect file is less than a second, so I'm trying to play all of them at the same time. I play them using a for loop which runs every second.(So at every loop 30 sounds will be played then it goes on and plays the same 30 sounds each second)
It works fine for a few seconds but suddenly it stops playing any sound (The loop is still working) then again starts working for once or twice and again stops working . It also sometimes makes some bad noises as if the audio system cant support too many sounds to be play at a time.
I'm not sure how I can solve the problem , if its a buffer problem or threads.
Nico Schertler is right! I've faced the same problem and fixed it by managing instances. Normally when you play soundeffect you always get the instance! By default you have to hope XNA/Monogame will care about it, but it doesn't. When you have to many live instances (even stopped, you get breaks, noise, even silence.
I hold rectangular array for all my sound effects with up to 4 instance for each, and if I have instances of a sound I want to play instead of creating I stop the oldest (by timestamp), play it and remember the current timestamp.
See the following code:
private const int MAX_INST_OF_ONE_SOUND = 4;
private SoundEffectInstance[][] sndInstArray = null;
private float[][] sndInstTimes = null;
public init()
{
sndArray = new SoundEffect[SoundsSchema.sounds.Length];
sndInstArray = new SoundEffectInstance[SoundsSchema.sounds.Length][];
sndInstTimes = new float[SoundsSchema.sounds.Length][];
for (int i = 0; i < SoundsSchema.sounds.Length; i++)
{
try
{
sndArray[i] = content.Load<SoundEffect>(SoundsSchema.sounds[i]);//SoundsSchema is string list holder class
}
catch (System.Exception)
{
}
sndInstArray[i] = new SoundEffectInstance[MAX_INST_OF_ONE_SOUND];
sndInstTimes[i] = new float[MAX_INST_OF_ONE_SOUND];
}
}
private SoundEffectInstance getValidInstance(int sound)
{
if (sound < 0 || sound > sndInstArray.Length)
return null;
SoundEffectInstance inst = null;
for (int i = 0; i < MAX_INST_OF_ONE_SOUND; i++)
{
if (sndInstArray[sound][i] == null || (sndInstArray[sound][i] != null && sndInstArray[sound][i].IsDisposed))
{
sndInstArray[sound][i] = sndArray[sound].CreateInstance();
sndInstTimes[sound][i] = MyEngine.CurTime;
inst = sndInstArray[sound][i];
break;
}
}
if (inst == null)
{
float min_time = float.MaxValue;
int ind = -1;
for (int i = 0; i < MAX_INST_OF_ONE_SOUND; i++)
{
if (sndInstArray[sound][i] != null && sndInstTimes[sound][i] < min_time)
{
min_time = sndInstTimes[sound][i];
ind = i;
}
}
if (ind == -1)
ind = 0;
if (sndInstArray[sound][ind].IsDisposed)
sndInstArray[sound][ind] = sndArray[sound].CreateInstance();
else
{
try
{
sndInstArray[sound][ind].Stop();
}
catch
{}
}
sndInstTimes[sound][ind] = MyEngine.CurTime;
inst = sndInstArray[sound][ind];
}
return inst;
}
public virtual void playSound(int sound, float volume, float panoram, bool loop)
{
if (sound < 0 || sound > sndArray.Length)
return null;
if (!mMuted && mVolume > 0)
{
SoundEffectInstance sndinst = getValidInstance(sound);
if (sndinst == null)
return null;
try
{
sndinst.IsLooped = loop;
sndinst.Pan = panoram;
sndinst.Volume = mVolume * vol;
sndinst.Play();
}
catch
{
}
}
}

Categories