前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Golang语言情怀--第133期 Go语言Ebiten引擎全栈游戏开发:第4节:sprites实例分析

Golang语言情怀--第133期 Go语言Ebiten引擎全栈游戏开发:第4节:sprites实例分析

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

sprites实例分析

sprite在游戏中我们常见的角色信息、面板UI都可以定义为sprite,翻译中文就是游戏中的精灵,也是前端游戏开发中需要掌握的知识点。

代码如下:

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

import (
    "bytes"
    "fmt"
    "image"
    _ "image/png"
    "log"
    "math"
    "math/rand/v2"

    "github.com/hajimehoshi/ebiten/v2"
    "github.com/hajimehoshi/ebiten/v2/ebitenutil"
    "github.com/hajimehoshi/ebiten/v2/examples/resources/images"
)

const (
    screenWidth  = 320
    screenHeight = 240
    maxAngle     = 256
)

var (
    ebitenImage *ebiten.Image
)

func init() {
    // Decode an image from the image file's byte slice.
    img, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
    if err != nil {
        log.Fatal(err)
    }
    origEbitenImage := ebiten.NewImageFromImage(img)

    s := origEbitenImage.Bounds().Size()
    ebitenImage = ebiten.NewImage(s.X, s.Y)

    op := &ebiten.DrawImageOptions{}
    op.ColorScale.ScaleAlpha(0.5)
    ebitenImage.DrawImage(origEbitenImage, op)
}

type Sprite struct {
    imageWidth  int
    imageHeight int
    x           int
    y           int
    vx          int
    vy          int
    angle       int
}

func (s *Sprite) Update() {
    s.x += s.vx
    s.y += s.vy
    if s.x < 0 {
        s.x = -s.x
        s.vx = -s.vx
    } else if mx := screenWidth - s.imageWidth; mx <= s.x {
        s.x = 2*mx - s.x
        s.vx = -s.vx
    }
    if s.y < 0 {
        s.y = -s.y
        s.vy = -s.vy
    } else if my := screenHeight - s.imageHeight; my <= s.y {
        s.y = 2*my - s.y
        s.vy = -s.vy
    }
    s.angle++
    if s.angle == maxAngle {
        s.angle = 0
    }
}

type Sprites struct {
    sprites []*Sprite
    num     int
}

func (s *Sprites) Update() {
    for i := 0; i < s.num; i++ {
        s.sprites[i].Update()
    }
}

const (
    MinSprites = 0
    MaxSprites = 50000
)

type Game struct {
    touchIDs []ebiten.TouchID
    sprites  Sprites
    op       ebiten.DrawImageOptions
    inited   bool
}

func (g *Game) init() {
    defer func() {
        g.inited = true
    }()

    g.sprites.sprites = make([]*Sprite, MaxSprites)
    g.sprites.num = 500
    for i := range g.sprites.sprites {
        w, h := ebitenImage.Bounds().Dx(), ebitenImage.Bounds().Dy()
        x, y := rand.IntN(screenWidth-w), rand.IntN(screenHeight-h)
        vx, vy := 2*rand.IntN(2)-1, 2*rand.IntN(2)-1
        a := rand.IntN(maxAngle)
        g.sprites.sprites[i] = &Sprite{
            imageWidth:  w,
            imageHeight: h,
            x:           x,
            y:           y,
            vx:          vx,
            vy:          vy,
            angle:       a,
        }
    }
}

func (g *Game) leftTouched() bool {
    for _, id := range g.touchIDs {
        x, _ := ebiten.TouchPosition(id)
        if x < screenWidth/2 {
            return true
        }
    }
    return false
}

func (g *Game) rightTouched() bool {
    for _, id := range g.touchIDs {
        x, _ := ebiten.TouchPosition(id)
        if x >= screenWidth/2 {
            return true
        }
    }
    return false
}

func (g *Game) Update() error {
    if !g.inited {
        g.init()
    }
    g.touchIDs = ebiten.AppendTouchIDs(g.touchIDs[:0])

    // Decrease the number of the sprites.
    if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || g.leftTouched() {
        g.sprites.num -= 20
        if g.sprites.num < MinSprites {
            g.sprites.num = MinSprites
        }
    }

    // Increase the number of the sprites.
    if ebiten.IsKeyPressed(ebiten.KeyArrowRight) || g.rightTouched() {
        g.sprites.num += 20
        if MaxSprites < g.sprites.num {
            g.sprites.num = MaxSprites
        }
    }

    g.sprites.Update()
    return nil
}

func (g *Game) Draw(screen *ebiten.Image) {
    // Draw each sprite.
    // DrawImage can be called many many times, but in the implementation,
    // the actual draw call to GPU is very few since these calls satisfy
    // some conditions e.g. all the rendering sources and targets are same.
    // For more detail, see:
    // https://pkg.go.dev/github.com/hajimehoshi/ebiten/v2#Image.DrawImage
    w, h := ebitenImage.Bounds().Dx(), ebitenImage.Bounds().Dy()
    for i := 0; i < g.sprites.num; i++ {
        s := g.sprites.sprites[i]
        g.op.GeoM.Reset()
        g.op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
        g.op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
        g.op.GeoM.Translate(float64(w)/2, float64(h)/2)
        g.op.GeoM.Translate(float64(s.x), float64(s.y))
        screen.DrawImage(ebitenImage, &g.op)
    }
    msg := fmt.Sprintf(`TPS: %0.2f
FPS: %0.2f
Num of sprites: %d
Press <- or -> to change the number of sprites`, ebiten.ActualTPS(), ebiten.ActualFPS(), g.sprites.num)
    ebitenutil.DebugPrint(screen, msg)
}

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

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

核心代码分析

通过矿建函数Draw()绘制所有精灵,并显示出来,代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (g *Game) Draw(screen *ebiten.Image) {
    // Draw each sprite.
    // DrawImage can be called many many times, but in the implementation,
    // the actual draw call to GPU is very few since these calls satisfy
    // some conditions e.g. all the rendering sources and targets are same.
    // For more detail, see:
    // https://pkg.go.dev/github.com/hajimehoshi/ebiten/v2#Image.DrawImage
    w, h := ebitenImage.Bounds().Dx(), ebitenImage.Bounds().Dy()
    for i := 0; i < g.sprites.num; i++ {
        s := g.sprites.sprites[i]
        g.op.GeoM.Reset()
        g.op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
        g.op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
        g.op.GeoM.Translate(float64(w)/2, float64(h)/2)
        g.op.GeoM.Translate(float64(s.x), float64(s.y))
        screen.DrawImage(ebitenImage, &g.op)
    }
    msg := fmt.Sprintf(`TPS: %0.2f
FPS: %0.2f
Num of sprites: %d
Press <- or -> to change the number of sprites`, ebiten.ActualTPS(), ebiten.ActualFPS(), g.sprites.num)
    ebitenutil.DebugPrint(screen, msg)
}

增减精灵的数量,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (g *Game) Update() error {
    if !g.inited {
        g.init()
    }
    g.touchIDs = ebiten.AppendTouchIDs(g.touchIDs[:0])

    // Decrease the number of the sprites.
    if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || g.leftTouched() {
        g.sprites.num -= 20
        if g.sprites.num < MinSprites {
            g.sprites.num = MinSprites
        }
    }

    // Increase the number of the sprites.
    if ebiten.IsKeyPressed(ebiten.KeyArrowRight) || g.rightTouched() {
        g.sprites.num += 20
        if MaxSprites < g.sprites.num {
            g.sprites.num = MaxSprites
        }
    }

    g.sprites.Update()
    return nil
}

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

社区自己开发的IO小游戏,欢迎体验:

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

参考资料:

Go语言中文文档

http://www.golang.ltd/

Golang语言情怀

ID:wwwGolangLtd

www.Golang.Ltd

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Golang语言情怀--第136期 Go语言Ebiten引擎全栈游戏开发:第7节:video实例(直播技术基础)
video实例这个例子其实动视频、直播流、推拉流的技术人员,应该有种小惊喜;意思可以用Go来做视频监控,直播,视频播放器了,也不用自己再封装系统调用了,直播推拉流技术我一直再研究,有疑问的可以一起探讨。同时还是涉及到FFmpeg,如果不懂的可以和我交流
李海彬
2024/11/11
1360
Golang语言情怀--第136期 Go语言Ebiten引擎全栈游戏开发:第7节:video实例(直播技术基础)
Golang语言情怀--第130期 Go语言Ebiten引擎全栈游戏开发:第1节:Ebiten介绍
Ebiten是一个使用Go语言编程库,用于2D游戏开发,可以跨平台。 Ebiten官网,https://ebiten.org/ Ebiten官方API文档,https://pkg.go.dev/github.com/hajimehoshi/ebiten
李海彬
2024/11/07
1650
Golang语言情怀--第130期 Go语言Ebiten引擎全栈游戏开发:第1节:Ebiten介绍
Golang语言情怀--第137期 Go语言Ebiten引擎全栈游戏开发:第8节:animation实例
游戏中的角色的行走、跑、攻击等等,都是动画来实现的;动画在游戏引擎中也是比不可少的一部分,成熟的游戏引擎针对2D开发游戏而言主要是满足spine动画,spine动画目前是使用比较广泛的,如果不了解的可以去网上查下。如果有不懂的也可以咨询我,《荒野坦克大战》中的部分动画都是我用spine来做的。
李海彬
2024/11/13
2220
Golang语言情怀--第137期 Go语言Ebiten引擎全栈游戏开发:第8节:animation实例
Golang语言情怀--第131期 Go语言Ebiten引擎全栈游戏开发:第2节:Ebiten框架分析
Ebiten是一个使用Go语言编程库,用于2D游戏开发,可以跨平台。本届开始讲解官方实例,实例熟悉后会给大家讲解实战游戏课。 贪吃蛇实例
李海彬
2024/11/07
2020
Golang语言情怀--第131期 Go语言Ebiten引擎全栈游戏开发:第2节:Ebiten框架分析
Golang语言情怀--第138期 Go语言Ebiten引擎全栈游戏开发:第8节:《荒野坦克大战》PC端移植-资源整理
李海彬
2024/11/13
1520
Golang语言情怀--第138期 Go语言Ebiten引擎全栈游戏开发:第8节:《荒野坦克大战》PC端移植-资源整理
Golang语言情怀--第134期 Go语言Ebiten引擎全栈游戏开发:第5节:fonts实例分析
fonts字体也是游戏引擎中比较重要的一个知识点,游戏本身需要视觉感受,不可能像文章一样,游戏中都是宋体、楷体等,所以游戏中fonts是必须要了解和掌握的内容。 实例代码,如下:
李海彬
2024/11/11
1210
Golang语言情怀--第134期 Go语言Ebiten引擎全栈游戏开发:第5节:fonts实例分析
一起用Go做一个小游戏(上)
最近偶然看到一个Go语言库,口号喊出“一个超级简单(dead simple)的2D游戏引擎”,好奇点开了它的官网。
用户7731323
2023/02/14
1.2K0
一起用Go做一个小游戏(上)
Golang语言情怀--第144期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:大厅UI编码
视频地址:https://mpvideo.qpic.cn/0b2e5qab6aaasmadbqr75ftvb3gdd7waahya.f10002.mp4?
李海彬
2024/11/25
870
Golang语言情怀--第144期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:大厅UI编码
Golang语言情怀--第140期 Go语言Ebiten引擎《荒野坦克大战》开发:游客功能UI完成
本节主要是完成:游客登录 涉及到的知识点,主要是按钮,背景相关。 以下代码是个按钮实例,大家可以简单看下:
李海彬
2024/11/15
1840
Golang语言情怀--第140期 Go语言Ebiten引擎《荒野坦克大战》开发:游客功能UI完成
Golang语言情怀--第139期 Go语言Ebiten引擎全栈游戏开发:第9节:《荒野坦克大战》PC端移植-游客功能UI开发
涉及到的知识点,主要是按钮,背景相关。以下代码是个按钮增加图实例,大家可以简单看下代码:
李海彬
2024/11/15
700
Golang语言情怀--第139期 Go语言Ebiten引擎全栈游戏开发:第9节:《荒野坦克大战》PC端移植-游客功能UI开发
一起用Go做一个小游戏(中)
上一篇文章还留了个尾巴,细心的同学应该发现了:飞船可以移动出屏幕!!!现在我们就来限制一下飞船的移动范围。我们规定飞船可以左右超过半个身位,如下图所示:
用户7731323
2023/02/14
6400
一起用Go做一个小游戏(中)
Golang语言情怀--第132期 Go语言Ebiten引擎全栈游戏开发:第3节:游戏手柄事件监听实例分析
首先,游戏手柄操作游戏是部分主机游戏必备,最近比较火的黑神话·悟空等等,手机游戏也可以使用手柄的,目前我们的坦克对决单机版就支持了手柄,后续完成给大家提供下载。直接上代码,如下:
李海彬
2024/11/07
1390
Golang语言情怀--第132期 Go语言Ebiten引擎全栈游戏开发:第3节:游戏手柄事件监听实例分析
Golang语言情怀--第143期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Game服务器
后续会在抖音直播间或者视频给大家讲解,主要文章中贴太多代码特别是项目的都比较晦涩难懂,抖音直播间名称:VersusWar。
李海彬
2024/11/25
750
Golang语言情怀--第143期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Game服务器
Java游戏编程不完全详解-5
在2D游戏中,地图是整体结构,或者我们叫做游戏地图(game map),通常是几个屏幕的宽度表示。有些游戏地图是屏幕的20倍;甚至是100位以上,主要特点是跨屏幕之后,让地图滚动显示,这种类型的游戏又叫做2D平台游戏(2D platform game)。
老九君
2021/10/26
1.7K0
Golang语言情怀--第141期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试登录服务器完成
本节主要调试登录,客户端链接登录服务器,目前已经测试完成,并且成功拿点登录服务器的token数据,如下图:
李海彬
2024/11/19
1000
Golang语言情怀--第141期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试登录服务器完成
Golang语言情怀--第118期 全栈小游戏开发:第9节:精灵帧资源(SpriteFrame)
Cocos Creator 的 SpriteFrame 是 UI 渲染基础图形的容器。其本身管理图像的裁剪和九宫格信息,默认持有一个与其同级的 Texture2D 资源引用。
李海彬
2023/11/22
3840
Golang语言情怀--第118期 全栈小游戏开发:第9节:精灵帧资源(SpriteFrame)
Golang语言情怀--第121期 全栈小游戏开发:第12节:自动图集资源 (Auto Atlas)
自动图集 作为 Cocos Creator 自带的合图功能,可以将指定的一系列碎图打包成一张大图,具体作用和 Texture Packer 的功能很相近。
李海彬
2023/11/29
2480
Golang语言情怀--第121期 全栈小游戏开发:第12节:自动图集资源 (Auto Atlas)
Go语言Web开发|GoFrame框架入门笔记
启动成功后,在浏览器中输入http://127.0.0.1:8000/hello查看结果
Jensen_97
2024/07/14
7850
Golang语言情怀--第142期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Proxy服务器
上一节链接登录服务器成功,通过登录服务器获取到token数据;token数据的作用是通过websocket在游戏服务器验证合法性;本节实现的是客户端链接代理服务器成功,主要思路是客户单通过代理Proxy服务器访问内网游戏服务器。
李海彬
2024/11/21
960
Golang语言情怀--第142期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Proxy服务器
Python pickle 反序列化实例分析
之前 SUCTF 出了一题 pickle 反序列化的杂项题,就感觉相当有意思。后来 Balsn 一次性搞了三个,太强了,学到了很多,感谢这些师傅。下文记录了我的学习笔记以及踩过的坑,希望对大家理解 pickle 有点帮助。
wywwzjj
2023/05/09
8600
Python pickle 反序列化实例分析
推荐阅读
Golang语言情怀--第136期 Go语言Ebiten引擎全栈游戏开发:第7节:video实例(直播技术基础)
1360
Golang语言情怀--第130期 Go语言Ebiten引擎全栈游戏开发:第1节:Ebiten介绍
1650
Golang语言情怀--第137期 Go语言Ebiten引擎全栈游戏开发:第8节:animation实例
2220
Golang语言情怀--第131期 Go语言Ebiten引擎全栈游戏开发:第2节:Ebiten框架分析
2020
Golang语言情怀--第138期 Go语言Ebiten引擎全栈游戏开发:第8节:《荒野坦克大战》PC端移植-资源整理
1520
Golang语言情怀--第134期 Go语言Ebiten引擎全栈游戏开发:第5节:fonts实例分析
1210
一起用Go做一个小游戏(上)
1.2K0
Golang语言情怀--第144期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:大厅UI编码
870
Golang语言情怀--第140期 Go语言Ebiten引擎《荒野坦克大战》开发:游客功能UI完成
1840
Golang语言情怀--第139期 Go语言Ebiten引擎全栈游戏开发:第9节:《荒野坦克大战》PC端移植-游客功能UI开发
700
一起用Go做一个小游戏(中)
6400
Golang语言情怀--第132期 Go语言Ebiten引擎全栈游戏开发:第3节:游戏手柄事件监听实例分析
1390
Golang语言情怀--第143期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Game服务器
750
Java游戏编程不完全详解-5
1.7K0
Golang语言情怀--第141期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试登录服务器完成
1000
Golang语言情怀--第118期 全栈小游戏开发:第9节:精灵帧资源(SpriteFrame)
3840
Golang语言情怀--第121期 全栈小游戏开发:第12节:自动图集资源 (Auto Atlas)
2480
Go语言Web开发|GoFrame框架入门笔记
7850
Golang语言情怀--第142期 Go语言Ebiten引擎《荒野坦克大战》开发PC端:调试访问Proxy服务器
960
Python pickle 反序列化实例分析
8600
相关推荐
Golang语言情怀--第136期 Go语言Ebiten引擎全栈游戏开发:第7节:video实例(直播技术基础)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验