C# 如何在每个条件下仅使用一次标志?
此简单类附加到游戏中的某些对象:C# 如何在每个条件下仅使用一次标志?,c#,unity3d,C#,Unity3d,此简单类附加到游戏中的某些对象: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class InteractableItem : MonoBehaviour { public enum InteractableMode { Description, Action,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InteractableItem : MonoBehaviour
{
public enum InteractableMode
{
Description,
Action,
ActionWithoutThrow
};
public InteractableMode interactableMode = InteractableMode.Description;
public float distance;
[TextArea(1, 10)]
public string description = "";
public bool IsAnyAction()
{
return interactableMode == InteractableMode.ActionWithoutThrow || interactableMode == InteractableMode.Action;
}
}
例如,脚本附加到游戏对象:
因此,当播放器与安全键盘的距离接近1.7时,它将触发以下事件:
在此脚本中,我使用InteractiableItem枚举:
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour
{
public InteractableItem[] lookObj = null;
public GameObject objToThrow;
public Text text;
public float weightDamping = 1.5f;
public bool RightHandToTarget = true;
public float throwSpeed;
public bool handFinishedMove = false;
private List<InteractableItem> allDetectedItems;
private Animator animator;
private InteractableItem lastPrimaryTarget;
private float lerpEndDistance = 0.1f;
private float finalLookWeight = 0;
private bool transitionToNextTarget = false;
void Start()
{
animator = GetComponent<Animator>();
allDetectedItems = new List<InteractableItem>();
}
// Callback for calculating IK
void OnAnimatorIK()
{
if (lookObj != 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 lookObj)
{
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;
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;
allDetectedItems.Add(target);
}
}
if (primaryTarget != null)
{
if ((lastPrimaryTarget != null) && (lastPrimaryTarget != primaryTarget) && (finalLookWeight > 0f))
{
// Here we start a new transition because the player looks already to a target but
// we have found another target the player should look at
transitionToNextTarget = true;
}
}
// The player is in a neutral look position but has found a new target
if ((primaryTarget != null) && !transitionToNextTarget)
{
if(primaryTarget.interactableMode == InteractableItem.InteractableMode.ActionWithoutThrow)
{
RightHandToTarget = true;
}
lastPrimaryTarget = primaryTarget;
//finalLookWeight = Mathf.Lerp(finalLookWeight, closestLookWeight, Time.deltaTime * weightDamping);
finalLookWeight = Mathf.Lerp(finalLookWeight, 1f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(primaryTarget.transform.position);
if (RightHandToTarget && primaryTarget.IsAnyAction())
{
Vector3 relativePos = primaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 1f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, primaryTarget.transform.position);
// -> new code block
if (finalLookWeight > 0.95f) // here you can play with a value between 0.95f -> 1.0f
{
if(primaryTarget.interactableMode == InteractableItem.InteractableMode.Action)
// call your funtion to shoot something here
StartCoroutine(ThrowObject(objToThrow.transform, primaryTarget.transform.position, 30f));
}
if(finalLookWeight > 0.9f)
{
handFinishedMove = true;
}
}
}
// Let the player smoothly look away from the last target to the neutral look position
if ((primaryTarget == null && lastPrimaryTarget != null) || transitionToNextTarget)
{
finalLookWeight = Mathf.Lerp(finalLookWeight, 0f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(lastPrimaryTarget.transform.position);
if (RightHandToTarget)
{
Vector3 relativePos = lastPrimaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 0.5f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, lastPrimaryTarget.transform.position);
}
if (finalLookWeight < lerpEndDistance)
{
transitionToNextTarget = false;
finalLookWeight = 0f;
lastPrimaryTarget = null;
}
}
// Show primary object found by the player
if (primaryTarget != null)
{
text.text = primaryTarget.description;
}
else
{
text.text = "";
}
}
}
IEnumerator ThrowObject(Transform objectToMove, Vector3 toPosition, float duration)
{
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
Vector3 currentPos = objectToMove.position;
float time = Vector3.Distance(currentPos, toPosition) / (duration - counter) * Time.deltaTime;
objectToMove.position = Vector3.MoveTowards(currentPos, toPosition, time);
yield return null;
}
}
}
问题是在最后一个脚本解锁中,问题是playAnimOnce标志始终在false和true之间变化。我需要以某种方式使用标志,但也要检查与安全键盘的距离。我可以在解锁箱中添加一个本地距离检查,检查与播放器的距离,或者检查播放器与安全键盘之间的距离
但其思想是在许多对象上使用InteractiableItem脚本来执行操作或获取描述。
但我想用InteractiableItem中的距离来做。如果播放器与安全键盘的距离为1.7,则在解锁箱脚本中执行某些操作
如果玩家与其他对象(例如树)的距离为55,则对树进行处理
问题有点长,但所有脚本都是连接在一起的。我不确定要从脚本中减少什么。我建议不要检查每一帧上的标志,而是使用事件。当交互完成时,尝试在
interactiableitem
上放置一个事件,然后在UnlockCrate
中创建一个方法,该方法可以注册到属于键盘的interactiableitem
上的事件,并将代码放在其中,使板条箱执行它需要执行的任何操作(你的问题并不能真正解释这一点,所以我不能说得更具体)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class UnlockCrate : MonoBehaviour
{
public Animation anim;
public IKControl ikControl;
public GameObject securityKeyPad;
public CinemachineVirtualCamera virtualCam;
public CinemachineFreeLook freeLookCam;
public CamerasControl camerasContorl;
private bool playAnimOnce = false;
private void Update()
{
if (!playAnimOnce)
{
if (ikControl.handFinishedMove == true)
{
securityKeyPad.SetActive(true);
virtualCam.enabled = true;
freeLookCam.enabled = false;
Cursor.visible = true;
camerasContorl.enabled = false;
}
playAnimOnce = true;
}
else if (playAnimOnce)
{
securityKeyPad.SetActive(false);
virtualCam.enabled = false;
freeLookCam.enabled = true;
Cursor.visible = false;
camerasContorl.enabled = true;
playAnimOnce = false;
}
}
}