/** * Apply the effect of the dam * * Fish will attempt to cross the dam and may be able to pass or "get stuck" and die */ protected override void ApplyFilterEffect(Fish fish) { // only let it through if it hasn't been flagged as stuck if (!fish.IsStuck()) { // chance between fish getting past the dam and being caught/getting stuck depends on what size the fish is float crossingRate; FishGenePair sizeGenePair = fish.GetGenome()[FishGenome.GeneType.Size]; if (sizeGenePair.momGene == FishGenome.b && sizeGenePair.dadGene == FishGenome.b) { crossingRate = smallCrossingRate; } else if (sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B) { crossingRate = mediumCrossingRate; } else { crossingRate = largeCrossingRate; } // based on the crossing rate we figured out, roll for a crossing // if we pass, put the fish past the dam if (Random.Range(0f, 1f) <= crossingRate) { fish.transform.position = GetRandomDropOff(fish.transform.position.z); } // if it didn't make it, make it permanently stuck (so it can't try repeated times) else { fish.SetStuck(true); } } }
/** * Get a list of all large fish genomes from a list of fish genomes * * @param genomeList List<FishGenome> The list of fish to be looked through * * @return List<FishGenome> A list of all large fish within the original list */ public static List <FishGenome> FindLargeGenomes(List <FishGenome> genomeList) { return(genomeList.Where((fish) => { FishGenePair sizeGenePair = fish[FishGenome.GeneType.Size]; return sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B; }).ToList()); }
/** * Constructor for situations where we want to create a genome from two parent genomes * * @param momGenome FishGenePair The genome from the mother * @param dadGenome FishGenePair the genome from the father */ public FishGenome(FishGenome momGenome, FishGenome dadGenome) { for (int index = 0; index < Length; index++) { FishGenePair newPair = new FishGenePair(); newPair.momGene = Random.Range(0, 2) == 1 ? momGenome[index].momGene : momGenome[index].dadGene; newPair.dadGene = Random.Range(0, 2) == 1 ? dadGenome[index].momGene : dadGenome[index].dadGene; genePairList[index] = newPair; } }
/* * The sealion attempts to catch a given fish * * @param fish The fish the sealion is catching */ private IEnumerator TryCatchFishCoroutine(Fish fish) { // How likely we are to catch fish is dependent on what size the fish is // Determine that now float catchRate; float weight; FishGenePair sizeGenePair = fish.GetGenome()[FishGenome.GeneType.Size]; switch (sizeGenePair.momGene) { case FishGenome.X when sizeGenePair.dadGene == FishGenome.X: catchRate = femaleCatchRate; weight = 2f; //4 Debug.Log("bbCatchR=" + catchRate + "; weight=" + weight); break; case FishGenome.X when sizeGenePair.dadGene == FishGenome.Y: catchRate = maleCatchRate; weight = 9f; //15 Debug.Log("BBCatchR=" + catchRate + "; weight=" + weight); break; default: catchRate = maleCatchRate; weight = 6f; //9 break; } Debug.Log("SeaLionCatch: MaleCR=" + maleCatchRate + "FemCR=" + femaleCatchRate); // Figure out whether the fish will be caught or not bool caught = Random.Range(0f, 1f) <= catchRate; // Handle fish being caught if (caught) { // Tell the fish that it is being caught fish.StartCatch(); // Trigger Water Splash effect on fish fish.waterSplash.Play(); fish.swimSpeed = 0; fish.fishRenderer.enabled = false; yield return(new WaitForSeconds(2)); // Actually catch the fish fish.Catch(); caughtFish.Add(fish); } // Fish escaped -- just wait for end of action else { yield return(new WaitForSeconds(timePerApplyEffect)); } }
/** * Apply the effect of the dam * * Fish will attempt to cross the dam and may be able to pass or "get stuck" and die * * @param fish The fish trying to pass by the dam */ public void ApplyFilterEffect(Fish fish) { // Only let it through if it hasn't been flagged as stuck if (!fish.IsStuck()) { // Chance between fish getting past the dam and being caught/getting stuck depends on what size the fish is float crossingRate; Debug.Log("Dam.ApplyFilterEffect: SMcr =" + smallCrossingRate + "; MDcr = " + mediumCrossingRate + "; LGcr = " + largeCrossingRate); FishGenePair sizeGenePair = fish.GetGenome()[FishGenome.GeneType.Size]; if (sizeGenePair.momGene == FishGenome.b && sizeGenePair.dadGene == FishGenome.b) { crossingRate = smallCrossingRate; } else if (sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B) { crossingRate = largeCrossingRate; } else { crossingRate = mediumCrossingRate; } while (!fish.IsStuck()) { // Based on the crossing rate we figured out, roll for a crossing // If we pass, put the fish past the dam if (Random.Range(0f, 1f) <= crossingRate) { fish.transform.position = GetRandomDropOff(fish.transform.position.y); break; } // If we have not expended our total tries (based on damPassCounter in fish), increment, wait, and try again else if (fish.damPassCounter < 2) { fish.damPassCounter++; Invoke("DamPassCooldown", 6.0f); } // If it didn't make it, make it permanently stuck (so it can't try repeated times) else { fish.SetStuck(true); break; } } } }
/** * Determine which fish prefab should be used given a fish's genome * * @param genome FishGenome The genome that determines which prefab we should use */ public GameObject GetFishPrefab(FishGenome genome) { // gameobject we will return at end GameObject toReturn; // get the size gene for the fish FishGenePair sizeGenePair = genome[FishGenome.GeneType.Size]; // different prefabs for each sex if (genome.IsMale()) { // different prefabs for each male size if (sizeGenePair.momGene == FishGenome.b && sizeGenePair.dadGene == FishGenome.b) { toReturn = smallMale; } else if (sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B) { toReturn = largeMale; } else { toReturn = mediumMale; } } else { // different prefabs for each female size if (sizeGenePair.momGene == FishGenome.b && sizeGenePair.dadGene == FishGenome.b) { toReturn = smallFemale; } else if (sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B) { toReturn = largeFemale; } else { toReturn = mediumFemale; } } return(toReturn); }
/* * Loads the game state of the turn in the list of saves to revert the game to */ public static void LoadGame() { // The turn number from the Pause Menu UI slider that we want to revert the game to int turn = (int)GameManager.Instance.pauseMenu.turnSlider.value; // List counters for each kind of tower we are loading in int currentAngler = 0; int currentRanger = 0; int currentSealion = 0; int currentTower = 0; // Clear all the existing towers foreach (TowerBase tower in GameManager.Instance.GetTowerList()) { Destroy(tower.transform.parent.gameObject); } // Grab the save from turn - 1 as we start at turn 0, but the pause menu slider starts at 1 Save loadSave = saves[turn - 1]; // Loop through each saved tower and load them back into the scene appropriately foreach (int towerType in loadSave.towerTypes) { // NOTE: This can also be accomplished with a Swicth statement, but this seems more readable for little loss of performance // Angler if (towerType == 0) { GameObject angler = Instantiate(GameManager.Instance.GetTowerPrefabs()[0]); AnglerTower towerScript = angler.GetComponent <AnglerTower>(); angler.transform.position = new Vector3(loadSave.towerPositions[currentTower][0], loadSave.towerPositions[currentTower][1], loadSave.towerPositions[currentTower][2]); angler.transform.rotation = Quaternion.Euler(loadSave.towerRotations[currentTower][0], loadSave.towerRotations[currentTower][1], loadSave.towerRotations[currentTower][2]); towerScript.turnPlaced = loadSave.anglerPlaced[currentAngler]; towerScript.fishCaught = loadSave.caughtFish[currentAngler]; towerScript.smallCatchRate = loadSave.anglerCatchRates[currentAngler][0]; towerScript.mediumCatchRate = loadSave.anglerCatchRates[currentAngler][1]; towerScript.largeCatchRate = loadSave.anglerCatchRates[currentAngler][2]; currentTower++; currentAngler++; } // Ranger else if (towerType == 1) { GameObject ranger = Instantiate(GameManager.Instance.GetTowerPrefabs()[1]); RangerTower towerScript = ranger.GetComponent <RangerTower>(); ranger.transform.position = new Vector3(loadSave.towerPositions[currentTower][0], loadSave.towerPositions[currentTower][1], loadSave.towerPositions[currentTower][2]); ranger.transform.rotation = Quaternion.Euler(loadSave.towerRotations[currentTower][0], loadSave.towerRotations[currentTower][1], loadSave.towerRotations[currentTower][2]); towerScript.turnPlaced = loadSave.rangerPlaced[currentRanger]; towerScript.slowdownEffectSmall = loadSave.rangerRegulateRates[currentRanger][0]; towerScript.slowdownEffectMedium = loadSave.rangerRegulateRates[currentRanger][1]; towerScript.slowdownEffectLarge = loadSave.rangerRegulateRates[currentRanger][2]; currentTower++; currentRanger++; } // Sealion else if (towerType == 4) { GameObject sealion = Instantiate(GameManager.Instance.GetTowerPrefabs()[4]); SealionTower towerScript = sealion.GetComponent <SealionTower>(); sealion.transform.position = new Vector3(loadSave.towerPositions[currentTower][0], loadSave.towerPositions[currentTower][1], loadSave.towerPositions[currentTower][2]); sealion.transform.rotation = Quaternion.Euler(loadSave.towerRotations[currentTower][0], loadSave.towerRotations[currentTower][1], loadSave.towerRotations[currentTower][2]); towerScript.turnPlaced = loadSave.sealionAppeared[currentSealion]; towerScript.maleCatchRate = loadSave.sealionCatchRates[currentSealion][0]; towerScript.femaleCatchRate = loadSave.sealionCatchRates[currentSealion][1]; currentTower++; currentSealion++; } // Dam else if (towerType == 2) { GameObject dam = Instantiate(GameManager.Instance.GetTowerPrefabs()[2]); Dam towerScript = dam.GetComponent <Dam>(); dam.transform.position = new Vector3(loadSave.towerPositions[currentTower][0], loadSave.towerPositions[currentTower][1], loadSave.towerPositions[currentTower][2]); dam.transform.rotation = Quaternion.Euler(loadSave.towerRotations[currentTower][0], loadSave.towerRotations[currentTower][1], loadSave.towerRotations[currentTower][2]); towerScript.turnPlaced = loadSave.damPlaced; currentTower++; } // Ladder else if (towerType == 3) { GameObject ladder = Instantiate(GameManager.Instance.GetTowerPrefabs()[3]); DamLadder towerScript = ladder.GetComponent <DamLadder>(); ladder.transform.position = new Vector3(loadSave.towerPositions[currentTower][0], loadSave.towerPositions[currentTower][1], loadSave.towerPositions[currentTower][2]); ladder.transform.rotation = Quaternion.Euler(loadSave.towerRotations[currentTower][0], loadSave.towerRotations[currentTower][1], loadSave.towerRotations[currentTower][2]); towerScript.turnPlaced = loadSave.ladderType; currentTower++; } } // Load in the generation of fish from this turn List <FishGenome> revertGeneration = new List <FishGenome>(); /* * This is lengthy. The gist is we COULD just grab the list via GetFish in FishSchool, but then the save * would not be potentially serializable if we want that in the future. So instead, we are reconstructing the * appropriate generation based on the counts of small, medium, and large fish (both male and female) we saved * at the place stage of that turn. */ // Small Male Fish FishGenePair[] SMgenes = new FishGenePair[FishGenome.Length]; FishGenePair sexPair; sexPair.momGene = FishGenome.X; sexPair.dadGene = FishGenome.Y; FishGenePair sizePair; sizePair.momGene = FishGenome.b; sizePair.dadGene = FishGenome.b; SMgenes[(int)FishGenome.GeneType.Sex] = sexPair; SMgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome smallMGenome = new FishGenome(SMgenes); for (int i = 0; i < loadSave.smallMale; i++) { revertGeneration.Add(smallMGenome); } // Medium Male Fish FishGenePair[] MMgenes = new FishGenePair[FishGenome.Length]; sizePair.momGene = FishGenome.b; sizePair.dadGene = FishGenome.B; MMgenes[(int)FishGenome.GeneType.Sex] = sexPair; MMgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome mediumMGenome = new FishGenome(MMgenes); for (int i = 0; i < loadSave.mediumMale; i++) { revertGeneration.Add(mediumMGenome); } // Large Male Fish FishGenePair[] LMgenes = new FishGenePair[FishGenome.Length]; sizePair.momGene = FishGenome.B; sizePair.dadGene = FishGenome.B; LMgenes[(int)FishGenome.GeneType.Sex] = sexPair; LMgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome largeMGenome = new FishGenome(LMgenes); for (int i = 0; i < loadSave.largeMale; i++) { revertGeneration.Add(largeMGenome); } // Small Female Fish FishGenePair[] SFgenes = new FishGenePair[FishGenome.Length]; sexPair.dadGene = FishGenome.X; SFgenes[(int)FishGenome.GeneType.Sex] = sexPair; sizePair.momGene = FishGenome.b; sizePair.dadGene = FishGenome.b; SFgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome smallFGenome = new FishGenome(SFgenes); for (int i = 0; i < loadSave.smallFemale; i++) { revertGeneration.Add(smallFGenome); } // Medium Female Fish FishGenePair[] MFgenes = new FishGenePair[FishGenome.Length]; sizePair.momGene = FishGenome.B; sizePair.dadGene = FishGenome.b; MFgenes[(int)FishGenome.GeneType.Sex] = sexPair; MFgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome mediumFGenome = new FishGenome(MFgenes); for (int i = 0; i < loadSave.mediumFemale; i++) { revertGeneration.Add(mediumFGenome); } // Large Female Fish FishGenePair[] LFgenes = new FishGenePair[FishGenome.Length]; sizePair.momGene = FishGenome.B; sizePair.dadGene = FishGenome.B; LFgenes[(int)FishGenome.GeneType.Sex] = sexPair; LFgenes[(int)FishGenome.GeneType.Size] = sizePair; FishGenome largeFGenome = new FishGenome(LFgenes); for (int i = 0; i < loadSave.largeFemale; i++) { revertGeneration.Add(largeFGenome); } FishGenomeUtilities.Shuffle(revertGeneration); GameManager.Instance.school.nextGenerationGenomes = revertGeneration; // Remove future turns we reverted over and set the UI slider in the pause menu appropriately GameManager.Instance.pauseMenu.turnSlider.maxValue = turn; GameManager.Instance.pauseMenu.turnSlider.value = turn; GameManager.Instance.Turn = turn; GameManager.Instance.SetState(new PlaceState()); currentSaveIndex = turn; }
/** * Display attempt to catch fish */ private IEnumerator TryCatchFishCoroutine(Fish fish) { // how likely we are to catch fish is dependent on what size the fish is // determine that now float catchRate; FishGenePair sizeGenePair = fish.GetGenome()[FishGenome.GeneType.Size]; if (sizeGenePair.momGene == FishGenome.b && sizeGenePair.dadGene == FishGenome.b) { catchRate = currentSmallCatchRate; } else if (sizeGenePair.momGene == FishGenome.B && sizeGenePair.dadGene == FishGenome.B) { catchRate = currentMediumCatchRate; } else { catchRate = currentLargeCatchRate; } // figure out whether the fish will be caught or not bool caught = Random.Range(0f, 1f) <= catchRate; // do setup for catch attempt line visualizer catchAttemptFish = fish; Destroy(catchAttemptLine.material); catchAttemptLine.material = caught ? hitLineMaterial : missLineMaterial; catchAttemptLine.enabled = true; // handle fish being caught if (caught) { // tell the fish that it is being caught fish.StartCatch(); // make the fish flash for a bit SkinnedMeshRenderer fishRenderer = fish.GetComponentInChildren <SkinnedMeshRenderer>(); for (int i = 0; i < numFlashesPerCatch; i++) { Material oldMaterial = fishRenderer.material; fishRenderer.material = flashMaterial; yield return(new WaitForSeconds((float)timePerApplyEffect / numFlashesPerCatch / 2f)); Destroy(fishRenderer.material); fishRenderer.material = oldMaterial; yield return(new WaitForSeconds((float)timePerApplyEffect / numFlashesPerCatch / 2f)); } // actually catch the fish fish.Catch(); caughtFish.Add(fish); } // fish escaped -- just wait for end of action else { yield return(new WaitForSeconds(timePerApplyEffect)); } // end the catch attempt line catchAttemptLine.enabled = false; }
/** * Create a new, random generation of fish for the initial group of salmon * * @param generationSize int The number of fish that should be in this generation * @param lockSexRatio bool True if we want to lock to half males, half females (or as close as is possible), false if we want random * @param lockSizeRatio bool True if we want to lock to set ratios of sizes, false if we want random */ public static List <FishGenome> MakeNewGeneration(int generationSize, bool lockSexRatio, bool lockSizeRatio) { // create a list to hold the new genomes List <FishGenome> newGeneration = new List <FishGenome>(); for (int i = 0; i < generationSize; i++) { FishGenePair[] genes = new FishGenePair[FishGenome.Length]; // figure out the sex gene pair FishGenePair sexPair; // the mom gene will always be an x sexPair.momGene = FishGenome.X; // how we determine the dad gene depends on whether we want equal number of males and females or if we want it to be random if (lockSexRatio) { // want to lock sex ratio, so odd fish will be one sex and even fish will be the other sexPair.dadGene = i % 2 == 0 ? FishGenome.X : FishGenome.Y; } else { // dad gene determined by pseudorandom chance sexPair.dadGene = Random.Range(0, 2) == 0 ? FishGenome.X : FishGenome.Y; } // add the sex gene to our list of genomes genes[(int)FishGenome.GeneType.Sex] = sexPair; // figure out the size gene pair FishGenePair sizePair; // how we determine the size genes is dependant on whether we want to lock to specific ratios or do random // if we're locking values, we use i % 4 to get 25% big, 50% medium, 25% small // if we aren't just do a random value int value = lockSizeRatio ? i % 4 : Random.Range(0, 4); switch (value) { case 0: default: sizePair.momGene = FishGenome.B; sizePair.dadGene = FishGenome.B; break; case 1: sizePair.momGene = FishGenome.B; sizePair.dadGene = FishGenome.b; break; case 2: sizePair.momGene = FishGenome.b; sizePair.dadGene = FishGenome.B; break; case 3: sizePair.momGene = FishGenome.b; sizePair.dadGene = FishGenome.b; break; } // add the size gene to our list of genomes genes[(int)FishGenome.GeneType.Size] = sizePair; // create a genome out of our genes and add it to the list FishGenome genome = new FishGenome(genes); newGeneration.Add(genome); } return(newGeneration); }
/** * Display attempt to catch fish * * @param fish The fish the fisherman is trying to catch */ private IEnumerator TryCatchFishCoroutine(Fish fish) { // How likely we are to catch fish is dependent on what size the fish is // Determine that now float catchRate; float weight; FishGenePair sizeGenePair = fish.GetGenome()[FishGenome.GeneType.Size]; switch (sizeGenePair.momGene) { case FishGenome.b when sizeGenePair.dadGene == FishGenome.b: catchRate = smallCatchRate; weight = 2f; //4 //Debug.Log("bbCatchR=" + catchRate + "; weight=" + weight); break; case FishGenome.B when sizeGenePair.dadGene == FishGenome.B: catchRate = largeCatchRate; weight = 9f; //15 //Debug.Log("BBCatchR=" + catchRate + "; weight=" + weight); break; default: catchRate = mediumCatchRate; weight = 6f; //9 //Debug.Log("BbCatchR=" + catchRate + "; weight=" + weight); break; } Debug.Log("TryCatchFishCoroutine: cScr=" + smallCatchRate + "; cMcr=" + mediumCatchRate + "; cLcr=" + largeCatchRate); // Figure out whether the fish will be caught or not bool caught = Random.Range(0f, 1f) <= catchRate; // Do setup for catch attempt line visualizer catchAttemptFish = fish; Destroy(catchAttemptLine.material); catchAttemptLine.material = caught ? hitLineMaterial : missLineMaterial; catchAttemptLine.enabled = true; // Handle fish being caught if (caught) { // Tell the fish that it is being caught fish.StartCatch(); // Trigger Water Splash effect on fish fish.waterSplash.Play(); fish.swimSpeed = 0; yield return(new WaitForSeconds(1)); fish.fishRenderer.enabled = false; yield return(new WaitForSeconds(1)); // Actually catch the fish fish.Catch(); caughtFish.Add(fish); // Add Appropriate Funds to Bank ManagerIndex.MI.MoneyManager.AddCatch(weight); // Increase this angler's fish caught total fishCaught++; } // Fish escaped -- just wait for end of action else { yield return(new WaitForSeconds(timePerApplyEffect)); } // End the catch attempt line catchAttemptLine.enabled = false; }