I am trying to implement two touch functions. One tap and long tap. I have implemented one tap which is pretty straightforward but for a long tap function, a timer must be set?
I would like the long press to be active only after 1 second of holding the tap and then the timer should get reset on release. How do I do this?
public float longTapTime;
void Update()
{
if ((Input.touchCount > 0) && (Input.GetTouch (0).phase == TouchPhase.Began)) {
//One tap
}
if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
{
longTapTime = 0;
}
}
using UnityEngine;
public class example : MonoBehaviour
{
[SerializeField]
private float long_tap_consider_duration = 1.0f;
private float time_helper;
private float duration;
private bool is_touched;
private void Start()
{
time_helper = 0;
duration = 0;
is_touched = false;
}
private void Update()
{
if (Input.touchCount > 0)
ProcessInput();
}
private void ProcessInput()
{
if (is_touched && ((Input.GetTouch(0).phase == TouchPhase.Ended) || (Input.GetTouch(0).phase == TouchPhase.Canceled)))
{
if (duration > long_tap_consider_duration)
OnLongTap();
else OnTap();
}
if (!is_touched && (Input.GetTouch(0).phase == TouchPhase.Began))
{
time_helper = Time.time;
is_touched = true;
}
duration = Time.time - time_helper;
}
//Callback function, when just a short tap occurs
private void OnTap()
{
Debug.Log("Short Tap");
}
//Callback function, when long tap occurs
private void OnLongTap()
{
Debug.Log("Long Tap");
}
}
actually, if you are using the new input system, this is a built in feature and does not need any code.
find your Input Actions ".inputActions"
find the button on the list of inputs registered
with that item selected, find the plus "+" next to the word interactions on the right hand side
add a "hold" interaction from the list and set desired hold time.
for more information on the input action asset system: https://www.youtube.com/watch?v=mvuXOyKz7k4
Related
I'm making a platformer for my A Level programming project where the player automatically jumps on a platform upon touching it. However, I'm having trouble with the collision detection because it only bounces on one platform and falls right through the rest. they all have the same tags so i know that's not the issue.
the way that it's coded is that it will detect collision with any rectangle with the tag 'platform' however it only detects collision with 1 rectangle
Code sample below:
public partial class MainWindow : Window
{
private DispatcherTimer GameTimer = new DispatcherTimer();
private bool LeftKeyPressed, RightKeyPressed, gravity;
double score;
//this value will increase to be 5x the highest Y value so the score increases the higher Meke gets
private float SpeedX, SpeedY, FrictionX = 0.88f, Speed = 1, FrictionY = 0.80f;
//SpeedX controls horizontal movement, SpeedY controls vertical movement
private void Collide(string Dir)
{
foreach (var x in GameScreen.Children.OfType<Rectangle>())
{
if (x.Tag != null)
{
var platformID = (string)x.Tag;
if (platformID == "platform")
{
x.Stroke = Brushes.Black;
Rect MeekHB = new Rect(Canvas.GetLeft(Meek), Canvas.GetTop(Meek), Meek.Width, Meek.Height);
Rect PlatformHB = new Rect(Canvas.GetLeft(x), Canvas.GetTop(x), x.Width, x.Height);
int Jumpcount = 1;
if (MeekHB.IntersectsWith(PlatformHB))
{
if (Dir == "y")
{
while (Jumpcount != 700)
{
gravity = false;
Jumpcount = Jumpcount + 1;
}
}
}
else
{
gravity = true;
}
}
}
}
}
private void KeyboardUp(object sender, KeyEventArgs e)
{
//this is what detects when the 'A' key is being pressed
if (e.Key == Key.A)
{
LeftKeyPressed = false;
}
if (e.Key == Key.D)
{
RightKeyPressed = false;
}
}
private void KeyboardDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.A)
{
LeftKeyPressed = true;
}
if (e.Key == Key.D)
{
RightKeyPressed = true;
}
}
public MainWindow()
{
InitializeComponent();
GameScreen.Focus();
GameTimer.Interval = TimeSpan.FromMilliseconds(16);
GameTimer.Tick += GameTick;
GameTimer.Start();
}
private void GameTick(Object Sender, EventArgs e)
{
txtScore.Content = "Score: " + score;
if (LeftKeyPressed)
{
SpeedX -= Speed;
}
if (RightKeyPressed)
{
SpeedX += Speed;
}
if (gravity == true)
{
SpeedY += Speed;
}
else if (gravity == false)
{
SpeedY -= Speed+50;
}
SpeedX = SpeedX * FrictionX;
SpeedY = SpeedY * FrictionY;
Canvas.SetLeft(Meek, Canvas.GetLeft(Meek) + SpeedX);
Collide("x");
Canvas.SetTop(Meek, Canvas.GetTop(Meek) + SpeedY);
Collide("y");
double maxY = 0;
if (Canvas.GetBottom(Meek) > maxY)
{
maxY = Canvas.GetBottom(Meek);
}
score = maxY;
}
}
}
I think there is an error in your gravity = true logic. You make check for intersections in loop for all platforms, so even if first platform in loop sets gravity to false, next platform in loop will set gravity to true again and logic won't work. As far as I understand, your logic works only to detect last platform in GameScreen.Children.OfType(). Maybe try to break; you loop after you found an intersection.
And for future - add some logs to your app to be able to debug such issues. Most likely your game library provide some ways to print debug messages - add them to your code so you can see, what's going on.
And also your while (Jumpcount != 700) loop looks useless
I'm making a game and I want jumping to feel like jumping in Super Mario Bros. I'm able to get the result I want with a Keyboard or a Controller because they have KeyDown, Key (While pressed), and KeyUp. But touchButtons only have a single boolean. (Pressed or Not Pressed) Is there a way I can work around this?
I tried using Input.GetTouch and using the begin and end phase, this gave the correct result but I'm not sure how to implement it into a GUI button.
The code I'm using has a GUI button with a script that when the button is pressed, joybutton.Pressed = true
void PlayerJump()
{
bool canJump = charController.isGrounded;
//Button Pressed start jumpDuration
if (joybutton.Pressed && canJump)
{
isJumping = true;
jumpDuration = jumpTime;
}
if (isJumping == true)
{
if (jumpDuration > 0)
{
vertical_Velocity = jump_Force;
jumpDuration -= Time.deltaTime;
}
//timer runs out
else
{
isJumping = false;
}
}
//cancel jump if mid-air
if (!joybutton.Pressed)
{
isJumping = false;
}
}
I have no way of stopping the player from jumping as soon as they land with the GUI touchButton. I get desired results with keyboard and gamepad buttons.
Add a variable to remember the state of the button last frame. That way, you can enter the jump start block only if it's the first frame of the button being hit:
private bool wasJumpPressedLastFrame = false;
void PlayerJump()
{
bool canJump = charController.isGrounded;
//Button Pressed start jumpDuration
if (joybutton.Pressed && canJump && !wasJumpPressedLastFrame )
{
isJumping = true;
jumpDuration = jumpTime;
}
if (isJumping == true)
{
if (jumpDuration > 0)
{
vertical_Velocity = jump_Force;
jumpDuration -= Time.deltaTime;
}
//timer runs out
else
{
isJumping = false;
}
}
//cancel jump if mid-air
if (!joybutton.Pressed)
{
isJumping = false;
}
wasJumpPressedLastFrame = joyButton.Pressed;
}
I am new here and I'm beginning my adventure with UNITY. I have problem with double click event. I'd like to buying or selling something in my shop. When I assign a button on unity (public Button button;) earlier it works. But when i try this change to button on Start and Update methods:
void Start () {
button = GameObject.Find(EventSystem.current.currentSelectedGameObject.name).GetComponent<Button>();
button.onClick.AddListener(ButtonListner);
}
void Update()
{
button = GameObject.Find(EventSystem.current.currentSelectedGameObject.name).GetComponent<Button>();
}
private void ButtonListner()
{
counter++;
if (counter == 1)
{
StartCoroutine("doubleClickEvent");
}
}
IEnumerator doubleClickEvent()
{
yield return new WaitForSeconds(clickTimer);
if (counter > 1)
{...}
the method doubleClickEvent() doesnt work unfortunately...
What shall I do? Regards ;)
First thing I noticed was: button = GameObject.Find(EventSystem.current.currentSelectedGameObject.name).GetComponent<Button>();
The EventSystem.current.currentSelectedGameObject property can be null at anytime especially in the first frame which means that using it in the Start function is not a good idea. Find the Button GameObject then get the Button component from it:
Button button;
void Start()
{
button = GameObject.Find("YourButtonName").GetComponent<Button>();
button.onClick.AddListener(ButtonListner);
}
Replace "YourButtonName" with the name of your Button GameObject.
You don't even need to do most of the stuff you did. You can get double click or click count with PointerEventData.clickCount from the OnPointerClick function. You must implement the IPointerClickHandler interface for this to work.
Simply attach to the Button GameObject:
public class ClickCountDetector : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
int clickCount = eventData.clickCount;
if (clickCount == 1)
OnSingleClick();
else if (clickCount == 2)
OnDoubleClick();
else if (clickCount > 2)
OnMultiClick();
}
void OnSingleClick()
{
Debug.Log("Single Clicked");
}
void OnDoubleClick()
{
Debug.Log("Double Clicked");
}
void OnMultiClick()
{
Debug.Log("MultiClick Clicked");
}
}
You can detect double click without a coroutine like the following:
// Choose the time you want between clicks to consider it a double click
float doubleClickTime = .2f, lastClickTime;
void Update()
{
// Checking left mouse button click, you could choose the input you want here
if (Input.GetMouseButtonDown(0))
{
float timeSinceLastClick = Time.time - lastClickTime;
if (timeSinceLastClick <= doubleClickTime)
Debug.Log("Double click");
else
Debug.Log("Normal click");
lastClickTime = Time.time;
}
}
I'm developing in Unity, C#, and I have a bit of code that checks for player activity based on mouse position and it's working well but I'm needing to also check player activity on a touchscreen (not a mobile phone touchscreen, but a touchscreen attached to a pc). How should I modify the code that I have below to also work with touch?
private void Start()
{
InvokeRepeating("LastMousePosition", 0, _checkMousePositionTimingInterval);
}
private void Update()
{
_currentMousePosition = Input.mousePosition;
}
void LastMousePosition()
{
_prevMousePosition = Input.mousePosition;
}
void CheckPlayerIdle()
{
if (_currentMousePosition != _prevMousePosition)
UserActive = true;
else if (_currentMousePosition == _prevMousePosition)
UserActive = false;
}
Well for touch you start your inactivity timer if you don't get any touch inputs and wait for x duration.
for eg:
private void Update()
{
if(Input.touchCount == 0)
{
if(!checkingForInactivity)
{
checkingForInactivity = true;
myRoutine = StartCoroutine(CheckForInactivity());
}
}
else
{
if(checkingForInactivity) StopCoroutine(myRoutine);
}
}
Ienumrable CheckForInactivity()
{
yield new waitForSecond(3.0f);
//user is inactive
}
}
I almost have a working radio, where the player can walk up to it, press a button and cycle through songs. Everything works except for that with each button press the new song will play but the original will continue to play underneath it. For each new song that is played a new object is created but they are all called 'One Shot Audio,' so I don't know how to destroy them. If I can fix this bug then this should be a useful radio script for anyone who wants to use it.
Update, here is my modified radio code, now working, with the help of the answer below:
void OnTriggerEnter2D(Collider2D target) {
if (target.gameObject.tag == "radio") {
radioEnter = true;
}
}
void OnTriggerExit2D(Collider2D target) {
if (target.gameObject.tag == "radio") {
radioEnter = false;
}
}
public void radioUse(){
if ((Input.GetKeyDown (KeyCode.M)) && song3on == true && radioEnter == true) {
TurnOn ();
song1on = true;
song2on = false;
song3on = false;
}
else if ((Input.GetKeyDown (KeyCode.M)) && song1on == true && radioEnter == true) {
TurnOff ();
song1on = false;
song2on = true;
song3on = false;
TurnOn();
}
else if ((Input.GetKeyDown (KeyCode.M)) && song2on == true && radioEnter == true) {
TurnOff ();
song1on = false;
song2on = false;
song3on = true;
TurnOn ();
}
}
public void Update() {
raidoUse();
}
Since PlayClipAtPoint does not return an AudioSource to manage you should not use it for these kind of sounds. I recommend setting up your radio with one AudioSource and multiple AudioClips in a array. Just drag the clips you want to the inspector and use the public methods to control the radio. This way you can reuse it with different songs.
The following code is not tested.
Public class Radio : MonoBehaviour
{
AudioSource output;
public AudioClip[] songs;
int songIndex = 0;
void Start(){
output = gameObject.AddComponent<AudioSource>();
}
public void ToggleSong(){
songIndex++;
output.clip = songs[songIndex % songs.Length];
output.Play();
}
public void TurnOn(){
ToggleSong();
}
public void TurnOff(){
output.Stop();
}