Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
机器学习中的交叉验证
总第100篇 本篇讲讲机器学习中的交叉验证问题,并利用sklearn实现。 前言 在说交叉验证以前,我们先想一下我们在搭建模型时的关于数据切分的常规做法[直接利用train_test_split把所有的数据集分成两部分:train_data和test_data,先在train_data上进行训练,然后再在test_data上进行测试评估模型效果的好坏]。 因为我们训练模型时,不是直接把数丢进去就好了,而是需要对模型的不断进行调整(比如参数),使模型在测试集上的表现足够好,但是即使模型在测试集上效果好,不
张俊红
2018/04/11
2K0
机器学习中的交叉验证
深度学习中超大规模数据集的处理
在机器学习项目中,如果使用的是比较小的数据集,数据集的处理上可以非常简单:加载每个单独的图像,对其进行预处理,然后输送给神经网络。但是,对于大规模数据集(例如ImageNet),我们需要创建一次只访问一部分数据集的数据生成器(比如mini batch),然后将小批量数据传递给网络。其实,这种方法在我们之前的示例中也有所涉及,在使用数据增强技术提升模型泛化能力一文中,我就介绍了通过数据增强技术批量扩充数据集,虽然那里并没有使用到超大规模的数据集。Keras提供的方法允许使用磁盘上的原始文件路径作为训练输入,而不必将整个数据集存储在内存中。
云水木石
2019/07/02
1.5K0
深度学习中超大规模数据集的处理
机器学习|模型选择之划分数据集及Sklearn实现
直接将数据集D划分为两个互斥的集合:训练集S和测试集T(D = S∪T,S∩T = ∅),在S上训练模型,用T来评估其测试误差。
用户1621951
2019/10/18
2.5K0
微调YOLOv11:实用指南 【详细过程与代码】
本指南旨在引导您为自身任务微调YOLOv11。我将分享我个人认为有效的步骤,附带详细代码、真实案例及实用建议。内容包括:
小白学视觉
2025/01/07
1.2K0
微调YOLOv11:实用指南 【详细过程与代码】
英文文本关系抽取(fine-tune Huggingface XLNet)
本文主要是基于英文文本关系抽取比赛,讲解如何fine-tune Huggingface的预训练模型,同时可以看作是关系抽取的一个简单案例
mathor
2020/08/31
1.5K0
智能环保卫士:AI 图像识别助力垃圾分类与环保教育
不用多讲,想必大部分也都知道深度学习是人工智能的一个重要分支,它通过构建多层神经网络来模拟人脑的信息处理方式。在图像识别领域,深度学习模型(如卷积神经网络,CNN)能够自动从大量图像数据中学习特征,从而实现对图像的分类和识别。尤其是近年来,深度学习在图像识别任务中取得了显著的成果,其准确率和效率都得到了极大的提升。
三掌柜
2025/04/18
1230
使用自己的数据集训练MobileNet、ResNet实现图像分类(TensorFlow)| CSDN博文精选
之前写了一篇博客《使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)》https://panjinquan.blog.csdn.net/article/details/81560537,本博客就是此博客的框架基础上,完成对MobileNet的图像分类模型的训练,其相关项目的代码也会统一更新到一个Github中,强烈建议先看这篇博客《使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)》后,再来看这篇博客。
AI科技大本营
2019/12/23
7K0
在Python和R中使用交叉验证方法提高模型性能
模型表现差异很大的可能原因是什么?换句话说,为什么在别人评估我们的模型时会失去稳定性?
拓端
2021/01/28
1.7K0
在Python和R中使用交叉验证方法提高模型性能
MNIST手写数据集
MNIST是一个非常经典的手写数字数据集,由美国国家标准与技术研究所(NIST)在20世纪80年代整理和标注。这个数据集包含了一系列0到9的手写数字图像,用于机器学习中的图像分类任务。MNIST数据集被广泛应用于训练和验证机器学习模型的性能。
大盘鸡拌面
2023/10/22
8940
使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)「建议收藏」
【尊重原创,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/81560537
全栈程序员站长
2022/09/21
1.2K0
使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)「建议收藏」
python︱sklearn一些小技巧的记录(训练集划分/pipelline/交叉验证等)
版权声明:博主原创文章,微信公众号:素质云笔记,转载请注明来源“素质云博客”,谢谢合作!! https://blog.csdn.net/sinat_26917383/article/details/77917881
悟乙己
2019/05/26
1.4K0
深入探索:【人工智能】、【机器学习】与【深度学习】的全景视觉之旅
人工智能(Artificial Intelligence, AI)是计算机科学的一个分支,旨在开发能够模拟或增强人类智能的系统。AI的研究范围广泛,涵盖了从基础算法到复杂系统的开发。
小李很执着
2024/08/14
1410
Python 深度学习第二版(GPT 重译)(三)
您现在对 Keras 有了一些经验——您熟悉 Sequential 模型、Dense 层以及用于训练、评估和推断的内置 API——compile()、fit()、evaluate() 和 predict()。您甚至在第三章中学习了如何从 Layer 类继承以创建自定义层,以及如何使用 TensorFlow 的 GradientTape 实现逐步训练循环。
ApacheCN_飞龙
2024/03/21
4270
Python 深度学习第二版(GPT 重译)(三)
B.机器学习实战系列[一]:工业蒸汽量预测(最新版本下篇)含特征优化模型融合等
K折交叉验证: KFold 将所有的样例划分为 k 个组,称为折叠 (fold) (如果 k = n, 这等价于 Leave One Out(留一) 策略),都具有相同的大小(如果可能)。预测函数学习时使用 k - 1 个折叠中的数据,最后一个剩下的折叠会用于测试。
汀丶人工智能
2023/03/28
1.6K0
B.机器学习实战系列[一]:工业蒸汽量预测(最新版本下篇)含特征优化模型融合等
深度揭秘,教你驾驭 AI 大模型的无限可能
随着人工智能技术的飞速发展,AI 大模型在诸多领域展现出了强大的能力。然而,要充分发挥其潜力,正确的使用方法至关重要。
羑悻的小杀马特.
2025/03/30
1810
手把手学机器学习算法中数据预处理(附代码)
当你想了解机器学习,最好的方式就是用真实的数据入手做实验。网络上有很多优秀的开源资料。这里我们选择了加利福尼亚的房价数据集(数据的获得后面会给出),它的统计图如下所示,横纵坐标分别代表经纬度,图上有很多圈圈,而圈圈的大小代表着人口数,颜色图则表示房均价,那么一堆数据到手了,但是我们到底要做什么呢?
智能算法
2020/09/08
1K0
手把手搭建一个【卷积神经网络】
本文介绍卷积神经网络的入门案例,通过搭建和训练一个模型,来对10种常见的物体进行识别分类;使用到CIFAR10数据集,它包含10 类,即:“飞机”,“汽车”,“鸟”,“猫”,“鹿”, “狗”,“青蛙”,“马”,“船”,“卡车” ;共 60000 张彩色图片;通过搭建和训练卷积神经网络模型,对图像进行分类,能识别出图像是“汽车”,或“鸟”,还是其它。
一颗小树x
2021/05/12
1.5K0
手把手搭建一个【卷积神经网络】
机器学习数据集的获取和测试集的构建方法
上一篇机器学习入门系列(2)--如何构建一个完整的机器学习项目(一)介绍了开始一个机器学习项目需要明确的问题,比如当前任务属于有监督还是无监督学习问题,然后性能指标需要选择什么,常用的分类和回归损失函数有哪些,以及实际开发中需要明确系统的输入输出接口问题。
kbsc13
2019/08/16
2.6K0
1维卷积神经网络_卷积神经网络 一维信号处理
  维卷积神经网络,可以用来做一维的数据分析,以家用电器的识别分类作为背景。使用excel画出的简单的图形如下,横坐标为用电器开启后的秒数,纵坐标为某一秒的有功功率,由上至下分别为空调(Air Conditioner),冰箱(Refrigerator),烤炉(Stove): !
全栈程序员站长
2022/09/30
2.1K0
1维卷积神经网络_卷积神经网络 一维信号处理
使用贝叶斯优化进行深度神经网络超参数优化
为了方便起见本文将使用 Tensorflow 中包含的 Fashion MNIST[1] 数据集。该数据集在训练集中包含 60,000 张灰度图像,在测试集中包含 10,000 张图像。每张图片代表属于 10 个类别之一的单品(“T 恤/上衣”、“裤子”、“套头衫”等)。因此这是一个多类分类问题。
deephub
2022/11/11
1.3K0
使用贝叶斯优化进行深度神经网络超参数优化
推荐阅读
相关推荐
机器学习中的交叉验证
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验