【发布时间】:2011-11-05 05:34:57
【问题描述】:
我正在制作一款游戏,并希望实现像 Konami 代码这样的作弊代码。
但是如何检查击键顺序呢?
我希望它能够正常工作,以便玩家只要输入代码就会触发。
提前致谢!
【问题讨论】:
我正在制作一款游戏,并希望实现像 Konami 代码这样的作弊代码。
但是如何检查击键顺序呢?
我希望它能够正常工作,以便玩家只要输入代码就会触发。
提前致谢!
【问题讨论】:
下面是一个检查Konami代码的类,包括“UP, UP, UP, DOWN等”的情况
这应该适用于任何给定的序列。
import java.util.Map;
import java.util.TreeMap;
public class Konami {
static private int[] code =
{UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B};
static private Map<Integer, Integer>[] graph;
static private int currentNode = 0;
public static void main(String args[]) {
//Create graph
graph = generateSequenceMap(code);
//Call checkKonami(key) whenever a key is pressed
}
static public boolean checkKonami(int keyPressed) {
Integer nextNode = graph[currentNode].get(keyPressed);
//Set currentNode to nextNode or to 0 if no matching sub-sequence exists
currentNode = (nextNode==null ? 0 : nextNode);
return currentNode == code.length-1;
}
static private Map<Integer, Integer>[] generateSequenceMap(int[] sequence) {
//Create map
Map<Integer, Integer>[] graph = new Map[sequence.length];
for(int i=0 ; i<sequence.length ; i++) {
graph[i] = new TreeMap<Integer,Integer>();
}
//i is delta
for(int i=0 ; i<sequence.length ; i++) {
loop: for(int j=i ; j<sequence.length-1 ; j++) {
if(sequence[j-i] == sequence[j]) {
System.out.println("If at Node "+j+" you give me seq["+(j-i+1)
+ "] OR " + (sequence[j-i+1]) + " , goto Node " + (j-i+1));
//Ensure that the longest possible sub-sequence is recognized
Integer value = graph[j].get(sequence[j-i+1]);
if(value == null || value < j-i+1)
graph[j].put(sequence[j-i+1], j-i+1);
}
else
break loop;
}
}
return graph;
}
}
【讨论】:
编辑: 有关始终有效的代码,请参阅我的另一篇文章。如果代码与自身重叠,则以下代码不会检测到(例如:“UP, UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B”不起作用)
感谢 Gevorg 指出这一点。
如果它只是如何识别您关心的序列(我假设您知道如何从键盘获取输入),那么您可以使用以下内容。
int[] sequence = {UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B};
int currentButton = 0;
boolean checkKonami(int keyPressed) {
//Key sequence pressed is correct thus far
if(keyPressed == sequence[currentButton]) {
currentButton++;
//return true when last button is pressed
if(currentButton == sequence.length) {
//Important! Next call to checkKonami()
//would result in ArrayIndexOutOfBoundsException otherwise
currentButton = 0;
return true;
}
}
else {
//Reset currentButton
currentButton = 0;
}
return false;
}
每当注册按键时调用此函数,并传递已按下的键。当然在适当的地方修改类型。
【讨论】:
我确定您现在已经完成了这个项目,但我刚刚将它应用到我的一项任务中,并希望将它留给其他人查找。此解决方案将最后 n 次击键(此处定义为 10)记录到一个循环数组中,并在它们与我们的代码匹配时返回 true。作为方法的一部分,您可以轻松地传递不同的长度和代码(但此实现不需要它)。我用过 ^ ^ v v b a.
public class Code {
private static int[] history = new int[10];
private static int front = 0;
private static int size = 0;
// Here is the Code they must enter (ascii vals for konami).
private static int[] code = {38, 38, 40, 40, 37, 39, 37, 39, 66, 65};
// Static class. No constructor.
private Code(){}
// Adds key-press into history buffer. If code is matched, return true.
public static boolean add(int e){
// Write the value into our key history.
history[(front + size) % 10] = e;
// Stop growing at length 10 and overwrite the oldest value instead.
if (size < 10){
size++;
} else {
front = front + 1 % 10;
}
// Compare our history (from the current front) to the code (from 0)
for(int i = front; i < front + size; i++){
if (history[i % 10] != code[i-front]){
// Any 1 mismatch will abort
return false;
}
}
// Make sure we've logged enough keystrokes so it doesn't fire off
// if your first key press matches the code.
if (size < 10){
return false;
}
return true;
}
享受吧! :D
【讨论】:
我不知道你的需求是什么。您是在尝试使用 System.in 和 System.out 创建游戏,还是尝试制作完整的可视化 GUI?
同时,请参阅接口java.awt.event.KeyListener。 (Oracle Documentation) 另见Oracle's Tutorial。
根据个人经验,下面的代码与您需要的差不多。
import java.awt.event.*; //Specifically KeyListener and KeyEvent
import java.util.ArrayList;
public class Test implements KeyListener {
private final int[] cheatCode = {38, 38, 40, 40, 37, 39, 37, 39, 66, 65, 83, 84, 65, 82, 84} //assuming user types out "start"
private final ArrayList<Integer> KONAMI_CODE = createCheatCode(cheatCode);
private ArrayList<Integer> typedKeys = new ArrayList<Integer>();
public Test() {
//constructor goes here, if necessary
}
public /*static*/ ArrayList<Integer> createCheatCode(int[] code) { //uses Key Codes
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 0; i < code.length; i++)
temp.add(new Integer(code[i]));
return temp;
}
// Warning: MUST implement ALL KeyListener methods, or compiler will complain
public /*static*/ void keyPressed(KeyEvent e) {}
public /*static*/ void keyReleased(KeyEvent e) {
typedKeys.add(new Integer(e.getKeyCode()));
}
public /*static*/ void keyTyped(KeyEvent e) {}
public /*static*/ boolean cheatEntered() {
int cheatLen = KONAMI_CODE.size(); // or length, depending on what you use
int index = typedKeys.size() - cheatLen;
if (index < 0)
return false;
return typedKeys.get(index, typedKeys.size()).equals(KONAMI_CODE);
}
}
当使用 runner 方法时,只需指定
if (test.cheatEntered()) {
// do something
}
如果你想要面向对象的编程,你可以删除/*static*/;否则,如果您想使用静态方法运行它,请去掉 /* 和 */ 对。
【讨论】:
keyTyped 中完成。 typedKeys.add(keyChar) 之类的东西,对 KONAMI_CODE 常量进行索引比较检查。如果其中一个字符不对应,则typedKeys.clear() 否则会触发作弊或设置标志。知道是否可以一次输入多个密钥会很有趣,在这种情况下应该添加一些额外的检查。
查看状态模式可能会很有趣,但您可以尝试以下技巧,因为这是一个简单的案例:
String secretCode
StringBuilder userInput 来保存用户按下的键userInput
userInput 中附加的每个键之后,检查更新后的userInput 是否包含secretCode 以及以下内容:userInput.indexOf(secretCode)>-1
您可能希望从现在开始清空userInput,然后根据时间或在识别出序列之后。
【讨论】: