Random in Random? - unity3d

This script was made to compare player tags and determine if they are active (clones) and select an active clone and rename Rplayer to random players name. But It seems to get stuck on the second random select if a player isn't active. I receive Debug.log (Rplayer 2) Debug.Log (Player tag 1) I have tried swapping it around so it's if (! = null) and rebuilding the code but still no luck same thing. Any Ideas? I feel like I'm just looking at this wrong.
if (player.CompareTag("Player1"))
{
Rplayer = Random.Range(1, 4);
if (Rplayer == 1)
{
rplayer1 = GameObject.FindWithTag("Player2");
Debug.Log("Rplayer 1");
}
else if (Rplayer == 2)
{
if (GameObject.FindGameObjectsWithTag("Player3") == null)
{
Rplayer = Random.Range(1, 3);
if (Rplayer == 1)
{
rplayer1 = GameObject.FindWithTag("Player2");
}
else if (Rplayer == 2)
{
if (GameObject.FindGameObjectsWithTag("Player4") == null)
{
rplayer1 = GameObject.FindWithTag("Player2");
}
else
{
rplayer1 = GameObject.FindWithTag("Player4");
}
}
}
else
{
rplayer1 = GameObject.FindWithTag("Player3");
}
Debug.Log("Rplayer 2");
}
else if (Rplayer == 3)
{
if (GameObject.FindGameObjectsWithTag("Player4") == null)
{
Rplayer = Random.Range(1, 3);
if (Rplayer == 1)
{
rplayer1 = GameObject.FindWithTag("Player2");
}
else if (Rplayer == 2)
{
if (GameObject.FindGameObjectsWithTag("Player3") == null)
{
rplayer1 = GameObject.FindWithTag("Player2");
}
else
{
rplayer1 = GameObject.FindWithTag("Player3");
}
}
}
else
{
rplayer1 = GameObject.FindWithTag("Player4");
}
Debug.Log("Rplayer 3");
}
Debug.Log("player tag 1");
}

Going off of this comment:
So I'll try and explain this sorry if it takes 2 comment boxes. You start the game there is an option for 4 players 2 are always active, player 1 player 2. Player 3 and 4 are options to turn on and off, What i'm doing is trying to display an alert when a player lands on a spot <-- Works. The displayed Alert Will get the players name that landed on the spot and enter it into the alert. it then needs to check if player 3 or 4 is active and randomly select 1 player that is not the player who landed on the spot. then activate the alert if (message == 1) { yield return MessageAlert.instance.DisplayAlert(player.name + "Trade Spaces with " + rplayer1.name, Color.blue);
Assuming each player in the game has a Player.cs script attached to it (or something similar), this should be fairly straightforward. Rather than managing players with tags and ids, we can manage the references directly.
First, let's create a method that selects another random player that is NOT the one that landed on the spot. This script can be made as a singleton, or even just attached to the spot.
public Player[] allActivePlayers;
void Start()
{
//Only returns active GameObjects with the Player.cs script attached
allActivePlayers = FindObjectsOfType<Player>();
}
public Player RandomOtherPlayer(Player excludedPlayer)
{
//Create a collection of all other active players that don't include the current player
IEnumerable<Player> activeOtherPlayers = allActivePlayers.Where(player => player != excludedPlayer);
//generate a random number to select from the new collection
int randNum = Random.Range(0, activeOtherPlayers.Count());
//Return the randomly select player
return activeOtherPlayers.ElementAt(randNum);
}
Now when playerA lands on the spot, you can call this to get a random other player.
Player playerB = RandomOtherPlayer(playerA);
--Disclaimer: If there are any syntax errors please let me know. I typed this in browser and have not yet tested via Unity.

Related

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);
}
}

AudioSource.Play() not working in Enumerator

I have an Enumerator for the effects played when you shoot a gun. It is:
private IEnumerator ShotEffect()
{
gunAudio.Play();
laserLine.enabled = true;
yield return shotDuration;
laserLine.enabled = false;
}
When I take the gunAudio.Play() out, the code works fine. However, when I add it in, the sound does not play and the line doesn't disable. I assume there is a problem with the shotDuration?
The variable gunAudio is given the audio component in start, and shotDuration is a wait for seconds.
EDIT:
Also, if I set it to play on awake, it plays. Therefore I think there is a problem with the code, not the component.
Here is where I call the Enumerator:
if (Input.GetKey(KeyCode.Mouse0) && Time.time > nextFire)
{
torsoDamage = (int)Random.Range(50f, 70f);
legDamage = (int)Random.Range(20f, 30f);
handDamage = (int)Random.Range(5f, 15f);
nextFire = Time.time + fireRate;
StartCoroutine (ShotEffect());
Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f));
RaycastHit hit;
laserLine.SetPosition (0, gunEnd.position);
if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange))
{
laserLine.SetPosition (1, hit.point);
if (enemyAi.enemy_currentHealth != null)
{
if (hit.collider.gameObject.tag == "head")
{
enemyAi.Damage(100);
}
if (hit.collider.gameObject.tag == "torso")
{
enemyAi.Damage(torsoDamage);
}
if (hit.collider.gameObject.tag == "leg" || hit.collider.gameObject.tag == "arm")
{
enemyAi.Damage(legDamage);
}
if (hit.collider.gameObject.tag == "hand" || hit.collider.gameObject.tag == "foot")
{
enemyAi.Damage(handDamage);
}
}
if (hit.rigidbody != null)
{
hit.rigidbody.AddForce (-hit.normal * hitForce);
}
}
else
{
laserLine.SetPosition (1, gunEnd.position + (fpsCam.transform.forward * weaponRange));
}
}
I fixed it - there was some weird problem with another variable that was being called from another script.
The code works fine now.

How to show a tracking line from where the model is placed in Augmented Reality?

I am looking to show a line in my app from where the model is placed so that the user knows position where the model is kept in real world. When user changes device camera away from model the line gets turned on to show where the model is. Similarly it turns off when model is detected. I have attached images to show from a similar app white dotted lines show the path. Notice how the lines disappear when the model is detected.
LineRenderer lins;
public GameObject Lineprefab;
private GameObject newline;
public Transform startpoint;
public Renderer m_rend1;
bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
if (hitResults.Count > 0 && check==true)
{
foreach (var hitResult in hitResults)
{
Debug.Log ("Got hit!");
//obj.Hideplane();
Genplanes.SetActive(false);
if (Select == 0) {
Debug.Log("hit-zero!");
Instantiate(Instaobj[0], ForSelect);
check = false;
}
if (Select == 1) {
Debug.Log("hit-one!");
Instantiate(Instaobj[1], ForSelect);
check = false;
}
if (Select == 2) {
Debug.Log("hit-two!");
Instantiate(Instaobj[2], ForSelect);
check = false;
}
m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
obj.StopPlaneTracking();
}
}
return false;
}
private void Start()
{
spawngenerator();
newline.SetActive(false);
m_rend1 = GetComponent<MeshRenderer>();
}
void spawngenerator()
{
GameObject newline = Instantiate(Lineprefab);
lins = newline.GetComponent<LineRenderer>();
}
private void LateUpdate()
{
lins.SetPosition(0, startpoint.position);
lins.SetPosition(1, m_HitTransform.position);
if( m_rend1.isVisible==true)
{
Debug.Log("Render is Visible");
newline.SetActive(false);
}
else if( m_rend1.isVisible==false)
{
newline.SetActive(true);
Debug.Log("It is InVisible");
Debug.Log("Render is InVisible");
}
}
void Update () {
#if UNITY_EDITOR //we will only use this script on the editor side, though there is nothing that would prevent it from working on device
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
//we'll try to hit one of the plane collider gameobjects that were generated by the plugin
//effectively similar to calling HitTest with ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent
if (Physics.Raycast (ray, out hit, maxRayDistance, collisionLayer)) {
//we're going to get the position from the contact point
m_HitTransform.position = hit.point;
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
//and the rotation from the transform of the plane collider
m_HitTransform.rotation = hit.transform.rotation;
}
}
#else
if (Input.touchCount > 0 && m_HitTransform != null )
{
var touch = Input.GetTouch(0);
if ((touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved) && !EventSystem.current.IsPointerOverGameObject(touch.fingerId))
{
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
ARPoint point = new ARPoint {
x = screenPosition.x,
y = screenPosition.y
};
// prioritize reults types
ARHitTestResultType[] resultTypes = {
//ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingGeometry,
ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
// if you want to use infinite planes use this:
//ARHitTestResultType.ARHitTestResultTypeExistingPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedVerticalPlane,
//ARHitTestResultType.ARHitTestResultTypeFeaturePoint
};
foreach (ARHitTestResultType resultType in resultTypes)
{
if (HitTestWithResultType (point, resultType))
{
return;
}
}
}
}
#endif
}
.
First, I 'd start with checking if the model is within the bounding box of the camera https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
if the object is not visible (isVisible == false), create a line renderer from object position to wherever it should end.
The end point could be a camera child place just in front of it, so it looks like it starts from the user to the object.

Unity2D: Fixing my coin system

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.

Input.GetKeyDown not working

I'm trying to get an input from the "space" button, but it looks like it doesn't take the input when I click. Here's my code:
void OnTriggerEnter2D (Collider2D other)
{
if (other.gameObject.tag == "GreenKey") {
print ("Green Key taken");
Destroy (other.gameObject);
greenKey_canvas.enabled = true;
} else if (other.gameObject.tag == "RedKey") {
print ("Red Key taken");
Destroy (other.gameObject);
redKey_canvas.enabled = true;
} else if (other.gameObject.tag == "YellowKey") {
print ("Yellow Key taken");
Destroy (other.gameObject);
yellowKey_canvas.enabled = true;
} else if (other.gameObject.tag == "Gem") {
print ("Gem taken");
gems = gems + 5;
gemsText.text = gems.ToString ();
Destroy (other.gameObject);
} else if (other.gameObject.tag == "RedGem") {
print ("Gem taken");
gems++;
gemsText.text = gems.ToString ();
Destroy (other.gameObject);
} else if (other.gameObject.tag == "LiveTaker") {
lives--;
} else if (other.gameObject.tag == "RedDoor") {
if (redKey_canvas.enabled) {
if (Input.GetKeyDown(KeyCode.Space)) {
//OPEN DOOR
other.gameObject.GetComponent<SpriteRenderer>().sprite = enterDoor;
redKey_canvas.enabled = false;
}
}
} else if (other.gameObject.tag=="YellowDoor") {
if (yellowKey_canvas.enabled) {
//OPEN DOOR
}
} else if (other.gameObject.tag=="GreenDoor") {
if (greenKey_canvas.enabled) {
//OPEN DOOR
}
}
}
In the console, I get the "entered door with key" message, but when I press Space, nothing happens.
I've also tried to add an Axis to the Input Manager named "DoorEnter", but it doesn't work either...
The reason this dosent work, is that the OnCollisionEnter function only activates the frame that the collision first happens, and that the GetKeyDown only lauches the single frame the button gets pushed.
One quite ugly fix, would be to Replace GetKeyDown with GetKey, then already hold space when walking into the door.
A better solution would be to add a variable, for an if statement in the Update loop. Make it activate when the user enters, and deactivate when the user leaves collision area.
Then make an if statement like this:
if(inCollider && Input.GetKeyDown(KeyCode.Space)){
//Open door here
}
Also, can anyone format this correctly? (Am on phone)
EDIT: Collision means trigger! Sorry!