<cite id="ffb66"></cite><cite id="ffb66"><track id="ffb66"></track></cite>
      <legend id="ffb66"><li id="ffb66"></li></legend>
      色婷婷久,激情色播,久久久无码专区,亚洲中文字幕av,国产成人A片,av无码免费,精品久久国产,99视频精品3
      網易首頁 > 網易號 > 正文 申請入駐

      用 200 行 MoonBit 構建原生移動端游戲

      0
      分享至


      一、引言

      當你想做一個簡單的手機游戲 , 比如 Flappy Bird、2048、貪吃蛇——你的第一反應可能是打開 Unity 或者 Godot。但你有沒有想過:對于一個只需要畫幾個矩形和圓的游戲,你真的需要一個完整的游戲引擎嗎?

      引擎內部數十萬行的 C++ 代碼 帶來的不只是便利, 或許還有冗余 。如果我們換一種思路 : 不用引擎,不依賴運行時,直接用一門現代語言編寫游戲邏輯,編譯為原生機器碼,再搭配一個極簡的圖形庫 , 結果會怎樣?

      這正是本文要探討的命題 : 使用 MoonBit (一門編譯到原生代碼的現代語言)和 Raylib (一個僅提供最基本圖形能力的 C 庫),從零構建一個可以在 Android 手機上運行的 Flappy Bird。

      在這個過程中,你會看到:一個完整的移動游戲,可以只有幾百行代碼、幾 MB 的 APK,以及零引擎依賴。

      Web 游戲試玩鏈接:

      https://moonbit-community.github.io/tonyfettes-raylib-android-games

      Android 游戲 APK 下載鏈接:

      https://moonbit-community.github.io/tonyfettes-raylib-android-games/

      二、移動游戲開發的技術選型 演進

      2015年前后,手機游戲開發主要依賴三大技術路線:

      1. 引擎時代(Unity/Godot):提供一站式開發環境,大幅降低門檻,但存在包體臃腫、底層黑箱、版本更新風險等問題。Godot 雖開源,思路仍類似。

      2. 跨平臺框架(React Native/Flutter):承諾一套代碼多端運行,適合 UI 應用。但在游戲中暴露出額外抽象層、GC 停頓、非為高頻渲染優化等性能瓶頸。

      3. 原生 NDK(C/C++):性能最優,無中間開銷,但開發體驗差,手動內存管理易引發段錯誤等 bug,對業余項目成本過高。

      有沒有一種方案,既能獲得原生性能,又能享受現代語言的開發體驗?

      這正是 MoonBit 和 Raylib 的組合所提供的。

      MoonBit 是一門為性能而設計的現代編程語言。它擁有強類型系統、模式匹配、類型推導,編寫體驗接近 Rust 或 OCaml,但編譯目標是 C——這意味著它可以直接對接 Android NDK 的工具鏈,最終生成和手寫 C 一樣高效的原生代碼。

      Raylib 則是游戲圖形庫的極簡主義代表。它不是引擎,不幫你管理場景,不提供編輯器——它只做四件事: 開窗口、畫圖形、讀輸入、放聲音 。用戶面對的核心 API 集中在一個頭文件 raylib.h 中,沒有復雜的依賴關系,沒有狀態機,沒有回調地獄。

      把它們組合在一起,你得到的是:


      這不是說 MoonBit + Raylib 適合所有場景——如果你在做一款需要物理引擎、粒子系統、骨骼動畫的大型游戲,Unity 仍然是更合理的選擇。但如果你的目標是一款邏輯清晰的 2D 游戲,這套"極簡主義"方案可能是最干凈的路徑。

      讓我們來看看它是怎么工作的。

      三、理解構建鏈路:從源碼到 APK

      在動手寫代碼之前,有一個問題值得想清楚: 你寫的 MoonBit 代碼,是如何變成手機上可以運行的 APK 的?

      理解構建鏈路不是為了背誦流程——而是為了在出問題時,知道該往哪里看。

      1、 構建鏈路

      整個過程可以用一條鏈來描述:


      讓我們逐步拆解。

      第一步:MoonBit → C 。MoonBit 編譯器將你的 `.mbt` 源文件編譯為標準 C 代碼。MoonBit 的強類型系統在編譯期就排除了大量常見錯誤,生成的 C 代碼是高效的、確定性的。你可以把它理解為:MoonBit 幫你寫了人類不太愿意手寫的那種高質量 C 代碼。

      第二步:C → .so 。Android NDK 中的交叉編譯器(通常是 clang)接手,將 C 代碼連同 Raylib 的源碼一起編譯為目標架構的共享庫(`.so` 文件)。這一步和你用 NDK 編譯任何 C/C++ 項目一樣。

      第三步:打包成 APK 。Gradle 構建系統將 .so 文件打包進 APK。同時,那個極輕量的 Kotlin 入口點(僅僅是加載庫和隱藏系統 UI)會經過標準的 Android 編譯流程:Kotlin 編譯器將其編譯為 JVM 字節碼,再由 D8 工具轉換為 Android 運行時使用的 classes.dex 。最終的 APK 結構非常簡單:

      APK
      ├── classes.dex ← 極小的 Kotlin 膠水代碼
      ├── lib/
      │ ├── arm64-v8a/
      │ │ └── libflappybird.so ← 你的游戲 + Raylib
      │ └── armeabi-v7a/
      │ └── libflappybird.so
      └── AndroidManifest.xml

      如果用一個類比:傳統引擎方案就像你寫了一封信,然后把它裝進一個帶有自動翻譯器、排版引擎和朗讀功能的智能信封里寄出去。而 MoonBit + Raylib 的方案就像你直接把信折好,塞進一個普通信封——信的內容沒有變,但信封輕了十倍。

      2、 腳手架:一鍵搭建項目

      理解了鏈路之后,實際操作反而很簡單。MoonBit 生態提供了一個腳手架工具,可以一鍵生成上述所有構建配置:

      moon install tonyfettes/create-moonbit-raylib-android-app
      create-moonbit-raylib-android-app MyFlappyBird

      生成的項目結構看起來像這樣:

      MyFlappyBird/
      ├── gradlew # Gradle 構建包裝器
      ├── app/
      │ ├── build.gradle.kts # Android 構建配置 (NDK, ABI 目標)
      │ ├── src/main/
      │ │ ├── AndroidManifest.xml # 應用清單 (NativeActivity)
      │ │ ├── java/.../MainActivity.kt # 輕量 Kotlin 入口點
      │ │ ├── moonbit/ # 你的游戲代碼存放處
      │ │ │ ├── main.mbt # 游戲代碼
      │ │ │ ├── moon.mod.json # MoonBit 模塊配置
      │ │ │ └── moon.pkg # 包聲明
      │ │ └── cpp/
      │ │ └── CMakeLists.txt # 構建管道膠水代碼
      │ └── ...
      └── gradle/

      這里關鍵的只有一個目錄: app/src/main/moonbit/ ——你的所有游戲邏輯都寫在這里。其余的 Gradle 配置、CMake 文件、Kotlin 入口點,腳手架已經幫你處理好了。

      模塊配置( moon.mod.json )聲明了對 Raylib 綁定的依賴:

      {
      "name": "username/myflappybird",
      "version": "0.1.0",
      "deps": {
      "tonyfettes/raylib": "0.2.2"
      },
      "preferred-target": "native"
      }

      構建和部署也是一行命令:

      cd MyFlappyBird
      ./gradlew assembleDebug --no-daemon

      第一次構建需要幾分鐘(它會從源碼編譯 Raylib),之后的增量構建會快得多。你也可以在 Android Studio 中打開項目,點擊 Run 按鈕一鍵編譯部署。


      在運行時,輕量的 MainActivity 加載 .so 庫,NDK 膠水代碼啟動原生端,Raylib 初始化 OpenGL ES 上下文,然后調用 main() ——也就是你用 MoonBit 寫的那個 fn main 。

      基礎設施講完了。現在讓我們進入真正有趣的部分:游戲邏輯。

      四、構建 Flappy Bird

      1、游戲循環

      從《超級馬里奧》到《原神》,所有實時游戲在最底層都共享同一個結構——初始化(Init)、循環執行更新(Update)與繪制(Draw)、最后清理(Cleanup):


      這就是 游戲循環(Game Loop) 。它揭示了實時游戲的本質: 游戲不是一系列事件的響應,而是一幀又一幀的持續模擬 。和 Web 應用的事件驅動模型不同,游戲代碼每秒執行 60 次,無論用戶是否操作——用戶輸入不是觸發器,而是被每一幀"采樣"的信號。

      一個良好的游戲架構應該將 狀態更新(update) 和 畫面繪制(draw) 嚴格分離:update 只修改數據,draw 只讀取數據,不存在交叉副作用。讓我們用這個原則來構建 Flappy Bird。

      2、定義游戲世界

      首先,用結構體描述游戲中的所有對象:

      ///|
      privstructBird {
      muty : Float
      mutvelocity : Float
      }

      ///|
      privstructPipe {
      mutx : Float
      mutgap_y : Float
      mutscored : Bool
      }

      ///|
      privstructGame {
      sw : Float
      sh : Float
      bird_x : Float
      bird : Bird
      bird_radius : Float
      gravity : Float
      jump_force : Float
      pipes : Array[Pipe]
      pipe_width : Float
      gap_size : Float
      pipe_speed : Float
      pipe_spacing : Float
      mut score : Int
      mut game_over : Bool
      }

      Bird 只保存 每幀變化 的值(位置和速度),而 不變的屬性 (水平位置、半徑)由 Game 持有—— 可變狀態越少,bug 越少 。每個 Pipe 記錄水平位置 x 、空隙中心點 gap_y (開口的垂直中點)和計分標志 `scored`。

      另一個值得關注的細節:所有大小都從屏幕尺寸( sw 、 sh )派生——鳥的半徑是 sh / 25.0 ,重力加速度是 sh * 1.5 。這意味著游戲在任何分辨率的設備上都能保持相同的視覺比例和手感,不需要額外的適配邏輯。

      3、游戲邏輯

      update 函數處理所有狀態變化——物理模擬、水管移動、碰撞檢測和計分:

      ///|
      fn update(game : Game, dt : Float) -> Unit {
      if game.game_over {
      if@raylib.is_gesture_detected(@raylib.GestureTap) {
      reset(game)
      }
      return
      }

      if@raylib.is_gesture_detected(@raylib.GestureTap) {
      game.bird.velocity = game.jump_force
      }

      game.bird.velocity += game.gravity * dt
      game.bird.y += game.bird.velocity * dt

      // 限制在屏幕邊緣內
      if game.bird.y < game.bird_radius {
      game.bird.y = game.bird_radius
      game.bird.velocity = 0.0
      }
      if game.bird.y > game.sh - game.bird_radius {
      game.bird.y = game.sh - game.bird_radius
      game.bird.velocity = 0.0
      }

      for pipe in game.pipes {
      pipe.x -= game.pipe_speed * dt
      // 水管滾出左邊緣后回收到右側
      if pipe.x < -game.pipe_width {
      pipe.x += Float::from_int(game.pipes.length()) * game.pipe_spacing
      pipe.gap_y = random_gap_y(game)
      pipe.scored = false
      }

      // AABB 碰撞檢測
      if game.bird_x + game.bird_radius > pipe.x &&
      game.bird_x - game.bird_radius < pipe.x + game.pipe_width {
      if game.bird.y - game.bird_radius < pipe.gap_y - game.gap_size / 2.0 ||
      game.bird.y + game.bird_radius > pipe.gap_y + game.gap_size / 2.0 {
      game.game_over = true
      }
      }

      // 飛過水管時計分
      if not(pipe.scored) && pipe.x + game.pipe_width < game.bird_x {
      game.score += 1
      pipe.scored = true
      }
      }
      }

      這段代碼有幾個值得注意的設計決策:

      • 幀率無關性 :所有涉及"隨時間變化"的量都乘以 `dt`(自上一幀經過的秒數)。`game.bird.velocity += game.gravity * dt` 意味著"每秒增加 `gravity` 這么多速度"——無論設備是 60fps 還是 30fps,物理效果一致。

      • 對象回收 :整個游戲只有 4 個水管對象。當一根水管滾出左邊緣,直接把 `x` 坐標加上偏移量"傳送"到最右邊,重新隨機空隙位置。不需要對象池框架——一個 `if` 和一次坐標重置就夠了。

      • AABB 碰撞檢測 :將圓形小鳥近似為外接矩形,檢測它與水管矩形是否重疊——先查水平方向重疊,再查小鳥是否在空隙之外。不是像素級精確,但對休閑游戲完全足夠。

      • 游戲結束檢查 :`update` 頂部的 `game_over` 檢查攔截一切后續邏輯,讓游戲"凍結"在撞擊瞬間,只允許點擊重啟。

      draw 函數只負責將當前狀態繪制到屏幕:

      ///|
      fn draw(game : Game) -> Unit {
      @raylib.begin_drawing()
      @raylib.clear_background(@raylib.skyblue)
      for pipe in game.pipes {
      let px = pipe.x.to_int()
      let pw = game.pipe_width.to_int()
      let gap_top = (pipe.gap_y - game.gap_size / 2.0).to_int()
      let gap_bottom = (pipe.gap_y + game.gap_size / 2.0).to_int()
      @raylib.draw_rectangle(px, 0, pw, gap_top, @raylib.darkgreen)
      @raylib.draw_rectangle(
      px,
      gap_bottom,
      pw,
      @raylib.get_screen_height() - gap_bottom,
      @raylib.darkgreen,
      )
      }
      @raylib.draw_circle_v(
      @raylib.Vector2::new(game.bird_x, game.bird.y),
      game.bird_radius,
      @raylib.yellow,
      )
      @raylib.end_drawing()
      }

      先畫水管再畫小鳥,確保小鳥總在最上層。所有繪圖調用必須在 begin_drawing() 和 end_drawing() 之間。

      輔助函數和初始化邏輯:

      ///|
      fn random_gap_y(game : Game) -> Float {
      Float::from_int(
      @raylib.get_random_value(
      (game.gap_size / 2.0 + 50.0).to_int(),
      (game.sh - game.gap_size / 2.0 - 50.0).to_int(),
      ),
      )
      }


      ///|
      fn reset(game : Game) -> Unit {
      game.bird.y = game.sh / 2.0
      game.bird.velocity = 0.0
      game.score = 0
      game.game_over = false
      for i in 0..
      game.pipes[i].x = game.sw + Float::from_int(i) * game.pipe_spacing
      game.pipes[i].gap_y = random_gap_y(game)
      game.pipes[i].scored = false
      }
      }

      最后, main 將一切連接起來:

      ///|
      fn main {
      @raylib.init_window(0, 0, "Flappy Bird")
      @raylib.set_target_fps(60)
      @raylib.set_exit_key(0)
      letsw = Float::from_int(@raylib.get_screen_width())
      letsh = Float::from_int(@raylib.get_screen_height())

      let game : Game = {
      sw,
      sh,
      bird_x: sw * 0.2,
      bird: { y: 0.0, velocity: 0.0 },
      bird_radius:sh / 25.0,
      gravity: sh * 1.5,
      jump_force: sh * -0.65,
      pipes: Array::make(4, fn() { { x: 0.0, gap_y: 0.0, scored: false } }),
      pipe_width: sw / 8.0,
      gap_size: sh / 4.0,
      pipe_speed: sw * 0.4,
      pipe_spacing:sw / 2.5,
      score: 0,
      game_over: false,
      }
      reset(game)

      while not(@raylib.window_should_close()) {
      let dt = @raylib.get_frame_time()
      update(game, dt)
      draw(game)
      }
      @raylib.close_window()
      }

      init_window(0, 0, ...) 表示使用屏幕全尺寸——在 Android 上就是全屏。游戲循環本身只有三行:獲取 dt、更新、繪制。 is_gesture_detected(GestureTap) 同時響應觸屏和鼠標點擊,可以在桌面開發測試后無縫部署到手機。

      構建并部署:

      cd MyFlappyBird
      ./gradlew assembleDebug --no-daemon
      adb install -r app/build/outputs/apk/debug/app-debug.apk


      重力、水管、碰撞檢測、計分、游戲結束和重啟——全在一個文件、約 200 行代碼里。沒有引擎,沒有運行時,沒有框架。

      五 、總結與展望

      讓我們回顧一下整個技術脈絡。

      我們從一個簡單的問題出發: 一個休閑小游戲,真的需要一個完整的游戲引擎嗎? 然后沿著"從重到輕"的路徑,審視了移動游戲開發的幾種技術選型——從引擎(Unity/Godot)到跨平臺框架,再到原生 NDK,最終到達 MoonBit + Raylib 這個極簡組合。

      在構建鏈路層面,我們看到 MoonBit 編譯到 C、C 通過 NDK 編譯到 .so 、 .so 打包進 APK 的清晰路徑——每一步都是確定性的,沒有黑箱。

      在游戲架構層面,我們理解了游戲循環這個"所有游戲的共同骨架",以及為什么 update/draw 分離、幀率無關的物理模擬是重要的設計原則。

      在具體實現層面,我們用約 200 行代碼構建了一個完整的 Flappy Bird,其中涉及了對象回收(窮人版對象池)和 AABB 碰撞檢測等實用技巧。

      這套方案不是萬能的。如果你需要 3D 渲染管線、物理引擎、骨骼動畫、熱更新——使用 Unity 或 Godot 仍然是更務實的選擇。但如果你的目標是一款輕量的 2D 游戲,追求的是 小包體、高性能、完全可控的代碼 ,那么"做減法"的思路值得一試。

      這里有一些可以繼續探索的方向:

      • tonyfettes/raylib —— MoonBit 的 Raylib 綁定庫,涵蓋圖形、紋理、音頻、3D 模型、著色器等完整功能

      • selene —— 一個用 MoonBit 編寫的實驗性游戲引擎,支持 WebGPU 和 Raylib 后端,專為網頁和原生游戲設計

      • MoonBit 文檔 —— 語言詳細文檔

      另外值得注意一點的是,本文中所有示例代碼均由 AI 生成,甚至包括 Raylib 綁定庫本身。我們利用 AI Agent 的 Subagent 并行化地在桌面、Web 和 Android 平臺上產出了超過 150 款游戲。更多詳情可參見 tonyfettes/raylib 下的 examples/ 目錄。

      從 Unity 的"給你一切"到 MoonBit + Raylib 的"只給你需要的",這不僅是技術選型的變化,更是一種開發哲學的轉變—— 最好的代碼不是寫出來的,而是不需要寫的 。

      特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

      Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

      相關推薦
      熱點推薦
      港媒:中國高鐵快被“糞便淹沒”!若不處理后果嚴重,是真的嗎?

      港媒:中國高鐵快被“糞便淹沒”!若不處理后果嚴重,是真的嗎?

      奇思妙想生活家
      2026-03-12 13:12:18
      伊朗媒體:伊朗不會放棄參加世界杯,但FIFA和美國政府必須保證球隊安全

      伊朗媒體:伊朗不會放棄參加世界杯,但FIFA和美國政府必須保證球隊安全

      懂球帝
      2026-03-12 18:20:05
      國乒小將擊敗世界第二,慶祝引對手情緒失控舉動夸張

      國乒小將擊敗世界第二,慶祝引對手情緒失控舉動夸張

      老糿尾聲體育解說
      2026-03-13 00:03:36
      穆杰塔巴當選伊朗新任最高領袖,革命衛隊壓倒了教士集團?

      穆杰塔巴當選伊朗新任最高領袖,革命衛隊壓倒了教士集團?

      合贊歷史
      2026-03-12 13:32:47
      56歲大媽心梗離世,醫生:吃他汀時除了牛奶,這6種食物盡量少碰

      56歲大媽心梗離世,醫生:吃他汀時除了牛奶,這6種食物盡量少碰

      岐黃傳人孫大夫
      2026-02-28 22:15:03
      10萬億窟窿!比恒大更坑的民企來了,曾力壓許家印,位居第一

      10萬億窟窿!比恒大更坑的民企來了,曾力壓許家印,位居第一

      孤單是寂寞的毒
      2026-03-04 15:38:03
      離開廣州后才敢坦白:廣州,遠比你想象中更厲害!

      離開廣州后才敢坦白:廣州,遠比你想象中更厲害!

      吃貨的分享
      2026-03-12 18:48:43
      新冠后遺癥對人體的最大影響,很多人深受其害,有些人還不自知

      新冠后遺癥對人體的最大影響,很多人深受其害,有些人還不自知

      呼吸科大夫胡洋
      2026-02-22 11:39:12
      如果地球只有1.5厘米,按比例縮小的宇宙有多大?

      如果地球只有1.5厘米,按比例縮小的宇宙有多大?

      心中的麥田
      2026-03-12 18:58:33
      小紅書自然流已經死了……

      小紅書自然流已經死了……

      蔡汶川
      2026-03-12 10:39:19
      莫言告誡:家里越是干凈到極致的人,晚年往往逃不過這3種凄涼

      莫言告誡:家里越是干凈到極致的人,晚年往往逃不過這3種凄涼

      王二哥老搞笑
      2026-03-12 06:58:26
      別人送你這3樣東西,多半是瞧不起你、不尊重你,直接拒絕為好

      別人送你這3樣東西,多半是瞧不起你、不尊重你,直接拒絕為好

      陌上桃花開的
      2026-03-10 13:01:11
      霍華德生涯榮譽:1次總冠軍,8次入選全明星,3次當選DPOY

      霍華德生涯榮譽:1次總冠軍,8次入選全明星,3次當選DPOY

      懂球帝
      2026-03-13 03:20:05
      青島老板造出堅果王國,年營收破10億,IPO終止后如何突圍?

      青島老板造出堅果王國,年營收破10億,IPO終止后如何突圍?

      山東財經報道
      2026-03-12 16:51:43
      偶像女團出身!偶像系核彈!美園和花成業界“拼命三娘”

      偶像女團出身!偶像系核彈!美園和花成業界“拼命三娘”

      碧波萬覽
      2026-03-13 01:00:05
      震驚!網傳50%已婚男人活成老婆的供養血包者,網友:至少90%吧

      震驚!網傳50%已婚男人活成老婆的供養血包者,網友:至少90%吧

      火山詩話
      2026-03-10 15:39:53
      女航天員王亞平,因工作常年沒回家,和丈夫的關系一句話道出真相

      女航天員王亞平,因工作常年沒回家,和丈夫的關系一句話道出真相

      掉了顆大白兔糖
      2026-02-25 07:07:28
      美國先遣隊已離京!中方很不“滿意”,特朗普訪華行程大幅縮水?

      美國先遣隊已離京!中方很不“滿意”,特朗普訪華行程大幅縮水?

      他想要很多很多的夢
      2026-03-13 03:09:08
      若臺海爆發戰事,我軍可能面臨一個大麻煩:打不掉臺軍的指揮系統

      若臺海爆發戰事,我軍可能面臨一個大麻煩:打不掉臺軍的指揮系統

      健身狂人
      2026-03-13 03:53:22
      男演員深夜發裸露半身視頻,配文“開心的晚上沒有公司的管束”!引發熱議后火速刪除

      男演員深夜發裸露半身視頻,配文“開心的晚上沒有公司的管束”!引發熱議后火速刪除

      深圳晚報
      2026-03-12 12:25:38
      2026-03-13 05:32:49
      開源中國 incentive-icons
      開源中國
      每天為開發者推送最新技術資訊
      7614文章數 34506關注度
      往期回顧 全部

      游戲要聞

      《約翰·卡朋特的毒液突擊隊》評測:期望越大,失望越大"/> 主站 商城 論壇 自運營 登錄 注冊 《約翰·卡朋特的毒液突擊隊》評測:期望越大,失望越大 ...

      頭條要聞

      伊朗:特朗普幾條推文結束不了戰爭

      頭條要聞

      伊朗:特朗普幾條推文結束不了戰爭

      體育要聞

      建議將“出球型門將”納入反詐app

      娛樂要聞

      貝克漢姆全家給27歲大布送生日祝福

      財經要聞

      盧鋒:從特朗普團隊群演看時代變局

      科技要聞

      當養蝦人開始卸載,大廠的戰爭才真正開始

      汽車要聞

      大眾2025財報:轉型雖有陣痛 "大象"已然起跑

      態度原創

      藝術
      房產
      旅游
      手機
      公開課

      藝術要聞

      深圳能源大廈,“看得我強迫癥都要犯了”

      房產要聞

      唏噓!三亞又一房企巨頭破產,狂欠43億甩賣資產!

      旅游要聞

      春假去哪玩?南京文旅向長三角家庭發出“串門”邀約

      手機要聞

      榮耀Magic9標準版曝光:潛望鏡+無線充+超聲波指紋,仍沒有3D人臉

      公開課

      李玫瑾:為什么性格比能力更重要?

      無障礙瀏覽 進入關懷版