Go SDL2 游戏开发入门3-事件驱动
前言
我们现在已经会显示图片了, 这一节我们来讲一下事件驱动
原理
SDL 事件包括了键盘输入, 鼠标输入, 手柄, 等等
SDL 会将所有发生的事件放到一个队列中去, 用户通过 sdl.PollEvent 来一个个获取, 直到队列为空
退出事件
running := true for running { for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch event.(type) { case *sdl.QuitEvent: println("Quit") running = false break } } sdl.Delay(16) }
- 之前的代码里最后都有这么一段
- for running 作为主循环, running 为 true 时, 循环会一直进行下去
- 在第一层循环里, 再嵌套一个循环不断调用 sdl.PollEvent 来获取事件来处理, 直到处理完所有事件退出这一层循环
- switch 可以通过 *sdl.QuitEvent 来判断事件的类型, 这里判断是否是 quit 事件, 如果是将 running 置为 false, 主循环退出
- sdl.Delay 的作用是做一个延迟, 每16豪秒做一次循环, 近似1秒60帧
完整的键盘事件
package main import ( "fmt" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( KEY_PRESS_SURFACE_DEFAULT = iota KEY_PRESS_SURFACE_UP KEY_PRESS_SURFACE_DOWN KEY_PRESS_SURFACE_LEFT KEY_PRESS_SURFACE_RIGHT KEY_PRESS_SURFACE_TOTAL ) var pressSurface [KEY_PRESS_SURFACE_TOTAL]*sdl.Surface func init() { pressSurface[KEY_PRESS_SURFACE_DEFAULT] = loadSurface("../asserts/image/press.bmp") pressSurface[KEY_PRESS_SURFACE_UP] = loadSurface("../asserts/image/up.bmp") pressSurface[KEY_PRESS_SURFACE_DOWN] = loadSurface("../asserts/image/down.bmp") pressSurface[KEY_PRESS_SURFACE_RIGHT] = loadSurface("../asserts/image/right.bmp") pressSurface[KEY_PRESS_SURFACE_LEFT] = loadSurface("../asserts/image/left.bmp") } func loadSurface(path string) *sdl.Surface { img, err := img.Load(path) if err != nil { panic(err) } return img } func main() { sdl.Init(sdl.INIT_EVERYTHING) defer sdl.Quit() window, _ := sdl.CreateWindow("test", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 670, 620, sdl.WINDOW_SHOWN) defer window.Destroy() surface, _ := window.GetSurface() defer surface.Free() surface.FillRect(nil, sdl.MapRGB(surface.Format, 0x0, 0x0, 0x0)) curSurface := pressSurface[KEY_PRESS_SURFACE_DEFAULT] curSurface.BlitScaled(nil, surface, &sdl.Rect{X: 0, Y: 0, W: 52, H: 52}) window.UpdateSurface() running := true for running { for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { switch t := event.(type) { case *sdl.QuitEvent: println("Quit") running = false break case *sdl.KeyboardEvent: switch t.Keysym.Sym { case sdl.K_UP: curSurface = pressSurface[KEY_PRESS_SURFACE_UP] case sdl.K_DOWN: curSurface = pressSurface[KEY_PRESS_SURFACE_DOWN] case sdl.K_LEFT: curSurface = pressSurface[KEY_PRESS_SURFACE_LEFT] case sdl.K_RIGHT: curSurface = pressSurface[KEY_PRESS_SURFACE_RIGHT] } } } curSurface.Blit(nil, surface, nil) window.UpdateSurface() sdl.Delay(16) } stop() } func stop() { fmt.Println("game stop") for i := 0; i < KEY_PRESS_SURFACE_TOTAL; i++ { pressSurface[i].Free() } }
- 该段代码的作用是打开窗口显示一张默认的图片, 然后用户可以按上下左右键, 按不同的键, 会显示不同的图片
- 初始的 const 定义了6个枚举值, 很容易理解
- pressSurface 是一个指针数组, 大小为5, 存放了5个 surface 指针, 分别指向了默认的 surface, 和上下左右这四个 surface
- init 函数中将五张图片加载进来并赋值给 pressSurface
- loadSurface 函数封装了一下 img.Load 函数, 很容易理解
- main 函数中 window, surface, 都是讲过的, curSurface 我们把它指向 pressSurface 数组中的第0个, 也就是默认 surface
- 主循环 for 中进行事件的检测, QuitEvent 是之前讲过的退出事件, KeyboardEvent 是键盘事件
- 当检测到是 KeyboardEvent 事件的时候, 还要嵌套一层 switch 来检测 t.Keysym.Sym 到底是哪个键被按下
- 根据不同的按键, 将 curSurface 指向 pressSurface 数组中相应的 surface
- 调用 curSurface.Blit 来将图片显示出来
- 最后还有一个 stop 函数, 在退出的时候记得将 surface 内存释放掉