专栏名称: Linux中国
十万级技术订阅号,依托于『Linux中国』(https://linux.cn/)社区,专注于 Linux 学习、技术研究、开源思想传播。
目录
相关文章推荐
Linux就该这么学  ·  微信期待已久的功能终于来了!支持U盘、SSD ... ·  14 小时前  
Linux爱好者  ·  1 个空指针,捅破了天……谷歌官方首次披露 ·  2 天前  
Linux就该这么学  ·  跨越平台壁垒:可将用户账号密码安全迁至 ... ·  昨天  
Linux就该这么学  ·  麟卓推出开源鸿蒙 OpenHarmony ... ·  2 天前  
Linux就该这么学  ·  先收藏!!运维最常用的 Shell ... ·  2 天前  
51好读  ›  专栏  ›  Linux中国

OpenGL 与 Go 教程(三)实现游戏

Linux中国  · 公众号  · linux  · 2017-10-19 10:03

正文

请到「今天看啥」查看全文


() {

  • ...

  • for ! window . ShouldClose () {

  • for x := range cells {

  • for _ , c := range cells [ x ] {

  • c . checkState ( cells )

  • }

  • }

  • draw ( cells , window , program )

  • }

  • }

  • 现在我们的游戏逻辑全都设置好了,我们需要修改细胞绘制函数来跳过绘制不存活的细胞:

    1. func (c *cell) draw() {

    2.    if !c.alive {

    3.            return

    4.    }

    5.    gl.BindVertexArray(c.drawable)

    6.    gl.DrawArrays(gl.TRIANGLES, 0, int32(len(square)/3))

    7. }

    如果我们现在运行这个游戏,你将看到一个纯黑的屏幕,而不是我们辛苦工作后应该看到生命模拟。为什么呢?其实这正是模拟在工作。因为我们没有活着的细胞,所以就一个都不会绘制出来。

    现在完善这个函数。回到 makeCells 函数,我们用 0.0 1.0 之间的一个随机数来设置游戏的初始状态。我们会定义一个大小为 0.15 的常量阈值,也就是说每个细胞都有 15% 的几率处于存活状态。

    1. import (

    2.    "math/rand"

    3.    "time"

    4.    ...

    5. )

    6. const (

    7.    ...

    8.    threshold = 0.15

    9. )

    10. func makeCells() [][]*cell {

    11.    rand.Seed(time.Now().UnixNano())

    12.    cells := make([][]*cell, rows, rows)

    13.    for x := 0; x < rows; x++ {

    14.        for y := 0; y < columns; y++ {

    15.            c := newCell(x, y)

    16.            c.alive = rand.Float64() < threshold

    17.            c.aliveNext = c.alive

    18.            cells[x] = append(cells[x], c)

    19.        }

    20.    }

    21.    return cells

    22. }

    我们首先增加两个引入:随机( math/rand )和时间( time ),并定义我们的常量阈值。然后在 makeCells 中我们使用当前时间作为随机种子,给每个游戏一个独特的起始状态。你也可也指定一个特定的种子值,来始终得到一个相同的游戏,这在你想重放某个有趣的模拟时很有用。

    接下来在循环中,在用 newCell 函数创造一个新的细胞时,我们根据随机浮点数的大小设置它的存活状态,随机数在 0.0 1.0 之间,如果比阈值( 0.15 )小,就是存活状态。再次强调,这意味着每个细胞在开始时都有 15% 的几率是存活的。你可以修改数值大小,增加或者减少当前游戏中存活的细胞。我们还把 aliveNext 设成 alive 状态,否则在第一次迭代之后我们会发现一大片细胞消亡了,这是因为 aliveNext 将永远是 false

    现在继续运行它,你很有可能看到细胞们一闪而过,但你却无法理解这是为什么。原因可能在于你的电脑太快了,在你能够看清楚之前就运行了(甚至完成了)模拟过程。

    让我们降低游戏速度,在主循环中引入一个帧率(FPS)限制:

    1. const (

    2.    ...

    3.    fps = 2

    4. )

    5. func main() {

    6.    ...

    7.    for !window.ShouldClose() {

    8.        t := time.Now()

    9.        for x := range cells {

    10.            for _, c := range cells[x] {

    11.                c.checkState(cells)

    12.            }

    13.        }

    14.        if err := draw(prog, window, cells); err != nil {

    15.            panic(err)

    16.        }

    17.        time.Sleep(time.Second/time.Duration(fps) - time.Since(t))

    18.    }

    19. }

    现在你能给看出一些图案了,尽管它变换的很慢。把 FPS 加到 10,把方格的尺寸加到 100x100,你就能看到更真实的模拟:

    1. const (

    2.    ...

    3.    rows = 100

    4.    columns = 100

    5.    fps = 10

    6.    ...

    7. )

    试着修改常量,看看它们是怎么影响模拟过程的 —— 这是你用 Go 语言写的第一个 OpenGL 程序,很酷吧?

    进阶内容?

    这是《OpenGL 与 Go 教程》的最后一节,但是这不意味着到此而止。这里有些新的挑战,能够增进你对 OpenGL (以及 Go)的理解。

    ☉ 给每个细胞一种不同的颜色。
    ☉ 让用户能够通过命令行参数指定格子尺寸、帧率、种子和阈值。在 GitHub 上的 github.com/KyleBanks/conways-gol [4] 里你可以看到一个已经实现的程序。
    ☉ 把格子的形状变成其它更有意思的,比如六边形。
    ☉ 用颜色表示细胞的状态 —— 比如,在第一帧把存活状态的格子设成绿色,如果它们存活了超过三帧的时间,就变成黄色。
    ☉ 如果模拟过程结束了,就自动关闭窗口,也就是说所有细胞都消亡了,或者是最后两帧里没有格子的状态有改变。
    ☉ 将着色器源代码放到单独的文件中,而不是把它们用字符串的形式放在 Go 的源代码中。

    总结

    希望这篇教程对想要入门 OpenGL (或者是 Go)的人有所帮助!这很有趣,因此我也希望理解学习它也很有趣。

    正如我所说的,OpenGL 可能是非常恐怖的,但只要你开始着手了就不会太差。你只用制定一个个可达成的小目标,然后享受每一次成功,因为尽管 OpenGL 不会总像它看上去的那么难,但也肯定有些难懂的东西。我发现,当遇到一个难于理解用 go-gl 生成的代码的 OpenGL 问题时,你总是可以参考一下在网上更流行的当作教程的 C 语言代码,这很有用。通常 C 语言和 Go 语言的唯一区别是在 Go 中,gl 函数的前缀是 gl. 而不是 gl ,常量的前缀是 gl 而不是 GL_ 。这可以极大地增加了你的绘制知识!

    该教程的完整源代码可从 GitHub [4] 上获得。

    回顾

    这是 main.go 文件最终的内容:

    1. package main

    2. import (

    3.    "fmt"

    4.    "log"

    5.    "math/rand"

    6.    "runtime"

    7.    "strings"

    8.    "time"

    9.    "github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl

    10.    "github.com/go-gl/glfw/v3.2/glfw"

    11. )

    12. const (

    13.    width  = 500

    14.    height







    请到「今天看啥」查看全文