Game设计中的一些问题

一、            轮询键盘
轮询键盘会带来新的问题。首先,一次按键可能带来两次响应的问题。尽管移动设备上的FPS很低,但对于按键来说还是太快了。以下是常见的解决方法:
方法一:使用时间阈值技术。设定一个时间阈值。比如100ms,比较同一个按键两次按下的时间间隔。若小于这个时间阈值则不做处理,若大于这个时间阈值则执行相关的逻辑。
private long leftLastPressedTime=0;//记录上次左键按下的时间
private long limit=100;//定100ms为时间阈值
private void input(){
  int keyState=getKeyStates();
  if((keyState&LEFT_PRESSED)!=0)
     long pastime=System.currentTimeMillis()-leftLastPressedTime;
     if(pastTime>limit){
    leftLastPressedTime+=pastime;
    doSomething();
}
}
方 法二:设置标志变量。通过检查一个标志变量来确定按键的状态。当检测到按键按下后,若标记为false,则说明第一次按下,应处理逻辑。之后将标记变量改 为true,说明已经处理过了,下次就不再处理了;当按键抬起时,标记变量被重置,这样以可以进行下一次处理了。以下是运用标志变量思想的代码。
private boolean leftFlag=false;//标记变量
private void input(){//处理输入
    int keyState=getKeyStates();
    if((keyState&LEFT_PRESSED)!=0){
    doSomething();
    leftFlag=true;
}else{
    leftFlag=false;
}
}
另 一个重要的问题是如何清除已经记录的按键缓冲区。通常为了界面的美观,游戏的主画面和菜单都在同一个Canvas上绘制,当从游戏主画面切换到菜单,或反 过来从菜单切换到游戏时,可能上一个画面的按键没有被处理便遗留到了新的画面。这时希望清除在上一个画面没有处理的残余按键。方法是两次调用 getKeyStates()。getKeyStates()有一个附加的作用是清空键盘缓冲区,所以两次调用getKeyStates()从理论上讲会 返回当前的按键状态。

二、            实现自己的键盘映射机制
设计一种键盘响应机制,既要基于轮询又要拥有传统回调的灵活性。此外最好能简捷的解决轮询中的常见问题。这个输入组件应该提供的功能有:
n        将键盘 keyCode映射到通用的输入action上;
n        能够模拟按键;
n        用户可自定义按键;
n        可清除按键状态;
n        一部分按键遵循只要按下就起作用的模式(支持重复按键);
n        一部分按键遵循按下后只起一次作用的模式。
这 个输入组件由两部分组成:InputAction类和InputManager类。InputAction类代表了按键的逻辑映射; InputManager类负责将keyCode映射到哪一个InputAction上。先来看看InputAction具有的两种检测模式: MODE_NORMAL和MODE_INTAL_ONLY。前者遵循只要按下就起作用的模式(支持重复按键);后者遵循按下后只起一次作用的模式。 InputAction的使用很简单,只要轮询调用InputAction实例的isPressed()方法就可以了,它会根据不同的模式,返回按键是否 按下。以下是InputAction类的代码

public

class InputAction {
    //两种检测模式
     public static final int MODE_NORAML =0;
     public static final int MODE_INITAL_ONLY =1;
    
    //三种按键状态
     private static final int STATE_PRESSED =1;
     private static final int STATE_RELEASED =2;
     private static final int STATE_HOLDON =3;
    
    //检测模式变量
     private int mode;
    
    //按键状态变量
     private int state;
    
     public InputAction(){
       this ( MODE_NORAML );
    }
    
     public InputAction( int mode){
       this .mode=mode;
       this .state= STATE_RELEASED ;
       reset();
    }
    
     public synchronized void press(){//按下
       if (state!= STATE_HOLDON )
           state= STATE_PRESSED ;
    }
    
     public synchronized void release(){//释放
       state= STATE_RELEASED ;
    }
    
     public synchronized void reset(){//重置
       release();
    }
    
     public synchronized void tap(){//模拟一次按键
       press();
       release();
    }
    
     public synchronized boolean isPressed(){
       int lastState=state;
       if (state== STATE_PRESSED &&mode== MODE_INITAL_ONLY )
           state= STATE_HOLDON ;
       return lastState== STATE_PRESSED ;
    }
    
}

InputManager 类负责管理将keyCode映射到哪一个InputAction上。它内部维护了一个Map。以keyCode作为(key),以InputAction 对象实例作为值。通过调用方法mapkeyToInputAction(int keyCode,InputAction action)来进行按键映射。这种机制允许将多个键盘映射到同一个InputStream上。例如,将方向“↑”和数字键“2”都映射到一个 InputAction上。以下是InputManager类的代码。
import java.util.Enumeration;
import java.util.Hashtable;


public class InputManager {
    private Hashtable keyMap=new Hashtable();//保存键盘映射的MAP
    
    public InputManager(){
      
    }
    
    public void mapkeyCodeToInputAction(int keyCode,InputAction action){
       keyMap.put(new Integer(keyCode),action );//将一个整型keyCode映射到一个action
    }
    
    public void clearAll(){//清空所有的映射
       keyMap.clear();
    }
    
    public void keyPressed(int keyCode){//回调方法,用于键盘按下
       InputAction action=getInputAction(keyCode);
       if(action!=null)
           action.press();
    }
    
    public void keyReleased(int keyCode){//回调方法,用于键盘释放
       InputAction action=getInputAction(keyCode);
       if(action!=null)
           action.release();
    }
    
    public void keyRepeated(int keyCode){//回调方法,用于键盘重复,保持空白
      
    }
    
    protected InputAction getInputAction(int keyCode){//取得map中与之对应的action
       return (InputAction)keyMap.get(new Integer(keyCode));
    }
    
    public void resetAll(){//
       for(Enumeration e=keyMap.elements();e.hasMoreElements();)
           ((InputAction)e.nextElement()).reset();
    }
}
下 面是使用方法。首先实例化一个InputStream对象,并在职Canvas的三个回调函数中分别对InputManager的对应方法进行回调。准备 工作完成后,可以根据需求以不同的检测模式参数来构造InputAction对象。可选的模式有InputAction.MODE_NORMAL和 InputAction.MODE_INITAL_ONLY。调用inputManager.mapkeyCodeToAction()方法,将不同的 KeyCode映射到InputAction对象上。使用时只要在轮询的input()方法中轮询调用InputAction实例的isPressed方 法就可以了。
import javax.microedition.lcdui.game.GameCanvas;


public class GameScreenInputEnable extends GameCanvas implements Runnable{
    //...
    InputManager inputManager= new InputManager();
    
    InputAction upAction= new InputAction(InputAction. MODE_INITAL_ONLY );
    InputAction downAction= new InputAction();
    //...
    
     public GameScreenInputEnable(){
       super ( false );
    }
    
     public void run(){
       //The main part of the Game
    }
    
     public void init(){
       //...
       inputManager.mapkeyCodeToInputAction( KEY_NUM2 , upAction); //映射数字键
       inputManager.mapkeyCodeToInputAction( KEY_NUM8 , downAction);
       inputManager.mapkeyCodeToInputAction(-1, upAction);//映射方向导航键
       inputManager.mapkeyCodeToInputAction(-2, downAction);
    }
    
     public void input(){
       if (upAction.isPressed()){
           // TODO
       }
       if (downAction.isPressed()){
           // TODO
       }
    }
    
     protected void keyPressed( int keyCode){//
       inputManager.keyPressed(keyCode);
    }
    
     protected void keyReleased( int keyCode){
       inputManager.keyReleased(keyCode);
    }
    
     protected void keyRepeated( int keyCode){
       inputManager.keyRepeated(keyCode);
    }
    
}
在这个例子中,方向导航键“↑”和数字键“2”被映射到了upAction,并只在按下后起一次作用。对应的方向导航键“↓”和数字键“8”被映射到了downAction,在按下后总是有效。
可以在运行时改变按键的检测模式和按键的映射关系,这为在运行时由用户自行配置按键提供了可能。使用这个输入组件的前提条件是:GameCanvas不能屏蔽键盘事件,即构造函数传入false,不能为true。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值