中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Node.js實現一個多人游戲服務器引擎

發布時間:2020-10-25 11:16:15 來源:腳本之家 閱讀:291 作者:瘋狂的技術宅 欄目:web開發

摘要

聽說過文字冒險游戲嗎? 如果你的年齡足夠大的話(就像我一樣),那么你可能聽說過、甚至玩過“back in the day”。在本文中,我將向你展示編寫的整個過程。這不僅僅是一個文本冒險游戲,而是一個能讓你和你的朋友們一起玩的,可以進行任何劇情的文本冒險游戲引擎。 沒錯,我們將通過在添加多人游戲功能來增加它的趣味性。

文字冒險是最早的 RPG 形式的游戲之一,回到還沒有圖形畫面的時代,你只能通過閱讀 CRT 顯示器上黑色背景下的描述,并且依賴自己的想象力來推動游戲劇情的發展。

如果要懷舊的話,可能世界上第一個文字冒險游戲名叫 Colossal Cave Adventure(也許是叫 Adventure)。

使用Node.js實現一個多人游戲服務器引擎

文字冒險游戲 back in the day 的畫面

上圖是你實際看到的游戲畫面,這與我們現在的頂級 AAA 冒險游戲相差甚遠。 盡管如此,但是他們玩起來卻很有趣,并會很容易的消磨你幾百個小時的時間,因為只有你自己自己坐在顯示器前,試圖找到打穿它的途徑。

可以理解的是,多年以來,文字冒險已經被更好的視覺效果所取代,特別是在過去幾年里,游戲的協作性越強,你可以和朋友們一起玩。 這是原始的文字冒險游戲所缺少的,同時也是我想在本文中提到的功能。

我們的目標

可能你已經從標題中猜到了,本文的重點在于創建一個文字冒險引擎,并且讓你和朋友們一起玩,使你能夠與他們進行協作,就像在玩“龍與地下城”這個游戲一樣。

在創建引擎時,聊天服務器和客戶端的工作了相當大。 在本文中,我將向你展示設計思路、解釋引擎背后的架構、客戶端如何與服務器交互以及這個游戲的規則。

為了讓你對我的目標又一個直觀的感受,先上一張圖:

使用Node.js實現一個多人游戲服務器引擎

游戲客戶端的 UI 設計

這就是我們的目標。 一旦達成這個目標,將會得到截圖而不是簡單和骯臟的模型。 所以,需要了解這個過程。首先要介紹的就是整體設計;然后介紹我將用來編碼的相關工具;最后我將向你展示一些核心代碼(當然,還有指向完整代碼庫的鏈接)。

希望到最后,你能夠自己創造一個新的文字冒險游戲,并與朋友一起樂在其中!

設計階段

在設計階段,我將描述這個游戲的整體藍圖。 我會盡力不讓你覺得無聊,不過我認為在給你展示第一行代碼之前,很有必要先搞清楚幕后的一些工作。

我想接下來介紹的這四個組件能夠提供相當多的細節:

  • 引擎
    • 這將成為游戲的主服務器。游戲規則會在這里實現,它將為任何類型的客戶端提供技術無關接口。本項目中我們將實現終端類型的客戶端,但是你可以用Web客戶端或者你喜歡的任何其他類型。
  • 聊天服務器
    • 因為它的復雜性足以再寫一篇文章了,所以這項服務也會擁有自己的模塊。聊天服務器負責讓玩家在游戲的過程中彼此通信。
  • 客戶端
    • 如前文所述,這將是一個終端類型的客戶端,在理想情況下,它看起來與之前的模型類似。它將利用引擎和聊天服務器所提供的服務。
  • 游戲( JSON文件 )
    • 最后,我將介紹實際游戲的定義。這部分的重點是創建一個可以運行任何游戲的引擎,只要你的游戲文件符合引擎的要求即可。所以,即使這不需要編碼,我也將解釋如何構建冒險文件以便將來編寫我們自己的冒險規則。

引擎

游戲引擎或游戲服務器將會是REST API,并提供所有必需的功能。

我選擇REST API只是因為(對于這種類型的游戲)HTTP造成的延遲以及他的異步特性不會造成任何麻煩。 但是,我們必須為聊天服務器采用不同的路線。 在開始定義 API 之前,先需要定義引擎的功能。 所以,讓我們來看看吧。

特性 描述
加入游戲 玩家可以通過指定的游戲ID來加入游戲。
創建一個新游戲 玩家還可以創建新的游戲實例。 引擎應該返回一個ID,以便其他人可以使它來加入游戲。
返回場景 此功能應返回玩家所在的當前場景。 基本上,它將返回描述,包含所有相關信息(可能的操作、其中的對象等)。
與場景互動 這將是最復雜的一個,因為它將從客戶端獲取命令并執行該操作——例如移動,攻擊,獲取,查看,讀取等等。
檢查庫存 雖然這是與游戲互動的一種方式,但它與場景并沒有直接關系。 因此,檢查每個玩家的庫存將被視為不同的操作。

關于移動

我們需要一種用來測量游戲中距離的方法,因為在游戲中玩家可以采取的核心行動之一就是移動。 我們需要用這個數字作為時間的衡量標準,來簡化游戲的玩法。 考慮到這一類型的游戲具有基于回合的動作,例如戰斗,使用實際時鐘對時間進行測量可能不是最好的。 所以我們將使用距離來測量時間(意味著距離為 8 比距離為 2 將需要更多的時間,從而允許我們做一些事情,例如為持續一定數量的“距離點”的玩家添加效果)。

考慮運動的另一個原因是不是一個人在玩這個游戲。 為簡單起見,引擎不會讓玩家隨意組隊(雖然這對未來可能是一個有趣的改進)。 該模塊的初始版本只允許個人朝著大多數參與者決定的地方移動。因此,必須以協商一致的方式進行移動,這意味著每一步行動都將等待大多數人在行動之前提出請求。

戰斗

戰斗是這種游戲另一個非常重要的方面,我們不得不考慮將它添加到引擎中,否則我們最終會失去一些樂趣。

說實話,這并不需要重新發明輪子。基于回合制的組隊對戰已經存在了幾十年,所以在這里只實現這個機制的一個簡單版本。我們將把它與“龍與地下城”中的“主動性”這個概念混合起來,產生一個隨機數使戰斗更有活力。

換句話說,就是參與戰斗的每個人的行動順序將會被隨機化,其中包括敵人。

最后(雖然我將在下面詳細介紹這一點),你可以用設置的“攻擊力”值的物品。這些是你在戰斗中可以使用的道具;如果一個道具沒有這個屬性的話只能對敵人造成 0 點傷害。當你試圖用這樣的道具進行戰斗時,我們可能會添加一條消息,這樣你就能知道自己要做的事情是毫無意義的。

客戶端 - 服務器交互

現在來看看客戶端怎樣基于前面定義的功能與服務器進行交互(目前還沒考慮端點,不過馬上就會講到這個):

使用Node.js實現一個多人游戲服務器引擎

客戶端與服務器之間的交互

客戶端和服務器之間的初始交互(從服務器的角度來看)是一個新游戲的開始,其步驟如下:

  • 創建一個新游戲。
    • 客戶端請求向服務器創建新游戲。
  • 創建聊天室。
    • 雖然沒有明確說明,但是服務器不只是在聊天服務器中創建聊天室,而且還設置好了所需的一切,可以允許一組玩家進行游戲。
  • 返回游戲的元數據。
    • 一旦服務器為玩家創建好了游戲和聊天室,那么客戶端會在后續請求用到這個信息。這是客戶端可以用來標識自己和將要加入的游戲實例的一組ID。
  • 手動分享游戲ID 。
    • 這一步必須由玩家自己完成。我們可以提出某種共享機制,但我會將它留在愿望清單上等待將來改進。
  • 加入游戲。
    • 這個非常簡單。每個人都有一個 ID,客戶端通過這個 ID 加入游戲。
  • 加入聊天室。
    • 最后,玩家的客戶端程序將通過游戲的元數據加入對應的聊天室。這是游戲開始前的最后一步。一旦完成所有操作,玩家就可以開始在游戲中冒險了!

使用Node.js實現一個多人游戲服務器引擎

游戲的動作指令

一旦滿足了先決條件,玩家就可以開始游戲,通過聊天室分享他們的想法,并推動故事的發展。上圖顯示了所需的四個步驟。

以下步驟將作為游戲循環的一部分來運行,這意味著它們將會不斷重復,一直到游戲結束。

  • 請求場景。
    • 客戶端程序將請求當前場景的元數據。這是循環每次迭代的第一步。
  • 返回元數據。
    • 服務器將發回當前場景的元數據。這些信息中包括一般描述,從中可以找到的對象以及它們彼此之間的關系。
  • 發送命令。
    • 好戲開始。這是玩家的主要輸入方式。它包括玩家想要執行的操作,以及可選的操作目標(例如吹蠟燭、抓住巖石等)。
  • 對發來的命令做出響應。
    • 這應該屬于第二步,但為了清楚起見,我把它作為額外步驟。主要區別在于第二步可以被認為是這個循環的開始,而這一步考慮到你已經開始進行游戲了,因此,服務器需要了解這個動作將影響誰(單個或所有玩家)。

作為額外步驟,雖然不是流程的一部分,但服務器將通知客戶端與它們相關的狀態的更新情況。

存在這個額外重復步驟的原因是玩家可以從其他玩家的動作中獲得更新。回想從一個地方移動另一個地方的需求;正如我之前所說那樣,一旦大多數玩家選擇了方向,那么所有玩家都會移動(不需要所有球員的輸入)。

不過 HTTP(前面已經提到服務器為REST API)不允許這種類型的行為。所以,我們的選擇是:

  • 每隔 X 秒從客戶端輪詢,
  • 使用某種與客戶端-服務器連接通信機制并行工作的通知系統。

根據我的經驗,我傾向于選擇選項 2。實際上,我會(在本文中)使用Redis來實現這種行為。

下圖演示了服務之間的依賴關系。

使用Node.js實現一個多人游戲服務器引擎

客戶端應用程序與游戲引擎之間的交互

聊天服務器

我將把這個模塊的設計細節留給開發階段(本文不涉及這一部分)。話雖如此,我們仍可以決定一些事情。

我們可以確定的一件事是服務器的限制集合,這將簡化我們的工作。如果我們正確地玩牌,最終可能會有一個提供強大界面的服務,從而允許我們去進行擴展甚至修改實現,以提供更少的限制,而不會影響到游戲。

  • 每個組隊只有一個房間。
    • 我們不會創建子組隊。這和不讓組隊分裂是相輔相成的。也許一旦以后我們實現了這個增強功能,允許創建子組和自定義聊天室或許是一個好主意。
  • 沒有私信功能。
    • 這純粹是為了簡化,但是只有群聊并不夠好。目前我們不需要私信。請記住,任何時候只研究你的最小化可行產品,盡量避免掉進不必要功能的陷阱;這是一條危險的道路,很難從困境中擺脫出來。
  • 不會保存留言。
    • 換句話說,如果你離開組隊,將會丟失這些信息。這將極大地簡化我們的任務,因為我們不必處理任何類型的數據存儲,也不必浪費時間來優化存儲和恢復舊消息的數據結構。它們都存在于內存中,只要聊天室處于活動狀態,就會一直存在。一旦關閉,就會簡單地對它們說Goodbye!
  • 通過網絡套接字進行通信。
    • 可悲的是,我們的客戶將不得不處理雙重溝通渠道:游戲引擎的 RESTful 和聊天服務器的套接字。這可能會增加客戶端的復雜性,但與此同時,它將為每個模塊使用最佳通信方法。 (在聊天服務器上強制 REST 或在游戲服務器上強制使用套接字沒有任何意義。這種方法會增加服務器端代碼的復雜性,這也是處理業務邏輯的代碼,所以讓我們關注目前的問題。)

這就是聊天服務器。畢竟,它不會很復雜。在開始編碼之前還有很多工作要做,但是對于本文來說已經足夠了。

客戶端

這是最后一個需要編碼的模塊,它將是最笨重的一個模塊。根據經驗來看,我更喜歡讓客戶端笨重,使服務器輕巧。這樣為服務器開發新的客戶端會更加容易。

這是我們最終應該采用的架構。

使用Node.js實現一個多人游戲服務器引擎

最終架構

我們要實現的ClI客戶端很簡單,不會實現任何非常復雜的東西。實際上,必須要解決的最復雜的部分是 UI,因為它是一個基于文本的界面。

客戶端應用程序必須實現的功能如下:

  • 創建一個新游戲。
    • 因為我希望盡可能保持簡單,所以這只能通過 CLI 界面完成。實際用戶界面只會在加入游戲后被用到,這把我們帶到下一個問題。
  • 加入現有游戲。
    • 玩家可以根據由上一條返回的游戲編號來加入游戲。另外,這件事應該能夠在沒有 UI 的情況下完成,因此這個功能將成為開始使用文本 UI 所需的過程的一部分。
  • 解析游戲定義文件。
    • 我們將對這點進行的討論,客戶端應該能夠理解這些文件,以便能夠理解要顯示的內容,并知道應該如何使用這個數據。
  • 與冒險互動。
    • 基本上,這使玩家能夠在任何時間與給出描述的環境進行交互。
  • 為每位玩家維護背包內容。
    • 客戶端的每個實例都將在內存中包含一份道具列表。此列表將被備份。
  • 支持聊天。
    • 客戶端程序還需要連接到聊天服務器,并使用戶登錄到組隊的聊天室。

稍后將詳細介紹客戶端的內部結構和設計。與此同時,讓我們完成設計階段的最后一部分:游戲文件。

游戲:JSON文件

這是它變得有趣的地方,因為到次為止,我已經涵蓋了基本的微服務定義。其中一些可能會基于 REST,而另外一些可能會使用套接字,但本質上它們都是一樣的:你定義并對它們編碼,然后它們提供服務。

我不打算對這個特定的組件做任何編碼,但我們仍然需要設計它。基本上我們是在實現一種協議來定義游戲、它內部的場景以及一切。

如果你想一想,文本冒險的核心基本上是一組相互連接的房間,里面是你可以與之互動的“事物”,所有這些都與一個引人入勝的故事聯系在一起。現在我們的引擎不會處理最后一部分,這部分將取決于你。

現在回到相互連接的房間,對我來說這就像一個圖結構,如果我們還添加了前面提到的距離或移動速度的概念,還需要一個加權圖。這只是一組節點,它們具有權重(或只是一個數字 —— 不要糾結它的名稱),代表了它們之間的路徑。下面是一個示意圖(我喜歡通過觀察進行學習,所以只看圖,好嗎?):

使用Node.js實現一個多人游戲服務器引擎

這是一個加權圖 —— 就是這樣。我相信你已經弄明白了,但為了完整起見,讓我告訴你一旦我們的引擎準備就緒,你將會做些什么。

一旦開始設置游戲,你將創建地圖(就像你在下圖中左側看到的那樣)。然后將其轉換為加權圖,如圖所示。引擎將能夠接收它并讓你按正確的順序進行瀏覽。

使用Node.js實現一個多人游戲服務器引擎

一個地牢的示例圖

通過上面的加權圖,可以確保玩家不能從入口一下子走到左翼。他們必須通過這兩者之間的節點,這樣做會消耗時間,可以用連接的權重來測量。

現在,進入“有趣”的部分。來看看地圖在 JSON 格式中的樣子。這個JSON將包含很多信息:

{
 "graph": [
  { "id": "entrance", "name": "Entrance", "north": { "node": "1stroom", "distance": 1 } },
 { "id": "1st room", "name": "1st Room", "south": {"node": "entrance", "distance": 1} , "north": { "node": "bigroom", "distance": 1} } ,
 { "id": "bigroom",
 "name": "Big room",
 "south": { "node": "1stroom", "distance": 1},
 "north": { "node": "bossroom", "distance": 2},
 "east": { "node": "rightwing", "distance": 3} ,
 "west": { "node": "leftwing", "distance": 3}
 },
 { "id": "bossroom", "name": "Boss room", "south": {"node": "bigroom", "distance": 2} }
 { "id": "leftwing", "name": "Left Wing", "east": {"node": "bigroom", "distance": 3} }
 { "id": "rightwing", "name": "Right Wing", "west": { "node": "bigroom", "distance": 3 } }
 ],
 "game": {
 "win-condition": {
 "source": "finalboss",
 "condition": {
  "type": "comparison",
  "left": "hp",
  "right": "0",
  "symbol": "<="
 }
 },
 "lose-condition": {
 "source": "player",
 "condition": {
  "type": "comparison",
  "left": "hp",
  "right": "0",
  "symbol": "<="
 }
 }
 },
 "rooms": {
 "entrance": {
 "description": {
  "default": "You're at the entrance of the dungeon. There are two lit torches on each wall (one on your right and one on your left). You see only one path: ahead."
 },
 "items": [
  {
  "id": "littorch2",
  "name": "Lit torch on the right", 
  "triggers": [
  {
  "action": "grab", //grab Lit torch on the right
  "effect":{
   "statusUpdate": "has light",
   "target": "game",
  }
  }
  ] ,
  "destination": "hand"
  },
  {
  "id": "littorch3",
  "name": "Lit torch on the left", 
  "triggers": [
  {
  "action": "grab", //grab Lit torch on the left
  "effect":{
   "statusUpdate": "has light",
   "target": "game",
  }
  }
  ] ,
  "destination": "hand"
  
  }
 ]
 },
 "1stroom": {
 "description": {
  "default": "You're in a very dark room. There are no windows and no source of light, other than the one at the entrance. You get the feeling you're not alone here.",
  "conditionals": {
  "has light": "The room you find yourself in appears to be empty, aside from a single chair in the right corner. There appears to be only one way out: deeper into the dungeon."
  }
 },
 "items": [
  {
  "id": "chair",
  "name": "Wooden chair",
  "details": "It's a wooden chair, nothing fancy about it. It appears to have been sitting here, untouched, for a while now.",
  "subitems": [
  { "id": "woodenleg", 
  "name": "Wooden leg",
  "triggeractions": [
   { "action": "break", "target": "chair"}, //break 
   { "action": "throw", "target": "chair"} //throw 
  ],
  "destination": "inventory",
  "damage": 2
  }
  ]
  }
 ]
 },
 "bigroom": {
 "description": {
  "default": "You've reached the big room. On every wall are torches lighting every corner. The walls are painted white, and the ceiling is tall and filled with painted white stars on a black background. There is a gateway on either side and a big, wooden double door in front of you."
 },
 "exits": {
  "north": { "id": "bossdoor", "name": "Big double door", "status": "locked", "details": "A aig, wooden double door. It seems like something big usually comes through here."}
 },
 "items": []
 },
 "leftwing": {
 "description": {
  "default": "Another dark room. It doesn't look like it's that big, but you can't really tell what's inside. You do, however, smell rotten meat somewhere inside.",
  "conditionals": {
  "has light": "You appear to have found the kitchen. There are tables full of meat everywhere, and a big knife sticking out of what appears to be the head of a cow."
  }
 },
 "items": [
  { "id": "bigknife", "name": "Big knife", "destination": "inventory", "damage": 10}
 ]
 },
 "rightwing": {
 "description": {
  "default": "This appear to be some sort of office. There is a wooden desk in the middle, torches lighting every wall, and a single key resting on top of the desk."
 },
 "items": [
  { "id": "key",
  "name": "Golden key",
  "details": "A small golden key. What use could you have for it?",
  "destination": "inventory",
  "triggers": [{
  "action": "use", //use on north exit (contextual)
  "target": {
  "room": "bigroom",
  "exit": "north"
  },
  "effect": {
  "statusUpdate": "unlocked",
  "target": {
   "room": "bigroom",
   "exit": "north"
  }
  }
  }
  ]
  }
 ]
 },
 "bossroom": {
 "description": {
  "default": "You appear to have reached the end of the dungeon. There are no exits other than the one you just came in through. The only other thing that bothers you is the hulking giant looking like it's going to kill you, standing about 10 feet from you."
 },
 "npcs": [
  {
  "id": "finalboss",
  "name": "Hulking Ogre",
  "details": "A huge, green, muscular giant with a single eye in the middle of his forehead. It doesn't just look bad, it also smells like hell.",
  "stats": {
  "hp": 10,
  "damage": 3
  }
  }
 ]
 }
 }
}

它看起來有很多內容,但是如果你把它視為一個簡單的游戲描述,就會明白這是一個含有六個房間的地牢,每個房間都與其他房間相互連接,如上圖所示。

你的任務是穿越并探索它。你會發現有兩個地方可以找到武器(無論是在廚房還是在黑暗的房間,只要破壞掉椅子就能得到)。你也將面對一扇上鎖的門,所以,一旦找到鑰匙(位于類似辦公室的房間內),就可以打開并用你收集到的武器和BOSS展開一場大戰。

你可以干掉它而獲勝,也可以被它殺死而輸掉。

現在讓我們更詳細地了解整個 JSON 結構及其中的三個部分。

Graph

這里包含節點之間的關系。基本上這一部分會直接轉換為我們之前看到的圖。

這部分的結構非常簡單。它是一個節點列表,其中每個節點都包含以下屬性:

  • 一個標識游戲中所有其他節點的唯一 ID;
  • 一個名稱,實際上是給玩家看到的 ID 版本;
  • 一組指向其他節點的鏈接。這可以通過四個可能的 key 來描述:north, south, east 和 west.。我們可以通過添加這四個組合來增加更多方向。每個鏈接都包含相關節點的 ID 以及該關系的距離(或權重)。

Game

本節包含常規設置和條件。特別是在上面的示例中,此部分包含輸贏條件。換句話說,在這兩個條件下,我們會讓游戲知道什么時候結束。

為了簡單起見,我添加了兩個條件:

  • 要么通過殺死 BOSS 獲勝,
  • 或者因為被殺而輸掉。

Rooms

這一部分占了 JSON 文件很大的篇幅,也是最復雜的部分。在這里描述冒險中所有區域及其內部所有房間。

每個房間都有一把鑰匙,使用我們之前定義的 ID。每個房間都有一個描述,一個物品列表,一個出口(或門)列表和一個非玩家角色(NPC)列表。在這些屬性中,唯一應該被強制定義的屬性是描述,因為引擎需要這個屬性才能讓你明白所看到的內容。如果有什么東西需要展示,它們只能在那里。

讓我們來看看這些屬性能為游戲做些什么。

description
這一項并不像想象的那么簡單,因為你看到的房間可能會根據不同的情況而變化。例如:如果你查看第一個房間的描述,就會注意到在默認情況下,你將看不到任何東西,除非你有一個點亮的火炬。

因此,拾取物品并使用它們,可能會觸發影響游戲中其他部分的全局條件。

items

這些代表了你可以在房間內找到的所有東西。每個項目都會共享與 graph 節點相同的 ID 和名稱。

它們還有“目標”屬性,該屬性指示一旦拾取該道具應放在哪里。這是有意義的,因為你手上只能裝備一個道具,而在背包中可以存放很多的道具。

最后,其中一些道具可能會觸發其他操作或者狀態更新,具體取決于玩家決定用它們做什么。其中一個例子就是從入口處點燃的火把。如果你拿著一個,將在游戲中觸發狀態更新,這反過來將使游戲向你顯示下一個房間的不同描述。

道具也可以有“子道具”,一旦原始道具被銷毀(例如通過“分解”操作)就會發揮作用。一個道具可以被分解為多個,并在“subitems”元素中定義。

本質上,此元素只是一個新道具的數組,其中還包含可以觸發其創建的一組操作。基本上可以根據你對原始道具執行的操作創建不同的子道具。

最后,有些物品會有“傷害”屬性。所以如果你用某個道具擊中 NPC,該值用于從中減去生命。

exits

出口是與道具分開的實體,因為引擎需要知道你是否能夠根據其狀態去遍歷它們。否則被鎖定的出口無法讓你通過,除非你把它的狀態改為已解鎖。

NPC

最后,NPC 將成為另一個列表的一部分。它們是有狀態信息的項目,引擎將使用這些狀態信息來了解每個項目的行為方式。在我們的例子中定義的是 “hp”,它代表健康狀態,還有“damage”,就像武器一樣,每次命中將從玩家的健康狀況中減去相應的值。

這就是我創造的地牢。內容很多,將來我可能會考慮寫一個編輯器,來簡化 JSON 文件的創建。但就目前而言還沒有必要。

你可能還沒有意識到,這樣在文件中定義游戲是有很大好處的,能夠像超級任天堂時代那樣切換 JSON 文件。只需加載一個新文件就能開始另一個游戲。非常簡單!

總結

感謝你能讀到這里。希望你能喜歡我所經歷的設計過程,并將想法變為現實。我正在努力實現這一目標。我們以后可能會意識到,今天定義的內容可能會不起作用,出現這種情況時,我們將不得不回溯并修復它。

我敢肯定,有很多方法可以對這里提出的想法進行改善,并創建一個地獄的引擎。但是這需要在本文中添加的更多的內容,為了不讓讀者感到無聊,所以就先這樣吧。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

涪陵区| 离岛区| 班戈县| 永川市| 什邡市| 安溪县| 哈尔滨市| 泾源县| 徐闻县| 定襄县| 易门县| 海门市| 紫金县| 张北县| 陵川县| 桦川县| 舒兰市| 郯城县| 五莲县| 河南省| 五河县| 松江区| 隆尧县| 门源| 济源市| 松滋市| 锡林郭勒盟| 彭泽县| 丰镇市| 陇西县| 桐乡市| 水富县| 南昌市| 富宁县| 营口市| 梓潼县| 贺兰县| 海盐县| 井冈山市| 丁青县| 绥江县|