If list contains 4 of the given gameObjects - c#

I am trying to find how I can check if 4 of the given gameObjects are in a list.
So I have a list with gameObjects. Sometimes a gameObject gets out of the list, sometimes it gets in. I want to check if 4 of the same colors are in a list. In this case, "childTiles" is the list.
I tried it by doing this:
void Update()
{
foreach (GameObject tile in ChildTiles)
{
if (tile.gameObject.name == "tileGreen1" && tile.gameObject.name == "tileGreen2" && tile.gameObject.name == "tileGreen3" && tile.gameObject.name == "tileGreen4")
{
gameManager.finalGreenComplete = true;
Debug.Log (gameManager.finalGreenComplete);
}
}
}
This returns nothing. It does work if I check only 1 object. I also can't use ChildTiles.Contains() I think, because that is only possible with 1 gameObject if I'm right. So how do I check this with multiple gameObjects?
EDIT: A bit more information.
I have 4 different colors, each color has 4 tiles. Everytime the player clicks a button, the parent will rotate with the tiles as child. The childs are automatically child of a specific parent. The parents are the colliders (in the image below the white gameobjects are the colliders. They normally have no sprite renderer) which is behind the button that is pressed. The grey circles are the buttons.
The following script is attached to all the white colliders. The public void Squareclicked is attached to each button, but it is in the same script.
public List<GameObject> ChildTiles = new List<GameObject>();
public void SquareClicked()
{
if (parentPositions.canTurn == true && gameManager.turns > 0f)
{
gameManager.turns -= 1;
gameManager.turnsText.text = "Turns: " + gameManager.turns;
foreach(GameObject go in ParentPositions)
{
parentPositions = go.GetComponent<TileController> ();
parentPositions.canTurn = false;
}
foreach(GameObject tile in ChildTiles)
{
tile.transform.parent = gameObject.transform;
}
StartCoroutine(Rotate()); //this is where you do the rotation of the parent object.
if (gameManager.turns == 0f)
{
gameManager.turnsText.text = "No turns left";
}
}
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "Tile")
{
ChildTiles.Add (col.gameObject);
}
}
void OnTriggerExit2D(Collider2D col)
{
if (col.gameObject.tag == "Tile")
{
ChildTiles.Remove (col.gameObject);
}
}
Only the top-left, the top-right, the bottom-left and the bottom-right colliders are needed to check wheter is has four of the same color in it's list. I can either make a new script and attach that to those colliders (gameObjects) or I can make it so that the script only works for those.

The conditional will certainly never be true, since for a given tile, tile.gameObject.name has some given string value, and you are checking that every tile has each of the four names.
If I understand the question correctly, you want to check that within ChildTiles, there is some GameObject whose .gameObject.name is "tileGreen1", one that is "tileGreen2", and so on. If so, and if performance is not critical, you could check write the condition as follows:
var names = ChildTiles.Select(tile => tile.gameObject.name);
var shouldBeContained = new List<string> { "tileGreen1", "tileGreen2", "tileGreen3", "tileGreen4" };
bool condition = shouldBeContained.All(names.Contains);

In answer to your request to explain how to use enums for colors here:
I don't have unity, so I can't guarantee this will work, but anyway.
First, define your enum:
public enum Color
{
Black,
Green,
Blue,
Yellow,
///...
}
Next inherit a Tile object from GameObject (or whatever you want to use as a base class) and add a color property to it. Use these instead of GameObject as the Type of the ChildTiles.
public class Tile : GameObject
{
public Color Color { get; private set; }
public Tile(Color color) :base()
{
Color = color;
}
}
Then your Update function should look something like this:
void Update()
{
if (ChildTiles.Count(a => a.Color == Color.Green)>=4)
{
gameManager.finalGreenComplete = true;
Debug.Log(gameManager.finalGreenComplete);
}
}

Related

How do I find the location of an object through code

I'm trying to attach the camera to a character's xPos without grouping the camera to the player
The thing to be careful about is whether you mean you want the camera to be linked to the character's local x-position or if you want the camera to be linked to the character's world x-position. The two will vary based on the transforms of the character's parent GameObjects.
You can either tag the character and find it by doing a lookup in Start() or you can make the character reference a public GameObject targetCharacter in your camera script and set the reference manually in the editor.
Once you determine how you're going to do it:
public class CameraLocator : MonoBehaviour
{
public GameObject targetCharacter;
void Start()
{
if(targetCharacter == null)
{
targetCharacter = GameObject.FindGameObjectWithTag("YourCharacterTag");
if(targetCharacter == null)
{
Debug.LogError("targetCharacter is not set and could not be found!");
}
}
}
void Update()
{
if(targetCharacter != null)
{
var camPosition = this.gameObject.transform.position;
var targetPosition = targetCharacter.transform.position;
camPosition.x = targetPosition.x;
this.gameObject.transform.position = camPosition;
}
}

is there the way to change color on two different objects dependent on each other

I have two gameobjects in my game. I want to make one of them after ball collides with that in red color. And another in white color. Right now they both become red after collide with my projectile(ball). How to share this ?
This sounds like you are basically asking "How to handle a collision only on one of the colliding parties?"
Collisions happen in the physics update routine so basically after FixedUpdate.
See Execution Order of event Messages where you can see that FixedUpdate is always executed before all OnCollisionXY are handled.
So what you can do is store a reference in the first OnCollisionEnter to the other object and then ignore the second one if the object is the se you already collided with.
Then simply reset the field in the next FixedUpdate call.
Something like e.g.
public class CollisionDetection : MonoBehaviour
{
public Color color1 = Color.red;
public Color color2 = Color.white;
private GameObject ignoreCollisionWith
void OnCollisionEnter(Collision col)
{
if(col.gameObject == ignoreCollisionWith) return;
if(col.gameObject.TryGetComponent<CollisionDetection>(out var other))
{
// Set the color for both involved objects
GetComponent<Renderer>(). material.color = color1;
other.GetComponent<Renderer>(). material.color = color2;
// Tell the other object to do nothing for this collision with you
other.ignoreCollisionWith = gameObject;
}
}
void FixedUpdate()
{
ignoreCollisionWith = null;
}
}

Stacking effects & powerups in UI | Unity C#

How could I make it so, for example, if only one thing is on it will move to the first slot, I think you know what I mean... So how could I make this?1
I thought about using arrays but I don't understand how.
This is my code currently, rn it just shows and hides but doesnt move them so there just a gap.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class UI : MonoBehaviour
{
public Text myText;
public GameObject Player;
public GameObject SugarIcon;
public GameObject DashIcon;
public GameObject JumpIcon;
public GameObject ShieldIcon;
private string dashreadystring;
private string doublejumpstring;
private string triplejumpstring;
private string shieldbuffstring;
private int iconamount = 0;
void Start()
{
GameObject Player = GameObject.Find("Player");
}
void Update()
{
PlayerScript PlayerScript = Player.GetComponent<PlayerScript>();
bool dashready = PlayerScript.canDash;
float sugarbuff = PlayerScript.sugarbuffactive;
int airJumpCount = PlayerScript.airJumpCount;
int airJumpCountMax = PlayerScript.airJumpCountMax;
bool canDoubleJump = PlayerScript.canDoubleJump;
bool shieldon = PlayerScript.shieldon;
float score = Player.transform.position.x;
// If Dash is ready, show icon, if not, hide it.
if (dashready == true)
{
DashIcon.GetComponent<Renderer>().enabled = true;
}
else
{
DashIcon.GetComponent<Renderer>().enabled = false;
}
// If Sugarbuff is active, show icon, if not, hide it.
if (sugarbuff == 1.5)
{
SugarIcon.GetComponent<Renderer>().enabled = true;
}
else
{
SugarIcon.GetComponent<Renderer>().enabled = false;
}
// If can jump,
if ((airJumpCount < airJumpCountMax) | ((canDoubleJump) && (sugarbuff == 1.5f)))
{
JumpIcon.GetComponent<Renderer>().enabled = true;
}
else
{
JumpIcon.GetComponent<Renderer>().enabled = false;
}
if (shieldon)
{
ShieldIcon.GetComponent<Renderer>().enabled = true;
}
else
{
ShieldIcon.GetComponent<Renderer>().enabled = false;
}
}
}
How could I make this? Thanks.
If your icons are children of a parent container that uses a HorizontalLayoutGroup component, it will automatically line up your icons horizontally (use VerticalLayoutGroup or GridLayoutGroup to autoalign in different patterns).
Then, if you disable the gameObject of the icons, they will disappear. The HorizontalLayoutGroup will rearrange the remaining icons in the way I think you want. When you reenable the icon, it will be reinserted into the horizontal layout.
Notes:
You are currently disabling the Renderer Component on the gameObject. This does make the object invisible, but it still exists and takes up space. Instead, disable the gameObject for the icon itself (SugarIcon.enabled = false). Hopefully the Icon objects are just images, and have no scripts/logic on them, but if so, you'll need to decouple that.
It looks like you're using GetComponent() calls many times every frame. Don't do this -- GetComponent() calls have a pretty big overhead. Instead, call it once, when you initialize your manager, and then cache the result. This will save a ton of processing.
// Call GetComponent() and cache the reference one time (when you initialize the objects).
Renderer sugarIconRenderer = SugarIcon.GetComponent<Renderer>();
// Call the cached reference every frame when you need it.
sugarIconRenderer.enabled = false;

Unity 2D, Shooting with bow Instantiate problem

Hi everyone I have a little problem with my bow shooting script. I mean i want to shoot an arrow when play the one of last frames from my animation. I try to do it by setting an firePoint GameObject, put it by recording in my Animation Tab in desired frame. It's of course disabled but its enabled when animation plays and then its again disabled. So the problem is:
- When i hit button which match my Shooting input, the animation plays,
- My Instantiate appears and it produces multiple arrows,
- When its disabled it stops to produce arrows.
I want to produce only one arrow. Could anyone help?
CombatScript.cs:
/* private bool shootBow;
* public bool needReload = false;
* public float reloadTime = 1.5f;
* public float realoadCD;
*/
public void RangeAttack()
{
if (needReload == false && gameObject.GetComponent<PlayerControls>().grounded == true && Input.GetButtonDown("Ranged"))
{
animator.SetTrigger("shootBow");
attack1 = false; // Melle attacks sets to false in case of lag or smth.
attack2 = false;
attack3 = false;
needReload = true;
if (needReload == true)
{
reloadCD = reloadTime;
}
}
if (reloadCD > 0 && needReload == true)
{
reloadCD -= Time.deltaTime;
}
if (reloadCD <= 0)
{
reloadCD = 0;
needReload = false;
}
if (firePoint.gameObject.activeSelf == true)
{
Instantiate(Missile, new Vector3(firePoint.position.x + 1, firePoint.position.y), firePoint.rotation);
Debug.Log("It's a bird, a plane, no.. it's arrow.");
}
}
Arrow Controller.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArrowController : MonoBehaviour {
public float speed;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(speed, GetComponent<Rigidbody2D>().velocity.y);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
Destroy(collision.gameObject);
}
Debug.Log("Arrow Broke");
Debug.Log(gameObject.name);
//Destroy(gameObject);
}
public void OnCollisionEnter2D(Collision2D collision)
{
}
}
Example of my situation:
Example of true/false needReload statement:
in right Inspector you have my Player informations, in left (or bottom) Inspector you have Missile (Arrow) inspector
You can use Animation Events and for example a boolean that is your firerate.
And you Code can look something like this:
float LastShoot;
float FireRate = 10;
public void OnShoot()
{
if (LastShoot <= 0)
{
//Shoot your arrow
LastShoot = FireRate;
}
}
void Update()
{
LastShoot -= 0.5f;
}
But i don't know if this is the best solution to calculate a firerate. If someone knows a better one feel free and edit my awnser :)
Okey... couple of hours later (which I wasted...). The answer was ridiculously easy. For future "problems" like that... the thing was to create in my script function called "ProduceArrow()"and (additionaly to what i did) something like Animation Event it's in Animation Tab, when you create your animation timeline you just need to call it clicking right mouse button and then choose it and pick proper function.
Some feedback - gif
The way your code works right now, Instatiate will be called every frame. So one button click, which is probably longer than one frame, will trigger multiple arrows, so you need to set a condition for when you want Instantiate to be called. You already calculate a reload time, which is exactly what you need. You just need to include it in your if-statement like follows:
if (firePoint.gameObject.activeSelf == true && !needReload)
{
Instantiate(Missile, new Vector3(firePoint.position.x + 1, firePoint.position.y), firePoint.rotation);
Debug.Log("It's a bird, a plane, no.. it's arrow.");
}

OnMouseDown() called for only the foremost GameObject

(source: ibin.co)
I have a BoxCollider2D component and a script attached to the black and red boxes. Each script with some things to happen in a OnMouseDown() function. The problem is if I click on the part of the orange box that overlaps the black one, the OnMouseDown() of the black box will be called but I want only the orange box function to be called.
How do you achieve this?
I don't think OnMouseDown is a great approach here. You can use 2D RayCast to only get the top most collider. You are going to have to account for sorting layer and sorting order on your own with this approach.
The trick to checking a single point in 2D is to not give the raycast direction as shown below with:
Physics2D.Raycast(touchPostion, Vector2.zero);
Here is an example I threw together that doesn't account for using sorting layers, just sorting order.
using UnityEngine;
public class RayCastMultiple : MonoBehaviour
{
//Current active camera
public Camera MainCamera;
// Use this for initialization
void Start ()
{
if(MainCamera == null)
Debug.LogError("No MainCamera");
}
// Update is called once per frame
void FixedUpdate ()
{
if(Input.GetMouseButtonDown(0))
{
var mouseSelection = CheckForObjectUnderMouse();
if(mouseSelection == null)
Debug.Log("nothing selected by mouse");
else
Debug.Log(mouseSelection.gameObject);
}
}
private GameObject CheckForObjectUnderMouse()
{
Vector2 touchPostion = MainCamera.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D[] allCollidersAtTouchPosition = Physics2D.RaycastAll(touchPostion, Vector2.zero);
SpriteRenderer closest = null; //Cache closest sprite reneder so we can assess sorting order
foreach(RaycastHit2D hit in allCollidersAtTouchPosition)
{
if(closest == null) // if there is no closest assigned, this must be the closest
{
closest = hit.collider.gameObject.GetComponent<SpriteRenderer>();
continue;
}
var hitSprite = hit.collider.gameObject.GetComponent<SpriteRenderer>();
if(hitSprite == null)
continue; //If the object has no sprite go on to the next hitobject
if(hitSprite.sortingOrder > closest.sortingOrder)
closest = hitSprite;
}
return closest != null ? closest.gameObject : null;
}
}
This is pretty much just a duplicate of my answer here: Game Dev Question

Categories