I have opened the unity(2021.3.7f1) first person module, and tried to add an attack animation to it. I have discovered that my code as soon as it takes 1 input(click), it keeps taking that input. The "isAttacking" variable, keeps being set to "true", even when the player is not clicking. The debug there is how I have figured out this problem.
I cannot for the life of me figure out why this is happening, please help.
Under StarterAssets
public class StarterAssetsInputs : MonoBehaviour
{
[Header("Character Input Values")]
public Vector2 move;
public Vector2 look;
public bool jump;
public bool sprint;
[Header("Movement Settings")]
public bool analogMovement;
[Header("Mouse Cursor Settings")]
public bool cursorLocked = true;
public bool cursorInputForLook = true;
// I added this in vv
public bool attack = false;
#if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
public void OnMove(InputValue value)
{
MoveInput(value.Get<Vector2>());
}
public void OnLook(InputValue value)
{
if(cursorInputForLook)
{
LookInput(value.Get<Vector2>());
}
}
public void OnJump(InputValue value)
{
JumpInput(value.isPressed);
}
public void OnSprint(InputValue value)
{
SprintInput(value.isPressed);
}
// I added this in vv
public void OnAttack(InputValue value)
{
AttackInput(value.isPressed);
}
#endif
public void MoveInput(Vector2 newMoveDirection)
{
move = newMoveDirection;
}
public void LookInput(Vector2 newLookDirection)
{
look = newLookDirection;
}
public void JumpInput(bool newJumpState)
{
jump = newJumpState;
}
public void SprintInput(bool newSprintState)
{
sprint = newSprintState;
}
private void OnApplicationFocus(bool hasFocus)
{
SetCursorState(cursorLocked);
}
private void SetCursorState(bool newState)
{
Cursor.lockState = newState ? CursorLockMode.Locked : CursorLockMode.None;
}
// I added this in vv
private void AttackInput(bool newAttack)
{
attack = newAttack;
}
}
}
Under first-person controller
private void Attack()
{
if (_input.attack)
{
Debug.Log("Debug " + debugNR);
debugNR++;
WeaponController attackState = weapon.GetComponent<WeaponController>();
attackState.isAttacking = true;
}
}
Under weapon controller
public class WeaponController : MonoBehaviour
{
public Animator animator;
public bool isAttacking = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
animator.SetBool("Attack", isAttacking);
}
public void Attack()
{
isAttacking = false;
animator.SetBool("Attack", isAttacking);
}
}
Thanks in advance for the help
_input.attack must be set to false, as part of the attack function in the first person controller
The function was changed from:
private void Attack()
{
if (_input.attack)
{
Debug.Log("Debug " + debugNR);
debugNR++;
WeaponController attackState = weapon.GetComponent<WeaponController>();
attackState.isAttacking = true;
}
}
To:
private void Attack()
{
if (_input.attack)
{
Debug.Log("Debug " + debugNR);
debugNR++;
WeaponController attackState = weapon.GetComponent<WeaponController>();
attackState.isAttacking = true;
_input.attack = false;
}
}
Related
I'm looking for a solution of the following issue:
I have a player instantiated in lobby room at initial scene. There are two platform objects with colliders, I need to make one platform to join to one room with a scene and other platform to another room with another scene. I have attached the same script for both of platform with a boolean value which determines to which room to join. Instead of determine to which room to join it triggers both scripts. I need to work it in this way:
Platform A:
private bool teleportToShop = true;
If (teleportToShop) -> join shop room
Platform B:
private bool teleportToShop = false;
If (!teleportToShop) -> join event room
Here's my code attached to both game objects:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Portal : MonoBehaviourPunCallbacks
{
[SerializeField] private bool teleportToShop;
private float portalTime = 3f;
private string EVENT_HALL_TAG = "Cinema Hall";
private string LOBBY_TAG = "Lobby";
private string SHOP_TAG = "Shop";
private int currentRoom = 0;
private string nextRoom;
private PhotonView portalView;
private void Awake()
{
portalView = GetComponent<PhotonView>();
}
private void OnTriggerStay(Collider other)
{
if (portalView.IsMine)
{
if (other.GetComponent<PhotonView>().IsMine)
{
if (other.gameObject.tag == "Player")
{
if (portalTime > 0)
{
portalTime -= Time.deltaTime;
}
else
{
portalTime = 3f;
if (SceneManager.GetActiveScene().name == EVENT_HALL_TAG || SceneManager.GetActiveScene().name == SHOP_TAG)
{
currentRoom = 1;
PhotonNetwork.LeaveRoom();
}
else
{
currentRoom = 0;
PhotonNetwork.LeaveRoom();
}
}
}
}
}
}
private void OnTriggerExit(Collider other)
{
portalTime = 3f;
}
public override void OnConnectedToMaster()
{
PhotonNetwork.AutomaticallySyncScene = false;
PhotonNetwork.JoinLobby();
}
public override void OnJoinedLobby()
{
if (currentRoom == 0)
{
if (!teleportToShop)
{
PhotonNetwork.JoinRoom("EventHallRoom");
}
else if (teleportToShop)
{
PhotonNetwork.JoinRoom("ShopRoom");
}
}
else PhotonNetwork.JoinRoom("LobbyRoom");
}
public override void OnJoinRoomFailed(short returnCode, string message)
{
base.OnJoinRandomFailed(returnCode, message);
if (currentRoom == 0)
{
if (!teleportToShop)
{
PhotonNetwork.CreateRoom("EventHallRoom");
}
else if (teleportToShop)
{
PhotonNetwork.CreateRoom("ShopRoom");
}
}
else PhotonNetwork.CreateRoom("LobbyRoom");
}
public override void OnJoinedRoom()
{
if (currentRoom == 0)
{
if (!teleportToShop)
{
PhotonNetwork.LoadLevel(EVENT_HALL_TAG);
}
else if (teleportToShop)
{
PhotonNetwork.LoadLevel(SHOP_TAG);
}
}
else PhotonNetwork.LoadLevel(LOBBY_TAG);
}
public override void OnLeftRoom()
{
GameManager.currentPlayer = null;
}
}
I have a condition that should check whether it is true or false. I did this:
void Update()
{
if (Slot.SlotBool == true)
{
score++;
Debug.Log("OK! " + score);
}
}
But I want him to check without pressing the button, and put it in Update(), but then Score was increasing every second... Is there any other way to do it?
I have 3 scripts, the first one is needed to move an object, get a starting position, etc. It looks like this:
public class DManager : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerClickHandler
{
public static GameObject objBeingDraged;
private Vector2 startPosition;
private Transform startParent;
private CanvasGroup canvasGroup;
private Transform itemDraggerParent;
void Start()
{
canvasGroup = GetComponent<CanvasGroup>();
itemDraggerParent = GameObject.FindGameObjectWithTag("ItemDraggerParent").transform;
}
public void OnBeginDrag(PointerEventData eventData)
{
objBeingDraged = gameObject;
startPosition = transform.position;
startParent = transform.parent;
transform.SetParent(itemDraggerParent);
canvasGroup.blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData)
{
transform.position = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
public void OnEndDrag(PointerEventData eventData)
{
objBeingDraged = null;
canvasGroup.blocksRaycasts = true;
if (transform.parent == itemDraggerParent)
{
transform.position = startPosition;
transform.SetParent(startParent);
}
}
public void OnPointerClick(PointerEventData eventData)
{
transform.rotation *= Quaternion.Euler(0,0, -90);
}
}
The second one is needed so that when the object is released:
public class Puzzle : MonoBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
if (DManager.objBeingDraged == null) return;
DManager.objBeingDraged.transform.SetParent(transform);
}
}
And the third one is needed already in order to get an object and compare the resulting object name. I could put score accruals here, but here he checks every element
int score=0;
public static bool f=false;
public void OnDrop(PointerEventData eventData)
{
if (!item)
{
item = DManager.objBeingDraged;
if (item.name== this.gameObject.name)
{
if (item.transform.rotation == this.gameObject.transform.rotation)
{
f = true;
Debug.Log(f);
score++;
Debug.Log(score);
}
}
item.transform.SetParent(transform);
item.transform.position = transform.position;
}
}
void Update()
{
if (item != null && item.transform.parent != transform)
{
item = null;
}
}
So I created another script where points are already awarded
you can add another boolean to check if the score was already incremented.
private bool incrementedBool = false;
void Update()
{
if(incrementedBool == false)
{
incrementedBool = true;
if (Slot.SlotBool == true)
{
score++;
Debug.Log("OK! " + score);
}
}
}
Then, if you want to incremente another time the score for any reason, you can reset the boolean like that :
incrementedBool = false;
public class BuyableItem : MonoBehaviour
{
public float PickUpRadius = 1f;
public InventoryItemData ItemData;
private SphereCollider myCollider;
private void Awake()
{
myCollider = GetComponent<SphereCollider>();
myCollider.isTrigger = true;
myCollider.radius = PickUpRadius;
}
private void OnTriggerEnter(Collider other)
{
var inventory = other.transform.GetComponent<InventoryHolder>();
if (!inventory) return;
if (inventory.InventorySystem.AddToInventory(ItemData, 1))
{
Destroy(this.gameObject);
}
}
public static void UpdateDiamondText(PlayerInventory playerInventory)
{
InventoryUI.newDiamondText.text = playerInventory.NumberOfDiamonds.ToString();
}
}
Based off of this, how would I be able to make the counter of my InventoryUI newDiamondText script reach zero when picking up an item?
I am rewriting my player movement script to make use of hierarchical state machines (mostly to get the practice and learn how they work) as per this tutorial.
I am beginning to understand how the state machine works, but having some trouble making changes that I'd like to make. Specifically, I want to make the PlayerJumpState a substate that gets called if the PlayerAirborneState is switched to and the jump button was pressed. The problem is I can't seem to figure out a way to switch to the jump as a substate while maintaining the airborne state as the superstate.
I have a PlayerGroundedState which functions as it should - it initializes the necessary substates, and the player is switched to these substates when the right conditions are met, meanwhile, the superState they are in can be either grounded or airborne. The jump state I want to use should only be accessible by the airborne state, and it should maintain the airborne superstate when switched to.
Here's the PlayerGroundedState script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerGroundedState : PlayerBaseState
{
public PlayerGroundedState(PlayerStateMachine currentContext, PlayerStateFactory playerStateFactory)
: base(currentContext, playerStateFactory)
{
IsRootState = true;
InitializeSubstate();
}
public override void EnterState()
{
Debug.Log("Grounded State Entered");
Ctx.CharacterController.stepOffset = Ctx.OrigStepOffset;
Ctx.Animator.SetBool("isGrounded", true);
Ctx.Animator.SetBool("isJumping", false);
Ctx.YSpeed = -1;
}
public override void UpdateState()
{
if (Ctx.IsJumpPressed)
{
Ctx.WasJumpPressed = true;
}
CheckSwitchStates();
}
public override void ExitState() { }
public override void InitializeSubstate()
{
if (!Ctx.IsMovementPressed)
{
SetSubState(Factory.Idle());
}
else if (Ctx.IsMovementPressed)
{
SetSubState(Factory.Walk());
}
}
public override void CheckSwitchStates()
{
if (Ctx.IsJumpPressed)
{
SwitchState(Factory.Airborne());
}
}
void OnAnimatorMove()
{
Vector3 velocity = Ctx.Animator.deltaPosition;
velocity.y = Ctx.YSpeed * Time.deltaTime;
Ctx.CharacterController.Move(velocity);
}
}
My PlayerAirborneState script is currently set up the same way as PlayerGroundedState, but obviously isn't even switching the substate like I was hoping. If I use the SwitchState function in CheckSwitchStates() it will switch to the jump state, but doing that does not maintain airborne as the superstate. I expect that some of this might have to do with the fact that in my PlayerStateMachine script, the grounded state is initialized as the first current state.
PlayerAirborneState:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAirborneState : PlayerBaseState
{
public PlayerAirborneState(PlayerStateMachine currentContext, PlayerStateFactory playerStateFactory)
: base(currentContext, playerStateFactory)
{
IsRootState = true;
}
public override void EnterState()
{
Debug.Log("Airborne State Entered");
Ctx.Animator.SetBool("isJumping", true);
InitializeSubstate();
}
public override void UpdateState()
{
HandleAirMovement();
CheckSwitchStates();
}
public override void ExitState()
{
Debug.Log("Airborne State exited");
Ctx.Animator.SetBool("isJumping", false);
}
public override void InitializeSubstate()
{
if (Ctx.WasJumpPressed || Ctx.YSpeed > 0)
{
SetSubState(Factory.Jump());
}
else
{
SetSubState(Factory.Falling());
}
}
public override void CheckSwitchStates()
{
if (Time.time - Ctx.LastGroundedTime <= Ctx.JumpButtonGracePeriod)
{
SwitchState(Factory.Grounded());
}
//if (Ctx.WasJumpPressed || Ctx.YSpeed > 0)
//{
// SwitchState(Factory.Jump());
//}
//else
//{
// SwitchState(Factory.Falling());
//}
}
void HandleAirMovement()
{
Ctx.LastGroundedTime = null;
if (Ctx.WasJumpPressed)
{
Ctx.YSpeed = Ctx.JumpSpeed;
}
Vector3 airVelocity;
airVelocity = Ctx.BetterMoveVector.normalized * Ctx.InputMagnitude * Ctx.JumpHorizontalSpeed;
airVelocity.y = Ctx.YSpeed;
Ctx.CharacterController.Move(airVelocity * Time.deltaTime);
}
}
And my PlayerStateMachine script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerStateMachine : MonoBehaviour
{
// input booleans (iHeartGameDev tutorial)
bool _isJumpPressed = false;
bool _isMovementPressed;
// constants (iHeartGameDev)
float _rotationFactorPerFrame = 15;
public ParticleSystem jetFire1;
public ParticleSystem jetFire2;
public PlayerInventory playerInventory;
[SerializeField] float _rotationSpeed;
[SerializeField] float _turnSmoothTime;
[SerializeField] float _jumpSpeed;
[SerializeField] float _jumpButtonGracePeriod;
[SerializeField] float _jetForce;
[SerializeField] float _jumpHorizontalSpeed;
[SerializeField] float _boostSpeed;
[SerializeField] float _boostTime;
[SerializeField] float _wallJumpBuffer;
[SerializeField] float _wallJumpForce;
[SerializeField] Transform _cameraTransform;
CharacterController _characterController;
Animator _animator;
CapsuleCollider _capsuleCollider;
float _ySpeed;
float _inputMagnitude;
float? _jumpButtonPressedTime;
float? _lastGroundedTime;
float _origStepOffset;
float _wallJumpStartTime;
bool _touchingWall;
bool _wallJumpStarted;
bool _raycastIsGrounded;
bool _wasJumpPressed;
Vector2 _moveVector2;
Vector3 _betterMoveVector;
Vector3 _moveDirection;
Vector3 _wallJumpNormal;
//Vector3 _airVelocity;
// state variables
PlayerBaseState _currentState;
PlayerStateFactory _states;
// getters and setters
public PlayerBaseState CurrentState { get { return _currentState; } set { _currentState = value; } }
public CharacterController CharacterController { get { return _characterController; } }
public Animator Animator { get { return _animator; } }
public CapsuleCollider CapsuleCollider { get { return _capsuleCollider; } }
public float JumpButtonGracePeriod { get { return _jumpButtonGracePeriod; } }
public float YSpeed { get { return _ySpeed; } set { _ySpeed = value; } }
public float JumpSpeed { get { return _jumpSpeed; } }
public float OrigStepOffset { get { return _origStepOffset; } }
public float InputMagnitude { get { return _inputMagnitude; } }
public float JumpHorizontalSpeed { get { return _jumpHorizontalSpeed; } }
public float? JumpButtonPressedTime { get { return _jumpButtonPressedTime; } set { _jumpButtonPressedTime = value; } }
public float? LastGroundedTime { get { return _lastGroundedTime; } set { _lastGroundedTime = value; } }
public bool IsJumpPressed { get { return _isJumpPressed; } }
public bool WasJumpPressed { get { return _wasJumpPressed; } set { _wasJumpPressed = value; } }
public bool IsMovementPressed { get { return _isMovementPressed; } }
public bool RaycastIsGrounded { get { return _raycastIsGrounded; } }
public Vector2 MoveVector2 { get { return _moveVector2; } set { _moveVector2 = value; } }
public Vector3 BetterMoveVector { get { return _betterMoveVector; } set { _betterMoveVector = value; } }
//public Vector3 AirVelocity { get { return _airVelocity; } set { _airVelocity = value; } }
private void Awake()
{
_characterController = GetComponent<CharacterController>();
_animator = GetComponent<Animator>();
_capsuleCollider = GetComponent<CapsuleCollider>();
_ySpeed = -1;
// setup state
_states = new PlayerStateFactory(this);
_currentState = _states.Grounded();
_currentState.EnterState();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
_currentState.UpdateStates();
//_ySpeed += (Physics.gravity.y * Time.deltaTime);
RaycastGroundCheck();
_animator.SetFloat("Input Magnitude", _inputMagnitude, 0.05f, Time.deltaTime);
// set movement vector to inputs
_betterMoveVector.x = MoveVector2.x;
_betterMoveVector.z = MoveVector2.y;
HandleRotation();
}
void HandleRotation()
{
// move in direction of camera
_betterMoveVector = Quaternion.AngleAxis(_cameraTransform.rotation.eulerAngles.y, Vector3.up) * _betterMoveVector;
_betterMoveVector.Normalize();
// the current rotation of our character
Quaternion currentRotation = transform.rotation;
if (_isMovementPressed)
{
// creates a new rotation based on where the player is currently pressing
Quaternion targetRotation = Quaternion.LookRotation(_betterMoveVector, Vector3.up);
// rotate the character to face the positionToLookAt
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, _rotationFactorPerFrame * Time.deltaTime);
}
}
void RaycastGroundCheck()
{
float extraHeight = 0.1f;
if (Physics.Raycast(_capsuleCollider.bounds.center, Vector3.down, CapsuleCollider.bounds.extents.y + extraHeight))
{
_raycastIsGrounded = true;
}
else
{
_raycastIsGrounded = false;
}
}
//input functions
public void JumpFunction(InputAction.CallbackContext context)
{
_isJumpPressed = context.ReadValueAsButton();
_jumpButtonPressedTime = Time.time;
}
public void MoveFunction(InputAction.CallbackContext context)
{
if (context.performed || context.started)
{
Debug.Log("Movement!");
_moveVector2 = context.ReadValue<Vector2>();
//Debug.Log("_moveVector2: " + _moveVector2);
_inputMagnitude = _moveVector2.magnitude;
_isMovementPressed = _inputMagnitude != 0;
_moveVector2.Normalize();
}
else
{
Debug.Log("movement exited");
_moveVector2 = Vector2.zero;
_isMovementPressed = false;
}
}
public void JetUpFunction(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("Jet Up performed");
}
}
public void JetBoostFunction(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("Forward Boost performed");
}
}
public void DebugCurrentStates(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("Current State: " + _currentState);
}
}
}
This is my first Unity project as well as my first question on SO, so apologies for my newbiness on both accounts.
I am in a game jam and I have been creating a conversion script. I made a base Interact virtual void In Unity in which each interactable will use public override void Interact() and do whatever is needed. My problem is that when I call Interact() in one my scripts only main function is being called and not the overriding function. I am using Unity 2017, Csharp.
Base Interaction Script
using UnityEngine.AI;
using UnityEngine;
public class Interactable : MonoBehaviour {
private NavMeshAgent NavAgent;
private bool isInteracting;
public virtual void MoveToLocation(NavMeshAgent navMesh)
{
isInteracting = false;
this.NavAgent = navMesh;
NavAgent.stoppingDistance = 4;
NavAgent.destination = transform.position;
}
private void Update()
{
if(!isInteracting && NavAgent != null && !NavAgent.pathPending)
{
if(NavAgent.remainingDistance <= NavAgent.stoppingDistance)
{
Interact();
Debug.Log("Moving To Interactable");
isInteracting = true;
}
else
{
isInteracting = false;
}
}
}
public virtual void Interact()
{
Debug.Log("herro");
}
}
NPC Interaction Script
using UnityEngine.UI;
using UnityEngine;
public class NPC : Interactable {
//Setting Up Conversation Var
public string NPCName;
public string[] Conversation;
private int currentConversation;
//Gettig=ng UI
public CanvasGroup ConversationUI;
public Text Title;
public Text Text;
private void Start()
{
currentConversation = 0;
}
public override void Interact()
{
Debug.Log("Interacting With NPC");
//Opening UI
ConversationUI.alpha = 1;
ConversationUI.interactable = true;
ConversationUI.blocksRaycasts = true;
//Setting Up Name
Title.text = NPCName;
Text.text = Conversation[currentConversation];
}
public void NextConv()
{
currentConversation++;
if (currentConversation >= Conversation.Length)
{
ConversationUI.alpha = 0;
ConversationUI.interactable = false;
ConversationUI.blocksRaycasts = false;
}
else if (currentConversation < Conversation.Length)
{
Text.text = Conversation[currentConversation];
}
}
}