I'm making a simple game for a school project using Unity. The purpose of the game is to control a ball and pick up coins. The game has 3 scenes. I have written some code in C# to count my pick up coins and set a condition to check if all coins are picked up, if so, a wintext appears at the center of the screen.
It works just fine for the first scene (lvl1) but not for the other 2.
All 3 scenes have a different number of coins. C# is new to me and I have tried various combinations but it hasn't worked.
How do I re-write this code so that the wintext appears after I pick up the right number of coins on every scene/level?
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
public float speed;
public Text countText;
public Text winText;
private Rigidbody rb;
private int count;
void Start()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText();
winText.text = "";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
rb.AddForce(movement * speed);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Pick Up"))
{
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Coins: " + count.ToString();
if (count >= 2)
{
winText.text = "You Win!";
}
}
}
Make a new public variable
...
public float speed;
public Text countText;
public Text winText;
public int numberOfCoinsToWin;
...
remember to set this new value in the editor for each scene
Use the variable in your condition.
if (count >= numberOfCoinstoWin)
{
winText.text = "You Win!";
}
Sounds like you're lacking a very basic understanding of C# and programming in general. Here are somethings you could research to make life easier for you:
variables
control flow
access modifiers
classes (in computer science)
object orientation
Also using Unity to learn C# is not great. You will miss a lot of fundamentals. I suggest learning C# without unity for a week or 2 and coming back.
This code snippet would dynamically set win condition based on scene, however it would be better if the scene could hold coinToCollect variable.
void SetCountText()
{
countText.text = "Coins: " + count.ToString();
int coinsToCollect = 0;
switch( /* get current scene here */)
{
case "scene1": // repeat for other scenes
coinsToCollect = 2;
break;
}
if (count >= coinsToCollect)
{
winText.text = "You Win!";
}
}
Related
I am busy building a platformer(2d). And I really want procedural generation. I think that I came up with a smart system for spawning the platforms randomly(up for debate). But my platforms keep on picking to randomly spawn down. No matter how many times I restart the game
eg :
here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlatformSpawner : MonoBehaviour
{
public GameObject[] platform;
public Vector2 SpawnGap;
public float randomspawn;
public float VerticalRandomness;
public float queueTime = 1.5f;
private float time = 0;
public Vector2 startspawn;
public GameObject flag;
Vector2 nextspawn;
Vector2 nextspawncentre;
Vector3 prevspawn;
public int platamount;
int amountspawned;
bool alreadyspawnedflag;
// Start is called before the first frame update
void Start()
{
platamount = Random.Range(5, 15); // random amount of platforms in level
alreadyspawnedflag = false;
}
// Update is called once per frame
void Update()
{
if (time > queueTime) // just for quality of life(so that if I maybe have 10000 platforms I can delay the spawning)
{
if(platamount >= amountspawned) // random amount of platform
{
GameObject go = Instantiate( platform[ Random.Range (0, platform.Length) ] ); // instantiating random object from list, to make it even more random(objects assigned in inspector)
Vector2 randomrange = new Vector2(Random.Range(1f, -1f) * randomspawn, Random.Range(2f, -0.25f/*perferes up, but stil not working*/) * VerticalRandomness);//calculates random position
Debug.Log(randomrange);// it is indeed choosing random pos, even on y but still giong down
nextspawncentre = new Vector2(prevspawn.x + SpawnGap.x + startspawn.x, prevspawn.y + SpawnGap.y + startspawn.y); // calculates next spawn without randomness
nextspawn = new Vector2(nextspawncentre.x + randomrange.x, nextspawncentre.y + randomrange.y);// adds randomness
go.transform.position = transform.position + new Vector3(nextspawn.x, nextspawn.y, 0);// places object at nextspawn variable
time = 0;// resets timer
prevspawn = go.transform.position;
amountspawned += 1;
randomrange = new Vector2(0, 0);// tried reseting the random, but to no success
}
else if(!alreadyspawnedflag)// almost same logic as before just for the flag to reload scene(handeled in another script)
{
GameObject spawnedflag = Instantiate(flag);
spawnedflag.transform.position = new Vector3(nextspawncentre.x + 1, 15, 0f);
alreadyspawnedflag = true;
}
}
time += Time.deltaTime;
}
}
look at comments explained, everything there.
In advance thanks for the help.
ps: Platforms do not have rigidbodies, just sprite renderer and boxcollider2d.
I think the issue is related to your startSpawn being a negative value (at least it looks like that from your first platform). So even if the Y is positive in the randomrange it might be overruled by the negative startSpawn Y value.
Actually I think you don't even add your startSpawn every time at all but rather only using it as the initial position
I think you should simply do e.g.
private bool firstPlatform = true;
and
...
if(firstPlatform)
{
nextspawn = startspawn;
firstPlatform = false;
}
else
{
nextspawncentre = prevspawn + SpawnGap;
nextspawn = nextspawncentre + randomrange;
}
...
For a game I am developing I have a part when if the user gets too close to an enemy it switches scene to a battle scene. However I have no clue how to load that enemy into the battle screen (given that a user can battle many different enemies). Below is my current cod for the enemy. I was wondering if I could carry over it's name into the next scene or something. I just want my enemy to go from one screen to another when the scene is changed. Code would be appreciated thankyou
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FolllowAndLoad : MonoBehaviour
{
public Transform target;
public Animator anim;
public Rigidbody2D myRigidBody;
public string levelToLoad;
private static string keyname; // value I want to carry over
public float MoveSpeed;
private bool checkTrigger;
public Rigidbody2D targetRigidBody;
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();//getting the position of our player
anim = GetComponent<Animator>();
myRigidBody = GetComponent<Rigidbody2D>(); //getting my components
targetRigidBody = GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>();
}
void Update()
{
float distance = Vector2.Distance(target.position, myRigidBody.transform.position); //getting the distance between our player and our enemy
if (distance < 5)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, MoveSpeed * Time.deltaTime); //moving our enemy towards our player
anim.SetBool("checkTrigger", true);
anim.SetFloat("MoveX", moveXvalue()); //updating the animations for our enemy
anim.SetFloat("MoveY", moveYvalue());
}
else if (distance > 5) //if out of range stop walking
{
anim.SetBool("checkTrigger", false);
}
}
int moveXvalue()
{
int value;
if (myRigidBody.transform.position.x < target.transform.position.x && Mathf.Abs(target.position.y - myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x)) //these are saying if the enemy is closer in x than in y use x animations and vice versa
value = 1;
else if (myRigidBody.transform.position.x > target.transform.position.x && Mathf.Abs(target.position.y - myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x))
value = -1;
else
value = 0;
return value;
}
int moveYvalue()
{
int value;
if (myRigidBody.transform.position.y < target.transform.position.y && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x))
value = 1;
else if (myRigidBody.transform.position.x > target.transform.position.x && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x))
value = -1;
else
value = 0;
return value;
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name == "Player")
{
Debug.Log(gameObject.name);
anim.SetBool("checkInContact", true);
Application.LoadLevel (levelToLoad); //loading our level
}
}
}
There are a lot of ways to do this, but the simplest way to get something working quickly just until you get more familiar with Unity it to use a simple static class in your project that you can access from any script in any scene.
So if you were to make a new script in your project right now called SharedResources.cs and then pasted this into the script and saved it....
public static class SharedResources
{
public const int kSceneIs_TitleScene = 0;
public const int kSceneIs_ActualGameScene = 1;
public const int kSceneIs_HighScoreScene = 2;
public static int highScore = 0;
public static int enemyID = 0;
public static void sampleFunction()
{
//this is a sample method you can call from any other script
}
}
You could now be in a script in one scene and do this
SharedResources.highScore=SharedResources.highScore+20;
SharedResources.enemyID=5;
You could then open up a new scene and a script in that scene could access the high score
Debug.Log(SharedResources.highScore)
Debug.Log(SharedResources.enemyID)
You can also access constant and run subroutines that are in the static class as shown above.
The correct way to do this is up for debate and really depends on what your ultimate goal is. I will reference another link to a post that goes into more detail....
https://gamedev.stackexchange.com/questions/110958/unity-5-what-is-the-proper-way-to-handle-data-between-scenes
Ideally, you should read and understand the difference between using a simple static class versus one that derives from MonoBehavior, and also the different between a static class and a Singleton, which in many ways is much more powerful (but can also cause issues if you don't code it correctly)
Last but not least, don't forget you can also use the built in PlayerPrefs function in Unity to store scores and other settings that need to carry over between launches of the game....
https://answers.unity.com/questions/1325056/how-to-use-playerprefs-2.html
I am doing a roll-a-ball game where the ball moves and it counts when the ball collides with the cubes. I need for the game to count every time the ball moves but I can't seem to figure it out. I keep getting errors. I appreciate any help.
using UnityEngine;
// Include the namespace required to use Unity UI
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
// Create public variables for player speed, and for the Text UI game objects
public float speed;
public Text countText;
public Text winText;
public Text movesText;
// Create private references to the rigidbody component on the player, and the count of pick up objects picked up so far
private Rigidbody rb;
private int count;
private int moves;
private float location;
// At the start of the game..
void Start()
{
// Assign the Rigidbody component to our private rb variable
rb = GetComponent<Rigidbody>();
// Set the count to zero
count = 0;
// Set moves to zero
moves = 0;
// Run the SetCountText function to update the UI (see below)
SetCountText();
// Set the text property of our Win Text UI to an empty string, making the 'You Win' (game over message) blank
winText.text = "";
location = transform.location;
SetMovesText();
}
void LateUpdate()
{
if (location != transform.location)
{
moves = moves + 1;
location = transform.location;
SetMovesText();
}
}
// Each physics step..
void FixedUpdate()
{
// Set some local float variables equal to the value of our Horizontal and Vertical Inputs
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
// Create a Vector3 variable, and assign X and Z to feature our horizontal and vertical float variables above
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
// Add a physical force to our Player rigidbody using our 'movement' Vector3 above,
// multiplying it by 'speed' - our public player speed that appears in the inspector
rb.AddForce(movement * speed);
}
// When this game object intersects a collider with 'is trigger' checked,
// store a reference to that collider in a variable named 'other'..
void OnTriggerEnter(Collider other)
{
// ..and if the game object we intersect has the tag 'Pick Up' assigned to it..
if (other.gameObject.CompareTag("Pick Up"))
{
// Make the other game object (the pick up) inactive, to make it disappear
other.gameObject.SetActive(false);
// Add one to the score variable 'count'
count = count + 1;
// Run the 'SetCountText()' function (see below)
SetCountText();
}
}
// Create a standalone function that can update the 'countText' UI and check if the required amount to win has been achieved
void SetCountText()
{
// Update the text field of our 'countText' variable
countText.text = "Count: " + count.ToString();
// Check if our 'count' is equal to or exceeded 12
if (count >= 12)
{
// Set the text value of our 'winText'
winText.text = "You Win!";
}
}
void SetMovesText()
{
movesText.text = "Moves: " + moves.ToString();
}
}
There is no such thing as transform.location in Unity. I believe you want to get the position of the object. This is done with transform.position and the rotation of an object can be modified with transform.rotation.
I need for the game to count every time the ball moves
You can do this by checking when transform.position changes.
Here are the changes that needs to be made based on what I said above:
1.Change your private float location; to private Vector3 location;
2.Change location = transform.location; to location = transform.position;
3.Change if (location != transform.location) to if (location != transform.position)
4.Finally change location = transform.location; to location = transform.position;.
The fixed code:
public class PlayerController : MonoBehaviour
{
// Create public variables for player speed, and for the Text UI game objects
public float speed;
public Text countText;
public Text winText;
public Text movesText;
// Create private references to the rigidbody component on the player, and the count of pick up objects picked up so far
private Rigidbody rb;
private int count;
private int moves;
private Vector3 location;
// At the start of the game..
void Start()
{
// Assign the Rigidbody component to our private rb variable
rb = GetComponent<Rigidbody>();
// Set the count to zero
count = 0;
// Set moves to zero
moves = 0;
// Run the SetCountText function to update the UI (see below)
SetCountText();
// Set the text property of our Win Text UI to an empty string, making the 'You Win' (game over message) blank
winText.text = "";
location = transform.position;
SetMovesText();
}
void LateUpdate()
{
if (location != transform.position)
{
moves = moves + 1;
location = transform.position;
SetMovesText();
}
}
// Each physics step..
void FixedUpdate()
{
// Set some local float variables equal to the value of our Horizontal and Vertical Inputs
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
// Create a Vector3 variable, and assign X and Z to feature our horizontal and vertical float variables above
Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
// Add a physical force to our Player rigidbody using our 'movement' Vector3 above,
// multiplying it by 'speed' - our public player speed that appears in the inspector
rb.AddForce(movement * speed);
}
// When this game object intersects a collider with 'is trigger' checked,
// store a reference to that collider in a variable named 'other'..
void OnTriggerEnter(Collider other)
{
// ..and if the game object we intersect has the tag 'Pick Up' assigned to it..
if (other.gameObject.CompareTag("Pick Up"))
{
// Make the other game object (the pick up) inactive, to make it disappear
other.gameObject.SetActive(false);
// Add one to the score variable 'count'
count = count + 1;
// Run the 'SetCountText()' function (see below)
SetCountText();
}
}
// Create a standalone function that can update the 'countText' UI and check if the required amount to win has been achieved
void SetCountText()
{
// Update the text field of our 'countText' variable
countText.text = "Count: " + count.ToString();
// Check if our 'count' is equal to or exceeded 12
if (count >= 12)
{
// Set the text value of our 'winText'
winText.text = "You Win!";
}
}
void SetMovesText()
{
movesText.text = "Moves: " + moves.ToString();
}
}
So I'm working on a project for class in which, using Unity3D, I'm instatiating fish game objects into a game and making them appear randomly across the background. Currently, I have this code that's supposed to make my critter appear. I wrote two scripts that are supposed to make my critter game objects appear on different sides of the screen
using UnityEngine;
using System.Collections;
public class Wrangler : MonoBehaviour {
public static float halfWidth = 6;
public static float halfHeight = 5;
public GameObject critterPrefab;
public GameObject crabPrefab;
int critterCount = 0; //how many we've made so far
int critterMax = 5; //how many you want
int crabCount = 0;
int crabMax = 5;
// how long between critter spawns
void Start()
{
StartCoroutine("SpawnCritter");
StartCoroutine("SpawnCrab");
}
IEnumerator SpawnCritter()
{
while (critterCount < critterMax)
{
CreateCritter();
yield return new WaitForSeconds(1.0f);
}
}
IEnumerator SpawnCrab()
{
while (crabCount < crabMax)
{
CreateCrab();
yield return new WaitForSeconds(1.0f);
}
}
void CreateCritter() {
critterCount++;
Instantiate(critterPrefab);
}
void CreateCrab() {
crabCount++;
Instantiate(crabPrefab);
}
}
using UnityEngine; //allows us to use objects and stuff from Unity Engine
using System.Collections;
//creates a class we can manipulate called "Critter" and allows it to do the
//same thing MonoBehavior does
public class Critter : MonoBehaviour {
//variables here are for the class to use and functions can use them any time
//It looks like you can create variables first, then create the functions
protected Rigidbody rb;
// Use this for initialization
public virtual void Start () {
float startX = Random.Range (-Wrangler.halfWidth, Wrangler.halfwidth);
float startY = Random.Range (-Wrangler.halfHeight, Wrangler.halfheight);
transform.position = new Vector2 (startX, startY);
rb = GetComponent<Rigidbody> ();// Functions make classes do stuff
setVelocity ();
}
public virtual void setVelocity() {
rb.velocity = new Vector2 (-1,0);
}
// Update is called once per frame
void Update () {
if (transform.position.x > Wrangler.halfWidth)
transform.position = new Vector2 (-Wrangler.halfWidth, transform.position.y);
if(transform.position.x < Wrangler.halfWidth)
transform.position = new Vector2 (Wrangler.halfWidth, transform.position.y);
if(transform.position.y > Wrangler.halfHeight)
transform.position = new Vector2 (-Wrangler.halfHeight, transform.position.y);
if(transform.position.y < Wrangler.halfHeight)
transform.position = new Vector22 (Wrangler.halfHeight, transform.position.y);
}
}
I keep getting compiler errors in Unity that say things like "Wrangler does not contain definition for "halfWidth" when I clearly define halfWidth = 6.
What do I do to add the definition and fix these errors?
C# is case sensitive.
In Critter code you use:
float startX = Random.Range (-Wrangler.halfWidth, Wrangler.halfwidth);
float startY = Random.Range (-Wrangler.halfHeight, Wrangler.halfheight);
In Wrangler, halfWidth and halfWidth are declared with capital W and H, but here you use halfwidth and halfheight.
About the error in the image - the Wrangler as you posted is correct and should compile, however pay attention that the error is about "CrabPrefab" and not "crabPrefab" as you declared it, so maybe in your local code you used capital CrabPrefab and CritterPrefab instead?
Just pay attention to the case of your variables.
I was making game in Unity 3D
and used the one click converter of unity to convert it in Android .apk
The game is opening in Android phone
but the player is not moving
Player controller Script:
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {
public Vector2 moving = new Vector2();
public int Bulletlimit = 0;
public int MaxBulletlimit = 3;
public bool Gun;
private float lastShotTime ;
public float fireDelay = 0.2f;
public Transform BulletDirection;
public Bullet bullet;
// Use this for initialization
void Start () {
lastShotTime = Time.time;
}
// Update is called once per frame
void Update () {
moving.x = moving.y = 0;
if (Input.GetKey ("right")) {
moving.x = 1;
} else if (Input.GetKey ("left")) {
moving.x = -1;
}
if (Input.GetKey ("up")) {
moving.y = 1;
} else if (Input.GetKey ("down")) {
moving.y = -1;
}
if (Input.GetKey ("s")) {
if(Gun){
if(Bulletlimit < MaxBulletlimit)
{
if(Time.time > lastShotTime + fireDelay)
{
Bullet clone = Instantiate (bullet, BulletDirection.position, Quaternion.identity) as Bullet;
Bulletlimit = Bulletlimit + 1;
lastShotTime = Time.time;
}
}
}
}
}
public void BulletCount()
{
Bulletlimit = Bulletlimit - 1;
}
}
How do I make him move in touch screens?
Your code is based on keystrokes - that (probably) wont apply to your touch screen.
There are a few ways you could do this, for something so simple I would probably try adding a Canvas along with some buttons to act as controls.
From there you can use the OnMouseDown()/OnMouseUp()/OnClick() methods (This also converts to touchscreens) instead of keystrokes.
How you code from there is a choice you have to make but in this case I would likely use the buttons to turn on/off movement bools and check/apply them in the Update() method.
If you're unsure of how to use the new unity UI try this...
https://unity3d.com/learn/tutorials/modules/beginner/ui/ui-canvas
If you're running the new version of unity (currently 5.1 I believe), my editor looks different to the tutorials and won't stay as default for some reason. Simply set the editor/inspector view to default if some of the options appear to be missing.
There are more complex things you can do with the actual touch inputs but I don't think you need to worry about it in this particular case.
Hope this helps :)