Я новичок в новой системе ввода Unity, недавно я перенес свой проект со старой системы ввода на новую систему ввода, но столкнулся с некоторыми трудностями при ее использовании.
У меня есть класс под названием InputManager
, который управляет всеми действиями ввода для моей игры, и еще один класс под названием PlayerInteractions
, который содержит все взаимодействия игрока, такие как сбор предметов, открытие и закрытие ящиков/дверей и так далее.
playerInteraction
класс отлично работал со старой системой ввода, но когда я перешел на новую систему ввода, я не мог правильно обрабатывать вызовы функций, поэтому он не работал полностью. Мне удалось заставить работать сбор объектов, но часть открытия/закрытия не работала, потому что для этого я вызываю другую функцию из класса с именем InteractiveObjects
, которая прикреплена ко всем объектам, которые можно открывать/закрывать, например, двери/ящики. ..
и мне было трудно обрабатывать эти вызовы функций, так как я недостаточно хорошо разбираюсь в новой системе ввода.
Вот фрагмент PlayerInteractions Class
private InteractiveObjects interactiveObjects;
bool PickingUp, Open;
void Update()
{
raycastPos = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, 0));
RaycastHit hit;
if (Physics.SphereCast(raycastPos, sphereCastRadius, mainCamera.transform.forward, out hit, maxDistance, 1 << interactableLayerIndex))
{
lookObject = hit.collider.transform.gameObject;
}
else
{
lookObject=null;
}
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
PickupObject();
}
}
else
{
BreakConnection();
}
}
PickingUp = false;
if (hit.transform)
{
interactiveObjects = hit.transform.GetComponent<InteractiveObjects>();
}
else
{
lookObject = null;
interactiveObjects = null;
}
if (Open)
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
Open = false;
}
public void OnPickingUp()
{
PickingUp = true;
}
public void OnOpen()
{
Open = true;
}
Эта часть сверху:
if (Open)
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
было так:
if (Input.GetKeyDown(KeyCode.E))
{
if (interactiveObjects)
{
interactiveObjects.PerformAction();
}
}
а класс InteractiveObject
был примерно таким:
public void PerformAction()
{
if (aSource)
{
aSource.Play();
}
if (Input.GetKeyDown(KeyCode.E))
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch(movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
if (Input.GetKeyDown(KeyCode.E))
было изменено на if (Open)
.
Вот полный класс IneractiveObject
после изменения:
public class InteractiveObjects : MonoBehaviour
{
[SerializeField] private Vector3 openPosition, closedPosition;
[SerializeField] private float animationTime;
[SerializeField] private bool isOpen = false;
[SerializeField] private MovementType movementType;
bool Open;
private enum MovementType { Slide, Rotate };
private Hashtable iTweenArgs;
private AudioSource aSource;
void Start()
{
iTweenArgs = iTween.Hash();
iTweenArgs.Add("position", openPosition);
iTweenArgs.Add("time", animationTime);
iTweenArgs.Add("islocal", true);
aSource = GetComponent<AudioSource>();
}
public void PerformAction()
{
if (aSource)
{
aSource.Play();
}
if (Open)
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch (movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
Open = false;
}
public void OnOpen()
{
Open = true;
}
}
InputManager
класс:
public class InputManager : MonoBehaviour
{
[SerializeField] Movement movement;
[SerializeField] PlayerInteractions playerInteractions;
[SerializeField] MouseLook mouseLook;
PlayerControls controls;
PlayerControls.GroundMovementActions groundMovement;
Vector2 horizontalInput;
Vector2 mouseInput;
private void Awake()
{
controls = new PlayerControls();
groundMovement = controls.GroundMovement;
// groundMovement.[action].performed += context => do something
groundMovement.HorizontalMovement.performed += ctx => horizontalInput = ctx.ReadValue<Vector2>();
groundMovement.Jump.performed += _ => movement.OnJumpPressed();
groundMovement.Running.performed += _ => movement.OnRunning();
groundMovement.PickingUp.performed += _ => playerInteractions.OnPickingUp();
groundMovement.MouseX.performed += ctx => mouseInput.x = ctx.ReadValue<float>();
groundMovement.MouseY.performed += ctx => mouseInput.y = ctx.ReadValue<float>();
groundMovement.Open.performed += _ => playerInteractions.OnOpen();
}
private void Update()
{
movement.ReceiveInput(horizontalInput);
mouseLook.ReceiveInput(mouseInput);
}
private void OnEnable()
{
controls.Enable();
}
private void OnDestroy()
{
controls.Disable();
}
}
Таким образом, класс InputManager
вызывает функцию из playerInteractions
, которая также вызывает функцию из InteractiveObjects
для открытия/закрытия функции. это не сработало для меня, но я не знаю, как это исправить. пожалуйста помоги.
Решение здесь, вам больше не нужно Open
Boolean, и вы можете вызывать функцию напрямую через новую систему ввода. для этой работы; Введите только содержимое if on OnOpen
.
public void OnOpen()
{
if (isOpen)
{
iTweenArgs["position"] = closedPosition;
iTweenArgs["rotation"] = closedPosition;
}
else
{
iTweenArgs["position"] = openPosition;
iTweenArgs["rotation"] = openPosition;
}
isOpen = !isOpen;
switch(movementType)
{
case MovementType.Slide:
iTween.MoveTo(gameObject, iTweenArgs);
break;
case MovementType.Rotate:
iTween.RotateTo(gameObject, iTweenArgs);
break;
}
}
Это не только упрощает структуру кода. Скорее, это предотвращает повторение условия if в обновлении. Теперь запустите OnOpen
, как вы установили, нажав клавишу B:
controls.GroundMovement.Open.performed += _ => playerInteraction.OnOpen();
Существует несколько способов создания функций, которые работают непрерывно. Это пример, который работает, определяя Func<bool>
в скрипте целевого объекта:
public class PlayerInteraction : MonoBehaviour
{
public Func<bool> IsPressingOpen;
public void Update()
{
if (IsPressingOpen())
{
// do something...
}
}
}
И достаточно установить функцию по результату key pressing
:
playerInteraction.IsPressingOpen = () => controls.GroundMovement.Open.IsPressed();
Надеюсь, этот ответ будет исчерпывающим и практичным.
Я также попробовал часть ответа с булочками, IsPressed(); не определен. и это вызывает ошибки.
@Okashi Могу я спросить, вы обычно получаете обратный вызов, когда нажимаете клавиши, или какая-либо клавиша не работает, когда вы ее нажимаете?
Да, вообще все действия в Input Action работают, кроме Open.
Я думаю, проблема в том, что он никогда не доходит до функции в InteractiveObject из PLayerInteractions. Я попытался напечатать там строку, но она никогда не печатается, поэтому я думаю, что она не дошла до функции должным образом.
пришлите мне свои коды на ([email protected]), если ваша проблема не решится.
Большое спасибо за то, что вы так полезны. Я постараюсь еще немного, чтобы это сработало, если это не так, я пришлю вам. Спасибо еще раз
Спасибо наконец заработало. В конце концов, проблема была не в коде, а в инспекторе чего-то не хватало!
Спасибо за ваш ответ. Итак, в первой части ответа я понял, что мне нужно изменить имя функции в классе InteractiveObject на OnOpen(), затем в классе InputManager функция была вызвана из класса PlayerInteractions следующим образом:controls.GroundMovement.Open.performed += _ => playerInteraction.OnOpen(); но вы не упомянули, как вызвать функцию из playerInteraction.