我正在进行一场简单的三场比赛,类似于宝石迷阵,我只是想通过触摸精灵对象来移动精灵对象,然后将其向左,向右,向上和向下四个方向移动一步。我通过将Down上的X和Y值与Move上的X和Y值进行比较来实现此目的。它起作用但它还远非完美!如果运动不直接,那么很容易得到错误的值。我的问题是:有没有办法改善这一点并使其更好?
我也看了一下手势,但这对我使用的平面视图来说似乎非常复杂。
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("test","Down");
touchActionDownX = (int)event.getX();
touchActionDownY = (int)event.getY();
touchActionMoveStatus = true;
gameLoop.touchX = (int)event.getX();
gameLoop.touchY = (int)event.getY();
gameLoop.touchActionDown = true;
break;
case MotionEvent.ACTION_POINTER_UP:
touchActionMoveStatus = true;
break;
case MotionEvent.ACTION_MOVE:
//Log.i("test","Move");
gameLoop.touchActionMove = true;
if(touchActionMoveStatus) {
touchActionMoveX = (int)event.getX();
touchActionMoveY = (int)event.getY();
if(touchActionMoveX < touchActionDownX)
Log.i("test","Move Left");
else if(touchActionMoveX > touchActionDownX)
Log.i("test","Move Right");
else if(touchActionMoveY < touchActionDownY)
Log.i("test","Move Up");
else if(touchActionMoveY > touchActionDownY)
Log.i("test","Move Down");
touchActionMoveStatus = false; // Will be set to true when pointer is up
}
break;
}
// return false;
return true; // This gets the coordinates all the time
}
答案 0 :(得分:3)
尝试这样的事情:
@Override
public boolean onTouch(View v, MotionEvent event) {
//You may have to play with the value and make it density dependant.
int threshold = 10;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("test","Down");
touchActionDownX = (int)event.getX();
touchActionDownY = (int)event.getY();
touchActionMoveStatus = true;
gameLoop.touchX = (int)event.getX();
gameLoop.touchY = (int)event.getY();
gameLoop.touchActionDown = true;
break;
case MotionEvent.ACTION_POINTER_UP:
touchActionMoveStatus = false;
break;
case MotionEvent.ACTION_MOVE:
//Log.i("test","Move");
gameLoop.touchActionMove = true;
if(touchActionMoveStatus) {
touchActionMoveX = (int)event.getX();
touchActionMoveY = (int)event.getY();
if(touchActionMoveX < (touchActionDownX - threshold) && (touchActionMoveY > (touchActionDownY - threshold)) && (touchActionMoveY (touchActionDownY + threshold))){
Log.i("test","Move Left");//If the move left was greater than the threshold and not greater than the threshold up or down
touchActionMoveStatus = false;
}
else if(touchActionMoveX > (touchActionDownX + threshold) && (touchActionMoveY > (touchActionDownY - threshold)) && (touchActionMoveY < (touchActionDownY + threshold))){
Log.i("test","Move Right");//If the move right was greater than the threshold and not greater than the threshold up or
touchActionMoveStatus = false;
}
else if(touchActionMoveY < (touchActionDownY - threshold) && (touchActionMoveX > (touchActionDownX - threshold)) && (touchActionMoveX < (touchActionDownX + threshold))){
Log.i("test","Move Up");//If the move up was greater than the threshold and not greater than the threshold left or right
touchActionMoveStatus = false;
}
else if(touchActionMoveY > (touchActionDownY + threshold) && (touchActionMoveX > (touchActionDownX - threshold)) && (touchActionMoveX < (touchActionDownX + threshold))){
Log.i("test","Move Down");//If the move down was greater than the threshold and not greater than the threshold left or right
touchActionMoveStatus = false;
}
}
break;
}
// return false;
return true; // This gets the coordinates all the time
}
或使用比例:
@Override
public boolean onTouch(View v, MotionEvent event) {
//You may have to play with the value.
//A value of two means you require the user to move twice as
//far in the direction they intend to move than any perpendicular direction.
float threshold = 2.0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("test","Down");
touchActionDownX = (int)event.getX();
touchActionDownY = (int)event.getY();
touchActionMoveStatus = true;
gameLoop.touchX = (int)event.getX();
gameLoop.touchY = (int)event.getY();
gameLoop.touchActionDown = true;
break;
case MotionEvent.ACTION_POINTER_UP:
touchActionMoveStatus = true;
break;
case MotionEvent.ACTION_MOVE:
//Log.i("test","Move");
gameLoop.touchActionMove = true;
if(touchActionMoveStatus) {
touchActionMoveX = (int)event.getX();
touchActionMoveY = (int)event.getY();
// I haven't tested this so you may have a few typos to correct.
float ratioLeftRight = Math.abs(touchActionMoveX - touchActionDownX)/Math.abs(touchActionMoveY - touchActionDownY)
float ratioUpDown = Math.abs(touchActionMoveY - touchActionDownY)/Math.abs(touchActionMoveX - touchActionDownX)
if(touchActionMoveX < touchActionDownX && ratioLeftRight > threshold){
Log.i("test","Move Left");
touchActionMoveStatus = false;
}
else if(touchActionMoveX > touchActionDownX && ratioLeftRight > threshold){
Log.i("test","Move Right");
touchActionMoveStatus = false;
}
else if(touchActionMoveY < touchActionDownY && ratioUpDown > threshold){
Log.i("test","Move Up");
touchActionMoveStatus = false;
}
else if(touchActionMoveY > touchActionDownY && ratioUpDown > threshold){
Log.i("test","Move Down");
touchActionMoveStatus = false;
}
}
break;
}
// return false;
return true; // This gets the coordinates all the time
}
答案 1 :(得分:3)
我会选择 LARGEST 移动的尺寸并完全忽略另一个尺寸,例如,如果移动是x = 10且y = 8则只使用x尺寸(即左/右)反之亦然。
同样如 Larry McKenzie 所述,使用阈值忽略较小的移动是一个好主意,以防止注册用户不想要的意外移动。将阈值调整为感觉自然的东西。
以下是使用您的示例的一些代码(仅限ACTION_MOVE案例):
case MotionEvent.ACTION_MOVE:
//Log.i("test","Move");
gameLoop.touchActionMove = true;
if(touchActionMoveStatus) {
touchActionMoveX = (int)event.getX();
touchActionMoveY = (int)event.getY();
// setup a threshold (below which no movement would occur)
int threshold = 5; /* tweak this as needed */
// first calculate the "delta" movement amounts
int xMove = touchActionMoveX - touchActionDownX;
int yMove = touchActionMoveY - touchActionDownY;
// now find the largest of the two (note that if they
// are equal, x is assumed largest)
if ( Math.abs( xMove ) >= Math.abs( yMove ) ) { /* X-Axis */
if ( xMove >= threshold )
Log.i("test","Move Right");
else if ( xMove <= -threshold )
Log.i("test","Move Left");
}
else { /* Y-Axis */
if ( yMove >= threshold )
Log.i("test","Move Down");
else if ( yMove <= -threshold )
Log.i("test","Move Up");
}
touchActionMoveStatus = false; // Will be set to true when pointer is up
}
}
break;
注意:正如在其他一些答案中所提到的,因为可能会发生具有非常小值的多个事件,所以最好累积(即总结)移动直到达到阈值 - 您可以使用成员来实现此目的在ACTION_DOWN中重置。一旦达到阈值(在任一维度),那么您可以执行检查哪个方向。
替代方法
另一种方法是检测 FIRST ACTION_MOVE事件中的最大移动,然后将所有进一步的移动锁定到该维度。为此,您需要添加各种状态成员 - 这些成员需要在每个州更新。 这是一个粗略的例子(只有状态跟踪):
// members
private boolean axisLock = false; /* Track When Lock is Required */
private boolean axisX = true; /* Axis to Lock (true) for X, (false) for Y */
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// set this state so that ACTION_MOVE knows a lock is required
axisLock = true;
break;
case MotionEvent.ACTION_UP:
// clear the state in case no move was made
axisLock = false;
case MotionEvent.ACTION_MOVE:
// now lock the axis if this is the first move event
if ( axisLock ) {
// this will set whether the locked axis is X (true) or Y (false)
axisX = event.getX() >= event.getY();
// reset the state (to keep the axis locked)
axisLock = false;
}
// at this point you only need to consider the movement for the locked axis
if ( axisX ) {
int movement = (int)event.getX(); /* Get Movement for Locked Axis */
// check for your movement conditions here
}
else {
int movement = (int)event.getY(); /* Get Movement for Locked Axis */
// check for your movement conditions here
}
break;
}
return true;
}
您可以为此代码添加许多优化,现在它只是说明了基本概念。
答案 2 :(得分:2)
拉里有正确的想法,我只想提出一个小解决方案,
//put this in the wraping class
private static int THRESHOLD = 10;
private static int initX;
private static int initY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initX = (int)event.getX();
initY = (int)event.getY();
break;
case MotionEvent.ACTION_POINTER_UP:
//you can add in some kind of "move back" animation for the item
break;
case MotionEvent.ACTION_MOVE:
if(((int)event.getY - initY) > THRESHOLD){
//move down
break;
}
if(((int)event.getY - initY) > -THRESHOLD){
//move up
break;
}
if(((int)event.getX - initX) > THRESHOLD){
//move right
break;
}
if(((int)event.getX - initX) < -THRESHOLD){
//move left
break;
}
break;
}
}
我没有测试这段代码,只是免费写它,但我希望你能得到我的想法:)