如何在Gloss Haskell中实施多个级别?

发布于 2025-02-12 07:30:44 字数 898 浏览 0 评论 0原文

我正在尝试在Haskell中实施具有多个级别的游戏。每个级别都有不同但广义的游戏状态。我们可以像以下内容一样定义游戏状态

type Player = (Float, Float) -- Player coordinates
data State a = State Player a Bool

- a是环境。在一个级别上,它被定义为String,在另一个级别中,它被定义为([int],[int])。 Bool确定水平是否完成。

我实现了两个不同的功能,它们使用play from graphics.gloss.interface.pure.game。我可以将任何此功能都注入main并单独播放。例如 -

lv1 = play window black 90 (State (0,0) "Hello" False) drawLv1 handleLv1 updateLv1
lv2 = play window black 90 (State (0,0) ([1,2,3,4], [0,0,0,0]) False) drawLv2 handleLv2 updateLv2

main :: IO()
main = lv1
-- main = lv2

但是,我想以某种方式从LV1转到LV2。我知道Haskell函数可以作为值传递,并且显然有一种将主函数从lv1更改为lv2的方法,但我无法弄清楚。

解决方案或有关如何正确处理问题的想法将非常好。

I am trying to implement a game with multiple levels in Haskell. Each level has different but generalized game state. We can define the game state like the following-

type Player = (Float, Float) -- Player coordinates
data State a = State Player a Bool

Here, a is the environment. In one level it is defined as String and in another level it is defined as ([Int], [Int]). And the Bool determines if level is complete or not.

I have two different functions implemented that uses play from Graphics.Gloss.Interface.Pure.Game. I can inject any of this functions to the main and play them individually. For example-

lv1 = play window black 90 (State (0,0) "Hello" False) drawLv1 handleLv1 updateLv1
lv2 = play window black 90 (State (0,0) ([1,2,3,4], [0,0,0,0]) False) drawLv2 handleLv2 updateLv2

main :: IO()
main = lv1
-- main = lv2

However, I want to go from lv1 to lv2 somehow. I know that Haskell functions can be passed through as values and there is obviously a way to change the main function from lv1 to lv2 but I cannot figure that out.

A solution or maybe an idea on how the problem can be generalized and handled properly, would be very nice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

涙—继续流 2025-02-19 07:30:44

当您说这些级别可以具有不同的类型时,以某种方式播放级别的游戏代码必须在解释和修改此状态值。因此,必须有从字符串到游戏中某些类型的功能,而从([int],[int])到相​​同类型的等效函数。

如果是这样,则需要将这些功能放入类中:

class MyGameState a where
   someFunction :: a -> Int
   someOtherFunction :: a -> Thing
   updateGameState :: Int -> a -> a

instance MyGameState String where
   someFunction str = .....
   someOtherFunction str = ......
   updateGameState n oldState = ......

实例myGamestate([int],[int])同样。然后,您可以使用somefunctionsomeotherfunction来定义游戏玩法功能。

When you say that the levels can have different types, somehow your game code that plays the levels must be interpreting and modifying this state value. So there must be functions from a String to some types in your game, and equivalent function from ([Int], [Int]) to the same types.

If so then you need to put these functions in a class:

class MyGameState a where
   someFunction :: a -> Int
   someOtherFunction :: a -> Thing
   updateGameState :: Int -> a -> a

instance MyGameState String where
   someFunction str = .....
   someOtherFunction str = ......
   updateGameState n oldState = ......

And likewise for instance MyGameState ([Int],[Int]). Then you can define your game play function using someFunction and someOtherFunction.

夏日落 2025-02-19 07:30:44

我决定写我最终解决问题的方法,因为其他人可能会遇到与我相同的问题 -

首先,我更改了state数据,以制造一个通用系统,以更好地在不同级别之间进行过渡。因此,我现在拥有状态,而不是当前状态a数据,但是使用新的参数level

type Player = (Float, Float) -- Player coordinates
-- data State a = State Player a Bool
data State = State {
    getPlayer :: Player,
    getLevel :: Level,
    levelCompleted :: Bool
}
data Level = Lv1 String | Lv2 ([Int], [Int])

,我需要相应地修复特定级别的功能。例如,

updateLv1 :: Float -> State -> State
-- If com is true then level is complete
updateLv1 _ (State player (Lv1 st) com) =
    if com then State (0,0) ([1,2,3,4], [0,0,0,0]) False
    else
        ...
        ...

updateLv1 time state = commonUpdater time state

绘图和事件处理程序也是如此。

最后,我必须修复普通处理程序 -

commonUpdater time state = case getLevel state of
    Lv1 _ = updateLv1 time state
    Lv2 _ = updateLv2 time state

我也必须实现concomhandlerconsondrawer。该过程几乎相同。

最后,播放功能很容易。我只需要初始化LV1状态,而休息就是通过共同的功能来处理的 -

game :: IO()
game = play window black 90 (State (0,0) (Lv2 "Hello") False) commonDrawer commonHandler commonUpdater

main :: IO()
main = game

仅此而已!

I decided to write how I finally solved the problem since others might face the same problem as me-

First of all, I changed the State data to make a generalized system for better transition between different levels. So instead of current State a data, I now have State but with a new parameter Level

type Player = (Float, Float) -- Player coordinates
-- data State a = State Player a Bool
data State = State {
    getPlayer :: Player,
    getLevel :: Level,
    levelCompleted :: Bool
}
data Level = Lv1 String | Lv2 ([Int], [Int])

Then I needed to fix the level specific functions accordingly. For example-

updateLv1 :: Float -> State -> State
-- If com is true then level is complete
updateLv1 _ (State player (Lv1 st) com) =
    if com then State (0,0) ([1,2,3,4], [0,0,0,0]) False
    else
        ...
        ...

updateLv1 time state = commonUpdater time state

Same goes for drawing and event handlers.

Finally I had to fix the common handlers-

commonUpdater time state = case getLevel state of
    Lv1 _ = updateLv1 time state
    Lv2 _ = updateLv2 time state

I had to implement the commonHandler and commonDrawer too. The process is almost the same.

Finally the play function was easy. I just had to initialize the Lv1 state and rest were to be handled by common functions-

game :: IO()
game = play window black 90 (State (0,0) (Lv2 "Hello") False) commonDrawer commonHandler commonUpdater

main :: IO()
main = game

That's all!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文