凹语言开发案例分享: Pong 游戏 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
chai2010
V2EX    程序员

凹语言开发案例分享: Pong 游戏

  •   chai2010
    chai2010 2024-09-06 08:21:26 +08:00 2539 次点击
    这是一个创建于 432 天前的主题,其中的信息可能已经有所发展或是发生改变。

    WASM-4 是一款使用 WebAssembly 实现的复古风格游戏机。凹语言作为国内首个面向 WebAssembly 设计的通用编程语言在 syscall/wasm4 内置标准库对 WASM4 平台提供了支持,从而为使用凹语言开发小游戏的用户提供最佳体验。

    我们以一个简单的乒乓球游戏作为例子,看看如何开发 WASM4 游戏。

    配置环境

    安装凹语言 v0.15 以上的版本,或者通过以下 Go 命令安装最新的 wa 命令行:

    $ go install wa-lang.org/wa@master 

    然后通过以下命令创建一个 hello 新目录工程:

    $ wa init -wasm4 $ tree hello/ hello/ ├── README.md ├── src │ └── main.wa └── wa.mod 2 directories, 3 files 

    命令行环境进入 hello 目录后,输入wa run可以在浏览器打开查看效果。

    程序整体骨架

    直接修改src/main.wa文件:

    import ( "math/rand" "strconv" "syscall/wasm4" ) const ( width = 5 height = 15 ballSize = 5 screenSize = int(wasm4.SCREEN_SIZE) ) // 玩家 1(右边): 上下方向键 // 玩家 2(左边): ED 键对应上下键, 左右方向键盘控制 global game = NewPongGame(true) // 双人游戏 #wa:export update func Update { game.Input() game.Update() game.Draw() } 

    Update 函数会以每秒 60 帧的频率被调用,其中分布出来游戏的输入、更新游戏状态并显示。

    定义游戏对象

    在对象中保存的游戏状态:

    // 游戏的状态 type PongGame :struct { isMultiplayer: bool // 多人游戏 ballX: int // 球的水平位置 ballY: int // 球的竖直位置 dirX: int // 球的方向 dirY: int // 球的方向 y1: int // 左边挡板位置 y2: int // 右边挡板位置 score1: int // 玩家分数 score2: int // 玩家分数 } // 构建一个新游戏对象 func NewPongGame(enableMultiplayer: bool) => *PongGame { return &PongGame{ isMultiplayer: enableMultiplayer, ballX: screenSize / 2, ballY: screenSize / 2, dirX: 1, dirY: 1, y1: screenSize / 2, y2: screenSize / 2, score1: 0, score2: 0, } } 

    主要是乒乓球、挡板等位置和方向信息。

    处理输入键

    通过不同方向键盘分别控制 2 个挡板的移动。

    func PongGame.Input { // 第 1 个玩家 if pad := wasm4.GetGamePad1(); pad&wasm4.BUTTON_UP != 0 && this.y1 > 0 { this.y1 -= 2 } else if pad&wasm4.BUTTON_DOWN != 0 && this.y1+height < screenSize { this.y1 += 2 } // 第 2 个玩家或机器人 if this.isMultiplayer { // 左右方向键盘控制 if pad := wasm4.GetGamePad1(); pad&wasm4.BUTTON_LEFT != 0 && this.y2 > 0 { this.y2 -= 2 } else if pad&wasm4.BUTTON_RIGHT != 0 && this.y2+height < screenSize { this.y2 += 2 } if pad := wasm4.GetGamePad2(); pad&wasm4.BUTTON_UP != 0 && this.y2 > 0 { this.y2 -= 2 } else if pad&wasm4.BUTTON_DOWN != 0 && this.y2+height < screenSize { this.y2 += 2 } } else { this.y2 = this.ballY // 自动对齐到接球位置(TODO: 失误机制) } } 

    根据键盘更新挡板的位置信息。

    更新游戏的状态

    每秒钟 60 帧的速度更新状态:

    func PongGame.Update { // 更新球的方向 if dirNow := this.paddleCollision(); dirNow != 0 { wasm4.Tone(2000, 5, 100, wasm4.TONE_PULSE2|wasm4.TONE_MODE2) if rand.Int()%2 != 0 { this.dirX = dirNow this.dirY = -1 } else { this.dirX = dirNow this.dirY = 1 } } // 更新球的位置 this.ballX += this.dirX this.ballY += this.dirY // 检查球是否反弹 if this.ballY > screenSize || this.ballY < 0 { wasm4.Tone(2000, 5, 100, wasm4.TONE_PULSE2|wasm4.TONE_MODE2) this.dirY = -this.dirY } // 判断得分 if this.ballX <= 0 || this.ballX > screenSize { wasm4.Tone(1000, 5, 100, wasm4.TONE_PULSE2|wasm4.TONE_MODE2) if this.ballX <= 0 { // 左边玩家失球 this.score2 += 1 } else if this.ballX > screenSize { this.score1 += 1 // 右边玩家失球 } // 重置球位置 this.ballX = screenSize / 2 this.ballY = screenSize / 2 this.dirX = -this.dirX } } 

    同时判断失球和得分情况。以下是碰撞判断:

    func PongGame.paddleCollision => int { if this.ballX < width && this.ballY < this.y2+height && this.ballY+ballSize > this.y2 { return 1 } if this.ballX+ballSize > screenSize-width && this.ballY < this.y1+height && this.ballY+ballSize > this.y1 { return -1 } return 0 } 

    球碰到和超出边界表示失球得分。

    如何画乒乓球和挡板

    WASM4 的调色板寄存器一次只能存储 4 种颜色,可以通过更改这一寄存器来引入新的颜色。以下是 WASM4 默认的配色表:

    WASM4 内置的绘图函数不直接访问这个颜色表寄存器,而是访问同样能够存储 4 个颜色的 DRAW_COLORS 寄存器来指定对应的颜色表索引。可以通过wasm4.SetDrawColors函数完成。

    绘制场景的代码:

    func PongGame.Draw { wasm4.SetDrawColors(0, 4) wasm4.SetDrawColors(1, 0) wasm4.Text(strconv.Itoa(this.score1), 85, 0) wasm4.Text(strconv.Itoa(this.score2), 70, 0) wasm4.Rect(screenSize/2, 0, 2, screenSize) wasm4.SetDrawColors(0, 2) wasm4.SetDrawColors(1, 3) wasm4.Oval(this.ballX, this.ballY, ballSize, ballSize) wasm4.Rect(0, this.y2, width, height) wasm4.Rect(screenSize-width, this.y1, width, height) } 

    到此乒乓球游戏就完成了。

    完整代码

    完整代码大约 150 行: https://github.com/wa-lang/wa/tree/master/waroot/examples/w4-pong

    在线体验地址: https://wa-lang.org/wa/w4-pong/

    如果你也是游戏爱好者,也可以试试用凹语言开发自己的游戏了。

    Borch
        1
    Borch  
       2024-09-06 08:36:55 +08:00
    乍一看以为是 rust...
    xinyu391
        2
    xinyu391  
       2024-09-06 09:39:25 +08:00   1
    @Borch go 理了个发
    mightybruce
        3
    mightybruce  
       2024-09-06 11:41:18 +08:00   1
    回复有点少啊,支持一下凹语言, 毕竟是基于 go 开发出来的针对 wasm 的语言。
    StoneKnocker
        4
    StoneKnocker  
       2024-09-06 16:02:48 +08:00   1
    哇, 想不到柴大的凹语言还在推进呢, 好几年了吧
    chai2010
        5
    chai2010  
    OP
       2024-09-06 16:35:25 +08:00
    @StoneKnocker 2019 年初立项,2022 年 7 月开源,有几年了现在刚刚进到深水区。感谢支持
    chai2010
        6
    chai2010  
    OP
       2024-09-06 16:43:04 +08:00
    @Borch 目前和 Rust 没有交集
    chai2010
        7
    chai2010  
    OP
       2024-09-06 16:43:33 +08:00
    @xinyu391 凹语言是基于 Go 语言子集开始定制,站在 Go 巨人的腰上
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1019 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 21ms UTC 18:48 PVG 02:48 LAX 10:48 JFK 13:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86