You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android游戏开发:Player类中OnTouch事件无法生效问题求助

问题分析与解决方案

首先,你的触摸事件没生效的核心原因很明确:你的Player类虽然实现了View.OnTouchListener,但从来没有任何View把它设置为触摸监听器。触摸事件是由当前显示的GameView(SurfaceView)接收的,而你没有把Player和GameView的触摸事件关联起来,所以Player的onTouch方法永远不会被调用。

快速修复方案

最简单的修复方式是在GameView的构造函数里,把自己的触摸监听器设置为Player实例:

public GameView (Context context){
    super(context);
    simpleTurret = SimpleTurret.getInstance(context);
    player = Player.getInstance(context);
    // 添加这一行,把Player设置为GameView的触摸监听器
    this.setOnTouchListener(player);
    thread.start();
}

这样,当用户触摸GameView时,触摸事件就会传递到Player的onTouch方法里,你的移动逻辑就能正常工作了。

游戏开发最佳实践建议

不过从架构设计的角度来说,让Player类直接处理触摸事件并不是最优的做法,原因如下:

  • Player的核心职责应该是管理角色的状态(位置、生命值、移动逻辑等),而输入处理属于外部交互逻辑,应该和角色逻辑分离。
  • 如果后续需要添加更多输入方式(比如键盘、手柄),或者多个角色共享输入逻辑,这种耦合的设计会让代码变得难以维护。

更合理的做法是:

  1. 让GameView(或者专门的输入管理类)负责接收所有输入事件。
  2. GameView根据输入事件的类型,调用Player提供的状态修改方法(比如startMovingRight()、stopMovingRight())。

修改后的Player类(专注角色逻辑)

public class Player {
    private static Player instance = null;
    int x, y;
    boolean moveRight = false;
    Bitmap sprite;

    public Player (Context context){
        sprite = BitmapFactory.decodeResource(context.getResources(), R.drawable.test_sprite);
        x = 300;
        y = 0;
    }

    public void Update(){
        if (moveRight){
            x += 3;
        } else {
            x -= 3;
        }
    }

    public static Player getInstance(Context context) {
        if (instance == null){
            instance = new Player(context);
        }
        return instance;
    }

    // 对外暴露状态修改方法
    public void startMovingRight() {
        moveRight = true;
    }

    public void stopMovingRight() {
        moveRight = false;
    }

    // 补充必要的getter方法
    public Bitmap getSprite() { return sprite; }
    public int getX() { return x; }
    public int getY() { return y; }
}

修改后的GameView类(处理输入并通知Player)

public class GameView extends SurfaceView implements Runnable, View.OnTouchListener {
    private boolean running = true;
    SurfaceHolder surfaceHolder = getHolder();
    SimpleTurret simpleTurret;
    Player player;
    private Thread thread = new Thread(this);

    public GameView (Context context){
        super(context);
        simpleTurret = SimpleTurret.getInstance(context);
        player = Player.getInstance(context);
        // 设置自身为触摸监听器
        this.setOnTouchListener(this);
        thread.start();
    }

    @Override
    public void run() {
        while (running){
            player.Update(); // 补充调用Player的更新逻辑
            DrawCanvas();
            Control();
        }
    }

    public void DrawCanvas(){
        Canvas canvas = surfaceHolder.lockCanvas();
        if (surfaceHolder.getSurface().isValid()){
            canvas.drawColor(Color.RED);
            canvas.drawBitmap(simpleTurret.getSprite(), simpleTurret.getX(), simpleTurret.getY(), null);
            canvas.drawBitmap(player.getSprite(), player.getX(), player.getY(), null);
            surfaceHolder.unlockCanvasAndPost(canvas);
        }
    }

    public void Control(){
        try{
            thread.sleep(17);
        } catch(InterruptedException e){
            e.printStackTrace();
        }
    }

    // 实现触摸事件处理,通知Player更新状态
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction() & MotionEvent.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                player.startMovingRight();
                break;
            case MotionEvent.ACTION_UP:
                player.stopMovingRight();
                break;
        }
        return true;
    }
}

另外注意:原代码的GameView.run()方法里没有调用player.Update(),这会导致Player的位置永远不会更新,即使触摸事件生效了也看不到移动,我在上面的代码里补充了这一点。

内容的提问来源于stack exchange,提问作者Frenchie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:04:05