前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Golang语言情怀--第132期 Go语言Ebiten引擎全栈游戏开发:第3节:游戏手柄事件监听实例分析

Golang语言情怀--第132期 Go语言Ebiten引擎全栈游戏开发:第3节:游戏手柄事件监听实例分析

作者头像
李海彬
发布2024-11-07 17:21:20
发布2024-11-07 17:21:20
12000
代码可运行
举报
文章被收录于专栏:Golang语言社区Golang语言社区
运行总次数:0
代码可运行

Ebiten框架手柄监听

首先,游戏手柄操作游戏是部分主机游戏必备,最近比较火的黑神话·悟空等等,手机游戏也可以使用手柄的,目前我们的坦克对决单机版就支持了手柄,后续完成给大家提供下载。直接上代码,如下:

代码语言:javascript
代码运行次数:0
复制
package main

import (
    "fmt"
    "github.com/hajimehoshi/ebiten/v2"
    "log"
    "sort"
    "strconv"
    "strings"
    "time"

    "github.com/hajimehoshi/ebiten/v2/ebitenutil"
    "github.com/hajimehoshi/ebiten/v2/inpututil"
)

const (
    screenWidth  = 640
    screenHeight = 480
)

type Game struct {
    gamepadIDsBuf  []ebiten.GamepadID
    gamepadIDs     map[ebiten.GamepadID]struct{}
    axes           map[ebiten.GamepadID][]string
    pressedButtons map[ebiten.GamepadID][]string
}

func (g *Game) Update() error {
    if g.gamepadIDs == nil {
        g.gamepadIDs = map[ebiten.GamepadID]struct{}{}
    }

    // Log the gamepad connection events.
    g.gamepadIDsBuf = inpututil.AppendJustConnectedGamepadIDs(g.gamepadIDsBuf[:0])
    for _, id := range g.gamepadIDsBuf {
        log.Printf("gamepad connected: id: %d, SDL ID: %s", id, ebiten.GamepadSDLID(id))
        g.gamepadIDs[id] = struct{}{}
    }
    for id := range g.gamepadIDs {
        if inpututil.IsGamepadJustDisconnected(id) {
            log.Printf("gamepad disconnected: id: %d", id)
            delete(g.gamepadIDs, id)
        }
    }

    g.axes = map[ebiten.GamepadID][]string{}
    g.pressedButtons = map[ebiten.GamepadID][]string{}
    for id := range g.gamepadIDs {
        maxAxis := ebiten.GamepadAxisType(ebiten.GamepadAxisCount(id))
        for a := ebiten.GamepadAxisType(0); a < maxAxis; a++ {
            v := ebiten.GamepadAxisValue(id, a)
            g.axes[id] = append(g.axes[id], fmt.Sprintf("%d:%+0.2f", a, v))
        }

        maxButton := ebiten.GamepadButton(ebiten.GamepadButtonCount(id))
        for b := ebiten.GamepadButton(0); b < maxButton; b++ {
            if ebiten.IsGamepadButtonPressed(id, b) {
                g.pressedButtons[id] = append(g.pressedButtons[id], strconv.Itoa(int(b)))
            }

            // Log button events.
            if inpututil.IsGamepadButtonJustPressed(id, b) {
                log.Printf("button pressed: id: %d, button: %d", id, b)
            }
            if inpututil.IsGamepadButtonJustReleased(id, b) {
                log.Printf("button released: id: %d, button: %d", id, b)
            }
        }

        if ebiten.IsStandardGamepadLayoutAvailable(id) {
            for b := ebiten.StandardGamepadButton(0); b <= ebiten.StandardGamepadButtonMax; b++ {
                // Log button events.
                if inpututil.IsStandardGamepadButtonJustPressed(id, b) {
                    var strong float64
                    var weak float64
                    switch b {
                    case ebiten.StandardGamepadButtonLeftTop,
                        ebiten.StandardGamepadButtonLeftLeft,
                        ebiten.StandardGamepadButtonLeftRight,
                        ebiten.StandardGamepadButtonLeftBottom:
                        weak = 0.5
                    case ebiten.StandardGamepadButtonRightTop,
                        ebiten.StandardGamepadButtonRightLeft,
                        ebiten.StandardGamepadButtonRightRight,
                        ebiten.StandardGamepadButtonRightBottom:
                        strong = 0.5
                    }
                    if strong > 0 || weak > 0 {
                        op := &ebiten.VibrateGamepadOptions{
                            Duration:        200 * time.Millisecond,
                            StrongMagnitude: strong,
                            WeakMagnitude:   weak,
                        }
                        ebiten.VibrateGamepad(id, op)
                    }
                    log.Printf("standard button pressed: id: %d, button: %d", id, b)
                }
                if inpututil.IsStandardGamepadButtonJustReleased(id, b) {
                    log.Printf("standard button released: id: %d, button: %d", id, b)
                }
            }
        }
    }
    return nil
}

var standardButtonToString = map[ebiten.StandardGamepadButton]string{
    ebiten.StandardGamepadButtonRightBottom:      "RB",
    ebiten.StandardGamepadButtonRightRight:       "RR",
    ebiten.StandardGamepadButtonRightLeft:        "RL",
    ebiten.StandardGamepadButtonRightTop:         "RT",
    ebiten.StandardGamepadButtonFrontTopLeft:     "FTL",
    ebiten.StandardGamepadButtonFrontTopRight:    "FTR",
    ebiten.StandardGamepadButtonFrontBottomLeft:  "FBL",
    ebiten.StandardGamepadButtonFrontBottomRight: "FBR",
    ebiten.StandardGamepadButtonCenterLeft:       "CL",
    ebiten.StandardGamepadButtonCenterRight:      "CR",
    ebiten.StandardGamepadButtonLeftStick:        "LS",
    ebiten.StandardGamepadButtonRightStick:       "RS",
    ebiten.StandardGamepadButtonLeftBottom:       "LB",
    ebiten.StandardGamepadButtonLeftRight:        "LR",
    ebiten.StandardGamepadButtonLeftLeft:         "LL",
    ebiten.StandardGamepadButtonLeftTop:          "LT",
    ebiten.StandardGamepadButtonCenterCenter:     "CC",
}

func standardMap(id ebiten.GamepadID) string {
    m := `       [FBL ]                    [FBR ]
     [FTL ]                    [FTR ]

     [LT  ]       [CC  ]       [RT  ]
  [LL  ][LR  ] [CL  ][CR  ] [RL  ][RR  ]
     [LB  ]                    [RB  ]
           [LS  ]       [RS  ]
`

    for b, str := range standardButtonToString {
        placeholder := "[" + str + strings.Repeat(" ", 4-len(str)) + "]"
        v := ebiten.StandardGamepadButtonValue(id, b)
        switch {
        case !ebiten.IsStandardGamepadButtonAvailable(id, b):
            m = strings.Replace(m, placeholder, "  --  ", 1)
        case ebiten.IsStandardGamepadButtonPressed(id, b):
            m = strings.Replace(m, placeholder, fmt.Sprintf("[%0.2f]", v), 1)
        default:
            m = strings.Replace(m, placeholder, fmt.Sprintf(" %0.2f ", v), 1)
        }
    }

    // TODO: Use ebiten.IsStandardGamepadAxisAvailable
    m += fmt.Sprintf("    Left Stick:  X: %+0.2f, Y: %+0.2f\n    Right Stick: X: %+0.2f, Y: %+0.2f",
        ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickHorizontal),
        ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisLeftStickVertical),
        ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisRightStickHorizontal),
        ebiten.StandardGamepadAxisValue(id, ebiten.StandardGamepadAxisRightStickVertical))
    return m
}

func (g *Game) Draw(screen *ebiten.Image) {
    // Draw the current gamepad status.
    str := ""
    if len(g.gamepadIDs) > 0 {
        ids := make([]ebiten.GamepadID, 0, len(g.gamepadIDs))
        for id := range g.gamepadIDs {
            ids = append(ids, id)
        }
        sort.Slice(ids, func(a, b int) bool {
            return ids[a] < ids[b]
        })
        for _, id := range ids {
            var standard string
            if ebiten.IsStandardGamepadLayoutAvailable(id) {
                standard = " (Standard Layout)"
            }
            str += fmt.Sprintf("Gamepad (ID: %d, SDL ID: %s)%s:\n", id, ebiten.GamepadSDLID(id), standard)
            str += fmt.Sprintf("  Name:    %s\n", ebiten.GamepadName(id))
            str += fmt.Sprintf("  Axes:    %s\n", strings.Join(g.axes[id], ", "))
            str += fmt.Sprintf("  Buttons: %s\n", strings.Join(g.pressedButtons[id], ", "))
            if ebiten.IsStandardGamepadLayoutAvailable(id) {
                str += "\n"
                str += standardMap(id) + "\n"
            }
            str += "\n"
        }
    } else {
        str = "Please connect your gamepad."
    }
    ebitenutil.DebugPrint(screen, str)
}

func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
    return screenWidth, screenHeight
}

func main() {
    ebiten.SetWindowSize(screenWidth, screenHeight)
    ebiten.SetWindowTitle("Gamepad (Ebitengine Demo)")
    if err := ebiten.RunGame(&Game{}); err != nil {
        log.Fatal(err)
    }
}

分析代码

手柄按键的定义:

代码语言:javascript
代码运行次数:0
复制
var standardButtonToString = map[ebiten.StandardGamepadButton]string{
    ebiten.StandardGamepadButtonRightBottom:      "RB",
    ebiten.StandardGamepadButtonRightRight:       "RR",
    ebiten.StandardGamepadButtonRightLeft:        "RL",
    ebiten.StandardGamepadButtonRightTop:         "RT",
    ebiten.StandardGamepadButtonFrontTopLeft:     "FTL",
    ebiten.StandardGamepadButtonFrontTopRight:    "FTR",
    ebiten.StandardGamepadButtonFrontBottomLeft:  "FBL",
    ebiten.StandardGamepadButtonFrontBottomRight: "FBR",
    ebiten.StandardGamepadButtonCenterLeft:       "CL",
    ebiten.StandardGamepadButtonCenterRight:      "CR",
    ebiten.StandardGamepadButtonLeftStick:        "LS",
    ebiten.StandardGamepadButtonRightStick:       "RS",
    ebiten.StandardGamepadButtonLeftBottom:       "LB",
    ebiten.StandardGamepadButtonLeftRight:        "LR",
    ebiten.StandardGamepadButtonLeftLeft:         "LL",
    ebiten.StandardGamepadButtonLeftTop:          "LT",
    ebiten.StandardGamepadButtonCenterCenter:     "CC",
}

手柄事件的监听,支持多个手柄操作:

代码语言:javascript
代码运行次数:0
复制
func (g *Game) Update() error {
    if g.gamepadIDs == nil {
        g.gamepadIDs = map[ebiten.GamepadID]struct{}{}
    }

    // Log the gamepad connection events.
    g.gamepadIDsBuf = inpututil.AppendJustConnectedGamepadIDs(g.gamepadIDsBuf[:0])
    for _, id := range g.gamepadIDsBuf {
        log.Printf("gamepad connected: id: %d, SDL ID: %s", id, ebiten.GamepadSDLID(id))
        g.gamepadIDs[id] = struct{}{}
    }
    for id := range g.gamepadIDs {
        if inpututil.IsGamepadJustDisconnected(id) {
            log.Printf("gamepad disconnected: id: %d", id)
            delete(g.gamepadIDs, id)
        }
    }

    g.axes = map[ebiten.GamepadID][]string{}
    g.pressedButtons = map[ebiten.GamepadID][]string{}
    for id := range g.gamepadIDs {
        maxAxis := ebiten.GamepadAxisType(ebiten.GamepadAxisCount(id))
        for a := ebiten.GamepadAxisType(0); a < maxAxis; a++ {
            v := ebiten.GamepadAxisValue(id, a)
            g.axes[id] = append(g.axes[id], fmt.Sprintf("%d:%+0.2f", a, v))
        }

        maxButton := ebiten.GamepadButton(ebiten.GamepadButtonCount(id))
        for b := ebiten.GamepadButton(0); b < maxButton; b++ {
            if ebiten.IsGamepadButtonPressed(id, b) {
                g.pressedButtons[id] = append(g.pressedButtons[id], strconv.Itoa(int(b)))
            }

            // Log button events.
            if inpututil.IsGamepadButtonJustPressed(id, b) {
                log.Printf("button pressed: id: %d, button: %d", id, b)
            }
            if inpututil.IsGamepadButtonJustReleased(id, b) {
                log.Printf("button released: id: %d, button: %d", id, b)
            }
        }

        if ebiten.IsStandardGamepadLayoutAvailable(id) {
            for b := ebiten.StandardGamepadButton(0); b <= ebiten.StandardGamepadButtonMax; b++ {
                // Log button events.
                if inpututil.IsStandardGamepadButtonJustPressed(id, b) {
                    var strong float64
                    var weak float64
                    switch b {
                    case ebiten.StandardGamepadButtonLeftTop,
                        ebiten.StandardGamepadButtonLeftLeft,
                        ebiten.StandardGamepadButtonLeftRight,
                        ebiten.StandardGamepadButtonLeftBottom:
                        weak = 0.5
                    case ebiten.StandardGamepadButtonRightTop,
                        ebiten.StandardGamepadButtonRightLeft,
                        ebiten.StandardGamepadButtonRightRight,
                        ebiten.StandardGamepadButtonRightBottom:
                        strong = 0.5
                    }
                    if strong > 0 || weak > 0 {
                        op := &ebiten.VibrateGamepadOptions{
                            Duration:        200 * time.Millisecond,
                            StrongMagnitude: strong,
                            WeakMagnitude:   weak,
                        }
                        ebiten.VibrateGamepad(id, op)
                    }
                    log.Printf("standard button pressed: id: %d, button: %d", id, b)
                }
                if inpututil.IsStandardGamepadButtonJustReleased(id, b) {
                    log.Printf("standard button released: id: %d, button: %d", id, b)
                }
            }
        }
    }
    return nil
}

以上是Ebiten引擎的手操操作实例代码,代码不难,很简单;如果有不懂的可以留言。

同学们,兴趣是最好的老师;只争朝夕,不负韶华!加油!

参考资料:

Go语言中文文档

http://www.golang.ltd/

Golang语言情怀

ID:wwwGolangLtd

www.Golang.Ltd

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言情怀 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Ebiten框架手柄监听
  • 分析代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档