Im using a Grab Object script that grabs a object that is inside the trigger collider.
But when i try to grab a object with more than 1 object inside the collider it grabs all the objects at the same time (example image with two bricks grabbed at the same time).
I need a rule to grab only the nearest object.
two brick grabbed
im using this script to grab the objects.
Found it on a YT tutorial and tweaked it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUp : MonoBehaviour {
public float throwForce = 100;
public bool canHold = true;
public GameObject item;
public GameObject tempParent;
public GameObject poof;
public GameObject vanish;
public GameObject poofParent;
public Transform guide;
public bool isHolding = false;
float distance;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
distance = Vector3.Distance(item.transform.position, guide.transform.position);
if (Input.GetKeyDown("space"))
if (distance <= 6f)
{
isHolding = true;
item.transform.position = tempParent.transform.position;
//Poof
GameObject myPoof = Instantiate(poof, Vector3.zero, Quaternion.identity) as GameObject;
myPoof.transform.parent = poofParent.transform;
myPoof.transform.position = poofParent.transform.position;
Destroy (myPoof, 2);
//Particles
GameObject myVanish = Instantiate(vanish, Vector3.zero, Quaternion.identity) as GameObject;
myVanish.transform.parent = tempParent.transform;
myVanish.transform.position = tempParent.transform.position;
Destroy (myVanish, 4);
}
if (isHolding==true)
{
item.GetComponent<Rigidbody>().useGravity = false;
item.GetComponent<Rigidbody>().detectCollisions = true;
item.GetComponent<Rigidbody>().isKinematic = false;
item.transform.parent = tempParent.transform;
item.transform.position = tempParent.transform.position;
if (Input.GetKeyUp("space"))
{
Debug.Log("Trying to throw");
item.GetComponent<Rigidbody>().AddForce(guide.transform.forward * throwForce);
isHolding = false;
}
}
else
{
item.GetComponent<Rigidbody>().useGravity = true;
item.GetComponent<Rigidbody>().isKinematic = false;
item.transform.parent = null;
}
}
}
There is a sphere cast implemented in Unity's physics system, however it exists for a different purpose. Instead you're looking for Physics.OverlapSphere
Assuming that your guide object should be the center of the sphere you can determine the closest object (closestSelectedObject) in a specified selection radius.
float radiusOfSphere;
float smallesDistance;
Transform closestSelectedObject;
/***/
void Update(){
if(Input.GetKeyDown("space")){
Collider[] hitColliders = Physics.OverlapSphere(guide.transform.position, radiusOfSphere);
if(hitColliders.length > 0){
smallesDistance = radiusOfSphere;
foreach(Collider obj in hitColliders){
float tempDistance = Vector3.Distance(obj.transform.position, guide.transform.position);
if(tempDistance <= smallesDistance){
smallesDistance = tempDistance;
closestSelectedObject = obj;
}
}
/*other stuff that your code does*/
}
}
}
my final functional (Update) code here
Cant make it without your help #derHugo, thank you!
void Update () {
Collider[] hitColliders = Physics.OverlapSphere(guide.transform.position, radiusOfSphere);
var closestSelectedObject = hitColliders.OrderBy(obj => (obj.transform.position - guide.transform.position). sqrMagnitude).FirstOrDefault();
GameObject grabbed = GameObject.Find("grabbedObject");
if (grabbed != null)
{
Debug.Log("existe");
if (Input.GetKeyDown(KeyCode.Space) && !spaceDisabled) {
spaceDisabled = true;
}
}
else
{
if (Input.GetKeyDown("space"))
{
// targetObject does not exist in the scene
Debug.Log("NAOexiste");
if (closestSelectedObject.tag.Contains("CanPickup"))
{
closestSelectedObject.transform.position = tempParent.transform.position;
closestSelectedObject.transform.parent = tempParent.transform;
closestSelectedObject.GetComponent<Rigidbody>().detectCollisions = false;
closestSelectedObject.GetComponent<Rigidbody>().isKinematic = true;
closestSelectedObject.GetComponent<Rigidbody>().useGravity = true;
originalName = closestSelectedObject.name;
closestSelectedObject.name = "grabbedObject";
//Poof
GameObject myPoof = Instantiate(poof, Vector3.zero, Quaternion.identity) as GameObject;
myPoof.transform.parent = poofParent.transform;
myPoof.transform.position = poofParent.transform.position;
Destroy (myPoof, 2);
//Particles
GameObject myVanish = Instantiate(vanish, Vector3.zero, Quaternion.identity) as GameObject;
myVanish.transform.parent = tempParent.transform;
myVanish.transform.position = tempParent.transform.position;
Destroy (myVanish, 4);
}
}
}
if (Input.GetKeyDown(KeyCode.Q))
{
Debug.Log("Q key was pressed.");
grabbed.transform.parent = null;
grabbed.GetComponent<Rigidbody>().detectCollisions = true;
grabbed.GetComponent<Rigidbody>().isKinematic = false;
grabbed.GetComponent<Rigidbody>().useGravity = true;
grabbed.GetComponent<Rigidbody>().AddForce(guide.transform.forward * throwForce);
Input.ResetInputAxes();
grabbed.name = originalName;
}
}
Related
I've tried a lot of different things. Assigning the array elements just in the editor. Assigning the elements on boot using the Await(). Changing what script calls the functions. What GameObject has the attached script. How the Vector2 is called. How the array is initialized. I can't figure out what I'm missing.
GameRules Script
using System.Collections.Generic;
using UnityEngine;
public class GameRules : MonoBehaviour
{
public GameObject[] rightSwitchSpawns = new GameObject[7];
public GameObject[] leftSwitchSpawns = new GameObject[7];
public GameObject rightSwitchPrefab;
public GameObject leftSwitchPrefab;
void Awake(){
rightSwitchSpawns = GameObject.FindGameObjectsWithTag("RightSpawns");
leftSwitchSpawns = GameObject.FindGameObjectsWithTag("LeftSpawns");
}
// Start is called before the first frame update
void Start()
{
RandomLeft();
RandomRight();
}
public void RandomLeft()
{ Debug.Log("This Left array length is " + leftSwitchSpawns.Length);
int leftRandom1 = Random.Range(0, leftSwitchSpawns.Length -1);
Debug.Log("left 1 index is " + leftRandom1);
Vector2 leftOne = new Vector2(leftSwitchSpawns[leftRandom1].transform.position.x,leftSwitchSpawns[leftRandom1].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftOne.x,leftOne.y), Quaternion.identity);
int leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom2 == leftRandom1)
{
leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftTwo = new Vector2(leftSwitchSpawns[leftRandom2].transform.position.x,leftSwitchSpawns[leftRandom2].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftTwo.x,leftTwo.y), Quaternion.identity);
Debug.Log("Left 2 index is: " + leftRandom2);
int leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom3 == leftRandom1 || leftRandom3 == leftRandom2)
{
leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftThree = new Vector2(leftSwitchSpawns[leftRandom3].transform.position.x,leftSwitchSpawns[leftRandom3].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftThree.x,leftThree.y), Quaternion.identity);
Debug.Log("Left 3 index is: " + leftRandom3);
}
public void RandomRight()
{
int rightRandom1 = Random.Range(0, rightSwitchSpawns.Length -1);
Debug.Log("This Right array length is " + rightSwitchSpawns.Length);
Vector2 rightOne = rightSwitchSpawns[rightRandom1].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightOne.x,rightOne.y), Quaternion.identity);
Debug.Log("Right 1 index is: " + rightRandom1);
int rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom2 == rightRandom1)
{
rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightTwo = rightSwitchSpawns[rightRandom2].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightTwo.x,rightTwo.y), Quaternion.identity);
Debug.Log("Right 2 index is: " + rightRandom2);
int rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom3 == rightRandom1 || rightRandom3 == rightRandom2)
{
rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightThree = rightSwitchSpawns[rightRandom3].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightThree.x,rightThree.y), Quaternion.identity);
Debug.Log("Right 3 index is: " + rightRandom3);
}
public void DestroyRightSwitches(){
Debug.Log("Right Switches Destroyed");
Destroy(rightSwitchPrefab);
}
public void DestroyLeftSwitches(){
Debug.Log("Left Switches Destroyed");
Destroy(leftSwitchPrefab);
}
}
PlayerMovement Script
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : GameRules
{
private float speed = 5f;
private float jump = 5f;
private Rigidbody2D rb;
private bool isPlaying = false;
private Transform trans;
// Start is called before the first frame update
void Awake()
{
trans = gameObject.GetComponent<Transform>();
rb = gameObject.GetComponent<Rigidbody2D>();
rb.simulated = false;
}
// Update is called once per frame
void Update()
{
if(Input.GetMouseButtonDown(0)){
if(isPlaying == false){
isPlaying = true;
rb.simulated = true;
rb.velocity = new Vector2(speed,0f);
}
else{
rb.velocity = new Vector2(speed,jump);
}
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Wall")
{
OnDeath();
}
if(collision.gameObject.tag == "RightSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyRightSwitches();
RandomRight();
}
if(collision.gameObject.tag == "LeftSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyLeftSwitches();
RandomLeft();
}
}
void OnDeath(){
isPlaying = false;
rb.simulated = false;
trans.position = new Vector2(0,0);
DestroyLeftSwitches();
DestroyRightSwitches();
RandomLeft();
RandomRight();
}
}
The specific error is
IndexOutOfRangeException: Index was outside the bounds of the array.
GameRules.RandomLeft () (at Assets/Scripts/GameRules.cs:28)
GameRules.Start () (at Assets/Scripts/GameRules.cs:20)
But if you look at the debug statements. At initial runtime the array is full with a length of 7, Gives you the indexes of each point. and then it runs again for some reason with a length and index of 0. Then the error shows up.
The errors I Get in picture form
Your arrays are declared as public. In Unity3d's MonoBehaviour it means that these fields are serialized. If you have this script attached to the game object on the scene or to some prefab that is instantiated after, serialized values will be taken from this game object (you can see it in the inspector). It means that if there will be empty arrays in the serialized object, the length of your arrays will be 0 at runtime.
The issue is that I have the Playermovement script deriving from my GameRules script so in the hierarchy the player movement script also has empty arrays attached to the game object.
I followed a tutorial on Youtube and it was from a man named Dani. I also followed another one from someone called Dave / GameDevelopment on how to pick up objects in Unity 3D. I have ran into a problem where if I pick up a weapon that was on the ground by default it does not work. My gun floats in the air. I believe the main reason for this (don't quote me on this) is that the Gun is some how not becoming a child of the camera, which is what supposed to happen. Please fix and thanks.
This is my pick up script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpScript : MonoBehaviour
{
public GrappleGun gunScript;
public Rigidbody rb;
public BoxCollider coll;
public Transform player, gunContainer, fpsCam;
public float pickUpRange;
public float dropForwardForce, dropUpwardForce;
public bool equipped;
public static bool slotFull;
private void Start()
{
if(!equipped)
{
gunScript.enabled = false;
rb.isKinematic = false;
coll.isTrigger = false;
}
if (equipped)
{
gunScript.enabled = true;
rb.isKinematic = true;
coll.isTrigger = true;
slotFull = true;
}
}
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
}
private void PickUp()
{
equipped = true;
slotFull = true;
transform.SetParent(gunContainer);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.Euler(Vector3.zero);
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
private void Drop()
{
equipped = false;
slotFull = false;
transform.SetParent(null);
//Enable rb and km and coll = trigger
rb.isKinematic = false;
coll.isTrigger = false;
//GunCarries momentum of player
rb.velocity = player.GetComponent<Rigidbody>().velocity;
//AddForce
rb.AddForce(fpsCam.forward * dropForwardForce, ForceMode.Impulse);
rb.AddForce(fpsCam.up * dropUpwardForce, ForceMode.Impulse);
//Enable Script
gunScript.enabled = false;
}
}
This is grapple hook script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrappleGun : MonoBehaviour
{
private LineRenderer lr;
private Vector3 grapplePoint;
public LayerMask whatIsGrappable;
public Transform gunTip, camera, player;
private float maxDistance = 50f;
private SpringJoint joint;
void Awake()
{
lr = GetComponent<LineRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartGrapple();
}
if (Input.GetMouseButtonUp(0))
{
StopGrapple();
}
}
void LateUpdate()
{
DrawRope();
}
void StartGrapple()
{
RaycastHit hit;
if (Physics.Raycast(camera.position, camera.forward, out hit, maxDistance, whatIsGrappable))
{
grapplePoint = hit.point;
joint = player.gameObject.AddComponent<SpringJoint>();
joint.autoConfigureConnectedAnchor = false;
joint.connectedAnchor = grapplePoint;
float distanceFromPoint = Vector3.Distance(player.position, grapplePoint);
//the distance
joint.maxDistance = distanceFromPoint * 0.8f;
joint.minDistance = distanceFromPoint * 0.25f;
joint.spring = 5f;
joint.damper = 0;
joint.massScale = 1f;
lr.positionCount = 2;
}
}
void DrawRope()
{
//if not grappling
if (!joint) return;
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, grapplePoint);
}
void StopGrapple()
{
lr.positionCount = 0;
Destroy(joint);
}
public bool IsGrappling()
{
return joint != null;
}
public Vector3 GetGrapplePoint()
{
return grapplePoint;
}
}
I think a better way for your situation would be to create an empty game object where you want the grappling gun to be held when it's picked up, and the empty game object parented to the camera from the scene. Then from the script, you can write these lines of code.
To reference the empty game object:
public transform gunHoldPosition;
And you can attach that from the scene view in Unity.
Then to make the gun snap to the position when it's held:
private void PickUp()
{
equipped = true;
slotFull = true;
transform.localPosition = Vector3.zero;
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
Now In the Update function, you have to write a little more:
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
if (equipeed){
/* If this script is on the gun itself, then you just have to do transform.position, but if it's on some other object then you have to reference the gun that's being picked with the variable of 'public gameObject gun;' up and say gun.transform.position*/
transform.position = gunHoldPosition.position;
}
}
I'm not exactly sure why you have to do this in the Update function, but once I made a pickup script and the same thing happened to me, so I had to put the transform.postition in the Update Function. Hopefully this works for you if it doesn't reply to me and I will try something else.
Also sorry that I am late to answer my question even though I fixed it really fast. I was making the object with the script, aka a child of the model without actually making the model a child of thing.
i have my zombies wandering, chasing me on LOS & FOV but when they reach me ( Camera Rig Vive VR ), only one attack me (not eveytime but he try). I would like to make them all to attack me once they are close to me ( the best would be they make a circle around me ).
If i try to change distance or use a trigger collider to pass a boolean to true instead of calulate the remaining distance (in the attack coroutine), i have stack overflow error. I dont understand why. If Someone can explane me, it would be very nice.
Here is code for AI_Enemy :
using UnityEngine;
using System.Collections;
using UltimateSpawner;
using System.Collections.Generic;
public class AI_Enemy : MonoBehaviour
{
public enum ENEMY_STATE {PATROL, CHASE, ATTACK, DEAD};
public ENEMY_STATE CurrentState
{
get{return currentstate;}
set
{
//Update current state
currentstate = value;
//Stop all running coroutines
StopAllCoroutines();
switch(currentstate)
{
case ENEMY_STATE.PATROL:
StartCoroutine(AIPatrol());
break;
case ENEMY_STATE.CHASE:
StartCoroutine(AIChase());
break;
case ENEMY_STATE.ATTACK:
StartCoroutine(AIAttack());
break;
case ENEMY_STATE.DEAD:
break;
}
}
}
[SerializeField]
private ENEMY_STATE currentstate = ENEMY_STATE.PATROL;
[SerializeField] Animator ThisAnimator;
[SerializeField] AudioSource ThisAudioSource;
//Reference to patrol destination
[SerializeField] GameObject[] PatrolDestinations;
private AudioClip sound;
public AudioClip[] attacksSounds;
//Reference to line of sight component
private LineSight ThisLineSight = null;
//Reference to nav mesh agent
private UnityEngine.AI.NavMeshAgent ThisAgent;
//Reference to transform
private Transform ThisTransform = null;
//Reference to player health
public PlayerHealth PlayerHealth = null;
//Reference to player transform
private Transform PlayerTransform = null;
public Transform PatrolDestination;
[SerializeField] float timeBetweenAttacks = 1.4f;
private WaitForSeconds attackDelay;
//Damage amount per second
public float MaxDamage = 2.8f;
public static bool inRange = false;
void Awake()
{
ThisLineSight = GetComponent<LineSight>();
ThisAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
ThisTransform = GetComponent<Transform>();
ThisAnimator = GetComponent<Animator>();
ThisAudioSource = GetComponent<AudioSource>();
attackDelay = new WaitForSeconds(timeBetweenAttacks);
}
void Start()
{
//Configure starting state
ThisAgent.enabled = true;
PlayerHealth = GameManager.Instance.Player;
PlayerTransform = GameManager.Instance.EnemyTarget;
PatrolDestinations = GameObject.FindGameObjectsWithTag("Waypoint");
StartCoroutine(StartZombie());
}
public IEnumerator AIPatrol()
{
ThisAnimator.SetBool("Attack", false);
ThisAnimator.SetBool("Chase", false);
ThisAnimator.SetBool("Walk", true);
PatrolDestination = PatrolDestinations[Random.Range(0, (PatrolDestinations.Length - 1))].transform;
//Loop while patrolling
while (currentstate == ENEMY_STATE.PATROL)
{
//Set strict search
ThisLineSight.Sensitity = LineSight.SightSensitivity.STRICT;
ThisAgent.speed = 1f;
//Chase to patrol position
//ThisAgent.Resume();
ThisAgent.isStopped = false;
ThisAgent.SetDestination(PatrolDestination.position);
//Wait until path is computed
while(ThisAgent.pathPending)
yield return null;
if (ThisAgent.remainingDistance < 1.5f)
PatrolDestination = PatrolDestinations[Random.Range(0, (PatrolDestinations.Length))].transform;
//If we can see the target then start chasing
if (ThisLineSight.CanSeeTarget)
{
//ThisAgent.Stop();
ThisAgent.isStopped = true;
transform.LookAt(GameManager.Instance.EnemyTarget);
CurrentState = ENEMY_STATE.CHASE;
yield break;
}
//Wait until next frame
yield return null;
}
}
public IEnumerator AIChase()
{
ThisAnimator.SetBool("Attack", false);
ThisAnimator.SetBool("Chase", true);
ThisAnimator.SetBool("Walk", false);
ThisAgent.speed = 1.7f;
//Loop while chasing
while (currentstate == ENEMY_STATE.CHASE)
{
//transform.LookAt(GameManager.Instance.EnemyTarget);
//Set loose search
ThisLineSight.Sensitity = LineSight.SightSensitivity.LOOSE;
//Chase to last known position
//ThisAgent.Resume();
ThisAgent.isStopped = false;
ThisAgent.SetDestination(ThisLineSight.LastKnowSighting);
//Wait until path is computed
while(ThisAgent.pathPending)
yield return null;
//Have we reached destination?
if(ThisAgent.remainingDistance <= ThisAgent.stoppingDistance +0.5f)
{
//Stop agent
ThisAgent.isStopped = true;
//ThisAgent.Stop();
//Reached destination but cannot see player
if(!ThisLineSight.CanSeeTarget)
CurrentState = ENEMY_STATE.PATROL;
else //Reached destination and can see player. Reached attacking distance
CurrentState = ENEMY_STATE.ATTACK;
yield break;
}
//Wait until next frame
yield return null;
}
}
public IEnumerator AIAttack()
{
ThisAnimator.SetBool("Attack", true);
ThisAnimator.SetBool("Chase", false);
ThisAnimator.SetBool("Walk", false);
//Loop while chasing and attacking
while (currentstate == ENEMY_STATE.ATTACK)
{
//Chase to player position
ThisAgent.isStopped = false;
ThisAgent.SetDestination(GameManager.Instance.EnemyTarget.position);
//Wait until path is computed
while (ThisAgent.pathPending)
yield return null;
//Has player run away?
if(ThisAgent.remainingDistance > ThisAgent.stoppingDistance + 0.5f)
//if(!inRange)
{
//Change back to chase
CurrentState = ENEMY_STATE.CHASE;
yield break;
}
else
{
//Attack
GameManager.Instance.Player.TakeDamage(MaxDamage);
sound = attacksSounds[Random.Range(0, (attacksSounds.Length))];
ThisAudioSource.PlayOneShot(sound);
}
//Wait until next frame
yield return attackDelay;
}
yield break;
}
//Called when the enemy is defeated and can no longer move
public void Defeated()
{
Debug.Log("DEFEATED");
//Disable the navmesh agent
ThisAgent.enabled = false;
ThisAnimator.SetBool("Die", true);
SpawnableManager.informSpawnableDestroyed(gameObject, false);
CurrentState = ENEMY_STATE.DEAD;
EnemyManager.nbrZombies --;
EnemyManager.CountAllZombie();
}
public IEnumerator StartZombie()
{
yield return new WaitForSeconds(5);
CurrentState = ENEMY_STATE.PATROL;
}
}
Code for Line of Sight :
using UnityEngine;
using System.Collections;
//------------------------------------------
public class LineSight : MonoBehaviour
{
//------------------------------------------
//How sensitive should we be to sight
public enum SightSensitivity {STRICT, LOOSE};
//Sight sensitivity
public SightSensitivity Sensitity = SightSensitivity.STRICT;
//Can we see target
public bool CanSeeTarget = false;
public bool DebugFOV = false;
//FOV
public float FieldOfView = 120f;
//Reference to target
public Transform Target = null;
//Reference to eyes
public Transform EyePoint = null;
//Reference to transform component
private Transform ThisTransform = null;
//Reference to sphere collider
public SphereCollider ThisCollider = null;
//Reference to last know object sighting, if any
public Vector3 LastKnowSighting = Vector3.zero;
private Vector3 DirToTarget;
void Awake()
{
ThisTransform = GetComponent<Transform>();
ThisCollider = GetComponent<SphereCollider>();
LastKnowSighting = ThisTransform.position;
}
private void Start()
{
Target = GameManager.Instance.EnemyTarget;
}
//------------------------------------------
bool InFOV()
{
//Get direction to target
DirToTarget = Target.position - EyePoint.position;
//Get angle between forward and look direction
float Angle = Vector3.Angle(EyePoint.forward, DirToTarget);
//Are we within field of view?
if(Angle <= FieldOfView)
{
Debug.DrawRay(EyePoint.position, (Target.position - EyePoint.position), Color.cyan);
return true;
}
//Not within view
return false;
}
//------------------------------------------
bool ClearLineofSight()
{
RaycastHit Info;
if (Physics.Raycast(EyePoint.position, (Target.position - EyePoint.position), out Info, ThisCollider.radius *2))
{
//If player, then can see player
//if (Info.transform.CompareTag("MainCamera"))
if(Info.transform.gameObject.layer == LayerMask.NameToLayer("Gringan"))
return true;
}
return false;
}
//------------------------------------------
void UpdateSight()
{
switch(Sensitity)
{
case SightSensitivity.STRICT:
CanSeeTarget = InFOV() && ClearLineofSight();
break;
case SightSensitivity.LOOSE:
CanSeeTarget = InFOV() || ClearLineofSight();
break;
}
}
//------------------------------------------
void OnTriggerStay(Collider Other)
{
UpdateSight();
//Update last known sighting
if(CanSeeTarget)
LastKnowSighting = Target.position;
}
void OnDrawGizmos()
{
float totalFOV = 120.0f;
float rayRange = 3.9f;
float halfFOV = totalFOV / 2.0f;
Quaternion leftRayRotation = Quaternion.AngleAxis(-halfFOV, Vector3.up);
Quaternion rightRayRotation = Quaternion.AngleAxis(halfFOV, Vector3.up);
Vector3 leftRayDirection = leftRayRotation * transform.forward;
Vector3 rightRayDirection = rightRayRotation * transform.forward;
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, leftRayDirection * rayRange);
Gizmos.DrawRay(transform.position, rightRayDirection * rayRange);
}
private void Update()
{
if(CanSeeTarget)
Debug.DrawRay(EyePoint.position, (Target.position - EyePoint.position), Color.yellow);
}
Thanks for helping me.
Firstly, you should be able to get the stack trace from your stack overflow, which would help a lot in tracking down these issues.
Although I don't know exactly what you're trying to do here, the most likely cause of a stack overflow from your code here is an infinite swapping between the attacking and chasing states.
If you follow the code through, currently chasing goes to attacking if range is less than or equal to a number, and attacking goes to chasing if range is more than that number.
Those conditions work currently, as they are mutually exclusive. If you were to change one of them to work off a trigger however (removing the mutual exclusivity), then you would have the potential to infinitely change state back and forth.
Every 5 seconds I need to take a photo and display it in the world. That part is working fine.
Once a photo is taken it need to disappear 1 second after. That's where I'm stuck.
I've gotten it to disappear but then I cant get the new picture to reappear when its function is called again.
Any ideas?
I've tried:
m_CanvasRenderer.enabled = false;
m_CanvasRenderer.enabled = true;
m_Canvas = null;
m_Canvas.setActive(false);
m_Canvas.setActive(true);
With no luck
public class PhotoCaptureExample : MonoBehaviour
{
GestureRecognizer m_GestureRecognizer;
GameObject m_Canvas = null;
Renderer m_CanvasRenderer = null;
PhotoCapture m_PhotoCaptureObj;
CameraParameters m_CameraParameters;
bool m_CapturingPhoto = false;
Texture2D m_Texture = null;
void Start()
{
Initialize();
InvokeRepeating("TakePhoto", 5.0f, 5.0f);
//StartCoroutine(TakePhoto());
}
void TakePhoto()
{
if (m_CapturingPhoto)
{
return;
}
m_CapturingPhoto = true;
m_PhotoCaptureObj.TakePhotoAsync(OnPhotoCaptured);
}
void OnPhotoCaptured(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
// m_CanvasRenderer.enabled = true;
if (m_Canvas == null)
{
m_Canvas = GameObject.CreatePrimitive(PrimitiveType.Quad);
m_Canvas.name = "PhotoCaptureCanvas";
m_CanvasRenderer = m_Canvas.GetComponent<Renderer>() as Renderer;
m_CanvasRenderer.material = new Material(Shader.Find("AR/HolographicImageBlend"));
}
Matrix4x4 cameraToWorldMatrix;
photoCaptureFrame.TryGetCameraToWorldMatrix(out cameraToWorldMatrix);
Matrix4x4 worldToCameraMatrix = cameraToWorldMatrix.inverse;
Matrix4x4 projectionMatrix;
photoCaptureFrame.TryGetProjectionMatrix(out projectionMatrix);
photoCaptureFrame.UploadImageDataToTexture(m_Texture);
m_Texture.wrapMode = TextureWrapMode.Clamp;
m_CanvasRenderer.sharedMaterial.SetTexture("_MainTex", m_Texture);
m_CanvasRenderer.sharedMaterial.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix);
m_CanvasRenderer.sharedMaterial.SetMatrix("_CameraProjectionMatrix", projectionMatrix);
m_CanvasRenderer.sharedMaterial.SetFloat("_VignetteScale", 1.0f);
// Position the canvas object slightly in front
// of the real world web camera.
Vector3 position = cameraToWorldMatrix.GetColumn(3) - cameraToWorldMatrix.GetColumn(2);
// Rotate the canvas object so that it faces the user.
Quaternion rotation = Quaternion.LookRotation(-cameraToWorldMatrix.GetColumn(2), cameraToWorldMatrix.GetColumn(1));
m_Canvas.transform.position = position;
m_Canvas.transform.rotation = rotation;
m_CapturingPhoto = false;
float counter = 0; float target = 1;
while (counter < target)
{
counter += Time.deltaTime;
}
// m_CanvasRenderer.enabled = false;
}
}
I have a scene in which the player can pick up and drop objects, as well as move and look around.
All player objects are children of an empty game object "MainCharacter":
MainCharacter >
Capsule (With RigidBody and PlayerMoveScript) >
PlayerBase (empty - used for checking if grounded)
MainCamera >
Hands(With PickUpDrop script)
The object I pick up Lerps to my Hands position, however after my capsule collides with any walls there is a strange jittering which I cannot work out how to fix!!
Heres the .exe:GameTest
Heres the data folder : Data
Here are the scripts:
Pick Up and Drop Script:
public bool handsFull = false;
public float distanceMax = 20f;
public Transform handPosition;
public LayerMask canPickUp;
public GameObject taggedGameObject;
public bool colliderTriggered;
public bool bounds;
public PickedUpObject pickedUpScript;
public Rigidbody player;
// Use this for initialization
void Start () {
print(FindClosestPickup().name);
handPosition = transform;
pickedUpScript = null;
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.E) && !bounds) {
if (Physics.CheckSphere (handPosition.position, 2f, canPickUp)) {
if (handsFull) {
Drop ();
}
if (!handsFull) {
PickedUp ();
}
handsFull = !handsFull;
}
}
if (handsFull) {
RotateMovePickedUpObject();
}
}
private void PickedUp(){
//Closest object to top of list
taggedGameObject = (GameObject)FindClosestPickup();
taggedGameObject.collider.isTrigger = true;
taggedGameObject.rigidbody.useGravity = false;
taggedGameObject.rigidbody.isKinematic = true;
pickedUpScript = taggedGameObject.GetComponent<PickedUpObject> ();
Debug.Log ("Pick Up");
}
private void RotateMovePickedUpObject(){
//Rotate
if(Input.GetKeyDown(KeyCode.End)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 0, 45);
}
if(Input.GetKeyDown(KeyCode.Delete)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 45, 0);
}
if(Input.GetKeyDown(KeyCode.PageDown)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(0, -45, 0);
}
if(Input.GetKeyDown(KeyCode.Home)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(0, 0, -45);
}
if(Input.GetKeyDown(KeyCode.PageUp)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(-45, 0, 0);
}
if(Input.GetKeyDown(KeyCode.Insert)){
taggedGameObject.transform.localRotation *= Quaternion.Euler(45, 0, 0);
}
taggedGameObject.transform.position = Vector3.Lerp(taggedGameObject.transform.position, handPosition.position, (1 - Mathf.Exp( -20 * Time.smoothDeltaTime )) * 10);
}
private void Drop(){
taggedGameObject.collider.isTrigger = false;
taggedGameObject.rigidbody.useGravity = true;
taggedGameObject.rigidbody.isKinematic = false;
taggedGameObject = null;
Debug.Log ("Drop");
pickedUpScript = null;
}
private GameObject FindClosestPickup() {
//Find closest gameobject with tag
GameObject[] gos;
gos = GameObject.FindGameObjectsWithTag("pickup");
GameObject closest = null;
float distance = Mathf.Infinity;
Vector3 position = transform.position;
foreach (GameObject go in gos) {
Vector3 diff = go.transform.position - position;
float curDistance = diff.sqrMagnitude;
if (curDistance < distance) {
closest = go;
distance = curDistance;
}
}
return closest;
}
}
The Picked Up Objects Script:
public PickUpDrop pickUpScript;
public GameObject thisOne;
public Color thecolor;
public bool inObject;
// Use this for initialization
void Start () {
thisOne = this.gameObject;
}
// Update is called once per frame
void Update ()
{
thecolor = thisOne.renderer.material.color;
if (pickUpScript.taggedGameObject != thisOne)
{
gameObject.renderer.material.color = Color.gray;
}
if (pickUpScript.taggedGameObject == thisOne)
{
Color color = renderer.material.color;
color.a = 0.5f;
renderer.material.color = color;
}
}
void OnTriggerEnter ()
{
if (thisOne == pickUpScript.taggedGameObject)
{
inObject = true;
pickUpScript.bounds = true;
gameObject.renderer.material.color = Color.red;
}
}
void OnTriggerExit()
{
if(thisOne == pickUpScript.taggedGameObject)
{
inObject = false;
pickUpScript.bounds = false;
gameObject.renderer.material.color = Color.gray;
}
}
}
taggedGameObject.transform.position = Vector3.Lerp(taggedGameObject.transform.position, handPosition.position, (1 - Mathf.Exp( -20 * Time.smoothDeltaTime )) * 10);
This line will keep moving the object towards the hand's position. If you have a rigidbody attached to the game object you're moving then the physics acting on that object during the physics calculation will conflict with the manual movement of the object during the Update function.
It depends on what you would like to happen when this conflict occurs as to the solution. If you simply want the 'jittering' to stop and still be able to hold objects against other physical objects, then use this;
taggedGameObject.rigidbody.AddForce( ( taggedGameObject.transform.position - handPosition.position ) * force );
This will keep all interactions with the rigidbody. You'll have to tweak the force you move the object with, and perhaps disable gravity on the tagged game object while it's in the players hands. But it should have the desired effect.