Snake: MoonBit版贪吃蛇来了!

什么是贪吃蛇?

贪吃蛇(Snake)是起源于1976年的街机游戏 Blockade。此类游戏在1990年代由于一些具有小型屏幕的移动电话的引入而再度流行起来,在现在的手机上基本都可安装此小游戏。版本亦有所不同。

在游戏中,玩家操控一条细长的直线(俗称蛇或虫),它会不停前进,玩家只能操控蛇的头部朝向(上下左右),一路拾起触碰到之物(或称作“豆”),并要避免触碰到自身或者其他障碍物。每次贪吃蛇吃掉一个食物,它的身体便增长一些。吃掉一些食物后会使蛇的移动速度逐渐加快,让游戏的难度渐渐变大。游戏设计大致分为四面都有墙(都不可穿越)以及某部分的墙可以穿越,以及四面墙都可以穿越的模式。有些游戏碰到自己身体也不会死掉,例如蛇蛇食颜色、贪吃蛇进化论等等。本文将介绍如何用MoonBit实现贪吃蛇,完整的代码:https://github.com/moonbitlang/moonbit-docs/tree/main/examples/snake

如果你想尝试一下,可以点击此处进行尝试:https://www.moonbitlang.cn/gallery。

如何用MoonBit实现贪吃蛇

struct GameState来创建整个游戏:

struct GameState{mut grid:  Array[Int]mut body:  List[Position]mut dir:   Direction
}

grid来初始化每个格子的颜色:

0 0 0 0 0 0
0 2 0 1 0 0
0 0 0 0 0 0

0代表普通格子,1代表蛇的身体,2代表食物

初始化后的游戏界面:

在这里插入图片描述

生成食物

fn random() -> Double = "Math" "random"
fn floor(i: Double) -> Int = "Math" "floor"fn generate_Food(self: GameState){while true {let i : Int = floor(random() * 20.0)let j : Int = floor(random() * 20.0)if(self.grid[j * grid_col_count + i] == grid_num(Default)){self.setGridType({x: i, y: j}, Food)return}}
}

首先通过两个外部引用函数随机生成新食物的横坐标和纵坐标,然后通过grid_num来判断新生成的坐标是否可以放置,最后通过setGridType方法来设置为食物。

控制蛇行进

pub fn tran_step(self : GameState, a : Int){let mut action : Direction = Defaultmatch a {1 => action = Up2 => action = Down3 => action = Left4 => action = Right_ => action = Default}self.step(action)
}pub fn step(self : GameState, action : Direction) {match action {// move upUp =>{if length(self.body) == 1{self.dir = Up}else{if self.dir == Left || self.dir == Right || self.dir == Up{self.dir = Up}else{self.dir = self.dir}}}// move downDown =>{if length(self.body) == 1{self.dir = Down}else{if self.dir == Left || self.dir == Right || self.dir == Down{self.dir = Down}else{self.dir = self.dir}}}// move leftLeft =>{if length(self.body) == 1{self.dir = Left}else{if self.dir == Up || self.dir == Left || self.dir == Down{self.dir = Left}else{self.dir = self.dir}}}// move rightRight =>{if length(self.body) == 1{self.dir = Right}else{if self.dir == Up || self.dir == Right || self.dir == Down{self.dir = Right}else{self.dir = self.dir}}}_ =>{self.dir = self.dir}}self.go_step()
}

首先,通过tran_step方法识别外部键盘的响应并对应不同的输入方向指令。

其次,通过step方法来过滤输入方向是否合法。游戏规定蛇无法转向180度,但在蛇身长度为1时,蛇可以上下左右自由移动。

最后,调用go_step方法完成蛇的移动。

fn go_step(self: GameState){let head : Position = get_head(self.body)let newHead : Position = {x: head.x , y: head.y }newHead.x = dir_posi(self.dir).x + newHead.xnewHead.y = dir_posi(self.dir).y + newHead.ynewHead.x = (newHead.x + grid_col_count) % grid_col_countnewHead.y = (newHead.y + grid_col_count) % grid_col_countif self.grid[newHead.y * grid_col_count + newHead.x] == 1{initialize(self)return}else if self.grid[newHead.y * grid_col_count + newHead.x] == 2{self.setGridType(newHead, Body)self.body = Cons(newHead, self.body)generate_Food(self)}else {self.setGridType(newHead, Body)self.body = Cons(newHead, self.body)self.setGridType(get_tail(self.body), Default)self.body = delete_tail(self.body)}}

go_step方法中,首先通过self.dirPosition获得新头的位置,其次判断新头的位置是普通格子,蛇的身体还是食物。

  • 如果为普通格子,则将新头设置为蛇身,删除蛇原本的尾巴
  • 如果为蛇的身体,本轮游戏结束,重新initialize整场游戏
  • 如果为食物,则吃掉这个食物,并把食物的位置设置成蛇身

通过外部引用画图

声明外部函数引用

type Canvas_ctxfn set_stroke_color(self : Canvas_ctx, color : Int) = "canvas" "set_stroke_color"fn set_line_width(self : Canvas_ctx, width : Double) = "canvas" "set_line_width"fn stroke_rect(self : Canvas_ctx, x : Int, y : Int, width : Int, height : Int) = "canvas" "stroke_rect"fn fill_rect(self : Canvas_ctx, x : Int, y : Int, width : Int, height : Int) = "canvas" "fill_rect"fn set_fill_style(self : Canvas_ctx, color : Int) = "canvas" "set_fill_style"

然后进行画图

pub fn draw(canvas : Canvas_ctx, snake : GameState) {let mut c = 0// draw backgroudwhile c < grid_col_count {canvas.set_fill_style(0)canvas.fill_rect(c, 0, 1, grid_row_count)c = c + 1}draw_piece(canvas, snake.grid, (0, 0))
}pub fn draw_piece(canvas : Canvas_ctx, matrix : Array[Int],offset : (Int, Int)) {let mut r = 0let mut c = 0let mut c0 = 0while c < matrix.length() {if matrix[c] == 0 {c = c + 1continue}c0 = c % grid_col_countr = c / grid_col_countcanvas.set_fill_style(matrix[c] + 1)canvas.fill_rect( offset.0 + c0, r, 1, 1)canvas.set_stroke_color(1)canvas.set_line_width(0.1)canvas.stroke_rect( c0, r, 1, 1)c = c + 1}
}

JavaScript 键盘监听与画面更新

window.addEventListener("keydown", (e) => {if (!requestAnimationFrameId) returnswitch (e.key) {case "ArrowLeft": {snake_step(snake, 3)snake_draw(context, snake)break}case "ArrowRight": {snake_step(snake, 4)snake_draw(context, snake)break}case "ArrowDown": {snake_step(snake, 2)snake_draw(context, snake)break}case "ArrowUp": {snake_step(snake, 1)snake_draw(context, snake)break}}
})

update画面,调用snake_stepsnake_draw方法

function update(time = 0) {const deltaTime = time - lastTimedropCounter += deltaTimeif (dropCounter > dropInterval) {snake_step(snake, 5);dropCounter = 0}lastTime = timesnake_draw(context, snake)requestAnimationFrameId = requestAnimationFrame(update)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/456165.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时序预测 | MATLAB实现基于CNN-LSTM-AdaBoost卷积长短期记忆网络结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于CNN-LSTM-AdaBoost卷积长短期记忆网络结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于CNN-LSTM-AdaBoost卷积长短期记忆网络结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于CNN-LST…

JVM 性能调优 - 常用的垃圾回收器(6)

垃圾收集器 在 JVM(Java虚拟机)中,垃圾收集器(Garbage Collector)是负责自动管理内存的组件。它的主要任务是在程序运行过程中,自动回收不再使用的对象所占用的内存空间,以便为新的对象提供足够的内存。 JVM中的垃圾收集器使用不同的算法和策略来实现垃圾收集过程,以…

vue2 自定义指令 v-highlight 文本高亮显示分享

简单分享一个文本高亮显示的自定义指令&#xff0c;主要分两部分&#xff1a; 1、代码实现&#xff1a;在 main.js 文件中添加一个自定义指令&#xff0c;实现搜索时文本高亮显示&#xff0c;代码如下&#xff1a; const highlightText (el, searchText) > {const textCo…

42、馒头详谈脑电设备

脑电设备作为脑机接口技术的中层&#xff0c;有着承上启下的作用&#xff0c;设备采集的脑电信号质量如何&#xff0c;直接关乎着后续的模型的训练&#xff0c;虽然我们拿到原始EEG信号后会做一些预处理&#xff0c;比如工频滤波&#xff0c;通道加权平均&#xff0c;ICA去伪迹…

进阶C语言-通讯录的实现

通讯录 🎈1.设计要求🎈2.程序实现🔭2.1打印菜单及初始化通讯录🔭2.2显示所有联系人🔭2.3查找指定的联系人🔭2.4删除指定的联系人🔭2.5查找指定的联系人🔭2.6修改指定联系人🔭2.7按照年龄排序(以此为例)🎈3.全部源码以及实现🎈1.设计要求 🌞通过前面…

复杂人像背景分割解决方案

随着人工智能和图像处理技术的不断发展&#xff0c;人像处理已成为企业宣传、产品展示、线上教育等领域不可或缺的一环。然而&#xff0c;面对复杂多变的人像背景&#xff0c;如何实现精准、高效的分割&#xff0c;一直是困扰企业的技术难题。为此&#xff0c;美摄科技凭借其领…

停止内耗,做有用的事

很多读者朋友跟我交流的时候&#xff0c;都以为我有存稿&#xff0c;于是听到我说每周四现写的时候都很惊讶。其实没什么好惊讶的&#xff0c;每周四我都会把自己关在书房里一整天&#xff0c;断掉一切电话、微信、邮件&#xff0c;从中午写到晚上&#xff0c;直到写完为止。 这…

Jmeter 01 -概述线程组

1、Jmeter:概述 1.1 是什么&#xff1f; Jmeter是Apache公司使用Java 开发的一款测试工具 1.2 为什么&#xff1f; 高效、功能强大 模拟一些高并发或多次循环等特殊场景 1.3 怎么用&#xff1f; 下载安装 1、下载jmeter&#xff0c;解压缩2、安装Java环境&#xff08;jmet…

五、Redis之发布订阅及事务管理

5.1 发布订阅 5.1.1 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。Redis 客户端可以订阅任意数量的频道。下图展示了频道 channel1 &#xff0c;以及订阅这个频道的三个客户端 —— client1 、client2 …

牛客“迎新春,过大年”多校程序设计竞赛A题

题目描述&#xff1a; 这里有个小trick 当时也看到数据范围的问题了 n 是 1 e 6 ∑ i 1 n a [ i ] < 5 e 7 n是1e6 \quad \sum_{i1}^na[i]<5e7 n是1e6∑i1n​a[i]<5e7 我们考虑不同的数 1 2 . . . k − 1 k 1 \quad 2 \quad ... k-1 \quad k 12...k−1k s u m …

2024年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;上海市安全员B证证模拟考试题库是根据上海市安全员B证最新版教材&#xff0c;上海市安全员B证大纲整理…

浅析现代计算机启动流程

文章目录 前言启动流程概述磁盘分区格式MBR磁盘GPT磁盘隐藏分区 传统BIOS引导传统BIOS启动流程 UEFI引导UEFI引导程序UEFI启动流程 引导加载程序启动操作系统相关参考 前言 现代计算机的启动是一个漫长的流程&#xff0c;这个流程中会涉及到各种硬件的配置与交互&#xff0c;包…