What is wrong with this code? I tried to make ads show every 5 rounds but it doesn't work - unity3d

I have this script where I want the ads to show every 5 rounds/losses. When I test the game the ads just don't show. They only show when I put 1 in the gamesToShowAd variable. I have tried multiple ways how to make ads play every 5 rounds/losses and none of them worked.
GameManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject gameOverCanvas;
public AdsManager ads;
int gameCount = 0;
int gamesToShowAd = 5;
private void Start()
{
Time.timeScale = 1;
ads.ShowBanner();
gameCount = 0;
}
public void GameOver()
{
gameOverCanvas.SetActive(true);
Time.timeScale = 0;
gameCount++; //increment game count
if (gameCount >= gamesToShowAd) // check if player played enough games to show ad
{
ads.PlayAd();
gameCount = 0; // reset counter
}
}
public void Replay()
{
SceneManager.LoadScene(0);
}
}
Maybe its something to do with the ads manager script?
AdsManager:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Advertisements;
public class AdsManager : MonoBehaviour, IUnityAdsListener
{
#if UNITY_IOS
string gameId = "#######";
#else
string gameId = "#######";
#endif
Action onRewardedAdSuccess;
// Start is called before the first frame update
void Start()
{
Advertisement.Initialize(gameId);
Advertisement.AddListener(this);
ShowBanner();
}
public void PlayAd()
{
if(Advertisement.IsReady("Interstitial_Android"))
Advertisement.Show("Interstitial_Android");
}
public void PlayRewardedAd(Action onSuccess)
{
onRewardedAdSuccess = onSuccess;
if(Advertisement.IsReady("Rewarded_Android"))
{
Advertisement.Show("Rewarded_Android");
}
else
{
Debug.Log("Rewarded ad is not ready!");
}
}
public void ShowBanner()
{
if (Advertisement.IsReady("Banner_Android"))
{
Advertisement.Banner.SetPosition(BannerPosition.BOTTOM_CENTER);
Advertisement.Banner.Show("Banner_Android");
}
else
{
StartCoroutine(RepeatShowBanner());
}
}
public void HideBanner()
{
Advertisement.Banner.Hide();
}
IEnumerator RepeatShowBanner()
{
yield return new WaitForSeconds(1);
ShowBanner();
}
public void OnUnityAdsReady(string placementId)
{
Debug.Log("ADS ARE READY!");
}
public void OnUnityAdsDidError(string message)
{
Debug.Log("ERROR: " + message);
}
public void OnUnityAdsDidStart(string placementId)
{
Debug.Log("VIDEO STARTED!");
}
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
if (placementId == "Rewarded_Android" && showResult == ShowResult.Finished)
{
onRewardedAdSuccess.Invoke();
}
}
}
Any help is appreciated!

Instead of 5 rounds, why don't you make it 20% chance of playing every round? This is more efficient than your way.
But your issue seems to be here. (Unity calls Start() and Awake() every time the scene that the object is from is called)
Take a look at this.
private void Start(){
Time.timeScale = 1;
ads.ShowBanner();
gameCount = 0;
//It sets to 0 every time your scene reloads
//Try creating this object at your main menu or loading a empty scene before hitting play on menu
}
Or if you want that percentage to show ads, create this:
[Range(0, 10)]
public int chanceToShowAds;
private int currentChance;
public void GameOver(){
currentChance = Random.Range(0, 10);
if (currentChance >= chanceToShowAds)
ads.PlayAd();
}

Related

why does the cooldown on my gun not work?

I have this gun that's supposed to have a cooldown after every shot by using time between shots += Time.deltaTime. The problem is that it's like timeBeetweenShots dosen't increase. Here's the part of my code that I think matters:
private void Update()
{
timeSinceLastShot += Time.deltaTime;
}
public bool CanShoot() => !gunData.reloading && timeSinceLastShot > 1 / (gunData.fireRate / 60);
public void Shoot()
{
if (gunData.currentAmmo > 0)
{
if (CanShoot())
{
Debug.Log("shooting");
gunData.currentAmmo--;
timeSinceLastShot = 0;
OnGunShot();
}
} else
{
StartCoroutine(Reload());
}
}
what did I do wrong?
I think we might need to use Time.time.
The doc link is just perfect for gun fire interval.
However I had edit your code.
using System.Collections;
using UnityEngine;
public class Gun : MonoBehaviour
{
GunData gunData; // gundata might be access from player
float timeSinceLastShot = 0;
private void Update()
{
}
public bool CanShoot() => !gunData.reloading && (timeSinceLastShot + gunData.fireRate) < Time.time;
public void Shoot()
{
if (gunData.currentAmmo > 0)
{
if (CanShoot())
{
Debug.Log("shooting");
gunData.currentAmmo--;
timeSinceLastShot = Time.time;// save the last time that shot
OnGunShot();
}
}
else
{
StartCoroutine(Reload());
}
}
public void OnGunShot()
{ // animation might be here
}
IEnumerator Reload()
{ // relaoding might be here
yield return new WaitForEndOfFrame();
}
}
public class GunData // just dummy data
{
public int currentAmmo = 10;
public float fireRate = 0.2f;
public bool reloading = false;
}

Count Deaths in multiplayer game

I am doing a multiplayer game using photon and I want my player deaths to be count every time is killed. I used this script but I didn't add any photonView.IsMine because every time my player dies , the text from canvas remain : Deaths:0 . The script I used for deaths is this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon;
using Photon.Pun;
public class DeathsCount : MonoBehaviour
{
public Text countText;
public int deathcount;
void Start()
{
countText = GetComponent<Text>();
deathcount = 0;
CmdDeathsCount();
}
void CmdDeathsCount()
{
countText.text = "Death: " + deathcount.ToString();
}
void CmdSetDeathsCount(int newCount)
{
deathcount = newCount;
}
public void RpcRespawn()
{
Debug.Log(deathcount);
deathcount = deathcount + 1;
CmdDeathsCount();
}
}
and the function in my character script I used for damage the player and death :
[PunRPC]
void Damage()
{
Debug.Log("I damaged");
Health -= 20;
if (Health <= 0) // check health status
{
Health = 0; // make that Heath don't be < 0
if (photonView.IsMine)
{
myCounts.RpcRespawn(); //Here you should to call counter
}
}
}
You need to add a method to simply increase the death count in deathcount, and to call it when death is determined.
void IncreaseDeathsCount()
{
deathcount++;
CmdDeathsCount()
}
[PunRPC]
void Damage()
{
Debug.Log("I damaged");
Health -= 20;
if (Health <= 0) // check health status
{
Health = 0; // make that Heath don't be < 0
if (photonView.IsMine)
{
myCounts.RpcRespawn(); //Here you should to call counter
DeathsCount.cmdDeathsCount;
}
}
}
However you will either have to make cmdDeathsCount a static or add a reference to your instance to be able to call it

Using a timer in conjunction with 2 push buttons from arduino

So I am using two push buttons (connected to an Arduino Uno) as an input to my game. The player has to push down both buttons at the same time for the character to move in the game. I want the player to hold down the buttons for a different amount of time in each level. I have a working Arduino and a working Unity timer and player script, but am not able to get the code to do what I want. What I basically want is that only when the player presses the buttons down, does the timer start counting down. Right now, the timer starts as soon as the scene begins. I know that I somehow have to reference the timer script to the button object, I have tried this but it still doesn't work. Note that the timer UI does have a Timer tag on it. I have also referenced the Player Controller script in the Timer script. Right now, Its giving me a range of errors. I have attached an image depicting these errors.error image
The Timer script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Timer : MonoBehaviour
{
//int startTime = 0;
public bool buttonPressed = false;
public int timeLeft;
public Text countdownText;
GameObject Character;
void Awake()
{
Character = GameObject.FindWithTag("Player");
}
public void Start()
{
//StartCoroutine("LoseTime");
BeginTimer();
}
void Update()
{
countdownText.text = ("Time Left = " + timeLeft);
if (timeLeft <= 0)
{
//StopCoroutine("LoseTime");
//countdownText.text = "Times Up!";
Invoke("ChangeLevel", 0.1f);
}
}
public void BeginTimer()
{
Character.GetComponent<PlayerController>().Update();
//gameObject.GetComponent<MyScript2>().MyFunction();
if (buttonPressed == true )
{
StartCoroutine("LoseTime");
}
else if (buttonPressed == false)
{
StopCoroutine("LoseTime");
}
}
IEnumerator LoseTime()
{
while (true)
{
yield return new WaitForSeconds(1);
timeLeft--;
}
}
void ChangeLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
The Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
public class PlayerController : MonoBehaviour
{
SerialPort sp = new SerialPort("\\\\.\\COM4", 9600);
//player == GameObject.FindWithTag("Player").GetComponent<>();
public float Speed;
public Vector2 height;
public float xMin, xMax, yMin, yMax;
public bool buttonPressed = false;
GameObject Character;
public void Awake()
{
Character = GameObject.FindWithTag("Player");
}
public void Start()
{
if (!sp.IsOpen)
{ // If the erial port is not open
sp.Open(); // Open
}
sp.ReadTimeout = 1; // Timeout for reading
}
public void Update()
{
if (sp.IsOpen)
{ // Check to see if the serial port is open
try
{
string value = sp.ReadLine();//To("Button"); //Read the information
int button = int.Parse(value);
//float amount = float.Parse(value);
//transform.Translate(Speed * Time.deltaTime, 0f, 0f); //walk
if (button == 0) //*Input.GetKeyDown(KeyCode.Space*/) //jump
{
buttonPressed = true;
Character.GetComponent<Rigidbody2D>().AddForce(height, ForceMode2D.Impulse);
Character.GetComponent<Rigidbody2D>().position = new Vector3
(
Mathf.Clamp(GetComponent<Rigidbody2D>().position.x, xMin, xMax),
Mathf.Clamp(GetComponent<Rigidbody2D>().position.y, yMin, yMax)
);
Timer tmr = GameObject.Find("Timer").GetComponent<Timer>();
tmr.BeginTimer();
}
}
catch (System.Exception)
{
}
}
void ApplicationQuit()
{
if (sp != null)
{
{
sp.Close();
}
}
}
}
}
I think the problem may be with how I am referencing the scripts in each other.
In your timer you have a quite strange mixup of Update and Coroutine. Also note that BeginTimer is called exactly once! You also shouldn't "manually" call Update of another component.
I wouldn't use Update at all here. Simply start and stop a Coroutine.
The Timer script should only do the countdown. It doesn't have to know more:
public class Timer : MonoBehaviour
{
public int timeLeft;
public Text countdownText;
private bool timerStarted;
public void BeginTimer(int seconds)
{
// Here you have to decide whether you want to restart a timer
timeLeft = seconds;
// or if you rather want to continue counting down
//if(!timerStarted) timeLeft = seconds;
StartCoroutine(LoseTime());
}
public void StopTimer()
{
StopAllCoroutines();
}
private IEnumerator LoseTime()
{
timerStarted = true;
while (timeLeft > 0)
{
yield return new WaitForSeconds(1);
timeLeft --;
countdownText.text = $"Time Left = {timeLeft}";
}
// Only reached after the timer finished and wasn't interrupted meanwhile
// Using Invoke here is a very good idea since we don't want to interrupt anymore
// if the user lets go of the button(s) now
Invoke(nameof(ChangeLevel), 0.1f);
}
void ChangeLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
In general avoid to use Find at all. If anyhow possible already reference things in the Inspector! If needed you can use Find but only once! What you never want to do is use any of the Find and GetComponent variants repeatedly - rather store the reference the first time and re-use it - and especially not in Update no a per frame basis. They are very expensive calls!
public class PlayerController : MonoBehaviour
{
public float Speed;
public Vector2 height;
// I prefer to use Vector2 for such things
public Vector2 Min;
public Vector2 Max;
public bool buttonPressed = false;
// Already reference these via the Inspector if possible!
public Rigidbody2D Character;
public Timer timer;
public Rigidbody2D _rigidbody;
private SerialPort sp = new SerialPort("\\\\.\\COM4", 9600);
private void Awake()
{
FetchReferences();
}
// This is my "secret" tip for you! Go to the component in the Inspector
// open the ContextMenu and hit FetchReferences
// This already stores the references in the according fields ;)
[ContextMenu("FetchReferences")]
private void FetchReferences()
{
if(!Character)Character = GameObject.FindWithTag("Player"). GetComponent<Rigidbody2D>();
if(!timer) timer = GameObject.Find("Timer").GetComponent<Timer>();
}
private void Start()
{
if (!sp.IsOpen)
{
sp.Open(); // Open
}
sp.ReadTimeout = 1;
}
private void Update()
{
// I wouldn't do the serialport open check here
// your if block simply silently hides the fact that your application
// doesn't work correctly! Rather throw an error!
try
{
string value = sp.ReadLine(); //Read the information
int button = int.Parse(value);
//TODO: Since it isn't clear in your question how you get TWO buttons
//TODO: You will have to change this condition in order to only fire if both
//TODO: buttons are currently pressed!
buttonPressed = button == 0;
if (buttonPressed)
{
Character.AddForce(height, ForceMode2D.Impulse);
// The clamping of a rigidbody should always be done ine FixedUpdate!
// Pass in how many seconds as parameter or make the method
// parameterless and configure a fixed duration via the Inspector of the Timer
timer.BeginTimer(3.0f);
}
else
{
// Maybe stop the timer if condition is not fulfilled ?
timer.StopTimer();
}
}
catch (System.Exception)
{
// You should do something here! At least a Log ...
}
}
private void FixedUpdate()
{
// Here I wasn't sure: Are there actually two different
// Rigidbody2D involved? I would assume you rather wanted to use the Character rigidbody again!
Character.position = new Vector3(Mathf.Clamp(Character.position.x, Min.x, Max.x), Mathf.Clamp(Character.position.y, Min.y, Max.y));
}
// Did you mean OnApplicationQuit here?
private void ApplicationQuit()
{
if (sp != null)
{
{
sp.Close();
}
}
}
}
Typed on smartphone but I hope the idea gets clear

Unity Networking enemy spawning is not working

I am making a multiplayer MMO with unity and I am stuck on syncing up enemy spawning between clients. Basically the enemies spawn as intended, but only on the user that spawned them. Here is my code (Sorry it is a bit long, just wanted to include any information that could be relevant, as the is my first time with networking):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
[System.Serializable]
public class EnemySpawn {
public GameObject prefab;
public int difficulty;
public int rarity;
[HideInInspector()]
public GameObject instance;
}
public class EnemySpawner : NetworkBehaviour {
public EnemySpawn[] enemys;
public int maxDiff = 8;
public int spawnDistMin = 15;
public int spawnDistMax = 35;
public int spawnLvlDist = 30;
private int diffOnScreen;
private EnemySpawn enemyToSpawn;
public List<EnemySpawn> enemysOnScreen = new List<EnemySpawn>();
void Start() {
StartCoroutine (Spawn());
}
void Update() {
List<EnemySpawn> newEnemysOnScreen = new List<EnemySpawn>();
foreach(EnemySpawn c in enemysOnScreen) {
if (c.instance == null) {
diffOnScreen -= c.difficulty;
} else {
newEnemysOnScreen.Add (c);
}
}
enemysOnScreen = newEnemysOnScreen;
}
//IMPORTANT PART!!! \/\/\/
[Command]
void CmdSpawn(Vector3 pos) {
GameObject spawning = Instantiate (enemyToSpawn.prefab, pos, Quaternion.identity);
NetworkServer.Spawn (spawning);
diffOnScreen += enemyToSpawn.difficulty;
enemysOnScreen.Insert (0,enemyToSpawn);
enemysOnScreen [0].instance = spawning;
spawning.GetComponent<MonsterMain>().lvl = Mathf.RoundToInt(spawning.transform.position.magnitude / spawnLvlDist);
}
IEnumerator Spawn() {
while (true) {
int n = 0;
while (n != 1) {
enemyToSpawn = enemys [Random.Range (0, enemys.Length)];
n = Random.Range (1, enemyToSpawn.rarity);
}
while (maxDiff - diffOnScreen <= enemyToSpawn.difficulty) {
yield return null;
}
yield return null;
Transform player = Player.localPlayer.transform;
Vector2 randomOffset = Random.insideUnitCircle.normalized * Random.Range (spawnDistMin, spawnDistMax);
CmdSpawn(player.position + new Vector3(randomOffset.x,randomOffset.y,0));
}
}
}
I am using Unity 2017.1.3.3p3, and I am building this to IOS. It is a 2d game and I am using unity's build in networking system. Again everything works except that the enemies only spawn on one screen. I am connecting one phone to the editor. Any help is appreciated. thank you!

how to check animator state is finished unity3d

Below is my script, I want to check that animator state finished or not. If animator state(animation) is complete then do some action, but I am enable to do so, Thanks in advance.
using UnityEngine;
using System.Collections;
public class fun_for_level_complet : MonoBehaviour
{
public Animator animator_obj;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
check_end_state ();
}
public void level_complete()
{
if (this.GetComponent<movement_of_player> () != null)
{
this.GetComponent<movement_of_player> ().enabled = false;
}
animator_obj.SetBool ("congo",true);
}
public void check_end_state ()
{
// here I want to check if animation ends then print
// my state name is congo
// animation name Waving
// using base layer
if (animator_obj.GetCurrentAnimatorStateInfo (0).IsName ("congo") && !animator_obj.IsInTransition (0))
{
Debug.Log ("anim_done");
}
}
}
You can use events on animation clips. It's explained in Unity manual:
https://docs.unity3d.com/Manual/AnimationEventsOnImportedClips.html
In Animation Inport Settings in Annimations tab You can find Event heading. Position the playback to the end and click Add Event. Fill the Function field with name of the function to call at the end of animation. Just make sure that Game Object with this animation has a corresponding function.
I figure it out, and I done it by checking state starts or not if starts then check for end, by states names. Below is code, and working fine, remember(in last state you have to create empty state)
using UnityEngine;
using System.Collections;
public class fun_for_level_complet : MonoBehaviour
{
public Animator animator_obj;
private string[] states = new string[]{ "congo" };
private string current_state_name = "";
private bool waiting_end_state = false;
private bool wait_for_anim_start = false;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (waiting_end_state)
{
if (wait_for_anim_start)
{
if (animator_obj.GetCurrentAnimatorStateInfo (0).IsName (current_state_name))
{
wait_for_anim_start = false;
}
} else
{
check_end_state ();
}
}
}
public void level_complete()
{
if (this.GetComponent<movement_of_player> () != null)
{
this.GetComponent<movement_of_player> ().enabled = false;
}
animator_obj.SetBool ("congo",true);
waiting_end_state = true;
wait_for_anim_start = true;
current_state_name = states [0];
}
public void check_end_state()
{
if (!animator_obj.GetCurrentAnimatorStateInfo (0).IsName (current_state_name))
{
waiting_end_state = false;
if( current_state_name==states[0] )
{
GameObject.FindGameObjectWithTag ("inagmegui").SendMessage ("make_it_true");
print ( "animation has been ended" );
}
}
}
}
If you do not have any transitions and would like to to be notified when the animation has ended for the "stateName" in layer 0, I did by calling the following IEnumerator :
public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
{
targetAnim.Play(stateName);
//Wait until we enter the current state
while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
{
yield return null;
}
//Now, Wait until the current state is done playing
while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
{
yield return null;
}
//Done playing. Do something below!
EndStepEvent();
}
The main logic is once the state is entered, we should check if the fractional part of 'normalizedTime' variable reached 1, which means the animation has reached its end state.
Hope this helps
You can create custom StateMachineBehaviour like this:
using UnityEngine;
public class AttackBehaviour : StateMachineBehaviour
{
public GameObject particle;
public float radius;
public float power;
protected GameObject clone;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
clone = Instantiate(particle, animator.rootPosition, Quaternion.identity) as GameObject;
Rigidbody rb = clone.GetComponent<Rigidbody>();
rb.AddExplosionForce(power, animator.rootPosition, radius, 3.0f);
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Destroy(clone);
}
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack Update ");
}
override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack Move ");
}
override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack IK ");
}
}
Documentation https://docs.unity3d.com/ScriptReference/StateMachineBehaviour.html