Intergrating life of player in each level in unity - c#

In my game there are various levels
I have made those level in separate scenes
Every Scene has a player at the starting point and when it crosses the exit point the next level (next scene) is loaded but the health and life are reset as starting point in the game and not remain what the player currently has when he exited the level
Exit level Script:-
using UnityEngine;
using System.Collections;
public class ExitLevel : MonoBehaviour {
public string scene;
private Player player;
// Use this for initialization
void Start () {
player = GameObject.Find ("Player").GetComponent<Player> ();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D target){
if (target.gameObject.tag == "Player") {
if (player.ArtifactCount == 1) {
player.ArtifactCount = 0;
Destroy (target.gameObject);
Application.LoadLevel (scene);
}
}
}
}
LifeMeter Script:-
using UnityEngine;
using System.Collections;
public class LifeMeter : MonoBehaviour {
public float Life = 100;
public float maxLife = 100;
public float LifeBurnRate = 1f;
public Texture2D bgTexture;
public Texture2D LifeBarTexture;
public Texture2D HeartTexture;
public int iconWidth = 32;
public Vector2 LifeOffset = new Vector2(255, 10);
public int HeartCount = 3;
public Vector2 HeartOffset = new Vector2(455, 6.5f);
public int HeartDistance = 0;
public int HeartDistanceAddup = 40;
public int HeartDisplayWidth = 40;
public int HeartDisplayHeight = 40;
private Player player;
private ExitLevel exitLevel;
// Use this for initialization
void Start () {
player = GameObject.FindObjectOfType<Player> ();
}
public void OnGUI(){
var percent = Mathf.Clamp01 (Life / maxLife);
if (!player)
percent = 0;
if(Life == 0 && HeartCount !=0 ){
HeartCount = HeartCount - 1;
Life = 100;
}
HeartDistance = 0;
DrawMeter (LifeOffset.x, LifeOffset.y, LifeBarTexture, bgTexture, percent);
for (int i = 0; HeartCount > i; i++) {
HeartDistance = HeartDistance + HeartDistanceAddup;
GUI.DrawTexture (new Rect (HeartOffset.x + HeartDistance, HeartOffset.y, HeartDisplayWidth, HeartDisplayHeight), HeartTexture);
}
}
void DrawMeter(float x, float y, Texture2D texture, Texture2D background, float percent){
var bgW = background.width;
var bgH = background.height;
GUI.DrawTexture (new Rect (x, y, bgW, bgH), background);
var nW = ((bgW - iconWidth) * percent) + iconWidth;
GUI.BeginGroup (new Rect (x, y, nW, bgH));
GUI.DrawTexture (new Rect (0, 0, bgW, bgH), texture);
GUI.EndGroup ();
}
// Update is called once per frame
void Update () {
}
public void life(){
Life = Life - LifeBurnRate;
if (HeartCount == 0) {
{ Explode script = player.GetComponent<Explode> ();
script.OnExplode ();
}
}
}
}

you can use PlayerPrefs (Stores and accesses player preferences between game sessions)for save current status of Player.
Reffer this link http://docs.unity3d.com/ScriptReference/PlayerPrefs.html

There are two ways to proceed in the above case:
You can add DontDestroyOnload(this); to your player object. This
will not destroy that game object when the new level loads. And On
Every start of level you can spawn him your level start point. This
way your player's stats will remain consistent throughout the game.
You can use a static class to get the players health and other
required stats. Save the players health in the static class while
exiting the level and apply the values to the next levels player
object when the next level loads.

Related

How to utilize stacking blocks under the player object(cylinder) by using rigidbodies in unity3d?

I am working on a hypercasual game project which is very similar to Matching Cubes. Initially, I was using transform to stack blocks under my cylinder(player object). But in the game there will be a ramp to jump through it and by using transform I was ignoring the physics and it passes through the ramp. So I changed it a little bit by utilizing the rigidbody for the cylinder. If there is no block it jumps through the ramp but I need it to jump with blocks. The problem is I couldn't find a way to stack them under the cylinder by using rigidbody. Tried MovePosition or AddForce but it does not work at all.
How can I stack the blocks under the cylinder but also make them jump through the ramp together?
Here is my StackManager.cs . There is a Regulator function that will check the 'picks' list and regulate the positions. It is the function where I handle all positioning.
I also tried making the positioning by transform and when it collides with ramp, stop the Regulator() and AddForce(Vector3.up*offset) but it did not move up a bit.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
public class StackManager : MonoBehaviour
{
public static StackManager instance;
[SerializeField] private float distanceBetweenObjs;
[SerializeField] private Transform prevObject = null;
[SerializeField] private Transform parent;
[SerializeField] private Transform cylinder;
[SerializeField] private Transform trailer;
private List<Transform> picks; // Use this to order gate and random gate
private Vector3 firstPosition;
private int comboCounter; // fever mode tracker
private Rigidbody rb;
private Transform prev;
private void Awake() {
if(instance == null) {
instance = this;
}
}
void Start()
{
rb = cylinder.gameObject.GetComponent<PlayerController>().rb;
comboCounter = 0;
picks = new List<Transform>();
firstPosition = new Vector3(cylinder.position.x, cylinder.position.y, cylinder.position.z);
}
// Update is called once per frame
void Update()
{
Regulator();
}
void CheckChildren() {
List<Transform> children = new List<Transform>();
foreach (Transform child in picks)
{
children.Add(child);
}
for(int i = 0; i < children.Count - 2; i++) {
if (children[i].isSameMaterial2(children[i+1], children[i+2])) {
comboCounter++;
Destroy(children[i].gameObject);
Destroy(children[i+1].gameObject);
Destroy(children[i+2].gameObject);
picks.Remove(children[i]);
picks.Remove(children[i+1]);
picks.Remove(children[i+2]);
};
}
if(comboCounter == 3) {
SpeedBoost(); //fever mode
comboCounter = 0;
}
}
public void PickUp(GameObject pickedObj){
pickedObj.tag = "Picked";
pickedObj.transform.parent = parent;
picks.Add(pickedObj.transform);
}
private void Regulator(){
//Position of cylinder
//set y value based on the # of children objects
/**
*hold the first position of cylinder
*make calculation by referencing it
*reference + localScale.y + 0.1f:
*/
Vector3 newPos = new Vector3(cylinder.position.x, firstPosition.y, cylinder.position.z);
foreach (Transform child in picks)
{
newPos.y += child.localScale.y + 0.1f;
}
//cylinder.position = newPos;
rb.MovePosition(newPos);
//Position of children
if(picks.Count>0) {
prevObject = picks[picks.Count-1];
}
/**
*For each child
* cylinder-0.1f-pick-0.1f-pick-...
*/
prev = cylinder;
for(int i = 0; i < picks.Count; i++)
{
if(i==0){
picks[i].position = new Vector3(prev.position.x, prev.position.y-1.2f, prev.position.z);
//picks[i].gameObject.GetComponent<Rigidbody>().position(new Vector3(prev.position.x, prev.position.y-1.2f, prev.position.z));
} else {
//picks[i].gameObject.GetComponent<Rigidbody>().MovePosition(new Vector3(prev.position.x, prev.position.y-prev.localScale.y -0.1f, prev.position.z));
picks[i].position = new Vector3(prev.position.x, prev.position.y-prev.localScale.y -0.1f, prev.position.z);
}
prev = picks[i];
}
//Position of trailer object
if(picks.Count>0) {
trailer.position = new Vector3(prev.position.x, prev.position.y-0.2f, prev.position.z); //relocate the trailer object under last pick
trailer.GetComponent<TrailRenderer>().material = prev.GetComponent<MeshRenderer>().material; //change the color of the trail
}
CheckChildren(); //check for the 3-conjugate combo
}
public void ChangeRampState() {
Debug.Log("prev.gameObject");
Debug.Log(prev.gameObject);
prev.gameObject.GetComponent<Collider>().isTrigger = false;
rb.AddForce(Vector3.up * 300);
}
public void OrderPicks() {
picks.Sort((x, y) => string.Compare(x.GetComponent<MeshRenderer>().sharedMaterial.name, y.GetComponent<MeshRenderer>().sharedMaterial.name));
}
public void ShufflePicks() {
picks = picks.Fisher_Yates_CardDeck_Shuffle();
}
async public void onObstacle(Transform pickToDestroy) {
pickToDestroy.gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezePosition;
pickToDestroy.parent = null;
await Task.Delay(200);
picks.Remove(pickToDestroy);
}
public void SpeedBoost() {
cylinder.gameObject.GetComponent<PlayerController>().rb.velocity *= 2;
}
}

How to set distance between spawned prefabs?

I want to spawn prefab objects but now the object spawn multiply in one position. I have set up 4 positions around the player and for spawning the objects I'm using this code:
public class EnemySpawner : MonoBehaviour {
public static EnemySpawner instance;
[SerializeField]
private int scoreMileStone = 100; //this will define number of cars in the scene
private int milestoneIncreaser = 100; //this sets new milestone once old is reached
[SerializeField]
private Transform[] spawnPos; //store all the available spawn position
[SerializeField]
private int policeCarRequired; //this will tell how much cars are needed in the scene at a time
private int currentPoliceCar; //this variables keep track of total number of cars in the scene
private GameObject target; //store player reference in this variable
private int lastPosition, r;
private int lastSpawnPos;
public int CurrentPoliceCar { get { return currentPoliceCar; } set { currentPoliceCar = value; } } //getter and setter
// Use this for initialization
void Awake ()
{
if (instance == null) instance = this;
}
// Update is called once per frame
void Update ()
{
if (GuiManager.instance.GameStarted == false || GuiManager.instance.GameOver == true)
return;
if (target == null) //if target is null
{
target = GameObject.FindGameObjectWithTag("Player"); //try detecting target again
return; //return from the method
}
MilestoneIncreaser(); //increase milestone
if (currentPoliceCar < policeCarRequired) //if currentPoliceCar is less than policeCarRequired
{
SpawnPoliceCar(); //spawn police car
}
}
void SpawnPoliceCar() //spawn police car
{
GameObject wolf = ObjectPooling.instance.GetPooledObject("Wolf"); //get police car reference from objectpooling
RandomPos();
int r = Random.Range (0, spawnPos.Length);
while(lastSpawnPos == r)
r = Random.Range (0, spawnPos.Length);
wolf.transform.position = new Vector3(spawnPos[r].position.x, 0, spawnPos[r].position.z); //set the transform
wolf.SetActive(true); //set it active in scene
wolf.GetComponent<Damage>().DefaultSetting(); //call DefaultSettings method
lastSpawnPos = r;
currentPoliceCar++; //increase currentPoliceCar by 1
}
void MilestoneIncreaser() //increase the milestone
{
if (GuiManager.instance.Score >= scoreMileStone) //if currentScore is greater or equal to scoreMilestone
{
scoreMileStone += milestoneIncreaser; //increase the milestone
if (policeCarRequired < 8) //if max policeCarRequired is less than 8
policeCarRequired++; //increase policeCarRequired by 1
}
}
void RandomPos()
{
int r = Random.Range(0, spawnPos.Length); //get random number between zero and total spawnpos
while(lastPosition == r)
r = Random.Range(0, spawnPos.Length);
}
}
That gives me the objects but without any space between them, the objects spawn for example 4 in one position and 3 in the other but they are squeezed. Can I fix that in some way?

How can I generate the units at the same time?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
[Header("Stairs Prefb")]
public GameObject stairsPrefab;
[Space(5)]
[Header("Platforms")]
public bool addPlatforms = false;
public GameObject platformsPrefab;
[Space(5)]
[Header("Settings")]
[Range(1, 20)]
public int numberOfUnits = 1;
public float delay = 3;
public int stairsNumber = 5;
public Vector3 stairsStartPosition;
public Vector3 stairSize;
public Vector3 stairsSize;
public float stepWidthFactor = 1f;
private Vector3 stairsPosition;
private GameObject stairsParent;
private int oldNumberOfUnits = 0;
// Use this for initialization
void Start()
{
oldNumberOfUnits = numberOfUnits;
for (int i = 0; i < numberOfUnits; i++)
{
stairsParent = new GameObject();
stairsParent.name = "Stairs";
StartCoroutine(BuildStairs());
}
}
// Update is called once per frame
void Update()
{
if(oldNumberOfUnits != numberOfUnits)
{
StartCoroutine(BuildStairs());
oldNumberOfUnits = numberOfUnits;
}
}
private IEnumerator BuildStairs()
{
for (int i = 1; i <= stairsNumber; i++)
{
stairsPosition = new Vector3(
stairsStartPosition.x,
stairsStartPosition.y + (i * stairsSize.y),
stairsStartPosition.z + (i * stairsSize.y) * stepWidthFactor);
GameObject stair = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stair.tag = "Stair";
stair.transform.parent = stairsParent.transform;
stair.transform.localScale = stairSize;
yield return new WaitForSeconds(delay);
}
stairsParent.AddComponent<MoveObjects>().Init();
}
}
In the Start I'm doing a loop and start the Coroutine according to the numberOfunits.
It's working fine if numberOfUnits is 1. But is it's more then 1 for example 2 it's first creating the first set of stairs but then on the second "Stairs" parent it's creating only 1 stair. I don't want it to wait to finish the first Coroutine I want in the same time to create number of Coroutine's of stairs.
And I want also to add a gap between each stairs unit.
And also to make that in the Update if I change the numberOfUnits it will add/destroy more stairs units. All the stairs units should be Instantiate inside StartCoroutine.
You are mistaking how the coroutine works its not at thread. What is happening is your continually invoking the coroutine so its starting over and over again not creating a separate instance.
what you should do is create create a prefab and Instantiate that to do the work. My last remark was about threads but you wont be able to instantiate anything unless its on the main thread so the easiest way to get this done would be like so.
public GameObject yourGoWithAboveClassOnIt;
void Start()
{
oldNumberOfUnits = numberOfUnits;
for (int i = 0; i < numberOfUnits; i++)
{
Instantiate(yourGoWithAboveClassOnIt);
}
}
your prior class will remove this
void Start()
{
//oldNumberOfUnits = numberOfUnits;
//for (int i = 0; i < numberOfUnits; i++)
//{
stairsParent = new GameObject();
stairsParent.name = "Stairs";
StartCoroutine(BuildStairs());
//}
}

Unity what's wrong with my instantiating algorithm?

I dont know if I can call this algorithm. But I am working on a game in which player will move in a circular path.
As you can see in the picture player is suppose to orbit the circle. And obstacle shall be instantiated in the circle.I am trying to first create the obstacle in first half(left to the long cube) and then in the second half. But things are getting created in the next half too when code is not supposed to do that. Also, it is showing argument exception error. Please have a look at my code and tell me whether my method is wrong or my formulas are wrong or anything else.
public class ObjectInstantiater : MonoBehaviour {
DataHolder dataholder;
GameObject Obstacle;
LevelData leveldata;
private int currentlevel=0; // default level starts from 0
private List<GameObject> Inactivegameobject = new List<GameObject>(); // this object can be used
private List<GameObject> Activegameobject = new List<GameObject>();
private int totalgameobjects;
private int firsthalfgameobjects, secondhalfgameobjects;
public float outerradius;
public float innerradius;
private bool shallspawnouterradiues = true;
// Use this for initialization
void Awake () {
dataholder = (Object)GameObject.FindObjectOfType<DataHolder>() as DataHolder;
Obstacle = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
leveldata = dataholder.Leveldata[0];
}
void Start()
{
Updateleveldata();
FirstHalf();
}
public int Currentlevel
{
get { return currentlevel; }
set { currentlevel = value;
leveldata = dataholder.Leveldata[currentlevel];//sets the level data
}
}
private void Updateleveldata() // this function gets called after a round
{
totalgameobjects = Random.Range(leveldata.MinimumObstacle, leveldata.MaximumObstacle);
firsthalfgameobjects = Mathf.RoundToInt(totalgameobjects / 2);
secondhalfgameobjects = totalgameobjects - firsthalfgameobjects;
}
private void FirstHalf()
{
Debug.Log(firsthalfgameobjects);
Vector3 pos;
if (Inactivegameobject.Count < firsthalfgameobjects)
{
for (int x = 0; x <= (firsthalfgameobjects - Inactivegameobject.Count); x++)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
float spawnangledivision = 180 / firsthalfgameobjects;
float spawnangle = 180f;
for(int x = 0; x < firsthalfgameobjects; x++)
{
float proceduralRandomangle = spawnangle;
proceduralRandomangle = Random.Range(proceduralRandomangle , proceduralRandomangle + 2f);
if (shallspawnouterradiues)
{
pos = new Vector3(outerradius * Mathf.Cos(spawnangle), outerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = false;
}else
{
pos = new Vector3(innerradius * Mathf.Cos(spawnangle), innerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = true;
}
spawnangle += spawnangledivision;
Inactivegameobject[0].SetActive(true); // set it to 0
Inactivegameobject[0].transform.position = pos;
Activegameobject.Add(Inactivegameobject[0]);
Inactivegameobject.RemoveAt(0);
}
}
private void SecondHalf()// No need to check this
{
if (Inactivegameobject.Count < firsthalfgameobjects)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
}

Setting the spawn position for a 3D object

I am making an endless runner style game in unity where the floor tiles spawn randomly and endlessly in front of the player as they run and delete themselves after a certain distance behind the player this is all working fine and as intended however the individual tiles spawn about half way inside each other and as much as I try to debug my code I can't seem to effect them. Ideally, I want the code to do exactly what it's doing, but the tiles spawn end to end rather than inside each other.
Any help would be greatly appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile_Manager : MonoBehaviour
{
public GameObject[] tilePrefabs;
private Transform playerTransform;
private float spawnZ = 5.0f;
private float tileLength = 5.0f;
private float safeZone = 7.0f;
private int amtTilesOnScreen = 10;
private int lastPrefabIndex = 0;
private List<GameObject> activeTiles;
// Use this for initialization
void Start () {
activeTiles = new List<GameObject>();
playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
for (int i = 0; i < amtTilesOnScreen; i++)
{
if (i < 2)
SpawnTile(0);
else
SpawnTile();
}
}
// Update is called once per frame
void Update () {
if (playerTransform.position.z - safeZone > (spawnZ - amtTilesOnScreen * tileLength))
{
SpawnTile();
DeleteTile();
}
}
private void SpawnTile(int prefabIndex = -1)
{
GameObject go;
if (prefabIndex == -1)
go = Instantiate(tilePrefabs[RandomPrefabIndex()]) as GameObject;
else
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
go.transform.SetParent(transform);
go.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
activeTiles.Add (go);
}
private void DeleteTile()
{
Destroy(activeTiles [0]);
activeTiles.RemoveAt (0);
}
private int RandomPrefabIndex()
{
if (tilePrefabs.Length <= 1)
return 0;
int randomIndex = lastPrefabIndex;
while (randomIndex == lastPrefabIndex)
{
randomIndex = Random.Range(0, tilePrefabs.Length);
}
lastPrefabIndex = randomIndex;
return randomIndex;
}
}
stacked tiles
You need to take the length of a tile into account. Try changing this
go.transform.position = Vector3.forward * spawnZ;
to this
go.transform.position = Vector3.forward * (spawnZ + tileLength / 2);
to add half the tile length to the spawn position.
Wouldn't you want
go.transform.Translate(Vector3.forward * spawnZ);
not position?
As you're spawning things relative to the world coordinate system.
https://docs.unity3d.com/ScriptReference/Transform.Translate.html

Categories