纯golang语言开发客户端
前提:
游戏库 ebiten
引擎介绍地址 ebiten.org/
Ebiten 是Go 编程语言的开源游戏库。Ebiten 的简单 API 允许您快速轻松地开发可以跨多个平台部署的 2D 游戏。有别于unity3d,UE,cocos creator,godot等游戏引擎,没有图形界面。
没优化之前代码:
1.玩家的结构体如下:
里面定义了6个map数据结构,在游戏初始化阶段,根据事先分类好的图片名字(一共368张散装图),分类存入map。
type Player struct {
X float64
Y float64
State int
Direction int
MouseX int
MouseY int
ImgNow map[int]*ebiten.Image
ImgWeaNow map[int]*ebiten.Image
ImgSkillNow map[int]*ebiten.Image
asset map[string]*ebiten.Image //man
assetWea map[string]*ebiten.Image //weapon
skill_asset map[string]*ebiten.Image //skill
image *embed.FS
}
func NewPlayer(x, y float64, state, dir, mx, my int, images *embed.FS) *Player {
play := &Player{
X: x,
Y: y,
State: state,
Direction: dir,
MouseX: mx,
MouseY: my,
ImgNow: make(map[int]*ebiten.Image, 8),
ImgWeaNow: make(map[int]*ebiten.Image, 8),
ImgSkillNow: make(map[int]*ebiten.Image, 6),
asset: make(map[string]*ebiten.Image, 160),
assetWea: make(map[string]*ebiten.Image, 160),
skill_asset: make(map[string]*ebiten.Image, 48),
image: images,
}
return play
}
2.加载游戏素材
利用go协程并发加载游戏素材和手动GC
func (p *Player) LoadImages() {
wg := sync.WaitGroup{}
wg.Add(3)
//load skill images
go func() {
for j := 0; j < 8; j++ {
for i := 0; i < 6; i++ {
s, _ := p.image.ReadFile("resource/man/skill/" + strconv.Itoa(j) + "_skill_" + strconv.Itoa(i) + ".png")
mg := tools.GetEbitenImage(s)
name := strconv.Itoa(j) + "_" + strconv.Itoa(i)
p.skill_asset[name] = mg
}
}
go func() {
runtime.GC()
}()
wg.Done()
}()
...........
}
此种模式下,一次性使用多个map存储大量的数据,导致游戏启动阶段。内存占用相当之高,高达890MB左右,随着游戏运行,golang自动GC,才缓慢降到300MB左右。
优化方案
1.使用图集打包工具,将散图合批成一张大图。
为什么使用图集:
减少游戏包体和内存占用
减少drawcall,提高cpu和GPU效率。
打包后如下图:
| 一个json文件
| 一张图集
2.根据小图在大图中的位置,读取目标图块。
使用texturepacker工具库,去读取上面的JSON文件。
只支持”JSON (Hash)” 格式
https://github.com/fzipp/texturepacker
3.代码优化
少使用Map存储大量数据
type Player struct {
X float64
Y float64
State int
Direction int
MouseX int
MouseY int
image *embed.FS
}
func NewPlayer(x, y float64, state, dir, mx, my int, images *embed.FS) *Player {
play := &Player{
X: x,
Y: y,
State: state,
Direction: dir,
MouseX: mx,
MouseY: my,
image: images,
}
return play
}
素材不事先存入大量map,当渲染到对应图像的时候,直接从图集中截取。这样大大提高程序效率和减少内存占用。
imagess, x, y := g.player.GetAnimator("man", name)
//player option
op = &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(SCREENWIDTH/2+OFFSETX+x), float64(SCREENHEIGHT/2+OFFSETY+y))
op.GeoM.Scale(0.7, 0.7)
op.Filter = ebiten.FilterLinear
screen.DrawImage(imagess, op)
游戏素材加载资源后在代码尾部加入适当的手动GC
go func() {
runtime.GC()
}()
通过上面的代码改造,现在启动阶段能稳定在240mb左右。
源码地址github地址 Demo
本作品采用《CC 协议》,转载必须注明作者和本文链接