Sync Text objects in Unity - unity3d

I have a prefab that has a text object on it and that text represents a counter for the prefab lifespan that increases every second. The script works fine on the human vs computer mode, but when I try to make a host client the numbers are always different on the clients side. How can I let the numbers displayed on them sync together?
public class Timer : MonoBehaviour
{
public Planet pl;
private bool hasDone = false;
public int timeleft =6;
public Text countdownText;
// Use this for initialization
void Start()
{
timeleft = Random.Range (0, 31);
}
// Update is called once per frame
void Update()
{
countdownText.text = ("" + timeleft);
if (pl.get_owner () != null && hasDone == false) {
StartCoroutine("LoseTime");
hasDone = true;
}
if (pl.get_owner () == "Human") {
countdownText.color = new Color (0f, 0.5f, 1f, 1f);
}
if (pl.get_owner () == "Computer") {
countdownText.color = new Color (1f, 0.5f, 0f, 1f);
}
if (pl.get_collision () > 0) {
timeleft -= 1;
pl.decrease_collision ();
}
}
IEnumerator LoseTime()
{
if (pl.get_owner () != null) {
while (true)
{
yield return new WaitForSeconds(1);
timeleft++;
}
}
}
}

I think you are looking for the syncvar attribute: https://docs.unity3d.com/ScriptReference/Networking.SyncVarAttribute.html
[SyncVar]
public int timeleft =6;
Additionally only the server should change the value. Add the following code to all locations where you would alter timeleft.
if (!isServer)
return;

Related

I have a problem programming with unity to paste the image of footsteps on the ground when the player moves

public class FootPaint : MonoBehaviour
{
#region --- helpers --
public enum enumFoot
{
Left,
Right,
}
#endregion
public GameObject LeftPrefab;
public GameObject RightPrefab;
public float FootprintSpacer = 1.0f;
private Vector3 LastFootprint;
private enumFoot WhichFoot;
public GameObject[] intdexPos;
private void Start()
{
LastFootprint = this.transform.position;
}
private void Update()
{
FootPaints();
}
public void FootPaints()
{
if (CheckPaintItem.instance.isPaint == true && gameObject.name == "PlayerSeek")
{
float DistanceSinceLastFootprint = Vector3.Distance(transform.position, LastFootprint);
if (DistanceSinceLastFootprint >= FootprintSpacer)
{
LastFootprint = this.transform.position;
if (WhichFoot == enumFoot.Left)
{
SpawnFootDecal(LeftPrefab);
WhichFoot = enumFoot.Right;
}
else if (WhichFoot == enumFoot.Right)
{
SpawnFootDecal(RightPrefab);
WhichFoot = enumFoot.Left;
}
LastFootprint = new Vector3(this.transform.position.x, this.transform.position.y + 1f, this.transform.position.z);
}
}
}
public void SpawnFootDecal(GameObject prefab)
{
int index = Random.Range(0, intdexPos.Length);
//where the ray hits the ground we will place a footprint
GameObject decal = Instantiate(prefab);
decal.transform.position = intdexPos[index].transform.position;
decal.transform.Rotate(Vector3.forward, intdexPos[index].transform.eulerAngles.y);
//turn the footprint to match the direction the player is facing
}
}
public class CheckPaintItem : MonoBehaviour
{
public static CheckPaintItem instance;
#region boolPaint
[HideInInspector]
public bool isPaint = false;
[HideInInspector]
public bool isPaintYellow = false;
[HideInInspector]
public bool isPaintRed = false;
[HideInInspector]
public bool isPaintBlue = false;
[HideInInspector]
public bool isPaintGreen = false;
#endregion
private float currentMoveSpeed;
private void Awake()
{
instance = this;
}
private void Start()
{
currentMoveSpeed = 2.5f;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PaintsYellow")
{
Debug.Log("Yellow");
isPaint = true;
isPaintYellow = true;
StartCoroutine(timePaint());
}
else if (other.gameObject.tag == "PaintsRed")
{
isPaint = true;
isPaintRed = true;
StartCoroutine(timePaint());
}
else if (other.gameObject.tag == "PaintsBlue")
{
isPaint = true;
isPaintBlue = true;
StartCoroutine(timePaint());
}
else if (other.gameObject.tag == "PaintsGreen")
{
isPaint = true;
isPaintGreen = true;
StartCoroutine(timePaint());
}
else
{
isPaint = false;
isPaintYellow = false;
isPaintRed = false;
isPaintBlue = false;
isPaintGreen = false;
}
if (other.gameObject.tag == "PaintsGlue")
{
StartCoroutine(changeMoveSpeedSlow());
}
if (other.gameObject.tag == "Speed")
{
StartCoroutine(changeMoveSpeedFast());
Destroy(other.gameObject);
}
}
IEnumerator changeMoveSpeedSlow()
{
PlayerController.instance._moveSpeed = PlayerController.instance._moveSpeed / 2 + 0.2f;
yield return new WaitForSeconds(5f);
PlayerController.instance._moveSpeed = currentMoveSpeed;
}
IEnumerator changeMoveSpeedFast()
{
PlayerController.instance._moveSpeed = PlayerController.instance._moveSpeed + 1f;
yield return new WaitForSeconds(5f);
PlayerController.instance._moveSpeed = currentMoveSpeed;
}
IEnumerator timePaint()
{
yield return new WaitForSeconds(15f);
isPaint = false;
}
}
I want to code the game "hide and seek", but I had a problem when the character stepped into a puddle of paint.
My game has 1 character finding and 5 moving AIs, I want whether the AI or the player steps into the puddle, it will leave footprints. But I have problem with above scripts tag, I add script tag with all characters.
So one character walks in, all the other characters show their footsteps. I don't know if my direction is correct. If anyone wants to understand more about the game I'm coding, you can go to youtube and type hide and seek and it will come out.
Thank you.
It seems to me, that the problem lies within CheckPaintItem.instance.isPaint. I don't know what that script is exactly, but it's probably a singleton pattern as there is an instance call. If that's the case, then you're checking if any CheckPaintItem is true globally as it's fields are pretty much static. So make changes to CheckPaintItem or show us what it does exactly.

RayCastAll from Camera to Player Not Working

Trying to run a raycast from my camera to Z = 0 that will hit objects on the TransparentFX layer and temporarily make them transparent as they are likely blocking the view of the player. But the raycast never hits anything.
Camera
https://imgur.com/lyTo8OZ
Tree
https://imgur.com/bgNiMWR
ClearSight.cs
[RequireComponent(typeof(Camera))]
public class ClearSight : MonoBehaviour
{
[SerializeField]
private LayerMask raycastLayers;
// Update is called once per frame
void Update()
{
Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
Debug.DrawRay(transform.position, forward, Color.green);
RaycastHit2D[] hits = Physics2D.RaycastAll(transform.position, transform.TransformDirection(Vector3.forward), 10f, raycastLayers);
if(hits != null && hits.Length > 0)
{
Debug.Log("Found objects blocking player!");
foreach(RaycastHit2D hit in hits)
{
Debug.Log("Making " + hit.transform.gameObject.name + " transparent!");
AutoTransparent at = hit.transform.GetComponent<AutoTransparent>();
if(at == null)
{
at = hit.transform.gameObject.AddComponent<AutoTransparent>();
}
at.MakeTransparent();
}
}
}
}
AutoTransparent.cs
[RequireComponent(typeof(SpriteRenderer))]
public class AutoTransparent : MonoBehaviour
{
[SerializeField]
private SpriteRenderer[] renderTargets;
[SerializeField]
private float transparentRecoveryTime = 0.1f;
private bool isTransparent = false;
private float transparencyTimer = 0;
private void Update()
{
if (isTransparent)
{
UpdateTransparencyTimer();
}
}
private void UpdateTransparencyTimer()
{
transparencyTimer += Time.deltaTime / transparentRecoveryTime;
if(transparencyTimer >= 1)
{
MakeOpaque();
}
}
public void MakeTransparent()
{
transparencyTimer = 0;
if (!isTransparent)
{
isTransparent = true;
foreach (SpriteRenderer renderer in renderTargets)
{
Color c = renderer.color;
renderer.color = new Color(c.r, c.g, c.b, 0.3f);
}
}
}
public void MakeOpaque()
{
isTransparent = false;
foreach(SpriteRenderer renderer in renderTargets)
{
Color c = renderer.color;
renderer.color = new Color(c.r, c.g, c.b, 1);
}
}
}
Figured it out. I was using RaycastHit2D and Physics2D.RaycastAll, which uses Vector2 parameters so the Z forward variable was being taken out of the equation. Switched up to Box Collider and Physics.RaycastAll and it works great.

How to prevent same prefab from spawning twice in a row in Unity

Unity beginner here, I have a random prefab spawner attached to my game in Unity which randomly spawns 3 prefabs. The problem is, sometimes I get the same prefab like 5 times in a row. How can I prevent the same prefab from spawning twice in a row? Here is my code:
public class randomspawnscript : MonoBehaviour
{
public GameObject prefab1, prefab2, prefab3;
public float spawnRate = 2f;
float nextSpawn = 0f;
int whatToSpawn;
void Update()
{
if (collisionbutton.end != true || gameoverscreenrestart.restartPressed==true || gameovermainmenu.menuPressed==true)
{
if (Time.time > nextSpawn)
{
whatToSpawn = Random.Range(1, 4);
Debug.Log(whatToSpawn);
switch (whatToSpawn)
{
case 1:
Instantiate(prefab1, transform.position, Quaternion.identity);
break;
case 2:
Instantiate(prefab2, transform.position, Quaternion.identity);
break;
case 3:
Instantiate(prefab3, transform.position, Quaternion.identity);
break;
}
nextSpawn = Time.time + spawnRate;
}
}
else
{
return;
}
}
}
A simple way using the Unity's in build Random system is just to create a list of possible generated numbers, and pick a random number from that list, like so:
public class randomspawnscript : MonoBehaviour {
public GameObject prefab1, prefab2, prefab3;
public float spawnRate = 2f;
float nextSpawn = 0f;
int whatToSpawn;
private void Awake() {
// To not get a null ref error when generating the controlled random
// for the first time.
whatToSpawn = 0;
}
void Update() {
if (/* ... */) {
if (Time.time > nextSpawn) {
whatToSpawn = GetControlledRandom();
Debug.Log(whatToSpawn);
switch (whatToSpawn) {
//...
}
nextSpawn = Time.time + spawnRate;
}
} else {
return;
}
}
int GetControlledRandom() {
List<int> possibleChoices = new List<int> {
1, 2, 3
};
// Removes what was spawned before from the possible choices.
possibleChoices.Remove(whatToSpawn);
return possibleChoices[Random.Range(0, possibleChoices.Count)];
}
}
Alternatively, the more simpler way is to just keep generating a number until you get the one you are satisfied with, like so:
int RetardedControlledRandom() {
int generatedNumber;
do {
generatedNumber = Random.Range(1, 4);
} while (generatedNumber == whatToSpawn);
return generatedNumber;
}
This can help if you decide to use the .NET provided System.Random instead.
Also, note that currently most of your values/variables are hardcode.
(Aka it does not dynamically suit to spawning more than 4 types of prefab)
Unity Inspector accepts an array too, so you can make use of that and refactor your code like so:
public class randomspawnscript : MonoBehaviour {
public GameObject[] possibleSpawnPrefabs;
public float spawnRate = 2f;
float nextSpawn = 0f;
int whatToSpawn;
private void Awake() {
whatToSpawn = 0;
}
void Update() {
if (collisionbutton.end != true || gameoverscreenrestart.restartPressed == true || gameovermainmenu.menuPressed == true) {
if (Time.time > nextSpawn) {
whatToSpawn = GetControlledRandom();
Debug.Log(whatToSpawn);
var prefabToSpawn = possibleSpawnPrefabs[whatToSpawn];
Instantiate(prefabToSpawn, transform.position, Quaternion.identity);
nextSpawn = Time.time + spawnRate;
}
} else {
return;
}
}
int GetControlledRandom() {
List<int> possibleChoices = new List<int>();
for (int i = 0; i < possibleSpawnPrefabs.Length; ++i) {
possibleChoices.Add(i);
}
// Removes what was spawned before from the possible choices.
possibleChoices.Remove(whatToSpawn);
return possibleChoices[Random.Range(0, possibleChoices.Count)];
}
}
Well, just make a statement that checks the new randomized Prefab with the previous randomized prefab.
For the lazy code, you can just
GameObject previousPrefab;
and in Randomization, set the previousPrefab to the randomized prefab.
and in next Randomization, check if the previousPrefab == randomizedPrefab, if yes,
randomize again.
^ Also to achieve something like this you have to create a method from your Update() section and call it in Update() so you can call the method again if the previousPrefab is the same as the randomized one.

Unity 2D Camera Zooms in when character moves, but properties of the camera do not change

After I click play the camera stays as it should be, but when I move my character the camera zooms in for no reason
The properties of the camera do not change at all, zoom and everything stays the same. Tryed changing from orthographic to perspective no change, move z axis no change, change scale no change, change resolution and no change, making the camera not a parent and no change it behaves the same as parent and as child
before character walks
after character walks
I dont think that there is something to do with the code but here is the code attached to my character, the camera behaves the same as child and as parent
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public float speed = 5f;
public float jumpSpeed = 8f;
private float movementX = 0f;
private Rigidbody2D rigidBody;
public Transform groundCheckPoint;
public float groundCheckRadius;
public LayerMask groundLayer;
public bool isTouchingGround;
public SpriteRenderer box;
private bool canSpawn = true;
private bool canAnimateWalk = true;
private bool canAnimateIdle = true;
private bool canAnimateJump = true;
private bool stopJump = true;
private int spawningSpeed = 1000;
// Use this for initialization
void Start()
{
rigidBody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
isTouchingGround = Physics2D.OverlapBox(groundCheckPoint.position,new Vector2(0.9f,0.1f),0f, groundLayer);
movementX = Input.GetAxis("Horizontal");
if (movementX > 0f)
{
if(canAnimateWalk==true && isTouchingGround)
{
canAnimateWalk = false;
StartCoroutine(AnimateWalk());
}
GetComponent<SpriteRenderer>().transform.localScale = new Vector3(2, 2, 1);
rigidBody.velocity = new Vector2(movementX * speed, rigidBody.velocity.y);
}
else if (movementX < 0f)
{
if (canAnimateWalk == true && isTouchingGround)
{
canAnimateWalk = false;
StartCoroutine(AnimateWalk());
}
GetComponent<SpriteRenderer>().transform.localScale = new Vector3(-2, 2, 1);
rigidBody.velocity = new Vector2(movementX * speed, rigidBody.velocity.y);
}
else
{
if(isTouchingGround)
{
StopCoroutine(AnimateWalk());
if(canAnimateIdle==true)
{
canAnimateIdle = false;
StartCoroutine(AnimateIdle());
}
}
rigidBody.velocity = new Vector2(0, rigidBody.velocity.y);
}
if (Input.GetButtonDown("Jump") && isTouchingGround)
{
canAnimateJump = false;
rigidBody.velocity = new Vector2(rigidBody.velocity.x, jumpSpeed);
StartCoroutine(AnimateJump());
}
else if(!isTouchingGround)
{
StopCoroutine(AnimateWalk());
}
}
IEnumerator AnimateJump()
{
Debug.Log("Animating Jump");
int counter = 0;
while (counter < 10)
{
counter++;
GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("img/j" + counter);
yield return new WaitForSeconds(0.1f);
if(isTouchingGround==true)
{
break;
}
}
while(!isTouchingGround)
{
GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("img/j10");
yield return new WaitForSeconds(0.1f);
}
GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("img/i1");
canAnimateWalk = true;
canAnimateJump = true;
}
IEnumerator AnimateIdle()
{
int counter = 0;
while(Input.GetAxis("Horizontal")==0 && counter <10 && rigidBody.velocity.y==0)
{
counter++;
GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("img/i"+counter);
yield return new WaitForSeconds(0.2f);
}
canAnimateIdle = true;
}
IEnumerator AnimateWalk()
{
int counter = 0;
while (Input.GetAxis("Horizontal")!=0 && counter < 8 && rigidBody.velocity.y==0)
{
counter++;
GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>("img/g" + counter);
yield return new WaitForSeconds(0.08f);
}
canAnimateWalk = true;
}
}
What could it be? I tried everything I think
GetComponent<SpriteRenderer>().transform.localScale = new Vector3(-2, 2, 1);
If your movement script is attached to your "guy" gameobject, then you are changing the (local) scale of it. All children will also scale accordingly.
Since your camera is a child of guy, it will scale and produce the result you see.
Try unparenting the Camera from your guy and create a seperate script that follows your guy and attach that to your Camera.
I solved my problem
The issue was in the character scaling. The camera did not change but the size of the character did making me believe that there was a zoom in.
My character x and y scale is 1 and 1 but I used 2 and 2 scale on move
The scale was used to rotate my character when it moves left and right

Unity- Moving an Object to the left on a Scrolling Background

I am trying to create a simple Infinite Runner game on Unity and ran into a problem. The task is to make a ball spawn on the floor and immediately begin to roll to the left towards the Player. I have tried a number of ways to implement it, but it does not seem to work. Here is my most recent attempt:
public class ObstaclePool : MonoBehaviour {
public GameObject columnPrefab;
public GameObject ballPrefab;
public int obstaclePoolSize = 5;
public float spawnRate = 3f;
private GameObject[] obstacles;
private int currentObstacle = 0;
private Vector2 objectPoolPosition = new Vector2(-15, -25);
private float timeSinceLastSpawned;
private float spawnXPosition;
private bool hasCalled = false;
private int dice;
bool beforeBall = false;
// Use this for initialization
void Start () {
timeSinceLastSpawned = 0f;
SetupObstacles();
}
private void SetupObstacles()
{
obstacles = new GameObject[obstaclePoolSize];
for (int i = 0; i < obstaclePoolSize; i++)
{
dice = Random.Range(1, 3);
if (dice == 1)
{
obstacles[i] = (GameObject)Instantiate(columnPrefab, objectPoolPosition, Quaternion.identity);
}
else if (dice == 2)
{
obstacles[i] = (GameObject)Instantiate(ballPrefab, objectPoolPosition, Quaternion.identity);
}
}
}
// Update is called once per frame
void Update () {
timeSinceLastSpawned += Time.deltaTime;
if (GameControl.instance.gameOver == false && timeSinceLastSpawned >= spawnRate)
{
timeSinceLastSpawned = 0f;
if (hasCalled == false)
{
spawnXPosition = 10f;
hasCalled = true;
}
else
{
spawnXPosition = Random.Range(6f, 10f);
}
if (obstacles[currentObstacle].transform.tag == "Ball")
{
spawnXPosition = Random.Range(9f, 10f);
obstacles[currentObstacle].transform.position = new Vector2(spawnXPosition, -1.84f);
ballPrefab.GetComponent<Rigidbody2D>().AddForce(new Vector2(-100f, 0) * 5);
beforeBall = true;
}
else {
if (beforeBall == true)
{
spawnXPosition = Random.Range(9f, 10f);
beforeBall = false;
}
obstacles[currentObstacle].transform.position = new Vector2(spawnXPosition, -7.08f);
Debug.Log(spawnXPosition);
}
currentObstacle++;
if (currentObstacle >= obstaclePoolSize)
{
currentObstacle = 0;
SetupObstacles();
hasCalled = false;
}
}
}
}
For a quick explanation of my code: I have an array of size 5. It holds the obstacles that I have created. When deciding what to put inside the array, I generated a random number (1 or 2). If it's a 1, I put in a column. If it's a 2, I put in a ball. These obstacles are spawned off-screen. Then, I move them in the actual scene after using random number to determine the X position.
This part in particular is where I try to implement it:
if (obstacles[currentObstacle].transform.tag == "Ball")
{
spawnXPosition = Random.Range(9f, 10f);
obstacles[currentObstacle].transform.position = new Vector2(spawnXPosition, -1.84f);
ballPrefab.GetComponent<Rigidbody2D>().AddForce(new Vector2(-100f, 0) * 5);
beforeBall = true;
}
I may have some remnants of stuff that I have been testing out, so some of the code may seem redundant and messy.
I also tried using Translate and Velocity with no success. I also have a ScrollingObject code and a RepeatingBackground code. I placed the ScrollingObject code in the Ball prefab too. (Also, tried taking it out -> ball rolls to the right). These codes come from the Unity tutorial.
RepeatingBackground:
public class RepeatingBackground : MonoBehaviour {
private BoxCollider2D groundCollider;
private float groundHorizontalLength;
// Use this for initialization
private void Awake () {
groundCollider = GetComponent<BoxCollider2D>();
groundHorizontalLength = groundCollider.size.x;
}
// Update is called once per frame
private void Update () {
if (transform.position.x < -groundHorizontalLength)
{
RepositionBackground();
}
}
private void RepositionBackground()
{
Vector2 groundOffSet = new Vector2(groundHorizontalLength * 2f, 0);
transform.position = (Vector2)transform.position + groundOffSet;
}
}
ScrollingObjects:
public class ScrollingObject : MonoBehaviour {
private Rigidbody2D rb2d;
// Use this for initialization
void Start () {
rb2d = GetComponent<Rigidbody2D>();
rb2d.velocity = new Vector2(GameControl.instance.scrollSpeed, 0);
}
// Update is called once per frame
void Update () {
if (GameControl.instance.gameOver == true)
{
rb2d.velocity = Vector2.zero;
}
}
}
It looks like you simply named the wrong object in your first example.
if (obstacles[currentObstacle].transform.tag == "Ball")
{
spawnXPosition = Random.Range(9f, 10f);
obstacles[currentObstacle].transform.position = new Vector2(spawnXPosition, -1.84f);
ballPrefab.GetComponent<Rigidbody2D>().AddForce(new Vector2(-100f, 0) * 5);
beforeBall = true;
}
Notice how here you added the force to the prefab, not an instantiated version of the prefab.
I played around a bit more and got it to work. I just wrote another script that added force to the object. I still do not understand why my original way did not work though.