Difference between touch and tap in Corona - touch

I don't exactly understand what's the difference between tap and touch in Corona. I use both of them and when one touches on an object both listened for event until I wrote this piece of code which changes image when nextButton is touched. It's like when I touched the nextButton, It calls the function two times. However when I change it to tap, it worked smoothly. So can you tell me what is the difference between touch and tap and what was causing trouble when I use touch in this piece of code?
function nextButton:touch(event)
if i==7 then
else
i=i+1
imageObject:removeSelf()
imageObject =display.newImage(imageTable[i]..".jpg")
imageObject.x=_W/2
imageObject.y=_H/2
end
end
nextButton:addEventListener("touch", nextButton)

In the corona touch listeners you have 3 state:
function listener(event)
if event.phase == "began" then
-- in the 1st tap the phase will be "began"
elseif event.phase == "moved" then
-- after began phase when the listener will be called with moved phase,like touched coordinates
elseif event.phase == "ended" then
--when the touch will end
end
end
nextButton:addEventListener("touch", listener)
--[[
this was a simple touch listener for an image, self made button etc, btw when you need to yous buttons, use the ui library what is made exactly for this http://developer.coronalabs.com/code/enhanced-ui-library-uilua ]]
-- example for usage
local ui = require "ui" -- copy the ui.lua to your apps root directory
yourButton = ui.newButton{
defaultSrc = "menu/icon-back.png",--unpressed state image
x=85,
y=display.contentHeight-50,
defaultX = 110,
defaultY =80,
offset=-5,
overSrc = "menu/icon-back-2.png",--pressed state image
overX = 110,
overY = 80,
onEvent = buttonhandler,
id = "yourBtnId" -- what you want
}
local function buttonhandler(event)
if event.phase == "release" then
--if you have more buttons handle it whit they id-s
if event.id == "yourBtnId" then
-- when your button was finally released (like in 1st example ended, but this will be called only if the release target is your button)
end
end
end

A "tap" is a brief touch and release action. A touch can be a touch, move then release, or a touch and hold etc. A tap event simplifies your code because you only get one event: the tap happened. You don't have to code for all of the touch states.
A typical tap handler would look like:
local function tapHandler(event)
-- do stuff
return true
end
where has a touch handler that does the exact same thing would look like:
local function touchHandler(event)
if event.phase == "ended" then
-- do stuff
end
return true
end

Related

Handle short and long clicks, drag and drop and sprites overlapping?

My game is going to be using touch controls and I'm having a lot of trouble implementing the following mechanics.
When I make a short click on a sprite, I want it to do a simple click event, in my code, it should highlight the sprite.
But when I make a long click on a sprite, it should at one point anchor to the cursor and be dragged around by it. When I release it, it should then stop following the cursor and stay in place.
Last but not least, I'm actually working with multiple sprites and I want to always influence the top-most sprite (z_index wise).
So right now, my code looks like this:
# Node2D, parent of my sprite
func _process(delta):
# Checks for clicks and hold, calls function based on events
if not owning_hand or not owning_hand.my_hand:
is_holding = false
return
if Input.is_action_just_released("click"):
owning_hand.drop_card()
is_holding = false
if not input_in_sprite:
is_holding = false
return
if Input.is_action_just_pressed("click"):
is_holding = true
if Input.is_action_just_released("click"):
if hold_time < HOLD_TARGET:
owning_hand.clicked_cards.append(self)
is_holding = false
if is_holding:
hold_time += delta
else:
hold_time = 0
if hold_time >= HOLD_TARGET:
owning_hand.held_cards.append(self)
func _input(event):
# If the mouse is in the sprite, set input_in_sprite to true
if not owning_hand or not owning_hand.my_hand:
return
if event is InputEventMouse and sprite.get_rect().has_point(to_local(event.position)) and not played:
input_in_sprite = true
else:
input_in_sprite = false
# Position2D, represents the player's input and methods
func _process(delta): # Gets the top most card z_index wise
# Checks for any clicked cards
print(held_cards)
if dragged_card:
dragged_card.position = get_global_mouse_position()
if clicked_cards:
var top_card = clicked_cards[0]
for Card in clicked_cards:
if Card.z_index > top_card.z_index:
top_card = Card
clicked_cards.clear()
highlight_card(top_card)
if held_cards:
var top_card = held_cards[0]
for Card in held_cards:
if Card.z_index > top_card.z_index:
top_card = Card
held_cards.clear()
drag_card(top_card)
func drag_card(card):
# Drags the card around
dragged_card = card
func drop_card():
# Drops the card
dragged_card = null
func highlight_card(card):
# Highlights the card
card.move_rotate(card.position + transform.y * -HIGHLIGHT_HEIGHT, card.rotation, REORGANISE_TIME)
At the moment, the only issue is that dropping a sprite when there's another sprite under my cursor triggers the click event of the sprite isn't being dropped.
To be frank, the code is pretty much okay for what I'm doing. I'm asking here to see if anyone knows a better way to code those mechanics.
func _process(delta):
# Checks for clicks and hold, calls function based on events
if not owning_hand or not owning_hand.my_hand:
is_holding = false
return
if Input.is_action_just_released("click"):
if hold_time < HOLD_TARGET and input_in_sprite and is_holding:
owning_hand.clicked_cards.append(self)
if owning_hand.dragged_card:
owning_hand.drop_card()
is_holding = false
if Input.is_action_just_pressed("click") and input_in_sprite:
is_holding = true
if is_holding:
hold_time += delta
else:
hold_time = 0
if hold_time >= HOLD_TARGET:
owning_hand.held_cards.append(self)
Coding it like this seems to make it work correctly.
Basically, I used the is_holding bool to gather knowledge on if the sprite has been pressed earlier. If not, the is_action_just_released should completely ignore any action on the sprite.
Feel free to suggest better ways to implement this

Unity timeline, playing animation clips and controlling playback on events

I'm wondering if I can get some help on understanding how to use the timeline
I plan to have the character walking along a path with triggers that will activate the timeline,
I have set up a simple state machine on the monkey
which would be triggered by the path to play the timeline, that part works fine and I can see the events firing
How could I play part of the timeline when triggered (is that even possible?)
where the entire sequence is held Walk>Jump>Walk>Look>Walk>Idle
Or what would I need to do to be able to achieve playback of a clip/or part of a sequence of clips
On the monkey:
public enum State
{
WalkHappy,
Look,
Jump,
}
IEnumerator WalkHappyState()
{
Debug.Log("WalkHappy: Enter");
**//walk sequence with timeline here??**
while (state == State.WalkHappy)
{
yield return 0;
}
Debug.Log("WalkHappy: Exit");
NextState();
}
Called on the paths event listener when triggered
private void OnCustomEvent(string eventname)
{
if (eventname.Contains("MonkeyRunningJumpUp"))
{
GameObject tempMonkey = GameObject.FindGameObjectWithTag("Player");
Monkey tempMonkeyState = tempMonkey.GetComponent<Monkey>();
tempMonkeyState.state = Monkey.State.Jump;
}
}
I have seen its possible to control where the playback starts on a timeline, but I don't know how to force a range/clip to play then pause at the end of the clip rather than the end of the entire sequence
THE question is.. how to stop/pause at end of a clip to resume later?
playableDirector = myPlayableDirectorGO.GetComponent<PlayableDirector>();
Debug.Log(timeLinePosition);
playableDirector.time = timeLinePosition / ((TimelineAsset)playableDirector.playableAsset).editorSettings.fps;
playableDirector.RebuildGraph();
playableDirector.Play();
with thanks Natalie :)
First of all, I recommend to install Default Playables if you haven’t done it yet.
Use Timeline Signals and markers to do something at the end of timeline or at certain point. Also, there is PlayableDirector.stopped event.
You can use pause and resume methods;

Horrors of OnPointerDown versus OnBeginDrag in Unity3D

I'm concerned over the difference between OnPointerDown versus OnBeginDrag in single-finger movement code.
(In the latest Unity paradigm of using a physics raycaster: so, finally, Unity will properly ignore touch on the UI layer.
So from 2015 onwards what you must do is this:
Forget about the crap traditional Input or Touches system which are pointless crap and don't work
Add an empty game object with a usually BoxCollider2D, likely bigger than the screen. Make the layer called say "Draw". Physics settings, "Draw" interacts with nothing
Simply add to the camera, a 2D or 3D physics raycaster. Event mask the "Draw" layer.
Do a script like below and put it on.
(Tip - don't forget to simply add an EventSystem to the scene. Bizarrely, Unity does not do this automatically for you in some situations but Unity does do it automatically for you in other situations, so it's annoying if you forget!)
But here's the problem.
There has got to be some subtle difference between using OnPointerDown versus OnBeginDrag (and the matching end calls). (You can just swap the action in the following code sample.)
Naturally Unity offers no guidance on this; the following code beautifully rejects stray grabs and also flawlessly ignores your UI layer (thanks Unity! at last!) but I am mystified about the difference between the two approaches (begin drag V. begin touch) and I cannot in anyway find the logical difference between the two in unit testing.
What's the answer?
/*
general movement of something by a finger.
*/
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
public class FingerMove:MonoBehaviour,
IPointerDownHandler,
IBeginDragHandler,
IDragHandler,
IPointerUpHandler,
IEndDragHandler
{
public Transform moveThis;
private Camera theCam;
private FourLimits thingLimits;
private Vector3 prevPointWorldSpace;
private Vector3 thisPointWorldSpace;
private Vector3 realWorldTravel;
public void Awake()
{
theCam = Camera.main or whatever;
}
public void OnMarkersReady() // (would be EVENT DRIVEN for liveness)
{
thingLimits = Grid.liveMarkers. your motion limits
}
private int drawFinger;
private bool drawFingerAlreadyDown;
public void OnPointerDown (PointerEventData data)
{
Debug.Log(" P DOWN " +data.pointerId.ToString() );
}
public void OnBeginDrag (PointerEventData data)
{
Debug.Log(" BEGIN DRAG " +data.pointerId.ToString() );
if (drawFingerAlreadyDown == true)
{
Debug.Log(" IGNORE THAT DOWN! " +data.pointerId.ToString() );
return;
}
drawFinger = data.pointerId;
drawFingerAlreadyDown=true;
prevPointWorldSpace = theCam.ScreenToWorldPoint( data.position );
}
public void OnDrag (PointerEventData data)
{
Debug.Log(" ON DRAG " +data.pointerId.ToString() );
if (drawFingerAlreadyDown == false)
{
Debug.Log(" IGNORE THAT PHANTOM! " +data.pointerId.ToString() );
}
if ( drawFinger != data.pointerId )
{
Debug.Log(" IGNORE THAT DRAG! " +data.pointerId.ToString() );
return;
}
thisPointWorldSpace = theCam.ScreenToWorldPoint( data.position );
realWorldTravel = thisPointWorldSpace - prevPointWorldSpace;
_processRealWorldtravel();
prevPointWorldSpace = thisPointWorldSpace;
}
public void OnEndDrag (PointerEventData data)
{
Debug.Log(" END DRAG " +data.pointerId.ToString() );
if ( drawFinger != data.pointerId )
{
Debug.Log(" IGNORE THAT UP! " +data.pointerId.ToString() );
return;
}
drawFingerAlreadyDown = false;
}
public void OnPointerUp (PointerEventData data)
{
Debug.Log(" P UP " +data.pointerId.ToString() );
}
private void _processRealWorldtravel()
{
if ( Grid. your pause concept .Paused ) return;
// potential new position...
Vector3 pot = moveThis.position + realWorldTravel;
// almost always, squeeze to a limits box...
// (whether the live screen size, or some other box)
if (pot.x < thingLimits.left) pot.x = thingLimits.left;
if (pot.y > thingLimits.top) pot.y = thingLimits.top;
if (pot.x > thingLimits.right) pot.x = thingLimits.right;
if (pot.y < thingLimits.bottom) pot.y = thingLimits.bottom;
// kinematic ... moveThis.position = pot;
// or
// if pushing around physics bodies ... rigidbody.MovePosition(pot);
}
}
And here's a handy thing. Save typing with the same thing for 3D scenes, using the little-known but exquisite
pointerCurrentRaycast
here's how... notice the excellent
data.pointerCurrentRaycast.worldPosition
call courtesy Unity.
public class FingerDrag .. for 3D scenes:MonoBehaviour,
IPointerDownHandler,
IDragHandler,
IPointerUpHandler
{
public Transform moveMe;
private Vector3 prevPointWorldSpace;
private Vector3 thisPointWorldSpace;
private Vector3 realWorldTravel;
private int drawFinger;
private bool drawFingerAlreadyDown;
public void OnPointerDown (PointerEventData data)
{
if (drawFingerAlreadyDown == true)
return;
drawFinger = data.pointerId;
drawFingerAlreadyDown=true;
prevPointWorldSpace = data.pointerCurrentRaycast.worldPosition;
// in this example we'll put it under finger control...
moveMe.GetComponent<Rigidbody>().isKinematic = false;
}
public void OnDrag (PointerEventData data)
{
if (drawFingerAlreadyDown == false)
return;
if ( drawFinger != data.pointerId )
return;
thisPointWorldSpace = data.pointerCurrentRaycast.worldPosition;
realWorldTravel = thisPointWorldSpace - prevPointWorldSpace;
_processRealWorldtravel();
prevPointWorldSpace = thisPointWorldSpace;
}
public void OnPointerUp (PointerEventData data)
{
if ( drawFinger != data.pointerId )
return;
drawFingerAlreadyDown = false;
moveMe.GetComponent<Rigidbody>().isKinematic = false;
moveMe = null;
}
private void _processRealWorldtravel()
{
Vector3 pot = moveMe.position;
pot.x += realWorldTravel.x;
pot.y += realWorldTravel.y;
moveMe.position = pot;
}
}
I want to start by saying that Input and Touches are not crappy.They are still usefull and were the best way to check for touch on mobile devices before OnPointerDown and OnBeginDrag came along. OnMouseDown() you can call crappy because it was not optimized for mobile. For a beginner who just started to learn Unity, Input and Touches are their options.
As for your question, OnPointerDown and OnBeginDrag are NOT the-same. Although they almost do the-same thing but they were implemented to perform in different ways. Below I will describe most of these:
OnPointerDown:
Called when there is press/touch on the screen (when there is a click or finger is pressed down on touch screen)
OnPointerUp:
Called when press/touch is released (when click is released or finger is removed from the touch screen)
OnBeginDrag:
Called once before a drag is started(when the finger/mouse is moved for the first time while down)
OnDrag :
Repeatedly called when user is dragging on the screen (when the finger/mouse is moving on the touch screen)
OnEndDrag:
Called when drag stops (when the finger/mouse is no longer moving on the touch screen).
OnPointerDown versus OnBeginDrag and OnEndDrag
OnPointerUp will NOT be called if OnPointerDown has not been called. OnEndDrag will NOT be called if OnBeginDrag has not been called. Its like the curly braces in C++,C#, you open it '{' and you close it '}'.
THE DIFFERENCE:
OnPointerDown will be called once and immediately when finger/mouse is on the touch screen. Nothing else will happen until there is a mouse movement or the finger moves on the screen then OnBeginDrag will be called once followed by OnDrag.
These are made for doing advanced usage such such as custom UI with controls that is not included in Unity.
WHEN TO USE EACH ONE:
1. When you have to implement a simple click button, for example, Up,Down, Shoot Button on the screen, you only need OnPointerDown to detect the touch. This should work for Sprite Images.
2. When you have to implement a custom toggle switch and you want it to be realistic so that the player can drag to left/right or up/down to toggle it then you need OnPointerDown , OnBeginDrag , OnDrag , OnEndDrag , OnPointerUp. You need to write your code in this order to have a smooth Sprite/Texture transition on the screen. Some toggle switches are made to be to clicked and it will toggle. Some people prefer to make it look realistic by making it so that you have to drag it in order to toggle it.
3. Also when you want to implement a Generic re-usable pop-up window that is draggable, you also need to use those 5 functions (OnPointerDown , OnBeginDrag , OnDrag , OnEndDrag , OnPointerUp).
First detect when there is a click(OnPointerDown), check to make sure that the Sprite clicked is the right one you want to move. Wait for player to move(OnBeginDrag) their finger/mouse. Once they start dragging, maybe you can call a coroutine function with while loop that will start moving the Sprite and inside that coroutine, you can smooth the movement of the Sprite with Time.deltaTime or any other preferred method.
Since OnBeginDrag is called once, it is a good place to start the coroutine.
As the player continue to drag the Sprite, OnDrag will be called repeatedly. Use the OnDrag function to get the current location of the finder and update that to a Vector3 that the coroutine that is already running will use to update the position of the Sprite. When the player stops moving their finger/mouse on the screen, OnEndDrag is called and you can boolean variable and tell the coroutine to stop updating the position of the Sprite. Then, when the player releases their finger(OnPointerUp) you can then stop the coroutine with the StopCoroutine function.
Because of OnBeginDrag we we are able to start coroutine once drag started while waiting for drag to end. It wouldn't make sense to start that coroutine in OnPointerDown because that means that each time player touches the screen, a coroutine would be started.
Without OnBeginDrag, we have to use boolean variable to make the coroutine start only once in the OnDrag function which is called every time or else there would be coroutine running everywhere and unexpected movement of the Sprite will occur.
4. When you want to determine how long player moved their finger. Example of this is that famous game called Fruit Ninja. Lets just say you want to determine far the player swiped on the screen.
First, wait until OnPointerDown is called, wait again until OnBeginDrag is called, then you can get the current position of the finger inside OnBeginDrag function because OnBeginDrag is called before the finger starts moving. After the finger is released, OnEndDrag is called. Then you can get the current position of finger again. You can use these two positions to check how far the finger moved by subtracting them.
If you instead decide to use OnPointerDown as the place to get the first position of the finger, you will get a wrong result because if the player swipes right, then waits and swipes left then waits again and swipe up without releasing their finger after each swipe, the only good result you have is the first swipe(right swipe). The left and the up swipe will have invalid values because that first value you got when OnPointerDown was called is the value you are still using. This is because the player never removed their finger from the screen so therefore, OnPointerDown is never called again and the first old old value is still there.
But when you use OnBeginDrag instead of OnPointerDown, this problem will be gone because when the finger stops moving, OnEndDrag is called and when it starts moving again OnBeginDrag is called once again causing the first position to be overwritten with the new one.
The difference is that OnBeginDrag doesn't get called until the touch/mouse has moved a certain minimum distance, the drag threshold. You can set the drag threshold on the Event System component.
This is necessary for when you have a hierarchy of objects with different ways of handling input, especially scrollviews. Imagine you have a scrollview with a vertical stack of cells, each with a button in it. When the touch first starts on one of the buttons, we don't know whether the user is tapping a button or dragging the scrollview. It isn't until the touch gets dragged for the drag threshold that we know it is a drag and not a tap.

How to change the mouse cursor icon type when mouse moves out of client area ( propertysheet)?

I got stuck with an issue in property sheet .I want to load different cursor when the mouse position is within the client area and load another when moves out of the client area.
In the porpetysheet I added four page. In the first page when I click next I am loading cursor of IDC_WAIT type and loading IDC_ARROW when the mouse moves out of the client area.
In the page class I triggered the event for WM_MOUSEMOVE as follow:
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if(TRUE == m_bIsNextBtnClicked)
::SetCursor(LoadCursor(NULL, IDC_WAIT));
else
::SetCursor(LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
This event is getting triggered and absolutely had no issue with this. Similarly I tried adding MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) this event making an assumption that this will get triggered if the mouse moves out of the client area, but this event did not get triggered at all.If this is not the mouse event to be triggered for mouseleave which event should I trigger?
LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
::SetCursor(LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
Now when I click Next button , I was actually calling a function which is taking sometime to return . Before to this function I am loading IDC_WAIT cursor i.e.,
::SetCursor(LoadCursor(NULL, IDC_WAIT)); .
Now when move the mouse cursor on to the non-client area I want to load IDC_ARROW cursor i.e.,
::SetCursor(LoadCursor(NULL, IDC_ARROW));
When the moves on to the non-client area I am handling the mouse event in sheet derived class as follows,
MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNCMouseMove)
LRESULT OnNCMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
::SetCursor(LoadCursor(NULL, IDC_ARROW));
return 0;
}
This event is not getting triggered until unless the function in the Next button event is executed.
I want both of them to be done in parallel i.e, click Next button now hover mouse on the client area, Busy icon should come and when mouse moves out of the client area then IDC_ARROW icon should come.
LRESULT OnWizardNext()
{
::SetCursor(LoadCursor(NULL, IDC_WAIT));
m_bIsNextBtnIsClicked = TRUE;
BOOL bRet = MyFun();
m_bIsNextBtnIsClicked = FALSE;
//Until this function is executed **WM_NCMOUSEMOVE**
//event is not getting triggered.But this event should get triggered and I
//should be able to see the change of cursor within and out of client area.
}
Can anyone kindly help me to solve this issue.
As stated on the MSDN version of this question # here it's not good design to involve the user interface thread in a long operation, a progress bar that is updated from another thread would give more feedback to the user.

Best way to go about making ccTime function just for a sprite's movement?

I'm trying to make a simple game and I am currently trying to make an arrow shoot out.
So far I have two functions,
-(void)ccTouchesBegan
Touches began does some math and gets a vector from the initial shooting point of arrow and the thumbpress, then passes this data into another function:
-(void)shatArrow:(CGPoint)cl:(CGPoint)nv{
}
What I want is for the shatArrow function to call a ccTime function that runs solely for the purpose of making the arrow move, and once the arrow is done with it's projection, the ccTime function will stop, and can be called again later when needed.
How would I go about this?
Schedule the update selector (ie in the init method of your class):
[self scheduleUpdate];
Then implement the update method:
-(void) update:(ccTime)delta
{
if (isArrowMoving)
{
// arrow move code here
if (arrow movement should end)
{
isArrowMoving = NO;
}
}
}
You can keep the update method running, unless you have hundreds of arrows it won't affect performance.
-(void) shootArrow:(CGPoint)cl:(CGPoint)nv
{
isArrowMoving = YES;
// other arrow movement init code here
}
Btw, it's "shoot, shot, shot" and not "shoot, shot, shat" or something like that. (I suppose you didn't ask for a #LinguisticsOverflow answer) ;)