Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell Gloss-在按下每个帧键时执行某些操作_Haskell_Input_Gloss - Fatal编程技术网

Haskell Gloss-在按下每个帧键时执行某些操作

Haskell Gloss-在按下每个帧键时执行某些操作,haskell,input,gloss,Haskell,Input,Gloss,我想在Haskell Gloss中移动一个对象,每按一帧键,而不仅仅是开始按下键的那一帧。(示例:按下“w”键时,每帧加速一次对象) 编辑:我尝试使用EventKey的第二个参数,但没有效果 我的代码: --TODO - Holding keys doesn't work yet handleKeys :: Event -> AsteroidsGame -> AsteroidsGame handleKeys (EventKey (Char char) _ _ _) game

我想在Haskell Gloss中移动一个对象,每按一帧键,而不仅仅是开始按下键的那一帧。(示例:按下“w”键时,每帧加速一次对象)

编辑:我尝试使用EventKey的第二个参数,但没有效果

我的代码:

--TODO - Holding keys doesn't work yet
handleKeys :: Event -> AsteroidsGame -> AsteroidsGame
handleKeys (EventKey (Char char) _ _ _) game 
        | char == 'w' = move   0   1
        | char == 'a' = move (-1)  0
        | char == 's' = move   0 (-1)
        | char == 'd' = move   1   0
    where move x y = game {player = accelerateObject (player game) x y}
handleKeys _ game = game

accelerateObject :: Object -> Float -> Float -> Object
accelerateObject obj hor ver = obj {vel = (vx + hor, vy + ver)}
    where (vx, vy) = vel obj

正如OP正确推断的那样,gloss为您提供输入事件(“按键刚刚按下”,“鼠标刚刚移动”),而不是输入状态(“按键当前按下”,“鼠标位于x,y”)。似乎没有一种内置的方式来查看每个帧上的输入状态,因此我们必须制定自己的解决方案。谢天谢地,这并不难

作为一个简单的工作示例,我们将制作一个非常有趣的“游戏”,你可以在按下空格键的同时观看计数器向上计数。铆接这种方法适用于处理任何按键操作,因此很容易扩展到您的情况

我们首先需要的是我们的游戏状态:

import qualified Data.Set as S

data World = World
    { keys :: S.Set Key
    , counter :: Int }
update :: Float -> World -> World
update _ world
    | S.member (SpecialKey KeySpace) (keys world) = world { counter = 1 + counter world }
    | otherwise = world { counter = 0 }
我们跟踪特定的游戏状态(在本例中只是一个计数器),以及解决方案的状态(一组按下的键)

处理输入事件只需将一个键添加到当前按下的一组键或将其移除:

handleInput :: Event -> World -> World
handleInput (EventKey k Down _ _) world = world { keys = S.insert k (keys world)}
handleInput (EventKey k Up _ _) world = world { keys = S.delete k (keys world)}
handleInput _ world = world -- Ignore non-keypresses for simplicity
通过更改
World
类型以跟踪光标的最后一个已知坐标,并在看到
EventMotion
事件时在此函数中设置光标,可以轻松地扩展到处理鼠标移动等操作

然后,我们的帧到帧世界更新功能使用输入状态更新特定游戏状态:

import qualified Data.Set as S

data World = World
    { keys :: S.Set Key
    , counter :: Int }
update :: Float -> World -> World
update _ world
    | S.member (SpecialKey KeySpace) (keys world) = world { counter = 1 + counter world }
    | otherwise = world { counter = 0 }
如果当前按下空格键(
S.member(SpecialKey-Space)(keys-world)
),则增加计数器-否则,将其重置为0。我们不关心帧之间经过了多少时间,所以忽略float参数

最后,我们可以渲染游戏并进行游戏:

render :: World -> Picture
render = color white . text . show . counter

main :: IO ()
main = play display black 30 initWorld render handleInput update
    where
        display = InWindow "test" (800, 600) (0, 0)
        initWorld = World S.empty 0

只需在游戏中跟踪按下的键?我假设EventKey会告诉您按键是按下还是释放。正如@Krom所说,检查
向下
事件和
向上
事件。根据您的环境,在按键释放之前,您应该会看到重复的
Down
事件,该事件应显示为
Up
事件。@BobDalgleish我认为Down事件仅在按键时触发,而不是在按键后一次又一次地触发。所以它不起作用。我不知道如何确认没有更多的事件,也就是说,我不知道如何在HaskellYou的其他代码中间打印一些调试信息,可以使用<代码>调试.Trace< /Cult>包插入<代码> Trace< /Cord>语句。通常,当按键开始自动重复时,事件系统应发出事件。例如,任何文本编辑器都会在按住字符键时记录每个字符。检查文档,看看是否有东西没有过滤自动重复字符。@BobDalgleish我现在可以确认按下按钮时只有一个事件,按下按钮时没有更多事件,因此我仍然没有解决方案。