Unity2D: Fixing my coin system - unity3d

The way my coin system works is simple.
The player starts off with 10 fruit automatically
The enemies will then spawn in and steal a random amount of fruit from the player, the amount of fruit the enemy will steal varies from a random integer to the amount the player previously had.
The player can get more fruit by stabbing the enemies, the amount of fruit the player will get varies from a random integer to random integer.
However if the enemy takes a random amount of fruit from the player and then the player then stabs the enemy, the player will get back however much fruit the enemy took from them, plus the an extra bonus of fruit from the enemy (please look at point 3, if needed).
My problem:
This only happens occasionally, but sometimes the coin system will refuse to work especially during the beginning of the game or if the player has a large amount of fruit, i.e. 300 fruits. For example, if the player has about 300 fruits and the enemy takes about 200 fruits from the player (meaning the player will have 100 fruits remanding), then if the player stabs the enemy, the player will only receive about (for example) 25 fruits back instead of the initial 200 + the bonus(for example) 25. As mentioned before, this only happen occasionally - sometimes more than usual however I'd still like to make sure that it works accurately and smoothly. I have tried debugging it, but I am still stuck with why it is not working properly. Can anyone help me fix my codes or give me a better solution as to how I can make a better coin system. Thank you!
Enemy Theft script:
public static int scoreValue;
void Start () {
scoreValue = 0;
}
void Update () {
Debug.Log ("ScoreValue: " + scoreValue);
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "Farm") {
collidedwithFarm = true;
scoreValue = Random.Range (1, GameController.Fruit);
Debug.Log ("Enemy takes: " + scoreValue);
GameController.Fruit-= scoreValue;
//Wallet += scoreValue;
if (GameController.Fruit<= 0) {
GameController.Fruit = 0;
}
}
}
Enemy's script:
public int randomValue;
public int wallet;
public bool collidedwithFarm = false;
// Use this for initialization
void Start () {
wallet = 0;
collidedwithFarm = false;
randomValue = Random.Range (1, 101);
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "playerKnife") {
if (collidedwithFarm == false) {
text.text = " " + randomValue;
Debug.Log ("NOT COLLISION");
GameController.Fruit+= randomValue;
}
else if (collidedwithFarm == true) {
Debug.Log ("COLLISION");
GameController.Fruit+= EnemyTheft.scoreValue+ randomValue;
Debug.Log("Player gets back: " + EnemyTheft.scoreValue);
wallet += EnemyTheft.scoreValue + randomValue;
text.text = " " + wallet;
Debug.Log ("In total: " + wallet);
}
}
}
Coin Script:
public Text FruitText;
public static int Fruit = 10;
void Start()
{
SetFruitText ();
Fruit = 10;
}
void SetFruitText ()
{
FruitText.text = "Fruits: " + Fruit.ToString();
}

You don't need
public bool collidedwithFarm = false;
Remove it and then use this code in EnemyTheft.cs :
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "Farm")
{
scoreValue = Random.Range (1, GameController.Fruit);
GameController.Fruit-= scoreValue;
}
}
In Enemy.cs :
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "playerKnife")
{
int payBack = randomValue + EnemyTheft.coinsStolen;
GameController.Fruit += payBack;
wallet -= payBack;
}
}
Hope this helps.

Related

Scores not updated when collided the second time

Im having problem with an endless runner game. The scores are not updating after the first object collided. The script is attached to a prefab object. After the first object collided, the score updated to +100, the second object collides, no change.
void Start()
{
player = GameObject.FindGameObjectWithTag("Gameship");
YourScore = GameObject.Find("Score").GetComponentInChildren<TextMeshProUGUI>();
}
void Update()
{
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Border")
{
Destroy(this.gameObject);
}
else if(collision.tag == "Gameship")
{
if(this.gameObject.tag == "Reward")
{
Destroy(this.gameObject);
ChangeScore(100);
}
}
}
void ChangeScore(int changeValue)
{
this.score += changeValue;
YourScore.text = score.ToString();
}
}
Assuming your score is starting from zero i.e. score = 0, after colliding with Reward tagged gameObject, your code does the following:
The Score increases i.e. score += 100 -> score = 100
Updates the text. text = "100"
GameObject gets destroyed.
On destruction of gameObject, your score variable also gets destroyed,
assuming you are instantiating this object again, the whole script is executed again means score = 0, hence doing the above 3 steps over again and setting the text to 100 again which it already is.
I would suggest to use a Singleton class or just store the score variable in a different script that is not getting destroyed.
Currently you destroy the Object and so the scorevalue after it got triggered.
You will need an extra class with a static variable which has a score variable which you increase instead of increasing the local one.
public class ScoreHolder {
public static long score = 0;
}
void Start() {
player = GameObject.FindGameObjectWithTag("Gameship");
YourScore = GameObject.Find("Score").GetComponentInChildren<TextMeshProUGUI>();
}
void OnTriggerEnter2D(Collider2D collision) {
if (collision.tag == "Border") {
Destroy(this.gameObject);
} else if(collision.tag == "Gameship") {
if(this.gameObject.tag == "Reward") {
ChangeScore(100);
Destroy(this.gameObject);
}
}
}
void ChangeScore(int changeValue) {
ScoreHolder.score += changeValue;
YourScore.text = ScoreHolder.score.ToString();
}

Unity 2D: Timer in while loop not working, loop stays forever

I want my boost work by starting at 0 when the game starts.
In my game I can pick up boost coins to fill up my booster canister.
public static int boost;
private void OnTriggerEnter2D(Collider2D otherObject)
{
if (otherObject.tag == "Boost")
{
boost++;
GetComponent<AudioSource>().PlaySound(BoostSound, 5.7F);
Destroy(otherObject.gameObject);
}
}
After the player picks up enough boost coins to use the booster in the 2d vehicle.
you need a minimum of 3 boost to start booster. Each booster coin is equal to 1 second of boost.
I just want the player to be able to use the booster if they have over 3 boost coins collected, if they have 3 or more than that represents how many seconds they can use the boost for.
Button call code
public void BoostButton()
{
StartCoroutine("Use_VehicleBoost");
}
Booster code that a button calls.
IEnumerator Use_VehicleBoost()
{
// Check which boost package player picked
int boostLevel = SecurePlayerPrefs.GetInt("BoostLevel");
if (boostLevel == 0)
{
Debug.Log("Boost Level: None");
yield return null;
}
else if (boostLevel == 1)
{
Debug.Log("Boost Level: 1");
float aceleRate = 400, maxFWD = -2500;
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
}
if (Player.boost <= 0)
{
yield return null;
}
}
yield return null;
}
Problem: code stuck inside while loop so Unity freezes. It can never escape the loop but how if Im calling --boost using deltaTime while the loop running.
If you want to use that while loop to check, use it into IEnumerator and wait every frame. Eg:
IEnumerator Use_VehicleBoost(){
...
while (Player.boost >= 3)
{
yield return null;
}
...
}
I've done this by setting a bool in update to flip true when the ability is activated, and flip false once the conditions are no longer met. A method is also called when that bool flips true that holds the desired behavior. I was actually having the same issue as you and didn't realize yield return null was the solution, so this is what I came up with.
if (ultCharge >= pilotUltMin && !pilotUlting && !pilotUltingPressed)
{
if (Input.GetButton(bumperR1))
{
pilotUltingPressed = true;
pilotUlting = true;
curCharge = ultCharge;
pilotUltingPressed = false;
}
}
if (pilotUlting)
{
PilotUlt();
}
}
private void PilotUlt()
{
if (ultCharge > curCharge - pilotUltMax && ultCharge >= 0)
{
rb.AddRelativeForce(Vector2.up * SwitchController.ShipSpeed * 1.5f, ForceMode2D.Impulse);
ultCharge -= 0.7f;
ultExhaust1.SetActive(true);
ultExhaust2.SetActive(true);
}
else
{
pilotUlting = false;
ultExhaust1.SetActive(false);
ultExhaust2.SetActive(false);
}
}

Unity2D: PlayerPrefs.HasKey

I'm using playerprefs to save data through out scenes. Although I'm having troubles with saving this data when the application is closed. You see I have a IAP shop that gives the player a boomerang when they purchase one, the boomerang effect (done inside my script) is activated through a button. My problem is, is that playerprefs.haskey isn't saving my boomerang effect when I close the game and then reopening it. Although it does save my boomerang effect when through scenes. This is my script:
public bool forceActive = false;
public GameObject BoomerangOn, BoomerangOff;
public static int buttonCount = 0;
static int timesActivated = 0;
void Start()
{
if (PlayerPrefs.HasKey ("boomerangbutton")) {
buttonCount = PlayerPrefs.GetInt ("boomerangbutton");
BoomerangEffect();
}
}
void Update()
{
PlayerPrefs.SetInt("boomerangbutton", buttonCount);
}
public void Activated ()
{
if(timesActivated < BoomeerangText.score)
{
timesActivated++;
StartCoroutine(BoomerangEffect());
}
}
IEnumerator BoomerangEffect()
{
BoomerangOn.SetActive (true);
yield return new WaitForSeconds (10.0f);
BoomerangOn.SetActive (false);
BoomerangOff.SetActive (true);
yield return new WaitForSeconds (1f);
BoomerangOff.SetActive (false);
forceActive = false;
}
Second Edit
Okay I research a bit and linked up boomerang effect script with my boomerang text script. When the user purchase a boomerang from my IAP store, they will get 5 boomerangs, once clicked on, the boomerang text int will go down (like 5, 4, 3, 2 and 1 ) and so will my buttoncount int(that is why the timesactivaed is needed). However I change the Activated function to:
public void Activated ()
{
if (timesActivated < BoomeerangText.score) {
timesActivated++;
StartCoroutine (BoomerangEffect ());
}
}
So far it works regarding activating my boomerang effect when the application is closed, but when it gets to the last int (1) nothing happens, my effect doesn't takes place, so far this is my only problem.
Above is an updated version of what my code looks like now. And below is my Boomerang text script:
public static int score = 0; // The player's score.
public static int click = 1;
public GameObject button;
Text text; // Reference to the Text component.
// Use this for initialization
void Start()
{
if (PlayerPrefs.HasKey ("boomerangTextInt")) {
score = PlayerPrefs.GetInt("boomerangTextInt");
}
}
void Awake()
{
text = GetComponent<Text>();
}
public void Update()
{
SetScoreText();
PlayerPrefs.SetInt("boomerangTextInt", score);
}
void SetScoreText()
{
text.text = " " + score;
if (score <= 0)
{
text.text = "None";
button.GetComponent<Button>().interactable = false;
}
else if (score >= 1)
{
button.GetComponent<Button>().interactable = true;
}
// Set the displayed text to be the word "Score" followed by the score value.
}
public void MinusBoomerangText()
{
score -= click;
text.text = " " + score;
}
}
And in my purchasing script I have this:
public int scoreValue = 5;
if (String.Equals(args.purchasedProduct.definition.id, PRODUCT_5_BOOMERANG, StringComparison.Ordinal))
{
BoomerangEffect.buttonCount += 5;
BoomerangText.score += scoreValue;
Debug.Log("Purchase successfull");
}
Thank you.:)
You are not calling .Save() which means all changes to PlayerPrefs are only in memory and are not persisted to disk, which means the next time you start the application all previous changes are lost.
Try the following in your save function.
void Update()
{
PlayerPrefs.SetInt("boomerangbutton", buttonCount);
PlayerPrefs.Save();
}
Disclaimer : I am not suggesting this is something you should do in your Update at all, as this in inefficient, but this is the root cause of your problem

Unity3D: HighScore

Okay to be basic, I have a 2d top down game on unity. The premises of my game is to collect as much coins as you can before you die. I used player pref so that when a player get the highest score it will save the person's score. However I am facing a problem, which is; when you first play the game, you collect coins then die, the game then saves the highest point you got and displays it on a panel that comes down, BUT if you play the game again and don't collect any coins, then the game doesn't show the highest point you got, instead it will show "0". So to sum up if I don't collect any coins and I die then the panel will come down and show 0 as my high score. So I have to get at least 1 coin for it to show the person highest high score. Which is not want I want, want I want is for when the player dies, regardless of how many coins you have collected, it will show (in my panel) your highest high score the person got to. Does anyone knows how to fix this??? Thank you.
This is my code:
public Text ScoreText;
public Text Highscoretext;
public AudioClip coinsound;
public int Score;
public int highScore = 0;
void Start ()
{
Score = 0;
SetScoreText ();
if (PlayerPrefs.HasKey ("Highscore"))
{
highScore = PlayerPrefs.GetInt("Highscore");
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
Score = Score + 1;
SetScoreText ();
AudioSource.PlayClipAtPoint (coinsound, transform.position);
}
}
void SetScoreText ()
{
ScoreText.text = "Score: " + Score.ToString ();
Highscoretext.text = "Highscore" + highScore.ToString ();
}
Thank you.
Just use two playerpref variables. "ScoreThisPlaySesssion" and "HighestScoreEver" count score this session up when you collect coins and when that is higher than "highest score ever" count that up with one value evert time you get a coin.
void Start ()
{
Score = 0;
SetScoreText ();
if (PlayerPrefs.HasKey ("Highscore"))
{
highScore = PlayerPrefs.GetInt("Highscore");
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
Score = Score + 1;
SetScoreText ();
AudioSource.PlayClipAtPoint (coinsound, transform.position);
}
}
void SetScoreText ()
{
ScoreText.text = "Score: " + Score.ToString ();
if( PlayerPrefs.GetInt( "highestscoreever", 0 ) < Score )
PlayerPrefs.SetInt( "highestscoreever", Score );
Highscoretext.text = "Highscore" + PlayerPrefs.GetInt( "highestscoreever", 0 );
}

Unity 2D: My laser script is getting stuck on an if statement and I don't know why

I've been making a laser in my 2D platformer for the past day. I've made the arm follow to cursor perfectly however on the script for the weapon it self doesn't work. Here is my code
using UnityEngine;
using System.Collections;
public class Weapon : MonoBehaviour {
public float fireRate = 0;
public float Damage = 10;
public LayerMask whatToHit;
float timeToFire = 0;
Transform firePoint;
// Use this for initialization
void Awake () {
firePoint = transform.FindChild ("FirePoint");
if (firePoint == null) {
Debug.LogError ("No firePoint");
}
}
// Update is called once per frame
void Update () {
if (fireRate == 0) {
if (Input.GetButtonDown ("Fire1")) {
Shoot();
}
}
else {
if (Input.GetButton ("Fire1") && Time.time > timeToFire) {
timeToFire = Time.time + 1/fireRate;
Shoot();
}
}
}
void Shoot () {
Debug.Log ("Works");
Vector2 mousePosition = new Vector2 (Camera.main.ScreenToWorldPoint (Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firePointPosition = new Vector2 (firePoint.position.x, firePoint.position.y);
RaycastHit2D hit = Physics2D.Raycast (firePointPosition, mousePosition-firePointPosition, 100, whatToHit);
Debug.DrawLine (firePointPosition, (mousePosition-firePointPosition)*100, Color.cyan);
Debug.Log ("Works 2");
if (hit.collider != null) {
Debug.Log ("Work 3");
Debug.DrawLine (firePointPosition, hit.point, Color.red);
Debug.Log ("We hit " + hit.collider.name + " and did " + Damage + " damage.");
}
}
}
The if statement in void Shoot isn't working. The first two debug messages in void Shoot show up in the log however the two in the if statement don't and I have no idea why. Can anyone help?