Haskell Gloss - Делайте что-нибудь, что нажимается каждая клавиша - PullRequest
0 голосов
/ 18 октября 2018

Я хочу перемещать объект в 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

1 Ответ

0 голосов
/ 06 декабря 2018

При правильном выводе OP, глянец отображает события ввода («клавиша только что нажата», «мышь только что перемещена»), а не состояние ввода («клавиша в данный момент нажата», «мышь находится в точке х, у»),Кажется, не существует встроенного способа просмотра состояния ввода в каждом кадре, поэтому нам придется сделать наш обходной путь.К счастью, это не так уж сложно!

Для простого рабочего примера мы сделаем невероятно забавную «игру», в которой вы можете наблюдать за счетчиком вверх, пока нажата клавиша пробела.Клепка.Этот подход обобщает обработку любых нажатий клавиш, поэтому его будет легко распространить на ваш случай.

Первое, что нам нужно, это состояние нашей игры:

import qualified Data.Set as S

data World = World
    { keys :: S.Set Key
    , counter :: Int }

Мы отслеживаемнаше конкретное состояние игры (в данном случае просто счетчик), а также состояние нашего обходного пути (набор нажатых клавиш).

Обработка событий ввода просто включает либо добавление ключа к нашему набору нажатых в данный момент клавишили удаляя его:

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.

Наш мир от кадра к кадруЗатем функция обновления использует состояние ввода для обновления определенного игрового состояния:

update :: Float -> World -> World
update _ world
    | S.member (SpecialKey KeySpace) (keys world) = world { counter = 1 + counter world }
    | otherwise = world { counter = 0 }

Если в данный момент нажата пробел (S.member (SpecialKey KeySpace) (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
...