在没有控制台输出或创建新函数的情况下使用 MATLAB 'KeyPressFcn'

mda*_*ani 0 matlab character keypress

我正在用 Matlab 制作游戏(一种太空入侵者射击游戏)图形都在一个图形上,只是用多个情节生成,我知道 matlab 不适合这些东西,这使得向同学们展示特别有趣。对于我目前使用的关键输入:

f = figure(1)
set(f, 'KeyPressFcn', @(x,y)disp(get(f,'CurrentCharacter')));
a = get(f,'CurrentCharacter');
if a=='w' %move up..
if a=='d' %move right..
if a=='2' %switch to weapon 2..
Run Code Online (Sandbox Code Playgroud)

这工作得很好,但每次按下一个键时,它都会显示在控制台上,导致不必要的延迟。

我试过:

f = figure(1)
set(f, 'KeyPressFcn');
a = get(f,'CurrentCharacter');
Run Code Online (Sandbox Code Playgroud)

但每次按下一个键时它都会显示“字符串 - 或 - 函数句柄 - 或 - 单元格数组”。

如何识别按键并将其存储到变量中而不在控制台上弹出任何内容?我也希望不必创建第二个功能,因为目前所有内容都干净地保存在一个 .m 文件中。

谢谢!

小智 5

作为 MATLAB Central 上一些流行游戏的作者,我可以让您了解如何在 MATLAB 中正确执行此操作。我不能保证我的方法不是最好的,但这是我考虑这个问题多年后想出的最好的解决方案。首先,我在编写游戏时通常会遵循一些原则:

  1. 使用 'CurrentKey' 代替 'CurrentCharacter',因为前者可以识别更多未被归类为“字符”的键。

  2. 您可能还需要一个“KeyReleaseFcn”,因为这是一个射击游戏。通常,您希望飞机在按住某个键时保持移动,并在松开键时停止;您不想为了让飞机继续移动而反复按下和松开按键。它的工作原理是:当玩家按下“w”时,我们调用 KeyPressedFcn 一次,其中我们将标志变量“w_status”设置为 true;当玩家释放 'w' 时,调用 KeyReleasedFcn 一次,并将标志设置为 flase。在游戏的主循环中,反复检查 'w_status' 是否为真。如果是,则将飞行器向上移动一步,否则不更新位置。

  3. 如果您想将所有内容保存在一个文件中,请尝试将 KeyPressFcn 和 KeyReleaseFcn 实现为嵌套函数。这比将所有代码压缩到一行中要好。

  4. 避免在 if-else 子句中使用硬编码的键名。您稍后可能希望允许用户重新分配键,因此最好将键名保存在可以修改的数组中。

所以整个游戏会是这样的:

    function MainGame()

    KeyStatus = false(1,6);    % Suppose you are using 6 keys in the game
    KeyNames = {'w', 'a','s', 'd', 'j', 'k'};
    KEY.UP = 1;
    KEY.DOWN = 2;
    KEY.LEFT = 3;
    KEY.RIGHT = 4;
    KEY.BULLET = 5;
    KEY.BOMB = 6;
    ...
        gameWin = figure(..., 'KeyPressFcn', @MyKeyDown, 'KeyReleaseFcn', @MyKeyUp)
        ...
    % Main game loop
    while GameNotOver
        if KeyStatus(KEY.UP)  % If left key is pressed
            player.y = player.y - ystep;
        end
        if KeyStatus(KEY.LEFT)  % If left key is pressed
            player.x = player.x - xstep;
        end
        if KeyStatus(KEY.RIGHT)  % If left key is pressed
            %..
        end
        %...
    end

    % Nested callbacks...
        function MyKeyDown(hObject, event, handles)
            key = get(hObject,'CurrentKey');
            % e.g., If 'd' and 'j' are already held down, and key == 's'is
            % pressed now
            % then KeyStatus == [0, 0, 0, 1, 1, 0] initially
            % strcmp(key, KeyNames) -> [0, 0, 1, 0, 0, 0, 0]
            % strcmp(key, KeyNames) | KeyStatus -> [0, 0, 1, 1, 1, 0]
            KeyStatus = (strcmp(key, KeyNames) | KeyStatus);
        end
        function MyKeyUp(hObject, event, handles)
            key = get(hObject,'CurrentKey');
            % e.g., If 'd', 'j' and 's' are already held down, and key == 's'is
            % released now
            % then KeyStatus == [0, 0, 1, 1, 1, 0] initially
            % strcmp(key, KeyNames) -> [0, 0, 1, 0, 0, 0]
            % ~strcmp(key, KeyNames) -> [1, 1, 0, 1, 1, 1]
            % ~strcmp(key, KeyNames) & KeyStatus -> [0, 0, 0, 1, 1, 0]
            KeyStatus = (~strcmp(key, KeyNames) & KeyStatus);
        end

    end
Run Code Online (Sandbox Code Playgroud)

请注意,回调使用“字典”键名来消除对任何 if-else 子句的需要。这样,无论使用多少个按键以及它们的实际用途如何,这两个功能都可以插入任何游戏而无需任何修改。

要了解这个想法在现实生活中是如何运作的,您可以在 MATLAB Central 上查看我的游戏:

http://www.mathworks.com/matlabcentral/fileexchange/authors/111235

那里有一款太空射击游戏“Stellaria”。不过是在我不知道嵌套函数的那天写的,所以代码被拆分成很多小的函数文件,可能很难阅读。请谨慎使用。