The relevant part of the code : The script is attached to the player :
The player layer is set to "kid_from_space" when the player is interacting with the first interactable item target he also looking at the target.
but when the player is interacting with another target the player is not looking at the target.
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
using TMPro;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour
{
public List<InteractableItem> lookObjs = new List<InteractableItem>();
public TextMeshProUGUI text;
public float weightDamping = 1.5f;
public bool RightHandToTarget = false;
public GameObject descriptionTextImage;
public float duration;
private List<InteractableItem> allDetectedItems;
private Animator animator;
private InteractableItem lastPrimaryTarget;
private float lerpEndDistance = 0.1f;
private float finalLookWeight = 0;
private bool transitionToNextTarget = false;
private float t;
private bool showText = true;
private GameObject playerEyes;
void Start()
{
playerEyes = GameObject.Find("rig_eye.L");
animator = GetComponent<Animator>();
allDetectedItems = new List<InteractableItem>();
t = 0;
}
// Callback for calculating IK
void OnAnimatorIK()
{
if (lookObjs != null)
{
lookObjs.RemoveAll(x => x == null);
InteractableItem primaryTarget = null;
float closestLookWeight = 0;
// Here we find the target which is closest (by angle) to the players view line
allDetectedItems.Clear();
foreach (InteractableItem target in lookObjs)
{
if (target.enabledInteraction == false)
{
continue;
}
Vector3 lookAt = target.transform.position - transform.position;
lookAt.y = 0f;
// Filter out all objects that are too far away
if (lookAt.magnitude > target.distance) continue;
RaycastHit hit;
if (Physics.Raycast(playerEyes.transform.position, target.transform.position - playerEyes.transform.position, out hit, target.distance, ~LayerMask.GetMask("kid_from_space")))
{
if (hit.collider.gameObject == target.gameObject)
{
// First object hit was the target so there is a clear line of sight
float dotProduct = Vector3.Dot(new Vector3(transform.forward.x, 0f, transform.forward.z).normalized, lookAt.normalized);
float lookWeight = Mathf.Clamp(dotProduct, 0f, 1f);
if (lookWeight > 0.1f && lookWeight > closestLookWeight)
{
closestLookWeight = lookWeight;
primaryTarget = target;
if (showText)
{
StartCoroutine(WaitBeforeShowingText(primaryTarget));
showText = false;
}
}
else
{
showText = true;
text.text = "";
descriptionTextImage.SetActive(false);
}
allDetectedItems.Add(target);
}
else
{
showText = true;
text.text = "";
descriptionTextImage.SetActive(false);
}
}
}
InteractWithTarget(primaryTarget, closestLookWeight);
}
}
Each interactable item have this script attached :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractableItem : MonoBehaviour
{
public string currentMode;
public bool enabledInteraction = true;
private InteractableMode currentInteractableMode;
private string currentDesription;
private void Awake()
{
}
public enum InteractableMode
{
Description,
Action,
ActionWithoutThrow
};
public InteractableMode interactableMode = InteractableMode.Description;//public InteractableLookAtDirection interactableLookAtDirection = InteractableLookAtDirection.Forward;
public float distance;
[TextArea(1, 10)]
public string description = "";
public bool IsAnyAction()
{
return interactableMode == InteractableMode.ActionWithoutThrow || interactableMode == InteractableMode.Action;
}
public bool IsActionWithoutThrow()
{
return interactableMode == InteractableMode.ActionWithoutThrow;
}
private void Start()
{
currentMode = GetComponent<InteractableItem>().interactableMode.ToString();
currentInteractableMode = GetComponent<InteractableItem>().interactableMode;
currentDesription = GetComponent<InteractableItem>().description;
}
private void Update()
{
}
}
This screenshot is of the first interactable item target the player reach and the player is looking at the target item :
It's passing through inside this two conditions lines :
if (Physics.Raycast(playerEyes.transform.position, target.transform.position - playerEyes.transform.position, out hit, target.distance, ~LayerMask.GetMask("kid_from_space")))
{
if (hit.collider.gameObject == target.gameObject)
but when getting to the next second interactable item target the code is not passing the above two lines :
This time the distance is set to 0.3 and the player is not looking at the interactable item even if i'm moving the interactable item up down change it's position the player is not looking at it.
The player is keep looking straight forward like in his natural look.
I used a break point and i see that the variable primaryTarget is null because it's never passed through inside the line :
if (Physics.Raycast(playerEyes.transform.position, target.transform.position - playerEyes.transform.position, out hit, target.distance, ~LayerMask.GetMask("kid_from_space")))
target variable is : "Security Keypad (InteractableItem)"
distance is 0.3
and hit is :
I don't get it, why it's not passing the line with the Physics.Raycast ?
I guess the ray is never hitting the interactable item. but i'm not sure why and how to fix it.
I see now using a break point that it does pass the first if condition line but when it's getting to the second line if (hit.collider.gameObject == target.gameObject) i see that the hit.collider.gameObject is not the target gameObject but a child of the target.gameObject so it's never equal true. The interactable item as you see in the screenshots the second one is a keypad system and the hit collider gameobject is a button key child object and not the parent object. i guess it's not accurate because the target item and the child objects almost at the same positions. so i'm stuck here.
how can i make sure it will hit the interactable item object target and not a child of it ?
CodePudding user response:
According to your code and screenshots, something in this line is null:
if (Physics.Raycast(playerEyes.transform.position, target.transform.position - playerEyes.transform.position, out hit, target.distance, ~LayerMask.GetMask("kid_from_space")))
So I would just print these before:
Debug.Log(playerEyes == null ? "playerEyes null!" : "playerEyes valid");
Debug.Log(target == null ? "target null!" : "target valid");