I have a function that looks for a "Tile" on a certain position, adds that to a list and then returns that list to a different list. However, no list items are displayed in the inspector when the game runs, even tho when i use debugging or Debug.Log, it shows the list contains the correct "Tile".
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PieceController : MonoBehaviour
{
[Header("Location managing")]
public Tile currentTile;
public Vector3 currentTilePos;
[Header("Move making")]
public Piece pieceType;
public List<Tile> validTiles = new List<Tile>();
private TileSelector tileSelector;
// Start is called before the first frame update
void Start()
{
tileSelector = GameObject.Find("GameController").GetComponent<TileSelector>();
}
// Update is called once per frame
void Update()
{
currentTilePos = currentTile.GetComponent<Tile>().positionTop;
validTiles = CalculateValidTiles();
Debug.Log("Valid tiles: " + validTiles.ToString());
}
public List<Tile> CalculateValidTiles()
{
float tileLength = pieceType.tileLength;
List<Tile> tiles = new List<Tile>();
foreach (LegalMove move in pieceType.moves)
{
//Debug.Log("Calculating move: " + move.name);
Vector3 legalPosition;
Vector3 originPosition = transform.position;
legalPosition = new Vector3(originPosition.x + move.tilesPositiveX, originPosition.y, originPosition.z + move.tilesPositiveZ);
//Debug.Log("Legal position: " + legalPosition.ToString());
Ray ray = new Ray(legalPosition, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 1.5f))
{
Debug.Log("Hit: " + hit.collider.gameObject.name);
if (hit.collider.gameObject.tag == "piece" && !validTiles.Contains(hit.collider.gameObject.GetComponent<Tile>()))
{
tiles.Add(hit.collider.gameObject.GetComponent<Tile>());
//Debug.Log("Added tile: " + hit.collider.gameObject.GetComponent<Tile>().tile);
}
}
}
Debug.Log("Tiles calculated: " + tiles.ToString());
return tiles;
}
}
I can't figure out why it won't show the items in the inspector. I've tried updating my editor version to 2021.3.14f1, and adding items to the "validTiles" list directly, instead of using a return.
Related
I am working on a small Unity project and am relatively new. I am trying to have multiple objects be able to be selected by a click using raycasting. The objects are a prefab and have both circle collider2ds and rigidbody2ds. When There is one object on the field the code works fine. It detects that the object is there and "Selects" it. But when I try to run the same code with two objects it doesn't detect the colliders for either of the objects. I assume it is an issue with the editor and not the code but there is probably a better way of achieving what I want to have happen. Thanks for any help!
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CharacterMovment : MonoBehaviour
{
GameObject selected = null;
Characteristics characteristics;
public GameObject screenText;
private TMP_Text textComponent;
bool characterSelected = false;
private void Awake()
{
textComponent = screenText.GetComponent<TMP_Text>();
}
// Update is called once per frame
void Update()
{
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (Input.GetMouseButtonDown(0)){
Debug.Log(hit.collider.gameObject.tag);
if (hit.collider.gameObject.tag == "Character") {
characterSelected = true;
selected = hit.collider.gameObject;
characteristics = selected.GetComponent<Characteristics>();
Debug.Log("Adding character to selected. Character name: " + characteristics.name);
}else{
characterSelected = false;
}
}
if (characterSelected) {
textComponent.text = "Selected Character: " + characteristics.name;
}
}
}```
If you want to get all objects in the mouse position , you can use RaycastAll.
Please clarify if I misunderstood.
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class CharacterMovment : MonoBehaviour
{
GameObject selected = null;
List <Characteristics> characteristics;
public GameObject screenText;
private TMP_Text textComponent;
bool characterSelected = false;
private void Awake()
{
textComponent = screenText.GetComponent<TMP_Text>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D[] hit = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
for (int i = 0; i < hit.Length; i++)
{
Debug.Log(hit[i].collider.gameObject.tag);
if (hit[i].collider.gameObject.tag == "Character")
{
characterSelected = true;
selected = hit[i].collider.gameObject;
characteristics.Add(selected.GetComponent<Characteristics>());
Debug.Log("Adding character to selected. Character name: " + characteristics.name);
}
else
{
characterSelected = false;
}
if (characterSelected)
{
textComponent.text += "Selected Character: " + characteristics[i].name;
}
}
}
}
}
When you click script runs on every character. So basically you need only one instance of the MonoBehaviour for registering clicks. Right now you have CharacterMovement script on each character and it runs on each character multiple times when you click. Try to move logic to separate single script.
This is my frist time posting here.
I'm using the Mapbox Unity SDK in order to aid the creation of an app I'm developing. At the base of it, we have a 2D top-down map in which we can drag and drop UI images into the map to turn them into geolocalised POIs. I'm using a modified SpawnOnMap script:
using UnityEngine;
using Mapbox.Utils;
using Mapbox.Unity.Map;
using Mapbox.Unity.MeshGeneration.Factories;
using Mapbox.Unity.Utilities;
using System.Collections.Generic;
public class SpawnOnMap : MonoBehaviour
{
[SerializeField]
AbstractMap _map;
[SerializeField]
[Geocode]
string[] _locationStrings;
List<Vector2d> _locations;
public float _spawnScale = 100f;
public GameObject _markerPrefab;
List<GameObject> _spawnedObjects;
void Start()
{
_locations = new List<Vector2d>();
_spawnedObjects = new List<GameObject>();
for (int i = 0; i < _locationStrings.Length; i++)
{
var locationString = _locationStrings[i];
_locations[i] = Conversions.StringToLatLon(locationString);
var instance = Instantiate(_markerPrefab);
instance.transform.localPosition = _map.GeoToWorldPosition(_locations[i], true);
instance.transform.localScale = new Vector3(_spawnScale, _spawnScale, _spawnScale);
_spawnedObjects.Add(instance);
}
}
public void IncreaseMarkers(GameObject inst)
{
_spawnedObjects.Add(inst);
}
public void IncreaseLocations(Vector2d loc)
{
_locations.Add(loc);
}
private void Update()
{
int count = _spawnedObjects.Count;
for (int i = 0; i < count; i++)
{
var spawnedObject = _spawnedObjects[i];
var location = _locations[i];
spawnedObject.transform.localPosition = _map.GeoToWorldPosition(location, true);
spawnedObject.transform.localScale = new Vector3(_spawnScale, _spawnScale, _spawnScale);
}
}
}
and a 'AddPOI' script which is attached to the image:
using UnityEngine;
using Mapbox.Utils;
using Mapbox.Unity.Utilities;
using Mapbox.Unity.Map;
using Mapbox.Examples;
public class AddPOI : MonoBehaviour
{
float clicktime;
Ray ray;
RaycastHit hit;
AbstractMap _map;
[SerializeField]
Transform clickPoint;
[SerializeField]
LayerMask layerMask;
[SerializeField] private SpawnOnMap spawner;
// Start is called before the first frame update
void Start()
{
_map = FindObjectOfType<AbstractMap>();
}
void Update()
{
bool click = false;
if (Input.GetMouseButtonDown(0))
{
clicktime = Time.time;
}
if (Input.GetMouseButtonUp(0))
{
if (Time.time - clicktime < 0.15f)
{
//click = true;
}
}
if (click)
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
print(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
{
clickPoint.position = hit.point;
var clickLocation = new Vector2d();
clickLocation = clickPoint.GetGeoPosition(_map.CenterMercator, _map.WorldRelativeScale);
print(clickLocation);
AddPOIOnLocation(clickLocation);
}
}
}
public Vector2d GetLocation()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
{
clickPoint.position = hit.point;
Vector2d clickLocation = clickPoint.GetGeoPosition(_map.CenterMercator, _map.WorldRelativeScale);
print(clickLocation.x + ", " + clickLocation.y);
return clickLocation;
}
else return Vector2d.zero;
}
public void AddPOIOnLocation(Vector2d location)
{
var instance = Instantiate(spawner._markerPrefab);
instance.transform.localPosition = _map.GeoToWorldPosition(location, true);
instance.transform.localScale = new Vector3(spawner._spawnScale, spawner._spawnScale, spawner._spawnScale);
spawner.IncreaseMarkers(instance);
spawner.IncreaseLocations(location);
}
}
I'm also going from the ZoomableMap example, thus using their pan and zoom script.
Problem is, my script works fine at an angled rotation (the same one present in nearly all other examples, X 35.7 and Y 12.513), but, as soon as I change those angles, the map or camera position, things go haywire. I managed to make it work at a single zoom level and a modified camera position, but otherwise the positions registered in the raycast do not reflect the mouse pointer on the map. The further I go from the original angles, the worse it gets. At one point I just get an insane number that even gets unity to complain about floating point innacuracies. What gives?
Any help is greatly appreciated.
I am trying to make a movement where sprites go down in a row inside a panel, and then they stop when reaching the bottom boundry of the panel. Problem is after i set the position of the objects where it has to stop moving, its taking me position.y = 0 as if it was the middle of the screen. How do i set it to stop moving, when reaching the bottom of its parent object (the panel). Thank you.
here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Transform_test : MonoBehaviour
{
[SerializeField]
SpriteRenderer[] Reels;
[SerializeField]
Transform[] ReelsTransform;
int speed;
bool drop;
[SerializeField]
GameObject Panel;
void Start()
{
Debug.Log(transform);
//transform.position = new Vector3 (10,0,0);
speed = 1;
drop = false;
}
// Update is called once per frame
void Update()
{
// test();
if (drop == false)
{
foreach (Transform Reels in ReelsTransform)//This Targets All Children Objects Of The Main Parent Object
{
Debug.Log("pos " + Reels.transform.position.y);
for (int i = 0;i<5;i++)
{
//Direction And Speed Of Movement
new WaitForSeconds(Random.Range(1, 3));
Reels.transform.Translate(Vector3.down * Time.smoothDeltaTime * speed, Space.World);
if (Reels.transform.position.y <= 0 )
{
Reels.transform.position = new Vector3(Reels.transform.position.x, Reels.transform.position.y + 58, Reels.transform.position.z);
}
}
}
}
}
}
Ok this is how i solved it. I created an empty sprite on the place where i want the reel to stop, then i set the if to match that position with the position of the first sprite in the reel. If the positions match. Turn moveto to true and stop the movement
public class transform2 : MonoBehaviour
{
public float speed;
public SpriteRenderer sprite1;
public SpriteRenderer[] sprites;
public SpriteRenderer cell1;
public GameObject Panel;
bool moveto;
void move()
{
if (moveto == false)
{
foreach (SpriteRenderer sprites in sprites)
{
sprites.transform.Translate(Vector3.down * Time.smoothDeltaTime * speed, Space.World);
if (sprite1.transform.position.y <= cell1.transform.position.y)
{
moveto = true;
sprite1.transform.position = cell1.transform.position;
}
Debug.Log("MOVE");
}
}
}
// Start is called before the first frame update
void Start()
{
speed = 20;
}
// Update is called once per frame
void Update()
{
move();
}
}
in the problem of today is about unity
well i 'm always in the beginnings so i just took a full asset from the store
so while applying some changes i just get a crazy error saying that no cameras rendering
in the start of the project everything work smoothly
this is the script linked to the camera
this script just trying to make a map generator not completed yet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGen : MonoBehaviour
{
public GameObject[] flats=new GameObject[4];
public GameObject flat;
public int x;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = flat.transform.position;
x = pos.x;
Debug.Log("position :: "+ x );
if(x%26 == 0)
{
Destroy(flats[0]);
for(int i = 0; i < 3; i++)
{
flats[i] = flats[i + 1];
}
flats[3] = flat;
Debug.Log("position "+x);
}
}
}
all works great but when trying this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGen : MonoBehaviour
{
public GameObject[] flats=new GameObject[4];
public GameObject flat;
public int x;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = flat.transform.position ;
x=(int) pos.x;
Debug.Log("position :: "+ x );
if(x%26 == 0)
{
Destroy(flats[0]);
for(int i = 0; i < 3; i++)
{
flats[i] = flats[i + 1];
}
flats[3] = flat;
Debug.Log("position "+x);
}
}
}
it just give me the error after running the game just like if the camera was destroyed and as you can see it is just this expression that was changed
x=pos.x;
to
x=(int) pos.x;
by the way the variable flat is referring to the main camera
you end up assigning your camera to the array and end up moving it up to [0] position and destroying it
flats[3] = flat;
flats[i] = flats[i + 1];
Destroy(flats[0]);
I spawn objects that have laser beam property. When I click on one of them(specific object), I want it to only show its laser beam not the others.
How can I prevent it? I have a static GameObject variable (touch_detect.clickedObject) by which I can determine which object is clicked.
using UnityEngine;
using System.Collections;
public class Laser : MonoBehaviour
{
private LineRenderer lr;
private bool clicked = false;
RaycastHit rh;
// Use this for initialization
void Start()
{
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
if (rh.collider.gameObject.name == touch_detect.clickedObject.name)
{
Debug.Log(rh.collider.gameObject.name + " clicked.");
Debug.Log("static object name" + touch_detect.clickedObject.name + " clicked.");
clicked = true;
lr.enabled = true;
}
}
}
if (Input.GetMouseButtonUp(0))
{
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
if (rh.collider.gameObject.name == touch_detect.clickedObject.name)
{
Debug.Log(rh.collider.gameObject.name + " clicked.");
Debug.Log("static object name" + touch_detect.clickedObject.name + " clicked.");
clicked = false;
lr.enabled = false;
}
}
}
if (clicked)
{
lr.SetPosition(0, transform.position + new Vector3(0, 0, 0));
RaycastHit hit;
if (Physics.Raycast(transform.position + new Vector3(0, 0, 0), -transform.up, out hit))
{
if (hit.collider)
{
lr.SetPosition(1, hit.point);
}
}
else lr.SetPosition(1, -transform.up * 5000);
}
}
}
The issue is that since this script is attached to both of your gameobjects, there are two rays being cast at the mouse position (one from each script). Because you are just looking to see that the raycollider matches the static object, this statement is true for both scripts no matter which you click on:
if (rh.collider.gameObject.name == touch_detect.clickedObject.name) // always true
To get an immediate fix, you should change the above statement to something like this to check that the ray is intersecting the same gameobject that the script is attached to:
if (rh.collider.gameObject.name == gameObject.name)
This really is not the best method though since you are still casting two rays and therefore doing all the logic twice (or more times if you spawn more cubes).
A better method would be to have one master gameobject that casts the ray. When this ray intersects a cube, you would then activate a method inside that cubes script to show the laser. So for example:
on the master object you would have:
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
// add a tag to all objects with the laser script
if (rh.collider.gameObject.tag == "hasLaser") //verify object has laser script via tag
rh.collider.GetComponent<laser>().activateLaser(); // call public method in collider script
}
and then the cube would have the laser script with a public method:
public void activateLaser()
{
lr.enabled = true;
}