使用onTouchEvent在Android/Java/OpenGL中实现多线程
我有一个OpenGL项目,它有一组游戏对象。我有一个线程,它是在对象上迭代并调用update方法的游戏循环。此外,OpenGL具有drawFrame方法,该方法可以迭代对象并渲染对象。最后,我有第三个线程中的onTouchEvent方法,它迭代对象并调用onTouchEvent方法的每个对象版本 这就是说,当我的一个对象在屏幕触摸的基础上移动位置时,我会在它以前的位置上得到一个对象的鬼图像。这是一个简单的闪烁,但非常恼人,非常明显。其他自由移动的对象(不基于onTouchEvent)本身没有跟踪的重影图像,但调用onTouchEvent方法时位置发生变化的对象会创建重影图像 如何防止这种情况发生?我已经用“synchronized(this)”包装了我的两个方法,但它仍然不起作用使用onTouchEvent在Android/Java/OpenGL中实现多线程,android,multithreading,opengl-es,touch-event,Android,Multithreading,Opengl Es,Touch Event,我有一个OpenGL项目,它有一组游戏对象。我有一个线程,它是在对象上迭代并调用update方法的游戏循环。此外,OpenGL具有drawFrame方法,该方法可以迭代对象并渲染对象。最后,我有第三个线程中的onTouchEvent方法,它迭代对象并调用onTouchEvent方法的每个对象版本 这就是说,当我的一个对象在屏幕触摸的基础上移动位置时,我会在它以前的位置上得到一个对象的鬼图像。这是一个简单的闪烁,但非常恼人,非常明显。其他自由移动的对象(不基于onTouchEvent)本身没有跟踪
public void drawFrame(GL10 gl)
{
if(renderType == RenderType.r2D)
prepare2DDrawing(gl);
else if(renderType == RenderType.r3D)
prepare3DDrawing(gl);
synchronized(this)
{
camera.draw(gl);
for(GameObject obj:objects)
{
gl.glPushMatrix();
obj.draw(gl);
gl.glPopMatrix();
}
}
}
public void update(float time)
{
cds.testCollisions(objects);
synchronized(this)
{
camera.update(time);
for(GameObject obj:objects)
{
obj.update(time);
}
motions.clear();
}
}
public void onTouchEvent(MotionEvent e)
{
if(touchable == Touchable.TOUCHABLE)
{
synchronized(this)
{
for(GameObject obj:objects)
{
obj.onTouchEvent(e);
}
}
}
}
我使用了一个非常相似的游戏对象系统,但有一点不同。我有一个输入类,它有3个数组:
boolean[] isTouched = new boolean[10];
int[] touchX = new int[10];
int[] touchY = new int[10];
我在UI线程的onTouch事件中更新这些变量
当游戏对象发生时,我使用这些变量来确定它是否在游戏对象的更新事件中被触摸过,而不是为游戏对象调用onTouch。如果你想在某个时候切换到多点触摸,这也会使它更干净
如果你想的话,你也可以把变量设置成静态的,我只需要使用多个输入法,这样对我来说就更干净了
同样我建议在发生此类事件时睡眠16 ms。否则,当你将手指放在屏幕上时,你会经历巨大的滞后峰值
我还将发布我对这个问题的处理方法。我的输入类看起来像:
public class MultiTouchHandler implements OnTouchListener {
boolean[] isTouched = new boolean[10];
int[] touchX = new int[10];
int[] touchY = new int[10];
float scaleX;
float scaleY;
public MultiTouchHandler(View view, float scaleX, float scaleY) {
view.setOnTouchListener(this);
this.scaleX = scaleX;
this.scaleY = scaleY;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++)
{
touchX[i] = (int) event.getX(i);
touchY[i] = (int) event.getY(i);
int action = event.getActionMasked();
switch (action)
{
case MotionEvent.ACTION_DOWN:
isTouched[i] = true;
break;
case MotionEvent.ACTION_UP:
isTouched[i] = false;
break;
case MotionEvent.ACTION_POINTER_DOWN:
isTouched[i] = true;
break;
case MotionEvent.ACTION_POINTER_UP:
isTouched[i] = false;
break;
case MotionEvent.ACTION_MOVE:
isTouched[i] = true;
break;
default:
}
}
try {
Thread.sleep(16);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
public boolean isTouchDown(int pointer) {
return isTouched[pointer];
}
public int getTouchX(int pointer) {
return touchX[pointer];
}
public int getTouchY(int pointer) {
return touchY[pointer];
}
}
我希望我所说的有一定的道理,它也适用于您。重影可能是渲染线程有时在更新之后,有时在更新之前出现的结果 考虑以下场景:
synchronized
将无助于解决时间问题。解决方法是在更新线程上处理触摸事件。为此,您可以:
- 将要处理的事件存储在更新线程中。例如,丹尼尔·夏普(Daniel Sharp)的建议,尽管存在一些潜在的陷阱
- 发布
,并在更新线程中处理这些文件。很像Android的可运行文件
/post(runnable)
rununuithread(runnable)
更新方法是否也会改变位置?是的,它会根据其速度改变其位置。相机对象设计为跟随特定对象。当我使相机静止并且控制主对象时,我没有得到任何重影,这意味着它与跟随对象的相机有关。顺便说一句,我建议避免。这种方法依赖于在触摸事件之间进行的更新。在生产者-消费者队列模式中缓冲触摸事件不是更好吗?它会产生很多错误,但如果您能够处理它们,性能会更好。这只是一个解决方法,另一个需要考虑的选项。好吧,只是担心丢失(覆盖)例如一个关闭事件,因为它后面紧接着一个移动事件。
boolean touched = YOURMULTITOUCHHANDLER.isTouchDown(0);
float touchX = YOURMULTITOUCHHANDLER.getTouchX(0);
float touchY = YOURMULTITOUCHHANDLER.getTouchY(0);