Android ACTION_MOVE Threshold - android

I'm writing an app that involves writing on the screen using one's finger, or eventually a stylus. I have that part working. On ACTION_DOWN, starts drawing; on ACTION_MOVE, adds line segments; on ACTION_UP, finishes line.
The problem is that after ACTION_DOWN, apparently the pointer needs to move more than 10 pixels away from where it started (basically a 20x20 box around the starting point) in order to begin sending ACTION_MOVE events. After leaving the box, the move events are all quite accurate. (I figured out the 10 pixel thing by testing it.) Since this is meant to be used for writing or drawing, 10 pixels is a fairly significant loss: depending on how small you're trying to write, you can lose the first letter or two. I haven't been able to find anything about it - only a couple posts on a forum or two, like http://android.modaco.com/topic/339694-touch-input-problem-not-detecting-very-small-movements/page_pid_1701028#entry1701028. It seems to be present on some devices or systems and not others. No ideas as to how to get rid of it when you have it, though.
I'm using a Galaxy Tab 10.1, with Android 3.1. I've tried several different things to try to get rid of it: I've tried setting the event's coords to something else to see if I could trick it into thinking the cursor was in a different place; I tried re-dispatching the event with the coords changed (my handler reacted to the new points, but still didn't respond to movements in the 10-pixel radius.) I've searched through source code for any references to the effect, and found none (though I think it's from a different version of Android - code for 3.1 isn't released yet, is it?) I've searched for methods of querying the current state of the pointers, so I could just have a timer catch the changes until the pointer crossed the threshold. Couldn't find any way of getting pointer coords without a corresponding movement event. Nothing worked. Does anybody know anything about this, or have any ideas or work-arounds? Thank you.
-- Update: Drag and drop events show the same threshold.

I agree in part with the post by #passsy but come to a different conclusion. Firstly as mentioned, the mTouchSlop is the value that we are interested in and is exposed via ViewConfiguration.get(context).getScaledTouchSlop();
If you check the Android source for the ViewConfiguraton, the default value for TOUCH_SLOP is 8dip, but the comments mention that this value is a fallback only, and the actual value is defined when the Android OS for that specific device is built. (it may be more or less than this value. It appears to hold true for the Galaxy Tab devices)
More specific to the code sample, the mTouchSlop value is read from the ViewConfiguration when the View is initialised, but the value is only accessed in the onTouchEvent method. If you extend View and override this method (without calling super) then the behaviour of mTouchSlop in the View class is no longer relevant.
More telling (to us) was that when changing the Android settings to overlay touch events on the screen, a touch with a small drag does not register as a motion event, highlighted by the fact that the crosshairs from the Android OS do not move. From this our conclusion is that the minimal drag distance is being enforced at the OS level and your application will never be aware of drag events smaller than the TOUCH_SLOP value. You should also be aware that TOUCH_SLOP should not be used directly and the API deprecates the getTouchSlop method and recommends getScaledTouchSlop which takes the device screen size and pixel density into account. A side effect of this is that the actual minimum stroke length as perceived on different devices may vary. eg on a Galaxy Tab 2.0 7.0" it feels like we are able to draw shorter minimum strokes using the same code base than when running on a Galaxy Tab 2.0 10.1"
You should also be aware that (if you find a way to alter this value), this value determines how Android systems distinguish between taps and strokes. That is if you tap the screen but your finger moves slightly while performing the tap, it will be interpreted as a tap if it moved less than TOUCH_SLOP, but as a stroke if it moved more than TOUCH_SLOP. Therefore setting TOUCH_SLOP to a smaller value will increase the chance that a tap will be interpreted as a stroke.
Our own conclusion is that this minimum distance is not something that can be changed in practice and is something we need to live with.

The problem is on Line 6549 in class View https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java
if (!pointInView(x, y, mTouchSlop)) {...}
/**
* Utility method to determine whether the given point, in local coordinates,
* is inside the view, where the area of the view is expanded by the slop factor.
* This method is called while processing touch-move events to determine if the event
* is still within the view.
*/
private boolean pointInView(float localX, float localY, float slop) {
return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
localY < ((mBottom - mTop) + slop);
}
mTouchSlop is set in the constructor
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
You can extend View and set mTouchSlop to zero. I don't see an other way to set mTouchSlop. There is no function like getApplicationContext.setScaledTouchSlop(int n).

Extend View Class.
Override pointInView method without "#Override" annotaion and set touchSlop = 0:
public boolean pointInView(float localX, float localY, float slop) {
slop = 0;
return localX >= -slop && localY >= -slop && localX < (getWidth() + slop) &&
localY < (getBottom() + slop);
}

Related

Detect finger switch on touch

I have a bitmap that I can drag around on my app, but there is a small bug, if let's say someone clicks with one finger on the bitmap and starts moving it around, and then while moving it around clicks with another finger, the bitmap "teleports" over there. How can I detect if the user switched fingers so bitmaps wont teleport? this is my Action_MOVE code:
case MotionEvent.ACTION_MOVE:
if (dragging) {
CurrentMobEntry.getKey().x = (int) x
- CurrentMobEntry.getValue().getNormalbit()
.getWidth() / 2;
CurrentMobEntry.getKey().y = (int) y
- CurrentMobEntry.getValue().getNormalbit()
.getHeight() / 2;
CurrentMobEntry.getValue().getDestroyedP().x=(int)x
+CurrentMobEntry.getValue().getNormalbit()
.getWidth() / 2;
CurrentMobEntry.getValue().getDestroyedP().y = (int)y
+ CurrentMobEntry.getValue().getNormalbit()
.getHeight() / 2;
}
break;
From the documentation:
Some devices can report multiple movement traces at the same time. Multi-touch screens emit one movement trace for each finger. The individual fingers or other objects that generate movement traces are referred to as pointers. Motion events contain information about all of the pointers that are currently active even if some of them have not moved since the last event was delivered.
The number of pointers only ever changes by one as individual pointers go up and down, except when the gesture is canceled.
So what you want to do is to allow only for one pointer (finger) to operate in any given time. I can't seem to find a simple solution to this so we are going to use a workaround:
Each pointer gets a unique, constant ID. On any given touch event, you will check to see if that pointer initiated the event and then if true consume it, else ignore.
For a full example of this check the Android Developer's blog.

Unity2D Android Touch misbehaving

I am attempting to translate an object depending on the touch position of the user.
The problem with it is, when I test it out, the object disappears as soon as I drag my finger on my phone screen. I am not entirely sure what's going on with it?
If somebody can guide me that would be great :)
Thanks
This is the Code:
#pragma strict
function Update () {
for (var touch : Touch in Input.touches)
{
if (touch.phase == TouchPhase.Moved) {
transform.Translate(0, touch.position.y, 0);
}
}
}
The problem is that you're moving the object by touch.position.y. This isn't a point inworld, it's a point on the touch screen. What you'll want to do is probably Camera.main.ScreenToWorldPoint(touch.position).y which will give you the position inworld for wherever you've touched.
Of course, Translate takes a vector indicating distance, not final destination, so simply sticking the above in it still won't work as you're intending.
Instead maybe try this:
Vector3 EndPos = Camera.main.ScreenToWorldPoint(touch.position);
float speed = 1f;
transform.position = Vector3.Lerp(transform.position, EndPos, speed * Time.deltaTime);
which should move the object towards your finger while at the same time keeping its movements smooth looking.
You'll want to ask this question at Unity's dedicated Questions/Answers site: http://answers.unity3d.com/index.html
There are very few people that come to stackoverflow for Unity specific question, unless they relate to Android/iOS specific features.
As for the cause of your problem, touch.position.y is define in screen space (pixels) where as transform.Translate is expecting world units (meters). You can convert between the two using the Camera.ScreenToWorldPoint() method, then creating a vector out of the camera position and screen world point. With this vector you can then either intersect some geometry in the scene or simply use it as a point in front of the camera.
http://docs.unity3d.com/Documentation/ScriptReference/Camera.ScreenToWorldPoint.html

How to collide objects with high speed in Unity

I try to create game for Android and I have problem with high speed objects, they don't wanna to collide.
I have Sphere with Sphere Collider and Bouncy material, and RigidBody with this param (Gravity=false, Interpolate=Interpolate, Collision Detection = Continuous Dynamic)
Also I have 3 walls with Box Collider and Bouncy material.
This is my code for Sphere
function IncreaseBallVelocity() {
rigidbody.velocity *= 1.05;
}
function Awake () {
rigidbody.AddForce(4, 4, 0, ForceMode.Impulse);
InvokeRepeating("IncreaseBallVelocity", 2, 2);
}
In project Settings I set: "Min Penetration For Penalty Force"=0.001, "Solver Interation Count"=50
When I play on the start it work fine (it bounces) but when speed go to high, Sphere just passes the wall.
Can anyone help me?
Thanks.
Edited
var hit : RaycastHit;
var mainGameScript : MainGame;
var particles_splash : GameObject;
function Awake () {
rigidbody.AddForce(4, 4, 0, ForceMode.Impulse);
InvokeRepeating("IncreaseBallVelocity", 2, 2);
}
function Update() {
if (rigidbody.SweepTest(transform.forward, hit, 0.5))
Debug.Log(hit.distance + "mts distance to obstacle");
if(transform.position.y < -3) {
mainGameScript.GameOver();
//Application.LoadLevel("Menu");
}
}
function IncreaseBallVelocity() {
rigidbody.velocity *= 1.05;
}
function OnCollisionEnter(collision : Collision) {
Instantiate(particles_splash, transform.position, transform.rotation);
}
EDITED added more info
Fixed Timestep = 0.02 Maximum Allowed Tir = 0.333
There is no difference between running the game in editor player and on Android
No. It looks OK when I set 0.01
My Paddle is Box Collider without Rigidbody, walls are the same
There are all in same layer (when speed is normal it all works) value in PhysicsManager are the default (same like in image) exept "Solver Interation Co..." = 50
No. When I change speed it pass other wall
I am using standard cube but I expand/shrink it to fit my screen and other objects, when I expand wall more then it's OK it bouncing
No. It's simple project simple example from Video http://www.youtube.com/watch?v=edfd1HJmKPY
I don't use gravity
See:
Similar SO Question
A community script that uses ray tracing to help manage fast objects
UnityAnswers post leading to the script in (2)
You could also try changing the fixed time step for physics. The smaller this value, the more times Unity calculates the physics of a scene. But be warned, making this value too small, say <= 0.005, will likely result in an unstable game, especially on a portable device.
The script above is best for bullets or small objects. You can manually force rigid body collisions tests:
public class example : MonoBehaviour {
public RaycastHit hit;
void Update() {
if (rigidbody.SweepTest(transform.forward, out hit, 10))
Debug.Log(hit.distance + "mts distance to obstacle");
}
}
I think the main problem is the manipulation of Rigidbody's velocity. I would try the following to solve the problem.
Redesign your code to ensure that IncreaseBallVelocity and every other manipulation of Rigidbody is called within FixedUpdate. Check that there are no other manipulations to Transform.position.
Try to replace setting velocity directly by using AddForce or similar methods so the physics engine has a higher chance to calculate all dependencies.
If there are more items (main player character, ...) involved related to the physics calculation, ensure that their code runs in FixedUpdate too.
Another point I stumbled upon were meshes that are scaled very much. Having a GameObject with scale <= 0.01 or >= 100 has definitely a negative impact on physics calculation. According to the docs and this Unity forum entry from one of the gurus you should avoid Transform.scale values != 1
Still not happy? OK then the next test is starting with high velocities but no acceleration. At this phase we want to know, if the high velocity itself or the acceleration is to blame for the problem. It would be interesting to know the velocities' values at which the physics engine starts to fail - please post them so that we can compare them.
EDIT: Some more things to investigate
6.7 m/sec does not sound that much so that I guess there is a special reason or a combination of reasons why things go wrong.
Is your Maximum Allowed Timestep high enough? For testing I suggest 5 to 10x Fixed Timestep. Note that this might kill the frame rate but that can be dfixed later.
Is there any difference between running the game in editor player and on Android?
Did you notice any drops in frame rate because of the 0.01 FixedTimestep? This would indicate that the physics engine might be in trouble.
Could it be that there are static colliders (objects having a collider but no Rigidbody) that are moved around or manipulated otherwise? This would cause heavy recalculations within PhysX.
What about the layers: Are all walls on the same layer resp. are the involved layers are configured appropriately in collision detection matrix?
Does the no-bounce effect always happen at the same wall? If so, can you just copy the 1st wall and put it in place of the second one to see if there is something wrong with this specific wall.
If not to much effort, I would try to set up some standard cubes as walls just to be sure that transform.scale is not to blame for it (I made really bad experience with this).
Do you manipulate gravity or TimeManager.timeScale from within a script?
BTW: are you using gravity? (Should be no problem just

Canvas not displaying all drawn parts in Custom View?

I'm working on a custom view for an android application, similar to the Analog Gauge sample code available from Mind the Robot.
Running the code from listed site, I get see this on my screen:
(Motorola Droid, 2.2.3), (Emulator, 4.0.3)
(Xoom, 4.0.3)(Other phone, 4.0.3)
The hand is missing!
The drawing calls are being made (I can see them in logcat), but the canvas elements the calls draw are invisible.
It's not API level dependent, though; if I import it the right way into a project, it will hand will show up when I run it on the Xoom.
But, when I move the files to a different project folder (same source code, same layouts) it goes back to missing the dial.
What's going on? How could the same code be producing such different outcomes on different devices?
So, the key clue in my mystery seemed to be that it worked on the emulator, but not on the hardware devices.
Hardware Rendering
I did peruse the hardware rendering page on the Android Developer's website, but apparently not closely enough.
http://developer.android.com/guide/topics/graphics/hardware-accel.html
While it does mention that the API's are available beginning version 11, it does not say that Hardware Rendering is turned on for all applications by default, starting with API Level 14 (ICS).
What does this mean for us?
Almost everything is faster; except for the few things that don't work.
I managed to violate two of these, without realizing it:
Canvas.DrawTextOnPath()
Paint.setShadowLayer()
It's not mentioned in the API reference (or anywhere else I can find, and certainly not checked by Lint), but using any of the listed operations can do weird things.
In my case, Canvas.DrawTextOnPath() seemed to work just fine.
But when Android notice that the paint that I used on the hand had shadow layer set, it silently ignored it.
How do I know if my View is hardware accelerated?
From the documentation link above:
There are two different ways to check whether the application is hardware accelerated:
View.isHardwareAccelerated() returns true if the View is attached to a hardware accelerated window.
Canvas.isHardwareAccelerated() returns true if the Canvas is hardware accelerated
If you must do this check in your drawing code, use Canvas.isHardwareAccelerated() instead >of View.isHardwareAccelerated() when possible. When a view is attached to a hardware >accelerated window, it can still be drawn using a non-hardware accelerated Canvas. This >happens, for instance, when drawing a view into a bitmap for caching purposes.
In my case, the opposite appears to have occurred.
The custom view logs that it is not Hardware-accelerated; however, the canvas reports that it is hardware-accelerated.
Work Arounds and Fixings
The simplest fix is forcing the custom view to do software rendering. Per the documentation this can be accomplished by:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Alternatively, you could remove the offending operations, and keep hardware rendering turned on.
Learn from my misfortune. Good luck, all.
I put it into init() and worked fine after that.
private void init() {
setLayerType(myView.LAYER_TYPE_SOFTWARE, null);
....
}
With myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); suggestion I can see hand. But I have still a problem: I see scale with only 0 written! As in the picture and two strage zeros out of the schema: (GALAXY NEXUS 4.2.1)
My drawScale() method is as in the example:
private void drawScale(Canvas canvas) {
canvas.drawOval(scaleRect, scalePaint);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
for (int i = 0; i < totalNicks; ++i) {
float y1 = scaleRect.top;
float y2 = y1 - 0.020f;
canvas.drawLine(0.5f, y1, 0.5f, y2, scalePaint);
if ((i % 5) == 0) {
int value = nickToDegree(i);
if ((value >= minDegrees) && (value <= maxDegrees)) {
String valueString = Integer.toString(value);
canvas.drawText(valueString, 0.5f, y2 - 0.015f, scalePaint);
}
}
canvas.rotate(degreesPerNick, 0.5f, 0.5f);
}
canvas.restore();
}
in my case i made this:
AnalogView bar = (AnalogView) findViewById(R.id.AnalogBar);
bar.setLayerType(bar.LAYER_TYPE_SOFTWARE, null);
if (value_list.size()>0) bar.SetData(Double.parseDouble(value_list.get(value_list.size()-1)));
where SetData in AnalogView is
public void SetData(double data) {
setHandTarget((float)data);
invalidate();
}
On Galaxy S4 Android 4.4.2
TYPE_TEMPERATURE is deprecated
use
TYPE_AMBIENT_TEMPERATURE
For anyone having problems with text drawing on scale in the initialisation do this:
scalePaint.setLinearText(true);

Android Game Development: Collision Detection Failing

I am currently developing a game for Android, and I would like your expertise on an issue that I have been having.
Background:
My game incorporates frame rate independent motion, which takes into
account the delta time value before performing necessary Velocity
calculations.
The game is a traditional 2D platformer.
The Issue:
Here's my issue (simplified). Let's pretend that my character is a square standing on top of a platform (with "gravity" being a constant downward velocity of characterVelocityDown).
I have defined the collision detection as follows (assuming Y axis points downwards):
Given characterFootY is the y-coordinate of the base of my square character, platformSurfaceY is the upper y-coordinate of my platform, and platformBaseY is the lower y-coordinate of my platform:
if (characterFootY + characterVelocityDown > platformSurfaceY && characterFootY + characterDy < platformBaseY) {
//Collision Is True
characterFootY = platformSurfaceY;
characterVelocityDown = 0;
} else{
characterVelocityDown = deltaTime * 6;
This approach works perfectly fine when the game is running at regular speed; however, if the game slows down, the deltaTime (which is the elapsed time between the previous frame and the current frame) becomes large, and characterFootY + characterVelocityDown exceed the boundaries that define collision detection and the character just falls straight through (as if teleporting).
How should I approach this issue to prevent this?
Thanks in advance for your help and I am looking forward to learning from you!
What you need to do is to run your physics loop with constant delta time and iterate it as many time as it need with current tick.
const float PHYSICS_TICK = 1/60.f; // 60 FPS
void Update( float dt )
{
m_dt += dt;
while( m_dt > PHYSICS_TICK )
{
UpdatePhysics( PHYSICS_TICK );
m_dt -= PHYSICS_TICK;
}
}
There are various technics used to handle the tick left ( m_dt )
Caps for miniumum tick and maximum tick are also a must.
I guess the issue here is that slowdowns are inevitable. You can try and optimize the code but you'll always have users with slow devices or busy sections of your game where it takes a little longer than usual to process it all. Instead of assuming a consistent delta, assume the opposite. Code under the realization that someone could try installing it on an abacus.
So basically, as SeveN says, make your game loop handle slowdowns. The only real way to do this (in my admittedly limited experience) would be to place a cap on how large delta can be. This will result in your clock not running on time exactly, but when you think about it, that's how most games handle slowdown. You don't fire up StarCraft on your pentium 66 and have it run at 5 FPS but full speed, it slow down and processes it as normal, albeit at a slideshow.
If you did such a thing, during periods of slowdown in your game, it'd visibly slow down... but the calculations should still all be spot on.
edit: just realised you're SeveN. Well done.

Categories

Resources