i'm making a door (similiar to the Doom 64's ones) and i have this code:
public class aperturaPorta : MonoBehaviour
{
public Transform playerCheck;
public Vector3 halfSize = new Vector3 (3f, 3f, 0.5f);
public LayerMask playerLayer;
bool playerEntering = false;
public BoxCollider collider;
public MeshRenderer renderer;
bool aprendo = false;
bool chiudendo = false;
public float openSpeed;
int counter = 1;
public int tick = 99;
// Update is called once per frame
void Update()
{
playerEntering = Physics.CheckBox(playerCheck.position, halfSize, Quaternion.identity, playerLayer, QueryTriggerInteraction.UseGlobal);
if (playerEntering && Input.GetButtonDown("e")) {
aprendo = true;
chiudendo = false;
}
if (counter == 100) {
chiudendo = true;
}
if (aprendo) {
transform.position += new Vector3 (0f, openSpeed, 0f);
counter += 1;
if (counter > tick) {
aprendo = false;
chiudendo = true;
}
}
if (chiudendo) {
transform.position -= new Vector3 (0f, openSpeed, 0f);
counter -= 1;
if (counter < 1) {
chiudendo = false;
}
}
}
}
This work but the door start closing when it finishes openening but it's too fast so i want to implement a two or three seconds stopwatch so that when it finishes the door start closing, how can i do it? thank you
ps: excuse me but i'm a newbie in unity
If I understand correctly you want a simple delay when the door is open before it closes? Keeping the same code structure you can add an other counter for that.
public float openSpeed;
int counter = 1;
public int tick = 99;
public int delayTicks = 100;
private int delayCounter = 0;
// Update is called once per frame
void Update()
{
playerEntering = Physics.CheckBox(playerCheck.position, halfSize, Quaternion.identity, playerLayer, QueryTriggerInteraction.UseGlobal);
if (playerEntering && Input.GetKeyDown(KeyCode.P))
{
aprendo = true;
chiudendo = false;
}
if (counter == 100)
{
chiudendo = true;
}
if (aprendo)
{
transform.position += new Vector3(0f, openSpeed, 0f);
counter += 1;
if (counter > tick)
{
delayCounter = delayTicks;
aprendo = false;
}
}
if (delayCounter > 0)
{
delayCounter--;
if (delayCounter <= 0)
{
chiudendo = true;
}
}
else if (chiudendo)
{
transform.position -= new Vector3(0f, openSpeed, 0f);
counter -= 1;
if (counter < 1)
{
chiudendo = false;
}
}
}
Related
So I am trying to create a game where a player can swing with a rope/grappling hook, similar to a game like Teeworlds. The grappling hook feels great when I am hooked onto things and I am using my movement keys, the problem comes when I let go of my left or right movement keys the character slowly floats down. Feels like the gravity gets put to like 0.00001 on the character until i let go of the grappling hook button.
Will post a gif of how it looks and the code I am using for the grappling hook.
Thanks,
The Pepsidi.
Game Play of Issue
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class GrappleSystem : MonoBehaviour
{
public GameObject grappleAnchor;
public DistanceJoint2D grappleJoint;
public Transform crosshair;
public PlayerMovement playerMovement;
private bool grappleAttached;
private Vector2 playerPosition;
private Rigidbody2D grappleAnchorRb;
private SpriteRenderer grappleAnchorSprite;
public LineRenderer grappleRenderer;
public LayerMask grappleLayerMask;
private float grappleMaxCastDistance = 20f;
private List<Vector2> grapplePositions = new List<Vector2>();
private bool distanceSet;
void Awake()
{
grappleJoint.enabled = false;
playerPosition = transform.position;
grappleAnchorRb = grappleAnchor.GetComponent<Rigidbody2D>();
grappleAnchorSprite = grappleAnchor.GetComponent<SpriteRenderer>();
}
void Update()
{
var worldMousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f));
var facingDirection = worldMousePosition - transform.position;
var aimAngle = Mathf.Atan2(facingDirection.y, facingDirection.x);
if (aimAngle < 0f)
{
aimAngle = Mathf.PI * 2 + aimAngle;
}
var aimDirection = Quaternion.Euler(0, 0, aimAngle * Mathf.Rad2Deg) * Vector2.right;
playerPosition = transform.position;
if (!grappleAttached)
{
SetCrosshairPosition(aimAngle);
}
HandleInput(aimDirection);
UpdateGrapplePositions();
}
private void SetCrosshairPosition(float aimAngle)
{
var x = transform.position.x + 5f * Mathf.Cos(aimAngle);
var y = transform.position.y + 5f * Mathf.Sin(aimAngle);
var crossHairPosition = new Vector3(x, y, 0);
crosshair.transform.position = crossHairPosition;
}
private void HandleInput(Vector2 aimDirection)
{
if (Input.GetMouseButtonDown(1))
{
if (grappleAttached) return;
grappleRenderer.enabled = true;
var hit = Physics2D.Raycast(playerPosition, aimDirection, grappleMaxCastDistance, grappleLayerMask);
if (hit.collider != null)
{
grappleAttached = true;
if (!grapplePositions.Contains(hit.point))
{
transform.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, 5f), ForceMode2D.Force);
grapplePositions.Add(hit.point);
grappleJoint.distance = Vector2.Distance(playerPosition, hit.point);
grappleJoint.enabled = true;
grappleAnchorSprite.enabled = true;
}
}
else
{
grappleRenderer.enabled = false;
grappleAttached = false;
grappleJoint.enabled = false;
}
}
if (Input.GetMouseButtonUp(1))
{
ResetGrapple();
}
}
private void ResetGrapple()
{
grappleJoint.enabled = false;
grappleAttached = false;
//playerMovement.isSwinging = false;
grappleRenderer.positionCount = 2;
grappleRenderer.SetPosition(0, transform.position);
grappleRenderer.SetPosition(1, transform.position);
grapplePositions.Clear();
grappleAnchorSprite.enabled = false;
}
private void UpdateGrapplePositions()
{
if (!grappleAttached)
{
return;
}
grappleRenderer.positionCount = grapplePositions.Count + 1;
for (var i = grappleRenderer.positionCount - 1; i >= 0; i--)
{
if (i != grappleRenderer.positionCount - 1)
{
grappleRenderer.SetPosition(i, grapplePositions[i]);
if (i == grapplePositions.Count - 1 || grapplePositions.Count == 1)
{
var grapplePosition = grapplePositions[grapplePositions.Count - 1];
if (grapplePositions.Count == 1)
{
grappleAnchorRb.transform.position = grapplePosition;
if (!distanceSet)
{
grappleJoint.distance = Vector2.Distance(transform.position, grapplePosition);
distanceSet = true;
}
}
else
{
grappleAnchorRb.transform.position = grapplePosition;
if (!distanceSet)
{
grappleJoint.distance = Vector2.Distance(transform.position, grapplePosition);
distanceSet = true;
}
}
}
else if (i - 1 == grapplePositions.IndexOf(grapplePositions.Last()))
{
var grapplePosition = grapplePositions.Last();
grappleAnchorRb.transform.position = grapplePosition;
if (!distanceSet)
{
grappleJoint.distance = Vector2.Distance(transform.position, grapplePosition);
distanceSet = true;
}
}
}
else
{
grappleRenderer.SetPosition(i, transform.position);
}
}
}
}
So, I started following a tutorial and then added some other things that I needed and everything works fine, even the recoil, but the problem is that it is really choppy, it moves once a frame and it isn't smooth at all (which is what I want) I don't know a lot about programming so I hope you can help me :)
My code:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Audio;
public class GunController : MonoBehaviour
{
[Header("Gun Setting")]
public float fireRate = 0.1f;
public int clipSize = 30;
public int reservedAmmoCapacity = 270;
//Variables that change throughout the code
bool canShoot;
int _currentAmmoInClip;
int _ammoInReserve;
//Muzzle Flash
public ParticleSystem muzzleFlash;
//Aiming
public Vector3 normalLocalPosition;
public Vector3 aimingLocalPosition;
public float aimSmoothing = 10;
[Header("Mouse Settings")]
public float mouseSensitivity = 1;
Vector2 _currentRotation;
public float weaponSwayAmount = 10;
//Weapon Recoil
public bool randomizeRecoil;
public Vector2 randomRecoilConstraints;
//You only need to assign if randomize recoil is off
public Vector2[] recoilPattern;
//Audio
AudioSource shootingSound;
//Reloading
public float reloadTime = 1.5f;
private void Start()
{
_currentAmmoInClip = clipSize;
_ammoInReserve = reservedAmmoCapacity;
canShoot = true;
shootingSound = GetComponent<AudioSource>();
}
private void Update()
{
DetermineAim();
DetermineRotation();
if (Input.GetMouseButton(0) && canShoot && _currentAmmoInClip > 0)
{
shootingSound.Play();
StartCoroutine(FinishShooting());
muzzleFlash.Play();
canShoot = false;
_currentAmmoInClip--;
StartCoroutine(ShootGun());
}
else if (Input.GetKeyDown(KeyCode.R) && _currentAmmoInClip < clipSize && _ammoInReserve > 0)
{
StartCoroutine(Reload());
}
}
void DetermineRotation()
{
Vector2 mouseAxis = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
mouseAxis *= mouseSensitivity;
_currentRotation += mouseAxis;
_currentRotation.y = Mathf.Clamp(_currentRotation.y, -90, 90);
transform.localPosition += (Vector3)mouseAxis * weaponSwayAmount / 1000;
transform.root.localRotation = Quaternion.AngleAxis(_currentRotation.x, Vector3.up);
transform.parent.localRotation = Quaternion.AngleAxis(-_currentRotation.y, Vector3.right);
}
void DetermineAim()
{
Vector3 target = normalLocalPosition;
if (Input.GetMouseButton(1)) target = aimingLocalPosition;
Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing);
transform.localPosition = desiredPosition;
}
void DetermineRecoil()
{
transform.localPosition -= Vector3.forward * 0.1f;
if (randomizeRecoil)
{
float xRecoil = Random.Range(-randomRecoilConstraints.x, randomRecoilConstraints.x);
float yRecoil = Random.Range(-randomRecoilConstraints.y, randomRecoilConstraints.y);
Vector2 recoil = new Vector2(xRecoil, yRecoil);
_currentRotation += recoil;
}
else
{
int currentStep = clipSize + 1 - _currentAmmoInClip;
currentStep = Mathf.Clamp(currentStep, 0, recoilPattern.Length - 1);
_currentRotation += recoilPattern[currentStep];
}
}
IEnumerator ShootGun()
{
_currentAmmoInClip -= 1;
DetermineRecoil();
RayCastEnemy();
yield return new WaitForSeconds(fireRate);
canShoot = true;
}
void RayCastEnemy()
{
RaycastHit hit;
if (Physics.Raycast(transform.parent.position, transform.parent.forward, out hit, 1 << LayerMask.NameToLayer("Enemy")))
{
try
{
Debug.Log("Hit an enemy");
Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
rb.constraints = RigidbodyConstraints.None;
rb.AddForce(transform.parent.transform.forward * 50);
}
catch { }
}
}
IEnumerator FinishShooting()
{
yield return new WaitForSeconds(0.3f);
shootingSound.Stop();
}
IEnumerator Reload()
{
canShoot = false;
yield return new WaitForSeconds(reloadTime);
int amountNeeded = clipSize - _currentAmmoInClip;
if (amountNeeded > _ammoInReserve)
{
_currentAmmoInClip += _ammoInReserve;
_ammoInReserve -= amountNeeded;
canShoot = true;
}
else
{
canShoot = false;
_currentAmmoInClip = clipSize;
_ammoInReserve -= amountNeeded;
canShoot = true;
}
}
}
I don't see the function DetermineRecoil() called anywhere in the code, but maybe this solution will work:
let _currentRotation = Vector2.Lerp(_currentRotation, _currentRotation + recoilPattern[currentStep], 10*Time.deltaTime);
It will change the value of _currentRotation smoothly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DetectCollision : MonoBehaviour
{
public Transform player;
public Transform target;
public bool turnOnOffPlayerAnimator = false;
float timeElapsed = 0;
float lerpDuration = 3;
float startValue = 1;
float endValue = 0;
float valueToLerp = 0;
private Animator playerAnimator;
private bool entered = false;
private bool resetElapsed = false;
// Start is called before the first frame update
void Start()
{
playerAnimator = player.GetComponent<Animator>();
if (turnOnOffPlayerAnimator)
playerAnimator.enabled = false;
}
// Update is called once per frame
void Update()
{
if (IsFacing(target))
{
if (entered)
{
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
}
}
else
{
if (valueToLerp < 0.9f)
{
if(resetElapsed == false)
{
timeElapsed = 0;
resetElapsed = true;
}
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
}
}
if(turnOnOffPlayerAnimator)
{
playerAnimator.enabled = false;
}
else
{
playerAnimator.enabled = true;
}
}
private void OnTriggerEnter(Collider other)
{
entered = true;
Debug.Log("Entered !");
}
private void OnTriggerExit(Collider other)
{
entered = false;
Debug.Log("Exited !");
}
private bool IsFacing(Transform target)
{
Vector3 forward = player.TransformDirection(Vector3.forward);
Vector3 toTarget = target.position - player.position;
return Vector3.Dot(forward, toTarget) > 0;
}
}
I reset it once back to value 0 in this part :
if(resetElapsed == false)
{
timeElapsed = 0;
resetElapsed = true;
}
but it also working only once.
I need somehow to reset the value to 0 each time the player is switching direction facing or not facing the target but not sure where and how to do it in the Update.
if not resetting it to 0 when the player will not facing the target or will face it after not facing again the value of timeElapsed is bigger then the lerpDuration value.
You could store the result of your IsFacing() method in a field and check in the next update run if it's has still the same value.
Simple example:
private bool prevFacing = false;
void Update() {
var currFacing = IsFacing(target);
if(currFacing != prevFacing) {
// here you switched from facing to not facing or vise verca.
}
prevFacing = currFacing;
}
I couldn't find a clear double tap script which uses the Unity function Input.GetAxisRaw("Horizontal"). Below is my monstrous solution for the left and right horizontal axis, which took me too many hours... It serves my purpose although it still allows the player to dash in the direction opposite to the movement direction if he has quick fingers.
If anyone can show me a cleaner solution or has some advice it would be greatly appreciated?
Preferably a solution which can easily be implemented for other axis as well.
If anyone know of a standard unity function which could provide the same double tap behavior, it would be even better.
If you attach the script to a cube you can see the double tap behavior i am looking for.
The attached image shows the logic signal of the double tap behavior.
Logic signal of Double Tap
using System.Collections;
using UnityEngine;
public class DoubleTap : MonoBehaviour
{
float translationSpeedX = 20;
float translationSpeedY = 20;
Vector3 playerPosition;
float maxKeyDownTime = 0.2f;
float maxKeyUpTime = 0.2f;
float delayBetweenDoubleTaps = 0.4f;
bool doubleTapped = false;
bool firstLeftDown = false;
bool firstLeftUp = false;
bool prevLeftDown = false;
bool firstRightDown = false;
bool firstRightUp = false;
bool prevRightDown = false;
// Start is called before the first frame update
void Start()
{
playerPosition = transform.position;
StartCoroutine(KeyInputBuffer());
}
// Update is called once per frame
void Update()
{
//Take keyboard input and translate the player in X and Y directions
playerPosition.x += Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime;
playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
playerPosition.y += Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime;
playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
transform.position = playerPosition;
//Double tap left
if (firstLeftUp && Input.GetAxisRaw("Horizontal") < 0)
{
Debug.Log("Double Tap Left!");
playerPosition.x -= 10f;
firstLeftDown = false;
firstLeftUp = false;
StartCoroutine(DoubleTapDelayTimer());
}
else if (!firstLeftUp && firstLeftDown && Input.GetAxisRaw("Horizontal") == 0)
{
Debug.Log("firstLeftUp Left!");
firstLeftUp = true;
StartCoroutine(KeyUpTimer());
}
else if (!doubleTapped && !firstLeftDown && !prevLeftDown && Input.GetAxisRaw("Horizontal") < 0)
{
Debug.Log("firstLeftDown Left!");
firstLeftDown = true;
StartCoroutine(KeyDownTimer());
}
//Double tap right
if (firstRightUp && Input.GetAxisRaw("Horizontal") > 0)
{
Debug.Log("Double Tap Right!");
playerPosition.x += 10f;
firstRightDown = false;
firstRightUp = false;
StartCoroutine(DoubleTapDelayTimer());
}
else if (!firstRightUp && firstRightDown && Input.GetAxisRaw("Horizontal") == 0)
{
Debug.Log("firstRightUp Right!");
firstRightUp = true;
StartCoroutine(KeyRightUpTimer());
}
else if (!doubleTapped && !firstRightDown && !prevRightDown && Input.GetAxisRaw("Horizontal") > 0)
{
Debug.Log("firstRightDown Right!");
firstRightDown = true;
StartCoroutine(KeyRightDownTimer());
}
}
//Timer which controlls the minimun time between double taps
IEnumerator DoubleTapDelayTimer()
{
doubleTapped = true;
yield return new WaitForSeconds(delayBetweenDoubleTaps);
doubleTapped = false;
}
//Timers for the left horizontal axis
IEnumerator KeyDownTimer()
{
yield return new WaitForSeconds(maxKeyDownTime);
firstLeftDown = false;
}
IEnumerator KeyUpTimer()
{
yield return new WaitForSeconds(maxKeyUpTime);
firstLeftUp = false;
}
//Timers for the right horizontal axis
IEnumerator KeyRightDownTimer()
{
yield return new WaitForSeconds(maxKeyDownTime);
firstRightDown = false;
}
IEnumerator KeyRightUpTimer()
{
yield return new WaitForSeconds(maxKeyUpTime);
firstRightUp = false;
}
//Store the raw input conditions for the horizontal axis as reference in next frame
IEnumerator KeyInputBuffer()
{
while(true)
{
yield return new WaitForEndOfFrame();
if (Input.GetAxisRaw("Horizontal") > 0)
{
prevLeftDown = false;
prevRightDown = true;
}
else if (Input.GetAxisRaw("Horizontal") < 0)
{
prevLeftDown = true;
prevRightDown = false;
}
else
{
prevLeftDown = false;
prevRightDown = false;
}
}
}}
Below is the improved (and debugged) code as proposed by derHUGO.
I am really amazed how much code is required for so little functionality.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Axis
{
X,
Y
}
public enum AxisDirection
{
Right,
Left,
Up,
Down
}
public class DoubleTap : MonoBehaviour //StackOverFlow
{
// With [SerializeField] these are now configured directly via the Inspector
// in unity without having to recompile
// This way you can play with them in Playmode until you have the values the fit your needs
// For restring to the defaults simply hit Reset in the Context menu of the component
[SerializeField] private float translationSpeedX = 20;
[SerializeField] private float translationSpeedY = 20;
[SerializeField] private float maxKeyDownTime = 0.2f;
[SerializeField] private float maxKeyUpTime = 0.2f;
[SerializeField] private float delayBetweenDoubleTaps = 0.4f;
private Dictionary<Axis, string> axisName = new Dictionary<Axis, string>
{
{Axis.X, "Horizontal"},
{Axis.Y, "Vertical"}
};
private Dictionary<Axis, AxisDirection> axisPositive = new Dictionary<Axis, AxisDirection>
{
{Axis.X, AxisDirection.Right},
{Axis.Y, AxisDirection.Up}
};
private Dictionary<Axis, AxisDirection> axisNegative = new Dictionary<Axis, AxisDirection>
{
{Axis.X, AxisDirection.Left},
{Axis.Y, AxisDirection.Down}
};
private Vector3 playerPosition;
private bool doubleTapped = false;
private Dictionary<AxisDirection, bool> axisFirstDown = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisFirstUp = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisPrevDown = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, Action> doubleTapActions = new Dictionary<AxisDirection, Action>(); //MOD
// Start is called before the first frame update
private void Start()
{
doubleTapActions.Add(AxisDirection.Left, LeftDoubleTapAction); //MOD
doubleTapActions.Add(AxisDirection.Right, RightDoubleTapAction);//MOD
doubleTapActions.Add(AxisDirection.Up, UpDoubleTapAction); //MOD
doubleTapActions.Add(AxisDirection.Down, DownDoubleTapAction); //MOD
foreach (var axis in (AxisDirection[])Enum.GetValues(typeof(AxisDirection)))
{
axisFirstDown.Add(axis, false);
axisFirstUp.Add(axis, false);
axisPrevDown.Add(axis, false);
}
playerPosition = transform.position;
StartCoroutine(KeyInputBuffer());
}
// Update is called once per frame
private void Update()
{
foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
{
// positive
if (axisFirstUp[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0) //MOD axisFirstUp || axisFirstDown
{
Debug.Log($"Double Tap {axisPositive[axis]}!");
doubleTapActions[axisPositive[axis]].Invoke(); //MOD
axisFirstDown[axisPositive[axis]] = false;
axisFirstUp[axisPositive[axis]] = false;
StartCoroutine(DoubleTapDelayTimer());
return;
}
else if (!axisFirstUp[axisPositive[axis]] && axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
{
Debug.Log($"firstUp {axisPositive[axis]}!");
axisFirstUp[axisPositive[axis]] = true;
StartCoroutine(KeyUpTimer(axisPositive[axis])); //MOD axisPositive[axis]) || axis
}
else if (!doubleTapped && !axisFirstDown[axisPositive[axis]] && !axisPrevDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
{
Debug.Log($"firstDown {axisPositive[axis]}!");
axisFirstDown[axisPositive[axis]] = true;
StartCoroutine(KeyDownTimer(axisPositive[axis])); //MOD axisPositive[axis]) || axis
}
// negative
if (axisFirstUp[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0) //MOD axisFirstUp || axisFirstDown //MOD2 if || else if
{
Debug.Log($"Double Tap {axisNegative[axis]}!");
doubleTapActions[axisNegative[axis]].Invoke(); //MOD
axisFirstDown[axisNegative[axis]] = false;
axisFirstUp[axisNegative[axis]] = false;
StartCoroutine(DoubleTapDelayTimer());
return;
}
else if (!axisFirstUp[axisNegative[axis]] && axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
{
Debug.Log($"firstUp {axisNegative[axis]}!");
axisFirstUp[axisNegative[axis]] = true;
StartCoroutine(KeyUpTimer(axisNegative[axis])); //MOD axisPositive[axis]) || axis
}
else if (!doubleTapped && !axisFirstDown[axisNegative[axis]] && !axisPrevDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
{
Debug.Log($"firstDown {axisNegative[axis]}!");
axisFirstDown[axisNegative[axis]] = true;
StartCoroutine(KeyDownTimer(axisNegative[axis])); //MOD axisPositive[axis]) || axis
}
}
// Do only process the input as movement if there was no double tap this frame
//Take keyboard input and translate the player in X and Y directions
playerPosition.x += Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime; //MOD || UnityEgine.
playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
playerPosition.y += Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime; //MOD || UnityEgine.
playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
transform.position = playerPosition;
Debug.Log("update");
}
//Timer which controlls the minimun time between double taps
IEnumerator DoubleTapDelayTimer()
{
doubleTapped = true;
yield return new WaitForSeconds(delayBetweenDoubleTaps);
doubleTapped = false;
}
//Timers for the axis
IEnumerator KeyDownTimer(AxisDirection axis)
{
yield return new WaitForSeconds(maxKeyDownTime);
axisFirstDown[axis] = false;
}
IEnumerator KeyUpTimer(AxisDirection axis)
{
yield return new WaitForSeconds(maxKeyUpTime);
axisFirstUp[axis] = false;
}
//Store the raw input conditions for the horizontal axis as reference in next frame
IEnumerator KeyInputBuffer()
{
while (true)
{
Debug.Log("coroutine");
yield return new WaitForEndOfFrame();
foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
{
axisPrevDown[axisPositive[axis]] = false;
axisPrevDown[axisNegative[axis]] = false;
if (Input.GetAxisRaw(axisName[axis]) > 0) //MOD || UnityEgine.
{
axisPrevDown[axisPositive[axis]] = true;
}
else if (Input.GetAxisRaw(axisName[axis]) < 0) //MOD || UnityEgine.
{
axisPrevDown[axisNegative[axis]] = true;
}
}
}
}
//Double tap actions
private void LeftDoubleTapAction()
{
playerPosition.x -= 10f;
}
private void RightDoubleTapAction()
{
playerPosition.x += 10f;
}
private void UpDoubleTapAction()
{
playerPosition.y += 10f;
}
private void DownDoubleTapAction()
{
playerPosition.y -= 10f;
}
}
One thing might be to use proper Dictionaries for your bools etc and an enum for the axes so you don't have to implement the same thing multiple times and can easily add a new axis like e.g.
public enum Axis
{
X,
Y
}
public enum AxisDirection
{
Right,
Left,
Up,
Down
}
public class DoubleTap : MonoBehaviour
{
// With [SerializeField] these are now configured directly via the Inspector
// in unity without having to recompile
// This way you can play with them in Playmode until you have the values the fit your needs
// For restring to the defaults simply hit Reset in the Context menu of the component
[SerializeField] private float translationSpeedX = 20;
[SerializeField] private float translationSpeedY = 20;
[SerializeField] private float maxKeyDownTime = 0.2f;
[SerializeField] private float maxKeyUpTime = 0.2f;
[SerializeField] private float delayBetweenDoubleTaps = 0.4f;
private Dictionary<Axis, string> axisName = new Dictionary<Axis, string>
{
{Axis.X, "Horizontal"},
{Axis.Y, "Vertical"}
};
private Dictionary<Axis, AxisDirection> axisPositive = new Dictionary<Axis, AxisDirection>
{
{Axis.X, AxisDirection.Right},
{Axis.Y, AxisDirection.Up}
};
private Dictionary<Axis, AxisDirection> axisNegative = new Dictionary<Axis, AxisDirection>
{
{Axis.X, AxisDirection.Left},
{Axis.Y, AxisDirection.Down}
};
private Vector3 playerPosition;
private bool doubleTapped = false;
private Dictionary<AxisDirection, bool> axisFirstDown = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisFirstUp = new Dictionary<AxisDirection, bool>();
private Dictionary<AxisDirection, bool> axisPrevDown = new Dictionary<AxisDirection, bool>();
// Start is called before the first frame update
private void Start()
{
// setup dictionaries
foreach (var axis in (AxisDirection[])Enum.GetValues(typeof(AxisDirection)))
{
axisFirstDown.Add(axis, false);
axisFirstUp.Add(axis, false);
axisPrevDown.Add(axis, false);
}
playerPosition = transform.position;
StartCoroutine(KeyInputBuffer());
}
// Update is called once per frame
private void Update()
{
foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
{
// positive
if (axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
{
Debug.Log($"Double Tap {axisPositive[axis]}");
playerPosition.x -= 10f;
axisFirstDown[axisPositive[axis]] = false;
axisFirstUp[axisPositive[axis]] = false;
StartCoroutine(DoubleTapDelayTimer());
return;
}
else if (!axisFirstUp[axisPositive[axis]] && axisFirstDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
{
Debug.Log($"firstUp {axisPositive[axis]}!");
axisFirstUp[axisPositive[axis]] = true;
StartCoroutine(KeyUpTimer(axis));
}
else if (!doubleTapped && !axisFirstDown[axisPositive[axis]] && !axisPrevDown[axisPositive[axis]] && Input.GetAxisRaw(axisName[axis]) > 0)
{
Debug.Log($"firstDown {axisPositive[axis]}!");
axisFirstDown[axisPositive[axis]] = true;
StartCoroutine(KeyDownTimer(axis));
}
// negative
else if (axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
{
Debug.Log($"Double Tap {axisNegative[axis]}");
playerPosition.x -= 10f;
axisFirstDown[axisNegative[axis]] = false;
axisFirstUp[axisNegative[axis]] = false;
StartCoroutine(DoubleTapDelayTimer());
return;
}
else if (!axisFirstUp[axisNegative[axis]] && axisFirstDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) == 0)
{
Debug.Log($"firstUp {axisNegative[axis]}!");
axisFirstUp[axisNegative[axis]] = true;
StartCoroutine(KeyUpTimer(axis));
}
else if (!doubleTapped && !axisFirstDown[axisNegative[axis]] && !axisPrevDown[axisNegative[axis]] && Input.GetAxisRaw(axisName[axis]) < 0)
{
Debug.Log($"firstDown {axisNegative[axis]}!");
axisFirstDown[axisNegative[axis]] = true;
StartCoroutine(KeyDownTimer(axis));
}
}
// Do only process the input as movement if there was no double tap this frame
//Take keyboard input and translate the player in X and Y directions
playerPosition.x += UnityEngine.Input.GetAxis("Horizontal") * translationSpeedX * Time.deltaTime;
playerPosition.x = Mathf.Clamp(playerPosition.x, -100, 100);
playerPosition.y += UnityEngine.Input.GetAxis("Vertical") * translationSpeedY * Time.deltaTime;
playerPosition.y = Mathf.Clamp(playerPosition.y, -100, 100);
transform.position = playerPosition;
}
//Timer which controlls the minimun time between double taps
private IEnumerator DoubleTapDelayTimer()
{
doubleTapped = true;
yield return new WaitForSeconds(delayBetweenDoubleTaps);
doubleTapped = false;
}
//Timers for the axis
private IEnumerator KeyDownTimer(AxisDirection axis)
{
yield return new WaitForSeconds(maxKeyDownTime);
axisFirstDown[axis] = false;
}
private IEnumerator KeyUpTimer(AxisDirection axis)
{
yield return new WaitForSeconds(maxKeyUpTime);
axisFirstUp[axis] = false;
}
//Store the raw input conditions for the horizontal axis as reference in next frame
private IEnumerator KeyInputBuffer()
{
yield return new WaitForEndOfFrame();
foreach (var axis in (Axis[])Enum.GetValues(typeof(Axis)))
{
axisPrevDown[axisPositive[axis]] = false;
axisPrevDown[axisNegative[axis]] = false;
if (UnityEngine.Input.GetAxisRaw(axisName[axis]) > 0)
{
axisPrevDown[axisPositive[axis]] = true;
}
else if (UnityEngine.Input.GetAxisRaw(axisName[axis]) < 0)
{
axisPrevDown[axisNegative[axis]] = true;
}
}
}
}
I am new to Unity. I am playing around with a 2D sidescroller. Here are the features of the script I am trying to write:
Move left and right
Flip character when changing direction
Increase speed to a cap while continuously moving
Currently, the only thing working is Animation transitions. I am not sure what is wrong. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Avatar_Manager : MonoBehaviour {
private Animator anim;
private Rigidbody2D rigidbody2D;
private Transform trans;
private int direction;
private bool moving;
public const float acceleration = 1.0f / 180;
public float horizontal_speed;
public float vertical_speed;
// Use this for initialization
void Start () {
anim = GetComponent<Animator>();
rigidbody2D = GetComponent<Rigidbody2D>();
trans = GetComponent<Transform>();
//Default facing right
direction = 1;
moving = false;
vertical_speed = 0;
}
// Update is called once per frame
void Update () {
//Check direction
if (rigidbody2D.velocity.x < 0)
{
direction = -1;
}
else if (rigidbody2D.velocity.x > 0)
{
direction = 1;
}
// Move right
if (Input.GetKeyDown(KeyCode.D))
{
//Flip Avatar if facing left
if (direction == -1)
{
direction = 1;
trans.rotation.Set(trans.rotation.x, trans.rotation.y + 180, trans.rotation.z, trans.rotation.w);
}
//Start moving
if (!moving)
{
moving = true;
horizontal_speed = 10;
rigidbody2D.velocity = new Vector2(horizontal_speed, vertical_speed);
anim.SetInteger("State", 1);
}
//Update speed
else
{
if(horizontal_speed < 20)
{
horizontal_speed += acceleration;
rigidbody2D.velocity.Set(horizontal_speed, vertical_speed);
}
}
}
//Stop moving right
if (Input.GetKeyUp(KeyCode.D))
{
moving = false;
horizontal_speed = 0;
rigidbody2D.velocity.Set(horizontal_speed, vertical_speed);
anim.SetInteger("State", 0);
}
// Move left
if (Input.GetKeyDown(KeyCode.A))
{
//Flip Avatar if facing right
if (direction == 1)
{
direction = -1;
trans.rotation.Set(trans.rotation.x, trans.rotation.y - 180, trans.rotation.z, trans.rotation.w);
}
//Start moving
if (!moving)
{
moving = true;
horizontal_speed = -10;
rigidbody2D.velocity = new Vector2(horizontal_speed, vertical_speed);
anim.SetInteger("State", 1);
}
//Update speed
else
{
if (horizontal_speed > -20)
{
horizontal_speed -= acceleration;
rigidbody2D.velocity.Set(horizontal_speed, vertical_speed);
}
}
}
//Stop moving right
if (Input.GetKeyUp(KeyCode.A))
{
moving = false;
horizontal_speed = 0;
rigidbody2D.velocity.Set(horizontal_speed, vertical_speed);
anim.SetInteger("State", 0);
}
}
}
change this
if (rigidbody2D.velocity.x < 0)
{
direction = -1;
}
else if (rigidbody2D.velocity.x > 0)
{
direction = 1;
}
to this
if (rigidbody2D.velocity.x < 0)
{
transform.localscale = new Vector3 (-1,1,1);
}
else if (rigidbody2D.velocity.x > 0)
{
transform.localscale = new Vector3 (1,1,1);
}