×

Arduino游戏机

消耗积分:0 | 格式:zip | 大小:0.17 MB | 2023-06-27

分享资料个

描述

概述

该项目的硬件构建非常容易。一个 Arduino Mega 和一个 7 英寸 Nextion 显示器是主要组件!但是软件开发可以像您想要的那样具有挑战性。我已经使用这个平台开发了三款游戏,它们都包含在软件下载中。但我在这里希望找几个人为这个平台写游戏软件,这样我们就可以交换软件,并为它建立一个游戏库。

poYBAGOIxJGAf89kAADmZ631Zq0334.jpg
西蒙游戏的游戏机
 

为该平台创建的任何游戏都有两个软件组件 - Nextion 的图形用户界面 (GUI) 文件和构建游戏操作和逻辑的 Arduino 草图。

我在这里介绍的三款游戏是井字游戏、Dots and Boxes 和 Simon。

每个人都知道井字游戏。它可以使计算机无与伦比,但我遗漏了几步,为玩家赢得了一扇门。

Dots and Boxes 是另一种类似于井字游戏的游戏,您可以在其中与计算机对战。当你连接点并形成一个盒子时,你会得到一个点和另一个转弯。谁得到最多的盒子就赢了。在这种情况下,计算机是一个很好的播放器,但它可以被击败。

西蒙就像孩之宝的同名记忆挑战游戏。我使用了 Simon 游戏的图像,所以它看起来和工作起来都一样。

在一个单独的项目中,Arduino 游戏控制台第 2 部分,我将展示我也为这个平台开发的两个纸牌游戏:二十一点和五张牌扑克。

稍后我们将更详细地讨论每款游戏。除了下载中每个游戏的单独软件外,还有一个名为 Arcade 的应用程序中的前三个游戏的组合。

 

硬件

为了创建一个便携式游戏机,除了 Arduino Mega 和 Nextion 显示器之外,我还添加了一个 7.4 伏锂离子电池、一个开关和一个稳压器。2000 mAh 电池在两次充电之间可持续使用约 3 小时。稍后的示意图向您展示了它的接线方式。Arduino 可以通过 Vin 引脚直接使用电池供电,但 Nextion 需要 5 伏电压。有很多方法可以获得 5 伏,尽管 Arduino 上的 5 伏引脚不是其中之一。Nextion 带有几个警告,即 Arduino 无法处理 Nextion 当前的要求。我选择了一个 LM317 可变电压调节器模块,因为我有一个可用的。您只需将输出电压设置为 5 伏,因为它是一个可变电压调节器。

我还提供了 3D 打印案例的文件,但如果您无法使用 3D 打印机,您可能可以用塑料或轻质胶合板制作一个。以下是一些施工细节的照片:

poYBAGOIxJWACQB4AAD8rEXOptc235.jpg
内脏
 

 

pYYBAGOIxJeAHDJQAAEbAfKqjLw571.jpg
Nextion 显示器的背面视图
 

上图显示了一些重要的事情。该板带有一个漂亮的 4 针连接器,但它插入侧面。我的 3D 打印外壳没有为该连接器留出任何空间,因此我将 4 根电线直接焊接到连接器的背面。此外,重要的是要注意 Nextion 的 TX 连接到 Arduino RX (pin10),Nextion 的 RX 连接到 Arduino 的 TX (pin11)。我们在这里使用软件串行,以免占用用于编程 Arduino 的硬件串行引脚 0、1。

pYYBAGOIxJmAF-sEAABnHgyaXhQ283.jpg
可访问 Arduino 和电池充电器输入的侧视图
 

充电器插头和 Arduino Mega 都用大量热胶固定!

poYBAGOIxJ6AG7shAAAuTJIEOXk176.jpg
空壳
 

上面显示的空壳实际上经过了几次迭代,然后我才得到它以容纳 Nextion 显示器边缘的所有东西。

poYBAGOIxKGAMMaLAAAKTZWxmHs187.jpg
背面的插槽可访问 Nextion 的 Micro SD 卡插槽
 

Arduino 的编程显然是通过 USB 端口完成的,但 Nextion GUI 文件需要加载到 micro SD 卡上并插入 Nextion 背面的插槽中。只需在 SD 卡就位的情况下打开 Nextion 即可安装文件。然后可以取出 SD 卡进行正常使用。

关于硬件的最后一点说明:我使用 Arduino 上的模拟输入 A0 来获得一个随机值,用于设置随机种子,因为所有这些游戏都使用随机数。为了获得良好的随机模拟输入,我将一根 3 英寸的线连接到 A0。它不依附于任何东西。它只是接收杂散电噪声的天线。

使用 Nextion

在这个项目开始时,我并没有专门寻找 Nextion 显示器。我只是在寻找可以与 Arduino 一起使用的大型 LCD 屏幕。Nextion 不仅仅是一个 LCD 触摸屏。它有自己的处理器、自己的操作系统、用于设计图形用户界面的应用程序,以及您可以从 Arduino 使用的命令语言来配置和控制它。

我在这里看到的大多数使用 Nextion 的项目都将它视为他们用于用户界面的工具。我将尝试更深入地研究 Nextion 的真正含义,因为它已成为该项目的关键部分。

Nextion 显示器旨在为几乎任何事情提供人机界面,但似乎特别针对工业控制应用,即一个完整的触摸屏,可用于控制工业机械。在我看来,它并不是专门为业余爱好者设计的,所以需要一点时间来适应。

使用 Arduino 和 Nextion 构建项目涉及两个截然不同且不同的步骤 - 1) 使用 Nextion 编辑器创建图形用户界面或 GUI,2) 开发与该用户界面交互的 Arduino 应用程序。

pYYBAGOIxKWAdqUeAAH-KRnJKtQ760.jpg
使用 Nextion Editor 编辑井字游戏
 

Nextion Editor 是您构建 GUI 的应用程序。您可以创建菜单和各种页面。如果这一切听起来很熟悉,它可能应该,因为它几乎就像建立一个网站。

事实上,就网站而言,Nextion 系统的设计和行为与特定的 Web 技术平台非常相似:ASP.NET(Active Server Pages)。在这种情况下,Nextion 就像在您自己的计算机上运行的网络浏览器一样,而 Arduino 就像一个远程服务器,在用户界面上采取行动并响应更改,然后将它们传回 Nextion。

Nextion Editor 是一个非常好的应用程序!它易于学习且功能非常强大。它甚至有一个模拟器/调试器,可以模拟 Nextion 显示器,并允许您测试您创建的用户界面,而无需将其下载到实际的 Nextion 显示器。

Nextion 和 Arduino 之间的通信通过简单的串行连接在两个方向上完成。这种通信的协议和命令结构是 Nextion 自己的语言。它没有什么复杂的,但是有许多不同的命令和一门新的语言需要学习!有几个 Arduino 库可用,它们试图弥合差距并处理 Nextion 的所有命令。我不确定他们中的任何一个在这方面特别成功。我读过的几篇文章建议最直接的方法是一起跳过库并学习 Nextion 语言。

在查看了各种库和许多 Nextion 有点令人眼花缭乱的文档之后,我最终使用了 Neo Nextion。它是一个功能齐全的库,具有官方 Nextion 库的所有功能,但总体上比官方提供了很多好的示例和更好的文档。但即使有了这个库,也需要一些时间来弄清楚你在 Arduino 方面做了什么。

Nextion 的基本思想是用户界面中的对象(如按钮、图像框、页面、文本框等)具有属性,其中一些属性只能由 Nextion 编辑器设置,但大部分可以设置和从 Arduino 改变。因此,例如,我可以更改图像框中的图片或更改 Arduino 中按钮的颜色。因此,要使用此方案构建游戏,我们使用 Nextion Editor 创建用户界面,并使用 Arduino 对游戏逻辑进行编程。

Nextion 通过名称和 ID 号标识每个接口对象。一些命令使用对象的名称;其他人使用它的 ID。Neo Nextion 之类的库允许您仅使用对象的名称来保持一致性。(我对 Nextion 编辑器的一个批评是,如果你删除一个对象,例如一个按钮,它会更改页面上许多其他对象的 ID 号——这不是一个好主意——它真的会弄乱你的 Arduino草图!)

关于所有这些库的另一个值得一提的问题是它们实现了完整 Nextion 控制语言的一个子集。例如,Nextion 支持可以动态更改的按钮上的图像。但是 Neo Nextion 库不支持图像按钮,所以我无法从 Arduino 控制按钮上的图像。

我将通过快速概述 Arduino 如何与 Nextion 上的按钮交互来完成对 Nextion 的讨论。理解这一点将大大有助于理解 Nextion 使用的 Arduino 代码。首先,在 Nextion 方面,必须将按钮配置为将其 ID 发送到 Arduino,无论是在按下时,还是在释放时,或两者兼而有之。在 Arduino 端,我们需要在 Neo Nextion 中设置一个按钮实例和一个“回调”” 它将按钮链接到按下(或释放)按钮时执行的例程。我们还需要创建将要执行的实际例程。然后,在 Arduino 的设置中,我们需要向 Nextion 发送一个“回调”指令,该指令为 Nextion 提供我们的“回调”例程的地址。最后,在 Arduino 的主循环中唯一允许的是 Nextion 的按钮轮询例程。其他所有内容都内置在按钮被按下的“回调”响应中!

第一次设置按钮时似乎有点混乱,但每个按钮都是一样的,所以创建一堆按钮主要是“复制和粘贴”练习。Neo Nextion 有很多很好的例子,向你展示如何做按钮等等。

软件

正如我们已经说过的,该软件有两个部分:1)使用 Nextion 编辑器创建图形用户界面,以及 2)创建 Arduino 草图以生成所有游戏逻辑和对用户界面的响应。

在软件下载中,我为每个游戏和三个游戏的“街机”组合分别包含了 Arduino 草图和 Nextion GUI 文件。如果您只想重新创建我所做的,只需使用这些文件。顺便说一下,GUI 文件 (.tft) 需要通过 microSD 卡下载到 Nextion。如果您想为此硬件创建自己的游戏,请继续阅读...

Nextion 编辑器易于使用且有据可查,所以我不会在这里花很多时间解释它。您需要选择特定的 Nextion 显示器 - 我们的是 7 英寸、智能电容式触控,并在水平 0 模式下运行。您将按钮和图像框从工具包拖到活动屏幕并在属性窗口中配置它们。在应用程序的底部,您可以启用按钮的操作。一种操作是将该对象的 ID 发送到 Arduino,如果您希望 Arduino 响应,您必须启用该 ID。您希望 Nextion 自行执行的操作,例如更改页面或更改图片框中的图片,需要在操作窗口中指定。在大多数情况下,操作几乎是直观的,例如“page 1”切换到第 1 页或“p0.pic=3”将图片框 0 中的图片更改为图像编号 3。您可以参考Nextion 指令集以获取有关这些命令的更多信息。Nextion Editor 有自己的调试器,您可以在其中运行新创建的用户界面并测试它的工作原理——这是一个非常好的功能。

在这一点上我应该提到的一个细节是匹配 Nextion 和 Arduino 的串行通信波特率。Nextion 默认设置为 9600,但这很慢。我的每个 Nextion 文件都设置了波特率。(它是通过使用类似“bauds = 38400”的命令的预启动操作设置的)匹配的 Arduino 文件在 Setup() 中设置为相同的波特率。我在这里所做的一切都是波特率 38400。

我使用更高的波特率试图加快 Nextion 对我在 Arduino 上所做更改的反应。虽然它有一点帮助,但并没有我想象的那么好。显然,大部分感知到的延迟是等待 Nextion 确认成功接收请求的结果。这意味着我们有时会等待按钮变为活动状态。

对 Arduino 进行编程以与 Nextion 一起工作并不是特别直观,但 Neo Nextion 有很好的示例可以帮助您入门。Neo Nextion 库似乎需要大量初始代码才能启动。必须为要使用的库的每个部分添加“包含”,并且每个图形对象都需要在 Neo Nextion 中声明,然后才能与之交互。回调必须包含您希望按钮执行的例程,并且它们的地址必须传达给 Nextion。一切都发生在回调例程中。除了轮询按钮的活动外,主循环不做任何事情。

如果您想使用我的 Arduino 草图来帮助您入门,我建议您使用其中一款单独的游戏。三场比赛的街机变得相当复杂。

井字游戏

这是我处理的第一场比赛。网格是背景图像,每个正方形都有一个大按钮。一个非常大的字体(144 像素高)在这些按钮内形成了 Xs 和 Os。

 

Arduino 草图基本上有两部分:1)与 Nextion 按钮的接口和 2)实际玩井字游戏所需的逻辑。

游戏逻辑尝试按顺序完成以下步骤

  • 阻止对手获胜
  • 创建一个可以通过两种方式获胜的分叉
  • 阻止对手创建分叉
  • 走对面的角落
  • 走中心广场
  • 采取任何空的角落
  • 取一个中间正方形

如果以上都实现了,那电脑就打不过了。我故意省略了涉及分叉的第二步和第三步(它们在代码中,但为空),以便有可能击败计算机。击败它仍然不容易。只有几个非常特定的序列,您可以击败计算机。这是一个:

 

Nextion 有助于为游戏创建漂亮的图形。图像用于游戏标题和获胜、失败、平局图形,并且可以在 Arduino 控制下轻松打开或关闭或切换。

西蒙

西蒙是一个简单的记忆测试。它是四款游戏中最容易创建的一款,但视觉效果非常令人愉悦,因为它看起来与真实的西蒙游戏一模一样。

 

这一切都是通过交换图像来完成的。该序列是随机生成的,并一遍又一遍地重复,每次都会在序列中增加一个。与其物理对应物完全一样。

点和框

这个游戏很简单。不熟悉的可以去网上看看各种网上版本。(或者你的孩子可能会教你怎么玩!)我没想到无论是从 Nextion 的用户界面还是从 Arduino 的游戏逻辑来说,这都是一个巨大的挑战。但与井字游戏或西蒙游戏相比,这是一个巨大的挑战。

 

第一个问题是用户界面。我们的 5 x 5 游戏网格上有 30 个垂直门和 30 个水平门。那是60个按钮。当玩家或电脑分别拍摄时,这 25 个单元格需要分别涂成绿色或红色。我使用了空文本框的背景颜色,所以有 25 个文本框。然后有一个用于点网格的图像框、一个开始按钮、另一个显示游戏标题的图像框、一个获胜图像、一个失败图像、两个显示分数的数字框,以及一个用于标记分数的文本框。使用 Nextion 编辑器创建和配置大量图形对象。并且每一个都有一个唯一的ID号和一个唯一的名字。

Arduino 代码也是一个挑战。一方面,每个图形对象都有一个名称,名称可以包括它们在网格上的位置,但这些名称不能被索引。我们可以使用索引数组来定义每个盒子的状态(哪些边是闭合的,多少边是闭合的)但是将该索引转换为特定对象需要一个专门进行转换的子例程 - 一次一个对象!

设置和配置按钮所需的 Arduino 代码中的每个步骤都必须重复 60 次。而且由于它们无法被索引,因此每个步骤需要 60 行代码。没什么大不了的,但是很多复制和粘贴!

游戏逻辑也不是特别容易。关闭一个特定的门会导致几件事发生。我们首先要看到的是之前没有关闭。然后它会导致它两侧的盒子的一侧关闭(在水平门的情况下它的上方和下方)。然后我们必须看看关门是否导致这些盒子中的任何一个被完全关闭并被玩家或计算机认领。无论玩家还是电脑移动,所有这些都是真实的。

计算机如何决定移动到哪里是另一组问题。它首先尝试关闭它可以关闭的任何盒子并声称该盒子,它会再转一圈。当这不能发生时,它会尝试找到一个两侧尚未关闭的盒子,因为在两侧已经关闭的盒子旁边选择一个门会设置玩家关闭它并声称该盒子。如果这也失败了,它会随机从剩余的门中挑选。这就是计算机成为一个非常好的玩家所需要的一切,但是要实现这个相对简单的策略需要查看很多门和很多盒子的状态。

最重要的是,Dots & Boxes 比井字游戏或西蒙游戏更难构建和编程!

下一步是什么

正如我之前所说的,在第 2 部分中,我将为该平台介绍两种纸牌游戏的附加软件:二十一点和五张牌扑克。我希望其他人能建造这个游戏机并创造一些我们可以分享的新游戏。其他想法可能包括德州扑克、红心。跳棋,或任何两人棋盘游戏。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'Arduino游戏机',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);