Hello!
For a school project, I have to create a 2d Arcade Game. And one of the things that I have to include is a coin system. Let me explain:
In the main menu you start out with 3 coins, and whenever you click play, one coin will be spent so you will have 2 coins. At the end of some levels, you can pick a coin up so it will refill in the main menu. Once you got no coins left you cant enter the game anymore.
I hope I explained it well enough. I do have the coin pickup part but I just can't wrap my head around the rest of what I have to do. Can someone maybe link me a tutorial that implements this system or maybe help me?
You should use a variable for the amount of coins. Call it coins. Also, make sure you aren’t loading new scenes, or it will erase the amount. So once the player hits play, take a coin away and start the game. Then, they can pick the coins up again. Write this in the script coin:
public int coins = 3;
bool pressedTheButton;
bool pickedUpCoin;
void Update(){
if (pressedTheButton){
coins -= 1;
pressedTheButton = false;
}
if (pickedUpCoin){
coins += 1;
pickedUpCoin = false;
}
}
You should change the variable called pressedTheButton when the player starts the game. Same with the pickedUpCoin. If you are changing scenes, then add a function to it called DontDestroyOnLoad(gameObject);
Add it to a Start(){} function of the script.
public int coins = 3;
bool pressedTheButton;
bool pickedUpCoin;
void Start(){
DontDestroyOnLoad(gameObject);
}
void Update(){
if (pressedTheButton){
coins -= 1;
pressedTheButton = false;
}
if (pickedUpCoin){
coins += 1;
pickedUpCoin = false;
}
}
What this does, is doesn’t destroy the game object when you load the scene for the game. Attach the script to any game object you don’t want to be destroyed when loading the new scene. For example you can add it to an empty game object, or something that won’t change.
Related
So, I've been trying to learn Unity these past couple of weeks. As a starter project I decided to try and replicate the mobile game Pop the Lock. Right now, I'm having some problems with my keyboard inputs that I just can't figure out how to solve.
This is how my game screen looks: GameScreen. The red bar is the Player and the yellow circle is the Target. As the game progresses, the Player rotates around the ring towards the Target.
Basically, if the Player and the Target are touching AND the Player presses the Space Key at the exact same time, the Player is supposed to gain a point. The Target is also supposed to be destroyed, and a new Target is supposed to randomly be spawned in somewhere on the game screen. At the moment, this system works ... most of the time. About 80% of the time my code operates as it should, but around 20% of the time my code doesn't register when player presses the space key as the two collide. Here's my code:
public class Target: MonoBehaviour {
public GameObject target;
void Update () {
if (Input.GetKeyDown("space")) {
Debug.Log("SPACE PRESSED!!");
}
}
private void OnTriggerEnter2D (Collider2D collision) {
Debug.Log("Collision!");
}
private void OnTriggerStay2D(Collider2D other) {
// This is the part that sometimes isn't registering:
if (Input.GetKeyDown("space")) {
Debug.Log("HIT!!");
Score.score++;
// Code to spawn new Target on random place in the ring:
// Seems to be working as intended:
float distance = 2.034822f;
float x = Random.Range(-2f, 2f);
float y = Mathf.Pow(distance,2) - Mathf.Pow(x,2);
y = Mathf.Sqrt(y);
float[] options = {y, -y};
int randomIndex = Random.Range(0, 2);
y = options[randomIndex];
Vector3 vector = new Vector3(x, y, 0);
GameObject newTarget = Instantiate(target, vector, Quaternion.identity);
Destroy(gameObject);
}
}
}
As you can see I have Log statements that print something every time the player and the target are touching, every time the space key is pressed, and every time the space key is pressed while they are touching. This is how the console looks like when everything is working : Image One. This is what the console looks like when my code isn't working : Image Two.
So even when it isn't working, the collision and the key press are still registered at the exact same time. But for some reason the hit itself isn't registered (so the if condition isn't passed). Because of this I'm quite confident that it's not just input delay or me pressing the key at the wrong time. As I mentioned above, this only happens about 20% of the time, which makes it even more confusing to me. The Target has a trigger collider2D and it also has a dynamic RigidBody2D with gravity scale set to 0 (as I was told it should). Any help would be greatly appreciated.
(How my collider and rigidbody look: Image)
Something you can do is to set a flag to becomes true while you are pressing the key in the update loop, so the update loop will convert to something like:
private bool isSpacePressed = false;
update() {
isSpacePressed = false;
if (Input.GetKeyDown(KeyCode.Space)){
isSpacePressed = true;
}
}
so every loop the flag will be set to false except if you are pressing the space bar and the OnTriggerStay2D while become something like
OnTriggerStay2D () {
if(isSpacePressed){
.. do magic..
}
}
Look that I replace the Input.GetKeyDown('space') to Input.GetKeyDown(KeyCode.Space) I recommend using this one to avoid typing errors
I am following the 2D Roguelike tutorial from unity learn.
When testing my game I enter the play mode and everything is fine, when using the arrows to move the player, unity stops and I can't click at any of the buttons in the editor, and the animation stops.
Here is my player script :
//Delay time in seconds to restart level.
public float restartLevelDelay = 1f;
//Number of points to add to player food points when picking up a food object.
public int pointsPerFood = 10;
//Number of points to add to player food points whne picking up a soda object.
public int pointsPerSoda = 20;
//How much damage a player does to a wall whne chopping it.
public int wallDamage = 1;
//Used to store a refrence to the Player's animator component
private Animator animator;
//Used to store player food points total during level.
private int food;
//Start overrides the Start function of MovingObject
protected override void Start()
{
//Get a component reference to the Player's animator component
animator = GetComponent<Animator>();
//Get the current food point total stored in GameManager.instance between levels.
food = GameplayManager.instance.playerFoodPoints;
//Call the Start function of the MovingObject base class.
base.Start();
}
//This function is called when the behaviour becomes disabled or inactive.
private void OnDisable()
{
//When Player object is disabled, store the current local food total in the GameManager so it can be re-loaded in next level.
GameplayManager.instance.playerFoodPoints = food;
}
private void Update()
{
//If it's not the player's turn, exit the function.
if (!GameplayManager.instance.playersTurn) return;
int horizontal = 0; //Used to store the horizontal move direction.
int vertical = 0; //Used to store the vertical move direction.
//Get input from the input manager, round it to an integer and store in horizontal to set x axis move direction
int v = (int) (Input.GetAxisRaw("Horizontal"));
horizontal = v;
//Get input from the input manager, round it to an integer and store in vertical to set y axis move direction
vertical = (int) Input.GetAxisRaw ("Vertical");
//Check if moving horizontally, if so set vertical to zero.
if (horizontal != 0)
{
vertical = 0;
}
//Check if we have a non-zero value for horizontal or vertical
if (horizontal != 0 || vertical != 0)
{
//Call AttemptMove passing in the generic parameter Wall, since that is what Player may interact with if they encounter one (by attacking it)
//Pass in horizontal and vertical as parameters to specify the direction to move Player in.
AttemptMove<Wall>(horizontal, vertical);
}
}
//AttemptMove overrides the AttemptMove function in the base class MovingObject
//AttemptMove takes a generic parameter T which for Player will be of the type Wall, it also takes integers for x and y direction to move in.
protected override void AttemptMove<T>(int xDir, int yDir)
{
//Every time player moves, subtract from food points total.
food--;
//Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.
base.AttemptMove<T>(xDir, yDir);
//Hit allows us to reference the result of the Linecast done in Move.
RaycastHit2D hit;
//If Move returns true, meaning Player was able to move into an empty space.
if (Move(xDir, yDir, out hit))
{
//Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
}
//Since the player has moved and lost food points, check if the game has ended.
CheckIfGameOver();
//Set the playersTurn boolean of GameManager to false now that players turn is over.
GameplayManager.instance.playersTurn = false;
}
//OnCantMove overrides the abstract function OnCantMove in MovingObject.
//It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy.
protected override void OnCantMove<T>(T component)
{
//Set hitWall to equal the component passed in as a parameter.
Wall hitWall = component as Wall;
//Call the DamageWall function of the Wall we are hitting.
hitWall.DamageWall(wallDamage);
//Set the attack trigger of the player's animation controller in order to play the player's attack animation.
animator.SetTrigger("playerChop");
}
//OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only).
private void OnTriggerEnter2D(Collider2D other)
{
//Check if the tag of the trigger collided with is Exit.
if (other.tag == "Exit")
{
//Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second).
Invoke("Restart", restartLevelDelay);
//Disable the player object since level is over.
enabled = false;
}
//Check if the tag of the trigger collided with is Food.
else if (other.tag == "Food")
{
//Add pointsPerFood to the players current food total.
food += pointsPerFood;
//Disable the food object the player collided with.
other.gameObject.SetActive(false);
}
//Check if the tag of the trigger collided with is Soda.
else if (other.tag == "Soda")
{
//Add pointsPerSoda to players food points total
food += pointsPerSoda;
//Disable the soda object the player collided with.
other.gameObject.SetActive(false);
}
}
//Restart reloads the scene when called.
private void Restart()
{
//Load the last scene loaded, in this case Main, the only scene in the game.
SceneManager.LoadScene(0);
}
//LoseFood is called when an enemy attacks the player.
//It takes a parameter loss which specifies how many points to lose.
public void LoseFood(int loss)
{
//Set the trigger for the player animator to transition to the playerHit animation.
animator.SetTrigger("playerHit");
//Subtract lost food points from the players total.
food -= loss;
//Check to see if game has ended.
CheckIfGameOver();
}
//CheckIfGameOver checks if the player is out of food points and if so, ends the game.
private void CheckIfGameOver()
{
//Check if food point total is less than or equal to zero.
if (food <= 0)
{
//Call the GameOver function of GameManager.
GameplayManager.instance.GameOver();
}
}
How can I fix this?
I probably tried everything.
Regards.
This feels like an infinite loop to me, which would probably lock up the game and editor.
The code you posted calls out to other methods not listed here... I would look for a place where you might be recursively calling a method, or maybe where you're meaning to call base.theMethod but instead called this.theMethod.
This is probably a stack overflow where a function is calling himself infinitely.
It can also be a Coroutine from the base class with a infinite loop.
However, we can't say exactly where in the code, because is missing some information like what's inside the parent class (from the comments I suppose is called MovingObject)
Whenever posting a code be sure to send only the necessary piece of code (maybe removing some useless comments) and giving precious information like the inheritance and if is an override function would be useful to give also his base implementation.
I have made my first Unity3D game. It's a racing game with the infinite road. I made some pickup coins too.
the problem is when I pick up the coins and then I go to shop menu to see whether it's added to the total coins or not, it is not added till I play another round and then the coins i collected the round before will be added.
It's like a delay or something.
Is it because I don't know how can I use a value in different scenes? or it,s something else.
someone told me to use PlayerPrefs, I used it in my scripts but for this, I mean the count of coins, I don't know how to use it.
The script bellow is my player script in which I count the pickup coins and some other things related to the player. I only bring the Ontrigger and count related codes.
void Start () {
CameraAnimation = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Animator>();
_GameManager = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();
_AudioSource = GetComponent<AudioSource>();
count = 0;
SetCountText ();
}
void OnTriggerEnter(Collider other){
if(other.gameObject.tag == "Coins") {
count = count + 1;
SetCountText ();
}
}
public void SetCountText(){
CountText.text = count.ToString ();
}
The code below is my calculateCoin in which I add a count of collected coins to the previous value and show the total in shop scene textbox:
public class CalculateCoin : MonoBehaviour{
// Use this for initialization
public static int Coin = 10000;
public Text ShowCoin;
void Start () {
ShowCoin.text = PlayerPrefs.GetInt("Coin").ToString();
Coin =PlayerPrefs.GetInt("Coin")+Player.count;
PlayerPrefs.SetInt ("Coin", Coin);
}
}
First Option,
You can add 'DontDestroyOnLoad' for specific GameObject that include data as container. so It could be used as shared data between scene.
or Make 'Singleton' class and use it as data container it might be option.
is it a way for instantiate gameobjects as child of main? This is my example of code
void MakeCubes ()
{
GameObject cubes = Instantiate (Cube) as GameObject;
cubes.AddComponent <CubeScript> ();
cubes.SetActive (true);
}
I'm invoking MakeCube() function every time when previous is destroyed. I ask this because I'm giving option in game that you can continue playing if you lost life. Current situation is that when you continue playing game, score isn't counting. For example. If I hit 5 cubes. I have score 5, then I lost "life". I press continue. I can hit cubes but they doesn't counting. When I hit 5 cubes it doesn't count to current score. But when I hit sixth cube it is counting from score 5 to 6.
Parent is a attribute of transform so you can play with transforms to get this. Well, in your case you can do something like,
void MakeCubes ()
{
GameObject cubes = Instantiate (Cube) as GameObject;
cubes.AddComponent <CubeScript> ();
// Replace YOUR_PARENT_GO from your parent GameObject
cubes.transform.parent = YOUR_PARENT_GO.transform;
cubes.SetActive (true);
}
You can sue transform.SetParent(). Unity docs: Transform.SetParent
You can set the parent for something that already exists in your hierarchy:
gameObject.transform.parent = GameObject.Find("Name of game object").transform;
In my game there is a score. When an object collides, a set increment is added to the score. There is one scoreboard. What is happening in my game is that when an object collides it hijacks the scoreboard to show only its own person history of scores. When the next object collides, it takes over the scoreboard and shows its own personal history. I am trying to show the amalgamate score of all of the objects put together, each contributing their part to a grand total.
void OnCollisionEnter (Collision col)
{
if(col.gameObject.name == "Plane")
{
score += 50;
textMeshComponent = GameObject.Find ("Score").GetComponent<TextMesh> ();
textMeshComponent.text = score.ToString ();
}
}
There are 10 of (col.gameObject.name) and there is one "Plane" that they all interact with.
How can I make the score a conglomerate like I described? I am really at a loss for how to manipulate the (col.gameObject.name) side of that equation.
Thanks for your advice.
Make score a member of Plane, instead of this, and make it public so all the other gameObjects can get it.
You can also create score as its own gameObject, or create a gameObject that contains all the globals.
Let me suggest another approach although not recommended textMeshComponent.text = (score+(int.Parse(textMeshComponent.text))).toString();
now this will add points as a whole regardless each gameobject adding its own to the main value
Consider having an object in your scene whose sole concern is counting (and maybe displaying) the score. Lets name it ScoreController.
Whenever an event occurs for which you want to award score to the player, the responsible code just calls your ScoreController and tells them how much score to award.
Your ScoreController GameObject might have a script like this:
public class ScoreController : MonoBehaviour
{
public TextMesh scoreDisplay;
public int Score { get; private set; }
void Start()
{
UpdateView();
}
public void AwardScore(int amount)
{
Score += amount;
UpdateView();
}
private void UpdateView()
{
scoreDisplay.text = Score.ToString();
}
}
Now, other code can award score by calling
GameObject.FindObjectOfType<ScoreController>().AwardScore(123);
If you want to read up on related topics, consider reading about the Model-View-Control design pattern, and about SoC (seperation of concerns).