使用sdl2-go的GetKeyboardState实现isKeyJustPressed函数遇异常
问题根源
SDL2的sdl.GetKeyboardState()返回的是指向SDL内部维护的键盘状态数组的切片,不是数组副本。你直接把这个切片赋值给g.prevKeyboardState时,只是让g.prevKeyboardState和后续调用GetKeyboardState()拿到的切片指向同一块内存。这就导致检查按键时,prevKeyBoardState[keyCode]和当前状态永远是同一个值,自然只有当前状态为1时prev也为1。
解决方案
更新前一状态时,必须创建当前键盘状态数组的深拷贝,不能直接赋值切片(切片是引用类型,直接赋值只会复制指针,底层数组还是同一个)。
修改状态更新代码:
// 获取当前键盘状态 currentState := sdl.GetKeyboardState() // 创建新切片并拷贝所有元素 g.prevKeyboardState = make([]uint8, len(currentState)) copy(g.prevKeyboardState, currentState)
初始化g.prevKeyboardState时也要做同样的拷贝:
// 初始化阶段 initialState := sdl.GetKeyboardState() g.prevKeyboardState = make([]uint8, len(initialState)) copy(g.prevKeyboardState, initialState)
完整修正示例
// 定义游戏状态结构体 type Game struct { prevKeyboardState []uint8 } // 按键触发判断函数 func isKeyJustPressed(prevKeyBoardState []uint8, keyCode int) bool { currentState := sdl.GetKeyboardState() // 加边界检查,避免索引越界崩溃 if keyCode < 0 || keyCode >= len(currentState) || keyCode >= len(prevKeyBoardState) { return false } return prevKeyBoardState[keyCode] == 0 && currentState[keyCode] == 1 } // 主循环逻辑 func (g *Game) Update() { // 必须处理事件,SDL才会更新键盘状态 for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() { if _, ok := event.(*sdl.QuitEvent); ok { // 处理退出逻辑 } } // 检查空格键触发 if isKeyJustPressed(g.prevKeyboardState, sdl.SCANCODE_SPACE) { log.Println("空格键被按下了") } // 更新前一状态为当前状态的拷贝 currentState := sdl.GetKeyboardState() g.prevKeyboardState = make([]uint8, len(currentState)) copy(g.prevKeyboardState, currentState) }
额外注意事项
- 每次循环必须调用
sdl.PollEvent()或sdl.WaitEvent(),SDL只有在处理事件时才会更新内部键盘状态,否则GetKeyboardState()返回的状态不会变化。 - 加入索引越界检查,避免传入无效keyCode导致程序崩溃。
内容的提问来源于stack exchange,提问作者Debuholden
相关产品推荐
相关产品推荐

