使用JavaScript和Posttresql构建游戏

重温经典:开源免费的在线笨拙游戏

成为软件开发者是一段充满意义的旅程。我喜欢创造酷炫的东西,而我的业余项目通常都是为了解决我遇到的问题。我的家人一直热衷于一款流行的文字游戏——笨拙。如今,兄弟姐妹们都搬离了家,我们很难像以前那样经常一起玩游戏。为了解决这个问题,我决定重新制作这款深受喜爱的游戏,并将其开源和免费!

游戏设计

和所有项目一样,我首先使用了白板(Excalidraw)进行头脑风暴。设计游戏蓝图是开发过程中的关键一步。

使用JavaScript和Posttresql构建游戏

游戏机制很简单:玩家首先进入主页,可以选择创建新游戏或加入现有游戏大厅。点击按钮即可进入游戏大厅页面,查看公开的游戏大厅(创建游戏时可以选择公开或私密)。

我需要追踪每个游戏大厅的几个持久性变量:

立即学习“Java免费学习笔记(深入)”;

游戏棋盘配置(字母排列):字符串数组大厅玩家列表:字符串数组大厅状态(公开或私密):布尔值

游戏状态会在游戏开始或结束时更新。棋盘配置决定了棋盘上字母的排列方式,确保客户端之间的一致性(每次游戏开始时随机生成)。玩家加入大厅时,系统会提示输入昵称。昵称会被发送到boggle_game数据库表中,与对应的游戏大厅代码关联。创建新游戏时,玩家可以选择公开或私密游戏大厅,系统会自动生成随机的游戏大厅代码。

无需账号的玩家加入

使用JavaScript和Posttresql构建游戏

很多多人在线游戏都需要用户账号进行身份验证来保存玩家数据。经过慎重考虑,我决定让游戏尽可能简单,无需创建账号。这个决定虽然存在一些局限性,但对于我的目标来说已经足够了。

我选择了Next.js作为开发框架,因为它拥有出色的开发者体验。Next.js可以轻松创建动态路由,这正是我用来分离游戏客户端的方式。玩家创建/加入游戏大厅并选择昵称后,会跳转到动态路由/[lobby_code]/[player_name],其中/[player_name]会启动对应的游戏客户端。我创建了一个boggle_player表来追踪玩家统计数据,例如单词数量和分数。这对于区分游戏客户端和追踪玩家数据至关重要。

实时更新

使用JavaScript和Posttresql构建游戏

使用JavaScript和Posttresql构建游戏

游戏设计看似简单,但在实现实时更新时,我遇到了一个挑战:如何让所有客户端都能及时更新游戏状态,而不是仅仅更新当前操作的客户端。

我使用了Supabase作为数据库,选择了他们的免费层,因为它功能非常强大。Supabase的文档也很完善,方便上手。

幸运的是,Supabase的免费计划支持实时更新!查看文档后,我发现实现起来非常简单。

const channels = supabase.channel('custom-all-channel')  .on(    'postgres_changes',    { event: '*', schema: 'public', table: 'boggle_game' },    (payload) => {      console.log('Change received!', payload)    }  )  .subscribe()

使用JavaScript和Posttresql构建游戏

这段代码创建了一个通道,Supabase会监听boggle_game表中的任何更改。event: '*'属性指定监听所有事件(插入、更新、删除)。这使得监听事件变得非常简单。有效载荷包含数据库表更改前后的旧值和新值,可以从中提取更改或运行函数来获取更新后的数据。我在游戏中添加了一个计时器,计时器结束后,endgame()函数会更新game_status,从而触发实时更新。

技术细节

构建实时应用有多种方法来保持客户端数据同步。最常见的是数据库轮询和WebSocket,它们的工作方式不同。

数据库轮询

轮询是一种简单但低效的更新方法。客户端会定期(例如每秒)向服务器发送请求,检查数据是否更改。这种方法的缺点是:

服务器负载过高:即使数据没有更改,服务器也会处理请求。更新延迟:UI只会在发送下一个请求时刷新,导致实时交互体验不佳。可扩展性问题:用户越多,请求越多,成本和效率都会降低。

WebSocket和Supabase实时设置

WebSocket是一种更好的方法,它提供客户端和服务器之间持久的双向通信通道。建立WebSocket连接后,服务器可以立即将更新推送到客户端,无需等待请求。Supabase底层的PostgreSQL数据库支持逻辑复制。

使用JavaScript和Posttresql构建游戏

PostgreSQL逻辑复制:每当表发生更改(插入、更新、删除)时,PostgreSQL会发出“更改事件”。

Supabase实时:此服务监听PostgreSQL的复制流,并将这些事件转发到内部WebSocket服务器。

WebSocket通信:任何订阅实时更新的客户端都会立即收到数据库中的更改。

使用这种设置,我的笨拙游戏无需向服务器发送大量请求。每个客户端都打开一个WebSocket连接,只有在数据实际更改时才会收到通知——无论玩家加入、提交单词还是游戏结束。这使得游戏即使在多人游戏大厅中也能保持流畅的性能和即时反馈。

总结

这个项目让我学到了很多东西,这正是我进行业余项目的主要目标。最终结果是一个在线版本的家人喜爱的文字游戏。现在,家人可以在任何时间、任何地点玩游戏,延续了我们的传统。我学习了WebSocket的工作原理,以及它与其他解决方案(如数据库轮询)的区别,以及如何使用Supabase实现它。这个项目很有意义,我期待未来能用WebSocket构建更多项目。

您可以访问以下链接体验游戏:

Clif’s Boggle – [游戏链接] (此处应替换为实际游戏链接)

使用JavaScript和Posttresql构建游戏

游戏支持多人游戏大厅,您也可以独自游戏,看看在3分钟内能找到多少单词。祝您游戏愉快!

以上就是使用JavaScript和Posttresql构建游戏的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1501157.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月19日 23:19:51
下一篇 2025年12月19日 23:20:03

相关推荐

  • 在jQuery each 循环中为XML元素生成递增ID

    本文将指导您如何在jQuery的each循环中,为动态生成的XML或HTML元素分配递增的序列号ID。通过利用each回调函数提供的索引参数,您可以轻松地为每个新创建的元素生成一个唯一的、按顺序排列的ID,确保输出结构化且易于管理。 在构建动态xml或html结构时,一个常见的需求是为重复生成的元素…

    2025年12月20日
    000
  • Next.js 中 Firestore 文档重复读取的优化策略

    本文探讨了在 Next.js 应用中,Firestore 文档读取次数超出预期的问题。核心内容包括深入理解 Firestore 的计费机制,识别并解决 Next.js 环境下因重复调用数据获取函数而导致的额外读取,并重点介绍如何利用 React 的 cache API 优化服务器端数据获取,从而有效…

    2025年12月20日
    000
  • JavaScript中获取NodeList点击元素的索引

    本文详细介绍了如何在JavaScript中,针对querySelectorAll获取的NodeList,高效地获取用户最后点击的元素的索引。通过为每个元素添加点击事件监听器,并利用ES6扩展运算符将NodeList转换为数组,我们能够精确确定被点击元素在其集合中的位置,实现灵活的交互逻辑。在前端开发…

    2025年12月20日
    000
  • TypeScript 中如何强制对象属性间的动态匹配

    本文深入探讨了在 TypeScript 中如何利用泛型(Generics)实现对象属性间的动态匹配和类型安全。通过为 props 数组和 order 数组中的字符串定义共享的泛型类型参数,我们可以确保 order 数组中的所有引用都严格对应于 props 数组中声明的属性名称,从而在编译时捕获潜在的…

    2025年12月20日
    000
  • TypeScript 中利用泛型实现对象属性的动态匹配与约束

    本文深入探讨如何在 TypeScript 中强制实现对象属性间的动态匹配与约束。针对一个对象中包含属性列表 (props) 和其排列顺序 (order) 的场景,我们详细介绍了如何通过泛型类型参数,确保 order 数组中的元素严格匹配 props 数组中定义的属性名称,从而在编译时捕获潜在的类型不…

    2025年12月20日
    000
  • JavaScript中获取NodeList中被点击元素索引的教程

    本教程详细介绍了如何在JavaScript中获取通过document.querySelectorAll获取的NodeList中被点击元素的索引。通过为NodeList中的每个元素添加点击事件监听器,并在事件处理函数内部将NodeList转换为数组,然后利用indexOf方法,可以精确地识别并获取到被…

    2025年12月20日
    000
  • Python与JavaScript递归函数中数组操作的差异与实践

    在Python和JavaScript中使用递归函数处理数组时,核心区别在于如何获取数组的“尾部”子数组。Python通过切片语法array[1:]直观实现,而JavaScript需要使用Array.prototype.slice(1)方法来创建新的子数组。直接通过索引访问ars[1]只会获取单个元素…

    2025年12月20日
    000
  • TypeScript中如何使用泛型实现对象属性的动态匹配与类型约束

    本文探讨了在TypeScript中如何利用泛型机制,实现对象属性(props)与它们在特定结构(order)中的动态匹配与类型约束。通过定义泛型类型参数,确保order数组中引用的所有属性名称都严格来源于props数组中定义的有效属性,从而增强了代码的类型安全性,并减少了潜在的运行时错误。文章将通过…

    2025年12月20日
    000
  • JavaScript中的可选链(Optional Chaining)和空值合并(Nullish Coalescing)如何改善代码质量?

    可选链(?.)避免非法属性访问,空值合并(??)精准处理默认值。例如:const street = user?.address?.street; const count = inputCount ?? 10; 结合使用可提升代码安全性和可读性,如 const displayName = userDa…

    2025年12月20日
    000
  • 生成XML元素计数序列

    本教程旨在指导开发者如何从jQuery获取的XML元素数量中,生成一个按顺序排列的数字序列(例如:1 2 3 … N)。文章将详细介绍两种主要的JavaScript数组操作方法:Array.fill().map()和Array.from(),并通过示例代码展示如何将XML元素计数转化为所…

    2025年12月20日
    000
  • 理解 TypeScript 类型与运行时值的边界:如何获取声明类型的字面量值

    TypeScript 的类型系统主要用于编译时静态检查,提升代码安全性,但类型本身在运行时并不可用。本文将解释 TypeScript 类型与 JavaScript 运行时值的根本区别,并提供通过常量、对象属性或枚举等运行时构造来存储和访问与类型对应的字面量值的实践方法,帮助开发者正确处理类型与值的关…

    2025年12月20日
    000
  • 如何构建一个支持动态导入的模块联邦系统?

    要实现动态导入的模块联邦系统,需利用 Webpack 5 的 Module Federation 功能并在运行时手动加载远程模块。核心是绕过构建时的静态 remotes 配置,通过动态加载 remoteEntry.js 文件并调用联邦 API 获取模块。具体步骤包括:使用 import() 动态引入…

    2025年12月20日
    000
  • TypeScript类型与运行时值:深入理解及其实现策略

    TypeScript类型主要用于编译时提供类型安全,在运行时会被擦除,因此无法直接将类型作为值访问。本文将深入探讨TypeScript类型系统的工作原理,解释为何类型不能直接在运行时被引用,并提供将类型信息以值形式在运行时使用的有效替代方案,帮助开发者更好地理解和利用TypeScript。 Type…

    2025年12月20日
    000
  • 如何通过JavaScript生成符合语义的PDF文档?

    使用pdfmake通过JSON结构生成语义化PDF,定义标题、段落、列表和表格等内容节点,配合样式与元数据设置,确保文档结构清晰、可访问性强,优于纯坐标绘图方式。 要通过JavaScript生成符合语义的PDF文档,关键在于结构化内容与样式分离,同时确保输出的PDF具备清晰的层级和可读性。虽然浏览器…

    2025年12月20日
    000
  • Chart.js 中格式化坐标轴和工具提示中的日期

    本文介绍了如何在 Chart.js 图表中格式化 X 轴上的日期,使其仅显示年份,同时在工具提示中保留完整的日期格式。通过修改 Chart.js 的配置选项,可以自定义坐标轴刻度和工具提示的日期显示方式,从而满足不同的可视化需求。本文提供了一种使用回调函数和索引来正确格式化日期的方法,并解决了常见的…

    2025年12月20日
    000
  • JavaScript中的Promise.allSettled与Promise.all有何区别与适用场景?

    Promise.all要求所有Promise成功,否则立即失败;Promise.allSettled等待全部完成并返回每个结果状态。1. Promise.all适用于所有操作必须成功的场景,如同时获取多个关键数据。2. Promise.allSettled适用于允许部分失败且需收集最终状态的场景,如…

    2025年12月20日
    000
  • JavaScript中模拟MongoDB的find()方法:深度查找嵌套对象

    本教程探讨了在JavaScript中如何实现类似MongoDB find() 的深度嵌套对象查找功能。由于 Array.prototype.find() 仅适用于数组,本文将介绍如何通过自定义递归函数遍历复杂对象结构,并提供了一个通用且健壮的解决方案,以实现按条件查找任意深度的对象或值,同时强调了数…

    2025年12月20日
    000
  • JavaScript中数据属性值到数字的健壮转换指南

    本教程旨在提供在JavaScript中将HTML数据属性值安全转换为数字的指南,重点解决计算中出现NaN的问题。文章将比较Number()和parseFloat()的适用场景,并推荐使用parseFloat(value) || 0模式,确保在值无法有效解析为数字时,能够优雅地回退到0,从而提高代码的…

    2025年12月20日
    000
  • 如何理解JavaScript中的微任务与宏任务队列?

    宏任务是事件循环中的任务单元,如script、setTimeout、setInterval、I/O和UI渲染,每次执行完一个宏任务后会执行所有微任务;微任务如Promise回调、queueMicrotask、MutationObserver具有更高优先级,在当前宏任务结束后立即执行。执行顺序为:同步…

    2025年12月20日
    000
  • JavaScript实现随机图书封面生成器:优化与防重复展示

    本文详细介绍了如何将一个简单的随机文本生成器改造为随机图书封面生成器。通过JavaScript,我们学习了如何管理图片URL数组、随机选择图片,并将其显示在网页上。教程还包含一个优化技巧,以避免连续两次显示相同的图书封面,提升用户体验。 1. 引言:从文本到图像的转变 在网页开发中,随机内容生成器是…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信