You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:45:58