I build a brand new cards game every thing is work with out any errors ,
But wen i start to drag my object in this case is a card in to the drop zone my card is not visible for some reason , i am not sure but i thing they out of screen range or some thing like that i can not find the way to correct this , i try to debug but there is no error on it so i am not able to find the way to solve this.
This is my code for the draggable object
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;
public class Draggable : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
public Transform parentToReturnTo = null;
public Transform placeholderParent = null;
GameObject placeholder = null;
public void OnBeginDrag(PointerEventData eventData) {
Debug.Log ("OnBeginDrag");
placeholder = new GameObject();
placeholder.transform.SetParent( this.transform.parent );
LayoutElement le = placeholder.AddComponent<LayoutElement>();
le.preferredWidth = this.GetComponent<LayoutElement>().preferredWidth;
le.preferredHeight = this.GetComponent<LayoutElement>().preferredHeight;
le.flexibleWidth = 0;
le.flexibleHeight = 0;
placeholder.transform.SetSiblingIndex( this.transform.GetSiblingIndex() );
parentToReturnTo = this.transform.parent;
placeholderParent = parentToReturnTo;
this.transform.SetParent( this.transform.parent.parent );
GetComponent<CanvasGroup>().blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData) {
//Debug.Log ("OnDrag");
this.transform.position = eventData.position;
if(placeholder.transform.parent != placeholderParent)
placeholder.transform.SetParent(placeholderParent);
int newSiblingIndex = placeholderParent.childCount;
for(int i=0; i < placeholderParent.childCount; i++) {
if(this.transform.position.x < placeholderParent.GetChild(i).position.x) {
newSiblingIndex = i;
if(placeholder.transform.GetSiblingIndex() < newSiblingIndex)
newSiblingIndex--;
break;
}
}
placeholder.transform.SetSiblingIndex(newSiblingIndex);
}
public void OnEndDrag(PointerEventData eventData) {
Debug.Log ("OnEndDrag");
this.transform.SetParent( parentToReturnTo );
this.transform.SetSiblingIndex( placeholder.transform.GetSiblingIndex() );
GetComponent<CanvasGroup>().blocksRaycasts = true;
Destroy(placeholder);
}
}
Related
The script is attached to empty gameobject
At this line i'm using the mouse left button to fire a bullet one time.
If i'm using a break point it will shot one bullet once. but if i'm not using a break point it will shot two bullets in a row one after the other.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class Shooting : MonoBehaviour
{
public CinemachineVirtualCamera cmf;
[Header("Main")]
public Rigidbody bulletPrefab;
public float launchForce = 700f;
public bool automaticFire = false;
public float bulletDestructionTime;
public bool go = false;
[Space(5)]
[Header("Slow Down")]
public float maxDrag;
public float bulletSpeed;
public bool bulletsSlowDown = false;
public bool overAllSlowdown = false;
[Range(0, 1f)]
public float slowdownAll = 1f;
public List<Transform> firePoints = new List<Transform>();
public Animator anim;
private void Start()
{
if (anim != null)
{
anim.SetBool("Shooting", true);
}
}
public void Update()
{
if (overAllSlowdown == true)
{
Time.timeScale = slowdownAll;
}
if (firePoints.Count > 0))
{
for (int i = 0; i < firePoints.Count; i++)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
if (go)
{
LaunchProjectile(firePoints[i]);
go = false;
}
}
}
}
private void LaunchProjectile(Transform firePoint)
{
Rigidbody projectileInstance = Instantiate(
bulletPrefab,
firePoint.position,
firePoint.rotation);
projectileInstance.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
cmf.enabled = true;
cmf.Follow = projectileInstance.transform;
cmf.LookAt = projectileInstance.transform;
projectileInstance.AddForce(new Vector3(0, 0, 1) * launchForce);
if (bulletsSlowDown == true)
{
if (projectileInstance != null)
{
StartCoroutine(AddDrag(maxDrag, bulletSpeed, projectileInstance));
}
}
}
IEnumerator AddDrag(float maxDrag, float bulletSpeed, Rigidbody rb)
{
if (rb != null)
{
float current_drag = 0;
while (current_drag < maxDrag)
{
current_drag += Time.deltaTime * bulletSpeed;
rb.drag = current_drag;
yield return null;
}
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
rb.drag = 0;
}
}
}
This script is attached to my player with animator and i'm using this method to reference event i added to animation in the animator controller. when the event happens the variable bool flag go is set to true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowObject : MonoBehaviour
{
public Shooting shooting;
public void ThrowEvent()
{
shooting.go = true;
}
}
This is a screenshot of the animator controller.
I added a new state name Throwing with two transitions from and to the Grounded state.
The Grounded state is playing idle animation.
In the transition from the Grounded to the Throwing i added a condition name Shoot type trigger.
In the transition from the Throwing state to the Grounded there is no any conditions.
Afaik animator triggers are stackable!
So since you call this in a for loop it might happen that it adds multiple triggers at once but each transition only consumes one at a time!
What I ended up using in combination with triggers in an animator is this script
public class AnimatorTriggerResetter : StateMachineBehaviour
{
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach(var p in animator.parameters)
{
if (p.type == AnimatorControllerParameterType.Trigger)
{
animator.ResetTrigger(p.name);
}
}
}
}
attach this to no specific state at all but directly to the Basic layer of your AnimatorController itself => It is called for each and every state that is entered => resets all existing triggers.
In your specific case though, why not rather pull the general calls out of the loop and rather make it
if (firePoints.Count > 0 && go)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
for (int i = 0; i < firePoints.Count; i++)
{
LaunchProjectile(firePoints[i]);
}
go = false;
}
so I have like 5 game object in my scene but I only scale each of them separately. However when I try to do that all of them start scaling simultaneously. Also, I have a placement indicator that would be used to instantiate the object on the plane. It seems that instead of the object itself, the placement indicator is the one that gets scaled. How should I fix that?
I have tried deactivating the placement indicator but did not work.
Here is the code for instantiating objects:
I limited the obj number to 5.
I use this script instead of the usual "PlaceonPlane" script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.Experimental.XR;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;
public class ARTaptoPlaceObject : MonoBehaviour
{
private ARSessionOrigin arOrigin;
GameObject spawnedobj;
public GameObject placementIndicator;
private ARRaycastManager arRaycast;
public Pose placementPose;
public UIContoller sc;
public bool placementPoseIsValid = false;
private int count;
private string valu;
string prefabs;
void Start()
{
arOrigin = FindObjectOfType<ARSessionOrigin>();
arRaycast = FindObjectOfType<ARRaycastManager>();
count = 0;
}
// Update is called once per frame
void Update()
{
UpdatePlacementPose();
UpdatePlacementIndicator();
for (var i = 0; i < Input.touchCount; ++i)
{
if (Input.GetTouch(i).phase == TouchPhase.Began)
{
if (placementPoseIsValid && Input.GetTouch(i).tapCount == 2)
{
PlaceObject();
}
}
}
}
public void PlaceObject()
{
if (count <= 4)
{
if (sc.objectToPlace != null)
{
spawnedobj = Instantiate(sc.objectToPlace, placementPose.position, placementPose.rotation);
arOrigin.MakeContentAppearAt(spawnedobj.transform, spawnedobj.transform.position, spawnedobj.transform.rotation);
count++;
}
}
else
{
placementIndicator.SetActive(false);
}
}
private void UpdatePlacementIndicator()
{
if (placementPoseIsValid && count <= 4 && sc.active == false)
{
placementIndicator.SetActive(true);
placementIndicator.transform.SetPositionAndRotation(placementPose.position, placementPose.rotation);
}
else
{
placementIndicator.SetActive(false);
}
}
private void UpdatePlacementPose()
{
var screenCenter = Camera.current.ViewportToScreenPoint(new Vector3(0.5f, 0.5f));
var hits = new List<ARRaycastHit>();
arRaycast.Raycast(screenCenter, hits, UnityEngine.XR.ARSubsystems.TrackableType.Planes);
placementPoseIsValid = hits.Count > 0;
if (placementPoseIsValid)
{
placementPose = hits[0].pose;
var cameraForward = Camera.current.transform.forward;
var cameraBearing = new Vector3(cameraForward.x, 0, cameraForward.z).normalized;
placementPose.rotation = Quaternion.LookRotation(cameraBearing);
}
}
}
and here is the Scaler script that's attached to the button that would scale the object.
public class Scaler : MonoBehaviour
{
public UIContoller uc;
public ARTaptoPlaceObject ap;
private GameObject ReferenceToScale;
public void OnValueChange()
{
ReferenceToScale = (UnityEngine.GameObject)Resources.Load(uc.s_count, typeof(GameObject));
Vector3 t = ReferenceToScale.transform.localScale;
Vector3 scaleValue = t * 1.1f;
ReferenceToScale.transform.localScale = scaleValue;
}
Also the "objectToPlace" itself is in the "UI.Controller" script as I could not view it in the scene when it was in the "ARTaptoPlace" script
1.i have an issue when i start dragging object its clonning itself, i need that in panel zone(my object respawning in there) not in dropzone im trying to find solution for this can i make clone invisible? if i can how ?here is the code :
enter code here
public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public enum Slot { ileri, sağa, sola, fonksiyon };
public Slot typeofMove;
public Transform ParentreturnTo = null;
public Transform PlaceholderParent = null;
GameObject placeholder = null;
public GameObject ileriprefab;
public GameObject x;
public GameObject panel;
public void OnBeginDrag(PointerEventData eventData)
{
placeholder = new GameObject();
placeholder.transform.SetParent(this.transform.parent);
LayoutElement le = placeholder.AddComponent<LayoutElement>();
le.preferredWidth = this.GetComponent<LayoutElement>().preferredWidth;
le.preferredHeight = this.GetComponent<LayoutElement>().preferredHeight;
le.flexibleWidth = 0;
le.flexibleHeight = 0;
placeholder.transform.SetSiblingIndex(this.transform.GetSiblingIndex());
//sibling index kartı aldıgımız yeri döndürür.
Debug.Log("OnBeginDrag");
ParentreturnTo = this.transform.parent;
PlaceholderParent = ParentreturnTo;
this.transform.SetParent(this.transform.parent.parent);
if (this.transform.parent.position == GameObject.FindGameObjectWithTag("carddroparea").transform.position)
{
x = Instantiate(moveforwardprefab, moveforvardprefab.transform.position, Quaternion.identity);
x.transform.SetParent(PlaceholderParent.transform);
//im trying to saying here if the object "this" in drop zone dont instantiate it or make it invisible ??????? but its not working
}
GetComponent<CanvasGroup>().blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log("OnDrag");
this.transform.position = eventData.position;
if (placeholder.transform.parent != PlaceholderParent)
placeholder.transform.SetParent(PlaceholderParent);
int newSiblingIndex = PlaceholderParent.childCount;
for (int i = 0; i < PlaceholderParent.childCount; i++)
{
//**parentreturnto. getchild(i)**//
if (this.transform.position.x < PlaceholderParent.GetChild(i).position.x)
{
newSiblingIndex = i;
// placeholder.transform.SetSiblingIndex(i);
if (PlaceholderParent.transform.GetSiblingIndex() < newSiblingIndex)
newSiblingIndex--;
break;
}
}
placeholder.transform.SetSiblingIndex(newSiblingIndex);
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("OnEndDrag");
this.transform.SetParent(ParentreturnTo);
this.transform.SetSiblingIndex(placeholder.transform.GetSiblingIndex());
//Kartın alındıgı yere konulması için gerekli
GetComponent<CanvasGroup>().blocksRaycasts = true;
Destroy(placeholder);
if (this.transform.parent.position == GameObject.FindGameObjectWithTag("panel").transform.position)
{
Destroy(x);
Debug.Log("destroyed");
}
if (x.transform.parent.position == GameObject.FindGameObjectWithTag("carddroparea").transform.position)
{
Destroy(x);
Debug.Log("destroyed");
}
}
}
If you just want to make a GameObject invisible there are many ways to do it.
You can, for example:
yourGameObject.SetActive(false);
You can also deactivate your gameobject Renderer
yourGameObject.GetComponent<Renderer>().enabled = false;
how to adapt it to your code is up to you.
In the Hierarchy i have a Canvas and under it as childs i have a ui button and ui toggle. On the button i attached a script with a onclick event.
The idea is when i click the button depending on the toggle state false/true decide if to just create more gameobjects or destroy first all the old gameobjects and create new.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GenerateObjectsButton : MonoBehaviour
{
private InstantiateObjects instantiateobjects;
private bool toggleOnOf;
public Toggle toggle;
private void Start()
{
instantiateobjects = new InstantiateObjects();
toggle.onValueChanged.AddListener((value) =>
{
MyListener(value);
});
}
public void MyListener(bool value)
{
if (value)
{
//do the stuff when the toggle is on
toggleOnOf = true;
}
else
{
//do the stuff when the toggle is off
toggleOnOf = false;
}
}
public void OnButton()
{
if (toggleOnOf == false)
{
instantiateobjects.generateObjectOnTerrain();
}
else
{
instantiateobjects.DestroyObjects();
instantiateobjects.generateObjectOnTerrain();
}
}
}
The InstantiateObjects script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//[ExecuteInEditMode]
public class InstantiateObjects : MonoBehaviour
{
public GameObject prefab;
public Terrain terrain;
public float yOffset = 0.5f;
public int objectsToInstantiate;
public bool parent = true;
public bool randomScale = false;
public float setRandScaleXMin, setRandScaleXMax;
public float setTandScaleYMin, setTandScaleYMax;
public float setTandScaleZMin, setRandScaleZMax;
public bool generateNew;
private float terrainWidth;
private float terrainLength;
private float xTerrainPos;
private float zTerrainPos;
private int numberOfObjectsToCreate;
private GameObject objInstance;
private GameObject[] createdObjects;
private string objname;
public void Start()
{
//Get terrain size
terrainWidth = terrain.terrainData.size.x;
terrainLength = terrain.terrainData.size.z;
//Get terrain position
xTerrainPos = terrain.transform.position.x;
zTerrainPos = terrain.transform.position.z;
numberOfObjectsToCreate = objectsToInstantiate;
objname = prefab.name;
MyCustomEditor.TagsAndLayers.AddTag(objname);
generateNew = false;
generateObjectOnTerrain();
}
public void Update()
{
}
public void DestroyObjects()
{
if (createdObjects != null && createdObjects.Length > 0)
{
for (int i = 0; i < createdObjects.Length; i++)
{
DestroyImmediate(createdObjects[i]);
}
createdObjects = new GameObject[0];
}
}
public void generateObjectOnTerrain()
{
for (int i = 0; i < objectsToInstantiate; i++)
{
//Generate random x,z,y position on the terrain
float randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth);
float randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength);
float yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ));
//Generate random x,y,z scale on the terrain
float randScaleX = Random.Range(setRandScaleXMin, setRandScaleXMax);
float randScaleY = Random.Range(setTandScaleYMin, setTandScaleYMax);
float randScaleZ = Random.Range(setTandScaleYMax, setRandScaleZMax);
//Apply Offset if needed
yVal = yVal + yOffset;
//Generate the Prefab on the generated position
objInstance = Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity);
if (randomScale == true)
objInstance.transform.localScale = new Vector3(randScaleX, randScaleY, randScaleZ);
if (parent)
objInstance.transform.parent = this.transform;
objInstance.tag = objname;
}
createdObjects = GameObject.FindGameObjectsWithTag(objname);
}
}
The problems i'm facing now are:
In the InstantiateObjects when i click the button i'm getting null exception on the line:
createdObjects = GameObject.FindGameObjectsWithTag(objname);
createdObjects is null. Except the first time i'm running the game then it's not null but then each time when i click the button it's null.
Second problem is that i need to change the toggle state to false then click the button true click the button false click the button and only then it's getting the DestroyObjects method.
It might not be updating the array as the reference are the same. Reset the array to null at the start of each iteration and see if that works.
It may sound stupid but how can i reference a class from one script in child in another script in parent? I cant find anything on google. Note: There are couple errors in my script, that's not the point of the post.
//Public
//Private
private Rigidbody myRigidbody;
private Renderer myRenderer;
private Material tileDefaultMaterial;
private Material tileSelectedMaterial;
private Material tileSameGroupMaterial;
void Start () {
myRigidbody = GetComponent<Rigidbody> ();
myRenderer = GetComponent<Renderer> ();
tileDefaultMaterial = Resources.Load ("TileDefault", typeof(Material)) as Material;
tileSelectedMaterial = Resources.Load ("TileSelected", typeof(Material)) as Material;
tileSameGroupMaterial = Resources.Load ("TileSameGroup", typeof(Material)) as Material;
}
void Update () {
}
public class TileClass {
public int tileGroup = 0; //Indicates the Tile Group Number.
}
//Public
public GameObject[] allTiles; //Aray of all Tile GameObject.
public bool tileIsSelected = false; //If a Tile is Selected.
public int selectedTileGroup = 0; //Indicates the Selected Tile Group Number.
public int tileGroup = 0; //Indicates the Tile Group Number.
//Private
void Start () {
allTiles = new GameObject[transform.childCount];
for(int i = 0; i < transform.childCount; i++){
allTiles [i] = transform.GetChild (i).gameObject;
}
}
void Update () {
}
void OnMouseDown (){
RaycastHit hitInfo = new RaycastHit ();
bool hit = Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hitInfo);
if (hitInfo.transform.gameObject.tag == "Tile" && tileIsSelected == false) {
Debug.Log ("A Tile is Selected!");
tileIsSelected = true;
selectedTileGroup = ;
for(int i = 0; i < allTiles.Length; i++){
if (this.tileGroup == selectedTileGroup) {
allTiles [i].GetComponent<Renderer> ().material = tileSameGroupMaterial;
}
}
myRenderer.material = tileSelectedMaterial;
} else if (hitInfo.transform.gameObject.tag == "Tile" && tileIsSelected == true) {
Debug.Log ("Second Tile is Clicked! (Should Swap them!)");
myRenderer.material = tileDefaultMaterial;
}
}
There is a famous saying :
var allTiles = transform.GetComponentsInChildren<Tile>();
And as I told you yesterday, Add OnMouseDown() in Tile.cs and write myRenderer.material = tileDefaultMaterial; there. No need to write this in TileManager.cs. And NO need to use Raycast when using OnMouseDown().
I can't read your image code, so I'll make up my own class names for the example. I'll call the parent class TileManager and the child class Tile.
Say in Tile you want access to the array of tiles in the TileManager. If allTiles is declared as public, you'd do in Tile somewhere.
TileManager tileManager = transform.parent.GetComponent<TileManager>();
var allTiles = tileManager.allTiles;
Now the Tile child has a reference to the array. Was this what you were wanting?
how about base.Method?
That should do it