最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何利用nodejs實(shí)現(xiàn)命令行游戲

 更新時(shí)間:2020年11月24日 09:24:26   作者:YuClyc  
這篇文章主要給大家介紹了關(guān)于如何利用nodejs實(shí)現(xiàn)命令行游戲的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

本文以貪吃蛇為例, 一步一步地分析如何實(shí)現(xiàn)一個(gè)命令行游戲.

實(shí)現(xiàn)原理

命令行輸入

  • 通過(guò) process.stdin 監(jiān)聽(tīng)命令行輸入的按鍵, 改變小蛇的前進(jìn)的方向

畫(huà)面渲染

  • 通過(guò) ANSI 轉(zhuǎn)義序列 擦除之前的輸出
  • 通過(guò) process.stdout 每隔一段時(shí)間將畫(huà)面幀輸出到命令行

源碼解析

監(jiān)聽(tīng)按鍵事件

使用過(guò) yarn upgrade-interactive 命令更新 npm 依賴(lài), 或者使用過(guò) vue-cli 等腳手架創(chuàng)建過(guò)新項(xiàng)目的同學(xué)應(yīng)該都見(jiàn)過(guò): 這些工具會(huì)在命令行輸出很多選項(xiàng), 通過(guò)上下按鍵可以移動(dòng)焦點(diǎn), 通過(guò)空格鍵可以選擇

那么這些操作是如何實(shí)現(xiàn)的呢? 下面通過(guò) readline 和 process.stdin 來(lái)實(shí)現(xiàn)命令行監(jiān)聽(tīng)按鍵事件:

process.stdin 是一個(gè)可讀流, 通過(guò) readline.emitKeypressEvents 可以給可讀流注冊(cè) keypress 事件, 通過(guò) keypress 事件就能獲取到按鍵的值

readline.emitKeypressEvents(process.stdin) // 注冊(cè) keypress 事件

process.stdin.setRawMode(true) // 開(kāi)啟原始模式, 使輸入的每個(gè)字符帶上各種詳細(xì)屬性

process.stdin.on('keypress', (...args) => {
 console.log(args)
 // 按下方向鍵會(huì)輸出
 // [
 //  undefined,
 //  {
 //   sequence: '\u001b[A',
 //   name: 'up',
 //   ctrl: false,
 //   meta: false,
 //   shift: false,
 //   code: '[A'
 //  }
 // ]
})

注意: setRawMode 會(huì)使命令行按下 ctrl + c 不再發(fā)送終止信號(hào), 可能需要自行處理退出邏輯

繪制幀畫(huà)面

輸出到命令行的游戲畫(huà)面默認(rèn)為 30 行 x 50 列, 將其劃分為一個(gè)二維數(shù)組, 每隔一段時(shí)間將二維數(shù)組的值打印出來(lái)并擦除之前打印的值, 即完成一次幀畫(huà)面的渲染

process.stdout 是一個(gè)可寫(xiě)流, 調(diào)用 process.stdout.write 可以向命令行寫(xiě)入數(shù)據(jù), nodejs 中 console.log 其實(shí)就是將數(shù)據(jù)寫(xiě)入到 process.stdout 并換行

通過(guò)向命令行寫(xiě)入開(kāi)頭為 ANSI 轉(zhuǎn)義序列 的字符串可以 光標(biāo)移動(dòng)/滾動(dòng)屏幕/擦除顯示/顏色文本 等等功能, 想要深入了解可以自行搜索關(guān)鍵字學(xué)習(xí), 本文使用 ansi-escapes npm 包實(shí)現(xiàn)擦除功能

const ansiEscapes = require('ansi-escapes')

function clear(lines) {
 process.stdout.write(ansiEscapes.eraseLines(lines)) // 可以擦除指定行數(shù)的輸出
}

根據(jù)游戲畫(huà)面的寬高定義一個(gè)二維數(shù)組, 小蛇的頭和身體視為畫(huà)面中的點(diǎn), 值為非空值, 空白畫(huà)面則為空字符串

let dots = []
for (let col = 0; col < wall.height; col++) {
 dots[col] = new Array(wall.width).fill(' ')
}

在每一幀中, 小蛇的頭會(huì)向前進(jìn)的方向前進(jìn)一個(gè), 頭接著的第一節(jié)身體則會(huì)移動(dòng)到上一幀頭所在的位置, 以此類(lèi)推每一節(jié)身體都會(huì)移動(dòng)到前一節(jié)身體的位置上, 所以需要定義一個(gè)數(shù)據(jù)記錄之前的頭和身體的位置

const SNAKE_HEAD = '@' // 頭的符號(hào)
const SNAKE_BODY = '○' // 身體的符號(hào)

function drawFrame() {
 let dots = []
 for (let col = 0; col < wall.height; col++) {
  dots[col] = new Array(wall.width).fill(' ')
 }

 let nextBody = []
 let head = next(snake.body[0]) // next 方法傳入當(dāng)前點(diǎn)的 x, y 坐標(biāo), 返回向前進(jìn)方向前進(jìn)一個(gè)的 x, y 坐標(biāo)
 nextBody.push(head)
 dots[head.y][head.x] = SNAKE_HEAD
 for (let i = 1; i < snake.length; i++) {
  let body = snake.body[i - 1]
  dots[body.y][body.x] = SNAKE_BODY
  nextBody.push(body)
 }
 
 screen.draw(dots) // 將二維數(shù)組中的點(diǎn)輸出到命令行中
 
 // 更新蛇的狀態(tài)
 snake.body = nextBody
 snake.head = snake.body[0]
}

蛇吃鳥(niǎo)蛋邏輯

小蛇每吃到一個(gè)鳥(niǎo)蛋, 身體會(huì)長(zhǎng)一節(jié), 并在畫(huà)面中隨機(jī)生成另一個(gè)鳥(niǎo)蛋. 到了這一步其實(shí)就很簡(jiǎn)單了, 隨機(jī)生成一個(gè)點(diǎn)作為鳥(niǎo)蛋的位置, 插入到之前的二維數(shù)組中.

function layAEgg() {
 let x = ~~(wall.width * Math.random())
 let y = ~~(wall.height * Math.random())
 return { x, y }
}

當(dāng)小蛇的頭的位置與鳥(niǎo)蛋的位置相同時(shí), 則視為蛇吃到鳥(niǎo)蛋, 蛇的長(zhǎng)度加一, 并在尾部增加一節(jié)上一幀蛇尾的節(jié)點(diǎn)位置

const SNAKE_HEAD = '@'
const SNAKE_BODY = '○'
const BIRD_EGG = '●'

function drawFrame() {
 let dots = []
 for (let col = 0; col < wall.height; col++) {
  dots[col] = new Array(wall.width).fill(' ')
 }

 let nextBody = []
 let head = next(snake.body[0])
 nextBody.push(head)
 dots[head.y][head.x] = SNAKE_HEAD
 for (let i = 1; i < snake.length; i++) {
  let body = snake.body[i - 1]
  dots[body.y][body.x] = SNAKE_BODY
  nextBody.push(body)
 }

 // 判斷蛇頭位置在上一幀中是否為鳥(niǎo)蛋位置, 為真視為蛇吃到鳥(niǎo)蛋
 if (prevDots && prevDots[head.y][head.x] === BIRD_EGG) {
  let body = snake.body[snake.length - 1]
  dots[body.y][body.x] = SNAKE_BODY
  nextBody.push(body)
  snake.length += 1
  egg = null
  prevDots = null
 }

 if (!egg) {
  egg = layAEgg()
  while (dots[egg.y][egg.x] !== ' ') {
   egg = layAEgg()
  }
 }
 dots[egg.y][egg.x] = BIRD_EGG

 prevDots = dots // 保存上一幀的數(shù)據(jù), 用于下次繪制時(shí)判斷邏輯

 screen.draw(dots)
 snake.body = nextBody
 snake.head = snake.body[0]
}

總結(jié)

至此, 命令行貪吃蛇游戲基本邏輯都已實(shí)現(xiàn), 剩下的就是使用定時(shí)器每隔一段時(shí)間繪制一次幀畫(huà)面. 其實(shí)幾乎任何像素游戲(如俄羅斯方塊/吃豆人等)都可以按照這個(gè)流程實(shí)現(xiàn), 不同的只是幀畫(huà)面的處理邏輯而已. 如果感興趣的話(huà), 可以去我的 github 查看該 貪吃蛇游戲源碼

到此這篇關(guān)于如何利用nodejs實(shí)現(xiàn)命令行游戲的文章就介紹到這了,更多相關(guān)nodejs實(shí)現(xiàn)命令行游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • node中使用es6/7/8(支持性與性能)

    node中使用es6/7/8(支持性與性能)

    這篇文章主要介紹了node中使用es6/7/8(支持性與性能),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • koa框架的原理、功能,與基本使用方法概述

    koa框架的原理、功能,與基本使用方法概述

    這篇文章主要介紹了koa框架的原理、功能,與基本使用方法,結(jié)合實(shí)例形式分析了koa框架的基本功能、原理、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2023-04-04
  • 學(xué)習(xí)Nodejs之fs模塊的使用詳解

    學(xué)習(xí)Nodejs之fs模塊的使用詳解

    這篇文章主要為大家詳細(xì)介紹了Nodejs之fs模塊的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • nodeJS中關(guān)于path.resolve()的用法解析

    nodeJS中關(guān)于path.resolve()的用法解析

    這篇文章主要介紹了nodeJS中關(guān)于path.resolve()的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 如何在NestJS中添加對(duì)Shopify的WebHook驗(yàn)證詳解

    如何在NestJS中添加對(duì)Shopify的WebHook驗(yàn)證詳解

    這篇文章主要為大家介紹了如何在NestJS中添加對(duì)Shopify的WebHook驗(yàn)證詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • node.js路徑處理方法以及絕對(duì)路徑詳解

    node.js路徑處理方法以及絕對(duì)路徑詳解

    這篇文章介紹的是nodejs路徑處理及絕對(duì)路徑以及一個(gè)Node.js獲取項(xiàng)目根目錄的小技巧,這個(gè)內(nèi)容非常實(shí)用。有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2016-09-09
  • Node.js中讀取TXT文件內(nèi)容fs.readFile()用法

    Node.js中讀取TXT文件內(nèi)容fs.readFile()用法

    在本篇文章中我們給大家分享一下Node.js中讀取TXT文件內(nèi)容以及fs.readFile()的用法,需要的朋友們可以參考下。
    2018-10-10
  • NodeJS的使用與NPM包管理器詳解

    NodeJS的使用與NPM包管理器詳解

    Node.js 是一個(gè)基于 Chrome V8 JavaScript 引擎 構(gòu)建的開(kāi)源、跨平臺(tái)運(yùn)行時(shí)環(huán)境,這篇文章主要介紹了NodeJS的使用與NPM包管理器,需要的朋友可以參考下
    2025-04-04
  • 如何配置nodejs的環(huán)境變量

    如何配置nodejs的環(huán)境變量

    這篇文章主要介紹了如何配置nodejs的環(huán)境變量問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • node.JS路徑解析之PATH模塊使用方法詳解

    node.JS路徑解析之PATH模塊使用方法詳解

    path模塊包含一系列處理和轉(zhuǎn)換文件路徑的工具集,通過(guò) require('path') 可用來(lái)訪問(wèn)這個(gè)模塊。本文將詳細(xì)介紹path模塊
    2020-02-02

最新評(píng)論

运城市| 宁波市| 虹口区| 信阳市| 大余县| 兴海县| 台湾省| 新巴尔虎右旗| 砀山县| 崇仁县| 五台县| 都匀市| 嘉祥县| 光泽县| 长武县| 宁安市| 梁平县| 澜沧| 海兴县| 韶关市| 奎屯市| 天津市| 文成县| 平舆县| 陆河县| 定州市| 烟台市| 金阳县| 中牟县| 张北县| 体育| 丰镇市| 望都县| 安平县| 德令哈市| 碌曲县| 达拉特旗| 牙克石市| 金平| 揭西县| 屏东市|