I my code, severely simplified is the following:
if(action == MotionEvent.ACTION_DOWN){
x = me.getX();
y = me.getY();
}
else if(action == MotionEvent.ACTION_UP){
x = me.getX();
y = me.getY();
}
else if(action == MotionEvent.ACTION_MOVE){
x = me.getX();
y = me.getY();
}
if(action == MotionEvent.ACTION_POINTER_2_DOWN){
x2 = me.getX(1);
y2 = me.getY(1);
}
if(action == MotionEvent.ACTION_POINTER_2_UP){
x2 = me.getX(1);
y2 = me.getY(1);
}
I want to add
if(action == MotionEvent.ACTION_POINTER_2_MOVE){
x2 = me.getX(1);
y2 = me.getY(1);
}
But of course
MotionEvent.ACTION_POINTER_2_MOVE
Is not a real methode. I know there has to be a way around this. Any suggestions?
If you don't understand my question, what I am asking is, is there a multi-touch methode that runs when a pointer is moved? BTW googles not being helpful.
I also checked http://developer.android.com/reference/android/view/MotionEvent.html but again nothing useful
From the documentation:
The order in which individual pointers appear within a motion event is
undefined. Thus the pointer index of a pointer can change from one
event to the next but the pointer id of a pointer is guaranteed to
remain constant as long as the pointer remains active. Use the
getPointerId(int) method to obtain the pointer id of a pointer to
track it across all subsequent motion events in a gesture. Then for
successive motion events, use the findPointerIndex(int) method to
obtain the pointer index for a given pointer id in that motion event.
You must get and track the pointer IDs yourself and determine which pointer(s) moved.
http://developer.android.com/reference/android/view/MotionEvent.html
Related
I'm developing a 2D space shooter game with the player only moving left and right. I've rendered a button on the left and the right side of the screen and constantly check if it's touched. The problem with this is that you have to lift your finger of the button in order to press the button on the other side of the screen. I want the ship to be moving towards the last touched part of the screen(Even when you actually didn't lift the finger of your first-touched button).
public void keyListener(float delta){
//right movement
if(Gdx.input.isKeyPressed(Keys.RIGHT) || (Gdx.input.isTouched() && game.cam.getInputInGameWorld().x >= arrowMoveX - 40) && !isPlayerHit)
x+=SPEED*Gdx.graphics.getDeltaTime();
//left movement
if(Gdx.input.isKeyPressed(Keys.LEFT) || (Gdx.input.isTouched() && game.cam.getInputInGameWorld().x < arrowMoveWhite.getWidth() + 40) && !isPlayerHit)
x-=SPEED*Gdx.graphics.getDeltaTime();
I've tried puting another if statements in these to check for a second movement, but this way it only works on one direction.
Can you please help me?
What you need to know about for this is that Android indexes each separate touch in order of when the screen was touched, the index is known as a "pointer". For example, when you touch the screen with only one finger, the touch pointer is 0, and the second touch pointer is 1. The highest pointer that libGDX registers is 20.
For your particular situation, you want to read only the input that is on the highest pointer that is currently reading a touch, and have an int reading the highest touch. You can loop through the pointers, and set the int to whatever touch event is actually the highest pointer which is referring to the most recent press like this:
int highestpointer = -1; // Setting to -1 because if the pointer is -1 at the end of the loop, then it would be clear that there was no touch
for(int pointer = 0; pointer < 20; pointer++) {
if(Gdx.input.isTouched(pointer)) { // First check if there is a touch in the first place
int x = Gdx.input.getX(pointer); // Get x position of touch in screen coordinates (far left of screen will be 0)
if(x < arrowMoveWhite.getWidth() + 40 || x >= arrowMoveX - 40) {
highestpinter = pointer;
} // Note that if the touch is in neither button, the highestpointer will remain what ever it was previously
}
} // At the end of the loop, the highest pointer int would be the most recent touch, or -1
// And to handle actual movement you need to pass the highest pointer into Gdx.input.getX()
if(!isPlayerHit) { // Minor improvement: only check this once
if(Gdx.input.isKeyPressed(Keys.RIGHT) || (highestpointer > -1 && Gdx.input.getX(highestpointer) >= arrowMoveX - 40)) {
x+=SPEED*Gdx.graphics.getDeltaTime();
} else if(Gdx.input.isKeyPressed(Keys.LEFT) || (highestpointer > -1 && Gdx.input.getX(highestpointer) < arrowMoveWhite.getWidth() + 40)) {
x-=SPEED*Gdx.graphics.getDeltaTime();
}
}
Note that you will probably want a separate camera drawing your buttons (or any hud elements) because you would not need to worry about translating screen coordinates to world coordinates since x goes in the same direction.
Let me know how that works and if you need any changes!
I've tried searching around, but nothing really seems to cover what I'm looking for.
I'm currently making a mini graphics editor for my course, and its working okay at the minute for the paintbrush tool, only that it doesn't seem to work very well at all if I'm moving the mouse too quickly.
The drawing is done through a mouse listener, triggering a 'draw' event while the mouse is held down. It then adds a circle (size and color based upon settings elsewhere) each time the loop rolls. The method takes the initial mouse location (MouseEvent e), and then uses a PointerInfo to update the current mouse position with some calculations around it to make sure it draws in the current place (the canvas uses a null layout).
Some code to show what It's doing:
void setMouseDown(MouseEvent e){
PointerInfo mousePos = MouseInfo.getPointerInfo();
int mouseRelativeX = e.getX();
int mouseRelativeY = e.getY();
int startX = (int) mousePos.getLocation().getX();
int startY = (int) mousePos.getLocation().getY();
while(mouseDown){
mousePos = MouseInfo.getPointerInfo();
mouseMarginX = mouseRelativeX - (startX - (int) mousePos.getLocation().getX());
mouseMarginY = mouseRelativeY - (startY -(int) mousePos.getLocation().getY());
if(curTool == "drawPen"){
DrawPen drawPen = new DrawPen(toolSize, Color.BLACK);
add(drawPen);
drawPen.setBounds(mouseMarginX, mouseMarginY, toolSize, toolSize);
}else if(curTool == ""){
}else if(curTool == ""){
}else if(curTool == ""){
}
revalidate();
repaint();
}
}
If anybody has any advice on the best way to do this, then it'd be much appreciated. Thanks
I am trying to check what is touching the screen whenever it is pressed, a pointer is moved, or a touch is released.
The problem is that when a touch is released, getPointerCount() includes the pointer that just left the screen in its count. And so when I try to gather all the current X and Y values, it includes an x/y pair that has left the screen.
I am currently doing something like:
int count = e.getPointerCount();
for(i = 0; i < count; i++) {
x = e.getX(i);
y = e.getY(i);
/* do stuff with them */
}
Is there a way of getting the X and Y coordinates of that pointer that left the screen, or remove the pointer that left the screen and get only coordinates that are touching the screen?
Thanks
Have you tried using the onTouchEvent in your application?
import android.view.MotionEvent;
...
private int mActivePointerId;
protected void onCreate(Bundle savedInstanceState){
...
}
public boolean onTouchEvent(MotionEvent event){
// Get the pointer ID
mActivePointerId = event.getPointerId(0);
// ... Many touch events later...
// Use the pointer ID to find the index of the active pointer
// and fetch its position
int pointerIndex = event.findPointerIndex(mActivePointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
return true;
}
I think the method you want is getActionIndex(). From the documentation, it seems that when getActionMasked() returns ACTION_POINTER_UP, this method will return the corresponding pointer index and you can then ignore it in your loop (or do something else with it).
I want handle a gesture in my activity. To do this i have override the public boolean onTouchEvent(MotionEvent MEvent) method on my Activity. The content looks like this:
motionaction = MEvent.getAction();
if(motionaction == MotionEvent.ACTION_DOWN)
{
...
return true;
}
if(motionaction == MotionEvent.ACTION_UP)
{
...
return true;
}
if(motionaction == MotionEvent.ACTION_MOVE)
{
...
return true;
}
motionaction = MEvent.getActionMasked();
if(motionaction == MotionEvent.ACTION_POINTER_DOWN)
{
...
return true;
}
if(motionaction == MotionEvent.ACTION_POINTER_UP)
{
...
return true;
}
return true;
The gesture it's the follow:
-finger1 on the screen hold its position (virtually because there is always a little movement)
-finger2 move on the screen. This is the movement that i want to grab.
I can grab the 5 action but the problem it's that when two fingers are on the screen the ACTION_MOVE grabs the movement of both first and second finger. The method MEvent.getActionIndex() don't works for the ACTION_MOVE that is return always 0; The only thing that i can do it's to save the position of the finger1 and to discard the movement near to that point. The result it's not perfect indeed sometime the movement of the finger2 it's "tainted" by the little finger1 movement because though the finger holds it's position on the screen the listener feels each minimal movement.
How can i improve this ?
Referring to the answer of Quintin Balsdon:
I have a similar thing in my code. I save the position of the finger1 in the ACTION_DOWN case, then when the finger2 move i see if the Y coordinate of the move is over the saved finger1 Y coordinate. If so the movement it's referred to the finger2 otherwise is referred to finger1 and i discard that in two finger mode.
If i try to draw a circle on my view in one finger mode i have got something like this:
http://img208.imageshack.us/img208/8113/onefingercircle.jpg
If i try to draw a circle on my view in two finger mode i have got something like this:
http://img256.imageshack.us/img256/6778/twofingercircle.jpg
So in one finger mode it work perfectly but not in two finger mode.
I don't know if it's related to the phone multitouch handler or the touch screen. It can be only hardware related also or my misunderstanding of the API.
This is managed by you as the developer. You are going to have to create some boolean variable to set (to true) when the "DOWN" action takes place and then unset (false) when the "UP" or "MOVE" motionevent occurs. In the code below, I maintain the coordinates when the "DOWN" even happens and make adjustments while the user moves around.
switch (e.Action) //e is a MotionEvent type
{
case MotionEvent.ACTION_DOWN:
{
_prevx = e.getX();
_prevy = e.getY();
}
break;
case MotionEvent.ACTION_MOVE:
{
_xoffset += e.GetX() - _prevx;
_yoffset += e.GetY() - _prevy;
Invalidate();
_prevx = e.GetX();
_prevy = e.GetY();
}
break;
}
If you want to do multi-finger dragging you need to implement ScaleGestureDetector.OnScaleGestureListener (http://developer.android.com/reference/android/view/ScaleGestureDetector.OnScaleGestureListener.html)
I'm trying to rotate the camera around an object by using the touchscreen. The rotation around Y axis works fine (The X axis is disabled). Rotation around the X axis is really weird. when the Object (its a rocket) gets higher rocket.position().y++ & scene.camera().position.y++, the rotation around the x axis gets bigger and weird. If the rockets stops rocket.position().y = 500; & scene.camera().position.y = 500;, I can't rotate around x axis, I zoom in or out the object instead. With both axis enabled its weird as hell.
In initScene I set the camera to look at the center of the rocket.
Here's my code:
initScene:
scene.camera().position.z = 90;
scene.camera().target = raketeOBJ.position();
onTouchEvent:
public boolean onTouchEvent(MotionEvent me) {
if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}
if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
touchTurn = 0;
touchTurnUp = 0;
return true;
}
if (me.getAction() == MotionEvent.ACTION_MOVE) {
float xd = me.getX() - xpos;
float yd = me.getY() - ypos;
xpos = me.getX();
ypos = me.getY();
touchTurn = xd / -200f;
touchTurnUp = yd / -200f;
return true;
}
try {
Thread.sleep(15);
} catch (Exception e) {
}
return super.onTouchEvent(me);
}
UpdateScene:
if (touchTurn != 0) {
scene.camera().position.rotateY(touchTurn);
touchTurn = 0;
}
if (touchTurnUp != 0) {
scene.camera().position.rotateX(touchTurnUp);
touchTurnUp = 0;
}
I think it is a view-orientation-issue. try basic android opengl example "rotating cubes", i think it is a similar behaviour.
To avoid this you have to transform display-coordinates into min3D object rotation-coordinates.
Think about moving your finger 1cm on display to the left, with 3D-object following your finger. This means x_display = x_object.
If you rotate your object, there is still a fixed connection between display and object.
(x_display = - 1cm) equals (x_object = -1cm)
at 90° & 270° your object will move xy-inverted, at 180° your object will move x-inverted.
use some sin/cos to overcome this.
edit: also rotationangle (object) = - rotationangle (camera)
One option is to rotate the container itself instead of the camera. In min3d you often work with an Object3dContainer as a class variable in your activity that displays the model. When you get your MotionEvent you can use the method rotation() from your Object3dContainer class and set x or y properties as appropriate.
You keep saying wierd, but you know that it doesn't describe what you see. Rotate is actually method of Number3d. It doesn't know about the target, so I guess rotation is done according the center, not according the rocket (Didn't quite check that, just a guess). There might be 2 solutions:
The easiest thing is to set the rocket to (0,0,0) and instead moving the rocket, move evertything else. Well that would be a stupid suggestion. Forget it.
The other solution is to calculate camera rotation traectory using sin() and cos()
There might be a third solution, but I didn't think a a lot about it and it might be wrong. What you have to do is move the camera like target is at (0,0,0), rotate and then return the camera.
Would look like something like this:
Number3d target = scene.camera.target;
Number3d cp = scene.camera.position.clone();
// move position like target is (0,0,0)
cp.x -= target.x;
cp.y -= target.y;
cp.z -= target.z;
cp.roateX(angle);
// restore offset
cp.x += target.x;
cp.y += target.y;
cp.z += target.z;
scene.camera.position.setAllFrom(cp);
You can try 3 but don't rely it'll do the job.