-
Notifications
You must be signed in to change notification settings - Fork 14
/
db.json
1 lines (1 loc) · 802 KB
/
db.json
1
{"meta":{"version":1,"warehouse":"4.0.2"},"models":{"Asset":[{"_id":"source/images/avatar.png","path":"images/avatar.png","modified":0,"renderable":0},{"_id":"node_modules/hexo-theme-icarus/source/css/cyberpunk.styl","path":"css/cyberpunk.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/css/default.styl","path":"css/default.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/css/style.styl","path":"css/style.styl","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/avatar.png","path":"img/avatar.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/logo.svg","path":"img/logo.svg","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/favicon.svg","path":"img/favicon.svg","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/og_image.png","path":"img/og_image.png","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/razor-bottom-black.svg","path":"img/razor-bottom-black.svg","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/img/razor-top-black.svg","path":"img/razor-top-black.svg","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/js/animation.js","path":"js/animation.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/js/back_to_top.js","path":"js/back_to_top.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/js/column.js","path":"js/column.js","modified":0,"renderable":1},{"_id":"node_modules/hexo-theme-icarus/source/js/main.js","path":"js/main.js","modified":0,"renderable":1}],"Cache":[{"_id":"source/_posts/About.md","hash":"f3a67be02706a4f2f7af12c4a137693efd7c17dd","modified":1718003655483},{"_id":"source/images/avatar.png","hash":"b8138053a7035cc574944d73c1d804e0eecca8eb","modified":1716816559360},{"_id":"node_modules/hexo-theme-icarus/layout/comment/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709523},{"_id":"node_modules/hexo-theme-icarus/layout/donate/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709543},{"_id":"node_modules/hexo-theme-icarus/layout/misc/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709556},{"_id":"node_modules/hexo-theme-icarus/layout/search/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709570},{"_id":"node_modules/hexo-theme-icarus/layout/share/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709583},{"_id":"node_modules/hexo-theme-icarus/include/schema/comment/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709263},{"_id":"node_modules/hexo-theme-icarus/include/schema/donate/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709351},{"_id":"node_modules/hexo-theme-icarus/include/schema/misc/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709427},{"_id":"node_modules/hexo-theme-icarus/include/schema/search/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709473},{"_id":"node_modules/hexo-theme-icarus/include/schema/share/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1701013709507},{"_id":"node_modules/hexo-theme-icarus/README.md","hash":"32f9f4fc8cd7ec60b30544bd2e558b593519ae5d","modified":1701013709793},{"_id":"node_modules/hexo-theme-icarus/CONTRIBUTING.md","hash":"70254c6778c1e41bb2ff222bbf3a70b2239b9bc1","modified":1701013709791},{"_id":"node_modules/hexo-theme-icarus/LICENSE","hash":"86037e5335a49321fa73b7815cab542057fac944","modified":1701013709590},{"_id":"node_modules/hexo-theme-icarus/package.json","hash":"75db783b805785377db28d4cb844ee65bb7be613","modified":1701013709704},{"_id":"node_modules/hexo-theme-icarus/include/config.js","hash":"1ff0f174e9670074ad2bee890d5b6da486800c9a","modified":1701013709620},{"_id":"node_modules/hexo-theme-icarus/include/dependency.js","hash":"0ca35dec92ccf383f45db905db1a5a0e92d7209e","modified":1701013709629},{"_id":"node_modules/hexo-theme-icarus/include/register.js","hash":"ec6596b63bfb4349ba61792d905abe8e06fea625","modified":1701013709651},{"_id":"node_modules/hexo-theme-icarus/languages/es.yml","hash":"38579b8fad4b6997362acc770615bcd85ff20f68","modified":1701013709860},{"_id":"node_modules/hexo-theme-icarus/languages/id.yml","hash":"5e48b1d62378cadeb64b88349477726a5c1bae47","modified":1701013709864},{"_id":"node_modules/hexo-theme-icarus/languages/de.yml","hash":"78421f09961ca0b24756a0688fb2cb2e2696e25f","modified":1701013709856},{"_id":"node_modules/hexo-theme-icarus/languages/en.yml","hash":"3d674204d9f723c829226da745afddd180c1131d","modified":1701013709858},{"_id":"node_modules/hexo-theme-icarus/languages/fr.yml","hash":"06d5c819d6108a42b28cff7b52e5410d0bed55d1","modified":1701013709862},{"_id":"node_modules/hexo-theme-icarus/languages/pl.yml","hash":"2e7debb44cd91096f30efc87bf8d6b1d0d0214c9","modified":1701013709870},{"_id":"node_modules/hexo-theme-icarus/languages/ko.yml","hash":"e3374265377809c1518114cf352b595840c0b416","modified":1701013709868},{"_id":"node_modules/hexo-theme-icarus/languages/pt-BR.yml","hash":"ee8f73350e4c6e2f63b7fc72b34472a6b1e21244","modified":1701013709872},{"_id":"node_modules/hexo-theme-icarus/languages/ru.yml","hash":"9d91358c2acbe7a0f2a25daf7f65b999ff32d068","modified":1701013709874},{"_id":"node_modules/hexo-theme-icarus/languages/ja.yml","hash":"801d9930fef48d6a3f80470d5bed4f3eb78147e6","modified":1701013709866},{"_id":"node_modules/hexo-theme-icarus/languages/tr.yml","hash":"dd0a7bfe14848d6e1aa229198fe1db03e08e305e","modified":1701013709878},{"_id":"node_modules/hexo-theme-icarus/languages/tk.yml","hash":"ca583168bd2025124a1cd0e977da475d7a7496fd","modified":1701013709876},{"_id":"node_modules/hexo-theme-icarus/layout/archive.jsx","hash":"99bf235042d0c57af15d2f108ba5eda77443fea8","modified":1701013709736},{"_id":"node_modules/hexo-theme-icarus/languages/zh-TW.yml","hash":"a6826e0c8cdb9ad286324b682b466a9e2ad78e6f","modified":1701013709885},{"_id":"node_modules/hexo-theme-icarus/languages/vn.yml","hash":"5f2fffa642110c81d8f529949711c9d19ad6bbbe","modified":1701013709880},{"_id":"node_modules/hexo-theme-icarus/languages/zh-CN.yml","hash":"02475ba14afc70dfeaf5678467cee307835e4efa","modified":1701013709882},{"_id":"node_modules/hexo-theme-icarus/layout/category.jsx","hash":"fd15e4eac32de9ac8687aeb3dbe179ab61375700","modified":1701013709748},{"_id":"node_modules/hexo-theme-icarus/layout/categories.jsx","hash":"b8ad43e28a4990d222bfbb95b032f88555492347","modified":1701013709745},{"_id":"node_modules/hexo-theme-icarus/layout/page.jsx","hash":"d26c2db57e5a88d6483a03aeb51cda9d191d8cea","modified":1701013709768},{"_id":"node_modules/hexo-theme-icarus/layout/layout.jsx","hash":"ac7c4e3465a116c7f05f8c2e09ee6d6b9467abf1","modified":1701013709763},{"_id":"node_modules/hexo-theme-icarus/layout/index.jsx","hash":"0a84a2348394fa9fc5080dd396bd28d357594f47","modified":1701013709761},{"_id":"node_modules/hexo-theme-icarus/layout/post.jsx","hash":"d26c2db57e5a88d6483a03aeb51cda9d191d8cea","modified":1701013709773},{"_id":"node_modules/hexo-theme-icarus/layout/tag.jsx","hash":"d2f18cac32ca2725d34ccff3f2051c623be6c892","modified":1701013709784},{"_id":"node_modules/hexo-theme-icarus/scripts/index.js","hash":"0c666db6fcb4ffc4d300f4e108c00ee42b1cbbe6","modified":1701013709641},{"_id":"node_modules/hexo-theme-icarus/layout/tags.jsx","hash":"2c42cb64778235dd220c563a27a92108ddc50cc4","modified":1701013709786},{"_id":"node_modules/hexo-theme-icarus/include/schema/config.json","hash":"f233678cd656c0e300181ca79dd30cb42fc213b3","modified":1701013709687},{"_id":"node_modules/hexo-theme-icarus/include/migration/head.js","hash":"7189efe33d18927d3790e8afb06642fb293b8603","modified":1701013709634},{"_id":"node_modules/hexo-theme-icarus/include/migration/v2_v3.js","hash":"3ccb2d2ce11018bebd7172da66faecc3983bff00","modified":1701013709655},{"_id":"node_modules/hexo-theme-icarus/include/style/article.styl","hash":"105c983871b6c9148d97a0f756886e56411572bd","modified":1701013709803},{"_id":"node_modules/hexo-theme-icarus/include/style/base.styl","hash":"2bca6ad099949d52236c87db8db1002ffb99774c","modified":1701013709806},{"_id":"node_modules/hexo-theme-icarus/include/style/card.styl","hash":"f78674422eb408cd17c17bbdc3ee1ebe4a453e05","modified":1701013709811},{"_id":"node_modules/hexo-theme-icarus/include/style/button.styl","hash":"0fb35b4786be1b387c751fa2849bc71523fcedd4","modified":1701013709809},{"_id":"node_modules/hexo-theme-icarus/include/style/codeblock.styl","hash":"ec54dc24eb4d9802d8fefc44c210558bc1641109","modified":1701013709815},{"_id":"node_modules/hexo-theme-icarus/include/style/donate.styl","hash":"8d0af00628c13134b5f30a558608e7bebf18c2ec","modified":1701013709825},{"_id":"node_modules/hexo-theme-icarus/include/migration/v3_v4.js","hash":"9faf2184d7fe87debfbe007f3fc9079dcbcafcfe","modified":1701013709658},{"_id":"node_modules/hexo-theme-icarus/include/style/helper.styl","hash":"9f3393e6122cc9f351091bfab960674e962da343","modified":1701013709830},{"_id":"node_modules/hexo-theme-icarus/include/migration/v4_v5.js","hash":"6342310892d113763b5544789b45d44c0ccf2854","modified":1701013709661},{"_id":"node_modules/hexo-theme-icarus/include/style/footer.styl","hash":"a4ad715dee38b249538ac6cce94efc9b355a904b","modified":1701013709827},{"_id":"node_modules/hexo-theme-icarus/include/style/pagination.styl","hash":"b81bcd7ff915b4e9299533addc01bc4575ec35e3","modified":1701013709835},{"_id":"node_modules/hexo-theme-icarus/include/style/navbar.styl","hash":"34f09b144cb46a25ec2cc7260a6c207dd34ff1fe","modified":1701013709832},{"_id":"node_modules/hexo-theme-icarus/include/migration/v5_v5.1.js","hash":"073f22bd16e34b56f016633b1676dab2e7d8843d","modified":1701013709664},{"_id":"node_modules/hexo-theme-icarus/include/style/plugin.styl","hash":"084843d5a522029e0f84a4fe791fbcb2cabd4c36","modified":1701013709837},{"_id":"node_modules/hexo-theme-icarus/include/util/console.js","hash":"59cf9d277d3ac85a496689bd811b1c316001641d","modified":1701013709625},{"_id":"node_modules/hexo-theme-icarus/include/style/responsive.styl","hash":"207083fe287612cddee6608b541861b14ac8de81","modified":1701013709839},{"_id":"node_modules/hexo-theme-icarus/include/style/search.styl","hash":"416737e1da4e7e907bd03609b0fee9e2aacfe56c","modified":1701013709841},{"_id":"node_modules/hexo-theme-icarus/include/style/widget.styl","hash":"c746902251136544eb3fe523235b3183f4189460","modified":1701013709847},{"_id":"node_modules/hexo-theme-icarus/layout/common/article.jsx","hash":"1d06eee32ea1fcb3162227eb1d7d19be39b6f5e3","modified":1701013709740},{"_id":"node_modules/hexo-theme-icarus/include/style/timeline.styl","hash":"ea61798a09bffdda07efb93c2ff800b63bddc4c4","modified":1701013709845},{"_id":"node_modules/hexo-theme-icarus/layout/common/donates.jsx","hash":"889fb0a7ccc502f0a43b4a18eb330e351e50493c","modified":1701013709753},{"_id":"node_modules/hexo-theme-icarus/layout/common/head.jsx","hash":"2ec1f511f32e3a9c86d49f1338f57ae5ece18898","modified":1701013709759},{"_id":"node_modules/hexo-theme-icarus/layout/common/comment.jsx","hash":"427089c33002707b76e2f38709459a6824fd0f9b","modified":1701013709750},{"_id":"node_modules/hexo-theme-icarus/layout/common/footer.jsx","hash":"de966666f1e4ef80e0d15081b2709c3065b246dd","modified":1701013709756},{"_id":"node_modules/hexo-theme-icarus/layout/common/navbar.jsx","hash":"d96e501e52861056474659f96ee0206588d8c93a","modified":1701013709766},{"_id":"node_modules/hexo-theme-icarus/layout/common/scripts.jsx","hash":"4816c9099a881b5f7b13af3e42caae36edbffccd","modified":1701013709778},{"_id":"node_modules/hexo-theme-icarus/layout/common/plugins.jsx","hash":"f6826c1a5f5f59f4a0aa00c63bdb0ad4ff4eab69","modified":1701013709770},{"_id":"node_modules/hexo-theme-icarus/layout/common/search.jsx","hash":"6f244a37293031670a2964fe424ecd062e591d7b","modified":1701013709780},{"_id":"node_modules/hexo-theme-icarus/layout/common/widgets.jsx","hash":"251263b97de12f2b8d1fce2514e83430f2515b94","modified":1701013709789},{"_id":"node_modules/hexo-theme-icarus/layout/common/share.jsx","hash":"c9fb0319ad5e5a10ad3636b26a6c2afed14c590f","modified":1701013709782},{"_id":"node_modules/hexo-theme-icarus/source/css/cyberpunk.styl","hash":"ae17d3528df0c3f089df14a06b7bd82f1bc5fed9","modified":1701013709821},{"_id":"node_modules/hexo-theme-icarus/layout/plugin/back_to_top.jsx","hash":"7fc0c5aaabd7d0eaff04cb68ec139442dc3414e8","modified":1701013709743},{"_id":"node_modules/hexo-theme-icarus/source/css/default.styl","hash":"b01da3028e5a1267a40aaae5c86a11187a2259e3","modified":1701013709823},{"_id":"node_modules/hexo-theme-icarus/layout/plugin/animejs.jsx","hash":"e2aa27c3501a58ef1e91e511557b77395c2c02aa","modified":1701013709732},{"_id":"node_modules/hexo-theme-icarus/source/css/style.styl","hash":"5b9815586e993a6ccbe8cdcfc0c65ea38fc315ac","modified":1701013709843},{"_id":"node_modules/hexo-theme-icarus/source/img/avatar.png","hash":"0d8236dcca871735500e9d06bbdbe0853ed6775b","modified":1701013709796},{"_id":"node_modules/hexo-theme-icarus/source/img/logo.svg","hash":"e9b5c1438ddb576693a15d0713b2a1d9ceda4be9","modified":1701013709851},{"_id":"node_modules/hexo-theme-icarus/source/img/favicon.svg","hash":"16fd847265845063a16596761cddb32926073dd2","modified":1701013709849},{"_id":"node_modules/hexo-theme-icarus/layout/widget/profile.jsx","hash":"0d3a7fd922c12cc45d2c8d26a8f4d3a9a6ed0ae0","modified":1701013709776},{"_id":"node_modules/hexo-theme-icarus/source/img/razor-bottom-black.svg","hash":"a3eda07b1c605b456da9cdf335a1075db5e5d72c","modified":1701013709853},{"_id":"node_modules/hexo-theme-icarus/source/img/og_image.png","hash":"b03f163096ca9c350ec962feee9836277b5c2509","modified":1701013709800},{"_id":"node_modules/hexo-theme-icarus/source/img/razor-top-black.svg","hash":"201f1171a43ce667a39091fe47c0f278857f18f0","modified":1701013709854},{"_id":"node_modules/hexo-theme-icarus/source/js/animation.js","hash":"0a8e361c353daa3194f4de3d646b96025d128e1a","modified":1701013709601},{"_id":"node_modules/hexo-theme-icarus/source/js/back_to_top.js","hash":"d91f10c08c726135a13dfa1f422c49d8764ef03f","modified":1701013709607},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/article.json","hash":"e2502c39045c6a26ccd8e880858f93e78c7bda35","modified":1701013709676},{"_id":"node_modules/hexo-theme-icarus/source/js/column.js","hash":"0baee024ab67474c073a4c41b495f3e7f0df4505","modified":1701013709613},{"_id":"node_modules/hexo-theme-icarus/source/js/main.js","hash":"08a2641765eeaf712157ad134dd675e3f7708ae2","modified":1701013709647},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/comment.json","hash":"f49270b619f5d2c3decde6b0b5a0c3bbab4b54a5","modified":1701013709682},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/donates.json","hash":"ae86e6f177bedf4afbe638502c12635027539305","modified":1701013709690},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/navbar.json","hash":"6691e587284c4cf450e0288680d5ff0f3565f090","modified":1701013709701},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/plugins.json","hash":"6036a805749816416850d944f7d64aaae62e5e75","modified":1701013709707},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/footer.json","hash":"e85c9d7f2579805beb252a1b6345d5a668a13baa","modified":1701013709693},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/head.json","hash":"98889f059c635e6bdbd51effd04cf1cf44968a66","modified":1701013709697},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/providers.json","hash":"97ec953d497fb53594227ae98acaef8a8baa91da","modified":1701013709713},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/search.json","hash":"985fbcbf47054af714ead1a124869d54f2a8b607","modified":1701013709716},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/share.json","hash":"cf4f9ff4fb27c3541b35f57db355c228fa6873e4","modified":1701013709719},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/sidebar.json","hash":"eb241beaec4c73e3085dfb3139ce72e827e20549","modified":1701013709723},{"_id":"node_modules/hexo-theme-icarus/include/schema/common/widgets.json","hash":"cadd9dc942740ecd5037d3943e72f8b6a8399bbe","modified":1701013709726},{"_id":"node_modules/hexo-theme-icarus/include/schema/plugin/animejs.json","hash":"e62ab6e20bd8862efa1ed32e7c0db0f8acbcfdec","modified":1701013709669},{"_id":"node_modules/hexo-theme-icarus/include/schema/plugin/back_to_top.json","hash":"dc0febab7e7b67075d0ad3f80f5ec8b798b68dea","modified":1701013709679},{"_id":"node_modules/hexo-theme-icarus/include/schema/widget/profile.json","hash":"690ee1b0791cab47ea03cf42b5b4932ed2aa5675","modified":1701013709710},{"_id":"source/_posts/Demo/HelloWorld.md","hash":"6c6f85dae8efcce4790b01f14090ee9015a7a36f","modified":1718003655483},{"_id":"source/_posts/Flaaax/test.md","hash":"ca3e97582834612f20d11ffd74ee0a0a54c9eba4","modified":1718003655483},{"_id":"source/_posts/FlyingfishFantasticfan/git的使用学习.md","hash":"5c09a0cf214b0be4eb13a923dedba8f91137c2b8","modified":1718003655483},{"_id":"source/_posts/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性.md","hash":"d182ca4df4c86203af8f50a6676951506ee33125","modified":1718003655483},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌.md","hash":"85ca09f8fe5bb8211026418b63e85a3a51976bd5","modified":1718003367936},{"_id":"source/_posts/Touyouta/Demo.md","hash":"6e989ca1e21d201240c5367b26415df3099d8043","modified":1718003655562},{"_id":"source/_posts/QiNuoTu/Camera2D.md","hash":"7c46aeeff04f88a786da3f1023775682d0c8fcea","modified":1718003655483},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased.md","hash":"c24978343e46a6f31bc2c05922b8f5ac9af5ab24","modified":1718003655499},{"_id":"source/_posts/QiNuoTu/Iamme.md","hash":"298389e336d92f6a30ae133202f36d4477eaac95","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/OpenEasing.md","hash":"4014cc642e8727078f40fb91f85bc3984607fc0a","modified":1718003655546},{"_id":"source/_posts/QiNuoTu/一些包围盒类碰撞检测算法.md","hash":"15eb29a88bb83967f1b6cfb0fa684a11c52e72c0","modified":1718003655562},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践.md","hash":"da7836b91c6a1d2cb93254e1d360bc8ea91a1348","modified":1718003655562},{"_id":"source/_posts/XINDENG123456/self-introduction.md","hash":"819262500746ed2ea47f2bbda853c44706fe5f47","modified":1718003655609},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一).md","hash":"ddf65411bca78cc8c3ba7d9b2ffc6212a0447b0a","modified":1718003655593},{"_id":"source/_posts/Ye Minglv/植物明星大乱斗系列视频——勘误.md","hash":"3134e2aaaba9b3952aef717d531351e9b987c084","modified":1718003655609},{"_id":"source/_posts/YoungFlame/测试.md","hash":"a8bbaf4b0f0f3e132b6e7f6566c1b916b07554f2","modified":1718003655609},{"_id":"source/_posts/shuo-liu16/deploy-Hexo-2024-04-10.md","hash":"69bcbcefdf496d8cbf17faf95185c25ba7afc39b","modified":1718003655609},{"_id":"source/_posts/hszSoft/hello.md","hash":"e381200254403f5f6cb3690854a2ff8033105fc6","modified":1718003655609},{"_id":"source/_posts/suang/Aboutme.md","hash":"4bf109bc2a44010b59221574bfd3381cb1f424b5","modified":1718003655609},{"_id":"source/_posts/suang/EasyX_code.md","hash":"d8418d830d32f2ab93826091eae829a5f53058ff","modified":1718003655609},{"_id":"source/_posts/suang/publish_article.md","hash":"c4405b7c631531917a798a8da745ff43cbd1d60c","modified":1718003655609},{"_id":"source/_posts/yang/奥日与萤火意志2.md","hash":"f500d11c4b4cf4e340adf202380f24a8156295cb","modified":1718003655609},{"_id":"source/_posts/zExNocs/自我介绍.md","hash":"3f41e3ce3abb6765e3c01dbbfe9493911425d445","modified":1718003655609},{"_id":"source/_posts/Demo/HelloWorld/avatar.png","hash":"b8138053a7035cc574944d73c1d804e0eecca8eb","modified":1718003655483},{"_id":"source/_posts/zExNocs/随笔-如何提交文章到VoidGameSpace上.md","hash":"5be92913c3c96c28d6ad056d3978db50362ed42c","modified":1718003655609},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Blue_Joker.webp","hash":"f6745cc28248111b1cab499f7be9adbd42449ccc","modified":1717996375794},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Cavendish.webp","hash":"3e70ce4a2f84b90aaaadc07005599fb57c1eec05","modified":1717996481255},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Four_Fingers.webp","hash":"fa1eb1282d70090f7823f5548a74aa050154ec34","modified":1717996776558},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Golden_Joker.webp","hash":"78ba5a7ef0b003bfd73e760e6965fa40cbeb746c","modified":1717996666856},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Joker.webp","hash":"b3e379d991386f196056db261390a0482955c63e","modified":1717952859029},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Photograph.webp","hash":"d60103bbd1278b130d193d10172fd848bc5f777f","modified":1717999900670},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Smiley_Face.webp","hash":"2cd9d77f597467511a9a28ec636cf8741600c5b9","modified":1717999918507},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Hanging_Chad.webp","hash":"5f4bcb823455c57cf8398f96ee774f81de3997dc","modified":1717999932084},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/四指同花顺.png","hash":"90925427835740bf04868fa3a6c1dca2d999d283","modified":1717999109507},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/10.png","hash":"d55489ccf925b67369d68c26c5505239e8709f59","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/11.png","hash":"1ba80d4165fc370c705c1a39eee035a4f1b8119f","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/12.png","hash":"52fe1b85ee90d51fc5dffb06d3a83314ccc939b7","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/13.png","hash":"963b03eeddbc0e15d4e337aa1cfe90ed2170aa7c","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/14.png","hash":"18b75a590c32e3295456696d6fb5691e4ecd4615","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/16.png","hash":"8c2cafc02d8b957265894f0493e9710886a38b6a","modified":1718003655530},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/17.png","hash":"4b1781e1faf1e6e25b5eb3353c23ea824b6780aa","modified":1718003655530},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/20.png","hash":"9814939b228987d8ba9da37409431d262e5cce1a","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/21.png","hash":"5d962b0fff964d83b6982eb634932b65aa37bb68","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/26.png","hash":"f7075d0a8c4dbef5500b0cd12546123b14228036","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/28.png","hash":"f69cf6216941ce4f49a883880658d3729a083629","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/27.png","hash":"ed07e7793fd939792896afdaf360193b68f8dada","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/5.png","hash":"16cad4bfb0cef630fe9d04cfe1d84421ed8f9c6f","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/8.png","hash":"a8f89f4b96fc815606893b517b9df8f42d03b0ac","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/9.png","hash":"944b36b8abe71940c121cb3bc079b73340cc8e67","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/Iamme/1.jpg","hash":"295c008c11894b91f3d99e0dae846a525ac6393b","modified":1718003655546},{"_id":"source/_posts/YoungFlame/img/avatar.png","hash":"b8138053a7035cc574944d73c1d804e0eecca8eb","modified":1718003655609},{"_id":"source/_posts/shuo-liu16/deploy-Hexo-2024-04-10/2.png","hash":"d1d02bc974c1f8bdd0a39744afaa2badbf78fc13","modified":1718003655609},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/151655416259069.png","hash":"9516c3ce63a8d37662ebc4cfd107e541d724a41c","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/87331419268747.png","hash":"561a836ac933a90c5899ba7fa4442b270b67e239","modified":1718003655609},{"_id":"source/_posts/suang/Aboutme/who_am_I.png","hash":"9504f232d8247506cd4c6589c8164b8c69d36139","modified":1718003655609},{"_id":"source/_posts/suang/publish_article/image_pos.png","hash":"4ee5912434f6a5f97bd3353b1663df9a45e8d940","modified":1718003655609},{"_id":"source/_posts/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/游戏设计知识分享-依赖性-1.png","hash":"af1ff967b389e3766771c3bf43ff23843edf3aad","modified":1718003655483},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/计分板.png","hash":"0674747aeccad06462ecae936370eb4b8bfe4f83","modified":1717995565205},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/15.png","hash":"41ae2aa085fc610ace55b82fe840d1f714793d71","modified":1718003655530},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/19.png","hash":"039ba395b921713c71166343aa52aea6a4185fa9","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/2.png","hash":"6b06814a55b8d717621d47b0f00312eb1340550a","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/22.png","hash":"621e14dd48159ace6a48417cb1276751dfc61b42","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/23.png","hash":"f11e21162dfbd1e294a163eaaca2cabaa88cb0c2","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/25.png","hash":"c624bff787f9aa36a7cc2bfd5d4e3bf2665015f7","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/3.png","hash":"7a6f4e0e72399aeba70112e4f34ebdaa70f017c6","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/4.png","hash":"7ac0253154d18f1a369b3f3620f6f04b84234102","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/7.png","hash":"f12c47d616df36b2cd93c2471caba8469ad34bf8","modified":1718003655531},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/231573721246935.png","hash":"816d686114823ca98711b8b64539298f50c8b6d0","modified":1718003655578},{"_id":"source/_posts/shuo-liu16/deploy-Hexo-2024-04-10/1.png","hash":"b40806b4dc4034f1f781fc1585f3e8fe9bfac94a","modified":1718003655609},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/202434217267102.png","hash":"2a4fbffdfe6984414c682f23f3ade033e6b83c94","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/59555018265066.png","hash":"d42019821f83eacecf869aa883e77f21a6454fa1","modified":1718003655593},{"_id":"source/_posts/suang/Aboutme/suang.png","hash":"88fea2975e0b0f08e317b3dd2ef746c33c97982a","modified":1718003655609},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/24.png","hash":"45f6974531ea6864ecd0e47c6daad8149266d245","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/6.png","hash":"2cf7630a9e1b1e61dc0ba97bdc8f937d5353f700","modified":1718003655531},{"_id":"source/_posts/QiNuoTu/OpenEasing/OpenEasing.png","hash":"a2a17fe92afd47f77aaed36abd6f2fefe819d674","modified":1718003655562},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/125364318267564.png","hash":"788ecd6ca06f378ab2ca4e3a738271d7b6651b67","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/161600919246307.png","hash":"161fe2736a677825a6f67777a30f9bb255d2ae06","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/532531818252080.png","hash":"90482f22ddbe2a7b3b9d45a314cf1308d6fa963d","modified":1718003655593},{"_id":"source/_posts/suang/publish_article/fork_img.png","hash":"89ecaa744302b6b8cc3f3a09088b6b76f8db84c4","modified":1718003655609},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/18.png","hash":"dbc64ce5efb6bd99dec6f83efbb24a9102b69e1b","modified":1718003655531},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/403754021267101.png","hash":"1691dcbc729a2d8c80f846407d932e19a12059bf","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/553721218256326.png","hash":"8a368b2de95d44c6eb61ec4654a1d1ab825e8d1f","modified":1718003655593},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/1.png","hash":"1a77c95f4114bd9c82ff5a9aa7f9d39b7126c32f","modified":1718003655515},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/338824221259770.gif","hash":"f9f5067d95a10cab5ae9cbea82b8ac5210e40491","modified":1718003655593},{"_id":"source/_posts/QiNuoTu/Camera2D/2.png","hash":"3d643ceea5414eb349e3db001222e3b9ad1c9203","modified":1718003655499},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/76072812230849.png","hash":"54c0937a8017653bcc1b9370fb3d30bd70e2ea91","modified":1718003655609},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/294884321256325.gif","hash":"7e4ad2a2df59f8a06b3d60a07254a83f1a37d71a","modified":1718003655593},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/101894421252079.gif","hash":"3808d32546b4ac49444352f8833287b2521869d1","modified":1718003655578},{"_id":"source/_posts/QiNuoTu/icon.png","hash":"5e446ec16d961293b49818471c01033869b50ae9","modified":1718003655562},{"_id":"source/_posts/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg","hash":"a9bda682885260f432b7b7da4302f17df6c44bfa","modified":1718003655562},{"_id":"source/_posts/QiNuoTu/Iamme/2.png","hash":"cb04ae1e7c3cd1f4aa9561ddaec48b6890ac4f56","modified":1718003655546},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/123415231.png","hash":"7447631caaa0fd561766aa39b8b14e6ec823a679","modified":1718003655515},{"_id":"source/_posts/QiNuoTu/Camera2D/1.gif","hash":"8e3b9a6ff03ed2f15570808729ff9703ff167130","modified":1718003655499}],"Category":[{"name":"Demo","_id":"clx8n2hg50001o8yea90f4i5q"},{"name":"Flaaax","_id":"clx8n2hg80006o8yeewzpfvxv"},{"name":"FlyingfishFantasticfan","_id":"clx8n2hg9000co8ye8gtq5k5g"},{"name":"Touyouta","_id":"clx8n2hgh000so8ye43vv9vin"},{"name":"QiNuoTu","_id":"clx8n2hgi0010o8ye3b0i5mnm"},{"name":"Voidmatrix","_id":"clx8n2hgo001ro8ye7h744ueg"},{"name":"XINDENG123456","_id":"clx8n2hgo001xo8ye589taadj"},{"name":"Ye Minglv","_id":"clx8n2hgp0026o8yegryw9g2u"},{"name":"YoungFlame","_id":"clx8n2hgp002bo8yegnfp6dcm"},{"name":"shuo-liu16","_id":"clx8n2hgq002eo8yefriq959i"},{"name":"hszSoft","_id":"clx8n2hgq002ho8ye2piw2uzd"},{"name":"suang","_id":"clx8n2hgr002lo8ye42fa681j"},{"name":"yang12342","_id":"clx8n2hgx003qo8yehj5hdmre"},{"name":"zExNocs","_id":"clx8n2hgy003uo8ye9xgm7r7i"}],"Data":[],"Page":[],"Post":[{"title":"欢迎来到 VoidGameSpace","date":"2024-05-26T16:00:00.000Z","updated":"2024-05-26T16:00:00.000Z","_content":"\n> VoidGameSpace 游戏开发社区博客","source":"_posts/About.md","raw":"---\ntitle: 欢迎来到 VoidGameSpace\ndate: 2024-05-27\nupdated: 2024-05-27\npermalink: about/\n---\n\n> VoidGameSpace 游戏开发社区博客","slug":"About","published":1,"__permalink":"about/","_id":"clwp1dg660000m0ut65gd3vqr","comments":1,"layout":"post","photos":[],"link":"","content":"<blockquote>\n<p>VoidGameSpace 游戏开发社区博客</p>\n</blockquote>\n","site":{"data":{}},"excerpt":"","more":"<blockquote>\n<p>VoidGameSpace 游戏开发社区博客</p>\n</blockquote>\n"},{"title":"你好,世界","date":"2024-05-26T16:00:00.000Z","updated":"2024-05-26T16:00:00.000Z","_content":"\n群友的一小步,游戏行业的一大步\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n![ICON](articles/Demo/HelloWorld/avatar.png)\n\n</div>","source":"_posts/Demo/HelloWorld.md","raw":"---\ntitle: 你好,世界\ndate: 2024-05-27\nupdated: 2024-05-27\npermalink: articles/Demo/HelloWorld/\ncategories: Demo\ntags: [游戏开发]\n---\n\n群友的一小步,游戏行业的一大步\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n![ICON](articles/Demo/HelloWorld/avatar.png)\n\n</div>","slug":"Demo/HelloWorld","published":1,"__permalink":"articles/Demo/HelloWorld/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg20000o8yegq8i0076","content":"<p>群友的一小步,游戏行业的一大步</p>\n<span id=\"more\"></span>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Demo/HelloWorld/avatar.png\" alt=\"ICON\"></p>\n</div>","site":{"data":{}},"excerpt":"<p>群友的一小步,游戏行业的一大步</p>","more":"<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Demo/HelloWorld/avatar.png\" alt=\"ICON\"></p>\n</div>"},{"title":"测试测试测试测试测试测试测试测试测试测试","date":"2024-05-27T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"\n测试测试测试测试测试\n---\ntitle: test\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/Flaaax/test/\ncategories: Flaaax\ntags: [test]\n---\n\n测试测试测试测试测试\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n测试,测试,测试,测试, 测试,测试,测试,测试,测试\n\n</div>\n\n# 测试测试测试测试测试\n## 测试测试测试测试测试\n### 测试测试测试测试测试\n#### 测试测试测试测试测试\n### 测试测试测试测试测试\n## 测试测试测试测试测试\n# 测试测试测试测试测试\n\n### 锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\n","source":"_posts/Flaaax/test.md","raw":"---\ntitle: 测试测试测试测试测试测试测试测试测试测试\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/Flaaax/test/\ncategories: Flaaax\ntags: [测试测试测试测试测试]\n---\n\n测试测试测试测试测试\n---\ntitle: test\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/Flaaax/test/\ncategories: Flaaax\ntags: [test]\n---\n\n测试测试测试测试测试\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n测试,测试,测试,测试, 测试,测试,测试,测试,测试\n\n</div>\n\n# 测试测试测试测试测试\n## 测试测试测试测试测试\n### 测试测试测试测试测试\n#### 测试测试测试测试测试\n### 测试测试测试测试测试\n## 测试测试测试测试测试\n# 测试测试测试测试测试\n\n### 锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\n","slug":"Flaaax/test","published":1,"__permalink":"articles/Flaaax/test/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg70003o8yeemdx6k4n","content":"<h2 id=\"测试测试测试测试测试\"><a href=\"#测试测试测试测试测试\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h2 id=\"title-testdate-2024-05-28updated-2024-05-28permalink-articles-Flaaax-test-categories-Flaaaxtags-test\"><a href=\"#title-testdate-2024-05-28updated-2024-05-28permalink-articles-Flaaax-test-categories-Flaaaxtags-test\" class=\"headerlink\" title=\"title: testdate: 2024-05-28updated: 2024-05-28permalink: articles/Flaaax/test/categories: Flaaaxtags: [test]\"></a>title: test<br>date: 2024-05-28<br>updated: 2024-05-28<br>permalink: articles/Flaaax/test/<br>categories: Flaaax<br>tags: [test]</h2><p>测试测试测试测试测试</p>\n<span id=\"more\"></span>\n\n<div style=\"text-align:center\">\n\n<p>测试,测试,测试,测试, 测试,测试,测试,测试,测试</p>\n</div>\n\n<h1 id=\"测试测试测试测试测试-1\"><a href=\"#测试测试测试测试测试-1\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h1><h2 id=\"测试测试测试测试测试-2\"><a href=\"#测试测试测试测试测试-2\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h3 id=\"测试测试测试测试测试-3\"><a href=\"#测试测试测试测试测试-3\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h3><h4 id=\"测试测试测试测试测试-4\"><a href=\"#测试测试测试测试测试-4\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h4><h3 id=\"测试测试测试测试测试-5\"><a href=\"#测试测试测试测试测试-5\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h3><h2 id=\"测试测试测试测试测试-6\"><a href=\"#测试测试测试测试测试-6\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h1 id=\"测试测试测试测试测试-7\"><a href=\"#测试测试测试测试测试-7\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h1><h3 id=\"锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\"><a href=\"#锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\" class=\"headerlink\" title=\"锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\"></a>锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟</h3>","site":{"data":{}},"excerpt":"<h2 id=\"测试测试测试测试测试\"><a href=\"#测试测试测试测试测试\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h2 id=\"title-testdate-2024-05-28updated-2024-05-28permalink-articles-Flaaax-test-categories-Flaaaxtags-test\"><a href=\"#title-testdate-2024-05-28updated-2024-05-28permalink-articles-Flaaax-test-categories-Flaaaxtags-test\" class=\"headerlink\" title=\"title: testdate: 2024-05-28updated: 2024-05-28permalink: articles/Flaaax/test/categories: Flaaaxtags: [test]\"></a>title: test<br>date: 2024-05-28<br>updated: 2024-05-28<br>permalink: articles/Flaaax/test/<br>categories: Flaaax<br>tags: [test]</h2><p>测试测试测试测试测试</p>","more":"<div style=\"text-align:center\">\n\n<p>测试,测试,测试,测试, 测试,测试,测试,测试,测试</p>\n</div>\n\n<h1 id=\"测试测试测试测试测试-1\"><a href=\"#测试测试测试测试测试-1\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h1><h2 id=\"测试测试测试测试测试-2\"><a href=\"#测试测试测试测试测试-2\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h3 id=\"测试测试测试测试测试-3\"><a href=\"#测试测试测试测试测试-3\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h3><h4 id=\"测试测试测试测试测试-4\"><a href=\"#测试测试测试测试测试-4\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h4><h3 id=\"测试测试测试测试测试-5\"><a href=\"#测试测试测试测试测试-5\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h3><h2 id=\"测试测试测试测试测试-6\"><a href=\"#测试测试测试测试测试-6\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h2><h1 id=\"测试测试测试测试测试-7\"><a href=\"#测试测试测试测试测试-7\" class=\"headerlink\" title=\"测试测试测试测试测试\"></a>测试测试测试测试测试</h1><h3 id=\"锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\"><a href=\"#锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\" class=\"headerlink\" title=\"锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟\"></a>锟斤拷锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟锟</h3>"},{"title":"Git使用方法学习","date":"2024-05-28T16:00:00.000Z","updated":"2024-05-29T16:00:00.000Z","_content":"\n\n这篇文章既是记录Git的学习过程,同时也是markdown的练习,操作系统为Win11,文章末尾有自我介绍。\n\n## Git的安装和初始化配置\n1. 安装Git,[Git下载连接](https://git-scm.com/download),根据自己的操作系统进行选择,下载后运行exe文件,我下载选项暂时全部都选择默认\n2. 检查是否成功安装Git,下载完成后,打开控制面板(win+R 输入cmd),查看Git版本信息\n<!-- More -->\n ```\n // 输入此命令进行查看\n git --version\n ```\n\n3. 配置Git,配置用户名和邮箱,在命令行中输入以下指令\n\n ```\n git config --global user.name <此处替换为你的用户名>\n git config --global user.email <此处替换成你的邮箱>\n\n ```\n4. 检测是否配置成功,在命令行中输入以下指令\n ```\n git config user.name\n git config user.email\n ```\n\n## Git基础使用\n[中文官方文档链接](https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93) \n\n### 获取Git仓库\n- 在已存在目录中初始化仓库 \n\n 首先,新建一个文件夹,例如testGit,记录该文件夹的路径例如:\"D:\\testGit\",接下来点击鼠标右键,选择Git Bash,输入指令\n ```\n $ cd D:\\testGit //输入你自己文件夹的路径,该步骤是转到此文件夹下\n ```\n 再输入\n ```\n $ git init //该步骤将当前文件夹转化为一个Git仓库\n ```\n 若显示\n ```\n Initialized empty Git repository in D:/testGit/.git/\n ```\n 即为操作成功 \n\n 接下来可以在文件夹中创建两个文本文档,命名为test1和test2. \n 通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit : \n `$ git add *.txt` \n `$ git commit -m 'initial project version'` \n\n\n- 克隆现有的仓库 \n\n 使用命令\n ```\n git clone <url>\n ```\n 详情参考中文官方文档 \n\n### 记录每次更新到仓库\n工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。 \n\n1. 现在开始检查Git仓库的状态 \n \n 在Git Bash中输入以下指令,便可查看仓库当前状态\n ```\n $ git status\n ```\n 若看到以下输出\n ```\n On branch master\n nothing to commit, working tree clean\n ```\n 说明你现在的工作目录相当干净。所有已跟踪文件在上次提交后都未被更改过且当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 \n\n2. 然后在testGit中新建一个名为README的文本文档,再次输入`$ git status` \n 可以看到以下输出\n ```\n On branch master\n Untracked files:\n (use \"git add <file>...\" to include in what will be committed)\n README.txt\n nothing added to commit but untracked files present (use \"git add\" to track)\n ```\n 可以看到新建的 README 文件出现在 Untracked files 下面。除非明确表示要跟踪某文件,否则Git不会自动纳入跟踪范围,这样做生成的二进制文件或其它不想被跟踪的文件包含进来。\n\n3. 现在让我们跟踪README文件 \n\n 使用命令 git add 开始跟踪一个文件\n ```\n $ git add README.txt\n ```\n 输入`$ git status`,会看到 README 文件已被跟踪,并处于暂存状态\n ```\n $ git status\n On branch master\n Changes to be committed:\n (use \"git restore --staged <file>...\" to unstage)\n new file: README.txt\n ```\n 只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 \n\n4. 接着,尝试暂存已修改的文件\n \n 打开test1,在其中随意写一些文字,例如\"Hello World!\"并保存修改,输入`$ git status`,可以看到\n ```\n ........ \n\n Changes not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n modified: test1.txt\n ```\n test1.txt出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区. \n \n 要暂存这次更新,需要运行 `git add test1.txt` 命令, 接着再运行`git status`命令 \n 可以看到以下输出\n ```\n $ git status\n On branch master\n Changes to be committed:\n (use \"git restore --staged <file>...\" to unstage)\n new file: README.txt\n modified: test1.txt\n ```\n 可以看到现在两个文件都已暂存,下次提交时就会一并记录到仓库。 \n\n5. 提交更新,输入\n ```\n $ git commit\n ```\n 屏幕显示\n ```\n # Please enter the commit message for your changes. Lines starting\n # with '#' will be ignored, and an empty message aborts the commit.\n #\n # On branch master\n # Changes to be committed:\n # new file: README.txt\n # modified: test1.txt\n #\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n .git/COMMIT_EDITMSG [unix] (20:11 29/05/2024) 1,0-1 All\n \"/d/testGit/.git/COMMIT_EDITMSG\" [unix] 9L, 235B\n ```\n 按“i”键,插入`git commit`,再按“esc”键,输入`wq`,再按回车键,便可以成功提交。 \n\n### 查看提交历史\n输入`git log`即可查看该仓库提交历史。详情指令集可查看官方文档。 \n\n\n\n---\n\n\n最后写一丢丢随笔:\n我是一个普通的大学生,从小就喜欢玩电子游戏,从4399到Steam,玩了许多电子游戏,不过那时也就仅限于玩一下而已,对于怎么制作电子游戏说不上感兴趣,让我想要学习制作电子游戏的契机说起来还挺难过的,或许是长大了,又或许是因为生活中的一些不快,我慢慢的不能像儿时那样,一整天坐在电脑桌前,全身心的投入到游戏缤纷的世界里,但是我仍然热爱电子游戏,我喜欢这些用代码和美术构成的虚拟而又缤纷的世界,所以我决定把自己对游戏的热爱从玩电子游戏到制作电子游戏。 \n\n但是万事开头难,回忆自己在大学中一年多的学习,都是像数据结构,软件工程概论这样的理论上的学习,理论学习和技术学习有着巨大的鸿沟,我根本无法从命令行开始去想象如何制作一个游戏,在我为此绞尽脑汁时,意外的在EasyX的社区中看到了大V老师的视频,这才真正开启了我学习技术的道路。\n\n跟着大V老师学习差不多快两个月了,从刚开始跟着敲井字棋,到现在见证了社区的建立,大V老师质量优秀的视频和建立的学习交流群,提供给我游戏制作技术入门的途径,对大V老师的感谢难以言表,祝大V老师的教程越来越好,吸引更多对游戏制作感兴趣的人来观看,也祝社区越办越好,成为中国游戏制作的绿洲,滋养中国游戏界。\n","source":"_posts/FlyingfishFantasticfan/git的使用学习.md","raw":"---\ntitle: Git使用方法学习\ndate: 2024-05-29\nupdated: 2024-05-30\npermalink: articles/FlyingfishFantasticfan/Git学习记录/\ncategories: FlyingfishFantasticfan\ntags: [Git,学习,自我介绍]\n---\n\n\n这篇文章既是记录Git的学习过程,同时也是markdown的练习,操作系统为Win11,文章末尾有自我介绍。\n\n## Git的安装和初始化配置\n1. 安装Git,[Git下载连接](https://git-scm.com/download),根据自己的操作系统进行选择,下载后运行exe文件,我下载选项暂时全部都选择默认\n2. 检查是否成功安装Git,下载完成后,打开控制面板(win+R 输入cmd),查看Git版本信息\n<!-- More -->\n ```\n // 输入此命令进行查看\n git --version\n ```\n\n3. 配置Git,配置用户名和邮箱,在命令行中输入以下指令\n\n ```\n git config --global user.name <此处替换为你的用户名>\n git config --global user.email <此处替换成你的邮箱>\n\n ```\n4. 检测是否配置成功,在命令行中输入以下指令\n ```\n git config user.name\n git config user.email\n ```\n\n## Git基础使用\n[中文官方文档链接](https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93) \n\n### 获取Git仓库\n- 在已存在目录中初始化仓库 \n\n 首先,新建一个文件夹,例如testGit,记录该文件夹的路径例如:\"D:\\testGit\",接下来点击鼠标右键,选择Git Bash,输入指令\n ```\n $ cd D:\\testGit //输入你自己文件夹的路径,该步骤是转到此文件夹下\n ```\n 再输入\n ```\n $ git init //该步骤将当前文件夹转化为一个Git仓库\n ```\n 若显示\n ```\n Initialized empty Git repository in D:/testGit/.git/\n ```\n 即为操作成功 \n\n 接下来可以在文件夹中创建两个文本文档,命名为test1和test2. \n 通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit : \n `$ git add *.txt` \n `$ git commit -m 'initial project version'` \n\n\n- 克隆现有的仓库 \n\n 使用命令\n ```\n git clone <url>\n ```\n 详情参考中文官方文档 \n\n### 记录每次更新到仓库\n工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。 \n\n1. 现在开始检查Git仓库的状态 \n \n 在Git Bash中输入以下指令,便可查看仓库当前状态\n ```\n $ git status\n ```\n 若看到以下输出\n ```\n On branch master\n nothing to commit, working tree clean\n ```\n 说明你现在的工作目录相当干净。所有已跟踪文件在上次提交后都未被更改过且当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 \n\n2. 然后在testGit中新建一个名为README的文本文档,再次输入`$ git status` \n 可以看到以下输出\n ```\n On branch master\n Untracked files:\n (use \"git add <file>...\" to include in what will be committed)\n README.txt\n nothing added to commit but untracked files present (use \"git add\" to track)\n ```\n 可以看到新建的 README 文件出现在 Untracked files 下面。除非明确表示要跟踪某文件,否则Git不会自动纳入跟踪范围,这样做生成的二进制文件或其它不想被跟踪的文件包含进来。\n\n3. 现在让我们跟踪README文件 \n\n 使用命令 git add 开始跟踪一个文件\n ```\n $ git add README.txt\n ```\n 输入`$ git status`,会看到 README 文件已被跟踪,并处于暂存状态\n ```\n $ git status\n On branch master\n Changes to be committed:\n (use \"git restore --staged <file>...\" to unstage)\n new file: README.txt\n ```\n 只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 \n\n4. 接着,尝试暂存已修改的文件\n \n 打开test1,在其中随意写一些文字,例如\"Hello World!\"并保存修改,输入`$ git status`,可以看到\n ```\n ........ \n\n Changes not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n modified: test1.txt\n ```\n test1.txt出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区. \n \n 要暂存这次更新,需要运行 `git add test1.txt` 命令, 接着再运行`git status`命令 \n 可以看到以下输出\n ```\n $ git status\n On branch master\n Changes to be committed:\n (use \"git restore --staged <file>...\" to unstage)\n new file: README.txt\n modified: test1.txt\n ```\n 可以看到现在两个文件都已暂存,下次提交时就会一并记录到仓库。 \n\n5. 提交更新,输入\n ```\n $ git commit\n ```\n 屏幕显示\n ```\n # Please enter the commit message for your changes. Lines starting\n # with '#' will be ignored, and an empty message aborts the commit.\n #\n # On branch master\n # Changes to be committed:\n # new file: README.txt\n # modified: test1.txt\n #\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n ~\n .git/COMMIT_EDITMSG [unix] (20:11 29/05/2024) 1,0-1 All\n \"/d/testGit/.git/COMMIT_EDITMSG\" [unix] 9L, 235B\n ```\n 按“i”键,插入`git commit`,再按“esc”键,输入`wq`,再按回车键,便可以成功提交。 \n\n### 查看提交历史\n输入`git log`即可查看该仓库提交历史。详情指令集可查看官方文档。 \n\n\n\n---\n\n\n最后写一丢丢随笔:\n我是一个普通的大学生,从小就喜欢玩电子游戏,从4399到Steam,玩了许多电子游戏,不过那时也就仅限于玩一下而已,对于怎么制作电子游戏说不上感兴趣,让我想要学习制作电子游戏的契机说起来还挺难过的,或许是长大了,又或许是因为生活中的一些不快,我慢慢的不能像儿时那样,一整天坐在电脑桌前,全身心的投入到游戏缤纷的世界里,但是我仍然热爱电子游戏,我喜欢这些用代码和美术构成的虚拟而又缤纷的世界,所以我决定把自己对游戏的热爱从玩电子游戏到制作电子游戏。 \n\n但是万事开头难,回忆自己在大学中一年多的学习,都是像数据结构,软件工程概论这样的理论上的学习,理论学习和技术学习有着巨大的鸿沟,我根本无法从命令行开始去想象如何制作一个游戏,在我为此绞尽脑汁时,意外的在EasyX的社区中看到了大V老师的视频,这才真正开启了我学习技术的道路。\n\n跟着大V老师学习差不多快两个月了,从刚开始跟着敲井字棋,到现在见证了社区的建立,大V老师质量优秀的视频和建立的学习交流群,提供给我游戏制作技术入门的途径,对大V老师的感谢难以言表,祝大V老师的教程越来越好,吸引更多对游戏制作感兴趣的人来观看,也祝社区越办越好,成为中国游戏制作的绿洲,滋养中国游戏界。\n","slug":"FlyingfishFantasticfan/git的使用学习","published":1,"__permalink":"articles/FlyingfishFantasticfan/Git学习记录/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg70004o8yeabnyg1ae","content":"<p>这篇文章既是记录Git的学习过程,同时也是markdown的练习,操作系统为Win11,文章末尾有自我介绍。</p>\n<h2 id=\"Git的安装和初始化配置\"><a href=\"#Git的安装和初始化配置\" class=\"headerlink\" title=\"Git的安装和初始化配置\"></a>Git的安装和初始化配置</h2><ol>\n<li><p>安装Git,<a href=\"https://git-scm.com/download\">Git下载连接</a>,根据自己的操作系统进行选择,下载后运行exe文件,我下载选项暂时全部都选择默认</p>\n</li>\n<li><p>检查是否成功安装Git,下载完成后,打开控制面板(win+R 输入cmd),查看Git版本信息</p>\n<span id=\"more\"></span>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">// 输入此命令进行查看</span><br><span class=\"line\">git --version</span><br></pre></td></tr></table></figure>\n</li>\n<li><p>配置Git,配置用户名和邮箱,在命令行中输入以下指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config --global user.name <此处替换为你的用户名></span><br><span class=\"line\">git config --global user.email <此处替换成你的邮箱></span><br><span class=\"line\"></span><br></pre></td></tr></table></figure></li>\n<li><p>检测是否配置成功,在命令行中输入以下指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config user.name</span><br><span class=\"line\">git config user.email</span><br></pre></td></tr></table></figure></li>\n</ol>\n<h2 id=\"Git基础使用\"><a href=\"#Git基础使用\" class=\"headerlink\" title=\"Git基础使用\"></a>Git基础使用</h2><p><a href=\"https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93\">中文官方文档链接</a> </p>\n<h3 id=\"获取Git仓库\"><a href=\"#获取Git仓库\" class=\"headerlink\" title=\"获取Git仓库\"></a>获取Git仓库</h3><ul>\n<li><p>在已存在目录中初始化仓库 </p>\n<p> 首先,新建一个文件夹,例如testGit,记录该文件夹的路径例如:”D:\\testGit”,接下来点击鼠标右键,选择Git Bash,输入指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ cd D:\\testGit //输入你自己文件夹的路径,该步骤是转到此文件夹下</span><br></pre></td></tr></table></figure>\n<p> 再输入</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git init //该步骤将当前文件夹转化为一个Git仓库</span><br></pre></td></tr></table></figure>\n<p> 若显示</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">Initialized empty Git repository in D:/testGit/.git/</span><br></pre></td></tr></table></figure>\n<p> 即为操作成功 </p>\n<p> 接下来可以在文件夹中创建两个文本文档,命名为test1和test2.<br> 通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit :<br> <code>$ git add *.txt</code><br> <code>$ git commit -m 'initial project version'</code> </p>\n</li>\n<li><p>克隆现有的仓库 </p>\n<p> 使用命令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git clone <url></span><br></pre></td></tr></table></figure>\n<p> 详情参考中文官方文档</p>\n</li>\n</ul>\n<h3 id=\"记录每次更新到仓库\"><a href=\"#记录每次更新到仓库\" class=\"headerlink\" title=\"记录每次更新到仓库\"></a>记录每次更新到仓库</h3><p>工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。 </p>\n<ol>\n<li><p>现在开始检查Git仓库的状态 </p>\n<p>在Git Bash中输入以下指令,便可查看仓库当前状态</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br></pre></td></tr></table></figure>\n<p> 若看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">On branch master</span><br><span class=\"line\">nothing to commit, working tree clean</span><br></pre></td></tr></table></figure>\n<p> 说明你现在的工作目录相当干净。所有已跟踪文件在上次提交后都未被更改过且当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 </p>\n</li>\n<li><p>然后在testGit中新建一个名为README的文本文档,再次输入<code>$ git status</code><br> 可以看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">On branch master</span><br><span class=\"line\">Untracked files:</span><br><span class=\"line\">(use "git add <file>..." to include in what will be committed)</span><br><span class=\"line\"> README.txt</span><br><span class=\"line\">nothing added to commit but untracked files present (use "git add" to track)</span><br></pre></td></tr></table></figure>\n<p> 可以看到新建的 README 文件出现在 Untracked files 下面。除非明确表示要跟踪某文件,否则Git不会自动纳入跟踪范围,这样做生成的二进制文件或其它不想被跟踪的文件包含进来。</p>\n</li>\n<li><p>现在让我们跟踪README文件 </p>\n<p>使用命令 git add 开始跟踪一个文件</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git add README.txt</span><br></pre></td></tr></table></figure>\n<p> 输入<code>$ git status</code>,会看到 README 文件已被跟踪,并处于暂存状态</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\">(use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> new file: README.txt</span><br></pre></td></tr></table></figure>\n<p> 只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 </p>\n</li>\n<li><p>接着,尝试暂存已修改的文件</p>\n<p> 打开test1,在其中随意写一些文字,例如”Hello World!”并保存修改,输入<code>$ git status</code>,可以看到</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">........ </span><br><span class=\"line\"></span><br><span class=\"line\">Changes not staged for commit:</span><br><span class=\"line\">(use "git add <file>..." to update what will be committed)</span><br><span class=\"line\">(use "git restore <file>..." to discard changes in working directory)</span><br><span class=\"line\"> modified: test1.txt</span><br></pre></td></tr></table></figure>\n<p> test1.txt出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区. </p>\n<p> 要暂存这次更新,需要运行 <code>git add test1.txt</code> 命令, 接着再运行<code>git status</code>命令<br> 可以看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\">(use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> new file: README.txt</span><br><span class=\"line\"> modified: test1.txt</span><br></pre></td></tr></table></figure>\n<p> 可以看到现在两个文件都已暂存,下次提交时就会一并记录到仓库。 </p>\n</li>\n<li><p>提交更新,输入</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git commit</span><br></pre></td></tr></table></figure>\n<p> 屏幕显示</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"># Please enter the commit message for your changes. Lines starting</span><br><span class=\"line\"># with '#' will be ignored, and an empty message aborts the commit.</span><br><span class=\"line\">#</span><br><span class=\"line\"># On branch master</span><br><span class=\"line\"># Changes to be committed:</span><br><span class=\"line\"># new file: README.txt</span><br><span class=\"line\"># modified: test1.txt</span><br><span class=\"line\">#</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">.git/COMMIT_EDITMSG [unix] (20:11 29/05/2024) 1,0-1 All</span><br><span class=\"line\">"/d/testGit/.git/COMMIT_EDITMSG" [unix] 9L, 235B</span><br></pre></td></tr></table></figure>\n<p> 按“i”键,插入<code>git commit</code>,再按“esc”键,输入<code>wq</code>,再按回车键,便可以成功提交。</p>\n</li>\n</ol>\n<h3 id=\"查看提交历史\"><a href=\"#查看提交历史\" class=\"headerlink\" title=\"查看提交历史\"></a>查看提交历史</h3><p>输入<code>git log</code>即可查看该仓库提交历史。详情指令集可查看官方文档。 </p>\n<hr>\n<p>最后写一丢丢随笔:<br>我是一个普通的大学生,从小就喜欢玩电子游戏,从4399到Steam,玩了许多电子游戏,不过那时也就仅限于玩一下而已,对于怎么制作电子游戏说不上感兴趣,让我想要学习制作电子游戏的契机说起来还挺难过的,或许是长大了,又或许是因为生活中的一些不快,我慢慢的不能像儿时那样,一整天坐在电脑桌前,全身心的投入到游戏缤纷的世界里,但是我仍然热爱电子游戏,我喜欢这些用代码和美术构成的虚拟而又缤纷的世界,所以我决定把自己对游戏的热爱从玩电子游戏到制作电子游戏。 </p>\n<p>但是万事开头难,回忆自己在大学中一年多的学习,都是像数据结构,软件工程概论这样的理论上的学习,理论学习和技术学习有着巨大的鸿沟,我根本无法从命令行开始去想象如何制作一个游戏,在我为此绞尽脑汁时,意外的在EasyX的社区中看到了大V老师的视频,这才真正开启了我学习技术的道路。</p>\n<p>跟着大V老师学习差不多快两个月了,从刚开始跟着敲井字棋,到现在见证了社区的建立,大V老师质量优秀的视频和建立的学习交流群,提供给我游戏制作技术入门的途径,对大V老师的感谢难以言表,祝大V老师的教程越来越好,吸引更多对游戏制作感兴趣的人来观看,也祝社区越办越好,成为中国游戏制作的绿洲,滋养中国游戏界。</p>\n","site":{"data":{}},"excerpt":"<p>这篇文章既是记录Git的学习过程,同时也是markdown的练习,操作系统为Win11,文章末尾有自我介绍。</p>\n<h2 id=\"Git的安装和初始化配置\"><a href=\"#Git的安装和初始化配置\" class=\"headerlink\" title=\"Git的安装和初始化配置\"></a>Git的安装和初始化配置</h2><ol>\n<li><p>安装Git,<a href=\"https://git-scm.com/download\">Git下载连接</a>,根据自己的操作系统进行选择,下载后运行exe文件,我下载选项暂时全部都选择默认</p>\n</li>\n<li><p>检查是否成功安装Git,下载完成后,打开控制面板(win+R 输入cmd),查看Git版本信息</p>","more":"<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">// 输入此命令进行查看</span><br><span class=\"line\">git --version</span><br></pre></td></tr></table></figure>\n</li>\n<li><p>配置Git,配置用户名和邮箱,在命令行中输入以下指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config --global user.name <此处替换为你的用户名></span><br><span class=\"line\">git config --global user.email <此处替换成你的邮箱></span><br><span class=\"line\"></span><br></pre></td></tr></table></figure></li>\n<li><p>检测是否配置成功,在命令行中输入以下指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config user.name</span><br><span class=\"line\">git config user.email</span><br></pre></td></tr></table></figure></li>\n</ol>\n<h2 id=\"Git基础使用\"><a href=\"#Git基础使用\" class=\"headerlink\" title=\"Git基础使用\"></a>Git基础使用</h2><p><a href=\"https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E8%8E%B7%E5%8F%96-Git-%E4%BB%93%E5%BA%93\">中文官方文档链接</a> </p>\n<h3 id=\"获取Git仓库\"><a href=\"#获取Git仓库\" class=\"headerlink\" title=\"获取Git仓库\"></a>获取Git仓库</h3><ul>\n<li><p>在已存在目录中初始化仓库 </p>\n<p> 首先,新建一个文件夹,例如testGit,记录该文件夹的路径例如:”D:\\testGit”,接下来点击鼠标右键,选择Git Bash,输入指令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ cd D:\\testGit //输入你自己文件夹的路径,该步骤是转到此文件夹下</span><br></pre></td></tr></table></figure>\n<p> 再输入</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git init //该步骤将当前文件夹转化为一个Git仓库</span><br></pre></td></tr></table></figure>\n<p> 若显示</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">Initialized empty Git repository in D:/testGit/.git/</span><br></pre></td></tr></table></figure>\n<p> 即为操作成功 </p>\n<p> 接下来可以在文件夹中创建两个文本文档,命名为test1和test2.<br> 通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit :<br> <code>$ git add *.txt</code><br> <code>$ git commit -m 'initial project version'</code> </p>\n</li>\n<li><p>克隆现有的仓库 </p>\n<p> 使用命令</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git clone <url></span><br></pre></td></tr></table></figure>\n<p> 详情参考中文官方文档</p>\n</li>\n</ul>\n<h3 id=\"记录每次更新到仓库\"><a href=\"#记录每次更新到仓库\" class=\"headerlink\" title=\"记录每次更新到仓库\"></a>记录每次更新到仓库</h3><p>工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。 </p>\n<ol>\n<li><p>现在开始检查Git仓库的状态 </p>\n<p>在Git Bash中输入以下指令,便可查看仓库当前状态</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br></pre></td></tr></table></figure>\n<p> 若看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">On branch master</span><br><span class=\"line\">nothing to commit, working tree clean</span><br></pre></td></tr></table></figure>\n<p> 说明你现在的工作目录相当干净。所有已跟踪文件在上次提交后都未被更改过且当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 </p>\n</li>\n<li><p>然后在testGit中新建一个名为README的文本文档,再次输入<code>$ git status</code><br> 可以看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">On branch master</span><br><span class=\"line\">Untracked files:</span><br><span class=\"line\">(use "git add <file>..." to include in what will be committed)</span><br><span class=\"line\"> README.txt</span><br><span class=\"line\">nothing added to commit but untracked files present (use "git add" to track)</span><br></pre></td></tr></table></figure>\n<p> 可以看到新建的 README 文件出现在 Untracked files 下面。除非明确表示要跟踪某文件,否则Git不会自动纳入跟踪范围,这样做生成的二进制文件或其它不想被跟踪的文件包含进来。</p>\n</li>\n<li><p>现在让我们跟踪README文件 </p>\n<p>使用命令 git add 开始跟踪一个文件</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git add README.txt</span><br></pre></td></tr></table></figure>\n<p> 输入<code>$ git status</code>,会看到 README 文件已被跟踪,并处于暂存状态</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\">(use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> new file: README.txt</span><br></pre></td></tr></table></figure>\n<p> 只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 </p>\n</li>\n<li><p>接着,尝试暂存已修改的文件</p>\n<p> 打开test1,在其中随意写一些文字,例如”Hello World!”并保存修改,输入<code>$ git status</code>,可以看到</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">........ </span><br><span class=\"line\"></span><br><span class=\"line\">Changes not staged for commit:</span><br><span class=\"line\">(use "git add <file>..." to update what will be committed)</span><br><span class=\"line\">(use "git restore <file>..." to discard changes in working directory)</span><br><span class=\"line\"> modified: test1.txt</span><br></pre></td></tr></table></figure>\n<p> test1.txt出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区. </p>\n<p> 要暂存这次更新,需要运行 <code>git add test1.txt</code> 命令, 接着再运行<code>git status</code>命令<br> 可以看到以下输出</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\">(use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> new file: README.txt</span><br><span class=\"line\"> modified: test1.txt</span><br></pre></td></tr></table></figure>\n<p> 可以看到现在两个文件都已暂存,下次提交时就会一并记录到仓库。 </p>\n</li>\n<li><p>提交更新,输入</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git commit</span><br></pre></td></tr></table></figure>\n<p> 屏幕显示</p>\n <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"># Please enter the commit message for your changes. Lines starting</span><br><span class=\"line\"># with '#' will be ignored, and an empty message aborts the commit.</span><br><span class=\"line\">#</span><br><span class=\"line\"># On branch master</span><br><span class=\"line\"># Changes to be committed:</span><br><span class=\"line\"># new file: README.txt</span><br><span class=\"line\"># modified: test1.txt</span><br><span class=\"line\">#</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">~</span><br><span class=\"line\">.git/COMMIT_EDITMSG [unix] (20:11 29/05/2024) 1,0-1 All</span><br><span class=\"line\">"/d/testGit/.git/COMMIT_EDITMSG" [unix] 9L, 235B</span><br></pre></td></tr></table></figure>\n<p> 按“i”键,插入<code>git commit</code>,再按“esc”键,输入<code>wq</code>,再按回车键,便可以成功提交。</p>\n</li>\n</ol>\n<h3 id=\"查看提交历史\"><a href=\"#查看提交历史\" class=\"headerlink\" title=\"查看提交历史\"></a>查看提交历史</h3><p>输入<code>git log</code>即可查看该仓库提交历史。详情指令集可查看官方文档。 </p>\n<hr>\n<p>最后写一丢丢随笔:<br>我是一个普通的大学生,从小就喜欢玩电子游戏,从4399到Steam,玩了许多电子游戏,不过那时也就仅限于玩一下而已,对于怎么制作电子游戏说不上感兴趣,让我想要学习制作电子游戏的契机说起来还挺难过的,或许是长大了,又或许是因为生活中的一些不快,我慢慢的不能像儿时那样,一整天坐在电脑桌前,全身心的投入到游戏缤纷的世界里,但是我仍然热爱电子游戏,我喜欢这些用代码和美术构成的虚拟而又缤纷的世界,所以我决定把自己对游戏的热爱从玩电子游戏到制作电子游戏。 </p>\n<p>但是万事开头难,回忆自己在大学中一年多的学习,都是像数据结构,软件工程概论这样的理论上的学习,理论学习和技术学习有着巨大的鸿沟,我根本无法从命令行开始去想象如何制作一个游戏,在我为此绞尽脑汁时,意外的在EasyX的社区中看到了大V老师的视频,这才真正开启了我学习技术的道路。</p>\n<p>跟着大V老师学习差不多快两个月了,从刚开始跟着敲井字棋,到现在见证了社区的建立,大V老师质量优秀的视频和建立的学习交流群,提供给我游戏制作技术入门的途径,对大V老师的感谢难以言表,祝大V老师的教程越来越好,吸引更多对游戏制作感兴趣的人来观看,也祝社区越办越好,成为中国游戏制作的绿洲,滋养中国游戏界。</p>"},{"title":"游戏设计知识分享笔记-依赖性","date":"2024-06-07T16:00:00.000Z","updated":"2024-06-08T16:00:00.000Z","_content":"\n飞鱼丸的个人博客建成啦,欢迎大家参观![点击传送原文](https://flyingfishfantasticfan.github.io/2024/06/08/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/) \n## 前言\n在构思一个新游戏时常常会有许多想法,诸如不同的挑战、系统以及界面,完整的游戏常常会包含上百种机制及子系统,在已经构思好许多子系统后,紧接着我们要开始游戏的开发,现在我们有以下的选择\n- 最简单的模块\n- 最擅长的模块\n- 最具特色的模块\n- 常常能听到的核心玩法 \n\n绝大多数游戏开发者都会建议从核心玩法开始开发,但是为什么要这样做呢? \n<!-- More -->\n## 游戏开发顺序的影响\n当我们为某个已经完成的游戏制作几个额外关卡时,开发的顺序无关紧要,关卡之间并不会相互影响,但制作游戏并不一样,不同设计之间常常相互依赖\n<div style=\"text-align:center\">\n\n![ICON](articles/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/游戏设计知识分享-依赖性-1.png)\n\n</div>\n \n当我们修改某一个模块时,依赖于该模块的部分必然也会发生变化,例如,假设最初开发时先完成了场景布局,设计了一条玩家无法跳过只能从桥梁通过的河流,完成场景布局后,为了优秀的视觉表现,把桥梁设计的十分精美,河流周围的景色也十分美丽,但是在随后的开发中发现玩家的跳跃能力不够灵活,需要增强玩家跳跃能力,导致了原本设计无法跳过去的河流可以跳过去了,就得再修改场景布局,同时依赖于场景布局的视觉表现也需要再重新制作,若能够再开发前对不同模块的依赖性有更深刻的理解,我们也许会先确立移动体系,随后再去进行场景布局和视觉表现。 \n\n## 如何确定游戏开发顺序\n我们可以通过画依赖关系图,来分析识别设计中关键的依赖性,从而确定开发顺序\n1. 将游戏分解成许多独立的因素,包含机制,操作,界面,子系统等等,每个因素应包含一份详细的设计方案。\n2. 识别出各个因素之间关键的依赖,并通过树状图的结构将所有的因素囊括进来,通过连线来描述依赖关系。\n>TIPS:对A模块进行修改时会影响B模块时,便可称B依赖A,在设计中常常会出现A与B之间互相依赖的情况,事实上任何设计之间都会存在一定的依赖关系,在依赖关系图中会有意忽略依赖性较弱的部分,以便开发时能够更加专注于最重要的元素,时刻记得依赖关系图只是帮助开发进行决策的工具,无止境的拘泥于过于细致的分析只会导致项目难以推动。 \n\n## 额外需要注意的地方\n\n### 原创的不确定性\n原创度较高的游戏常会出现不按照设计方案来实现,这种不确定性使得依赖性变得非常重要,某个设计中出现的不确定不足以说明问题,然后由于依赖性的存在,不确定性会因为多层依赖的存在逐步积累,因此位于依赖关系图顶层的内容常常重新设计,甚至直接被删除。\n\n### 应对措施\n重新梳理最初的依赖关系图,将短期内不会实现的内容以及相互独立的设计灵感放置于设计库中,将底层的内容实现并测试再进行迭代,此时并没有依赖关系的存在,因此并不会产生巨大的不确定性积累,等到底层系统确定性足够高后再将设计库某一内容添加进来。\n\n>TIPS:可以将最初版所有内容包含进来的依赖关系图中拿走但不会使游戏毫无意义的内容全部拿走,剩下的就是核心玩法,核心玩法常常可以用于定义某一游戏的类型,尽早完成核心玩法的开发,可以让项目尽快开始进行测试及迭代。 ","source":"_posts/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性.md","raw":"---\ntitle: 游戏设计知识分享笔记-依赖性\ndate: 2024-06-08\nupdated: 2024-06-09\npermalink: articles/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/\ncategories: FlyingfishFantasticfan\ntags: [游戏设计,学习]\n---\n\n飞鱼丸的个人博客建成啦,欢迎大家参观![点击传送原文](https://flyingfishfantasticfan.github.io/2024/06/08/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/) \n## 前言\n在构思一个新游戏时常常会有许多想法,诸如不同的挑战、系统以及界面,完整的游戏常常会包含上百种机制及子系统,在已经构思好许多子系统后,紧接着我们要开始游戏的开发,现在我们有以下的选择\n- 最简单的模块\n- 最擅长的模块\n- 最具特色的模块\n- 常常能听到的核心玩法 \n\n绝大多数游戏开发者都会建议从核心玩法开始开发,但是为什么要这样做呢? \n<!-- More -->\n## 游戏开发顺序的影响\n当我们为某个已经完成的游戏制作几个额外关卡时,开发的顺序无关紧要,关卡之间并不会相互影响,但制作游戏并不一样,不同设计之间常常相互依赖\n<div style=\"text-align:center\">\n\n![ICON](articles/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/游戏设计知识分享-依赖性-1.png)\n\n</div>\n \n当我们修改某一个模块时,依赖于该模块的部分必然也会发生变化,例如,假设最初开发时先完成了场景布局,设计了一条玩家无法跳过只能从桥梁通过的河流,完成场景布局后,为了优秀的视觉表现,把桥梁设计的十分精美,河流周围的景色也十分美丽,但是在随后的开发中发现玩家的跳跃能力不够灵活,需要增强玩家跳跃能力,导致了原本设计无法跳过去的河流可以跳过去了,就得再修改场景布局,同时依赖于场景布局的视觉表现也需要再重新制作,若能够再开发前对不同模块的依赖性有更深刻的理解,我们也许会先确立移动体系,随后再去进行场景布局和视觉表现。 \n\n## 如何确定游戏开发顺序\n我们可以通过画依赖关系图,来分析识别设计中关键的依赖性,从而确定开发顺序\n1. 将游戏分解成许多独立的因素,包含机制,操作,界面,子系统等等,每个因素应包含一份详细的设计方案。\n2. 识别出各个因素之间关键的依赖,并通过树状图的结构将所有的因素囊括进来,通过连线来描述依赖关系。\n>TIPS:对A模块进行修改时会影响B模块时,便可称B依赖A,在设计中常常会出现A与B之间互相依赖的情况,事实上任何设计之间都会存在一定的依赖关系,在依赖关系图中会有意忽略依赖性较弱的部分,以便开发时能够更加专注于最重要的元素,时刻记得依赖关系图只是帮助开发进行决策的工具,无止境的拘泥于过于细致的分析只会导致项目难以推动。 \n\n## 额外需要注意的地方\n\n### 原创的不确定性\n原创度较高的游戏常会出现不按照设计方案来实现,这种不确定性使得依赖性变得非常重要,某个设计中出现的不确定不足以说明问题,然后由于依赖性的存在,不确定性会因为多层依赖的存在逐步积累,因此位于依赖关系图顶层的内容常常重新设计,甚至直接被删除。\n\n### 应对措施\n重新梳理最初的依赖关系图,将短期内不会实现的内容以及相互独立的设计灵感放置于设计库中,将底层的内容实现并测试再进行迭代,此时并没有依赖关系的存在,因此并不会产生巨大的不确定性积累,等到底层系统确定性足够高后再将设计库某一内容添加进来。\n\n>TIPS:可以将最初版所有内容包含进来的依赖关系图中拿走但不会使游戏毫无意义的内容全部拿走,剩下的就是核心玩法,核心玩法常常可以用于定义某一游戏的类型,尽早完成核心玩法的开发,可以让项目尽快开始进行测试及迭代。 ","slug":"FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性","published":1,"__permalink":"articles/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg80005o8yea1488m2y","content":"<p>飞鱼丸的个人博客建成啦,欢迎大家参观!<a href=\"https://flyingfishfantasticfan.github.io/2024/06/08/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/\">点击传送原文</a> </p>\n<h2 id=\"前言\"><a href=\"#前言\" class=\"headerlink\" title=\"前言\"></a>前言</h2><p>在构思一个新游戏时常常会有许多想法,诸如不同的挑战、系统以及界面,完整的游戏常常会包含上百种机制及子系统,在已经构思好许多子系统后,紧接着我们要开始游戏的开发,现在我们有以下的选择</p>\n<ul>\n<li>最简单的模块</li>\n<li>最擅长的模块</li>\n<li>最具特色的模块</li>\n<li>常常能听到的核心玩法</li>\n</ul>\n<p>绝大多数游戏开发者都会建议从核心玩法开始开发,但是为什么要这样做呢? </p>\n<span id=\"more\"></span>\n<h2 id=\"游戏开发顺序的影响\"><a href=\"#游戏开发顺序的影响\" class=\"headerlink\" title=\"游戏开发顺序的影响\"></a>游戏开发顺序的影响</h2><p>当我们为某个已经完成的游戏制作几个额外关卡时,开发的顺序无关紧要,关卡之间并不会相互影响,但制作游戏并不一样,不同设计之间常常相互依赖</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB-%E4%BE%9D%E8%B5%96%E6%80%A7-1.png\" alt=\"ICON\"></p>\n</div>\n \n<p>当我们修改某一个模块时,依赖于该模块的部分必然也会发生变化,例如,假设最初开发时先完成了场景布局,设计了一条玩家无法跳过只能从桥梁通过的河流,完成场景布局后,为了优秀的视觉表现,把桥梁设计的十分精美,河流周围的景色也十分美丽,但是在随后的开发中发现玩家的跳跃能力不够灵活,需要增强玩家跳跃能力,导致了原本设计无法跳过去的河流可以跳过去了,就得再修改场景布局,同时依赖于场景布局的视觉表现也需要再重新制作,若能够再开发前对不同模块的依赖性有更深刻的理解,我们也许会先确立移动体系,随后再去进行场景布局和视觉表现。 </p>\n<h2 id=\"如何确定游戏开发顺序\"><a href=\"#如何确定游戏开发顺序\" class=\"headerlink\" title=\"如何确定游戏开发顺序\"></a>如何确定游戏开发顺序</h2><p>我们可以通过画依赖关系图,来分析识别设计中关键的依赖性,从而确定开发顺序</p>\n<ol>\n<li>将游戏分解成许多独立的因素,包含机制,操作,界面,子系统等等,每个因素应包含一份详细的设计方案。</li>\n<li>识别出各个因素之间关键的依赖,并通过树状图的结构将所有的因素囊括进来,通过连线来描述依赖关系。<blockquote>\n<p>TIPS:对A模块进行修改时会影响B模块时,便可称B依赖A,在设计中常常会出现A与B之间互相依赖的情况,事实上任何设计之间都会存在一定的依赖关系,在依赖关系图中会有意忽略依赖性较弱的部分,以便开发时能够更加专注于最重要的元素,时刻记得依赖关系图只是帮助开发进行决策的工具,无止境的拘泥于过于细致的分析只会导致项目难以推动。</p>\n</blockquote>\n</li>\n</ol>\n<h2 id=\"额外需要注意的地方\"><a href=\"#额外需要注意的地方\" class=\"headerlink\" title=\"额外需要注意的地方\"></a>额外需要注意的地方</h2><h3 id=\"原创的不确定性\"><a href=\"#原创的不确定性\" class=\"headerlink\" title=\"原创的不确定性\"></a>原创的不确定性</h3><p>原创度较高的游戏常会出现不按照设计方案来实现,这种不确定性使得依赖性变得非常重要,某个设计中出现的不确定不足以说明问题,然后由于依赖性的存在,不确定性会因为多层依赖的存在逐步积累,因此位于依赖关系图顶层的内容常常重新设计,甚至直接被删除。</p>\n<h3 id=\"应对措施\"><a href=\"#应对措施\" class=\"headerlink\" title=\"应对措施\"></a>应对措施</h3><p>重新梳理最初的依赖关系图,将短期内不会实现的内容以及相互独立的设计灵感放置于设计库中,将底层的内容实现并测试再进行迭代,此时并没有依赖关系的存在,因此并不会产生巨大的不确定性积累,等到底层系统确定性足够高后再将设计库某一内容添加进来。</p>\n<blockquote>\n<p>TIPS:可以将最初版所有内容包含进来的依赖关系图中拿走但不会使游戏毫无意义的内容全部拿走,剩下的就是核心玩法,核心玩法常常可以用于定义某一游戏的类型,尽早完成核心玩法的开发,可以让项目尽快开始进行测试及迭代。 </p>\n</blockquote>\n","site":{"data":{}},"excerpt":"<p>飞鱼丸的个人博客建成啦,欢迎大家参观!<a href=\"https://flyingfishfantasticfan.github.io/2024/06/08/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/\">点击传送原文</a> </p>\n<h2 id=\"前言\"><a href=\"#前言\" class=\"headerlink\" title=\"前言\"></a>前言</h2><p>在构思一个新游戏时常常会有许多想法,诸如不同的挑战、系统以及界面,完整的游戏常常会包含上百种机制及子系统,在已经构思好许多子系统后,紧接着我们要开始游戏的开发,现在我们有以下的选择</p>\n<ul>\n<li>最简单的模块</li>\n<li>最擅长的模块</li>\n<li>最具特色的模块</li>\n<li>常常能听到的核心玩法</li>\n</ul>\n<p>绝大多数游戏开发者都会建议从核心玩法开始开发,但是为什么要这样做呢? </p>","more":"<h2 id=\"游戏开发顺序的影响\"><a href=\"#游戏开发顺序的影响\" class=\"headerlink\" title=\"游戏开发顺序的影响\"></a>游戏开发顺序的影响</h2><p>当我们为某个已经完成的游戏制作几个额外关卡时,开发的顺序无关紧要,关卡之间并不会相互影响,但制作游戏并不一样,不同设计之间常常相互依赖</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB%E7%AC%94%E8%AE%B0-%E4%BE%9D%E8%B5%96%E6%80%A7/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB-%E4%BE%9D%E8%B5%96%E6%80%A7-1.png\" alt=\"ICON\"></p>\n</div>\n \n<p>当我们修改某一个模块时,依赖于该模块的部分必然也会发生变化,例如,假设最初开发时先完成了场景布局,设计了一条玩家无法跳过只能从桥梁通过的河流,完成场景布局后,为了优秀的视觉表现,把桥梁设计的十分精美,河流周围的景色也十分美丽,但是在随后的开发中发现玩家的跳跃能力不够灵活,需要增强玩家跳跃能力,导致了原本设计无法跳过去的河流可以跳过去了,就得再修改场景布局,同时依赖于场景布局的视觉表现也需要再重新制作,若能够再开发前对不同模块的依赖性有更深刻的理解,我们也许会先确立移动体系,随后再去进行场景布局和视觉表现。 </p>\n<h2 id=\"如何确定游戏开发顺序\"><a href=\"#如何确定游戏开发顺序\" class=\"headerlink\" title=\"如何确定游戏开发顺序\"></a>如何确定游戏开发顺序</h2><p>我们可以通过画依赖关系图,来分析识别设计中关键的依赖性,从而确定开发顺序</p>\n<ol>\n<li>将游戏分解成许多独立的因素,包含机制,操作,界面,子系统等等,每个因素应包含一份详细的设计方案。</li>\n<li>识别出各个因素之间关键的依赖,并通过树状图的结构将所有的因素囊括进来,通过连线来描述依赖关系。<blockquote>\n<p>TIPS:对A模块进行修改时会影响B模块时,便可称B依赖A,在设计中常常会出现A与B之间互相依赖的情况,事实上任何设计之间都会存在一定的依赖关系,在依赖关系图中会有意忽略依赖性较弱的部分,以便开发时能够更加专注于最重要的元素,时刻记得依赖关系图只是帮助开发进行决策的工具,无止境的拘泥于过于细致的分析只会导致项目难以推动。</p>\n</blockquote>\n</li>\n</ol>\n<h2 id=\"额外需要注意的地方\"><a href=\"#额外需要注意的地方\" class=\"headerlink\" title=\"额外需要注意的地方\"></a>额外需要注意的地方</h2><h3 id=\"原创的不确定性\"><a href=\"#原创的不确定性\" class=\"headerlink\" title=\"原创的不确定性\"></a>原创的不确定性</h3><p>原创度较高的游戏常会出现不按照设计方案来实现,这种不确定性使得依赖性变得非常重要,某个设计中出现的不确定不足以说明问题,然后由于依赖性的存在,不确定性会因为多层依赖的存在逐步积累,因此位于依赖关系图顶层的内容常常重新设计,甚至直接被删除。</p>\n<h3 id=\"应对措施\"><a href=\"#应对措施\" class=\"headerlink\" title=\"应对措施\"></a>应对措施</h3><p>重新梳理最初的依赖关系图,将短期内不会实现的内容以及相互独立的设计灵感放置于设计库中,将底层的内容实现并测试再进行迭代,此时并没有依赖关系的存在,因此并不会产生巨大的不确定性积累,等到底层系统确定性足够高后再将设计库某一内容添加进来。</p>\n<blockquote>\n<p>TIPS:可以将最初版所有内容包含进来的依赖关系图中拿走但不会使游戏毫无意义的内容全部拿走,剩下的就是核心玩法,核心玩法常常可以用于定义某一游戏的类型,尽早完成核心玩法的开发,可以让项目尽快开始进行测试及迭代。 </p>\n</blockquote>"},{"title":"游戏评测-Balatro小丑牌","date":"2024-06-09T16:00:00.000Z","updated":"2024-06-09T16:00:00.000Z","_content":"\n## 概述\nBalatro是一款牌组构筑式类rogue游戏,玩家可以依照德州扑克的出牌规则,通过出牌弃牌两个简单的行为积累分数,当分数高于当前盲注要求的分数时便通过该盲注,每次通过盲注时会进入商店,商店中售卖小丑牌、不同卡包,玩家可以通过购买小丑牌、卡包完成卡组的构筑。 \n<!-- More -->\n## 游玩体验\n我是一个较深度的卡牌rogue玩家,玩过并且通关最高难度了许多类似游戏,包括杀戮尖塔、怪物火车、邪恶冥刻等等,卡牌rogue通过构筑、计算克服高难度的游戏体验令我十分着迷,每个种子的差异也让重复游玩都有不一样的乐趣,Balatro作为一款优秀的牌组构筑式rogue自然也有以上的优点,此外它还有自己更加独特的体验。 \n在前十个小时的游玩过程中,我尝试将以往其他卡牌rogue的经验往Balatro身上套用,Balatro通过计算筹码和倍率的乘积得到一次出牌后的分数\n\n<div style=\"text-align:center\">\n\n![蓝色为筹码,红色为倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/计分板.png)\n\n</div> \n\n\n游戏中的小丑牌大概可以分为一下几种: \n加筹码的小丑牌\n\n<div style=\"text-align:center\">\n\n![蓝色小丑 效果为卡组中每个剩余的牌提供2筹码](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Blue_Joker.webp)\n\n</div> \n\n加倍率的小丑牌\n\n<div style=\"text-align:center\">\n\n![小丑 效果为+4倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Joker.webp)\n\n</div> \n\n乘倍率的小丑牌\n\n<div style=\"text-align:center\">\n\n![卡文迪许 效果为×3倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Cavendish.webp)\n\n</div> \n\n提供资源的小丑牌\n\n<div style=\"text-align:center\">\n\n![黄金小丑 效果为每回合后提供4金币](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Golden_Joker.webp)\n\n</div> \n\n改变规则的小丑牌\n\n<div style=\"text-align:center\">\n\n![四指 效果为同花和顺子仅需要4张牌](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Four_Fingers.webp)\n\n</div> \n \n游戏中还有一些消耗品:星球牌可以升级某一牌型的效果,但是我觉得除了高牌、对子以外其他牌型都有一定的不稳定性,也就是怕鬼抽;塔罗牌拥有许多效果,绝大多数拥有改造牌组的能力,但是我觉得提供的增益杯水车薪。\n于是乎我把重心全部放在拥有强力效果的小丑牌上,我将杀戮尖塔玩家群体的三端学说搬运了过来,将Balatro也分为三端,基础筹码端,基础倍率端,倍率成倍端,我基本上每一局都是拿一张加筹码的小丑牌,一张加倍率的小丑牌,剩下全拿乘倍率的小丑牌,用这个简单的思路,我很快就通关了最高难度金注,运气好的时候甚至打了个四连胜。 \n但是这样玩起来千篇一律,每一局都是差不多的赢差不多的输,我很快就感到了乏味,在玩Balatro的第15个小时便就失去了兴趣,于是乎我便想看看其他玩家是怎么玩这个游戏的,结果令我大吃一惊,我看到了钢k男爵、四指同花顺、人头流、同花五条等等极具想象力的构筑 \n\n<div style=\"text-align:center\">\n\n![同花顺原本是很难凑齐的强力牌型,但拥有四指后,变得十分容易凑出来](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/四指同花顺.png)\n\n</div> \n\n我迫不及待的打开游戏,开始试验起了不同玩法,其中有一局让我印象十分深刻,我凑齐了以下几个小丑牌 \n\n<div style=\"text-align:center\">\n\n![未断选票 效果为将每次出牌第一个计分的牌额外触发两次](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Hanging_Chad.webp)\n\n</div> \n\n\n<div style=\"text-align:center\">\n\n![微笑表情 效果为每个计分的人头牌提供+5倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Smiley_Face.webp)\n\n</div> \n\n<div style=\"text-align:center\">\n\n![人脸照 效果为每次出牌第一个计分的人头牌提供×2倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Photograph.webp)\n\n</div> \n\n再加上我通过塔罗牌改造的有大量玻璃人头牌的卡组,我随意一次出牌便可以突破十亿的分数,而以上这三张小丑牌都只是普通稀有度,十分容易凑齐。 \n\n## 总结\n通过尝试各种搭配,游戏体验变得极其丰富有趣,每一局游戏都变成了脑洞大开的实验,Balatro并没有像其他游戏那样的敌人,缺乏了些斗智斗勇的感觉,取而代之的便是将游戏的可能性提高到了一个新的高度,同时Balatro有一个不能忽略的优点,极其优秀的视听体验,当看着分数不停上涨时,动感的音效伴随计分板冒出的火焰,总能使我十分激动,每次打开卡包时的动画也让人眼前一亮。\n不过游戏并非没有缺点,事实上游戏的设计导致了很多局基本上没有玩家能够改变的余地,杀戮尖塔的顶级玩家可以做到最高难度500多连胜,几乎已经验证了玩家可以通过自身的决策赢下每一局,而Balatro目前为止最高连胜次数都没有超过十次,这反映出游戏设计可能并不完美,运气的因素有着过大的占比,此外,在我60h的游玩后,有许多构筑我仍然没有体验过,哪怕我刻意的去进行某个流派的构筑,成功构筑可能性也很低,尝试各种流派过于不稳定,胜率远远不如三端的玩法。\n总体而言,Balatro是一款十分优秀的卡牌rogue,瑕不掩瑜,近期的更新也对最高难度进行了调整,相信未来Balatro能够解决这些缺点,把如同实验室的玩法发挥到极致。\n\n\n>图片资源来源于[Balatro wiki](https://balatrogame.fandom.com/wiki/Balatro),如有侵权,联系删除。\n\n","source":"_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌.md","raw":"---\ntitle: 游戏评测-Balatro小丑牌\ndate: 2024-06-10\nupdated: 2024-06-10\npermalink: articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/\ncategories: FlyingfishFantasticfan\ntags: [游戏评测,小丑牌,Balatro]\n---\n\n## 概述\nBalatro是一款牌组构筑式类rogue游戏,玩家可以依照德州扑克的出牌规则,通过出牌弃牌两个简单的行为积累分数,当分数高于当前盲注要求的分数时便通过该盲注,每次通过盲注时会进入商店,商店中售卖小丑牌、不同卡包,玩家可以通过购买小丑牌、卡包完成卡组的构筑。 \n<!-- More -->\n## 游玩体验\n我是一个较深度的卡牌rogue玩家,玩过并且通关最高难度了许多类似游戏,包括杀戮尖塔、怪物火车、邪恶冥刻等等,卡牌rogue通过构筑、计算克服高难度的游戏体验令我十分着迷,每个种子的差异也让重复游玩都有不一样的乐趣,Balatro作为一款优秀的牌组构筑式rogue自然也有以上的优点,此外它还有自己更加独特的体验。 \n在前十个小时的游玩过程中,我尝试将以往其他卡牌rogue的经验往Balatro身上套用,Balatro通过计算筹码和倍率的乘积得到一次出牌后的分数\n\n<div style=\"text-align:center\">\n\n![蓝色为筹码,红色为倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/计分板.png)\n\n</div> \n\n\n游戏中的小丑牌大概可以分为一下几种: \n加筹码的小丑牌\n\n<div style=\"text-align:center\">\n\n![蓝色小丑 效果为卡组中每个剩余的牌提供2筹码](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Blue_Joker.webp)\n\n</div> \n\n加倍率的小丑牌\n\n<div style=\"text-align:center\">\n\n![小丑 效果为+4倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Joker.webp)\n\n</div> \n\n乘倍率的小丑牌\n\n<div style=\"text-align:center\">\n\n![卡文迪许 效果为×3倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Cavendish.webp)\n\n</div> \n\n提供资源的小丑牌\n\n<div style=\"text-align:center\">\n\n![黄金小丑 效果为每回合后提供4金币](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Golden_Joker.webp)\n\n</div> \n\n改变规则的小丑牌\n\n<div style=\"text-align:center\">\n\n![四指 效果为同花和顺子仅需要4张牌](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Four_Fingers.webp)\n\n</div> \n \n游戏中还有一些消耗品:星球牌可以升级某一牌型的效果,但是我觉得除了高牌、对子以外其他牌型都有一定的不稳定性,也就是怕鬼抽;塔罗牌拥有许多效果,绝大多数拥有改造牌组的能力,但是我觉得提供的增益杯水车薪。\n于是乎我把重心全部放在拥有强力效果的小丑牌上,我将杀戮尖塔玩家群体的三端学说搬运了过来,将Balatro也分为三端,基础筹码端,基础倍率端,倍率成倍端,我基本上每一局都是拿一张加筹码的小丑牌,一张加倍率的小丑牌,剩下全拿乘倍率的小丑牌,用这个简单的思路,我很快就通关了最高难度金注,运气好的时候甚至打了个四连胜。 \n但是这样玩起来千篇一律,每一局都是差不多的赢差不多的输,我很快就感到了乏味,在玩Balatro的第15个小时便就失去了兴趣,于是乎我便想看看其他玩家是怎么玩这个游戏的,结果令我大吃一惊,我看到了钢k男爵、四指同花顺、人头流、同花五条等等极具想象力的构筑 \n\n<div style=\"text-align:center\">\n\n![同花顺原本是很难凑齐的强力牌型,但拥有四指后,变得十分容易凑出来](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/四指同花顺.png)\n\n</div> \n\n我迫不及待的打开游戏,开始试验起了不同玩法,其中有一局让我印象十分深刻,我凑齐了以下几个小丑牌 \n\n<div style=\"text-align:center\">\n\n![未断选票 效果为将每次出牌第一个计分的牌额外触发两次](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Hanging_Chad.webp)\n\n</div> \n\n\n<div style=\"text-align:center\">\n\n![微笑表情 效果为每个计分的人头牌提供+5倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Smiley_Face.webp)\n\n</div> \n\n<div style=\"text-align:center\">\n\n![人脸照 效果为每次出牌第一个计分的人头牌提供×2倍率](articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Photograph.webp)\n\n</div> \n\n再加上我通过塔罗牌改造的有大量玻璃人头牌的卡组,我随意一次出牌便可以突破十亿的分数,而以上这三张小丑牌都只是普通稀有度,十分容易凑齐。 \n\n## 总结\n通过尝试各种搭配,游戏体验变得极其丰富有趣,每一局游戏都变成了脑洞大开的实验,Balatro并没有像其他游戏那样的敌人,缺乏了些斗智斗勇的感觉,取而代之的便是将游戏的可能性提高到了一个新的高度,同时Balatro有一个不能忽略的优点,极其优秀的视听体验,当看着分数不停上涨时,动感的音效伴随计分板冒出的火焰,总能使我十分激动,每次打开卡包时的动画也让人眼前一亮。\n不过游戏并非没有缺点,事实上游戏的设计导致了很多局基本上没有玩家能够改变的余地,杀戮尖塔的顶级玩家可以做到最高难度500多连胜,几乎已经验证了玩家可以通过自身的决策赢下每一局,而Balatro目前为止最高连胜次数都没有超过十次,这反映出游戏设计可能并不完美,运气的因素有着过大的占比,此外,在我60h的游玩后,有许多构筑我仍然没有体验过,哪怕我刻意的去进行某个流派的构筑,成功构筑可能性也很低,尝试各种流派过于不稳定,胜率远远不如三端的玩法。\n总体而言,Balatro是一款十分优秀的卡牌rogue,瑕不掩瑜,近期的更新也对最高难度进行了调整,相信未来Balatro能够解决这些缺点,把如同实验室的玩法发挥到极致。\n\n\n>图片资源来源于[Balatro wiki](https://balatrogame.fandom.com/wiki/Balatro),如有侵权,联系删除。\n\n","slug":"FlyingfishFantasticfan/游戏评测-Balatro小丑牌","published":1,"__permalink":"articles/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg90009o8ye3b9e4vsg","content":"<h2 id=\"概述\"><a href=\"#概述\" class=\"headerlink\" title=\"概述\"></a>概述</h2><p>Balatro是一款牌组构筑式类rogue游戏,玩家可以依照德州扑克的出牌规则,通过出牌弃牌两个简单的行为积累分数,当分数高于当前盲注要求的分数时便通过该盲注,每次通过盲注时会进入商店,商店中售卖小丑牌、不同卡包,玩家可以通过购买小丑牌、卡包完成卡组的构筑。 </p>\n<span id=\"more\"></span>\n<h2 id=\"游玩体验\"><a href=\"#游玩体验\" class=\"headerlink\" title=\"游玩体验\"></a>游玩体验</h2><p>我是一个较深度的卡牌rogue玩家,玩过并且通关最高难度了许多类似游戏,包括杀戮尖塔、怪物火车、邪恶冥刻等等,卡牌rogue通过构筑、计算克服高难度的游戏体验令我十分着迷,每个种子的差异也让重复游玩都有不一样的乐趣,Balatro作为一款优秀的牌组构筑式rogue自然也有以上的优点,此外它还有自己更加独特的体验。<br>在前十个小时的游玩过程中,我尝试将以往其他卡牌rogue的经验往Balatro身上套用,Balatro通过计算筹码和倍率的乘积得到一次出牌后的分数</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/%E8%AE%A1%E5%88%86%E6%9D%BF.png\" alt=\"蓝色为筹码,红色为倍率\"></p>\n</div> \n\n\n<p>游戏中的小丑牌大概可以分为一下几种:<br>加筹码的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Blue_Joker.webp\" alt=\"蓝色小丑 效果为卡组中每个剩余的牌提供2筹码\"></p>\n</div> \n\n<p>加倍率的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Joker.webp\" alt=\"小丑 效果为+4倍率\"></p>\n</div> \n\n<p>乘倍率的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Cavendish.webp\" alt=\"卡文迪许 效果为×3倍率\"></p>\n</div> \n\n<p>提供资源的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Golden_Joker.webp\" alt=\"黄金小丑 效果为每回合后提供4金币\"></p>\n</div> \n\n<p>改变规则的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Four_Fingers.webp\" alt=\"四指 效果为同花和顺子仅需要4张牌\"></p>\n</div> \n \n<p>游戏中还有一些消耗品:星球牌可以升级某一牌型的效果,但是我觉得除了高牌、对子以外其他牌型都有一定的不稳定性,也就是怕鬼抽;塔罗牌拥有许多效果,绝大多数拥有改造牌组的能力,但是我觉得提供的增益杯水车薪。<br>于是乎我把重心全部放在拥有强力效果的小丑牌上,我将杀戮尖塔玩家群体的三端学说搬运了过来,将Balatro也分为三端,基础筹码端,基础倍率端,倍率成倍端,我基本上每一局都是拿一张加筹码的小丑牌,一张加倍率的小丑牌,剩下全拿乘倍率的小丑牌,用这个简单的思路,我很快就通关了最高难度金注,运气好的时候甚至打了个四连胜。<br>但是这样玩起来千篇一律,每一局都是差不多的赢差不多的输,我很快就感到了乏味,在玩Balatro的第15个小时便就失去了兴趣,于是乎我便想看看其他玩家是怎么玩这个游戏的,结果令我大吃一惊,我看到了钢k男爵、四指同花顺、人头流、同花五条等等极具想象力的构筑 </p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/%E5%9B%9B%E6%8C%87%E5%90%8C%E8%8A%B1%E9%A1%BA.png\" alt=\"同花顺原本是很难凑齐的强力牌型,但拥有四指后,变得十分容易凑出来\"></p>\n</div> \n\n<p>我迫不及待的打开游戏,开始试验起了不同玩法,其中有一局让我印象十分深刻,我凑齐了以下几个小丑牌 </p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Hanging_Chad.webp\" alt=\"未断选票 效果为将每次出牌第一个计分的牌额外触发两次\"></p>\n</div> \n\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Smiley_Face.webp\" alt=\"微笑表情 效果为每个计分的人头牌提供+5倍率\"></p>\n</div> \n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Photograph.webp\" alt=\"人脸照 效果为每次出牌第一个计分的人头牌提供×2倍率\"></p>\n</div> \n\n<p>再加上我通过塔罗牌改造的有大量玻璃人头牌的卡组,我随意一次出牌便可以突破十亿的分数,而以上这三张小丑牌都只是普通稀有度,十分容易凑齐。 </p>\n<h2 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h2><p>通过尝试各种搭配,游戏体验变得极其丰富有趣,每一局游戏都变成了脑洞大开的实验,Balatro并没有像其他游戏那样的敌人,缺乏了些斗智斗勇的感觉,取而代之的便是将游戏的可能性提高到了一个新的高度,同时Balatro有一个不能忽略的优点,极其优秀的视听体验,当看着分数不停上涨时,动感的音效伴随计分板冒出的火焰,总能使我十分激动,每次打开卡包时的动画也让人眼前一亮。<br>不过游戏并非没有缺点,事实上游戏的设计导致了很多局基本上没有玩家能够改变的余地,杀戮尖塔的顶级玩家可以做到最高难度500多连胜,几乎已经验证了玩家可以通过自身的决策赢下每一局,而Balatro目前为止最高连胜次数都没有超过十次,这反映出游戏设计可能并不完美,运气的因素有着过大的占比,此外,在我60h的游玩后,有许多构筑我仍然没有体验过,哪怕我刻意的去进行某个流派的构筑,成功构筑可能性也很低,尝试各种流派过于不稳定,胜率远远不如三端的玩法。<br>总体而言,Balatro是一款十分优秀的卡牌rogue,瑕不掩瑜,近期的更新也对最高难度进行了调整,相信未来Balatro能够解决这些缺点,把如同实验室的玩法发挥到极致。</p>\n<blockquote>\n<p>图片资源来源于<a href=\"https://balatrogame.fandom.com/wiki/Balatro\">Balatro wiki</a>,如有侵权,联系删除。</p>\n</blockquote>\n","site":{"data":{}},"excerpt":"<h2 id=\"概述\"><a href=\"#概述\" class=\"headerlink\" title=\"概述\"></a>概述</h2><p>Balatro是一款牌组构筑式类rogue游戏,玩家可以依照德州扑克的出牌规则,通过出牌弃牌两个简单的行为积累分数,当分数高于当前盲注要求的分数时便通过该盲注,每次通过盲注时会进入商店,商店中售卖小丑牌、不同卡包,玩家可以通过购买小丑牌、卡包完成卡组的构筑。 </p>","more":"<h2 id=\"游玩体验\"><a href=\"#游玩体验\" class=\"headerlink\" title=\"游玩体验\"></a>游玩体验</h2><p>我是一个较深度的卡牌rogue玩家,玩过并且通关最高难度了许多类似游戏,包括杀戮尖塔、怪物火车、邪恶冥刻等等,卡牌rogue通过构筑、计算克服高难度的游戏体验令我十分着迷,每个种子的差异也让重复游玩都有不一样的乐趣,Balatro作为一款优秀的牌组构筑式rogue自然也有以上的优点,此外它还有自己更加独特的体验。<br>在前十个小时的游玩过程中,我尝试将以往其他卡牌rogue的经验往Balatro身上套用,Balatro通过计算筹码和倍率的乘积得到一次出牌后的分数</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/%E8%AE%A1%E5%88%86%E6%9D%BF.png\" alt=\"蓝色为筹码,红色为倍率\"></p>\n</div> \n\n\n<p>游戏中的小丑牌大概可以分为一下几种:<br>加筹码的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Blue_Joker.webp\" alt=\"蓝色小丑 效果为卡组中每个剩余的牌提供2筹码\"></p>\n</div> \n\n<p>加倍率的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Joker.webp\" alt=\"小丑 效果为+4倍率\"></p>\n</div> \n\n<p>乘倍率的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Cavendish.webp\" alt=\"卡文迪许 效果为×3倍率\"></p>\n</div> \n\n<p>提供资源的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Golden_Joker.webp\" alt=\"黄金小丑 效果为每回合后提供4金币\"></p>\n</div> \n\n<p>改变规则的小丑牌</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Four_Fingers.webp\" alt=\"四指 效果为同花和顺子仅需要4张牌\"></p>\n</div> \n \n<p>游戏中还有一些消耗品:星球牌可以升级某一牌型的效果,但是我觉得除了高牌、对子以外其他牌型都有一定的不稳定性,也就是怕鬼抽;塔罗牌拥有许多效果,绝大多数拥有改造牌组的能力,但是我觉得提供的增益杯水车薪。<br>于是乎我把重心全部放在拥有强力效果的小丑牌上,我将杀戮尖塔玩家群体的三端学说搬运了过来,将Balatro也分为三端,基础筹码端,基础倍率端,倍率成倍端,我基本上每一局都是拿一张加筹码的小丑牌,一张加倍率的小丑牌,剩下全拿乘倍率的小丑牌,用这个简单的思路,我很快就通关了最高难度金注,运气好的时候甚至打了个四连胜。<br>但是这样玩起来千篇一律,每一局都是差不多的赢差不多的输,我很快就感到了乏味,在玩Balatro的第15个小时便就失去了兴趣,于是乎我便想看看其他玩家是怎么玩这个游戏的,结果令我大吃一惊,我看到了钢k男爵、四指同花顺、人头流、同花五条等等极具想象力的构筑 </p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/%E5%9B%9B%E6%8C%87%E5%90%8C%E8%8A%B1%E9%A1%BA.png\" alt=\"同花顺原本是很难凑齐的强力牌型,但拥有四指后,变得十分容易凑出来\"></p>\n</div> \n\n<p>我迫不及待的打开游戏,开始试验起了不同玩法,其中有一局让我印象十分深刻,我凑齐了以下几个小丑牌 </p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Hanging_Chad.webp\" alt=\"未断选票 效果为将每次出牌第一个计分的牌额外触发两次\"></p>\n</div> \n\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Smiley_Face.webp\" alt=\"微笑表情 效果为每个计分的人头牌提供+5倍率\"></p>\n</div> \n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/FlyingfishFantasticfan/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B-Balatro%E5%B0%8F%E4%B8%91%E7%89%8C/Photograph.webp\" alt=\"人脸照 效果为每次出牌第一个计分的人头牌提供×2倍率\"></p>\n</div> \n\n<p>再加上我通过塔罗牌改造的有大量玻璃人头牌的卡组,我随意一次出牌便可以突破十亿的分数,而以上这三张小丑牌都只是普通稀有度,十分容易凑齐。 </p>\n<h2 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h2><p>通过尝试各种搭配,游戏体验变得极其丰富有趣,每一局游戏都变成了脑洞大开的实验,Balatro并没有像其他游戏那样的敌人,缺乏了些斗智斗勇的感觉,取而代之的便是将游戏的可能性提高到了一个新的高度,同时Balatro有一个不能忽略的优点,极其优秀的视听体验,当看着分数不停上涨时,动感的音效伴随计分板冒出的火焰,总能使我十分激动,每次打开卡包时的动画也让人眼前一亮。<br>不过游戏并非没有缺点,事实上游戏的设计导致了很多局基本上没有玩家能够改变的余地,杀戮尖塔的顶级玩家可以做到最高难度500多连胜,几乎已经验证了玩家可以通过自身的决策赢下每一局,而Balatro目前为止最高连胜次数都没有超过十次,这反映出游戏设计可能并不完美,运气的因素有着过大的占比,此外,在我60h的游玩后,有许多构筑我仍然没有体验过,哪怕我刻意的去进行某个流派的构筑,成功构筑可能性也很低,尝试各种流派过于不稳定,胜率远远不如三端的玩法。<br>总体而言,Balatro是一款十分优秀的卡牌rogue,瑕不掩瑜,近期的更新也对最高难度进行了调整,相信未来Balatro能够解决这些缺点,把如同实验室的玩法发挥到极致。</p>\n<blockquote>\n<p>图片资源来源于<a href=\"https://balatrogame.fandom.com/wiki/Balatro\">Balatro wiki</a>,如有侵权,联系删除。</p>\n</blockquote>"},{"title":"mytest","date":"2024-05-27T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"\n这一次一定要可以,啊!!!\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n![ICON](articles/Demo/HelloWorld/avatar.png)\n\n</div>","source":"_posts/Touyouta/Demo.md","raw":"---\ntitle: mytest\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/Demo/Touyouta/\ncategories: Touyouta\ntags: [测试]\n---\n\n这一次一定要可以,啊!!!\n\n<!-- More -->\n\n<div style=\"text-align:center\">\n\n![ICON](articles/Demo/HelloWorld/avatar.png)\n\n</div>","slug":"Touyouta/Demo","published":1,"__permalink":"articles/Demo/Touyouta/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hg9000ao8yebxc71iym","content":"<p>这一次一定要可以,啊!!!</p>\n<span id=\"more\"></span>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Demo/HelloWorld/avatar.png\" alt=\"ICON\"></p>\n</div>","site":{"data":{}},"excerpt":"<p>这一次一定要可以,啊!!!</p>","more":"<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Demo/HelloWorld/avatar.png\" alt=\"ICON\"></p>\n</div>"},{"title":"自己设计一个游戏通用的2D摄像机累。Camera2D","date":"2024-06-03T16:00:00.000Z","updated":"2024-06-03T16:00:00.000Z","_content":"在2D游戏开发中,摄像机是一个至关重要的组件,允许开发者控制玩家的视角,决定他们能看到游戏世界的哪些部分。这对于引导玩家的注意力和提供沉浸式体验非常重要,在战斗场景中聚焦于战斗区域;而在探索场景中扩大视野以展示更多的环境细节,跟随主要角色移动,确保玩家始终能够看到控制中的角色和周围的环境,将摄像机焦点对准可交互对象,用来提示玩家这些对象的存在和重要性,还可以用来实现特殊效果,如震动或动态缩放等,在下文中我们将会实现这样一个摄像机类用于自己的游戏。\n![ICON](articles/QiNuoTu/Camera2D/1.gif)\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n## 一个合格的摄像机应该具有以下功能。\n 本人习惯已屏幕中心为基准处理数据,并且正向使用坐标,所有以下实现已本人使用舒适维主进行实现,我们来弄一些碎片吧。\n- **视口控制:**设置视口大小适应不同的分辨率和屏幕尺寸。\n```cpp\n void SetCameraCenter(short int Viewport_Width, short int Viewport_Height) {\n ViewportWidth = Viewport_Width;\n ViewportHeight = Viewport_Height;\n ViewportCenterX = ViewportWidth * 0.5f;\n ViewportCenterY = ViewportHeight * 0.5f;\n }\n```\n- **焦点跟随:**视点跟随焦点移动。\n```cpp\n void SetTarget(float targetX, float targetY) {\n TargetX = targetX;\n TargetY = targetY;\n }\n void SmoothMoveToPosition(float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n```\n- **坐标转换:**屏幕坐标与世界坐标之间转换,便于处理用户输入和游戏对象的位置。\n```cpp\n void ScreenToWorld(float screenX, float screenY, float& worldX, float& worldY) const {\n worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;\n worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;\n }\n\n void WorldToScreen(float worldX, float worldY, float& screenX, float& screenY) const {\n screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;\n screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;\n }\n```\n- **缩放功能:**适应不同的游戏场景和提供不同的视觉体验。\n```cpp\n float GetScale() const { return Zoom; }\n\n void SetScale(float zoom = 1)\n {\n Zoom = zoom;\n }\n```\n- **边界限制:**设置移动边界,防止摄像机移动到游戏世界之外。\n```cpp\n void SetWorldSize(float Width, float Height) {\n WorldBoundaryLeft = -Width * 0.5f;\n WorldBoundaryTop = -Height * 0.5f;\n WorldBoundaryRight = Width * 0.5f;\n WorldBoundaryBottom = Height * 0.5f;\n }\n\n bool SetWorldBoundaries(float left, float top, float right, float bottom) {\n if (left < right && top < bottom) {\n WorldBoundaryLeft = left;\n WorldBoundaryTop = top;\n WorldBoundaryRight = right;\n WorldBoundaryBottom = bottom;\n return true;\n }\n return false;\n }\n\n void ViewportCheckBoundaries() {\n float scaledOffsetX = ViewportCenterX / Zoom;\n float scaledOffsetY = ViewportCenterY / Zoom;\n CameraFocusX = std::max(WorldBoundaryLeft + scaledOffsetX, std::min(CameraFocusX, WorldBoundaryRight - scaledOffsetX));\n CameraFocusY = std::max(WorldBoundaryTop + scaledOffsetY, std::min(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));\n\n if (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {\n CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * 0.5f;\n }\n if (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {\n CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * 0.5f;\n }\n }\n```\n- **平滑过渡:**避免视角突变给玩家带来不适。\n```cpp\n void SmoothMoveToPosition(float targetX, float targetY, float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n\n void Scale(float zoom = 1){\n Zoom += zoom;\n }\n```\n- **抖动效果:**模拟冲击爆炸等效果来增强游戏的氛围和反馈。\n```cpp\n void Shake(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n CameraFocusX += disX(gen);\n CameraFocusY += disY(gen);\n }\n\n void ShakeCircle(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n std::uniform_real_distribution<float> angle(-360.0f, 360.0f);\n float radian = angle(gen) / 360 * m_PI * 2;\n CameraFocusX += disX(gen) * std::cos(radian);\n CameraFocusY += disY(gen) * std::sin(radian);\n }\n```\n## 此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\n```cpp\nclass Camera2D {\npublic:\n Camera2D(float Viewport_Width, float Viewport_Height,\n float World_Width, float World_Height,\n float FocusX = 0, float FocusY = 0) :\n ViewportCenterX(Viewport_Width * 0.5f),\n ViewportCenterY(Viewport_Height * 0.5f),\n ViewportWidth(Viewport_Width),\n ViewportHeight(Viewport_Height),\n WorldBoundaryLeft(-World_Width * 0.5),\n WorldBoundaryTop(-World_Height * 0.5),\n WorldBoundaryRight(World_Width * 0.5),\n WorldBoundaryBottom(World_Height * 0.5),\n TargetX(0),\n TargetY(0),\n CameraFocusX(FocusX),\n CameraFocusY(FocusY),\n Zoom(1){}\n\n ~Camera2D() = default;\n\n void ScreenToWorld(float screenX, float screenY, float& worldX, float& worldY) const {\n worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;\n worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;\n }\n\n void WorldToScreen(float worldX, float worldY, float& screenX, float& screenY) const {\n screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;\n screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;\n }\n\n float GetScale() const { return Zoom; }\n\n void SetScale(float zoom = 1)\n {\n Zoom = zoom;\n }\n\n void Scale(float zoom = 1)\n {\n Zoom += zoom;\n }\n\n void SmoothMoveToPosition(float targetX, float targetY, float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n\n void SetTarget(float targetX, float targetY) {\n TargetX = targetX;\n TargetY = targetY;\n }\n\n void SmoothMoveToTarget(float smoothing = 0.5f) {\n CameraFocusX += (TargetX - CameraFocusX) * smoothing;\n CameraFocusY += (TargetY - CameraFocusY) * smoothing;\n }\n\n void Shake(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n CameraFocusX += disX(gen);\n CameraFocusY += disY(gen);\n }\n\n void ShakeCircle(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n std::uniform_real_distribution<float> angle(-360.0f, 360.0f);\n float radian = angle(gen) / 360 * 3.1415926535 * 2;\n CameraFocusX += disX(gen) * std::cos(radian);\n CameraFocusY += disY(gen) * std::sin(radian);\n }\n\n void SetCameraCenter(short int Viewport_Width, short int Viewport_Height) {\n ViewportWidth = Viewport_Width;\n ViewportHeight = Viewport_Height;\n ViewportCenterX = ViewportWidth * 0.5f;\n ViewportCenterY = ViewportHeight * 0.5f;\n }\n\n void SetFocus(float FocusX, float FocusY) {\n CameraFocusX = FocusX;\n CameraFocusY = FocusY;\n }\n\n void Move(float deltaX, float deltaY) {\n CameraFocusX += deltaX;\n CameraFocusY += deltaY;\n }\n\n float GetFocusX() const { return CameraFocusX; }\n\n float GetFocusY() const { return CameraFocusY; }\n\n void SetWorldSize(float Width, float Height) {\n WorldBoundaryLeft = -Width * 0.5f;\n WorldBoundaryTop = -Height * 0.5f;\n WorldBoundaryRight = Width * 0.5f;\n WorldBoundaryBottom = Height * 0.5f;\n }\n\n bool SetWorldBoundaries(float left, float top, float right, float bottom) {\n if (left < right && top < bottom) {\n WorldBoundaryLeft = left;\n WorldBoundaryTop = top;\n WorldBoundaryRight = right;\n WorldBoundaryBottom = bottom;\n return true;\n }\n return false;\n }\n\n void ViewportCheckBoundaries() {\n float scaledOffsetX = ViewportCenterX / Zoom;\n float scaledOffsetY = ViewportCenterY / Zoom;\n CameraFocusX = std::max(WorldBoundaryLeft + scaledOffsetX, std::min(CameraFocusX, WorldBoundaryRight - scaledOffsetX));\n CameraFocusY = std::max(WorldBoundaryTop + scaledOffsetY, std::min(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));\n\n if (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {\n CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * 0.5f;\n }\n if (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {\n CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * 0.5f;\n }\n }\n\n void GetFocusRect(float& left, float& top, float& right, float& bottom) {\n left = CameraFocusX - ViewportCenterX;\n top = CameraFocusY - ViewportCenterY;\n right = CameraFocusX + ViewportCenterX;\n bottom = CameraFocusY + ViewportCenterY;\n }\n\nprivate:\n std::random_device rd;\n std::mt19937 gen(rd());\n float TargetX, TargetY;\n float CameraFocusX, CameraFocusY;\n float ViewportCenterX, ViewportCenterY, ViewportWidth, ViewportHeight;\n float Zoom, WorldBoundaryLeft, WorldBoundaryTop, WorldBoundaryRight, WorldBoundaryBottom;\n};\n```\n\n## 这是什么?\n![ICON](articles/QiNuoTu/Camera2D/2.png)\n","source":"_posts/QiNuoTu/Camera2D.md","raw":"---\ntitle: 自己设计一个游戏通用的2D摄像机累。Camera2D\ndate: 2024-06-4\nupdated: 2024-06-4\npermalink: articles/QiNuoTu/Camera2D/\ncategories: QiNuoTu\ntags: [教程,游戏开发]\n---\n在2D游戏开发中,摄像机是一个至关重要的组件,允许开发者控制玩家的视角,决定他们能看到游戏世界的哪些部分。这对于引导玩家的注意力和提供沉浸式体验非常重要,在战斗场景中聚焦于战斗区域;而在探索场景中扩大视野以展示更多的环境细节,跟随主要角色移动,确保玩家始终能够看到控制中的角色和周围的环境,将摄像机焦点对准可交互对象,用来提示玩家这些对象的存在和重要性,还可以用来实现特殊效果,如震动或动态缩放等,在下文中我们将会实现这样一个摄像机类用于自己的游戏。\n![ICON](articles/QiNuoTu/Camera2D/1.gif)\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n## 一个合格的摄像机应该具有以下功能。\n 本人习惯已屏幕中心为基准处理数据,并且正向使用坐标,所有以下实现已本人使用舒适维主进行实现,我们来弄一些碎片吧。\n- **视口控制:**设置视口大小适应不同的分辨率和屏幕尺寸。\n```cpp\n void SetCameraCenter(short int Viewport_Width, short int Viewport_Height) {\n ViewportWidth = Viewport_Width;\n ViewportHeight = Viewport_Height;\n ViewportCenterX = ViewportWidth * 0.5f;\n ViewportCenterY = ViewportHeight * 0.5f;\n }\n```\n- **焦点跟随:**视点跟随焦点移动。\n```cpp\n void SetTarget(float targetX, float targetY) {\n TargetX = targetX;\n TargetY = targetY;\n }\n void SmoothMoveToPosition(float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n```\n- **坐标转换:**屏幕坐标与世界坐标之间转换,便于处理用户输入和游戏对象的位置。\n```cpp\n void ScreenToWorld(float screenX, float screenY, float& worldX, float& worldY) const {\n worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;\n worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;\n }\n\n void WorldToScreen(float worldX, float worldY, float& screenX, float& screenY) const {\n screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;\n screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;\n }\n```\n- **缩放功能:**适应不同的游戏场景和提供不同的视觉体验。\n```cpp\n float GetScale() const { return Zoom; }\n\n void SetScale(float zoom = 1)\n {\n Zoom = zoom;\n }\n```\n- **边界限制:**设置移动边界,防止摄像机移动到游戏世界之外。\n```cpp\n void SetWorldSize(float Width, float Height) {\n WorldBoundaryLeft = -Width * 0.5f;\n WorldBoundaryTop = -Height * 0.5f;\n WorldBoundaryRight = Width * 0.5f;\n WorldBoundaryBottom = Height * 0.5f;\n }\n\n bool SetWorldBoundaries(float left, float top, float right, float bottom) {\n if (left < right && top < bottom) {\n WorldBoundaryLeft = left;\n WorldBoundaryTop = top;\n WorldBoundaryRight = right;\n WorldBoundaryBottom = bottom;\n return true;\n }\n return false;\n }\n\n void ViewportCheckBoundaries() {\n float scaledOffsetX = ViewportCenterX / Zoom;\n float scaledOffsetY = ViewportCenterY / Zoom;\n CameraFocusX = std::max(WorldBoundaryLeft + scaledOffsetX, std::min(CameraFocusX, WorldBoundaryRight - scaledOffsetX));\n CameraFocusY = std::max(WorldBoundaryTop + scaledOffsetY, std::min(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));\n\n if (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {\n CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * 0.5f;\n }\n if (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {\n CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * 0.5f;\n }\n }\n```\n- **平滑过渡:**避免视角突变给玩家带来不适。\n```cpp\n void SmoothMoveToPosition(float targetX, float targetY, float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n\n void Scale(float zoom = 1){\n Zoom += zoom;\n }\n```\n- **抖动效果:**模拟冲击爆炸等效果来增强游戏的氛围和反馈。\n```cpp\n void Shake(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n CameraFocusX += disX(gen);\n CameraFocusY += disY(gen);\n }\n\n void ShakeCircle(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n std::uniform_real_distribution<float> angle(-360.0f, 360.0f);\n float radian = angle(gen) / 360 * m_PI * 2;\n CameraFocusX += disX(gen) * std::cos(radian);\n CameraFocusY += disY(gen) * std::sin(radian);\n }\n```\n## 此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\n```cpp\nclass Camera2D {\npublic:\n Camera2D(float Viewport_Width, float Viewport_Height,\n float World_Width, float World_Height,\n float FocusX = 0, float FocusY = 0) :\n ViewportCenterX(Viewport_Width * 0.5f),\n ViewportCenterY(Viewport_Height * 0.5f),\n ViewportWidth(Viewport_Width),\n ViewportHeight(Viewport_Height),\n WorldBoundaryLeft(-World_Width * 0.5),\n WorldBoundaryTop(-World_Height * 0.5),\n WorldBoundaryRight(World_Width * 0.5),\n WorldBoundaryBottom(World_Height * 0.5),\n TargetX(0),\n TargetY(0),\n CameraFocusX(FocusX),\n CameraFocusY(FocusY),\n Zoom(1){}\n\n ~Camera2D() = default;\n\n void ScreenToWorld(float screenX, float screenY, float& worldX, float& worldY) const {\n worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;\n worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;\n }\n\n void WorldToScreen(float worldX, float worldY, float& screenX, float& screenY) const {\n screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;\n screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;\n }\n\n float GetScale() const { return Zoom; }\n\n void SetScale(float zoom = 1)\n {\n Zoom = zoom;\n }\n\n void Scale(float zoom = 1)\n {\n Zoom += zoom;\n }\n\n void SmoothMoveToPosition(float targetX, float targetY, float smoothing = 0.5f) {\n CameraFocusX += (targetX - CameraFocusX) * smoothing;\n CameraFocusY += (targetY - CameraFocusY) * smoothing;\n }\n\n void SetTarget(float targetX, float targetY) {\n TargetX = targetX;\n TargetY = targetY;\n }\n\n void SmoothMoveToTarget(float smoothing = 0.5f) {\n CameraFocusX += (TargetX - CameraFocusX) * smoothing;\n CameraFocusY += (TargetY - CameraFocusY) * smoothing;\n }\n\n void Shake(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n CameraFocusX += disX(gen);\n CameraFocusY += disY(gen);\n }\n\n void ShakeCircle(float intensityX = 5.5f, float intensityY = 5.5f) {\n std::uniform_real_distribution<float> disX(-intensityX, intensityX);\n std::uniform_real_distribution<float> disY(-intensityY, intensityY);\n std::uniform_real_distribution<float> angle(-360.0f, 360.0f);\n float radian = angle(gen) / 360 * 3.1415926535 * 2;\n CameraFocusX += disX(gen) * std::cos(radian);\n CameraFocusY += disY(gen) * std::sin(radian);\n }\n\n void SetCameraCenter(short int Viewport_Width, short int Viewport_Height) {\n ViewportWidth = Viewport_Width;\n ViewportHeight = Viewport_Height;\n ViewportCenterX = ViewportWidth * 0.5f;\n ViewportCenterY = ViewportHeight * 0.5f;\n }\n\n void SetFocus(float FocusX, float FocusY) {\n CameraFocusX = FocusX;\n CameraFocusY = FocusY;\n }\n\n void Move(float deltaX, float deltaY) {\n CameraFocusX += deltaX;\n CameraFocusY += deltaY;\n }\n\n float GetFocusX() const { return CameraFocusX; }\n\n float GetFocusY() const { return CameraFocusY; }\n\n void SetWorldSize(float Width, float Height) {\n WorldBoundaryLeft = -Width * 0.5f;\n WorldBoundaryTop = -Height * 0.5f;\n WorldBoundaryRight = Width * 0.5f;\n WorldBoundaryBottom = Height * 0.5f;\n }\n\n bool SetWorldBoundaries(float left, float top, float right, float bottom) {\n if (left < right && top < bottom) {\n WorldBoundaryLeft = left;\n WorldBoundaryTop = top;\n WorldBoundaryRight = right;\n WorldBoundaryBottom = bottom;\n return true;\n }\n return false;\n }\n\n void ViewportCheckBoundaries() {\n float scaledOffsetX = ViewportCenterX / Zoom;\n float scaledOffsetY = ViewportCenterY / Zoom;\n CameraFocusX = std::max(WorldBoundaryLeft + scaledOffsetX, std::min(CameraFocusX, WorldBoundaryRight - scaledOffsetX));\n CameraFocusY = std::max(WorldBoundaryTop + scaledOffsetY, std::min(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));\n\n if (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {\n CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * 0.5f;\n }\n if (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {\n CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * 0.5f;\n }\n }\n\n void GetFocusRect(float& left, float& top, float& right, float& bottom) {\n left = CameraFocusX - ViewportCenterX;\n top = CameraFocusY - ViewportCenterY;\n right = CameraFocusX + ViewportCenterX;\n bottom = CameraFocusY + ViewportCenterY;\n }\n\nprivate:\n std::random_device rd;\n std::mt19937 gen(rd());\n float TargetX, TargetY;\n float CameraFocusX, CameraFocusY;\n float ViewportCenterX, ViewportCenterY, ViewportWidth, ViewportHeight;\n float Zoom, WorldBoundaryLeft, WorldBoundaryTop, WorldBoundaryRight, WorldBoundaryBottom;\n};\n```\n\n## 这是什么?\n![ICON](articles/QiNuoTu/Camera2D/2.png)\n","slug":"QiNuoTu/Camera2D","published":1,"__permalink":"articles/QiNuoTu/Camera2D/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hga000eo8ye55wzathg","content":"<p>在2D游戏开发中,摄像机是一个至关重要的组件,允许开发者控制玩家的视角,决定他们能看到游戏世界的哪些部分。这对于引导玩家的注意力和提供沉浸式体验非常重要,在战斗场景中聚焦于战斗区域;而在探索场景中扩大视野以展示更多的环境细节,跟随主要角色移动,确保玩家始终能够看到控制中的角色和周围的环境,将摄像机焦点对准可交互对象,用来提示玩家这些对象的存在和重要性,还可以用来实现特殊效果,如震动或动态缩放等,在下文中我们将会实现这样一个摄像机类用于自己的游戏。<br><img src=\"/articles/QiNuoTu/Camera2D/1.gif\" alt=\"ICON\"></p>\n<span id=\"more\"></span>\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h2 id=\"一个合格的摄像机应该具有以下功能。\"><a href=\"#一个合格的摄像机应该具有以下功能。\" class=\"headerlink\" title=\"一个合格的摄像机应该具有以下功能。\"></a>一个合格的摄像机应该具有以下功能。</h2><pre><code>本人习惯已屏幕中心为基准处理数据,并且正向使用坐标,所有以下实现已本人使用舒适维主进行实现,我们来弄一些碎片吧。\n</code></pre>\n<ul>\n<li><strong>视口控制:</strong>设置视口大小适应不同的分辨率和屏幕尺寸。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetCameraCenter</span><span class=\"params\">(<span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Width, <span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Height)</span> </span>{</span><br><span class=\"line\"> ViewportWidth = Viewport_Width;</span><br><span class=\"line\"> ViewportHeight = Viewport_Height;</span><br><span class=\"line\"> ViewportCenterX = ViewportWidth * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> ViewportCenterY = ViewportHeight * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>焦点跟随:</strong>视点跟随焦点移动。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetTarget</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY)</span> </span>{</span><br><span class=\"line\"> TargetX = targetX;</span><br><span class=\"line\"> TargetY = targetY;</span><br><span class=\"line\">}</span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>坐标转换:</strong>屏幕坐标与世界坐标之间转换,便于处理用户输入和游戏对象的位置。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ScreenToWorld</span><span class=\"params\">(<span class=\"type\">float</span> screenX, <span class=\"type\">float</span> screenY, <span class=\"type\">float</span>& worldX, <span class=\"type\">float</span>& worldY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;</span><br><span class=\"line\"> worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">WorldToScreen</span><span class=\"params\">(<span class=\"type\">float</span> worldX, <span class=\"type\">float</span> worldY, <span class=\"type\">float</span>& screenX, <span class=\"type\">float</span>& screenY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;</span><br><span class=\"line\"> screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>缩放功能:</strong>适应不同的游戏场景和提供不同的视觉体验。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetScale</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> Zoom; }</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetScale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> Zoom = zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>边界限制:</strong>设置移动边界,防止摄像机移动到游戏世界之外。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetWorldSize</span><span class=\"params\">(<span class=\"type\">float</span> Width, <span class=\"type\">float</span> Height)</span> </span>{</span><br><span class=\"line\"> WorldBoundaryLeft = -Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryTop = -Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryRight = Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryBottom = Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">SetWorldBoundaries</span><span class=\"params\">(<span class=\"type\">float</span> left, <span class=\"type\">float</span> top, <span class=\"type\">float</span> right, <span class=\"type\">float</span> bottom)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (left < right && top < bottom) {</span><br><span class=\"line\"> WorldBoundaryLeft = left;</span><br><span class=\"line\"> WorldBoundaryTop = top;</span><br><span class=\"line\"> WorldBoundaryRight = right;</span><br><span class=\"line\"> WorldBoundaryBottom = bottom;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ViewportCheckBoundaries</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetX = ViewportCenterX / Zoom;</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetY = ViewportCenterY / Zoom;</span><br><span class=\"line\"> CameraFocusX = std::<span class=\"built_in\">max</span>(WorldBoundaryLeft + scaledOffsetX, std::<span class=\"built_in\">min</span>(CameraFocusX, WorldBoundaryRight - scaledOffsetX));</span><br><span class=\"line\"> CameraFocusY = std::<span class=\"built_in\">max</span>(WorldBoundaryTop + scaledOffsetY, std::<span class=\"built_in\">min</span>(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {</span><br><span class=\"line\"> CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {</span><br><span class=\"line\"> CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>平滑过渡:</strong>避免视角突变给玩家带来不适。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY, <span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Scale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span>{</span><br><span class=\"line\"> Zoom += zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>抖动效果:</strong>模拟冲击爆炸等效果来增强游戏的氛围和反馈。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Shake</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ShakeCircle</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">angle</span><span class=\"params\">(<span class=\"number\">-360.0f</span>, <span class=\"number\">360.0f</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> radian = <span class=\"built_in\">angle</span>(gen) / <span class=\"number\">360</span> * m_PI * <span class=\"number\">2</span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen) * std::<span class=\"built_in\">cos</span>(radian);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen) * std::<span class=\"built_in\">sin</span>(radian);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h2 id=\"此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\"><a href=\"#此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\" class=\"headerlink\" title=\"此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\"></a>此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">class</span> <span class=\"title class_\">Camera2D</span> {</span><br><span class=\"line\"><span class=\"keyword\">public</span>:</span><br><span class=\"line\"> <span class=\"built_in\">Camera2D</span>(<span class=\"type\">float</span> Viewport_Width, <span class=\"type\">float</span> Viewport_Height,</span><br><span class=\"line\"> <span class=\"type\">float</span> World_Width, <span class=\"type\">float</span> World_Height,</span><br><span class=\"line\"> <span class=\"type\">float</span> FocusX = <span class=\"number\">0</span>, <span class=\"type\">float</span> FocusY = <span class=\"number\">0</span>) :</span><br><span class=\"line\"> <span class=\"built_in\">ViewportCenterX</span>(Viewport_Width * <span class=\"number\">0.5f</span>),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportCenterY</span>(Viewport_Height * <span class=\"number\">0.5f</span>),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportWidth</span>(Viewport_Width),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportHeight</span>(Viewport_Height),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryLeft</span>(-World_Width * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryTop</span>(-World_Height * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryRight</span>(World_Width * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryBottom</span>(World_Height * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">TargetX</span>(<span class=\"number\">0</span>),</span><br><span class=\"line\"> <span class=\"built_in\">TargetY</span>(<span class=\"number\">0</span>),</span><br><span class=\"line\"> <span class=\"built_in\">CameraFocusX</span>(FocusX),</span><br><span class=\"line\"> <span class=\"built_in\">CameraFocusY</span>(FocusY),</span><br><span class=\"line\"> <span class=\"built_in\">Zoom</span>(<span class=\"number\">1</span>){}</span><br><span class=\"line\"></span><br><span class=\"line\"> ~<span class=\"built_in\">Camera2D</span>() = <span class=\"keyword\">default</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ScreenToWorld</span><span class=\"params\">(<span class=\"type\">float</span> screenX, <span class=\"type\">float</span> screenY, <span class=\"type\">float</span>& worldX, <span class=\"type\">float</span>& worldY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;</span><br><span class=\"line\"> worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">WorldToScreen</span><span class=\"params\">(<span class=\"type\">float</span> worldX, <span class=\"type\">float</span> worldY, <span class=\"type\">float</span>& screenX, <span class=\"type\">float</span>& screenY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;</span><br><span class=\"line\"> screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetScale</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> Zoom; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetScale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Zoom = zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Scale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Zoom += zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY, <span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetTarget</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY)</span> </span>{</span><br><span class=\"line\"> TargetX = targetX;</span><br><span class=\"line\"> TargetY = targetY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToTarget</span><span class=\"params\">(<span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (TargetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (TargetY - CameraFocusY) * smoothing;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Shake</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ShakeCircle</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">angle</span><span class=\"params\">(<span class=\"number\">-360.0f</span>, <span class=\"number\">360.0f</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> radian = <span class=\"built_in\">angle</span>(gen) / <span class=\"number\">360</span> * <span class=\"number\">3.1415926535</span> * <span class=\"number\">2</span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen) * std::<span class=\"built_in\">cos</span>(radian);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen) * std::<span class=\"built_in\">sin</span>(radian);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetCameraCenter</span><span class=\"params\">(<span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Width, <span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Height)</span> </span>{</span><br><span class=\"line\"> ViewportWidth = Viewport_Width;</span><br><span class=\"line\"> ViewportHeight = Viewport_Height;</span><br><span class=\"line\"> ViewportCenterX = ViewportWidth * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> ViewportCenterY = ViewportHeight * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetFocus</span><span class=\"params\">(<span class=\"type\">float</span> FocusX, <span class=\"type\">float</span> FocusY)</span> </span>{</span><br><span class=\"line\"> CameraFocusX = FocusX;</span><br><span class=\"line\"> CameraFocusY = FocusY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Move</span><span class=\"params\">(<span class=\"type\">float</span> deltaX, <span class=\"type\">float</span> deltaY)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += deltaX;</span><br><span class=\"line\"> CameraFocusY += deltaY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetFocusX</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> CameraFocusX; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetFocusY</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> CameraFocusY; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetWorldSize</span><span class=\"params\">(<span class=\"type\">float</span> Width, <span class=\"type\">float</span> Height)</span> </span>{</span><br><span class=\"line\"> WorldBoundaryLeft = -Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryTop = -Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryRight = Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryBottom = Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">SetWorldBoundaries</span><span class=\"params\">(<span class=\"type\">float</span> left, <span class=\"type\">float</span> top, <span class=\"type\">float</span> right, <span class=\"type\">float</span> bottom)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (left < right && top < bottom) {</span><br><span class=\"line\"> WorldBoundaryLeft = left;</span><br><span class=\"line\"> WorldBoundaryTop = top;</span><br><span class=\"line\"> WorldBoundaryRight = right;</span><br><span class=\"line\"> WorldBoundaryBottom = bottom;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ViewportCheckBoundaries</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetX = ViewportCenterX / Zoom;</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetY = ViewportCenterY / Zoom;</span><br><span class=\"line\"> CameraFocusX = std::<span class=\"built_in\">max</span>(WorldBoundaryLeft + scaledOffsetX, std::<span class=\"built_in\">min</span>(CameraFocusX, WorldBoundaryRight - scaledOffsetX));</span><br><span class=\"line\"> CameraFocusY = std::<span class=\"built_in\">max</span>(WorldBoundaryTop + scaledOffsetY, std::<span class=\"built_in\">min</span>(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {</span><br><span class=\"line\"> CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {</span><br><span class=\"line\"> CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">GetFocusRect</span><span class=\"params\">(<span class=\"type\">float</span>& left, <span class=\"type\">float</span>& top, <span class=\"type\">float</span>& right, <span class=\"type\">float</span>& bottom)</span> </span>{</span><br><span class=\"line\"> left = CameraFocusX - ViewportCenterX;</span><br><span class=\"line\"> top = CameraFocusY - ViewportCenterY;</span><br><span class=\"line\"> right = CameraFocusX + ViewportCenterX;</span><br><span class=\"line\"> bottom = CameraFocusY + ViewportCenterY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">private</span>:</span><br><span class=\"line\"> std::random_device rd;</span><br><span class=\"line\"> <span class=\"function\">std::mt19937 <span class=\"title\">gen</span><span class=\"params\">(rd())</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> TargetX, TargetY;</span><br><span class=\"line\"> <span class=\"type\">float</span> CameraFocusX, CameraFocusY;</span><br><span class=\"line\"> <span class=\"type\">float</span> ViewportCenterX, ViewportCenterY, ViewportWidth, ViewportHeight;</span><br><span class=\"line\"> <span class=\"type\">float</span> Zoom, WorldBoundaryLeft, WorldBoundaryTop, WorldBoundaryRight, WorldBoundaryBottom;</span><br><span class=\"line\">};</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"这是什么\"><a href=\"#这是什么\" class=\"headerlink\" title=\"这是什么?\"></a>这是什么?</h2><p><img src=\"/articles/QiNuoTu/Camera2D/2.png\" alt=\"ICON\"></p>\n","site":{"data":{}},"excerpt":"<p>在2D游戏开发中,摄像机是一个至关重要的组件,允许开发者控制玩家的视角,决定他们能看到游戏世界的哪些部分。这对于引导玩家的注意力和提供沉浸式体验非常重要,在战斗场景中聚焦于战斗区域;而在探索场景中扩大视野以展示更多的环境细节,跟随主要角色移动,确保玩家始终能够看到控制中的角色和周围的环境,将摄像机焦点对准可交互对象,用来提示玩家这些对象的存在和重要性,还可以用来实现特殊效果,如震动或动态缩放等,在下文中我们将会实现这样一个摄像机类用于自己的游戏。<br><img src=\"/articles/QiNuoTu/Camera2D/1.gif\" alt=\"ICON\"></p>","more":"<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h2 id=\"一个合格的摄像机应该具有以下功能。\"><a href=\"#一个合格的摄像机应该具有以下功能。\" class=\"headerlink\" title=\"一个合格的摄像机应该具有以下功能。\"></a>一个合格的摄像机应该具有以下功能。</h2><pre><code>本人习惯已屏幕中心为基准处理数据,并且正向使用坐标,所有以下实现已本人使用舒适维主进行实现,我们来弄一些碎片吧。\n</code></pre>\n<ul>\n<li><strong>视口控制:</strong>设置视口大小适应不同的分辨率和屏幕尺寸。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetCameraCenter</span><span class=\"params\">(<span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Width, <span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Height)</span> </span>{</span><br><span class=\"line\"> ViewportWidth = Viewport_Width;</span><br><span class=\"line\"> ViewportHeight = Viewport_Height;</span><br><span class=\"line\"> ViewportCenterX = ViewportWidth * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> ViewportCenterY = ViewportHeight * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>焦点跟随:</strong>视点跟随焦点移动。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetTarget</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY)</span> </span>{</span><br><span class=\"line\"> TargetX = targetX;</span><br><span class=\"line\"> TargetY = targetY;</span><br><span class=\"line\">}</span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>坐标转换:</strong>屏幕坐标与世界坐标之间转换,便于处理用户输入和游戏对象的位置。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ScreenToWorld</span><span class=\"params\">(<span class=\"type\">float</span> screenX, <span class=\"type\">float</span> screenY, <span class=\"type\">float</span>& worldX, <span class=\"type\">float</span>& worldY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;</span><br><span class=\"line\"> worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">WorldToScreen</span><span class=\"params\">(<span class=\"type\">float</span> worldX, <span class=\"type\">float</span> worldY, <span class=\"type\">float</span>& screenX, <span class=\"type\">float</span>& screenY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;</span><br><span class=\"line\"> screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>缩放功能:</strong>适应不同的游戏场景和提供不同的视觉体验。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetScale</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> Zoom; }</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetScale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> Zoom = zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>边界限制:</strong>设置移动边界,防止摄像机移动到游戏世界之外。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetWorldSize</span><span class=\"params\">(<span class=\"type\">float</span> Width, <span class=\"type\">float</span> Height)</span> </span>{</span><br><span class=\"line\"> WorldBoundaryLeft = -Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryTop = -Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryRight = Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryBottom = Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">SetWorldBoundaries</span><span class=\"params\">(<span class=\"type\">float</span> left, <span class=\"type\">float</span> top, <span class=\"type\">float</span> right, <span class=\"type\">float</span> bottom)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (left < right && top < bottom) {</span><br><span class=\"line\"> WorldBoundaryLeft = left;</span><br><span class=\"line\"> WorldBoundaryTop = top;</span><br><span class=\"line\"> WorldBoundaryRight = right;</span><br><span class=\"line\"> WorldBoundaryBottom = bottom;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ViewportCheckBoundaries</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetX = ViewportCenterX / Zoom;</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetY = ViewportCenterY / Zoom;</span><br><span class=\"line\"> CameraFocusX = std::<span class=\"built_in\">max</span>(WorldBoundaryLeft + scaledOffsetX, std::<span class=\"built_in\">min</span>(CameraFocusX, WorldBoundaryRight - scaledOffsetX));</span><br><span class=\"line\"> CameraFocusY = std::<span class=\"built_in\">max</span>(WorldBoundaryTop + scaledOffsetY, std::<span class=\"built_in\">min</span>(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {</span><br><span class=\"line\"> CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {</span><br><span class=\"line\"> CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>平滑过渡:</strong>避免视角突变给玩家带来不适。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY, <span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Scale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span>{</span><br><span class=\"line\"> Zoom += zoom;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li><strong>抖动效果:</strong>模拟冲击爆炸等效果来增强游戏的氛围和反馈。<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Shake</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ShakeCircle</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">angle</span><span class=\"params\">(<span class=\"number\">-360.0f</span>, <span class=\"number\">360.0f</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> radian = <span class=\"built_in\">angle</span>(gen) / <span class=\"number\">360</span> * m_PI * <span class=\"number\">2</span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen) * std::<span class=\"built_in\">cos</span>(radian);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen) * std::<span class=\"built_in\">sin</span>(radian);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h2 id=\"此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\"><a href=\"#此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\" class=\"headerlink\" title=\"此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。\"></a>此刻Camera2D类的所有碎片都已经获得,我们把他拼起来吧。</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">class</span> <span class=\"title class_\">Camera2D</span> {</span><br><span class=\"line\"><span class=\"keyword\">public</span>:</span><br><span class=\"line\"> <span class=\"built_in\">Camera2D</span>(<span class=\"type\">float</span> Viewport_Width, <span class=\"type\">float</span> Viewport_Height,</span><br><span class=\"line\"> <span class=\"type\">float</span> World_Width, <span class=\"type\">float</span> World_Height,</span><br><span class=\"line\"> <span class=\"type\">float</span> FocusX = <span class=\"number\">0</span>, <span class=\"type\">float</span> FocusY = <span class=\"number\">0</span>) :</span><br><span class=\"line\"> <span class=\"built_in\">ViewportCenterX</span>(Viewport_Width * <span class=\"number\">0.5f</span>),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportCenterY</span>(Viewport_Height * <span class=\"number\">0.5f</span>),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportWidth</span>(Viewport_Width),</span><br><span class=\"line\"> <span class=\"built_in\">ViewportHeight</span>(Viewport_Height),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryLeft</span>(-World_Width * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryTop</span>(-World_Height * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryRight</span>(World_Width * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">WorldBoundaryBottom</span>(World_Height * <span class=\"number\">0.5</span>),</span><br><span class=\"line\"> <span class=\"built_in\">TargetX</span>(<span class=\"number\">0</span>),</span><br><span class=\"line\"> <span class=\"built_in\">TargetY</span>(<span class=\"number\">0</span>),</span><br><span class=\"line\"> <span class=\"built_in\">CameraFocusX</span>(FocusX),</span><br><span class=\"line\"> <span class=\"built_in\">CameraFocusY</span>(FocusY),</span><br><span class=\"line\"> <span class=\"built_in\">Zoom</span>(<span class=\"number\">1</span>){}</span><br><span class=\"line\"></span><br><span class=\"line\"> ~<span class=\"built_in\">Camera2D</span>() = <span class=\"keyword\">default</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ScreenToWorld</span><span class=\"params\">(<span class=\"type\">float</span> screenX, <span class=\"type\">float</span> screenY, <span class=\"type\">float</span>& worldX, <span class=\"type\">float</span>& worldY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> worldX = CameraFocusX - (screenX - ViewportCenterX) / Zoom;</span><br><span class=\"line\"> worldY = CameraFocusY - (screenY - ViewportCenterY) / Zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">WorldToScreen</span><span class=\"params\">(<span class=\"type\">float</span> worldX, <span class=\"type\">float</span> worldY, <span class=\"type\">float</span>& screenX, <span class=\"type\">float</span>& screenY)</span> <span class=\"type\">const</span> </span>{</span><br><span class=\"line\"> screenX = ViewportCenterX + (CameraFocusX - worldX) * Zoom;</span><br><span class=\"line\"> screenY = ViewportCenterY + (CameraFocusY - worldY) * Zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetScale</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> Zoom; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetScale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Zoom = zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Scale</span><span class=\"params\">(<span class=\"type\">float</span> zoom = <span class=\"number\">1</span>)</span></span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Zoom += zoom;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToPosition</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY, <span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (targetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (targetY - CameraFocusY) * smoothing;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetTarget</span><span class=\"params\">(<span class=\"type\">float</span> targetX, <span class=\"type\">float</span> targetY)</span> </span>{</span><br><span class=\"line\"> TargetX = targetX;</span><br><span class=\"line\"> TargetY = targetY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SmoothMoveToTarget</span><span class=\"params\">(<span class=\"type\">float</span> smoothing = <span class=\"number\">0.5f</span>)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += (TargetX - CameraFocusX) * smoothing;</span><br><span class=\"line\"> CameraFocusY += (TargetY - CameraFocusY) * smoothing;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Shake</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ShakeCircle</span><span class=\"params\">(<span class=\"type\">float</span> intensityX = <span class=\"number\">5.5f</span>, <span class=\"type\">float</span> intensityY = <span class=\"number\">5.5f</span>)</span> </span>{</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disX</span><span class=\"params\">(-intensityX, intensityX)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">disY</span><span class=\"params\">(-intensityY, intensityY)</span></span>;</span><br><span class=\"line\"> <span class=\"function\">std::uniform_real_distribution<<span class=\"type\">float</span>> <span class=\"title\">angle</span><span class=\"params\">(<span class=\"number\">-360.0f</span>, <span class=\"number\">360.0f</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> radian = <span class=\"built_in\">angle</span>(gen) / <span class=\"number\">360</span> * <span class=\"number\">3.1415926535</span> * <span class=\"number\">2</span>;</span><br><span class=\"line\"> CameraFocusX += <span class=\"built_in\">disX</span>(gen) * std::<span class=\"built_in\">cos</span>(radian);</span><br><span class=\"line\"> CameraFocusY += <span class=\"built_in\">disY</span>(gen) * std::<span class=\"built_in\">sin</span>(radian);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetCameraCenter</span><span class=\"params\">(<span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Width, <span class=\"type\">short</span> <span class=\"type\">int</span> Viewport_Height)</span> </span>{</span><br><span class=\"line\"> ViewportWidth = Viewport_Width;</span><br><span class=\"line\"> ViewportHeight = Viewport_Height;</span><br><span class=\"line\"> ViewportCenterX = ViewportWidth * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> ViewportCenterY = ViewportHeight * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetFocus</span><span class=\"params\">(<span class=\"type\">float</span> FocusX, <span class=\"type\">float</span> FocusY)</span> </span>{</span><br><span class=\"line\"> CameraFocusX = FocusX;</span><br><span class=\"line\"> CameraFocusY = FocusY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">Move</span><span class=\"params\">(<span class=\"type\">float</span> deltaX, <span class=\"type\">float</span> deltaY)</span> </span>{</span><br><span class=\"line\"> CameraFocusX += deltaX;</span><br><span class=\"line\"> CameraFocusY += deltaY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetFocusX</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> CameraFocusX; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">GetFocusY</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span>{ <span class=\"keyword\">return</span> CameraFocusY; }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">SetWorldSize</span><span class=\"params\">(<span class=\"type\">float</span> Width, <span class=\"type\">float</span> Height)</span> </span>{</span><br><span class=\"line\"> WorldBoundaryLeft = -Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryTop = -Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryRight = Width * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> WorldBoundaryBottom = Height * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">SetWorldBoundaries</span><span class=\"params\">(<span class=\"type\">float</span> left, <span class=\"type\">float</span> top, <span class=\"type\">float</span> right, <span class=\"type\">float</span> bottom)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (left < right && top < bottom) {</span><br><span class=\"line\"> WorldBoundaryLeft = left;</span><br><span class=\"line\"> WorldBoundaryTop = top;</span><br><span class=\"line\"> WorldBoundaryRight = right;</span><br><span class=\"line\"> WorldBoundaryBottom = bottom;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">ViewportCheckBoundaries</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetX = ViewportCenterX / Zoom;</span><br><span class=\"line\"> <span class=\"type\">float</span> scaledOffsetY = ViewportCenterY / Zoom;</span><br><span class=\"line\"> CameraFocusX = std::<span class=\"built_in\">max</span>(WorldBoundaryLeft + scaledOffsetX, std::<span class=\"built_in\">min</span>(CameraFocusX, WorldBoundaryRight - scaledOffsetX));</span><br><span class=\"line\"> CameraFocusY = std::<span class=\"built_in\">max</span>(WorldBoundaryTop + scaledOffsetY, std::<span class=\"built_in\">min</span>(CameraFocusY, WorldBoundaryBottom - scaledOffsetY));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportWidth / Zoom > WorldBoundaryRight - WorldBoundaryLeft) {</span><br><span class=\"line\"> CameraFocusX = (WorldBoundaryLeft + WorldBoundaryRight) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ViewportHeight / Zoom > WorldBoundaryBottom - WorldBoundaryTop) {</span><br><span class=\"line\"> CameraFocusY = (WorldBoundaryTop + WorldBoundaryBottom) * <span class=\"number\">0.5f</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">GetFocusRect</span><span class=\"params\">(<span class=\"type\">float</span>& left, <span class=\"type\">float</span>& top, <span class=\"type\">float</span>& right, <span class=\"type\">float</span>& bottom)</span> </span>{</span><br><span class=\"line\"> left = CameraFocusX - ViewportCenterX;</span><br><span class=\"line\"> top = CameraFocusY - ViewportCenterY;</span><br><span class=\"line\"> right = CameraFocusX + ViewportCenterX;</span><br><span class=\"line\"> bottom = CameraFocusY + ViewportCenterY;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">private</span>:</span><br><span class=\"line\"> std::random_device rd;</span><br><span class=\"line\"> <span class=\"function\">std::mt19937 <span class=\"title\">gen</span><span class=\"params\">(rd())</span></span>;</span><br><span class=\"line\"> <span class=\"type\">float</span> TargetX, TargetY;</span><br><span class=\"line\"> <span class=\"type\">float</span> CameraFocusX, CameraFocusY;</span><br><span class=\"line\"> <span class=\"type\">float</span> ViewportCenterX, ViewportCenterY, ViewportWidth, ViewportHeight;</span><br><span class=\"line\"> <span class=\"type\">float</span> Zoom, WorldBoundaryLeft, WorldBoundaryTop, WorldBoundaryRight, WorldBoundaryBottom;</span><br><span class=\"line\">};</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"这是什么\"><a href=\"#这是什么\" class=\"headerlink\" title=\"这是什么?\"></a>这是什么?</h2><p><img src=\"/articles/QiNuoTu/Camera2D/2.png\" alt=\"ICON\"></p>"},{"title":"保姆级!使用网页版在VoidGameSpace中发表文章与图文。Ciallo~","date":"2024-05-29T16:00:00.000Z","updated":"2024-06-03T16:00:00.000Z","_content":"保姆级!保姆级!保姆级!Ciallo~!\n每一步都有图文混合讲解!\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n# 第一步,先分叉一个VoidGameSpace的原始库\n- **1**: 点击蓝字进入[VoidGameSpace](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。\n进入后,会看到这样的页面。\n![ICON](articles/QiNuoTu/CorrectlyReleased/1.png)\n- **2**: 点击右上角的,Fork,如果不明白全部默认,点击绿色按钮即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/2.png)\n![ICON](articles/QiNuoTu/CorrectlyReleased/3.png)\n- **3**: 此刻你的库中就有了一份分叉文件,第一步完成。\n# 第二步,来到自己的库中,并进入GameDevWebsite项目。\n- **1**: 点击左上角的,点点点,标志。\n![ICON](articles/QiNuoTu/CorrectlyReleased/4.png)\n选择,自己名字加上斜杠的/GameDevWebsite项目,非常重要!\n![ICON](articles/QiNuoTu/CorrectlyReleased/5.png)\n- **2**: 这样就进入了自己库中的GameDevWebsite克隆项目。\n![ICON](articles/QiNuoTu/CorrectlyReleased/6.png)\n这里的头像变成自己的,就正确了。\n# 第三步,来到,_posts,文件夹。\n点击项目中的,source,文件夹。\n![ICON](articles/QiNuoTu/CorrectlyReleased/7.png)\n在点击,_posts,文件夹\n![ICON](articles/QiNuoTu/CorrectlyReleased/8.png)\n这里会有一大堆别人的文件夹,不需要管理。\n![ICON](articles/QiNuoTu/CorrectlyReleased/9.png)\n# 第四步,准备文章!\n此刻,网页上的操作已经完成,回到本地,用自己的名字创建一个文件夹。\n## 自己的名字!,不要抄我的名字!\n![ICON](articles/QiNuoTu/CorrectlyReleased/10.png)\n进入文件夹,使用你任何喜欢的md文件编辑器在其中创建一个文件,然后进入,开始编写。\n编写参阅,[VoidGameSpace](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。下方的说明。\n- **1**: 跳过上面的说明我们创建一个。\n![ICON](articles/QiNuoTu/CorrectlyReleased/11.png)\n- **2**: 打开,在头部添加以下内容。\n![ICON](articles/QiNuoTu/CorrectlyReleased/12.png)\npermalink: 不太好理解,不用担心,请往下看,\n它是这样的结构,permalink: articles/QiNuoTu/Demo/\n- **articles**: 可以理解为根目录,必须加上。\n- **QiNuoTu**: 这个是我的名字,一个示意,需要修改为你名字文件夹的名称。\n![ICON](articles/QiNuoTu/CorrectlyReleased/10.png)\n- **Demo**: 这个是你创建的当前文章的文件名,不要扩展名,但要加上,/,斜杠在尾部。\n![ICON](articles/QiNuoTu/CorrectlyReleased/13.png)\n这样一来,文章头就准备完毕了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/14.png)\n# 第五步,编写文章!\n- **1**: 在上面的截图可以注意到,文章头下面有一些白字,没错,这个可以当作简介,或者先到言,具体的文章内容需要在,` <!-- More --> ` 标记下书写\n![ICON](articles/QiNuoTu/CorrectlyReleased/15.png)\n- **2**: 如何添加图片,在文章旁边使用同名创建一个文件夹。\n![ICON](articles/QiNuoTu/CorrectlyReleased/16.png)\n- **3**: 将图片丢进文件夹中,就可以使用,`![ICON](articles/自己名称文件夹名/文件夹名/文件名.后缀名)`表达式引用图片了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/17.png)\n- **4**: 网页链接同理,`[名称](链接)`,表达式,即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/27.png)\n- **5**: 置入代码,只需要使用,` ```cpp 代码 ``` `将代码包裹其中即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/28.png)\n# 第六步,发表文章。\n- **1**: 回到网页,那一堆名字的文件夹的页面,点击右上角的,上传文件。\n![ICON](articles/QiNuoTu/CorrectlyReleased/18.png)\n- **2**: 把文件夹拖住丢上去。\n![ICON](articles/QiNuoTu/CorrectlyReleased/19.png)\n- **3**: 点击绿色按钮。\n![ICON](articles/QiNuoTu/CorrectlyReleased/20.png)\n- **4**: 之后就可以看到自己的文件夹了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/21.png)\n- **5**: 点进去!,就可以看到自己的md文件和文件夹什么的了,在提交之前,需要说明,建立文件夹克隆库一类都只需要做一次,每次发布只要弄文章md和图片文件夹上传到自己的文件夹中即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/22.png)\n# 第七步,提交!\n- **1**: 点击右上角的GameDevWebsite。\n![ICON](articles/QiNuoTu/CorrectlyReleased/23.png)\n- **2**: 找到,Contribote,点击绿色按钮!\n![ICON](articles/QiNuoTu/CorrectlyReleased/24.png)\n- **2**: 填写标题,点击绿色按钮!\n![ICON](articles/QiNuoTu/CorrectlyReleased/25.png)\n# 等待审核即可!\n![ICON](articles/QiNuoTu/CorrectlyReleased/26.png)\n\n# 这是什么?\n![ICON](articles/QiNuoTu/CorrectlyReleased/123415231.png)\n","source":"_posts/QiNuoTu/CorrectlyReleased.md","raw":"---\ntitle: 保姆级!使用网页版在VoidGameSpace中发表文章与图文。Ciallo~\ndate: 2024-05-30\nupdated: 2024-06-4\npermalink: articles/QiNuoTu/CorrectlyReleased/\ncategories: QiNuoTu\ntags: [教程]\n---\n保姆级!保姆级!保姆级!Ciallo~!\n每一步都有图文混合讲解!\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n# 第一步,先分叉一个VoidGameSpace的原始库\n- **1**: 点击蓝字进入[VoidGameSpace](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。\n进入后,会看到这样的页面。\n![ICON](articles/QiNuoTu/CorrectlyReleased/1.png)\n- **2**: 点击右上角的,Fork,如果不明白全部默认,点击绿色按钮即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/2.png)\n![ICON](articles/QiNuoTu/CorrectlyReleased/3.png)\n- **3**: 此刻你的库中就有了一份分叉文件,第一步完成。\n# 第二步,来到自己的库中,并进入GameDevWebsite项目。\n- **1**: 点击左上角的,点点点,标志。\n![ICON](articles/QiNuoTu/CorrectlyReleased/4.png)\n选择,自己名字加上斜杠的/GameDevWebsite项目,非常重要!\n![ICON](articles/QiNuoTu/CorrectlyReleased/5.png)\n- **2**: 这样就进入了自己库中的GameDevWebsite克隆项目。\n![ICON](articles/QiNuoTu/CorrectlyReleased/6.png)\n这里的头像变成自己的,就正确了。\n# 第三步,来到,_posts,文件夹。\n点击项目中的,source,文件夹。\n![ICON](articles/QiNuoTu/CorrectlyReleased/7.png)\n在点击,_posts,文件夹\n![ICON](articles/QiNuoTu/CorrectlyReleased/8.png)\n这里会有一大堆别人的文件夹,不需要管理。\n![ICON](articles/QiNuoTu/CorrectlyReleased/9.png)\n# 第四步,准备文章!\n此刻,网页上的操作已经完成,回到本地,用自己的名字创建一个文件夹。\n## 自己的名字!,不要抄我的名字!\n![ICON](articles/QiNuoTu/CorrectlyReleased/10.png)\n进入文件夹,使用你任何喜欢的md文件编辑器在其中创建一个文件,然后进入,开始编写。\n编写参阅,[VoidGameSpace](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。下方的说明。\n- **1**: 跳过上面的说明我们创建一个。\n![ICON](articles/QiNuoTu/CorrectlyReleased/11.png)\n- **2**: 打开,在头部添加以下内容。\n![ICON](articles/QiNuoTu/CorrectlyReleased/12.png)\npermalink: 不太好理解,不用担心,请往下看,\n它是这样的结构,permalink: articles/QiNuoTu/Demo/\n- **articles**: 可以理解为根目录,必须加上。\n- **QiNuoTu**: 这个是我的名字,一个示意,需要修改为你名字文件夹的名称。\n![ICON](articles/QiNuoTu/CorrectlyReleased/10.png)\n- **Demo**: 这个是你创建的当前文章的文件名,不要扩展名,但要加上,/,斜杠在尾部。\n![ICON](articles/QiNuoTu/CorrectlyReleased/13.png)\n这样一来,文章头就准备完毕了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/14.png)\n# 第五步,编写文章!\n- **1**: 在上面的截图可以注意到,文章头下面有一些白字,没错,这个可以当作简介,或者先到言,具体的文章内容需要在,` <!-- More --> ` 标记下书写\n![ICON](articles/QiNuoTu/CorrectlyReleased/15.png)\n- **2**: 如何添加图片,在文章旁边使用同名创建一个文件夹。\n![ICON](articles/QiNuoTu/CorrectlyReleased/16.png)\n- **3**: 将图片丢进文件夹中,就可以使用,`![ICON](articles/自己名称文件夹名/文件夹名/文件名.后缀名)`表达式引用图片了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/17.png)\n- **4**: 网页链接同理,`[名称](链接)`,表达式,即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/27.png)\n- **5**: 置入代码,只需要使用,` ```cpp 代码 ``` `将代码包裹其中即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/28.png)\n# 第六步,发表文章。\n- **1**: 回到网页,那一堆名字的文件夹的页面,点击右上角的,上传文件。\n![ICON](articles/QiNuoTu/CorrectlyReleased/18.png)\n- **2**: 把文件夹拖住丢上去。\n![ICON](articles/QiNuoTu/CorrectlyReleased/19.png)\n- **3**: 点击绿色按钮。\n![ICON](articles/QiNuoTu/CorrectlyReleased/20.png)\n- **4**: 之后就可以看到自己的文件夹了。\n![ICON](articles/QiNuoTu/CorrectlyReleased/21.png)\n- **5**: 点进去!,就可以看到自己的md文件和文件夹什么的了,在提交之前,需要说明,建立文件夹克隆库一类都只需要做一次,每次发布只要弄文章md和图片文件夹上传到自己的文件夹中即可。\n![ICON](articles/QiNuoTu/CorrectlyReleased/22.png)\n# 第七步,提交!\n- **1**: 点击右上角的GameDevWebsite。\n![ICON](articles/QiNuoTu/CorrectlyReleased/23.png)\n- **2**: 找到,Contribote,点击绿色按钮!\n![ICON](articles/QiNuoTu/CorrectlyReleased/24.png)\n- **2**: 填写标题,点击绿色按钮!\n![ICON](articles/QiNuoTu/CorrectlyReleased/25.png)\n# 等待审核即可!\n![ICON](articles/QiNuoTu/CorrectlyReleased/26.png)\n\n# 这是什么?\n![ICON](articles/QiNuoTu/CorrectlyReleased/123415231.png)\n","slug":"QiNuoTu/CorrectlyReleased","published":1,"__permalink":"articles/QiNuoTu/CorrectlyReleased/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hga000go8ye6epw1ygl","content":"<p>保姆级!保姆级!保姆级!Ciallo~!<br>每一步都有图文混合讲解!</p>\n<span id=\"more\"></span>\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h1 id=\"第一步,先分叉一个VoidGameSpace的原始库\"><a href=\"#第一步,先分叉一个VoidGameSpace的原始库\" class=\"headerlink\" title=\"第一步,先分叉一个VoidGameSpace的原始库\"></a>第一步,先分叉一个VoidGameSpace的原始库</h1><ul>\n<li><strong>1</strong>: 点击蓝字进入<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">VoidGameSpace</a>。<br>进入后,会看到这样的页面。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/1.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 点击右上角的,Fork,如果不明白全部默认,点击绿色按钮即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/2.png\" alt=\"ICON\"><br><img src=\"/articles/QiNuoTu/CorrectlyReleased/3.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 此刻你的库中就有了一份分叉文件,第一步完成。</li>\n</ul>\n<h1 id=\"第二步,来到自己的库中,并进入GameDevWebsite项目。\"><a href=\"#第二步,来到自己的库中,并进入GameDevWebsite项目。\" class=\"headerlink\" title=\"第二步,来到自己的库中,并进入GameDevWebsite项目。\"></a>第二步,来到自己的库中,并进入GameDevWebsite项目。</h1><ul>\n<li><strong>1</strong>: 点击左上角的,点点点,标志。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/4.png\" alt=\"ICON\"><br>选择,自己名字加上斜杠的/GameDevWebsite项目,非常重要!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/5.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 这样就进入了自己库中的GameDevWebsite克隆项目。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/6.png\" alt=\"ICON\"><br>这里的头像变成自己的,就正确了。</li>\n</ul>\n<h1 id=\"第三步,来到,-posts,文件夹。\"><a href=\"#第三步,来到,-posts,文件夹。\" class=\"headerlink\" title=\"第三步,来到,_posts,文件夹。\"></a>第三步,来到,_posts,文件夹。</h1><p>点击项目中的,source,文件夹。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/7.png\" alt=\"ICON\"><br>在点击,_posts,文件夹<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/8.png\" alt=\"ICON\"><br>这里会有一大堆别人的文件夹,不需要管理。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/9.png\" alt=\"ICON\"></p>\n<h1 id=\"第四步,准备文章!\"><a href=\"#第四步,准备文章!\" class=\"headerlink\" title=\"第四步,准备文章!\"></a>第四步,准备文章!</h1><p>此刻,网页上的操作已经完成,回到本地,用自己的名字创建一个文件夹。</p>\n<h2 id=\"自己的名字!,不要抄我的名字!\"><a href=\"#自己的名字!,不要抄我的名字!\" class=\"headerlink\" title=\"自己的名字!,不要抄我的名字!\"></a>自己的名字!,不要抄我的名字!</h2><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/10.png\" alt=\"ICON\"><br>进入文件夹,使用你任何喜欢的md文件编辑器在其中创建一个文件,然后进入,开始编写。<br>编写参阅,<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">VoidGameSpace</a>。下方的说明。</p>\n<ul>\n<li><strong>1</strong>: 跳过上面的说明我们创建一个。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/11.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 打开,在头部添加以下内容。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/12.png\" alt=\"ICON\"><br>permalink: 不太好理解,不用担心,请往下看,<br>它是这样的结构,permalink: articles/QiNuoTu/Demo/</li>\n<li><strong>articles</strong>: 可以理解为根目录,必须加上。</li>\n<li><strong>QiNuoTu</strong>: 这个是我的名字,一个示意,需要修改为你名字文件夹的名称。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/10.png\" alt=\"ICON\"></li>\n<li><strong>Demo</strong>: 这个是你创建的当前文章的文件名,不要扩展名,但要加上,/,斜杠在尾部。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/13.png\" alt=\"ICON\"><br>这样一来,文章头就准备完毕了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/14.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第五步,编写文章!\"><a href=\"#第五步,编写文章!\" class=\"headerlink\" title=\"第五步,编写文章!\"></a>第五步,编写文章!</h1><ul>\n<li><strong>1</strong>: 在上面的截图可以注意到,文章头下面有一些白字,没错,这个可以当作简介,或者先到言,具体的文章内容需要在,<code><!-- More --></code> 标记下书写<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/15.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 如何添加图片,在文章旁边使用同名创建一个文件夹。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/16.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 将图片丢进文件夹中,就可以使用,<code>![ICON](articles/自己名称文件夹名/文件夹名/文件名.后缀名)</code>表达式引用图片了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/17.png\" alt=\"ICON\"></li>\n<li><strong>4</strong>: 网页链接同理,<code>[名称](链接)</code>,表达式,即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/27.png\" alt=\"ICON\"></li>\n<li><strong>5</strong>: 置入代码,只需要使用,<code>```cpp 代码 ```</code>将代码包裹其中即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/28.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第六步,发表文章。\"><a href=\"#第六步,发表文章。\" class=\"headerlink\" title=\"第六步,发表文章。\"></a>第六步,发表文章。</h1><ul>\n<li><strong>1</strong>: 回到网页,那一堆名字的文件夹的页面,点击右上角的,上传文件。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/18.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 把文件夹拖住丢上去。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/19.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 点击绿色按钮。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/20.png\" alt=\"ICON\"></li>\n<li><strong>4</strong>: 之后就可以看到自己的文件夹了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/21.png\" alt=\"ICON\"></li>\n<li><strong>5</strong>: 点进去!,就可以看到自己的md文件和文件夹什么的了,在提交之前,需要说明,建立文件夹克隆库一类都只需要做一次,每次发布只要弄文章md和图片文件夹上传到自己的文件夹中即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/22.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第七步,提交!\"><a href=\"#第七步,提交!\" class=\"headerlink\" title=\"第七步,提交!\"></a>第七步,提交!</h1><ul>\n<li><strong>1</strong>: 点击右上角的GameDevWebsite。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/23.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 找到,Contribote,点击绿色按钮!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/24.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 填写标题,点击绿色按钮!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/25.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"等待审核即可!\"><a href=\"#等待审核即可!\" class=\"headerlink\" title=\"等待审核即可!\"></a>等待审核即可!</h1><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/26.png\" alt=\"ICON\"></p>\n<h1 id=\"这是什么?\"><a href=\"#这是什么?\" class=\"headerlink\" title=\"这是什么?\"></a>这是什么?</h1><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/123415231.png\" alt=\"ICON\"></p>\n","site":{"data":{}},"excerpt":"<p>保姆级!保姆级!保姆级!Ciallo~!<br>每一步都有图文混合讲解!</p>","more":"<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h1 id=\"第一步,先分叉一个VoidGameSpace的原始库\"><a href=\"#第一步,先分叉一个VoidGameSpace的原始库\" class=\"headerlink\" title=\"第一步,先分叉一个VoidGameSpace的原始库\"></a>第一步,先分叉一个VoidGameSpace的原始库</h1><ul>\n<li><strong>1</strong>: 点击蓝字进入<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">VoidGameSpace</a>。<br>进入后,会看到这样的页面。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/1.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 点击右上角的,Fork,如果不明白全部默认,点击绿色按钮即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/2.png\" alt=\"ICON\"><br><img src=\"/articles/QiNuoTu/CorrectlyReleased/3.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 此刻你的库中就有了一份分叉文件,第一步完成。</li>\n</ul>\n<h1 id=\"第二步,来到自己的库中,并进入GameDevWebsite项目。\"><a href=\"#第二步,来到自己的库中,并进入GameDevWebsite项目。\" class=\"headerlink\" title=\"第二步,来到自己的库中,并进入GameDevWebsite项目。\"></a>第二步,来到自己的库中,并进入GameDevWebsite项目。</h1><ul>\n<li><strong>1</strong>: 点击左上角的,点点点,标志。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/4.png\" alt=\"ICON\"><br>选择,自己名字加上斜杠的/GameDevWebsite项目,非常重要!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/5.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 这样就进入了自己库中的GameDevWebsite克隆项目。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/6.png\" alt=\"ICON\"><br>这里的头像变成自己的,就正确了。</li>\n</ul>\n<h1 id=\"第三步,来到,-posts,文件夹。\"><a href=\"#第三步,来到,-posts,文件夹。\" class=\"headerlink\" title=\"第三步,来到,_posts,文件夹。\"></a>第三步,来到,_posts,文件夹。</h1><p>点击项目中的,source,文件夹。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/7.png\" alt=\"ICON\"><br>在点击,_posts,文件夹<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/8.png\" alt=\"ICON\"><br>这里会有一大堆别人的文件夹,不需要管理。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/9.png\" alt=\"ICON\"></p>\n<h1 id=\"第四步,准备文章!\"><a href=\"#第四步,准备文章!\" class=\"headerlink\" title=\"第四步,准备文章!\"></a>第四步,准备文章!</h1><p>此刻,网页上的操作已经完成,回到本地,用自己的名字创建一个文件夹。</p>\n<h2 id=\"自己的名字!,不要抄我的名字!\"><a href=\"#自己的名字!,不要抄我的名字!\" class=\"headerlink\" title=\"自己的名字!,不要抄我的名字!\"></a>自己的名字!,不要抄我的名字!</h2><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/10.png\" alt=\"ICON\"><br>进入文件夹,使用你任何喜欢的md文件编辑器在其中创建一个文件,然后进入,开始编写。<br>编写参阅,<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">VoidGameSpace</a>。下方的说明。</p>\n<ul>\n<li><strong>1</strong>: 跳过上面的说明我们创建一个。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/11.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 打开,在头部添加以下内容。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/12.png\" alt=\"ICON\"><br>permalink: 不太好理解,不用担心,请往下看,<br>它是这样的结构,permalink: articles/QiNuoTu/Demo/</li>\n<li><strong>articles</strong>: 可以理解为根目录,必须加上。</li>\n<li><strong>QiNuoTu</strong>: 这个是我的名字,一个示意,需要修改为你名字文件夹的名称。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/10.png\" alt=\"ICON\"></li>\n<li><strong>Demo</strong>: 这个是你创建的当前文章的文件名,不要扩展名,但要加上,/,斜杠在尾部。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/13.png\" alt=\"ICON\"><br>这样一来,文章头就准备完毕了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/14.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第五步,编写文章!\"><a href=\"#第五步,编写文章!\" class=\"headerlink\" title=\"第五步,编写文章!\"></a>第五步,编写文章!</h1><ul>\n<li><strong>1</strong>: 在上面的截图可以注意到,文章头下面有一些白字,没错,这个可以当作简介,或者先到言,具体的文章内容需要在,<code><!-- More --></code> 标记下书写<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/15.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 如何添加图片,在文章旁边使用同名创建一个文件夹。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/16.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 将图片丢进文件夹中,就可以使用,<code>![ICON](articles/自己名称文件夹名/文件夹名/文件名.后缀名)</code>表达式引用图片了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/17.png\" alt=\"ICON\"></li>\n<li><strong>4</strong>: 网页链接同理,<code>[名称](链接)</code>,表达式,即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/27.png\" alt=\"ICON\"></li>\n<li><strong>5</strong>: 置入代码,只需要使用,<code>```cpp 代码 ```</code>将代码包裹其中即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/28.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第六步,发表文章。\"><a href=\"#第六步,发表文章。\" class=\"headerlink\" title=\"第六步,发表文章。\"></a>第六步,发表文章。</h1><ul>\n<li><strong>1</strong>: 回到网页,那一堆名字的文件夹的页面,点击右上角的,上传文件。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/18.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 把文件夹拖住丢上去。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/19.png\" alt=\"ICON\"></li>\n<li><strong>3</strong>: 点击绿色按钮。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/20.png\" alt=\"ICON\"></li>\n<li><strong>4</strong>: 之后就可以看到自己的文件夹了。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/21.png\" alt=\"ICON\"></li>\n<li><strong>5</strong>: 点进去!,就可以看到自己的md文件和文件夹什么的了,在提交之前,需要说明,建立文件夹克隆库一类都只需要做一次,每次发布只要弄文章md和图片文件夹上传到自己的文件夹中即可。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/22.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"第七步,提交!\"><a href=\"#第七步,提交!\" class=\"headerlink\" title=\"第七步,提交!\"></a>第七步,提交!</h1><ul>\n<li><strong>1</strong>: 点击右上角的GameDevWebsite。<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/23.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 找到,Contribote,点击绿色按钮!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/24.png\" alt=\"ICON\"></li>\n<li><strong>2</strong>: 填写标题,点击绿色按钮!<br><img src=\"/articles/QiNuoTu/CorrectlyReleased/25.png\" alt=\"ICON\"></li>\n</ul>\n<h1 id=\"等待审核即可!\"><a href=\"#等待审核即可!\" class=\"headerlink\" title=\"等待审核即可!\"></a>等待审核即可!</h1><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/26.png\" alt=\"ICON\"></p>\n<h1 id=\"这是什么?\"><a href=\"#这是什么?\" class=\"headerlink\" title=\"这是什么?\"></a>这是什么?</h1><p><img src=\"/articles/QiNuoTu/CorrectlyReleased/123415231.png\" alt=\"ICON\"></p>"},{"title":"是琪诺兔啦!(●'◡'●)!","date":"2024-05-30T16:00:00.000Z","updated":"2024-05-30T16:00:00.000Z","_content":"琪诺兔是一种幻想生物,他十分可爱,o( ?_? )o/\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n![ICON](articles/QiNuoTu/Iamme/1.jpg)\n\n#这是什么?\n![ICON](articles/QiNuoTu/Iamme/2.png)\n","source":"_posts/QiNuoTu/Iamme.md","raw":"---\ntitle: 是琪诺兔啦!(●'◡'●)!\ndate: 2024-05-31\nupdated: 2024-05-31\npermalink: articles/QiNuoTu/Iamme/\ncategories: QiNuoTu\ntags: [闲聊]\n---\n琪诺兔是一种幻想生物,他十分可爱,o( ?_? )o/\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n![ICON](articles/QiNuoTu/Iamme/1.jpg)\n\n#这是什么?\n![ICON](articles/QiNuoTu/Iamme/2.png)\n","slug":"QiNuoTu/Iamme","published":1,"__permalink":"articles/QiNuoTu/Iamme/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgf000ko8ye18hp6oh1","content":"<p>琪诺兔是一种幻想生物,他十分可爱,o( ?_? )o/</p>\n<span id=\"more\"></span>\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<p><img src=\"/articles/QiNuoTu/Iamme/1.jpg\" alt=\"ICON\"></p>\n<p>#这是什么?<br><img src=\"/articles/QiNuoTu/Iamme/2.png\" alt=\"ICON\"></p>\n","site":{"data":{}},"excerpt":"<p>琪诺兔是一种幻想生物,他十分可爱,o( ?_? )o/</p>","more":"<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<p><img src=\"/articles/QiNuoTu/Iamme/1.jpg\" alt=\"ICON\"></p>\n<p>#这是什么?<br><img src=\"/articles/QiNuoTu/Iamme/2.png\" alt=\"ICON\"></p>"},{"title":"开箱即用平滑插值大合集!OpenEasing!","date":"2024-05-29T16:00:00.000Z","updated":"2024-05-29T16:00:00.000Z","_content":"在游戏或动画制作中,如何让一个对象或色彩等平滑过度,或在两个值之间平滑的自动分布一直以来是新人开发者的一大难题,很多同学没有那么多时间去寻找公式并将他们逐一实现,没关系已经有前人为我们铺好了路。[Easing](https://easings.net/zh-cn),\n![ICON](articles/QiNuoTu/OpenEasing/OpenEasing.png)\n网站中为我们实现了一系列用于时间缓动的函数与公式,但它并不是C++的,对于超级新手也不太容易使用,于是我花了一些时间对其中的实现进行了一些翻译为C++.\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n比例的概念可能有些困扰,在以下的实现中,我将他们重新封装为,提供四个参数的版本。\n> **begin_**: 当前时间&当前是第几段&当前位置,无需担心会被自动计算为比例。\n> \n> **start**: 开始值&开始时间&开始位置,等。\n> \n> **end**: 结束值&结束时间&结束位置,等。\n> \n> **percent_**: 将开始与结束之间分为多少段。\n\n```cpp\nint main() {\n // 示例\n double progress = 0.5; // 进度\n double startValue = 0; // 开始数值\n double endValue = 100; // 结束数值\n double segments = 10; // 分段数\n double result = Easing(progress, startValue, endValue, segments);\n std::cout << \"Easing price: \" << result << std::endl;\n return 0;\n}\nRGBA ColorDifference(const RGBA& start, const RGBA& end, double t) {\n return RGBA(start.R + (end.R - start.R) * t, \n start.G + (end.G - start.G) * t,\n start.B + (end.B - start.B) * t,\n start.A + (end.A - start.A) * t);\n}\ndouble _getOutBounce(double begin_,double end_,double percent_){\n double _st = end_ - begin_;\n double _ed = percent_;\n if (_st < 1 ÷ 2.75) return _ed * 7.5625 * _st * _st + begin_;\n else if (_st < 2 ÷ 2.75) {_st = _st - 1.5 ÷ 2.75; return _ed * (7.5625 * _st * _st + 0.75) + begin_;}\n else if (_st < 2.5 ÷ 2.75) {_st = _st - 2.25 ÷ 2.75; return _ed * (7.5625 * _st * _st + 0.9375) + begin_;}\n _st = _st - 2.625 ÷ 2.75;\n return _ed * (7.5625 * _st * _st + 0.984375) + begin_;\n}\ndouble _getInBounce(double begin_,double end_,double percent_){\n double _ed = end_ - begin_;\n return _ed - _getOutBounce (0, _ed, 1 - percent_) + begin_;\n}\ndouble Linear(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return ((_End - _Start) * percents_ * percents_ + _Start);\n}\ndouble OutQuad(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return -(_End - _Start) * percents_ * (percents_ - 2) + _Start;\n}\ndouble InOutQuad(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ts = percents_ * 2;\n if (_ts < 1) return (_End - _Start) ÷ 2 * _ts * _ts + _Start;\n return -(_End - _Start) ÷ 2 * (_ts * (_ts - 2) - 1) + _Start;\n}\ndouble InCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n return (_End - _Start) * (_st * _st * _st + 1) + _Start;\n}\ndouble InOutCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n if(_st < 1)return _ed1 ÷ 2 * _st * _st * _st + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (_st * _st * _st + 2) + _Start;\n}\ndouble InQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n return -(_End - _Start) * (_st * _st * _st * _st - 1) + _Start;\n}\ndouble InOutQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * _st * _st * _st * _st + _Start;\n _st = _st - 2;\n return -_ed1 ÷ 2 * (_st * _st * _st * _st - 2) + _Start;\n}\ndouble InQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n return _ed1 * (_st * _st * _st * _st * _st + 1) + _Start;\n}\ndouble InOutQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * _st * _st * _st * _st * _st + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (_st * _st * _st * _st * _st + 2) + _Start;\n}\ndouble InSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return -_ed1 * cos (percents_ ÷ 1 * M_PI ÷ 2) + _ed1 + _Start;\n} \ndouble OutSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return _ed1 * sin (percents_ ÷ 1 * M_PI ÷ 2) + _Start;\n}\ndouble InOutSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return _ed1 * pow (2, 10 * (percents_ ÷ 1 - 1)) + _Start;\n}\ndouble OutExpo(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * pow (2, 10 * (_st - 1)) + _Start;\n _st = _st - 1;\n return _ed1 ÷ 2 * (-pow (2, -10 * _st) + 2) + _Start;\n}\ndouble InCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return -_ed1 * (sqrt (1 - percents_ * percents_) - 1) + _Start;\n}\ndouble OutCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n return _ed1 * sqrt (1 - _st * _st) + _Start;\n}\ndouble InOutCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return -_ed1 ÷ 2 * (sqrt (1 - _st * _st) - 1) + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (sqrt (1 - _st * _st) + 1) + _Start;\n}\ndouble InBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return _getInBounce(_Start, _End, percents_);\n}\ndouble OutBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return _getOutBounce(_Start, _End, percents_);\n}\ndouble InOutBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n if (percents_ < 0.5) return _getInBounce (0, _ed, percents_ * 2) * 0.5 + _Start;\n return _getOutBounce (0, _ed, percents_ * 2 - 1) * 0.5 + _ed * 0.5 + _Start;\n}\ndouble InBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n return _ed * percents_ * percents_ * ((_s + 1) * percents_ - _s) + _Start;\n}\ndouble OutBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n double _st = percents_ - 1;\n return _ed * (_st * _st * ((_s + 1) * _st + _s) + 1) + _Start;\n}\ndouble InOutBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n double _st = percents_ * 2;\n if (_st < 1){_s = _s * 1.525; return _ed ÷ 2 * _st * _st * ((_s + 1) * _st - _s) + _Start;}\n double _st = _st - 2\n double _s = _s * 1.525\n return _ed ÷ 2 * (_st * _st * ((_s + 1) * _st + _s) + 2) + _Start;\n}\ndouble InElastic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n if(percents_ == 0) return _Start;\n if(percents_ == 1) return _End;\n double _ed = _End - _Start;\n double _d = 1\n double _p = _d * 0.3\n double _s = 0\n double _a = 0\n if (_a = 0 || _a < ads(_ed)){_a = _ed; _s = _p ÷ 4} else {_s = _p / (2 * M_PI) * std::asin(_ed / _a);}\n double _st = percents - 1;\n return -(_a * pow(2, 10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p)) + _Start;\n}\ndouble OutElastic(double _Progress, double _Start, double _end, double _segments) {\n double percents_ = _Progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _Start;\n double _d = 1;\n double _p = _d * 0.3;\n double _s = 0;\n double _a = 0;\n if (_a == 0 || _a < abs(_ed)) {_a = _ed;_s = _p / 4;} else {_s = _p / (2 * M_PI) * asin(_ed / _a);}\n return _a * pow(2, -10 * percents) * sin((percents * _d - _s) * 2 * M_PI / _p) + _end;\n}\ndouble InOutElastic(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _start;\n double _d = 1;\n double _p = _d * 0.3;\n double _s = 0;\n double _a = 0;\n double _st = percents_ * 2;\n if (_st == 2) {return _end;}\n if (_a == 0 || _a < abs(_ed)) {_a = _ed;_s = _p / 4;} else {_s = _p / (2 * M_PI) * asin(_ed / _a);}\n if (_st < 1) {_st -= 1;return -0.5 * _a * pow(2, 10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p) + _start;}\n _st -= 1;\n return _a * pow(2, -10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p) * 0.5 + _end;\n}\ndouble Clerp(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _start;\n const double _min = 0;\n const double _max = 360;\n const double _half = 180;\n double _retval = 0;\n double _diff = 0;\n if (_ed < -_half) {\n _diff = (_max - _start + _end) * percents_;\n _retval = _start + _diff;\n } else if (_ed > _half) {\n _diff = -(_max - _end + _start) * percents_;\n _retval = _start + _diff;\n } else {\n _retval = _start + _ed * percents_;\n }\n return _retval;\n}\ndouble Spring(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _st = sin(percents_ * M_PI * (0.2 + 2.5 * percents_ * percents_ * percents_)) * pow(1 - percents_, 2.2) + percents_;\n _st = _st * (1 + 1.2 * (1 - percents_));\n return _start + (_end - _start) * _st;\n}\ndouble Punch(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n if (percents_ == 0) return 0;\n if (percents_ == 1) return 0;\n const double _p = 0.3;\n double _s = _p / (2 * M_PI) * asin(0);\n return _end * pow(2, -10 * percents) * sin((percents - _s) * 2 * M_PI / _p);\n}\n```\n# 这是什么!\n![ICON](articles/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg)\n","source":"_posts/QiNuoTu/OpenEasing.md","raw":"---\ntitle: 开箱即用平滑插值大合集!OpenEasing!\ndate: 2024-05-30\nupdated: 2024-05-30\npermalink: articles/QiNuoTu/OpenEasing/\ncategories: QiNuoTu\ntags: [游戏开发] \n---\n在游戏或动画制作中,如何让一个对象或色彩等平滑过度,或在两个值之间平滑的自动分布一直以来是新人开发者的一大难题,很多同学没有那么多时间去寻找公式并将他们逐一实现,没关系已经有前人为我们铺好了路。[Easing](https://easings.net/zh-cn),\n![ICON](articles/QiNuoTu/OpenEasing/OpenEasing.png)\n网站中为我们实现了一系列用于时间缓动的函数与公式,但它并不是C++的,对于超级新手也不太容易使用,于是我花了一些时间对其中的实现进行了一些翻译为C++.\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n比例的概念可能有些困扰,在以下的实现中,我将他们重新封装为,提供四个参数的版本。\n> **begin_**: 当前时间&当前是第几段&当前位置,无需担心会被自动计算为比例。\n> \n> **start**: 开始值&开始时间&开始位置,等。\n> \n> **end**: 结束值&结束时间&结束位置,等。\n> \n> **percent_**: 将开始与结束之间分为多少段。\n\n```cpp\nint main() {\n // 示例\n double progress = 0.5; // 进度\n double startValue = 0; // 开始数值\n double endValue = 100; // 结束数值\n double segments = 10; // 分段数\n double result = Easing(progress, startValue, endValue, segments);\n std::cout << \"Easing price: \" << result << std::endl;\n return 0;\n}\nRGBA ColorDifference(const RGBA& start, const RGBA& end, double t) {\n return RGBA(start.R + (end.R - start.R) * t, \n start.G + (end.G - start.G) * t,\n start.B + (end.B - start.B) * t,\n start.A + (end.A - start.A) * t);\n}\ndouble _getOutBounce(double begin_,double end_,double percent_){\n double _st = end_ - begin_;\n double _ed = percent_;\n if (_st < 1 ÷ 2.75) return _ed * 7.5625 * _st * _st + begin_;\n else if (_st < 2 ÷ 2.75) {_st = _st - 1.5 ÷ 2.75; return _ed * (7.5625 * _st * _st + 0.75) + begin_;}\n else if (_st < 2.5 ÷ 2.75) {_st = _st - 2.25 ÷ 2.75; return _ed * (7.5625 * _st * _st + 0.9375) + begin_;}\n _st = _st - 2.625 ÷ 2.75;\n return _ed * (7.5625 * _st * _st + 0.984375) + begin_;\n}\ndouble _getInBounce(double begin_,double end_,double percent_){\n double _ed = end_ - begin_;\n return _ed - _getOutBounce (0, _ed, 1 - percent_) + begin_;\n}\ndouble Linear(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return ((_End - _Start) * percents_ * percents_ + _Start);\n}\ndouble OutQuad(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return -(_End - _Start) * percents_ * (percents_ - 2) + _Start;\n}\ndouble InOutQuad(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ts = percents_ * 2;\n if (_ts < 1) return (_End - _Start) ÷ 2 * _ts * _ts + _Start;\n return -(_End - _Start) ÷ 2 * (_ts * (_ts - 2) - 1) + _Start;\n}\ndouble InCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n return (_End - _Start) * (_st * _st * _st + 1) + _Start;\n}\ndouble InOutCubic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n if(_st < 1)return _ed1 ÷ 2 * _st * _st * _st + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (_st * _st * _st + 2) + _Start;\n}\ndouble InQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n return -(_End - _Start) * (_st * _st * _st * _st - 1) + _Start;\n}\ndouble InOutQuart(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * _st * _st * _st * _st + _Start;\n _st = _st - 2;\n return -_ed1 ÷ 2 * (_st * _st * _st * _st - 2) + _Start;\n}\ndouble InQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return (_End - _Start) * percents_ * percents_ * percents_ * percents_ * percents_ + _Start;\n}\ndouble OutQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n return _ed1 * (_st * _st * _st * _st * _st + 1) + _Start;\n}\ndouble InOutQuint(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * _st * _st * _st * _st * _st + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (_st * _st * _st * _st * _st + 2) + _Start;\n}\ndouble InSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return -_ed1 * cos (percents_ ÷ 1 * M_PI ÷ 2) + _ed1 + _Start;\n} \ndouble OutSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return _ed1 * sin (percents_ ÷ 1 * M_PI ÷ 2) + _Start;\n}\ndouble InOutSine(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return _ed1 * pow (2, 10 * (percents_ ÷ 1 - 1)) + _Start;\n}\ndouble OutExpo(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return _ed1 ÷ 2 * pow (2, 10 * (_st - 1)) + _Start;\n _st = _st - 1;\n return _ed1 ÷ 2 * (-pow (2, -10 * _st) + 2) + _Start;\n}\ndouble InCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed1 = _End - _Start;\n return -_ed1 * (sqrt (1 - percents_ * percents_) - 1) + _Start;\n}\ndouble OutCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ - 1;\n double _ed1 = _End - _Start;\n return _ed1 * sqrt (1 - _st * _st) + _Start;\n}\ndouble InOutCirc(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _st = percents_ * 2;\n double _ed1 = _End - _Start;\n if (_st < 1) return -_ed1 ÷ 2 * (sqrt (1 - _st * _st) - 1) + _Start;\n _st = _st - 2;\n return _ed1 ÷ 2 * (sqrt (1 - _st * _st) + 1) + _Start;\n}\ndouble InBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return _getInBounce(_Start, _End, percents_);\n}\ndouble OutBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n return _getOutBounce(_Start, _End, percents_);\n}\ndouble InOutBounce(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n if (percents_ < 0.5) return _getInBounce (0, _ed, percents_ * 2) * 0.5 + _Start;\n return _getOutBounce (0, _ed, percents_ * 2 - 1) * 0.5 + _ed * 0.5 + _Start;\n}\ndouble InBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n return _ed * percents_ * percents_ * ((_s + 1) * percents_ - _s) + _Start;\n}\ndouble OutBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n double _st = percents_ - 1;\n return _ed * (_st * _st * ((_s + 1) * _st + _s) + 1) + _Start;\n}\ndouble InOutBack(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n double _ed = _End - _Start;\n double _s = 1.70158;\n double _st = percents_ * 2;\n if (_st < 1){_s = _s * 1.525; return _ed ÷ 2 * _st * _st * ((_s + 1) * _st - _s) + _Start;}\n double _st = _st - 2\n double _s = _s * 1.525\n return _ed ÷ 2 * (_st * _st * ((_s + 1) * _st + _s) + 2) + _Start;\n}\ndouble InElastic(double _Progress,double _Start,double _End,double _segments){\n double percents_ = _Progress / _segments;\n if (percents < 0) percents = 0;\n else if (percents > 1) percents = 1;\n if(percents_ == 0) return _Start;\n if(percents_ == 1) return _End;\n double _ed = _End - _Start;\n double _d = 1\n double _p = _d * 0.3\n double _s = 0\n double _a = 0\n if (_a = 0 || _a < ads(_ed)){_a = _ed; _s = _p ÷ 4} else {_s = _p / (2 * M_PI) * std::asin(_ed / _a);}\n double _st = percents - 1;\n return -(_a * pow(2, 10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p)) + _Start;\n}\ndouble OutElastic(double _Progress, double _Start, double _end, double _segments) {\n double percents_ = _Progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _Start;\n double _d = 1;\n double _p = _d * 0.3;\n double _s = 0;\n double _a = 0;\n if (_a == 0 || _a < abs(_ed)) {_a = _ed;_s = _p / 4;} else {_s = _p / (2 * M_PI) * asin(_ed / _a);}\n return _a * pow(2, -10 * percents) * sin((percents * _d - _s) * 2 * M_PI / _p) + _end;\n}\ndouble InOutElastic(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _start;\n double _d = 1;\n double _p = _d * 0.3;\n double _s = 0;\n double _a = 0;\n double _st = percents_ * 2;\n if (_st == 2) {return _end;}\n if (_a == 0 || _a < abs(_ed)) {_a = _ed;_s = _p / 4;} else {_s = _p / (2 * M_PI) * asin(_ed / _a);}\n if (_st < 1) {_st -= 1;return -0.5 * _a * pow(2, 10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p) + _start;}\n _st -= 1;\n return _a * pow(2, -10 * _st) * sin((_st * _d - _s) * 2 * M_PI / _p) * 0.5 + _end;\n}\ndouble Clerp(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _ed = _end - _start;\n const double _min = 0;\n const double _max = 360;\n const double _half = 180;\n double _retval = 0;\n double _diff = 0;\n if (_ed < -_half) {\n _diff = (_max - _start + _end) * percents_;\n _retval = _start + _diff;\n } else if (_ed > _half) {\n _diff = -(_max - _end + _start) * percents_;\n _retval = _start + _diff;\n } else {\n _retval = _start + _ed * percents_;\n }\n return _retval;\n}\ndouble Spring(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n double _st = sin(percents_ * M_PI * (0.2 + 2.5 * percents_ * percents_ * percents_)) * pow(1 - percents_, 2.2) + percents_;\n _st = _st * (1 + 1.2 * (1 - percents_));\n return _start + (_end - _start) * _st;\n}\ndouble Punch(double _progress, double _start, double _end, double _segments) {\n double percents_ = _progress / _segments;\n if (percents_ < 0) percents_ = 0;\n else if (percents_ > 1) percents_ = 1;\n if (percents_ == 0) return 0;\n if (percents_ == 1) return 0;\n const double _p = 0.3;\n double _s = _p / (2 * M_PI) * asin(0);\n return _end * pow(2, -10 * percents) * sin((percents - _s) * 2 * M_PI / _p);\n}\n```\n# 这是什么!\n![ICON](articles/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg)\n","slug":"QiNuoTu/OpenEasing","published":1,"__permalink":"articles/QiNuoTu/OpenEasing/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgf000lo8ye6hli2vre","content":"<p>在游戏或动画制作中,如何让一个对象或色彩等平滑过度,或在两个值之间平滑的自动分布一直以来是新人开发者的一大难题,很多同学没有那么多时间去寻找公式并将他们逐一实现,没关系已经有前人为我们铺好了路。<a href=\"https://easings.net/zh-cn\">Easing</a>,<br><img src=\"/articles/QiNuoTu/OpenEasing/OpenEasing.png\" alt=\"ICON\"><br>网站中为我们实现了一系列用于时间缓动的函数与公式,但它并不是C++的,对于超级新手也不太容易使用,于是我花了一些时间对其中的实现进行了一些翻译为C++.</p>\n<span id=\"more\"></span>\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<p>比例的概念可能有些困扰,在以下的实现中,我将他们重新封装为,提供四个参数的版本。</p>\n<blockquote>\n<p><strong>begin_</strong>: 当前时间&当前是第几段&当前位置,无需担心会被自动计算为比例。</p>\n<p><strong>start</strong>: 开始值&开始时间&开始位置,等。</p>\n<p><strong>end</strong>: 结束值&结束时间&结束位置,等。</p>\n<p><strong>percent_</strong>: 将开始与结束之间分为多少段。</p>\n</blockquote>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br><span class=\"line\">143</span><br><span class=\"line\">144</span><br><span class=\"line\">145</span><br><span class=\"line\">146</span><br><span class=\"line\">147</span><br><span class=\"line\">148</span><br><span class=\"line\">149</span><br><span class=\"line\">150</span><br><span class=\"line\">151</span><br><span class=\"line\">152</span><br><span class=\"line\">153</span><br><span class=\"line\">154</span><br><span class=\"line\">155</span><br><span class=\"line\">156</span><br><span class=\"line\">157</span><br><span class=\"line\">158</span><br><span class=\"line\">159</span><br><span class=\"line\">160</span><br><span class=\"line\">161</span><br><span class=\"line\">162</span><br><span class=\"line\">163</span><br><span class=\"line\">164</span><br><span class=\"line\">165</span><br><span class=\"line\">166</span><br><span class=\"line\">167</span><br><span class=\"line\">168</span><br><span class=\"line\">169</span><br><span class=\"line\">170</span><br><span class=\"line\">171</span><br><span class=\"line\">172</span><br><span class=\"line\">173</span><br><span class=\"line\">174</span><br><span class=\"line\">175</span><br><span class=\"line\">176</span><br><span class=\"line\">177</span><br><span class=\"line\">178</span><br><span class=\"line\">179</span><br><span class=\"line\">180</span><br><span class=\"line\">181</span><br><span class=\"line\">182</span><br><span class=\"line\">183</span><br><span class=\"line\">184</span><br><span class=\"line\">185</span><br><span class=\"line\">186</span><br><span class=\"line\">187</span><br><span class=\"line\">188</span><br><span class=\"line\">189</span><br><span class=\"line\">190</span><br><span class=\"line\">191</span><br><span class=\"line\">192</span><br><span class=\"line\">193</span><br><span class=\"line\">194</span><br><span class=\"line\">195</span><br><span class=\"line\">196</span><br><span class=\"line\">197</span><br><span class=\"line\">198</span><br><span class=\"line\">199</span><br><span class=\"line\">200</span><br><span class=\"line\">201</span><br><span class=\"line\">202</span><br><span class=\"line\">203</span><br><span class=\"line\">204</span><br><span class=\"line\">205</span><br><span class=\"line\">206</span><br><span class=\"line\">207</span><br><span class=\"line\">208</span><br><span class=\"line\">209</span><br><span class=\"line\">210</span><br><span class=\"line\">211</span><br><span class=\"line\">212</span><br><span class=\"line\">213</span><br><span class=\"line\">214</span><br><span class=\"line\">215</span><br><span class=\"line\">216</span><br><span class=\"line\">217</span><br><span class=\"line\">218</span><br><span class=\"line\">219</span><br><span class=\"line\">220</span><br><span class=\"line\">221</span><br><span class=\"line\">222</span><br><span class=\"line\">223</span><br><span class=\"line\">224</span><br><span class=\"line\">225</span><br><span class=\"line\">226</span><br><span class=\"line\">227</span><br><span class=\"line\">228</span><br><span class=\"line\">229</span><br><span class=\"line\">230</span><br><span class=\"line\">231</span><br><span class=\"line\">232</span><br><span class=\"line\">233</span><br><span class=\"line\">234</span><br><span class=\"line\">235</span><br><span class=\"line\">236</span><br><span class=\"line\">237</span><br><span class=\"line\">238</span><br><span class=\"line\">239</span><br><span class=\"line\">240</span><br><span class=\"line\">241</span><br><span class=\"line\">242</span><br><span class=\"line\">243</span><br><span class=\"line\">244</span><br><span class=\"line\">245</span><br><span class=\"line\">246</span><br><span class=\"line\">247</span><br><span class=\"line\">248</span><br><span class=\"line\">249</span><br><span class=\"line\">250</span><br><span class=\"line\">251</span><br><span class=\"line\">252</span><br><span class=\"line\">253</span><br><span class=\"line\">254</span><br><span class=\"line\">255</span><br><span class=\"line\">256</span><br><span class=\"line\">257</span><br><span class=\"line\">258</span><br><span class=\"line\">259</span><br><span class=\"line\">260</span><br><span class=\"line\">261</span><br><span class=\"line\">262</span><br><span class=\"line\">263</span><br><span class=\"line\">264</span><br><span class=\"line\">265</span><br><span class=\"line\">266</span><br><span class=\"line\">267</span><br><span class=\"line\">268</span><br><span class=\"line\">269</span><br><span class=\"line\">270</span><br><span class=\"line\">271</span><br><span class=\"line\">272</span><br><span class=\"line\">273</span><br><span class=\"line\">274</span><br><span class=\"line\">275</span><br><span class=\"line\">276</span><br><span class=\"line\">277</span><br><span class=\"line\">278</span><br><span class=\"line\">279</span><br><span class=\"line\">280</span><br><span class=\"line\">281</span><br><span class=\"line\">282</span><br><span class=\"line\">283</span><br><span class=\"line\">284</span><br><span class=\"line\">285</span><br><span class=\"line\">286</span><br><span class=\"line\">287</span><br><span class=\"line\">288</span><br><span class=\"line\">289</span><br><span class=\"line\">290</span><br><span class=\"line\">291</span><br><span class=\"line\">292</span><br><span class=\"line\">293</span><br><span class=\"line\">294</span><br><span class=\"line\">295</span><br><span class=\"line\">296</span><br><span class=\"line\">297</span><br><span class=\"line\">298</span><br><span class=\"line\">299</span><br><span class=\"line\">300</span><br><span class=\"line\">301</span><br><span class=\"line\">302</span><br><span class=\"line\">303</span><br><span class=\"line\">304</span><br><span class=\"line\">305</span><br><span class=\"line\">306</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 示例</span></span><br><span class=\"line\"> <span class=\"type\">double</span> progress = <span class=\"number\">0.5</span>; <span class=\"comment\">// 进度</span></span><br><span class=\"line\"> <span class=\"type\">double</span> startValue = <span class=\"number\">0</span>; <span class=\"comment\">// 开始数值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> endValue = <span class=\"number\">100</span>; <span class=\"comment\">// 结束数值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> segments = <span class=\"number\">10</span>; <span class=\"comment\">// 分段数</span></span><br><span class=\"line\"> <span class=\"type\">double</span> result = <span class=\"built_in\">Easing</span>(progress, startValue, endValue, segments);</span><br><span class=\"line\"> std::cout << <span class=\"string\">"Easing price: "</span> << result << std::endl;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\">RGBA <span class=\"title\">ColorDifference</span><span class=\"params\">(<span class=\"type\">const</span> RGBA& start, <span class=\"type\">const</span> RGBA& end, <span class=\"type\">double</span> t)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">RGBA</span>(start.R + (end.R - start.R) * t, </span><br><span class=\"line\"> start.G + (end.G - start.G) * t,</span><br><span class=\"line\"> start.B + (end.B - start.B) * t,</span><br><span class=\"line\"> start.A + (end.A - start.A) * t);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"type\">double</span> _getOutBounce(<span class=\"type\">double</span> begin_,<span class=\"type\">double</span> end_,<span class=\"type\">double</span> percent_){</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = end_ - begin_;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = percent_;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span> ÷ <span class=\"number\">2.75</span>) <span class=\"keyword\">return</span> _ed * <span class=\"number\">7.5625</span> * _st * _st + begin_;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_st < <span class=\"number\">2</span> ÷ <span class=\"number\">2.75</span>) {_st = _st - <span class=\"number\">1.5</span> ÷ <span class=\"number\">2.75</span>; <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.75</span>) + begin_;}</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_st < <span class=\"number\">2.5</span> ÷ <span class=\"number\">2.75</span>) {_st = _st - <span class=\"number\">2.25</span> ÷ <span class=\"number\">2.75</span>; <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.9375</span>) + begin_;}</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2.625</span> ÷ <span class=\"number\">2.75</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.984375</span>) + begin_;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"type\">double</span> _getInBounce(<span class=\"type\">double</span> begin_,<span class=\"type\">double</span> end_,<span class=\"type\">double</span> percent_){</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = end_ - begin_;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed - _getOutBounce (<span class=\"number\">0</span>, _ed, <span class=\"number\">1</span> - percent_) + begin_;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Linear</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> ((_End - _Start) * percents_ * percents_ + _Start);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuad</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) * percents_ * (percents_ - <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuad</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ts = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_ts < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> (_End - _Start) ÷ <span class=\"number\">2</span> * _ts * _ts + _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) ÷ <span class=\"number\">2</span> * (_ts * (_ts - <span class=\"number\">2</span>) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * (_st * _st * _st + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(_st < <span class=\"number\">1</span>)<span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) * (_st * _st * _st * _st - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st * _st - <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * (_st * _st * _st * _st * _st + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st * _st * _st + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 * <span class=\"built_in\">cos</span> (percents_ ÷ <span class=\"number\">1</span> * M_PI ÷ <span class=\"number\">2</span>) + _ed1 + _Start;</span><br><span class=\"line\">} </span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">sin</span> (percents_ ÷ <span class=\"number\">1</span> * M_PI ÷ <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">10</span> * (percents_ ÷ <span class=\"number\">1</span> - <span class=\"number\">1</span>)) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutExpo</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * <span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">10</span> * (_st - <span class=\"number\">1</span>)) + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (-<span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">-10</span> * _st) + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - percents_ * percents_) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> -_ed1 ÷ <span class=\"number\">2</span> * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getInBounce(_Start, _End, percents_);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getOutBounce(_Start, _End, percents_);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0.5</span>) <span class=\"keyword\">return</span> _getInBounce (<span class=\"number\">0</span>, _ed, percents_ * <span class=\"number\">2</span>) * <span class=\"number\">0.5</span> + _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getOutBounce (<span class=\"number\">0</span>, _ed, percents_ * <span class=\"number\">2</span> - <span class=\"number\">1</span>) * <span class=\"number\">0.5</span> + _ed * <span class=\"number\">0.5</span> + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * percents_ * percents_ * ((_s + <span class=\"number\">1</span>) * percents_ - _s) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * (_st * _st * ((_s + <span class=\"number\">1</span>) * _st + _s) + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>){_s = _s * <span class=\"number\">1.525</span>; <span class=\"keyword\">return</span> _ed ÷ <span class=\"number\">2</span> * _st * _st * ((_s + <span class=\"number\">1</span>) * _st - _s) + _Start;}</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = _st - <span class=\"number\">2</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _s = _s * <span class=\"number\">1.525</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed ÷ <span class=\"number\">2</span> * (_st * _st * ((_s + <span class=\"number\">1</span>) * _st + _s) + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InElastic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(percents_ == <span class=\"number\">0</span>) <span class=\"keyword\">return</span> _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(percents_ == <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _End;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a = <span class=\"number\">0</span> || _a < <span class=\"built_in\">ads</span>(_ed)){_a = _ed; _s = _p ÷ <span class=\"number\">4</span>} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * std::<span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p)) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutElastic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress, <span class=\"type\">double</span> _Start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a == <span class=\"number\">0</span> || _a < <span class=\"built_in\">abs</span>(_ed)) {_a = _ed;_s = _p / <span class=\"number\">4</span>;} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * percents) * <span class=\"built_in\">sin</span>((percents * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) + _end;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutElastic</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st == <span class=\"number\">2</span>) {<span class=\"keyword\">return</span> _end;}</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a == <span class=\"number\">0</span> || _a < <span class=\"built_in\">abs</span>(_ed)) {_a = _ed;_s = _p / <span class=\"number\">4</span>;} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) {_st -= <span class=\"number\">1</span>;<span class=\"keyword\">return</span> <span class=\"number\">-0.5</span> * _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) + _start;}</span><br><span class=\"line\"> _st -= <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) * <span class=\"number\">0.5</span> + _end;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Clerp</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _start;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _min = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _max = <span class=\"number\">360</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _half = <span class=\"number\">180</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _retval = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _diff = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_ed < -_half) {</span><br><span class=\"line\"> _diff = (_max - _start + _end) * percents_;</span><br><span class=\"line\"> _retval = _start + _diff;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_ed > _half) {</span><br><span class=\"line\"> _diff = -(_max - _end + _start) * percents_;</span><br><span class=\"line\"> _retval = _start + _diff;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> _retval = _start + _ed * percents_;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _retval;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Spring</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = <span class=\"built_in\">sin</span>(percents_ * M_PI * (<span class=\"number\">0.2</span> + <span class=\"number\">2.5</span> * percents_ * percents_ * percents_)) * <span class=\"built_in\">pow</span>(<span class=\"number\">1</span> - percents_, <span class=\"number\">2.2</span>) + percents_;</span><br><span class=\"line\"> _st = _st * (<span class=\"number\">1</span> + <span class=\"number\">1.2</span> * (<span class=\"number\">1</span> - percents_));</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _start + (_end - _start) * _st;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Punch</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ == <span class=\"number\">0</span>) <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ == <span class=\"number\">1</span>) <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _p = <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(<span class=\"number\">0</span>);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _end * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * percents) * <span class=\"built_in\">sin</span>((percents - _s) * <span class=\"number\">2</span> * M_PI / _p);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<h1 id=\"这是什么!\"><a href=\"#这是什么!\" class=\"headerlink\" title=\"这是什么!\"></a>这是什么!</h1><p><img src=\"/articles/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg\" alt=\"ICON\"></p>\n","site":{"data":{}},"excerpt":"<p>在游戏或动画制作中,如何让一个对象或色彩等平滑过度,或在两个值之间平滑的自动分布一直以来是新人开发者的一大难题,很多同学没有那么多时间去寻找公式并将他们逐一实现,没关系已经有前人为我们铺好了路。<a href=\"https://easings.net/zh-cn\">Easing</a>,<br><img src=\"/articles/QiNuoTu/OpenEasing/OpenEasing.png\" alt=\"ICON\"><br>网站中为我们实现了一系列用于时间缓动的函数与公式,但它并不是C++的,对于超级新手也不太容易使用,于是我花了一些时间对其中的实现进行了一些翻译为C++.</p>","more":"<div align=\"center\">\n <p align=\"center\">\n <img src=\"articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<p>比例的概念可能有些困扰,在以下的实现中,我将他们重新封装为,提供四个参数的版本。</p>\n<blockquote>\n<p><strong>begin_</strong>: 当前时间&当前是第几段&当前位置,无需担心会被自动计算为比例。</p>\n<p><strong>start</strong>: 开始值&开始时间&开始位置,等。</p>\n<p><strong>end</strong>: 结束值&结束时间&结束位置,等。</p>\n<p><strong>percent_</strong>: 将开始与结束之间分为多少段。</p>\n</blockquote>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br><span class=\"line\">143</span><br><span class=\"line\">144</span><br><span class=\"line\">145</span><br><span class=\"line\">146</span><br><span class=\"line\">147</span><br><span class=\"line\">148</span><br><span class=\"line\">149</span><br><span class=\"line\">150</span><br><span class=\"line\">151</span><br><span class=\"line\">152</span><br><span class=\"line\">153</span><br><span class=\"line\">154</span><br><span class=\"line\">155</span><br><span class=\"line\">156</span><br><span class=\"line\">157</span><br><span class=\"line\">158</span><br><span class=\"line\">159</span><br><span class=\"line\">160</span><br><span class=\"line\">161</span><br><span class=\"line\">162</span><br><span class=\"line\">163</span><br><span class=\"line\">164</span><br><span class=\"line\">165</span><br><span class=\"line\">166</span><br><span class=\"line\">167</span><br><span class=\"line\">168</span><br><span class=\"line\">169</span><br><span class=\"line\">170</span><br><span class=\"line\">171</span><br><span class=\"line\">172</span><br><span class=\"line\">173</span><br><span class=\"line\">174</span><br><span class=\"line\">175</span><br><span class=\"line\">176</span><br><span class=\"line\">177</span><br><span class=\"line\">178</span><br><span class=\"line\">179</span><br><span class=\"line\">180</span><br><span class=\"line\">181</span><br><span class=\"line\">182</span><br><span class=\"line\">183</span><br><span class=\"line\">184</span><br><span class=\"line\">185</span><br><span class=\"line\">186</span><br><span class=\"line\">187</span><br><span class=\"line\">188</span><br><span class=\"line\">189</span><br><span class=\"line\">190</span><br><span class=\"line\">191</span><br><span class=\"line\">192</span><br><span class=\"line\">193</span><br><span class=\"line\">194</span><br><span class=\"line\">195</span><br><span class=\"line\">196</span><br><span class=\"line\">197</span><br><span class=\"line\">198</span><br><span class=\"line\">199</span><br><span class=\"line\">200</span><br><span class=\"line\">201</span><br><span class=\"line\">202</span><br><span class=\"line\">203</span><br><span class=\"line\">204</span><br><span class=\"line\">205</span><br><span class=\"line\">206</span><br><span class=\"line\">207</span><br><span class=\"line\">208</span><br><span class=\"line\">209</span><br><span class=\"line\">210</span><br><span class=\"line\">211</span><br><span class=\"line\">212</span><br><span class=\"line\">213</span><br><span class=\"line\">214</span><br><span class=\"line\">215</span><br><span class=\"line\">216</span><br><span class=\"line\">217</span><br><span class=\"line\">218</span><br><span class=\"line\">219</span><br><span class=\"line\">220</span><br><span class=\"line\">221</span><br><span class=\"line\">222</span><br><span class=\"line\">223</span><br><span class=\"line\">224</span><br><span class=\"line\">225</span><br><span class=\"line\">226</span><br><span class=\"line\">227</span><br><span class=\"line\">228</span><br><span class=\"line\">229</span><br><span class=\"line\">230</span><br><span class=\"line\">231</span><br><span class=\"line\">232</span><br><span class=\"line\">233</span><br><span class=\"line\">234</span><br><span class=\"line\">235</span><br><span class=\"line\">236</span><br><span class=\"line\">237</span><br><span class=\"line\">238</span><br><span class=\"line\">239</span><br><span class=\"line\">240</span><br><span class=\"line\">241</span><br><span class=\"line\">242</span><br><span class=\"line\">243</span><br><span class=\"line\">244</span><br><span class=\"line\">245</span><br><span class=\"line\">246</span><br><span class=\"line\">247</span><br><span class=\"line\">248</span><br><span class=\"line\">249</span><br><span class=\"line\">250</span><br><span class=\"line\">251</span><br><span class=\"line\">252</span><br><span class=\"line\">253</span><br><span class=\"line\">254</span><br><span class=\"line\">255</span><br><span class=\"line\">256</span><br><span class=\"line\">257</span><br><span class=\"line\">258</span><br><span class=\"line\">259</span><br><span class=\"line\">260</span><br><span class=\"line\">261</span><br><span class=\"line\">262</span><br><span class=\"line\">263</span><br><span class=\"line\">264</span><br><span class=\"line\">265</span><br><span class=\"line\">266</span><br><span class=\"line\">267</span><br><span class=\"line\">268</span><br><span class=\"line\">269</span><br><span class=\"line\">270</span><br><span class=\"line\">271</span><br><span class=\"line\">272</span><br><span class=\"line\">273</span><br><span class=\"line\">274</span><br><span class=\"line\">275</span><br><span class=\"line\">276</span><br><span class=\"line\">277</span><br><span class=\"line\">278</span><br><span class=\"line\">279</span><br><span class=\"line\">280</span><br><span class=\"line\">281</span><br><span class=\"line\">282</span><br><span class=\"line\">283</span><br><span class=\"line\">284</span><br><span class=\"line\">285</span><br><span class=\"line\">286</span><br><span class=\"line\">287</span><br><span class=\"line\">288</span><br><span class=\"line\">289</span><br><span class=\"line\">290</span><br><span class=\"line\">291</span><br><span class=\"line\">292</span><br><span class=\"line\">293</span><br><span class=\"line\">294</span><br><span class=\"line\">295</span><br><span class=\"line\">296</span><br><span class=\"line\">297</span><br><span class=\"line\">298</span><br><span class=\"line\">299</span><br><span class=\"line\">300</span><br><span class=\"line\">301</span><br><span class=\"line\">302</span><br><span class=\"line\">303</span><br><span class=\"line\">304</span><br><span class=\"line\">305</span><br><span class=\"line\">306</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 示例</span></span><br><span class=\"line\"> <span class=\"type\">double</span> progress = <span class=\"number\">0.5</span>; <span class=\"comment\">// 进度</span></span><br><span class=\"line\"> <span class=\"type\">double</span> startValue = <span class=\"number\">0</span>; <span class=\"comment\">// 开始数值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> endValue = <span class=\"number\">100</span>; <span class=\"comment\">// 结束数值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> segments = <span class=\"number\">10</span>; <span class=\"comment\">// 分段数</span></span><br><span class=\"line\"> <span class=\"type\">double</span> result = <span class=\"built_in\">Easing</span>(progress, startValue, endValue, segments);</span><br><span class=\"line\"> std::cout << <span class=\"string\">"Easing price: "</span> << result << std::endl;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\">RGBA <span class=\"title\">ColorDifference</span><span class=\"params\">(<span class=\"type\">const</span> RGBA& start, <span class=\"type\">const</span> RGBA& end, <span class=\"type\">double</span> t)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">RGBA</span>(start.R + (end.R - start.R) * t, </span><br><span class=\"line\"> start.G + (end.G - start.G) * t,</span><br><span class=\"line\"> start.B + (end.B - start.B) * t,</span><br><span class=\"line\"> start.A + (end.A - start.A) * t);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"type\">double</span> _getOutBounce(<span class=\"type\">double</span> begin_,<span class=\"type\">double</span> end_,<span class=\"type\">double</span> percent_){</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = end_ - begin_;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = percent_;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span> ÷ <span class=\"number\">2.75</span>) <span class=\"keyword\">return</span> _ed * <span class=\"number\">7.5625</span> * _st * _st + begin_;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_st < <span class=\"number\">2</span> ÷ <span class=\"number\">2.75</span>) {_st = _st - <span class=\"number\">1.5</span> ÷ <span class=\"number\">2.75</span>; <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.75</span>) + begin_;}</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_st < <span class=\"number\">2.5</span> ÷ <span class=\"number\">2.75</span>) {_st = _st - <span class=\"number\">2.25</span> ÷ <span class=\"number\">2.75</span>; <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.9375</span>) + begin_;}</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2.625</span> ÷ <span class=\"number\">2.75</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * (<span class=\"number\">7.5625</span> * _st * _st + <span class=\"number\">0.984375</span>) + begin_;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"type\">double</span> _getInBounce(<span class=\"type\">double</span> begin_,<span class=\"type\">double</span> end_,<span class=\"type\">double</span> percent_){</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = end_ - begin_;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed - _getOutBounce (<span class=\"number\">0</span>, _ed, <span class=\"number\">1</span> - percent_) + begin_;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Linear</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> ((_End - _Start) * percents_ * percents_ + _Start);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuad</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) * percents_ * (percents_ - <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuad</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ts = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_ts < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> (_End - _Start) ÷ <span class=\"number\">2</span> * _ts * _ts + _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) ÷ <span class=\"number\">2</span> * (_ts * (_ts - <span class=\"number\">2</span>) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * (_st * _st * _st + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutCubic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(_st < <span class=\"number\">1</span>)<span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_End - _Start) * (_st * _st * _st * _st - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuart</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st * _st - <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (_End - _Start) * percents_ * percents_ * percents_ * percents_ * percents_ + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * (_st * _st * _st * _st * _st + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutQuint</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * _st * _st * _st * _st * _st + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (_st * _st * _st * _st * _st + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 * <span class=\"built_in\">cos</span> (percents_ ÷ <span class=\"number\">1</span> * M_PI ÷ <span class=\"number\">2</span>) + _ed1 + _Start;</span><br><span class=\"line\">} </span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">sin</span> (percents_ ÷ <span class=\"number\">1</span> * M_PI ÷ <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutSine</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">10</span> * (percents_ ÷ <span class=\"number\">1</span> - <span class=\"number\">1</span>)) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutExpo</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * <span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">10</span> * (_st - <span class=\"number\">1</span>)) + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (-<span class=\"built_in\">pow</span> (<span class=\"number\">2</span>, <span class=\"number\">-10</span> * _st) + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -_ed1 * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - percents_ * percents_) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 * <span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutCirc</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed1 = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) <span class=\"keyword\">return</span> -_ed1 ÷ <span class=\"number\">2</span> * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) - <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\"> _st = _st - <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed1 ÷ <span class=\"number\">2</span> * (<span class=\"built_in\">sqrt</span> (<span class=\"number\">1</span> - _st * _st) + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getInBounce(_Start, _End, percents_);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getOutBounce(_Start, _End, percents_);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutBounce</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0.5</span>) <span class=\"keyword\">return</span> _getInBounce (<span class=\"number\">0</span>, _ed, percents_ * <span class=\"number\">2</span>) * <span class=\"number\">0.5</span> + _Start;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _getOutBounce (<span class=\"number\">0</span>, _ed, percents_ * <span class=\"number\">2</span> - <span class=\"number\">1</span>) * <span class=\"number\">0.5</span> + _ed * <span class=\"number\">0.5</span> + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * percents_ * percents_ * ((_s + <span class=\"number\">1</span>) * percents_ - _s) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed * (_st * _st * ((_s + <span class=\"number\">1</span>) * _st + _s) + <span class=\"number\">1</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutBack</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">1.70158</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>){_s = _s * <span class=\"number\">1.525</span>; <span class=\"keyword\">return</span> _ed ÷ <span class=\"number\">2</span> * _st * _st * ((_s + <span class=\"number\">1</span>) * _st - _s) + _Start;}</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = _st - <span class=\"number\">2</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _s = _s * <span class=\"number\">1.525</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> _ed ÷ <span class=\"number\">2</span> * (_st * _st * ((_s + <span class=\"number\">1</span>) * _st + _s) + <span class=\"number\">2</span>) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InElastic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress,<span class=\"type\">double</span> _Start,<span class=\"type\">double</span> _End,<span class=\"type\">double</span> _segments)</span></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents < <span class=\"number\">0</span>) percents = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents > <span class=\"number\">1</span>) percents = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(percents_ == <span class=\"number\">0</span>) <span class=\"keyword\">return</span> _Start;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(percents_ == <span class=\"number\">1</span>) <span class=\"keyword\">return</span> _End;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _End - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span></span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a = <span class=\"number\">0</span> || _a < <span class=\"built_in\">ads</span>(_ed)){_a = _ed; _s = _p ÷ <span class=\"number\">4</span>} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * std::<span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents - <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> -(_a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p)) + _Start;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">OutElastic</span><span class=\"params\">(<span class=\"type\">double</span> _Progress, <span class=\"type\">double</span> _Start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _Progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _Start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a == <span class=\"number\">0</span> || _a < <span class=\"built_in\">abs</span>(_ed)) {_a = _ed;_s = _p / <span class=\"number\">4</span>;} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * percents) * <span class=\"built_in\">sin</span>((percents * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) + _end;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">InOutElastic</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _start;</span><br><span class=\"line\"> <span class=\"type\">double</span> _d = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _p = _d * <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _a = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = percents_ * <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st == <span class=\"number\">2</span>) {<span class=\"keyword\">return</span> _end;}</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_a == <span class=\"number\">0</span> || _a < <span class=\"built_in\">abs</span>(_ed)) {_a = _ed;_s = _p / <span class=\"number\">4</span>;} <span class=\"keyword\">else</span> {_s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(_ed / _a);}</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_st < <span class=\"number\">1</span>) {_st -= <span class=\"number\">1</span>;<span class=\"keyword\">return</span> <span class=\"number\">-0.5</span> * _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) + _start;}</span><br><span class=\"line\"> _st -= <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _a * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * _st) * <span class=\"built_in\">sin</span>((_st * _d - _s) * <span class=\"number\">2</span> * M_PI / _p) * <span class=\"number\">0.5</span> + _end;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Clerp</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _ed = _end - _start;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _min = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _max = <span class=\"number\">360</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _half = <span class=\"number\">180</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _retval = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _diff = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (_ed < -_half) {</span><br><span class=\"line\"> _diff = (_max - _start + _end) * percents_;</span><br><span class=\"line\"> _retval = _start + _diff;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (_ed > _half) {</span><br><span class=\"line\"> _diff = -(_max - _end + _start) * percents_;</span><br><span class=\"line\"> _retval = _start + _diff;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> _retval = _start + _ed * percents_;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _retval;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Spring</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _st = <span class=\"built_in\">sin</span>(percents_ * M_PI * (<span class=\"number\">0.2</span> + <span class=\"number\">2.5</span> * percents_ * percents_ * percents_)) * <span class=\"built_in\">pow</span>(<span class=\"number\">1</span> - percents_, <span class=\"number\">2.2</span>) + percents_;</span><br><span class=\"line\"> _st = _st * (<span class=\"number\">1</span> + <span class=\"number\">1.2</span> * (<span class=\"number\">1</span> - percents_));</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _start + (_end - _start) * _st;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">Punch</span><span class=\"params\">(<span class=\"type\">double</span> _progress, <span class=\"type\">double</span> _start, <span class=\"type\">double</span> _end, <span class=\"type\">double</span> _segments)</span> </span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> percents_ = _progress / _segments;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ < <span class=\"number\">0</span>) percents_ = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (percents_ > <span class=\"number\">1</span>) percents_ = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ == <span class=\"number\">0</span>) <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (percents_ == <span class=\"number\">1</span>) <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">double</span> _p = <span class=\"number\">0.3</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> _s = _p / (<span class=\"number\">2</span> * M_PI) * <span class=\"built_in\">asin</span>(<span class=\"number\">0</span>);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> _end * <span class=\"built_in\">pow</span>(<span class=\"number\">2</span>, <span class=\"number\">-10</span> * percents) * <span class=\"built_in\">sin</span>((percents - _s) * <span class=\"number\">2</span> * M_PI / _p);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<h1 id=\"这是什么!\"><a href=\"#这是什么!\" class=\"headerlink\" title=\"这是什么!\"></a>这是什么!</h1><p><img src=\"/articles/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg\" alt=\"ICON\"></p>"},{"title":"一些开箱即用碰撞检测!AABB","date":"2024-05-27T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"听说有群友已经不满足于,大V老师提供的简单检测方法了,那么让我们为自己的游戏增加更多有趣的碰撞检测罢!\n全文采用AABB实现,包含矩矩,圆圆,矩圆,角度矩圆,椭圆,点矩,点环,点圆,点椭,等,必要情况下只要根据下文中的算法自行修改或嵌套使用即可!\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n## 在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\n```cpp\n// 定义一个结构体,表示二维空间中的点\nstruct Point_F {\n double x; // 点的x坐标\n double y; // 点的y坐标\n};\n\n// 定义一个结构体,表示矩形区域\nstruct RECT {\n double left; // 矩形左边缘的x坐标\n double top; // 矩形上边缘的y坐标\n double right; // 矩形右边缘的x坐标\n double bottom; // 矩形下边缘的y坐标\n};\n\n// 判断点是否在矩形区域内\nbool AABBPointInside(const Point_F& V, const RECT& RECT) {\n return (V.x > RECT.left && V.x < RECT.right && V.y > RECT.top && V.y < RECT.bottom);\n}\n// 判断一个矩形是否完全在另一个矩形内部\nbool AABBRectInside(const RECT& rect1, const RECT& rect2) {\n return (rect2.left >= rect1.left && rect2.right <= rect1.right && rect2.top >= rect1.top && rect2.bottom <= rect1.bottom);\n}\n// 判断两个矩形是否重叠\nbool AABBRectOverlap(const RECT& rect1, const RECT& rect2) {\n return (rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom) ? false : true;\n}\n// 判断矩形与圆形是否重叠,考虑矩形旋转的情况\nbool AABBRectCircleOverlap(double rectCenterX, double rectCenterY, double rectWidth, double rectHeight, double angle, double circleX, double circleY, double circleRadius) {\n // 计算旋转后的向量坐标\n double vectorX = circleX - rectCenterX;\n double vectorY = circleY - rectCenterY;\n double radians = angle * M_PI / 180.0;\n double x = vectorX * cos(radians) + vectorY * sin(radians);\n double y = vectorY * cos(radians) - vectorX * sin(radians);\n // 计算矩形的半宽和半高\n double halfWidth = rectWidth * 0.5;\n double halfHeight = rectHeight * 0.5;\n if (x - circleRadius < halfWidth && x + circleRadius > -halfWidth) {\n if (y - circleRadius < halfHeight && y + circleRadius > -halfHeight) {\n if (x < -halfWidth && y < -halfHeight){\n if (distance(x, y, -halfWidth, -halfHeight) >= circleRadius) { return true; }\n }\n else if (x < halfWidth && y < -halfHeight){\n if (distance(x, y, halfWidth, -halfHeight) >= circleRadius) { return true; }\n }\n else if (x > halfWidth && y > halfHeight){\n if (distance(x, y, halfWidth, halfHeight) >= circleRadius) { return true; }\n }\n else if (x < -halfWidth && y > halfHeight) {\n if (distance(x, y, -halfWidth, halfHeight) >= circleRadius) { return true; }\n }\n }\n return true;\n }\n return false;\n}\n// 判断点是否在圆内\nbool AABBPointInCircle(double pointX, double pointY, double circleCenterX, double circleCenterY, double circleRadius) {\n // 计算点到圆心的距离,判断是否小于等于半径\n double dx = pointX - circleCenterX;\n double dy = pointY - circleCenterY;\n return sqrt(dx * dx + dy * dy) <= circleRadius;\n}\n// 判断两个圆是否相交\nbool AABBCirclesIntersect(double circleCenterX1, double circleCenterY1, double circleRadius1, double circleCenterX2, double circleCenterY2, double circleRadius2) {\n // 计算两个圆心之间的距离,判断是否小于等于两个圆的半径之和\n double dx = circleCenterX1 - circleCenterX2;\n double dy = circleCenterY1 - circleCenterY2;\n return sqrt(dx * dx + dy * dy) <= circleRadius1 + circleRadius2;\n}\n// 判断点是否在圆环内\nbool AABBPointInAnnulus(double x, double y, double circleCenterX, double circleCenterY, double circleRadius, double innerThickness, double outerThickness) {\n // 计算点到圆心的距离\n double dx = x - circleCenterX;\n double dy = y - circleCenterY;\n double dist = sqrt(dx * dx + dy * dy);\n // 判断距离是否在内圆半径和外圆半径之间\n return (dist <= circleRadius + outerThickness && dist >= circleRadius - innerThickness);\n}\n// 判断点是否在椭圆内\nbool AABBPointInEllipse(double centerX, double centerY, double radiusA, double radiusB, double x, double y) {\n // 计算点到椭圆中心的距离,并与椭圆的参数化方程比较\n double dx = centerX - x;\n double dy = centerY - y;\n return (dx * dx / (radiusA * radiusA) + dy * dy / (radiusB * radiusB)) <= 1;\n}\n```\n","source":"_posts/QiNuoTu/一些包围盒类碰撞检测算法.md","raw":"---\ntitle: 一些开箱即用碰撞检测!AABB\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/QiNuoTu/一些包围盒类碰撞检测算法/\ncategories: QiNuoTu\ntags: [游戏开发]\n---\n听说有群友已经不满足于,大V老师提供的简单检测方法了,那么让我们为自己的游戏增加更多有趣的碰撞检测罢!\n全文采用AABB实现,包含矩矩,圆圆,矩圆,角度矩圆,椭圆,点矩,点环,点圆,点椭,等,必要情况下只要根据下文中的算法自行修改或嵌套使用即可!\n<!-- More -->\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n## 在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\n```cpp\n// 定义一个结构体,表示二维空间中的点\nstruct Point_F {\n double x; // 点的x坐标\n double y; // 点的y坐标\n};\n\n// 定义一个结构体,表示矩形区域\nstruct RECT {\n double left; // 矩形左边缘的x坐标\n double top; // 矩形上边缘的y坐标\n double right; // 矩形右边缘的x坐标\n double bottom; // 矩形下边缘的y坐标\n};\n\n// 判断点是否在矩形区域内\nbool AABBPointInside(const Point_F& V, const RECT& RECT) {\n return (V.x > RECT.left && V.x < RECT.right && V.y > RECT.top && V.y < RECT.bottom);\n}\n// 判断一个矩形是否完全在另一个矩形内部\nbool AABBRectInside(const RECT& rect1, const RECT& rect2) {\n return (rect2.left >= rect1.left && rect2.right <= rect1.right && rect2.top >= rect1.top && rect2.bottom <= rect1.bottom);\n}\n// 判断两个矩形是否重叠\nbool AABBRectOverlap(const RECT& rect1, const RECT& rect2) {\n return (rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom) ? false : true;\n}\n// 判断矩形与圆形是否重叠,考虑矩形旋转的情况\nbool AABBRectCircleOverlap(double rectCenterX, double rectCenterY, double rectWidth, double rectHeight, double angle, double circleX, double circleY, double circleRadius) {\n // 计算旋转后的向量坐标\n double vectorX = circleX - rectCenterX;\n double vectorY = circleY - rectCenterY;\n double radians = angle * M_PI / 180.0;\n double x = vectorX * cos(radians) + vectorY * sin(radians);\n double y = vectorY * cos(radians) - vectorX * sin(radians);\n // 计算矩形的半宽和半高\n double halfWidth = rectWidth * 0.5;\n double halfHeight = rectHeight * 0.5;\n if (x - circleRadius < halfWidth && x + circleRadius > -halfWidth) {\n if (y - circleRadius < halfHeight && y + circleRadius > -halfHeight) {\n if (x < -halfWidth && y < -halfHeight){\n if (distance(x, y, -halfWidth, -halfHeight) >= circleRadius) { return true; }\n }\n else if (x < halfWidth && y < -halfHeight){\n if (distance(x, y, halfWidth, -halfHeight) >= circleRadius) { return true; }\n }\n else if (x > halfWidth && y > halfHeight){\n if (distance(x, y, halfWidth, halfHeight) >= circleRadius) { return true; }\n }\n else if (x < -halfWidth && y > halfHeight) {\n if (distance(x, y, -halfWidth, halfHeight) >= circleRadius) { return true; }\n }\n }\n return true;\n }\n return false;\n}\n// 判断点是否在圆内\nbool AABBPointInCircle(double pointX, double pointY, double circleCenterX, double circleCenterY, double circleRadius) {\n // 计算点到圆心的距离,判断是否小于等于半径\n double dx = pointX - circleCenterX;\n double dy = pointY - circleCenterY;\n return sqrt(dx * dx + dy * dy) <= circleRadius;\n}\n// 判断两个圆是否相交\nbool AABBCirclesIntersect(double circleCenterX1, double circleCenterY1, double circleRadius1, double circleCenterX2, double circleCenterY2, double circleRadius2) {\n // 计算两个圆心之间的距离,判断是否小于等于两个圆的半径之和\n double dx = circleCenterX1 - circleCenterX2;\n double dy = circleCenterY1 - circleCenterY2;\n return sqrt(dx * dx + dy * dy) <= circleRadius1 + circleRadius2;\n}\n// 判断点是否在圆环内\nbool AABBPointInAnnulus(double x, double y, double circleCenterX, double circleCenterY, double circleRadius, double innerThickness, double outerThickness) {\n // 计算点到圆心的距离\n double dx = x - circleCenterX;\n double dy = y - circleCenterY;\n double dist = sqrt(dx * dx + dy * dy);\n // 判断距离是否在内圆半径和外圆半径之间\n return (dist <= circleRadius + outerThickness && dist >= circleRadius - innerThickness);\n}\n// 判断点是否在椭圆内\nbool AABBPointInEllipse(double centerX, double centerY, double radiusA, double radiusB, double x, double y) {\n // 计算点到椭圆中心的距离,并与椭圆的参数化方程比较\n double dx = centerX - x;\n double dy = centerY - y;\n return (dx * dx / (radiusA * radiusA) + dy * dy / (radiusB * radiusB)) <= 1;\n}\n```\n","slug":"QiNuoTu/一些包围盒类碰撞检测算法","published":1,"__permalink":"articles/QiNuoTu/一些包围盒类碰撞检测算法/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgg000po8ye0cbe7qrr","content":"<p>听说有群友已经不满足于,大V老师提供的简单检测方法了,那么让我们为自己的游戏增加更多有趣的碰撞检测罢!<br>全文采用AABB实现,包含矩矩,圆圆,矩圆,角度矩圆,椭圆,点矩,点环,点圆,点椭,等,必要情况下只要根据下文中的算法自行修改或嵌套使用即可!</p>\n<span id=\"more\"></span>\n<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h2 id=\"在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\"><a href=\"#在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\" class=\"headerlink\" title=\"在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\"></a>在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">// 定义一个结构体,表示二维空间中的点</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Point_F</span> {</span><br><span class=\"line\"> <span class=\"type\">double</span> x; <span class=\"comment\">// 点的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> y; <span class=\"comment\">// 点的y坐标</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 定义一个结构体,表示矩形区域</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">RECT</span> {</span><br><span class=\"line\"> <span class=\"type\">double</span> left; <span class=\"comment\">// 矩形左边缘的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> top; <span class=\"comment\">// 矩形上边缘的y坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> right; <span class=\"comment\">// 矩形右边缘的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> bottom; <span class=\"comment\">// 矩形下边缘的y坐标</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在矩形区域内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInside</span><span class=\"params\">(<span class=\"type\">const</span> Point_F& V, <span class=\"type\">const</span> RECT& RECT)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (V.x > RECT.left && V.x < RECT.right && V.y > RECT.top && V.y < RECT.bottom);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断一个矩形是否完全在另一个矩形内部</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectInside</span><span class=\"params\">(<span class=\"type\">const</span> RECT& rect1, <span class=\"type\">const</span> RECT& rect2)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (rect2.left >= rect1.left && rect2.right <= rect1.right && rect2.top >= rect1.top && rect2.bottom <= rect1.bottom);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断两个矩形是否重叠</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectOverlap</span><span class=\"params\">(<span class=\"type\">const</span> RECT& rect1, <span class=\"type\">const</span> RECT& rect2)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom) ? <span class=\"literal\">false</span> : <span class=\"literal\">true</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断矩形与圆形是否重叠,考虑矩形旋转的情况</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectCircleOverlap</span><span class=\"params\">(<span class=\"type\">double</span> rectCenterX, <span class=\"type\">double</span> rectCenterY, <span class=\"type\">double</span> rectWidth, <span class=\"type\">double</span> rectHeight, <span class=\"type\">double</span> angle, <span class=\"type\">double</span> circleX, <span class=\"type\">double</span> circleY, <span class=\"type\">double</span> circleRadius)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算旋转后的向量坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> vectorX = circleX - rectCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> vectorY = circleY - rectCenterY;</span><br><span class=\"line\"> <span class=\"type\">double</span> radians = angle * M_PI / <span class=\"number\">180.0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> x = vectorX * <span class=\"built_in\">cos</span>(radians) + vectorY * <span class=\"built_in\">sin</span>(radians);</span><br><span class=\"line\"> <span class=\"type\">double</span> y = vectorY * <span class=\"built_in\">cos</span>(radians) - vectorX * <span class=\"built_in\">sin</span>(radians);</span><br><span class=\"line\"> <span class=\"comment\">// 计算矩形的半宽和半高</span></span><br><span class=\"line\"> <span class=\"type\">double</span> halfWidth = rectWidth * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> halfHeight = rectHeight * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (x - circleRadius < halfWidth && x + circleRadius > -halfWidth) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (y - circleRadius < halfHeight && y + circleRadius > -halfHeight) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (x < -halfWidth && y < -halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, -halfWidth, -halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x < halfWidth && y < -halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, halfWidth, -halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x > halfWidth && y > halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, halfWidth, halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x < -halfWidth && y > halfHeight) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, -halfWidth, halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在圆内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInCircle</span><span class=\"params\">(<span class=\"type\">double</span> pointX, <span class=\"type\">double</span> pointY, <span class=\"type\">double</span> circleCenterX, <span class=\"type\">double</span> circleCenterY, <span class=\"type\">double</span> circleRadius)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到圆心的距离,判断是否小于等于半径</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = pointX - circleCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = pointY - circleCenterY;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy) <= circleRadius;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断两个圆是否相交</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBCirclesIntersect</span><span class=\"params\">(<span class=\"type\">double</span> circleCenterX1, <span class=\"type\">double</span> circleCenterY1, <span class=\"type\">double</span> circleRadius1, <span class=\"type\">double</span> circleCenterX2, <span class=\"type\">double</span> circleCenterY2, <span class=\"type\">double</span> circleRadius2)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算两个圆心之间的距离,判断是否小于等于两个圆的半径之和</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = circleCenterX1 - circleCenterX2;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = circleCenterY1 - circleCenterY2;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy) <= circleRadius1 + circleRadius2;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在圆环内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInAnnulus</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y, <span class=\"type\">double</span> circleCenterX, <span class=\"type\">double</span> circleCenterY, <span class=\"type\">double</span> circleRadius, <span class=\"type\">double</span> innerThickness, <span class=\"type\">double</span> outerThickness)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到圆心的距离</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = x - circleCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = y - circleCenterY;</span><br><span class=\"line\"> <span class=\"type\">double</span> dist = <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy);</span><br><span class=\"line\"> <span class=\"comment\">// 判断距离是否在内圆半径和外圆半径之间</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> (dist <= circleRadius + outerThickness && dist >= circleRadius - innerThickness);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在椭圆内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInEllipse</span><span class=\"params\">(<span class=\"type\">double</span> centerX, <span class=\"type\">double</span> centerY, <span class=\"type\">double</span> radiusA, <span class=\"type\">double</span> radiusB, <span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到椭圆中心的距离,并与椭圆的参数化方程比较</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = centerX - x;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = centerY - y;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (dx * dx / (radiusA * radiusA) + dy * dy / (radiusB * radiusB)) <= <span class=\"number\">1</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n","site":{"data":{}},"excerpt":"<p>听说有群友已经不满足于,大V老师提供的简单检测方法了,那么让我们为自己的游戏增加更多有趣的碰撞检测罢!<br>全文采用AABB实现,包含矩矩,圆圆,矩圆,角度矩圆,椭圆,点矩,点环,点圆,点椭,等,必要情况下只要根据下文中的算法自行修改或嵌套使用即可!</p>","more":"<div align=\"center\">\n <p align=\"center\">\n <img src=\"/articles/QiNuoTu/icon.png\" alt=\"logo\" width=\"200\">\n </p>\n <h1>琪诺兔</h1>\n <p>\n <a href=\"https://space.bilibili.com/69720374\" target=\"_blank\">关注我的哔哩哔哩走进我的生活</a>\n | \n <a href=\"https://github.com/QiNuoTu\" target=\"_blank\">关注我的GitHub获得我的代码</a>\n </p>\n</div>\n\n<h2 id=\"在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\"><a href=\"#在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\" class=\"headerlink\" title=\"在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。\"></a>在下文中,大家可能会发现,为什么没有旋转过的两个矩形的碰撞,那不是AABB了,未来在说。</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">// 定义一个结构体,表示二维空间中的点</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Point_F</span> {</span><br><span class=\"line\"> <span class=\"type\">double</span> x; <span class=\"comment\">// 点的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> y; <span class=\"comment\">// 点的y坐标</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 定义一个结构体,表示矩形区域</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">RECT</span> {</span><br><span class=\"line\"> <span class=\"type\">double</span> left; <span class=\"comment\">// 矩形左边缘的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> top; <span class=\"comment\">// 矩形上边缘的y坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> right; <span class=\"comment\">// 矩形右边缘的x坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> bottom; <span class=\"comment\">// 矩形下边缘的y坐标</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在矩形区域内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInside</span><span class=\"params\">(<span class=\"type\">const</span> Point_F& V, <span class=\"type\">const</span> RECT& RECT)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (V.x > RECT.left && V.x < RECT.right && V.y > RECT.top && V.y < RECT.bottom);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断一个矩形是否完全在另一个矩形内部</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectInside</span><span class=\"params\">(<span class=\"type\">const</span> RECT& rect1, <span class=\"type\">const</span> RECT& rect2)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (rect2.left >= rect1.left && rect2.right <= rect1.right && rect2.top >= rect1.top && rect2.bottom <= rect1.bottom);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断两个矩形是否重叠</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectOverlap</span><span class=\"params\">(<span class=\"type\">const</span> RECT& rect1, <span class=\"type\">const</span> RECT& rect2)</span> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom) ? <span class=\"literal\">false</span> : <span class=\"literal\">true</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断矩形与圆形是否重叠,考虑矩形旋转的情况</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBRectCircleOverlap</span><span class=\"params\">(<span class=\"type\">double</span> rectCenterX, <span class=\"type\">double</span> rectCenterY, <span class=\"type\">double</span> rectWidth, <span class=\"type\">double</span> rectHeight, <span class=\"type\">double</span> angle, <span class=\"type\">double</span> circleX, <span class=\"type\">double</span> circleY, <span class=\"type\">double</span> circleRadius)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算旋转后的向量坐标</span></span><br><span class=\"line\"> <span class=\"type\">double</span> vectorX = circleX - rectCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> vectorY = circleY - rectCenterY;</span><br><span class=\"line\"> <span class=\"type\">double</span> radians = angle * M_PI / <span class=\"number\">180.0</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> x = vectorX * <span class=\"built_in\">cos</span>(radians) + vectorY * <span class=\"built_in\">sin</span>(radians);</span><br><span class=\"line\"> <span class=\"type\">double</span> y = vectorY * <span class=\"built_in\">cos</span>(radians) - vectorX * <span class=\"built_in\">sin</span>(radians);</span><br><span class=\"line\"> <span class=\"comment\">// 计算矩形的半宽和半高</span></span><br><span class=\"line\"> <span class=\"type\">double</span> halfWidth = rectWidth * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> halfHeight = rectHeight * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (x - circleRadius < halfWidth && x + circleRadius > -halfWidth) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (y - circleRadius < halfHeight && y + circleRadius > -halfHeight) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (x < -halfWidth && y < -halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, -halfWidth, -halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x < halfWidth && y < -halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, halfWidth, -halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x > halfWidth && y > halfHeight){</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, halfWidth, halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (x < -halfWidth && y > halfHeight) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"built_in\">distance</span>(x, y, -halfWidth, halfHeight) >= circleRadius) { <span class=\"keyword\">return</span> <span class=\"literal\">true</span>; }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">false</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在圆内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInCircle</span><span class=\"params\">(<span class=\"type\">double</span> pointX, <span class=\"type\">double</span> pointY, <span class=\"type\">double</span> circleCenterX, <span class=\"type\">double</span> circleCenterY, <span class=\"type\">double</span> circleRadius)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到圆心的距离,判断是否小于等于半径</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = pointX - circleCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = pointY - circleCenterY;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy) <= circleRadius;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断两个圆是否相交</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBCirclesIntersect</span><span class=\"params\">(<span class=\"type\">double</span> circleCenterX1, <span class=\"type\">double</span> circleCenterY1, <span class=\"type\">double</span> circleRadius1, <span class=\"type\">double</span> circleCenterX2, <span class=\"type\">double</span> circleCenterY2, <span class=\"type\">double</span> circleRadius2)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算两个圆心之间的距离,判断是否小于等于两个圆的半径之和</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = circleCenterX1 - circleCenterX2;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = circleCenterY1 - circleCenterY2;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy) <= circleRadius1 + circleRadius2;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在圆环内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInAnnulus</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y, <span class=\"type\">double</span> circleCenterX, <span class=\"type\">double</span> circleCenterY, <span class=\"type\">double</span> circleRadius, <span class=\"type\">double</span> innerThickness, <span class=\"type\">double</span> outerThickness)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到圆心的距离</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = x - circleCenterX;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = y - circleCenterY;</span><br><span class=\"line\"> <span class=\"type\">double</span> dist = <span class=\"built_in\">sqrt</span>(dx * dx + dy * dy);</span><br><span class=\"line\"> <span class=\"comment\">// 判断距离是否在内圆半径和外圆半径之间</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> (dist <= circleRadius + outerThickness && dist >= circleRadius - innerThickness);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"comment\">// 判断点是否在椭圆内</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">bool</span> <span class=\"title\">AABBPointInEllipse</span><span class=\"params\">(<span class=\"type\">double</span> centerX, <span class=\"type\">double</span> centerY, <span class=\"type\">double</span> radiusA, <span class=\"type\">double</span> radiusB, <span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span> </span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算点到椭圆中心的距离,并与椭圆的参数化方程比较</span></span><br><span class=\"line\"> <span class=\"type\">double</span> dx = centerX - x;</span><br><span class=\"line\"> <span class=\"type\">double</span> dy = centerY - y;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (dx * dx / (radiusA * radiusA) + dy * dy / (radiusB * radiusB)) <= <span class=\"number\">1</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>"},{"title":"Boids集群算法浅析与实践","date":"2024-05-31T16:00:00.000Z","updated":"2024-05-31T16:00:00.000Z","_content":"\n> 鸟群算法 Boids是模拟鸟类群集行为的人工生命项目,由克雷格·雷诺兹(Craig Reynolds)于1986年开发。Boids 是涌现行为的典例,其复杂性来自于遵循一系列简单规则个体的相互作用。\n\nBoids 通常用于计算机图形学,提供鸟群和其他生物(如鱼群)的逼真表现:\n\n+ 《史丹利和史黛拉: 破冰》是第一部利用了 Boids 模型的动画片;\n+ 《半条命》中,游戏结束时出现的类似鸟类的飞行生物就使用了该模型;\n+ 《蝙蝠侠归来》电影中,蝙蝠群和成群的企鹅行进穿过哥谭市的街道时使用了该模型;\n+ 《黑客帝国》/《重装前哨》中,章鱼外形的哨兵机器人的集群特效使用了该模型。\n\n<div style=\"text-align:center\">\n\n![分离(左) - 聚集(中) - 对齐(右)](articles/Voidmatrix/boids-algorithm/231573721246935.png)\n\n</div>\n\n<!-- more -->\n\nBoids 模型由三种规则描述:\n\n1. **分离**:个体之间存在排斥趋向,自主移动避开群体拥挤处;\n3. **聚集**:个体会朝向周围同伴所处的平均位置处移动;\n2. **对齐**:个体会朝向周围同伴的平均移动方向运动。\n\n\n> 下面将使用 EasyX 可视化该算法。\n\n## 随机个体位置着色\n\n```cpp\nstd::vector<Boid> boids(500);\nfor (Boid& b : boids)\n{\n b.position.x = (float)(rand() % 1280);\n b.position.y = (float)(rand() % 720);\n b.color = RGB(rand() % 255, rand() % 255, rand() % 255);\n}\n```\n\n<div style=\"text-align:center\">\n\n![随机个体位置着色](articles/Voidmatrix/boids-algorithm/403754021267101.png)\n\n</div>\n\n## 添加“聚集”规则\n\n```cpp\nVector2D cohesion(const std::vector<Boid>& boids) \n{\n Vector2D center_of_mass(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance)\n {\n center_of_mass = center_of_mass + b.position;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n center_of_mass = center_of_mass * (1.0f / total_neighbors);\n return (center_of_mass - position);\n }\n\n return Vector2D(0, 0);\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则](articles/Voidmatrix/boids-algorithm/338824221259770.gif)\n\n</div>\n\n## 添加“分离”规则\n\n```cpp\nVector2D separation(const std::vector<Boid>& boids) \n{\n Vector2D separation(0, 0);\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < separation_distance) \n {\n Vector2D diff = position - b.position;\n separation = separation + diff * (1.0f / distance);\n }\n }\n\n return separation;\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则 + 分离规则](articles/Voidmatrix/boids-algorithm/294884321256325.gif)\n\n</div>\n\n## 添加“对齐”规则\n\n```cpp\nVector2D alignment(const std::vector<Boid>& boids) \n{\n Vector2D avg_velocity(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance) \n {\n avg_velocity = avg_velocity + b.velocity;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n avg_velocity = avg_velocity * (1.0f / total_neighbors);\n return avg_velocity - velocity;\n }\n\n return Vector2D(0, 0);\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则 + 分离规则 + 对齐规则](articles/Voidmatrix/boids-algorithm/101894421252079.gif)\n\n</div>\n\n## 完整代码\n\n```cpp\n#include <cmath>\n#include <vector>\n#include <iostream>\n#include <graphics.h>\n\n// 简单的二维向量\nstruct Vector2D \n{\n float x, y;\n\n Vector2D() = default;\n Vector2D(float _x, float _y) : x(_x), y(_y) {}\n\n Vector2D operator+(const Vector2D& other) const \n {\n return Vector2D(x + other.x, y + other.y);\n }\n\n Vector2D operator-(const Vector2D& other) const \n {\n return Vector2D(x - other.x, y - other.y);\n }\n\n Vector2D operator*(float scalar) const \n {\n return Vector2D(x * scalar, y * scalar);\n }\n\n float length() const \n {\n return std::sqrt(x * x + y * y);\n }\n\n void normalize() \n {\n float len = length();\n x /= len;\n y /= len;\n }\n};\n\n// 集群单位\nstruct Boid \n{\n COLORREF color;\n Vector2D position;\n Vector2D velocity;\n\n // 聚集规则\n Vector2D cohesion(const std::vector<Boid>& boids) \n {\n Vector2D center_of_mass(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance)\n {\n center_of_mass = center_of_mass + b.position;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n center_of_mass = center_of_mass * (1.0f / total_neighbors);\n return (center_of_mass - position);\n }\n\n return Vector2D(0, 0);\n }\n\n // 分离规则\n Vector2D separation(const std::vector<Boid>& boids) \n {\n Vector2D separation(0, 0);\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < separation_distance) \n {\n Vector2D diff = position - b.position;\n separation = separation + diff * (1.0f / distance);\n }\n }\n\n return separation;\n }\n\n // 对齐规则\n Vector2D alignment(const std::vector<Boid>& boids) \n {\n Vector2D avg_velocity(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance) \n {\n avg_velocity = avg_velocity + b.velocity;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n avg_velocity = avg_velocity * (1.0f / total_neighbors);\n return avg_velocity - velocity;\n }\n\n return Vector2D(0, 0);\n }\n\n // 更新方法\n void update(const std::vector<Boid>& boids) \n {\n Vector2D v1 = cohesion(boids);\n Vector2D v2 = separation(boids);\n Vector2D v3 = alignment(boids);\n\n // 根据规则权重调节最终行为\n v1 = v1 * cohesion_weight;\n v2 = v2 * separation_weight;\n v3 = v3 * align_weight;\n\n // 更新速度\n velocity = velocity + v1 + v2 + v3;\n\n // 限制速度\n float speed = velocity.length();\n if (speed > max_speed) velocity = velocity * (max_speed / speed);\n\n // 更新位置\n position = position + velocity;\n\n // 限制位置\n if (position.x < 0) position.x = 0;\n if (position.x > 1280) position.x = 1280;\n if (position.y < 0) position.y = 0;\n if (position.y > 720) position.y = 720;\n }\n\n float neighbour_distance = 100.0f; // 判定为临近单位的距离\n float separation_distance = 50.0f; // 临近单位的分离距离\n float cohesion_weight = 1.0f; // \"聚集\" 规则强度\n float separation_weight = 1.0f; // \"分离\" 规则强度 \n float align_weight = 1.0f; // \"对齐\" 规则强度\n float max_speed = 5.0f; // 集群最大速度\n};\n\nint main() \n{\n initgraph(1280, 720, EW_SHOWCONSOLE);\n BeginBatchDraw();\n\n // 初始化集群\n std::vector<Boid> boids(500);\n for (Boid& b : boids)\n {\n b.position.x = (float)(rand() % 1280);\n b.position.y = (float)(rand() % 720);\n b.color = RGB(rand() % 255, rand() % 255, rand() % 255);\n }\n\n // 循环模拟\n while (true) \n {\n // 更新集群\n for (Boid& b : boids)\n b.update(boids);\n\n // 渲染集群\n cleardevice();\n for (Boid& b : boids)\n {\n setfillcolor(b.color);\n fillcircle((int)b.position.x, (int)b.position.y, 10);\n }\n FlushBatchDraw();\n\n Sleep(25);\n }\n\n return 0;\n}\n```\n\n> 使用三角形等有指向性的元素,根据当前速度向量绘图模拟效果会更加清晰。\n\n<div style=\"text-align:center\">\n\n\\>\\>\\> [在 Voidmatrix's Blog 上查看本文章](https://www.voidmatrix.work/articles/boids-algorithm/) <<<\n\n</div>","source":"_posts/Voidmatrix/Boids集群算法浅析与实践.md","raw":"---\ntitle: Boids集群算法浅析与实践\ndate: 2024-06-01\nupdated: 2024-06-01\npermalink: articles/Voidmatrix/boids-algorithm/\ncategories: Voidmatrix\ntags: [EasyX, 算法, C++]\n---\n\n> 鸟群算法 Boids是模拟鸟类群集行为的人工生命项目,由克雷格·雷诺兹(Craig Reynolds)于1986年开发。Boids 是涌现行为的典例,其复杂性来自于遵循一系列简单规则个体的相互作用。\n\nBoids 通常用于计算机图形学,提供鸟群和其他生物(如鱼群)的逼真表现:\n\n+ 《史丹利和史黛拉: 破冰》是第一部利用了 Boids 模型的动画片;\n+ 《半条命》中,游戏结束时出现的类似鸟类的飞行生物就使用了该模型;\n+ 《蝙蝠侠归来》电影中,蝙蝠群和成群的企鹅行进穿过哥谭市的街道时使用了该模型;\n+ 《黑客帝国》/《重装前哨》中,章鱼外形的哨兵机器人的集群特效使用了该模型。\n\n<div style=\"text-align:center\">\n\n![分离(左) - 聚集(中) - 对齐(右)](articles/Voidmatrix/boids-algorithm/231573721246935.png)\n\n</div>\n\n<!-- more -->\n\nBoids 模型由三种规则描述:\n\n1. **分离**:个体之间存在排斥趋向,自主移动避开群体拥挤处;\n3. **聚集**:个体会朝向周围同伴所处的平均位置处移动;\n2. **对齐**:个体会朝向周围同伴的平均移动方向运动。\n\n\n> 下面将使用 EasyX 可视化该算法。\n\n## 随机个体位置着色\n\n```cpp\nstd::vector<Boid> boids(500);\nfor (Boid& b : boids)\n{\n b.position.x = (float)(rand() % 1280);\n b.position.y = (float)(rand() % 720);\n b.color = RGB(rand() % 255, rand() % 255, rand() % 255);\n}\n```\n\n<div style=\"text-align:center\">\n\n![随机个体位置着色](articles/Voidmatrix/boids-algorithm/403754021267101.png)\n\n</div>\n\n## 添加“聚集”规则\n\n```cpp\nVector2D cohesion(const std::vector<Boid>& boids) \n{\n Vector2D center_of_mass(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance)\n {\n center_of_mass = center_of_mass + b.position;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n center_of_mass = center_of_mass * (1.0f / total_neighbors);\n return (center_of_mass - position);\n }\n\n return Vector2D(0, 0);\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则](articles/Voidmatrix/boids-algorithm/338824221259770.gif)\n\n</div>\n\n## 添加“分离”规则\n\n```cpp\nVector2D separation(const std::vector<Boid>& boids) \n{\n Vector2D separation(0, 0);\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < separation_distance) \n {\n Vector2D diff = position - b.position;\n separation = separation + diff * (1.0f / distance);\n }\n }\n\n return separation;\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则 + 分离规则](articles/Voidmatrix/boids-algorithm/294884321256325.gif)\n\n</div>\n\n## 添加“对齐”规则\n\n```cpp\nVector2D alignment(const std::vector<Boid>& boids) \n{\n Vector2D avg_velocity(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance) \n {\n avg_velocity = avg_velocity + b.velocity;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n avg_velocity = avg_velocity * (1.0f / total_neighbors);\n return avg_velocity - velocity;\n }\n\n return Vector2D(0, 0);\n}\n```\n\n<div style=\"text-align:center\">\n\n![聚集规则 + 分离规则 + 对齐规则](articles/Voidmatrix/boids-algorithm/101894421252079.gif)\n\n</div>\n\n## 完整代码\n\n```cpp\n#include <cmath>\n#include <vector>\n#include <iostream>\n#include <graphics.h>\n\n// 简单的二维向量\nstruct Vector2D \n{\n float x, y;\n\n Vector2D() = default;\n Vector2D(float _x, float _y) : x(_x), y(_y) {}\n\n Vector2D operator+(const Vector2D& other) const \n {\n return Vector2D(x + other.x, y + other.y);\n }\n\n Vector2D operator-(const Vector2D& other) const \n {\n return Vector2D(x - other.x, y - other.y);\n }\n\n Vector2D operator*(float scalar) const \n {\n return Vector2D(x * scalar, y * scalar);\n }\n\n float length() const \n {\n return std::sqrt(x * x + y * y);\n }\n\n void normalize() \n {\n float len = length();\n x /= len;\n y /= len;\n }\n};\n\n// 集群单位\nstruct Boid \n{\n COLORREF color;\n Vector2D position;\n Vector2D velocity;\n\n // 聚集规则\n Vector2D cohesion(const std::vector<Boid>& boids) \n {\n Vector2D center_of_mass(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance)\n {\n center_of_mass = center_of_mass + b.position;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n center_of_mass = center_of_mass * (1.0f / total_neighbors);\n return (center_of_mass - position);\n }\n\n return Vector2D(0, 0);\n }\n\n // 分离规则\n Vector2D separation(const std::vector<Boid>& boids) \n {\n Vector2D separation(0, 0);\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < separation_distance) \n {\n Vector2D diff = position - b.position;\n separation = separation + diff * (1.0f / distance);\n }\n }\n\n return separation;\n }\n\n // 对齐规则\n Vector2D alignment(const std::vector<Boid>& boids) \n {\n Vector2D avg_velocity(0, 0);\n int total_neighbors = 0;\n\n for (const Boid& b : boids)\n {\n float distance = (b.position - position).length();\n\n if (distance > 0 && distance < neighbour_distance) \n {\n avg_velocity = avg_velocity + b.velocity;\n total_neighbors++;\n }\n }\n\n if (total_neighbors > 0) \n {\n avg_velocity = avg_velocity * (1.0f / total_neighbors);\n return avg_velocity - velocity;\n }\n\n return Vector2D(0, 0);\n }\n\n // 更新方法\n void update(const std::vector<Boid>& boids) \n {\n Vector2D v1 = cohesion(boids);\n Vector2D v2 = separation(boids);\n Vector2D v3 = alignment(boids);\n\n // 根据规则权重调节最终行为\n v1 = v1 * cohesion_weight;\n v2 = v2 * separation_weight;\n v3 = v3 * align_weight;\n\n // 更新速度\n velocity = velocity + v1 + v2 + v3;\n\n // 限制速度\n float speed = velocity.length();\n if (speed > max_speed) velocity = velocity * (max_speed / speed);\n\n // 更新位置\n position = position + velocity;\n\n // 限制位置\n if (position.x < 0) position.x = 0;\n if (position.x > 1280) position.x = 1280;\n if (position.y < 0) position.y = 0;\n if (position.y > 720) position.y = 720;\n }\n\n float neighbour_distance = 100.0f; // 判定为临近单位的距离\n float separation_distance = 50.0f; // 临近单位的分离距离\n float cohesion_weight = 1.0f; // \"聚集\" 规则强度\n float separation_weight = 1.0f; // \"分离\" 规则强度 \n float align_weight = 1.0f; // \"对齐\" 规则强度\n float max_speed = 5.0f; // 集群最大速度\n};\n\nint main() \n{\n initgraph(1280, 720, EW_SHOWCONSOLE);\n BeginBatchDraw();\n\n // 初始化集群\n std::vector<Boid> boids(500);\n for (Boid& b : boids)\n {\n b.position.x = (float)(rand() % 1280);\n b.position.y = (float)(rand() % 720);\n b.color = RGB(rand() % 255, rand() % 255, rand() % 255);\n }\n\n // 循环模拟\n while (true) \n {\n // 更新集群\n for (Boid& b : boids)\n b.update(boids);\n\n // 渲染集群\n cleardevice();\n for (Boid& b : boids)\n {\n setfillcolor(b.color);\n fillcircle((int)b.position.x, (int)b.position.y, 10);\n }\n FlushBatchDraw();\n\n Sleep(25);\n }\n\n return 0;\n}\n```\n\n> 使用三角形等有指向性的元素,根据当前速度向量绘图模拟效果会更加清晰。\n\n<div style=\"text-align:center\">\n\n\\>\\>\\> [在 Voidmatrix's Blog 上查看本文章](https://www.voidmatrix.work/articles/boids-algorithm/) <<<\n\n</div>","slug":"Voidmatrix/Boids集群算法浅析与实践","published":1,"__permalink":"articles/Voidmatrix/boids-algorithm/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgh000ro8ye7fyj2j4x","content":"<blockquote>\n<p>鸟群算法 Boids是模拟鸟类群集行为的人工生命项目,由克雷格·雷诺兹(Craig Reynolds)于1986年开发。Boids 是涌现行为的典例,其复杂性来自于遵循一系列简单规则个体的相互作用。</p>\n</blockquote>\n<p>Boids 通常用于计算机图形学,提供鸟群和其他生物(如鱼群)的逼真表现:</p>\n<ul>\n<li>《史丹利和史黛拉: 破冰》是第一部利用了 Boids 模型的动画片;</li>\n<li>《半条命》中,游戏结束时出现的类似鸟类的飞行生物就使用了该模型;</li>\n<li>《蝙蝠侠归来》电影中,蝙蝠群和成群的企鹅行进穿过哥谭市的街道时使用了该模型;</li>\n<li>《黑客帝国》/《重装前哨》中,章鱼外形的哨兵机器人的集群特效使用了该模型。</li>\n</ul>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/231573721246935.png\" alt=\"分离(左) - 聚集(中) - 对齐(右)\"></p>\n</div>\n\n<span id=\"more\"></span>\n\n<p>Boids 模型由三种规则描述:</p>\n<ol>\n<li><strong>分离</strong>:个体之间存在排斥趋向,自主移动避开群体拥挤处;</li>\n<li><strong>聚集</strong>:个体会朝向周围同伴所处的平均位置处移动;</li>\n<li><strong>对齐</strong>:个体会朝向周围同伴的平均移动方向运动。</li>\n</ol>\n<blockquote>\n<p>下面将使用 EasyX 可视化该算法。</p>\n</blockquote>\n<h2 id=\"随机个体位置着色\"><a href=\"#随机个体位置着色\" class=\"headerlink\" title=\"随机个体位置着色\"></a>随机个体位置着色</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">std::vector<Boid> <span class=\"title\">boids</span><span class=\"params\">(<span class=\"number\">500</span>)</span></span>;</span><br><span class=\"line\"><span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\">{</span><br><span class=\"line\"> b.position.x = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">1280</span>);</span><br><span class=\"line\"> b.position.y = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">720</span>);</span><br><span class=\"line\"> b.color = <span class=\"built_in\">RGB</span>(<span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/403754021267101.png\" alt=\"随机个体位置着色\"></p>\n</div>\n\n<h2 id=\"添加“聚集”规则\"><a href=\"#添加“聚集”规则\" class=\"headerlink\" title=\"添加“聚集”规则\"></a>添加“聚集”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">cohesion</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">center_of_mass</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass + b.position;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (center_of_mass - position);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/338824221259770.gif\" alt=\"聚集规则\"></p>\n</div>\n\n<h2 id=\"添加“分离”规则\"><a href=\"#添加“分离”规则\" class=\"headerlink\" title=\"添加“分离”规则\"></a>添加“分离”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < separation_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> Vector2D diff = position - b.position;</span><br><span class=\"line\"> separation = separation + diff * (<span class=\"number\">1.0f</span> / distance);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> separation;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/294884321256325.gif\" alt=\"聚集规则 + 分离规则\"></p>\n</div>\n\n<h2 id=\"添加“对齐”规则\"><a href=\"#添加“对齐”规则\" class=\"headerlink\" title=\"添加“对齐”规则\"></a>添加“对齐”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">alignment</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">avg_velocity</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity + b.velocity;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> avg_velocity - velocity;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/101894421252079.gif\" alt=\"聚集规则 + 分离规则 + 对齐规则\"></p>\n</div>\n\n<h2 id=\"完整代码\"><a href=\"#完整代码\" class=\"headerlink\" title=\"完整代码\"></a>完整代码</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br><span class=\"line\">143</span><br><span class=\"line\">144</span><br><span class=\"line\">145</span><br><span class=\"line\">146</span><br><span class=\"line\">147</span><br><span class=\"line\">148</span><br><span class=\"line\">149</span><br><span class=\"line\">150</span><br><span class=\"line\">151</span><br><span class=\"line\">152</span><br><span class=\"line\">153</span><br><span class=\"line\">154</span><br><span class=\"line\">155</span><br><span class=\"line\">156</span><br><span class=\"line\">157</span><br><span class=\"line\">158</span><br><span class=\"line\">159</span><br><span class=\"line\">160</span><br><span class=\"line\">161</span><br><span class=\"line\">162</span><br><span class=\"line\">163</span><br><span class=\"line\">164</span><br><span class=\"line\">165</span><br><span class=\"line\">166</span><br><span class=\"line\">167</span><br><span class=\"line\">168</span><br><span class=\"line\">169</span><br><span class=\"line\">170</span><br><span class=\"line\">171</span><br><span class=\"line\">172</span><br><span class=\"line\">173</span><br><span class=\"line\">174</span><br><span class=\"line\">175</span><br><span class=\"line\">176</span><br><span class=\"line\">177</span><br><span class=\"line\">178</span><br><span class=\"line\">179</span><br><span class=\"line\">180</span><br><span class=\"line\">181</span><br><span class=\"line\">182</span><br><span class=\"line\">183</span><br><span class=\"line\">184</span><br><span class=\"line\">185</span><br><span class=\"line\">186</span><br><span class=\"line\">187</span><br><span class=\"line\">188</span><br><span class=\"line\">189</span><br><span class=\"line\">190</span><br><span class=\"line\">191</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><cmath></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><vector></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 简单的二维向量</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Vector2D</span> </span><br><span class=\"line\">{</span><br><span class=\"line\"> <span class=\"type\">float</span> x, y;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">Vector2D</span>() = <span class=\"keyword\">default</span>;</span><br><span class=\"line\"> <span class=\"built_in\">Vector2D</span>(<span class=\"type\">float</span> _x, <span class=\"type\">float</span> _y) : <span class=\"built_in\">x</span>(_x), <span class=\"built_in\">y</span>(_y) {}</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>+(<span class=\"type\">const</span> Vector2D& other) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x + other.x, y + other.y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>-(<span class=\"type\">const</span> Vector2D& other) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x - other.x, y - other.y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>*(<span class=\"type\">float</span> scalar) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x * scalar, y * scalar);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">length</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> std::<span class=\"built_in\">sqrt</span>(x * x + y * y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">normalize</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> len = <span class=\"built_in\">length</span>();</span><br><span class=\"line\"> x /= len;</span><br><span class=\"line\"> y /= len;</span><br><span class=\"line\"> }</span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 集群单位</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Boid</span> </span><br><span class=\"line\">{</span><br><span class=\"line\"> COLORREF color;</span><br><span class=\"line\"> Vector2D position;</span><br><span class=\"line\"> Vector2D velocity;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 聚集规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">cohesion</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">center_of_mass</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass + b.position;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (center_of_mass - position);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 分离规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < separation_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> Vector2D diff = position - b.position;</span><br><span class=\"line\"> separation = separation + diff * (<span class=\"number\">1.0f</span> / distance);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> separation;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 对齐规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">alignment</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">avg_velocity</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity + b.velocity;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> avg_velocity - velocity;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新方法</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">update</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Vector2D v1 = <span class=\"built_in\">cohesion</span>(boids);</span><br><span class=\"line\"> Vector2D v2 = <span class=\"built_in\">separation</span>(boids);</span><br><span class=\"line\"> Vector2D v3 = <span class=\"built_in\">alignment</span>(boids);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 根据规则权重调节最终行为</span></span><br><span class=\"line\"> v1 = v1 * cohesion_weight;</span><br><span class=\"line\"> v2 = v2 * separation_weight;</span><br><span class=\"line\"> v3 = v3 * align_weight;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新速度</span></span><br><span class=\"line\"> velocity = velocity + v1 + v2 + v3;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 限制速度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> speed = velocity.<span class=\"built_in\">length</span>();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (speed > max_speed) velocity = velocity * (max_speed / speed);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新位置</span></span><br><span class=\"line\"> position = position + velocity;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 限制位置</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.x < <span class=\"number\">0</span>) position.x = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.x > <span class=\"number\">1280</span>) position.x = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.y < <span class=\"number\">0</span>) position.y = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.y > <span class=\"number\">720</span>) position.y = <span class=\"number\">720</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">float</span> neighbour_distance = <span class=\"number\">100.0f</span>; <span class=\"comment\">// 判定为临近单位的距离</span></span><br><span class=\"line\"> <span class=\"type\">float</span> separation_distance = <span class=\"number\">50.0f</span>; <span class=\"comment\">// 临近单位的分离距离</span></span><br><span class=\"line\"> <span class=\"type\">float</span> cohesion_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "聚集" 规则强度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> separation_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "分离" 规则强度 </span></span><br><span class=\"line\"> <span class=\"type\">float</span> align_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "对齐" 规则强度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> max_speed = <span class=\"number\">5.0f</span>; <span class=\"comment\">// 集群最大速度</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(<span class=\"number\">1280</span>, <span class=\"number\">720</span>, EW_SHOWCONSOLE);</span><br><span class=\"line\"> <span class=\"built_in\">BeginBatchDraw</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 初始化集群</span></span><br><span class=\"line\"> <span class=\"function\">std::vector<Boid> <span class=\"title\">boids</span><span class=\"params\">(<span class=\"number\">500</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> b.position.x = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">1280</span>);</span><br><span class=\"line\"> b.position.y = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">720</span>);</span><br><span class=\"line\"> b.color = <span class=\"built_in\">RGB</span>(<span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 循环模拟</span></span><br><span class=\"line\"> <span class=\"keyword\">while</span> (<span class=\"literal\">true</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"comment\">// 更新集群</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> b.<span class=\"built_in\">update</span>(boids);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 渲染集群</span></span><br><span class=\"line\"> <span class=\"built_in\">cleardevice</span>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"built_in\">setfillcolor</span>(b.color);</span><br><span class=\"line\"> <span class=\"built_in\">fillcircle</span>((<span class=\"type\">int</span>)b.position.x, (<span class=\"type\">int</span>)b.position.y, <span class=\"number\">10</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"built_in\">FlushBatchDraw</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">Sleep</span>(<span class=\"number\">25</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<blockquote>\n<p>使用三角形等有指向性的元素,根据当前速度向量绘图模拟效果会更加清晰。</p>\n</blockquote>\n<div style=\"text-align:center\">\n\n<p>>>> <a href=\"https://www.voidmatrix.work/articles/boids-algorithm/\">在 Voidmatrix’s Blog 上查看本文章</a> <<<</p>\n</div>","site":{"data":{}},"excerpt":"<blockquote>\n<p>鸟群算法 Boids是模拟鸟类群集行为的人工生命项目,由克雷格·雷诺兹(Craig Reynolds)于1986年开发。Boids 是涌现行为的典例,其复杂性来自于遵循一系列简单规则个体的相互作用。</p>\n</blockquote>\n<p>Boids 通常用于计算机图形学,提供鸟群和其他生物(如鱼群)的逼真表现:</p>\n<ul>\n<li>《史丹利和史黛拉: 破冰》是第一部利用了 Boids 模型的动画片;</li>\n<li>《半条命》中,游戏结束时出现的类似鸟类的飞行生物就使用了该模型;</li>\n<li>《蝙蝠侠归来》电影中,蝙蝠群和成群的企鹅行进穿过哥谭市的街道时使用了该模型;</li>\n<li>《黑客帝国》/《重装前哨》中,章鱼外形的哨兵机器人的集群特效使用了该模型。</li>\n</ul>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/231573721246935.png\" alt=\"分离(左) - 聚集(中) - 对齐(右)\"></p>\n</div>","more":"<p>Boids 模型由三种规则描述:</p>\n<ol>\n<li><strong>分离</strong>:个体之间存在排斥趋向,自主移动避开群体拥挤处;</li>\n<li><strong>聚集</strong>:个体会朝向周围同伴所处的平均位置处移动;</li>\n<li><strong>对齐</strong>:个体会朝向周围同伴的平均移动方向运动。</li>\n</ol>\n<blockquote>\n<p>下面将使用 EasyX 可视化该算法。</p>\n</blockquote>\n<h2 id=\"随机个体位置着色\"><a href=\"#随机个体位置着色\" class=\"headerlink\" title=\"随机个体位置着色\"></a>随机个体位置着色</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">std::vector<Boid> <span class=\"title\">boids</span><span class=\"params\">(<span class=\"number\">500</span>)</span></span>;</span><br><span class=\"line\"><span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\">{</span><br><span class=\"line\"> b.position.x = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">1280</span>);</span><br><span class=\"line\"> b.position.y = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">720</span>);</span><br><span class=\"line\"> b.color = <span class=\"built_in\">RGB</span>(<span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/403754021267101.png\" alt=\"随机个体位置着色\"></p>\n</div>\n\n<h2 id=\"添加“聚集”规则\"><a href=\"#添加“聚集”规则\" class=\"headerlink\" title=\"添加“聚集”规则\"></a>添加“聚集”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">cohesion</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">center_of_mass</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass + b.position;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (center_of_mass - position);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/338824221259770.gif\" alt=\"聚集规则\"></p>\n</div>\n\n<h2 id=\"添加“分离”规则\"><a href=\"#添加“分离”规则\" class=\"headerlink\" title=\"添加“分离”规则\"></a>添加“分离”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < separation_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> Vector2D diff = position - b.position;</span><br><span class=\"line\"> separation = separation + diff * (<span class=\"number\">1.0f</span> / distance);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> separation;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/294884321256325.gif\" alt=\"聚集规则 + 分离规则\"></p>\n</div>\n\n<h2 id=\"添加“对齐”规则\"><a href=\"#添加“对齐”规则\" class=\"headerlink\" title=\"添加“对齐”规则\"></a>添加“对齐”规则</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\">Vector2D <span class=\"title\">alignment</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">avg_velocity</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity + b.velocity;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> avg_velocity - velocity;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/boids-algorithm/101894421252079.gif\" alt=\"聚集规则 + 分离规则 + 对齐规则\"></p>\n</div>\n\n<h2 id=\"完整代码\"><a href=\"#完整代码\" class=\"headerlink\" title=\"完整代码\"></a>完整代码</h2><figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br><span class=\"line\">102</span><br><span class=\"line\">103</span><br><span class=\"line\">104</span><br><span class=\"line\">105</span><br><span class=\"line\">106</span><br><span class=\"line\">107</span><br><span class=\"line\">108</span><br><span class=\"line\">109</span><br><span class=\"line\">110</span><br><span class=\"line\">111</span><br><span class=\"line\">112</span><br><span class=\"line\">113</span><br><span class=\"line\">114</span><br><span class=\"line\">115</span><br><span class=\"line\">116</span><br><span class=\"line\">117</span><br><span class=\"line\">118</span><br><span class=\"line\">119</span><br><span class=\"line\">120</span><br><span class=\"line\">121</span><br><span class=\"line\">122</span><br><span class=\"line\">123</span><br><span class=\"line\">124</span><br><span class=\"line\">125</span><br><span class=\"line\">126</span><br><span class=\"line\">127</span><br><span class=\"line\">128</span><br><span class=\"line\">129</span><br><span class=\"line\">130</span><br><span class=\"line\">131</span><br><span class=\"line\">132</span><br><span class=\"line\">133</span><br><span class=\"line\">134</span><br><span class=\"line\">135</span><br><span class=\"line\">136</span><br><span class=\"line\">137</span><br><span class=\"line\">138</span><br><span class=\"line\">139</span><br><span class=\"line\">140</span><br><span class=\"line\">141</span><br><span class=\"line\">142</span><br><span class=\"line\">143</span><br><span class=\"line\">144</span><br><span class=\"line\">145</span><br><span class=\"line\">146</span><br><span class=\"line\">147</span><br><span class=\"line\">148</span><br><span class=\"line\">149</span><br><span class=\"line\">150</span><br><span class=\"line\">151</span><br><span class=\"line\">152</span><br><span class=\"line\">153</span><br><span class=\"line\">154</span><br><span class=\"line\">155</span><br><span class=\"line\">156</span><br><span class=\"line\">157</span><br><span class=\"line\">158</span><br><span class=\"line\">159</span><br><span class=\"line\">160</span><br><span class=\"line\">161</span><br><span class=\"line\">162</span><br><span class=\"line\">163</span><br><span class=\"line\">164</span><br><span class=\"line\">165</span><br><span class=\"line\">166</span><br><span class=\"line\">167</span><br><span class=\"line\">168</span><br><span class=\"line\">169</span><br><span class=\"line\">170</span><br><span class=\"line\">171</span><br><span class=\"line\">172</span><br><span class=\"line\">173</span><br><span class=\"line\">174</span><br><span class=\"line\">175</span><br><span class=\"line\">176</span><br><span class=\"line\">177</span><br><span class=\"line\">178</span><br><span class=\"line\">179</span><br><span class=\"line\">180</span><br><span class=\"line\">181</span><br><span class=\"line\">182</span><br><span class=\"line\">183</span><br><span class=\"line\">184</span><br><span class=\"line\">185</span><br><span class=\"line\">186</span><br><span class=\"line\">187</span><br><span class=\"line\">188</span><br><span class=\"line\">189</span><br><span class=\"line\">190</span><br><span class=\"line\">191</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><cmath></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><vector></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 简单的二维向量</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Vector2D</span> </span><br><span class=\"line\">{</span><br><span class=\"line\"> <span class=\"type\">float</span> x, y;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">Vector2D</span>() = <span class=\"keyword\">default</span>;</span><br><span class=\"line\"> <span class=\"built_in\">Vector2D</span>(<span class=\"type\">float</span> _x, <span class=\"type\">float</span> _y) : <span class=\"built_in\">x</span>(_x), <span class=\"built_in\">y</span>(_y) {}</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>+(<span class=\"type\">const</span> Vector2D& other) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x + other.x, y + other.y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>-(<span class=\"type\">const</span> Vector2D& other) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x - other.x, y - other.y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> Vector2D <span class=\"keyword\">operator</span>*(<span class=\"type\">float</span> scalar) <span class=\"type\">const</span> </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(x * scalar, y * scalar);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">float</span> <span class=\"title\">length</span><span class=\"params\">()</span> <span class=\"type\">const</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> std::<span class=\"built_in\">sqrt</span>(x * x + y * y);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">normalize</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"type\">float</span> len = <span class=\"built_in\">length</span>();</span><br><span class=\"line\"> x /= len;</span><br><span class=\"line\"> y /= len;</span><br><span class=\"line\"> }</span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 集群单位</span></span><br><span class=\"line\"><span class=\"keyword\">struct</span> <span class=\"title class_\">Boid</span> </span><br><span class=\"line\">{</span><br><span class=\"line\"> COLORREF color;</span><br><span class=\"line\"> Vector2D position;</span><br><span class=\"line\"> Vector2D velocity;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 聚集规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">cohesion</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">center_of_mass</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass + b.position;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> center_of_mass = center_of_mass * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> (center_of_mass - position);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 分离规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">separation</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < separation_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> Vector2D diff = position - b.position;</span><br><span class=\"line\"> separation = separation + diff * (<span class=\"number\">1.0f</span> / distance);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> separation;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 对齐规则</span></span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">alignment</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> <span class=\"function\">Vector2D <span class=\"title\">avg_velocity</span><span class=\"params\">(<span class=\"number\">0</span>, <span class=\"number\">0</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> total_neighbors = <span class=\"number\">0</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">const</span> Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">float</span> distance = (b.position - position).<span class=\"built_in\">length</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (distance > <span class=\"number\">0</span> && distance < neighbour_distance) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity + b.velocity;</span><br><span class=\"line\"> total_neighbors++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (total_neighbors > <span class=\"number\">0</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> avg_velocity = avg_velocity * (<span class=\"number\">1.0f</span> / total_neighbors);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> avg_velocity - velocity;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Vector2D</span>(<span class=\"number\">0</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新方法</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"type\">void</span> <span class=\"title\">update</span><span class=\"params\">(<span class=\"type\">const</span> std::vector<Boid>& boids)</span> </span></span><br><span class=\"line\"><span class=\"function\"> </span>{</span><br><span class=\"line\"> Vector2D v1 = <span class=\"built_in\">cohesion</span>(boids);</span><br><span class=\"line\"> Vector2D v2 = <span class=\"built_in\">separation</span>(boids);</span><br><span class=\"line\"> Vector2D v3 = <span class=\"built_in\">alignment</span>(boids);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 根据规则权重调节最终行为</span></span><br><span class=\"line\"> v1 = v1 * cohesion_weight;</span><br><span class=\"line\"> v2 = v2 * separation_weight;</span><br><span class=\"line\"> v3 = v3 * align_weight;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新速度</span></span><br><span class=\"line\"> velocity = velocity + v1 + v2 + v3;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 限制速度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> speed = velocity.<span class=\"built_in\">length</span>();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (speed > max_speed) velocity = velocity * (max_speed / speed);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 更新位置</span></span><br><span class=\"line\"> position = position + velocity;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 限制位置</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.x < <span class=\"number\">0</span>) position.x = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.x > <span class=\"number\">1280</span>) position.x = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.y < <span class=\"number\">0</span>) position.y = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (position.y > <span class=\"number\">720</span>) position.y = <span class=\"number\">720</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">float</span> neighbour_distance = <span class=\"number\">100.0f</span>; <span class=\"comment\">// 判定为临近单位的距离</span></span><br><span class=\"line\"> <span class=\"type\">float</span> separation_distance = <span class=\"number\">50.0f</span>; <span class=\"comment\">// 临近单位的分离距离</span></span><br><span class=\"line\"> <span class=\"type\">float</span> cohesion_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "聚集" 规则强度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> separation_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "分离" 规则强度 </span></span><br><span class=\"line\"> <span class=\"type\">float</span> align_weight = <span class=\"number\">1.0f</span>; <span class=\"comment\">// "对齐" 规则强度</span></span><br><span class=\"line\"> <span class=\"type\">float</span> max_speed = <span class=\"number\">5.0f</span>; <span class=\"comment\">// 集群最大速度</span></span><br><span class=\"line\">};</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(<span class=\"number\">1280</span>, <span class=\"number\">720</span>, EW_SHOWCONSOLE);</span><br><span class=\"line\"> <span class=\"built_in\">BeginBatchDraw</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 初始化集群</span></span><br><span class=\"line\"> <span class=\"function\">std::vector<Boid> <span class=\"title\">boids</span><span class=\"params\">(<span class=\"number\">500</span>)</span></span>;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> b.position.x = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">1280</span>);</span><br><span class=\"line\"> b.position.y = (<span class=\"type\">float</span>)(<span class=\"built_in\">rand</span>() % <span class=\"number\">720</span>);</span><br><span class=\"line\"> b.color = <span class=\"built_in\">RGB</span>(<span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>, <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 循环模拟</span></span><br><span class=\"line\"> <span class=\"keyword\">while</span> (<span class=\"literal\">true</span>) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"comment\">// 更新集群</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> b.<span class=\"built_in\">update</span>(boids);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 渲染集群</span></span><br><span class=\"line\"> <span class=\"built_in\">cleardevice</span>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Boid& b : boids)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"built_in\">setfillcolor</span>(b.color);</span><br><span class=\"line\"> <span class=\"built_in\">fillcircle</span>((<span class=\"type\">int</span>)b.position.x, (<span class=\"type\">int</span>)b.position.y, <span class=\"number\">10</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"built_in\">FlushBatchDraw</span>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">Sleep</span>(<span class=\"number\">25</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<blockquote>\n<p>使用三角形等有指向性的元素,根据当前速度向量绘图模拟效果会更加清晰。</p>\n</blockquote>\n<div style=\"text-align:center\">\n\n<p>>>> <a href=\"https://www.voidmatrix.work/articles/boids-algorithm/\">在 Voidmatrix’s Blog 上查看本文章</a> <<<</p>\n</div>"},{"title":"XINDENG123456自我介绍","date":"2024-05-27T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"\n\n>'hello everyone! Hello world!! 😝🤪😜'\n>阿巴阿巴啦啦啦\n>👻👻\n> ---\n> etc.\n> ...\n\n---\n\n# **自我介绍**\n1. 本人贪吃贪睡,玩世不恭\n2. 本人积懒成疾,无可救药\n3. 本人大愚若智,爱好躺平\n\n\n## 今天做的事: \n - [x] 吃饭\n - [x] 睡觉\n - [x] 赶作业\n - [ ] ==学习==\n - [ ] <U>找对象</u>\n\n## 试写代码:\n \n ```c\n \n int main(){\n return 0;\n}\n```\n\n## 试写公式\n\n...算了不会,晚点学[^晚点学 ]\n\nx^2^\n\n\n## 下面画一个表\n- 不想写,还是抄一个\n\n| |ASCII |HTML |\n|----------------|-------------------------------|-----------------------------|\n|Single backticks|`'Isn't this fun?'` |'Isn't this fun?' |\n|Quotes |`\"Isn't this fun?\"` |\"Isn't this fun?\" |\n|Dashes |`-- is en-dash, --- is em-dash`|-- is en-dash, --- is em-dash|\n---\n\n## 我的GitHub\n在这里\n[XINDENG123456]([github.com\"一个小链接\"](github.com/XINDENG123456))\n\n[^晚点学]: 指不知道多晚,可以参考[自我介绍](#自我介绍)\n\n","source":"_posts/XINDENG123456/self-introduction.md","raw":"---\ntitle: XINDENG123456自我介绍\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/XINDENG123456/self-introduction/\ncategories: XINDENG123456\ntags: \n - 自我介绍\n---\n\n\n>'hello everyone! Hello world!! 😝🤪😜'\n>阿巴阿巴啦啦啦\n>👻👻\n> ---\n> etc.\n> ...\n\n---\n\n# **自我介绍**\n1. 本人贪吃贪睡,玩世不恭\n2. 本人积懒成疾,无可救药\n3. 本人大愚若智,爱好躺平\n\n\n## 今天做的事: \n - [x] 吃饭\n - [x] 睡觉\n - [x] 赶作业\n - [ ] ==学习==\n - [ ] <U>找对象</u>\n\n## 试写代码:\n \n ```c\n \n int main(){\n return 0;\n}\n```\n\n## 试写公式\n\n...算了不会,晚点学[^晚点学 ]\n\nx^2^\n\n\n## 下面画一个表\n- 不想写,还是抄一个\n\n| |ASCII |HTML |\n|----------------|-------------------------------|-----------------------------|\n|Single backticks|`'Isn't this fun?'` |'Isn't this fun?' |\n|Quotes |`\"Isn't this fun?\"` |\"Isn't this fun?\" |\n|Dashes |`-- is en-dash, --- is em-dash`|-- is en-dash, --- is em-dash|\n---\n\n## 我的GitHub\n在这里\n[XINDENG123456]([github.com\"一个小链接\"](github.com/XINDENG123456))\n\n[^晚点学]: 指不知道多晚,可以参考[自我介绍](#自我介绍)\n\n","slug":"XINDENG123456/self-introduction","published":1,"__permalink":"articles/XINDENG123456/self-introduction/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgh000vo8ye3fv08lzg","content":"<blockquote>\n<h2 id=\"‘hello-everyone-Hello-world-😝🤪😜’阿巴阿巴啦啦啦👻👻\"><a href=\"#‘hello-everyone-Hello-world-😝🤪😜’阿巴阿巴啦啦啦👻👻\" class=\"headerlink\" title=\"‘hello everyone! Hello world!! 😝🤪😜’阿巴阿巴啦啦啦👻👻\"></a>‘hello everyone! Hello world!! 😝🤪😜’<br>阿巴阿巴啦啦啦<br>👻👻</h2><p>etc.<br>…</p>\n</blockquote>\n<hr>\n<h1 id=\"自我介绍\"><a href=\"#自我介绍\" class=\"headerlink\" title=\"自我介绍\"></a><strong>自我介绍</strong></h1><ol>\n<li>本人贪吃贪睡,玩世不恭</li>\n<li>本人积懒成疾,无可救药</li>\n<li>本人大愚若智,爱好躺平</li>\n</ol>\n<h2 id=\"今天做的事:\"><a href=\"#今天做的事:\" class=\"headerlink\" title=\"今天做的事:\"></a>今天做的事:</h2><ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 吃饭</li>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 睡觉</li>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 赶作业</li>\n<li><input disabled=\"\" type=\"checkbox\"> ==学习==</li>\n<li><input disabled=\"\" type=\"checkbox\"> <U>找对象</u></li>\n</ul>\n<h2 id=\"试写代码:\"><a href=\"#试写代码:\" class=\"headerlink\" title=\"试写代码:\"></a>试写代码:</h2> <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"type\">int</span> <span class=\"title function_\">main</span><span class=\"params\">()</span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"试写公式\"><a href=\"#试写公式\" class=\"headerlink\" title=\"试写公式\"></a>试写公式</h2><p>…算了不会,晚点学[^晚点学 ]</p>\n<p>x^2^</p>\n<h2 id=\"下面画一个表\"><a href=\"#下面画一个表\" class=\"headerlink\" title=\"下面画一个表\"></a>下面画一个表</h2><ul>\n<li>不想写,还是抄一个</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>ASCII</th>\n<th>HTML</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Single backticks</td>\n<td><code>'Isn't this fun?'</code></td>\n<td>‘Isn’t this fun?’</td>\n</tr>\n<tr>\n<td>Quotes</td>\n<td><code>"Isn't this fun?"</code></td>\n<td>“Isn’t this fun?”</td>\n</tr>\n<tr>\n<td>Dashes</td>\n<td><code>-- is en-dash, --- is em-dash</code></td>\n<td>– is en-dash, — is em-dash</td>\n</tr>\n</tbody></table>\n<hr>\n<h2 id=\"我的GitHub\"><a href=\"#我的GitHub\" class=\"headerlink\" title=\"我的GitHub\"></a>我的GitHub</h2><p>在这里<br><a href=\"%5Bgithub.com%22%E4%B8%80%E4%B8%AA%E5%B0%8F%E9%93%BE%E6%8E%A5%22%5D(github.com/XINDENG123456)\">XINDENG123456</a></p>\n<p>[^晚点学]: 指不知道多晚,可以参考<a href=\"#%E8%87%AA%E6%88%91%E4%BB%8B%E7%BB%8D\">自我介绍</a></p>\n","site":{"data":{}},"excerpt":"","more":"<blockquote>\n<h2 id=\"‘hello-everyone-Hello-world-😝🤪😜’阿巴阿巴啦啦啦👻👻\"><a href=\"#‘hello-everyone-Hello-world-😝🤪😜’阿巴阿巴啦啦啦👻👻\" class=\"headerlink\" title=\"‘hello everyone! Hello world!! 😝🤪😜’阿巴阿巴啦啦啦👻👻\"></a>‘hello everyone! Hello world!! 😝🤪😜’<br>阿巴阿巴啦啦啦<br>👻👻</h2><p>etc.<br>…</p>\n</blockquote>\n<hr>\n<h1 id=\"自我介绍\"><a href=\"#自我介绍\" class=\"headerlink\" title=\"自我介绍\"></a><strong>自我介绍</strong></h1><ol>\n<li>本人贪吃贪睡,玩世不恭</li>\n<li>本人积懒成疾,无可救药</li>\n<li>本人大愚若智,爱好躺平</li>\n</ol>\n<h2 id=\"今天做的事:\"><a href=\"#今天做的事:\" class=\"headerlink\" title=\"今天做的事:\"></a>今天做的事:</h2><ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 吃饭</li>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 睡觉</li>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> 赶作业</li>\n<li><input disabled=\"\" type=\"checkbox\"> ==学习==</li>\n<li><input disabled=\"\" type=\"checkbox\"> <U>找对象</u></li>\n</ul>\n<h2 id=\"试写代码:\"><a href=\"#试写代码:\" class=\"headerlink\" title=\"试写代码:\"></a>试写代码:</h2> <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"type\">int</span> <span class=\"title function_\">main</span><span class=\"params\">()</span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"试写公式\"><a href=\"#试写公式\" class=\"headerlink\" title=\"试写公式\"></a>试写公式</h2><p>…算了不会,晚点学[^晚点学 ]</p>\n<p>x^2^</p>\n<h2 id=\"下面画一个表\"><a href=\"#下面画一个表\" class=\"headerlink\" title=\"下面画一个表\"></a>下面画一个表</h2><ul>\n<li>不想写,还是抄一个</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>ASCII</th>\n<th>HTML</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Single backticks</td>\n<td><code>'Isn't this fun?'</code></td>\n<td>‘Isn’t this fun?’</td>\n</tr>\n<tr>\n<td>Quotes</td>\n<td><code>"Isn't this fun?"</code></td>\n<td>“Isn’t this fun?”</td>\n</tr>\n<tr>\n<td>Dashes</td>\n<td><code>-- is en-dash, --- is em-dash</code></td>\n<td>– is en-dash, — is em-dash</td>\n</tr>\n</tbody></table>\n<hr>\n<h2 id=\"我的GitHub\"><a href=\"#我的GitHub\" class=\"headerlink\" title=\"我的GitHub\"></a>我的GitHub</h2><p>在这里<br><a href=\"%5Bgithub.com%22%E4%B8%80%E4%B8%AA%E5%B0%8F%E9%93%BE%E6%8E%A5%22%5D(github.com/XINDENG123456)\">XINDENG123456</a></p>\n<p>[^晚点学]: 指不知道多晚,可以参考<a href=\"#%E8%87%AA%E6%88%91%E4%BB%8B%E7%BB%8D\">自我介绍</a></p>\n"},{"title":"程序化游戏地图生成浅析(一)","date":"2024-06-01T16:00:00.000Z","updated":"2024-06-01T16:00:00.000Z","_content":"\n使用 **程序化内容生成(PCG)** 的优势:\n\n+ 无限地图内容:两个维度,一是单次游玩的地图内容趋近于无限,即无限大世界;二是可以生成近似无限多的世界,提升游戏的可重复游玩性;\n+ 节省开发成本:开发者只需要定义生成规则来描述世界最底层的机制,而不需要从上到下事无巨细地完成玩家可游玩的全部内容;\n+ 挑战与变化:使用程序生成地图可以很好地控制随机性,给玩家创造挑战的机会,更具趣味性;\n+ 动态难度调整:使用规则描述世界生成可以站在更高的维度去调控世界资源,更好地平衡游戏难度或创造特殊难度的世界。\n\n在大多数情况下,程序化生成地图的游戏也并不能完全地摆脱传统的手工制作的部分,即便是程序化内容生成主导的世界中,也存在细粒度的部分需要开发者进行人工设计(如 Minecraft 中的村庄等内容),这同样也可以使用更细致的生成规则来描述。\n\n<!-- more -->\n\n## 生成思路总览\n\n对于程序化生成的游戏世界地图,可以使用**分批次地、递归地**类似分形的思想逐步进行细化处理,每一层处理都基本满足以下三个步骤:\n\n<div style=\"text-align:center\">\n\n![每层递归的三个生成步骤](articles/Voidmatrix/pcg-game-map-1/151655416259069.png)\n\n</div>\n\n1. **随机**:根据随机数或噪声算法生成最粗略的数据模板;\n2. **平滑**:根据当前生成内容的维度和粒度对得到的数据进行插值和过渡处理;\n3. **修正**:根据游戏内容和更上层的设计规则调整平滑后的世界。\n\n一个使用此思想实现的流程可以如下所示:\n\n<div style=\"text-align:center\">\n\n![三步走递归生成示例](articles/Voidmatrix/pcg-game-map-1/202434217267102.png)\n\n</div>\n\n在前两个步骤中,我们需要确保使用的算法满足下列三个条件:\n\n1. **随机性**:这个过程是随机的,或者说在相当大范围内不会出现重复的生成周期;\n2. **可哈希**:使用相同的随机数输入(种子),得到的随机内容是一致的;\n3. **连续性**:无论粒度大小,生成的内容都是连续且平滑的。\n\n> 可哈希的特性给游戏的增量存档提供了可能,存储游戏世界信息的存档不需要在初始化生成时便保存全部数据内容,而是可以随着游戏进行,只增量存储玩家探索过或修改过的内容。\n\n下面我们将分类讨论在随机和平滑的过程中使用的算法思路。\n\n## 直接使用随机数\n\n直接使用`rand()`等随机函数会存在以下问题:\n\n+ **不连续性**:随机数的生成是跳跃的,直接使用时无法起到平滑的效果;\n+ **易受影响**:虽然我们可以使用`srand()`等函数设置随机数的种子来确保随机数的哈希性,但是程序的其他部分可能需要使用时间来初始化随机数种子来获取更灵活的随机数,这就导致在全局环境下生成的随机数不稳定。\n\n使用如下代码生成的灰度图,可以很清楚地看出其不连续性:\n\n<div style=\"text-align:center\">\n\n![`rand()`随机数灰度图](articles/Voidmatrix/pcg-game-map-1/553721218256326.png)\n\n</div>\n\n```cpp\n#include <graphics.h>\n\nint main()\n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height, EW_SHOWCONSOLE);\n\n for (int x = 0; x < width; x++)\n {\n for (int y = 0; y < height; y++)\n {\n int val = rand() % 255;\n putpixel(x, y, RGB(val, val, val));\n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n但是,这并不意味着随机数函数是无用的,我们可以直接使用随机数生成离散的影响点,再根据距离权重进行平滑处理,如《文明6》等游戏中使用的**米切尔候选算法**(Mitchell's best-candidate algorithm),在处理初期时可以直接使用随机数进行候选节点的生成的,这将在后续的游戏资源生成章节再进行详细讨论。\n\n在上古项目[随机地图高度图](https://github.com/EtherProject/EtherWorkCollection/tree/main/%E9%9A%8F%E6%9C%BA%E5%9C%B0%E5%9B%BE%E9%AB%98%E5%BA%A6%E5%9B%BE)生成过程中,也是使用了简单的先随机后平滑的思路:\n\n<div style=\"text-align:center\">\n\n![随机地图高度图(白色为随机生成的影响点)](articles/Voidmatrix/pcg-game-map-1/532531818252080.png)\n\n</div>\n\n## 平滑的噪声函数\n\n在[《基于EasyX软渲染实现常见故障艺术》](https://www.voidmatrix.work/articles/%E5%9F%BA%E4%BA%8EEasyX%E8%BD%AF%E6%B8%B2%E6%9F%93%E5%AE%9E%E7%8E%B0%E5%B8%B8%E8%A7%81%E6%95%85%E9%9A%9C%E8%89%BA%E6%9C%AF/)一文中,提供了一种可行的随机噪声函数:\n\n<div style=\"text-align:center\">\n\n![f(x, y) = frac(sin(x * 12.9898 + y * 78.233) * 43758.5453)](articles/Voidmatrix/pcg-game-map-1/76072812230849.png)\n\n</div>\n\n```cpp\n// 获取随机噪声\nvirtual double GetRandomNoise(double x, double y)\n{\n\tdouble val = sin(x * 12.9898 + y * 78.233) * 43758.5453;\n\treturn val - floor(val);\n}\n```\n\n简单地,我们也可以使用正弦波叠加的思想处理类似的噪声生成:\n\n<div style=\"text-align:center\">\n\n![简单的正弦波叠加同样可以模拟地形效果](articles/Voidmatrix/pcg-game-map-1/125364318267564.png)\n\n</div>\n\n但是,我们可以很清晰地看出,这种直接使用函数生成的噪声即便可以满足哈希性和连续性,但它们的周期性太强,直接将生成得到的计算结果应用于游戏中会导致整个世界出现大量重复地形,并不能完全满足随机性的要求:\n\n<div style=\"text-align:center\">\n\n![噪声函数存在较强的周期性](articles/Voidmatrix/pcg-game-map-1/59555018265066.png)\n\n</div>\n\n```cpp\ndouble noise(int x, int y)\n{\n double val_x = abs((1 * sin(x * 1)) + (0.5 * sin(x * 2)) + (0.25 * sin(x * 4)) + (0.125 * sin(x * 8)));\n double val_y = abs((1 * sin(y * 1)) + (0.5 * sin(y * 2)) + (0.25 * sin(y * 4)) + (0.125 * sin(y * 8)));\n\n // 对得到的结果进行归一化\n return (val_x + val_y) / ((1 + 0.5 + 0.25 + 0.125) * 2);\n}\n\nint main()\n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height, EW_SHOWCONSOLE);\n\n for (int x = 0; x < width; x++)\n {\n for (int y = 0; y < height; y++)\n {\n int val = (int)(noise(x / 10, y / 10) * 255);\n putpixel(x, y, RGB(val, val, val));\n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n即便如此,这些生成噪声的方式,同样可以作为**分形噪声**等更进阶的噪声生成时的原始数据。\n\n## 更进阶的噪声生成\n\n有许多已经被实践证明满足上述需求的噪声算法,如:Perlin噪声,Simplex噪声,Wavelet噪声,Value噪声和Worley噪声等,下面将以大名鼎鼎的**柏林噪声**(Perlin)为例讲解实现思路。\n\n> 柏林噪声本质上可以算是一种非典型的晶格噪声技术,晶格噪声是一种在离散的、规则的网格上生成的噪声,所以晶格噪声通常在规则的格点上有着明确定义的数值,而柏林噪声的特殊之处在于,在使用晶格为单位生成基础噪声后,又通过插值和平滑处理,产生了空间中连续的噪声变化。\n\n柏林噪声的生成可以归纳为三步:\n\n1. **梯度生成**:在空间中随机生成梯度向量网格,梯度向量由每个整数坐标点(晶格)上随机确定的。这些梯度向量定义了一个在整个空间内变化的方向;\n2. **插值**:当需要计算某一点的噪声值时,首先确定其所处的网格单元,然后计算该点到网格单元内各个梯度向量的距离,并将这些距离用于权重插值,在这个过程中噪声得到了平滑的处理;\n3. **分形**:对生成得到的结果进行不同尺度的缩放和叠加,来生成更具随机性且不同粒度的结果。\n\n<div style=\"text-align:center\">\n\n![柏林噪声灰度图](articles/Voidmatrix/pcg-game-map-1/161600919246307.png)\n\n</div>\n\n```cpp\n#include <cmath>\n#include <graphics.h>\n\n// 生成基础噪声值\ndouble noise(int x, int y)\n{\n return fmod(sin(x * 12.9898 + y * 78.233) * 43758.5453, 1.0);\n}\n\n// 生成平滑噪声值\ndouble smooth_noise(int x, int y) \n{\n // 计算角落、边和中心的平均噪声值\n double corners = (noise(x - 1, y - 1) + noise(x + 1, y - 1) + noise(x - 1, y + 1) + noise(x + 1, y + 1)) / 16;\n double sides = (noise(x - 1, y) + noise(x + 1, y) + noise(x, y - 1) + noise(x, y + 1)) / 8;\n double center = noise(x, y) / 4;\n // 返回平滑噪声值\n return corners + sides + center; \n}\n\n// 线性插值\ndouble interpolate(double a, double b, double x) \n{\n // 计算插值权重\n double ft = x * 3.1415927; \n double f = (1 - cos(ft)) * 0.5;\n // 返回插值结果\n return a * (1 - f) + b * f; \n}\n\n// 插值计算\ndouble interpolated_noise(double x, double y) \n{\n // 提取整数部分和小数部分\n int integer_X = static_cast<int>(x);\n double fractional_X = x - integer_X;\n\n int integer_Y = static_cast<int>(y);\n double fractional_Y = y - integer_Y;\n\n // 计算插值点的噪声值\n double v1 = smooth_noise(integer_X, integer_Y);\n double v2 = smooth_noise(integer_X + 1, integer_Y);\n double v3 = smooth_noise(integer_X, integer_Y + 1);\n double v4 = smooth_noise(integer_X + 1, integer_Y + 1);\n\n double i1 = interpolate(v1, v2, fractional_X);\n double i2 = interpolate(v3, v4, fractional_X);\n\n // 返回插值后的噪声值\n return interpolate(i1, i2, fractional_Y); \n}\n\nint main() \n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height);\n\n // 循环生成每个像素点的噪声值并转换为灰度颜色\n for (int y = 0; y < height; y++) \n {\n for (int x = 0; x < width; x++) \n {\n // 生成插值噪声,并控制噪声的规模\n double value = interpolated_noise(x / 50.0, y / 50.0); \n // 将噪声值转换为灰度颜色\n COLORREF color = RGB((int)(value * 255),\n (int)(value * 255), (int)(value * 255)); \n // 在指定位置绘制像素\n putpixel(x, y, color); \n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n<div style=\"text-align:center\">\n\n![“痛苦终结者”](articles/Voidmatrix/pcg-game-map-1/87331419268747.png)\n\n</div>\n\n<div style=\"text-align:center\">\n\n\\>\\>\\> [在 Voidmatrix's Blog 上查看本文章](https://www.voidmatrix.work/articles/pcg-game-map-1/) <<<\n\n</div>","source":"_posts/Voidmatrix/程序化游戏地图生成浅析(一).md","raw":"---\ntitle: 程序化游戏地图生成浅析(一)\ndate: 2024-06-02\nupdated: 2024-06-02\npermalink: articles/Voidmatrix/pcg-game-map-1/\ncategories: Voidmatrix\ntags: [EasyX, 算法, C++, PCG]\n---\n\n使用 **程序化内容生成(PCG)** 的优势:\n\n+ 无限地图内容:两个维度,一是单次游玩的地图内容趋近于无限,即无限大世界;二是可以生成近似无限多的世界,提升游戏的可重复游玩性;\n+ 节省开发成本:开发者只需要定义生成规则来描述世界最底层的机制,而不需要从上到下事无巨细地完成玩家可游玩的全部内容;\n+ 挑战与变化:使用程序生成地图可以很好地控制随机性,给玩家创造挑战的机会,更具趣味性;\n+ 动态难度调整:使用规则描述世界生成可以站在更高的维度去调控世界资源,更好地平衡游戏难度或创造特殊难度的世界。\n\n在大多数情况下,程序化生成地图的游戏也并不能完全地摆脱传统的手工制作的部分,即便是程序化内容生成主导的世界中,也存在细粒度的部分需要开发者进行人工设计(如 Minecraft 中的村庄等内容),这同样也可以使用更细致的生成规则来描述。\n\n<!-- more -->\n\n## 生成思路总览\n\n对于程序化生成的游戏世界地图,可以使用**分批次地、递归地**类似分形的思想逐步进行细化处理,每一层处理都基本满足以下三个步骤:\n\n<div style=\"text-align:center\">\n\n![每层递归的三个生成步骤](articles/Voidmatrix/pcg-game-map-1/151655416259069.png)\n\n</div>\n\n1. **随机**:根据随机数或噪声算法生成最粗略的数据模板;\n2. **平滑**:根据当前生成内容的维度和粒度对得到的数据进行插值和过渡处理;\n3. **修正**:根据游戏内容和更上层的设计规则调整平滑后的世界。\n\n一个使用此思想实现的流程可以如下所示:\n\n<div style=\"text-align:center\">\n\n![三步走递归生成示例](articles/Voidmatrix/pcg-game-map-1/202434217267102.png)\n\n</div>\n\n在前两个步骤中,我们需要确保使用的算法满足下列三个条件:\n\n1. **随机性**:这个过程是随机的,或者说在相当大范围内不会出现重复的生成周期;\n2. **可哈希**:使用相同的随机数输入(种子),得到的随机内容是一致的;\n3. **连续性**:无论粒度大小,生成的内容都是连续且平滑的。\n\n> 可哈希的特性给游戏的增量存档提供了可能,存储游戏世界信息的存档不需要在初始化生成时便保存全部数据内容,而是可以随着游戏进行,只增量存储玩家探索过或修改过的内容。\n\n下面我们将分类讨论在随机和平滑的过程中使用的算法思路。\n\n## 直接使用随机数\n\n直接使用`rand()`等随机函数会存在以下问题:\n\n+ **不连续性**:随机数的生成是跳跃的,直接使用时无法起到平滑的效果;\n+ **易受影响**:虽然我们可以使用`srand()`等函数设置随机数的种子来确保随机数的哈希性,但是程序的其他部分可能需要使用时间来初始化随机数种子来获取更灵活的随机数,这就导致在全局环境下生成的随机数不稳定。\n\n使用如下代码生成的灰度图,可以很清楚地看出其不连续性:\n\n<div style=\"text-align:center\">\n\n![`rand()`随机数灰度图](articles/Voidmatrix/pcg-game-map-1/553721218256326.png)\n\n</div>\n\n```cpp\n#include <graphics.h>\n\nint main()\n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height, EW_SHOWCONSOLE);\n\n for (int x = 0; x < width; x++)\n {\n for (int y = 0; y < height; y++)\n {\n int val = rand() % 255;\n putpixel(x, y, RGB(val, val, val));\n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n但是,这并不意味着随机数函数是无用的,我们可以直接使用随机数生成离散的影响点,再根据距离权重进行平滑处理,如《文明6》等游戏中使用的**米切尔候选算法**(Mitchell's best-candidate algorithm),在处理初期时可以直接使用随机数进行候选节点的生成的,这将在后续的游戏资源生成章节再进行详细讨论。\n\n在上古项目[随机地图高度图](https://github.com/EtherProject/EtherWorkCollection/tree/main/%E9%9A%8F%E6%9C%BA%E5%9C%B0%E5%9B%BE%E9%AB%98%E5%BA%A6%E5%9B%BE)生成过程中,也是使用了简单的先随机后平滑的思路:\n\n<div style=\"text-align:center\">\n\n![随机地图高度图(白色为随机生成的影响点)](articles/Voidmatrix/pcg-game-map-1/532531818252080.png)\n\n</div>\n\n## 平滑的噪声函数\n\n在[《基于EasyX软渲染实现常见故障艺术》](https://www.voidmatrix.work/articles/%E5%9F%BA%E4%BA%8EEasyX%E8%BD%AF%E6%B8%B2%E6%9F%93%E5%AE%9E%E7%8E%B0%E5%B8%B8%E8%A7%81%E6%95%85%E9%9A%9C%E8%89%BA%E6%9C%AF/)一文中,提供了一种可行的随机噪声函数:\n\n<div style=\"text-align:center\">\n\n![f(x, y) = frac(sin(x * 12.9898 + y * 78.233) * 43758.5453)](articles/Voidmatrix/pcg-game-map-1/76072812230849.png)\n\n</div>\n\n```cpp\n// 获取随机噪声\nvirtual double GetRandomNoise(double x, double y)\n{\n\tdouble val = sin(x * 12.9898 + y * 78.233) * 43758.5453;\n\treturn val - floor(val);\n}\n```\n\n简单地,我们也可以使用正弦波叠加的思想处理类似的噪声生成:\n\n<div style=\"text-align:center\">\n\n![简单的正弦波叠加同样可以模拟地形效果](articles/Voidmatrix/pcg-game-map-1/125364318267564.png)\n\n</div>\n\n但是,我们可以很清晰地看出,这种直接使用函数生成的噪声即便可以满足哈希性和连续性,但它们的周期性太强,直接将生成得到的计算结果应用于游戏中会导致整个世界出现大量重复地形,并不能完全满足随机性的要求:\n\n<div style=\"text-align:center\">\n\n![噪声函数存在较强的周期性](articles/Voidmatrix/pcg-game-map-1/59555018265066.png)\n\n</div>\n\n```cpp\ndouble noise(int x, int y)\n{\n double val_x = abs((1 * sin(x * 1)) + (0.5 * sin(x * 2)) + (0.25 * sin(x * 4)) + (0.125 * sin(x * 8)));\n double val_y = abs((1 * sin(y * 1)) + (0.5 * sin(y * 2)) + (0.25 * sin(y * 4)) + (0.125 * sin(y * 8)));\n\n // 对得到的结果进行归一化\n return (val_x + val_y) / ((1 + 0.5 + 0.25 + 0.125) * 2);\n}\n\nint main()\n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height, EW_SHOWCONSOLE);\n\n for (int x = 0; x < width; x++)\n {\n for (int y = 0; y < height; y++)\n {\n int val = (int)(noise(x / 10, y / 10) * 255);\n putpixel(x, y, RGB(val, val, val));\n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n即便如此,这些生成噪声的方式,同样可以作为**分形噪声**等更进阶的噪声生成时的原始数据。\n\n## 更进阶的噪声生成\n\n有许多已经被实践证明满足上述需求的噪声算法,如:Perlin噪声,Simplex噪声,Wavelet噪声,Value噪声和Worley噪声等,下面将以大名鼎鼎的**柏林噪声**(Perlin)为例讲解实现思路。\n\n> 柏林噪声本质上可以算是一种非典型的晶格噪声技术,晶格噪声是一种在离散的、规则的网格上生成的噪声,所以晶格噪声通常在规则的格点上有着明确定义的数值,而柏林噪声的特殊之处在于,在使用晶格为单位生成基础噪声后,又通过插值和平滑处理,产生了空间中连续的噪声变化。\n\n柏林噪声的生成可以归纳为三步:\n\n1. **梯度生成**:在空间中随机生成梯度向量网格,梯度向量由每个整数坐标点(晶格)上随机确定的。这些梯度向量定义了一个在整个空间内变化的方向;\n2. **插值**:当需要计算某一点的噪声值时,首先确定其所处的网格单元,然后计算该点到网格单元内各个梯度向量的距离,并将这些距离用于权重插值,在这个过程中噪声得到了平滑的处理;\n3. **分形**:对生成得到的结果进行不同尺度的缩放和叠加,来生成更具随机性且不同粒度的结果。\n\n<div style=\"text-align:center\">\n\n![柏林噪声灰度图](articles/Voidmatrix/pcg-game-map-1/161600919246307.png)\n\n</div>\n\n```cpp\n#include <cmath>\n#include <graphics.h>\n\n// 生成基础噪声值\ndouble noise(int x, int y)\n{\n return fmod(sin(x * 12.9898 + y * 78.233) * 43758.5453, 1.0);\n}\n\n// 生成平滑噪声值\ndouble smooth_noise(int x, int y) \n{\n // 计算角落、边和中心的平均噪声值\n double corners = (noise(x - 1, y - 1) + noise(x + 1, y - 1) + noise(x - 1, y + 1) + noise(x + 1, y + 1)) / 16;\n double sides = (noise(x - 1, y) + noise(x + 1, y) + noise(x, y - 1) + noise(x, y + 1)) / 8;\n double center = noise(x, y) / 4;\n // 返回平滑噪声值\n return corners + sides + center; \n}\n\n// 线性插值\ndouble interpolate(double a, double b, double x) \n{\n // 计算插值权重\n double ft = x * 3.1415927; \n double f = (1 - cos(ft)) * 0.5;\n // 返回插值结果\n return a * (1 - f) + b * f; \n}\n\n// 插值计算\ndouble interpolated_noise(double x, double y) \n{\n // 提取整数部分和小数部分\n int integer_X = static_cast<int>(x);\n double fractional_X = x - integer_X;\n\n int integer_Y = static_cast<int>(y);\n double fractional_Y = y - integer_Y;\n\n // 计算插值点的噪声值\n double v1 = smooth_noise(integer_X, integer_Y);\n double v2 = smooth_noise(integer_X + 1, integer_Y);\n double v3 = smooth_noise(integer_X, integer_Y + 1);\n double v4 = smooth_noise(integer_X + 1, integer_Y + 1);\n\n double i1 = interpolate(v1, v2, fractional_X);\n double i2 = interpolate(v3, v4, fractional_X);\n\n // 返回插值后的噪声值\n return interpolate(i1, i2, fractional_Y); \n}\n\nint main() \n{\n const int width = 1280;\n const int height = 720;\n\n initgraph(width, height);\n\n // 循环生成每个像素点的噪声值并转换为灰度颜色\n for (int y = 0; y < height; y++) \n {\n for (int x = 0; x < width; x++) \n {\n // 生成插值噪声,并控制噪声的规模\n double value = interpolated_noise(x / 50.0, y / 50.0); \n // 将噪声值转换为灰度颜色\n COLORREF color = RGB((int)(value * 255),\n (int)(value * 255), (int)(value * 255)); \n // 在指定位置绘制像素\n putpixel(x, y, color); \n }\n }\n\n system(\"pause\");\n\n return 0;\n}\n```\n\n<div style=\"text-align:center\">\n\n![“痛苦终结者”](articles/Voidmatrix/pcg-game-map-1/87331419268747.png)\n\n</div>\n\n<div style=\"text-align:center\">\n\n\\>\\>\\> [在 Voidmatrix's Blog 上查看本文章](https://www.voidmatrix.work/articles/pcg-game-map-1/) <<<\n\n</div>","slug":"Voidmatrix/程序化游戏地图生成浅析(一)","published":1,"__permalink":"articles/Voidmatrix/pcg-game-map-1/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgi000yo8yedk2m781a","content":"<p>使用 <strong>程序化内容生成(PCG)</strong> 的优势:</p>\n<ul>\n<li>无限地图内容:两个维度,一是单次游玩的地图内容趋近于无限,即无限大世界;二是可以生成近似无限多的世界,提升游戏的可重复游玩性;</li>\n<li>节省开发成本:开发者只需要定义生成规则来描述世界最底层的机制,而不需要从上到下事无巨细地完成玩家可游玩的全部内容;</li>\n<li>挑战与变化:使用程序生成地图可以很好地控制随机性,给玩家创造挑战的机会,更具趣味性;</li>\n<li>动态难度调整:使用规则描述世界生成可以站在更高的维度去调控世界资源,更好地平衡游戏难度或创造特殊难度的世界。</li>\n</ul>\n<p>在大多数情况下,程序化生成地图的游戏也并不能完全地摆脱传统的手工制作的部分,即便是程序化内容生成主导的世界中,也存在细粒度的部分需要开发者进行人工设计(如 Minecraft 中的村庄等内容),这同样也可以使用更细致的生成规则来描述。</p>\n<span id=\"more\"></span>\n\n<h2 id=\"生成思路总览\"><a href=\"#生成思路总览\" class=\"headerlink\" title=\"生成思路总览\"></a>生成思路总览</h2><p>对于程序化生成的游戏世界地图,可以使用<strong>分批次地、递归地</strong>类似分形的思想逐步进行细化处理,每一层处理都基本满足以下三个步骤:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/151655416259069.png\" alt=\"每层递归的三个生成步骤\"></p>\n</div>\n\n<ol>\n<li><strong>随机</strong>:根据随机数或噪声算法生成最粗略的数据模板;</li>\n<li><strong>平滑</strong>:根据当前生成内容的维度和粒度对得到的数据进行插值和过渡处理;</li>\n<li><strong>修正</strong>:根据游戏内容和更上层的设计规则调整平滑后的世界。</li>\n</ol>\n<p>一个使用此思想实现的流程可以如下所示:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/202434217267102.png\" alt=\"三步走递归生成示例\"></p>\n</div>\n\n<p>在前两个步骤中,我们需要确保使用的算法满足下列三个条件:</p>\n<ol>\n<li><strong>随机性</strong>:这个过程是随机的,或者说在相当大范围内不会出现重复的生成周期;</li>\n<li><strong>可哈希</strong>:使用相同的随机数输入(种子),得到的随机内容是一致的;</li>\n<li><strong>连续性</strong>:无论粒度大小,生成的内容都是连续且平滑的。</li>\n</ol>\n<blockquote>\n<p>可哈希的特性给游戏的增量存档提供了可能,存储游戏世界信息的存档不需要在初始化生成时便保存全部数据内容,而是可以随着游戏进行,只增量存储玩家探索过或修改过的内容。</p>\n</blockquote>\n<p>下面我们将分类讨论在随机和平滑的过程中使用的算法思路。</p>\n<h2 id=\"直接使用随机数\"><a href=\"#直接使用随机数\" class=\"headerlink\" title=\"直接使用随机数\"></a>直接使用随机数</h2><p>直接使用<code>rand()</code>等随机函数会存在以下问题:</p>\n<ul>\n<li><strong>不连续性</strong>:随机数的生成是跳跃的,直接使用时无法起到平滑的效果;</li>\n<li><strong>易受影响</strong>:虽然我们可以使用<code>srand()</code>等函数设置随机数的种子来确保随机数的哈希性,但是程序的其他部分可能需要使用时间来初始化随机数种子来获取更灵活的随机数,这就导致在全局环境下生成的随机数不稳定。</li>\n</ul>\n<p>使用如下代码生成的灰度图,可以很清楚地看出其不连续性:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/553721218256326.png\" alt=\"`rand()`随机数灰度图\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height, EW_SHOWCONSOLE);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">int</span> val = <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>;</span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, <span class=\"built_in\">RGB</span>(val, val, val));</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>但是,这并不意味着随机数函数是无用的,我们可以直接使用随机数生成离散的影响点,再根据距离权重进行平滑处理,如《文明6》等游戏中使用的<strong>米切尔候选算法</strong>(Mitchell’s best-candidate algorithm),在处理初期时可以直接使用随机数进行候选节点的生成的,这将在后续的游戏资源生成章节再进行详细讨论。</p>\n<p>在上古项目<a href=\"https://github.com/EtherProject/EtherWorkCollection/tree/main/%E9%9A%8F%E6%9C%BA%E5%9C%B0%E5%9B%BE%E9%AB%98%E5%BA%A6%E5%9B%BE\">随机地图高度图</a>生成过程中,也是使用了简单的先随机后平滑的思路:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/532531818252080.png\" alt=\"随机地图高度图(白色为随机生成的影响点)\"></p>\n</div>\n\n<h2 id=\"平滑的噪声函数\"><a href=\"#平滑的噪声函数\" class=\"headerlink\" title=\"平滑的噪声函数\"></a>平滑的噪声函数</h2><p>在<a href=\"https://www.voidmatrix.work/articles/%E5%9F%BA%E4%BA%8EEasyX%E8%BD%AF%E6%B8%B2%E6%9F%93%E5%AE%9E%E7%8E%B0%E5%B8%B8%E8%A7%81%E6%95%85%E9%9A%9C%E8%89%BA%E6%9C%AF/\">《基于EasyX软渲染实现常见故障艺术》</a>一文中,提供了一种可行的随机噪声函数:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/76072812230849.png\" alt=\"f(x, y) = frac(sin(x * 12.9898 + y * 78.233) * 43758.5453)\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">// 获取随机噪声</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">virtual</span> <span class=\"type\">double</span> <span class=\"title\">GetRandomNoise</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"type\">double</span> val = <span class=\"built_in\">sin</span>(x * <span class=\"number\">12.9898</span> + y * <span class=\"number\">78.233</span>) * <span class=\"number\">43758.5453</span>;</span><br><span class=\"line\">\t<span class=\"keyword\">return</span> val - <span class=\"built_in\">floor</span>(val);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>简单地,我们也可以使用正弦波叠加的思想处理类似的噪声生成:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/125364318267564.png\" alt=\"简单的正弦波叠加同样可以模拟地形效果\"></p>\n</div>\n\n<p>但是,我们可以很清晰地看出,这种直接使用函数生成的噪声即便可以满足哈希性和连续性,但它们的周期性太强,直接将生成得到的计算结果应用于游戏中会导致整个世界出现大量重复地形,并不能完全满足随机性的要求:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/59555018265066.png\" alt=\"噪声函数存在较强的周期性\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> val_x = <span class=\"built_in\">abs</span>((<span class=\"number\">1</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">1</span>)) + (<span class=\"number\">0.5</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">2</span>)) + (<span class=\"number\">0.25</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">4</span>)) + (<span class=\"number\">0.125</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">8</span>)));</span><br><span class=\"line\"> <span class=\"type\">double</span> val_y = <span class=\"built_in\">abs</span>((<span class=\"number\">1</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">1</span>)) + (<span class=\"number\">0.5</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">2</span>)) + (<span class=\"number\">0.25</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">4</span>)) + (<span class=\"number\">0.125</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">8</span>)));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 对得到的结果进行归一化</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> (val_x + val_y) / ((<span class=\"number\">1</span> + <span class=\"number\">0.5</span> + <span class=\"number\">0.25</span> + <span class=\"number\">0.125</span>) * <span class=\"number\">2</span>);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height, EW_SHOWCONSOLE);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">int</span> val = (<span class=\"type\">int</span>)(<span class=\"built_in\">noise</span>(x / <span class=\"number\">10</span>, y / <span class=\"number\">10</span>) * <span class=\"number\">255</span>);</span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, <span class=\"built_in\">RGB</span>(val, val, val));</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>即便如此,这些生成噪声的方式,同样可以作为<strong>分形噪声</strong>等更进阶的噪声生成时的原始数据。</p>\n<h2 id=\"更进阶的噪声生成\"><a href=\"#更进阶的噪声生成\" class=\"headerlink\" title=\"更进阶的噪声生成\"></a>更进阶的噪声生成</h2><p>有许多已经被实践证明满足上述需求的噪声算法,如:Perlin噪声,Simplex噪声,Wavelet噪声,Value噪声和Worley噪声等,下面将以大名鼎鼎的<strong>柏林噪声</strong>(Perlin)为例讲解实现思路。</p>\n<blockquote>\n<p>柏林噪声本质上可以算是一种非典型的晶格噪声技术,晶格噪声是一种在离散的、规则的网格上生成的噪声,所以晶格噪声通常在规则的格点上有着明确定义的数值,而柏林噪声的特殊之处在于,在使用晶格为单位生成基础噪声后,又通过插值和平滑处理,产生了空间中连续的噪声变化。</p>\n</blockquote>\n<p>柏林噪声的生成可以归纳为三步:</p>\n<ol>\n<li><strong>梯度生成</strong>:在空间中随机生成梯度向量网格,梯度向量由每个整数坐标点(晶格)上随机确定的。这些梯度向量定义了一个在整个空间内变化的方向;</li>\n<li><strong>插值</strong>:当需要计算某一点的噪声值时,首先确定其所处的网格单元,然后计算该点到网格单元内各个梯度向量的距离,并将这些距离用于权重插值,在这个过程中噪声得到了平滑的处理;</li>\n<li><strong>分形</strong>:对生成得到的结果进行不同尺度的缩放和叠加,来生成更具随机性且不同粒度的结果。</li>\n</ol>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/161600919246307.png\" alt=\"柏林噪声灰度图\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><cmath></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 生成基础噪声值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">fmod</span>(<span class=\"built_in\">sin</span>(x * <span class=\"number\">12.9898</span> + y * <span class=\"number\">78.233</span>) * <span class=\"number\">43758.5453</span>, <span class=\"number\">1.0</span>);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 生成平滑噪声值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">smooth_noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算角落、边和中心的平均噪声值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> corners = (<span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y + <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y + <span class=\"number\">1</span>)) / <span class=\"number\">16</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> sides = (<span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y) + <span class=\"built_in\">noise</span>(x, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x, y + <span class=\"number\">1</span>)) / <span class=\"number\">8</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> center = <span class=\"built_in\">noise</span>(x, y) / <span class=\"number\">4</span>;</span><br><span class=\"line\"> <span class=\"comment\">// 返回平滑噪声值</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> corners + sides + center; </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 线性插值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">interpolate</span><span class=\"params\">(<span class=\"type\">double</span> a, <span class=\"type\">double</span> b, <span class=\"type\">double</span> x)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算插值权重</span></span><br><span class=\"line\"> <span class=\"type\">double</span> ft = x * <span class=\"number\">3.1415927</span>; </span><br><span class=\"line\"> <span class=\"type\">double</span> f = (<span class=\"number\">1</span> - <span class=\"built_in\">cos</span>(ft)) * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"comment\">// 返回插值结果</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> a * (<span class=\"number\">1</span> - f) + b * f; </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 插值计算</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">interpolated_noise</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 提取整数部分和小数部分</span></span><br><span class=\"line\"> <span class=\"type\">int</span> integer_X = <span class=\"built_in\">static_cast</span><<span class=\"type\">int</span>>(x);</span><br><span class=\"line\"> <span class=\"type\">double</span> fractional_X = x - integer_X;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">int</span> integer_Y = <span class=\"built_in\">static_cast</span><<span class=\"type\">int</span>>(y);</span><br><span class=\"line\"> <span class=\"type\">double</span> fractional_Y = y - integer_Y;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 计算插值点的噪声值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> v1 = <span class=\"built_in\">smooth_noise</span>(integer_X, integer_Y);</span><br><span class=\"line\"> <span class=\"type\">double</span> v2 = <span class=\"built_in\">smooth_noise</span>(integer_X + <span class=\"number\">1</span>, integer_Y);</span><br><span class=\"line\"> <span class=\"type\">double</span> v3 = <span class=\"built_in\">smooth_noise</span>(integer_X, integer_Y + <span class=\"number\">1</span>);</span><br><span class=\"line\"> <span class=\"type\">double</span> v4 = <span class=\"built_in\">smooth_noise</span>(integer_X + <span class=\"number\">1</span>, integer_Y + <span class=\"number\">1</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">double</span> i1 = <span class=\"built_in\">interpolate</span>(v1, v2, fractional_X);</span><br><span class=\"line\"> <span class=\"type\">double</span> i2 = <span class=\"built_in\">interpolate</span>(v3, v4, fractional_X);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 返回插值后的噪声值</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">interpolate</span>(i1, i2, fractional_Y); </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 循环生成每个像素点的噪声值并转换为灰度颜色</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"comment\">// 生成插值噪声,并控制噪声的规模</span></span><br><span class=\"line\"> <span class=\"type\">double</span> value = <span class=\"built_in\">interpolated_noise</span>(x / <span class=\"number\">50.0</span>, y / <span class=\"number\">50.0</span>); </span><br><span class=\"line\"> <span class=\"comment\">// 将噪声值转换为灰度颜色</span></span><br><span class=\"line\"> COLORREF color = <span class=\"built_in\">RGB</span>((<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>),</span><br><span class=\"line\"> (<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>), (<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>)); </span><br><span class=\"line\"> <span class=\"comment\">// 在指定位置绘制像素</span></span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, color); </span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/87331419268747.png\" alt=\"“痛苦终结者”\"></p>\n</div>\n\n<div style=\"text-align:center\">\n\n<p>>>> <a href=\"https://www.voidmatrix.work/articles/pcg-game-map-1/\">在 Voidmatrix’s Blog 上查看本文章</a> <<<</p>\n</div>","site":{"data":{}},"excerpt":"<p>使用 <strong>程序化内容生成(PCG)</strong> 的优势:</p>\n<ul>\n<li>无限地图内容:两个维度,一是单次游玩的地图内容趋近于无限,即无限大世界;二是可以生成近似无限多的世界,提升游戏的可重复游玩性;</li>\n<li>节省开发成本:开发者只需要定义生成规则来描述世界最底层的机制,而不需要从上到下事无巨细地完成玩家可游玩的全部内容;</li>\n<li>挑战与变化:使用程序生成地图可以很好地控制随机性,给玩家创造挑战的机会,更具趣味性;</li>\n<li>动态难度调整:使用规则描述世界生成可以站在更高的维度去调控世界资源,更好地平衡游戏难度或创造特殊难度的世界。</li>\n</ul>\n<p>在大多数情况下,程序化生成地图的游戏也并不能完全地摆脱传统的手工制作的部分,即便是程序化内容生成主导的世界中,也存在细粒度的部分需要开发者进行人工设计(如 Minecraft 中的村庄等内容),这同样也可以使用更细致的生成规则来描述。</p>","more":"<h2 id=\"生成思路总览\"><a href=\"#生成思路总览\" class=\"headerlink\" title=\"生成思路总览\"></a>生成思路总览</h2><p>对于程序化生成的游戏世界地图,可以使用<strong>分批次地、递归地</strong>类似分形的思想逐步进行细化处理,每一层处理都基本满足以下三个步骤:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/151655416259069.png\" alt=\"每层递归的三个生成步骤\"></p>\n</div>\n\n<ol>\n<li><strong>随机</strong>:根据随机数或噪声算法生成最粗略的数据模板;</li>\n<li><strong>平滑</strong>:根据当前生成内容的维度和粒度对得到的数据进行插值和过渡处理;</li>\n<li><strong>修正</strong>:根据游戏内容和更上层的设计规则调整平滑后的世界。</li>\n</ol>\n<p>一个使用此思想实现的流程可以如下所示:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/202434217267102.png\" alt=\"三步走递归生成示例\"></p>\n</div>\n\n<p>在前两个步骤中,我们需要确保使用的算法满足下列三个条件:</p>\n<ol>\n<li><strong>随机性</strong>:这个过程是随机的,或者说在相当大范围内不会出现重复的生成周期;</li>\n<li><strong>可哈希</strong>:使用相同的随机数输入(种子),得到的随机内容是一致的;</li>\n<li><strong>连续性</strong>:无论粒度大小,生成的内容都是连续且平滑的。</li>\n</ol>\n<blockquote>\n<p>可哈希的特性给游戏的增量存档提供了可能,存储游戏世界信息的存档不需要在初始化生成时便保存全部数据内容,而是可以随着游戏进行,只增量存储玩家探索过或修改过的内容。</p>\n</blockquote>\n<p>下面我们将分类讨论在随机和平滑的过程中使用的算法思路。</p>\n<h2 id=\"直接使用随机数\"><a href=\"#直接使用随机数\" class=\"headerlink\" title=\"直接使用随机数\"></a>直接使用随机数</h2><p>直接使用<code>rand()</code>等随机函数会存在以下问题:</p>\n<ul>\n<li><strong>不连续性</strong>:随机数的生成是跳跃的,直接使用时无法起到平滑的效果;</li>\n<li><strong>易受影响</strong>:虽然我们可以使用<code>srand()</code>等函数设置随机数的种子来确保随机数的哈希性,但是程序的其他部分可能需要使用时间来初始化随机数种子来获取更灵活的随机数,这就导致在全局环境下生成的随机数不稳定。</li>\n</ul>\n<p>使用如下代码生成的灰度图,可以很清楚地看出其不连续性:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/553721218256326.png\" alt=\"`rand()`随机数灰度图\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height, EW_SHOWCONSOLE);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">int</span> val = <span class=\"built_in\">rand</span>() % <span class=\"number\">255</span>;</span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, <span class=\"built_in\">RGB</span>(val, val, val));</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>但是,这并不意味着随机数函数是无用的,我们可以直接使用随机数生成离散的影响点,再根据距离权重进行平滑处理,如《文明6》等游戏中使用的<strong>米切尔候选算法</strong>(Mitchell’s best-candidate algorithm),在处理初期时可以直接使用随机数进行候选节点的生成的,这将在后续的游戏资源生成章节再进行详细讨论。</p>\n<p>在上古项目<a href=\"https://github.com/EtherProject/EtherWorkCollection/tree/main/%E9%9A%8F%E6%9C%BA%E5%9C%B0%E5%9B%BE%E9%AB%98%E5%BA%A6%E5%9B%BE\">随机地图高度图</a>生成过程中,也是使用了简单的先随机后平滑的思路:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/532531818252080.png\" alt=\"随机地图高度图(白色为随机生成的影响点)\"></p>\n</div>\n\n<h2 id=\"平滑的噪声函数\"><a href=\"#平滑的噪声函数\" class=\"headerlink\" title=\"平滑的噪声函数\"></a>平滑的噪声函数</h2><p>在<a href=\"https://www.voidmatrix.work/articles/%E5%9F%BA%E4%BA%8EEasyX%E8%BD%AF%E6%B8%B2%E6%9F%93%E5%AE%9E%E7%8E%B0%E5%B8%B8%E8%A7%81%E6%95%85%E9%9A%9C%E8%89%BA%E6%9C%AF/\">《基于EasyX软渲染实现常见故障艺术》</a>一文中,提供了一种可行的随机噪声函数:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/76072812230849.png\" alt=\"f(x, y) = frac(sin(x * 12.9898 + y * 78.233) * 43758.5453)\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">// 获取随机噪声</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">virtual</span> <span class=\"type\">double</span> <span class=\"title\">GetRandomNoise</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"type\">double</span> val = <span class=\"built_in\">sin</span>(x * <span class=\"number\">12.9898</span> + y * <span class=\"number\">78.233</span>) * <span class=\"number\">43758.5453</span>;</span><br><span class=\"line\">\t<span class=\"keyword\">return</span> val - <span class=\"built_in\">floor</span>(val);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>简单地,我们也可以使用正弦波叠加的思想处理类似的噪声生成:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/125364318267564.png\" alt=\"简单的正弦波叠加同样可以模拟地形效果\"></p>\n</div>\n\n<p>但是,我们可以很清晰地看出,这种直接使用函数生成的噪声即便可以满足哈希性和连续性,但它们的周期性太强,直接将生成得到的计算结果应用于游戏中会导致整个世界出现大量重复地形,并不能完全满足随机性的要求:</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/59555018265066.png\" alt=\"噪声函数存在较强的周期性\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">double</span> val_x = <span class=\"built_in\">abs</span>((<span class=\"number\">1</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">1</span>)) + (<span class=\"number\">0.5</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">2</span>)) + (<span class=\"number\">0.25</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">4</span>)) + (<span class=\"number\">0.125</span> * <span class=\"built_in\">sin</span>(x * <span class=\"number\">8</span>)));</span><br><span class=\"line\"> <span class=\"type\">double</span> val_y = <span class=\"built_in\">abs</span>((<span class=\"number\">1</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">1</span>)) + (<span class=\"number\">0.5</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">2</span>)) + (<span class=\"number\">0.25</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">4</span>)) + (<span class=\"number\">0.125</span> * <span class=\"built_in\">sin</span>(y * <span class=\"number\">8</span>)));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 对得到的结果进行归一化</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> (val_x + val_y) / ((<span class=\"number\">1</span> + <span class=\"number\">0.5</span> + <span class=\"number\">0.25</span> + <span class=\"number\">0.125</span>) * <span class=\"number\">2</span>);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height, EW_SHOWCONSOLE);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++)</span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"type\">int</span> val = (<span class=\"type\">int</span>)(<span class=\"built_in\">noise</span>(x / <span class=\"number\">10</span>, y / <span class=\"number\">10</span>) * <span class=\"number\">255</span>);</span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, <span class=\"built_in\">RGB</span>(val, val, val));</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p>即便如此,这些生成噪声的方式,同样可以作为<strong>分形噪声</strong>等更进阶的噪声生成时的原始数据。</p>\n<h2 id=\"更进阶的噪声生成\"><a href=\"#更进阶的噪声生成\" class=\"headerlink\" title=\"更进阶的噪声生成\"></a>更进阶的噪声生成</h2><p>有许多已经被实践证明满足上述需求的噪声算法,如:Perlin噪声,Simplex噪声,Wavelet噪声,Value噪声和Worley噪声等,下面将以大名鼎鼎的<strong>柏林噪声</strong>(Perlin)为例讲解实现思路。</p>\n<blockquote>\n<p>柏林噪声本质上可以算是一种非典型的晶格噪声技术,晶格噪声是一种在离散的、规则的网格上生成的噪声,所以晶格噪声通常在规则的格点上有着明确定义的数值,而柏林噪声的特殊之处在于,在使用晶格为单位生成基础噪声后,又通过插值和平滑处理,产生了空间中连续的噪声变化。</p>\n</blockquote>\n<p>柏林噪声的生成可以归纳为三步:</p>\n<ol>\n<li><strong>梯度生成</strong>:在空间中随机生成梯度向量网格,梯度向量由每个整数坐标点(晶格)上随机确定的。这些梯度向量定义了一个在整个空间内变化的方向;</li>\n<li><strong>插值</strong>:当需要计算某一点的噪声值时,首先确定其所处的网格单元,然后计算该点到网格单元内各个梯度向量的距离,并将这些距离用于权重插值,在这个过程中噪声得到了平滑的处理;</li>\n<li><strong>分形</strong>:对生成得到的结果进行不同尺度的缩放和叠加,来生成更具随机性且不同粒度的结果。</li>\n</ol>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/161600919246307.png\" alt=\"柏林噪声灰度图\"></p>\n</div>\n\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><cmath></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span> <span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 生成基础噪声值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">fmod</span>(<span class=\"built_in\">sin</span>(x * <span class=\"number\">12.9898</span> + y * <span class=\"number\">78.233</span>) * <span class=\"number\">43758.5453</span>, <span class=\"number\">1.0</span>);</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 生成平滑噪声值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">smooth_noise</span><span class=\"params\">(<span class=\"type\">int</span> x, <span class=\"type\">int</span> y)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算角落、边和中心的平均噪声值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> corners = (<span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y + <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y + <span class=\"number\">1</span>)) / <span class=\"number\">16</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> sides = (<span class=\"built_in\">noise</span>(x - <span class=\"number\">1</span>, y) + <span class=\"built_in\">noise</span>(x + <span class=\"number\">1</span>, y) + <span class=\"built_in\">noise</span>(x, y - <span class=\"number\">1</span>) + <span class=\"built_in\">noise</span>(x, y + <span class=\"number\">1</span>)) / <span class=\"number\">8</span>;</span><br><span class=\"line\"> <span class=\"type\">double</span> center = <span class=\"built_in\">noise</span>(x, y) / <span class=\"number\">4</span>;</span><br><span class=\"line\"> <span class=\"comment\">// 返回平滑噪声值</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> corners + sides + center; </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 线性插值</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">interpolate</span><span class=\"params\">(<span class=\"type\">double</span> a, <span class=\"type\">double</span> b, <span class=\"type\">double</span> x)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 计算插值权重</span></span><br><span class=\"line\"> <span class=\"type\">double</span> ft = x * <span class=\"number\">3.1415927</span>; </span><br><span class=\"line\"> <span class=\"type\">double</span> f = (<span class=\"number\">1</span> - <span class=\"built_in\">cos</span>(ft)) * <span class=\"number\">0.5</span>;</span><br><span class=\"line\"> <span class=\"comment\">// 返回插值结果</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> a * (<span class=\"number\">1</span> - f) + b * f; </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// 插值计算</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">double</span> <span class=\"title\">interpolated_noise</span><span class=\"params\">(<span class=\"type\">double</span> x, <span class=\"type\">double</span> y)</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"comment\">// 提取整数部分和小数部分</span></span><br><span class=\"line\"> <span class=\"type\">int</span> integer_X = <span class=\"built_in\">static_cast</span><<span class=\"type\">int</span>>(x);</span><br><span class=\"line\"> <span class=\"type\">double</span> fractional_X = x - integer_X;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">int</span> integer_Y = <span class=\"built_in\">static_cast</span><<span class=\"type\">int</span>>(y);</span><br><span class=\"line\"> <span class=\"type\">double</span> fractional_Y = y - integer_Y;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 计算插值点的噪声值</span></span><br><span class=\"line\"> <span class=\"type\">double</span> v1 = <span class=\"built_in\">smooth_noise</span>(integer_X, integer_Y);</span><br><span class=\"line\"> <span class=\"type\">double</span> v2 = <span class=\"built_in\">smooth_noise</span>(integer_X + <span class=\"number\">1</span>, integer_Y);</span><br><span class=\"line\"> <span class=\"type\">double</span> v3 = <span class=\"built_in\">smooth_noise</span>(integer_X, integer_Y + <span class=\"number\">1</span>);</span><br><span class=\"line\"> <span class=\"type\">double</span> v4 = <span class=\"built_in\">smooth_noise</span>(integer_X + <span class=\"number\">1</span>, integer_Y + <span class=\"number\">1</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">double</span> i1 = <span class=\"built_in\">interpolate</span>(v1, v2, fractional_X);</span><br><span class=\"line\"> <span class=\"type\">double</span> i2 = <span class=\"built_in\">interpolate</span>(v3, v4, fractional_X);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 返回插值后的噪声值</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">interpolate</span>(i1, i2, fractional_Y); </span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span> </span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> width = <span class=\"number\">1280</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> height = <span class=\"number\">720</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">initgraph</span>(width, height);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 循环生成每个像素点的噪声值并转换为灰度颜色</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> y = <span class=\"number\">0</span>; y < height; y++) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> x = <span class=\"number\">0</span>; x < width; x++) </span><br><span class=\"line\"> {</span><br><span class=\"line\"> <span class=\"comment\">// 生成插值噪声,并控制噪声的规模</span></span><br><span class=\"line\"> <span class=\"type\">double</span> value = <span class=\"built_in\">interpolated_noise</span>(x / <span class=\"number\">50.0</span>, y / <span class=\"number\">50.0</span>); </span><br><span class=\"line\"> <span class=\"comment\">// 将噪声值转换为灰度颜色</span></span><br><span class=\"line\"> COLORREF color = <span class=\"built_in\">RGB</span>((<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>),</span><br><span class=\"line\"> (<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>), (<span class=\"type\">int</span>)(value * <span class=\"number\">255</span>)); </span><br><span class=\"line\"> <span class=\"comment\">// 在指定位置绘制像素</span></span><br><span class=\"line\"> <span class=\"built_in\">putpixel</span>(x, y, color); </span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"built_in\">system</span>(<span class=\"string\">"pause"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/Voidmatrix/pcg-game-map-1/87331419268747.png\" alt=\"“痛苦终结者”\"></p>\n</div>\n\n<div style=\"text-align:center\">\n\n<p>>>> <a href=\"https://www.voidmatrix.work/articles/pcg-game-map-1/\">在 Voidmatrix’s Blog 上查看本文章</a> <<<</p>\n</div>"},{"title":"植物明星大乱斗系列视频——勘误","date":"2024-05-31T16:00:00.000Z","updated":"2024-05-31T16:00:00.000Z","_content":"本文收录并校对植物明星大乱斗系列视频中出现的错误\n\n[从零开始的植物明星大乱斗系列视频](https://space.bilibili.com/25864506/channel/collectiondetail?sid=2277932&ctype=0)\n<!-- More -->\n## 错误\n该部分收录已确定的错误 \n1. 在resources文件夹中 \n![winnner_bar.png](https://img2.imgtp.com/2024/06/01/TsrZUjB2.png) \n\"winnner_bar.png\"拼写错误,应重命名为\"winner_bar.png\"\n\n\n2. 在[资源加载和动画类实现](https://www.bilibili.com/video/BV1ej421Z77V)01:27中 \n![img_flpipped](https://img2.imgtp.com/2024/06/01/18bGI35B.png)\n\"img_flpipped\"拼写错误,应重命名为\"img_flipped\"\n\n\n3. 在[玩家子弹发射和角色技能实现](https://www.bilibili.com/video/BV1km421M79S)12:00中\n![timer_spwan_pea_ex](https://img2.imgtp.com/2024/06/01/R0uRCP8p.png) \n\"timer_spwan_pea_ex\"拼写错误,应重命名为\"timer_spawn_pea_ex\"\n\n\n4. 在[玩家子弹发射和角色技能实现](https://www.bilibili.com/video/BV1km421M79S)12:08中\n![](https://img2.imgtp.com/2024/06/01/sAM1veUe.png)\nSunflowerPlayer构造函数缺少头顶文本动画,左右特殊攻击动画的部分语句,应添加\n![](https://img2.imgtp.com/2024/06/01/5lRMNfFu.png)\n实际上这部分添加内容在08:53中出现过\n## 警告\n该部分收录的算不算错误我不好说\n1. resources文件夹中sun_explode_ex.mp3和sun_ex_explode系列图片命名不同 \n我把sun_explode_ex.mp3以及main.cpp、sun_bullet_ex.h中使用的别名统一修改为sun_ex_explode\n![main.cpp](https://img2.imgtp.com/2024/06/01/TAmj1Gha.png)\n![sun_bullet_ex.h](https://img2.imgtp.com/2024/06/01/G7cEDcpW.png)\n","source":"_posts/Ye Minglv/植物明星大乱斗系列视频——勘误.md","raw":"---\ntitle: 植物明星大乱斗系列视频——勘误\ndate: 2024-06-01\nupdated: 2024-06-01\npermalink: articles/Ye Minglv/video_corrigendum/\ncategories: Ye Minglv\ntags: [勘误]\n---\n本文收录并校对植物明星大乱斗系列视频中出现的错误\n\n[从零开始的植物明星大乱斗系列视频](https://space.bilibili.com/25864506/channel/collectiondetail?sid=2277932&ctype=0)\n<!-- More -->\n## 错误\n该部分收录已确定的错误 \n1. 在resources文件夹中 \n![winnner_bar.png](https://img2.imgtp.com/2024/06/01/TsrZUjB2.png) \n\"winnner_bar.png\"拼写错误,应重命名为\"winner_bar.png\"\n\n\n2. 在[资源加载和动画类实现](https://www.bilibili.com/video/BV1ej421Z77V)01:27中 \n![img_flpipped](https://img2.imgtp.com/2024/06/01/18bGI35B.png)\n\"img_flpipped\"拼写错误,应重命名为\"img_flipped\"\n\n\n3. 在[玩家子弹发射和角色技能实现](https://www.bilibili.com/video/BV1km421M79S)12:00中\n![timer_spwan_pea_ex](https://img2.imgtp.com/2024/06/01/R0uRCP8p.png) \n\"timer_spwan_pea_ex\"拼写错误,应重命名为\"timer_spawn_pea_ex\"\n\n\n4. 在[玩家子弹发射和角色技能实现](https://www.bilibili.com/video/BV1km421M79S)12:08中\n![](https://img2.imgtp.com/2024/06/01/sAM1veUe.png)\nSunflowerPlayer构造函数缺少头顶文本动画,左右特殊攻击动画的部分语句,应添加\n![](https://img2.imgtp.com/2024/06/01/5lRMNfFu.png)\n实际上这部分添加内容在08:53中出现过\n## 警告\n该部分收录的算不算错误我不好说\n1. resources文件夹中sun_explode_ex.mp3和sun_ex_explode系列图片命名不同 \n我把sun_explode_ex.mp3以及main.cpp、sun_bullet_ex.h中使用的别名统一修改为sun_ex_explode\n![main.cpp](https://img2.imgtp.com/2024/06/01/TAmj1Gha.png)\n![sun_bullet_ex.h](https://img2.imgtp.com/2024/06/01/G7cEDcpW.png)\n","slug":"Ye Minglv/植物明星大乱斗系列视频——勘误","published":1,"__permalink":"articles/Ye Minglv/video_corrigendum/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgi0012o8yebtfgesnl","content":"<p>本文收录并校对植物明星大乱斗系列视频中出现的错误</p>\n<p><a href=\"https://space.bilibili.com/25864506/channel/collectiondetail?sid=2277932&ctype=0\">从零开始的植物明星大乱斗系列视频</a></p>\n<span id=\"more\"></span>\n<h2 id=\"错误\"><a href=\"#错误\" class=\"headerlink\" title=\"错误\"></a>错误</h2><p>该部分收录已确定的错误 </p>\n<ol>\n<li><p>在resources文件夹中<br><img src=\"https://img2.imgtp.com/2024/06/01/TsrZUjB2.png\" alt=\"winnner_bar.png\"><br>“winnner_bar.png”拼写错误,应重命名为”winner_bar.png”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1ej421Z77V\">资源加载和动画类实现</a>01:27中<br><img src=\"https://img2.imgtp.com/2024/06/01/18bGI35B.png\" alt=\"img_flpipped\"><br>“img_flpipped”拼写错误,应重命名为”img_flipped”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1km421M79S\">玩家子弹发射和角色技能实现</a>12:00中<br><img src=\"https://img2.imgtp.com/2024/06/01/R0uRCP8p.png\" alt=\"timer_spwan_pea_ex\"><br>“timer_spwan_pea_ex”拼写错误,应重命名为”timer_spawn_pea_ex”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1km421M79S\">玩家子弹发射和角色技能实现</a>12:08中<br><img src=\"https://img2.imgtp.com/2024/06/01/sAM1veUe.png\"><br>SunflowerPlayer构造函数缺少头顶文本动画,左右特殊攻击动画的部分语句,应添加<br><img src=\"https://img2.imgtp.com/2024/06/01/5lRMNfFu.png\"><br>实际上这部分添加内容在08:53中出现过</p>\n</li>\n</ol>\n<h2 id=\"警告\"><a href=\"#警告\" class=\"headerlink\" title=\"警告\"></a>警告</h2><p>该部分收录的算不算错误我不好说</p>\n<ol>\n<li>resources文件夹中sun_explode_ex.mp3和sun_ex_explode系列图片命名不同<br>我把sun_explode_ex.mp3以及main.cpp、sun_bullet_ex.h中使用的别名统一修改为sun_ex_explode<br><img src=\"https://img2.imgtp.com/2024/06/01/TAmj1Gha.png\" alt=\"main.cpp\"><br><img src=\"https://img2.imgtp.com/2024/06/01/G7cEDcpW.png\" alt=\"sun_bullet_ex.h\"></li>\n</ol>\n","site":{"data":{}},"excerpt":"<p>本文收录并校对植物明星大乱斗系列视频中出现的错误</p>\n<p><a href=\"https://space.bilibili.com/25864506/channel/collectiondetail?sid=2277932&ctype=0\">从零开始的植物明星大乱斗系列视频</a></p>","more":"<h2 id=\"错误\"><a href=\"#错误\" class=\"headerlink\" title=\"错误\"></a>错误</h2><p>该部分收录已确定的错误 </p>\n<ol>\n<li><p>在resources文件夹中<br><img src=\"https://img2.imgtp.com/2024/06/01/TsrZUjB2.png\" alt=\"winnner_bar.png\"><br>“winnner_bar.png”拼写错误,应重命名为”winner_bar.png”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1ej421Z77V\">资源加载和动画类实现</a>01:27中<br><img src=\"https://img2.imgtp.com/2024/06/01/18bGI35B.png\" alt=\"img_flpipped\"><br>“img_flpipped”拼写错误,应重命名为”img_flipped”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1km421M79S\">玩家子弹发射和角色技能实现</a>12:00中<br><img src=\"https://img2.imgtp.com/2024/06/01/R0uRCP8p.png\" alt=\"timer_spwan_pea_ex\"><br>“timer_spwan_pea_ex”拼写错误,应重命名为”timer_spawn_pea_ex”</p>\n</li>\n<li><p>在<a href=\"https://www.bilibili.com/video/BV1km421M79S\">玩家子弹发射和角色技能实现</a>12:08中<br><img src=\"https://img2.imgtp.com/2024/06/01/sAM1veUe.png\"><br>SunflowerPlayer构造函数缺少头顶文本动画,左右特殊攻击动画的部分语句,应添加<br><img src=\"https://img2.imgtp.com/2024/06/01/5lRMNfFu.png\"><br>实际上这部分添加内容在08:53中出现过</p>\n</li>\n</ol>\n<h2 id=\"警告\"><a href=\"#警告\" class=\"headerlink\" title=\"警告\"></a>警告</h2><p>该部分收录的算不算错误我不好说</p>\n<ol>\n<li>resources文件夹中sun_explode_ex.mp3和sun_ex_explode系列图片命名不同<br>我把sun_explode_ex.mp3以及main.cpp、sun_bullet_ex.h中使用的别名统一修改为sun_ex_explode<br><img src=\"https://img2.imgtp.com/2024/06/01/TAmj1Gha.png\" alt=\"main.cpp\"><br><img src=\"https://img2.imgtp.com/2024/06/01/G7cEDcpW.png\" alt=\"sun_bullet_ex.h\"></li>\n</ol>"},{"title":"测试","date":"2024-05-27T16:00:00.000Z","update":"2024-05-27T16:00:00.000Z","_content":"\n这里是一个测试,大佬看看是这样咩?\n\n<!--More-->\n\n<div style=\"text-align:center\">\n\n![V](img/avatar.png)\n\n</div>","source":"_posts/YoungFlame/测试.md","raw":"---\ntitle: 测试\ndate: 2024-05-28\nupdate: 2024-05-28\npermalink: articles/YoungFlame/\ncategories: YoungFlame\ntags: [测试]\n---\n\n这里是一个测试,大佬看看是这样咩?\n\n<!--More-->\n\n<div style=\"text-align:center\">\n\n![V](img/avatar.png)\n\n</div>","slug":"YoungFlame/测试","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/YoungFlame/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgj0015o8ye980e2j2j","content":"<p>这里是一个测试,大佬看看是这样咩?</p>\n<span id=\"more\"></span>\n\n<div style=\"text-align:center\">\n\n<p><img src=\"/img/avatar.png\" alt=\"V\"></p>\n</div>","site":{"data":{}},"excerpt":"<p>这里是一个测试,大佬看看是这样咩?</p>","more":"<div style=\"text-align:center\">\n\n<p><img src=\"/img/avatar.png\" alt=\"V\"></p>\n</div>"},{"title":"博客第一步:将Hexo部署在GitHub上","date":"2024-04-09T16:00:00.000Z","_content":"\nHexo 是一个快速、简单且强大的静态博客框架,与 GitHub 结合使用可轻松搭建个人博客网站。\n\n<!-- more -->\n\nHexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他标记语言)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。其主题,模板也更加丰富多样,更适合创建功能丰富的个人博客或其他类型的静态网站。\n\n## Quick Start\n\n接下来,我将分享我在GitHub上部署Hexo的过程步骤,并给出其中我遇到的一些困难与解决方法。。\n\n### 1.安装Node\n\nHexo是一个基于Node.js的静态网站生成器,需要在本地安装Node.js环境,并通过命令行来创建、编译和部署网站。\n\n下载链接: [Node](https://nodejs.cn/)\n\n### 2.安装Sublime text\n\n这个算是文本编辑器,但功能更加强大,有许多妙用。\n\n下载链接: [Sublime text](https://www.sublimetext.com/)\n\n### 3.下载Git\n\n下载链接: [Git](https://git-scm.com/)\n\n#### 基本配置Git\n\n打开gitbush终端输入一下指令(名字邮箱皆与GitHub相关),这将关系到你是否能将仓库推送到GitHub上\n\na.配置昵称,邮箱\n\n``` bash\n$ git config --global user.name \"Your Name\"\n$ git config --global user.email \"your.email@example.com\"\n```\n\nb.生成ssh\n\n``` bash\n$ ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\" //生成ssh密钥\n```\n\nc.添加 SSH 公钥到GitHub账户\n\n#### 使用Git链接远程仓库(后续会使用到)\n\n需要替换url\n\n``` bash\n$ git init //初始化仓库\n$ git remote add origin https://github.com/exampleuser/example.git \n$ git remote -v //查看是否关联成功\n```\n\n### 4.创建GitHub仓库\n\n建立一个公共仓库,仓库名:<你的 GitHub 用户名>.github.io\neg:Dream-verylively.github.io\n\n### 5.配置并使用Hexo\n\na.配置hexo\n\n这个步骤将生成blog文件夹,接下来的诸多操作将围绕这个文件夹进行\n\n``` bash\n$ npm install hexo-cli -g //安装 Hexo CLI(命令行工具)到全局环境\n$ hexo init blog //始化 Hexo 博客,创建一个名为 \"blog\" 的目录,并在其中初始化 Hexo(名字可更改)\n$ cd blog //进入到刚创建的 \"blog\" 目录中\n$ npm install //npm install\n$ hexo server //启动 Hexo 服务器,用于本地预览您的博客\n```\n\nMore info: [hexo](https://hexo.io/zh-cn/)\n\nb.编辑你的 _config.yml\n\n第一处\n![ICON](articles/shuo-liu16/deploy-hexo/1.png)\n第二处\n![ICON](articles/shuo-liu16/deploy-hexo/2.png)\n\nc.在博客文件夹下打开终端执行以下命令\n\n``` bash\n$ hexo clean //清理 Hexo 生成的静态文件和缓存\n$ hexo g //使用 Hexo 生成静态文件,将 Markdown 格式的文章转换为 HTML 等静态文件\n$ hexo deploy //部署生成的静态文件到指定的部署目标(例如 GitHub Pages、FTP 等)\n```\n\n### GithubPages 404问题\n\n#### 1、github 仓库名称不匹配\n\n在 github 上面创建的仓库名称没有使用自己的 github 账号名称,例如你的 github 账号名称是 zhanghao,而你创建的仓库名称是 suibian.github.io,这样你是无法访问你的博客网站的。\n\n#### 2、配置文件错误\n\n在你的本地博客目录下(我创建的名称是 hexo,注意不是 themes 主题目录下的那个配置文件),有个配置文件 _config.yml,注意观察里边的内容是否符合条件。\n\n#### 3、分支错误\n\n注意提交的分支要与GitHub仓库中的默认分支一致\n\n#### 4、hexo 依赖不全\n\n检查依赖安装是否有不全的情况,可以使用 npm list 命令\n\n``` bash\n$ npm list --depth 0\n```\n\n如果检查有问题,会在控制台提示类似 npm ERR! missing xxxxx。\n\n#### 5.版本不匹配问题(node与hexo)\n\n``` bash\n$ node -v //检查两者的版本\n$ hexo -v\n```\n\n看这个:[版本限制](https://hexo.io/zh-cn/docs/#Node-js-%E7%89%88%E6%9C%AC%E9%99%90%E5%88%B6)\n\n###### 写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。","source":"_posts/shuo-liu16/deploy-Hexo-2024-04-10.md","raw":"---\ntitle: 博客第一步:将Hexo部署在GitHub上\n# author: shuo-liu16\ndate: 2024-4-10\npermalink: articles/shuo-liu16/deploy-hexo/\ncategories: shuo-liu16\ntags: hexo\n---\n\nHexo 是一个快速、简单且强大的静态博客框架,与 GitHub 结合使用可轻松搭建个人博客网站。\n\n<!-- more -->\n\nHexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他标记语言)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。其主题,模板也更加丰富多样,更适合创建功能丰富的个人博客或其他类型的静态网站。\n\n## Quick Start\n\n接下来,我将分享我在GitHub上部署Hexo的过程步骤,并给出其中我遇到的一些困难与解决方法。。\n\n### 1.安装Node\n\nHexo是一个基于Node.js的静态网站生成器,需要在本地安装Node.js环境,并通过命令行来创建、编译和部署网站。\n\n下载链接: [Node](https://nodejs.cn/)\n\n### 2.安装Sublime text\n\n这个算是文本编辑器,但功能更加强大,有许多妙用。\n\n下载链接: [Sublime text](https://www.sublimetext.com/)\n\n### 3.下载Git\n\n下载链接: [Git](https://git-scm.com/)\n\n#### 基本配置Git\n\n打开gitbush终端输入一下指令(名字邮箱皆与GitHub相关),这将关系到你是否能将仓库推送到GitHub上\n\na.配置昵称,邮箱\n\n``` bash\n$ git config --global user.name \"Your Name\"\n$ git config --global user.email \"your.email@example.com\"\n```\n\nb.生成ssh\n\n``` bash\n$ ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\" //生成ssh密钥\n```\n\nc.添加 SSH 公钥到GitHub账户\n\n#### 使用Git链接远程仓库(后续会使用到)\n\n需要替换url\n\n``` bash\n$ git init //初始化仓库\n$ git remote add origin https://github.com/exampleuser/example.git \n$ git remote -v //查看是否关联成功\n```\n\n### 4.创建GitHub仓库\n\n建立一个公共仓库,仓库名:<你的 GitHub 用户名>.github.io\neg:Dream-verylively.github.io\n\n### 5.配置并使用Hexo\n\na.配置hexo\n\n这个步骤将生成blog文件夹,接下来的诸多操作将围绕这个文件夹进行\n\n``` bash\n$ npm install hexo-cli -g //安装 Hexo CLI(命令行工具)到全局环境\n$ hexo init blog //始化 Hexo 博客,创建一个名为 \"blog\" 的目录,并在其中初始化 Hexo(名字可更改)\n$ cd blog //进入到刚创建的 \"blog\" 目录中\n$ npm install //npm install\n$ hexo server //启动 Hexo 服务器,用于本地预览您的博客\n```\n\nMore info: [hexo](https://hexo.io/zh-cn/)\n\nb.编辑你的 _config.yml\n\n第一处\n![ICON](articles/shuo-liu16/deploy-hexo/1.png)\n第二处\n![ICON](articles/shuo-liu16/deploy-hexo/2.png)\n\nc.在博客文件夹下打开终端执行以下命令\n\n``` bash\n$ hexo clean //清理 Hexo 生成的静态文件和缓存\n$ hexo g //使用 Hexo 生成静态文件,将 Markdown 格式的文章转换为 HTML 等静态文件\n$ hexo deploy //部署生成的静态文件到指定的部署目标(例如 GitHub Pages、FTP 等)\n```\n\n### GithubPages 404问题\n\n#### 1、github 仓库名称不匹配\n\n在 github 上面创建的仓库名称没有使用自己的 github 账号名称,例如你的 github 账号名称是 zhanghao,而你创建的仓库名称是 suibian.github.io,这样你是无法访问你的博客网站的。\n\n#### 2、配置文件错误\n\n在你的本地博客目录下(我创建的名称是 hexo,注意不是 themes 主题目录下的那个配置文件),有个配置文件 _config.yml,注意观察里边的内容是否符合条件。\n\n#### 3、分支错误\n\n注意提交的分支要与GitHub仓库中的默认分支一致\n\n#### 4、hexo 依赖不全\n\n检查依赖安装是否有不全的情况,可以使用 npm list 命令\n\n``` bash\n$ npm list --depth 0\n```\n\n如果检查有问题,会在控制台提示类似 npm ERR! missing xxxxx。\n\n#### 5.版本不匹配问题(node与hexo)\n\n``` bash\n$ node -v //检查两者的版本\n$ hexo -v\n```\n\n看这个:[版本限制](https://hexo.io/zh-cn/docs/#Node-js-%E7%89%88%E6%9C%AC%E9%99%90%E5%88%B6)\n\n###### 写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。","slug":"shuo-liu16/deploy-Hexo-2024-04-10","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/shuo-liu16/deploy-hexo/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgk0018o8yecnntceft","content":"<p>Hexo 是一个快速、简单且强大的静态博客框架,与 GitHub 结合使用可轻松搭建个人博客网站。</p>\n<span id=\"more\"></span>\n\n<p>Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他标记语言)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。其主题,模板也更加丰富多样,更适合创建功能丰富的个人博客或其他类型的静态网站。</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><p>接下来,我将分享我在GitHub上部署Hexo的过程步骤,并给出其中我遇到的一些困难与解决方法。。</p>\n<h3 id=\"1-安装Node\"><a href=\"#1-安装Node\" class=\"headerlink\" title=\"1.安装Node\"></a>1.安装Node</h3><p>Hexo是一个基于Node.js的静态网站生成器,需要在本地安装Node.js环境,并通过命令行来创建、编译和部署网站。</p>\n<p>下载链接: <a href=\"https://nodejs.cn/\">Node</a></p>\n<h3 id=\"2-安装Sublime-text\"><a href=\"#2-安装Sublime-text\" class=\"headerlink\" title=\"2.安装Sublime text\"></a>2.安装Sublime text</h3><p>这个算是文本编辑器,但功能更加强大,有许多妙用。</p>\n<p>下载链接: <a href=\"https://www.sublimetext.com/\">Sublime text</a></p>\n<h3 id=\"3-下载Git\"><a href=\"#3-下载Git\" class=\"headerlink\" title=\"3.下载Git\"></a>3.下载Git</h3><p>下载链接: <a href=\"https://git-scm.com/\">Git</a></p>\n<h4 id=\"基本配置Git\"><a href=\"#基本配置Git\" class=\"headerlink\" title=\"基本配置Git\"></a>基本配置Git</h4><p>打开gitbush终端输入一下指令(名字邮箱皆与GitHub相关),这将关系到你是否能将仓库推送到GitHub上</p>\n<p>a.配置昵称,邮箱</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git config --global user.name <span class=\"string\">"Your Name"</span></span><br><span class=\"line\">$ git config --global user.email <span class=\"string\">"your.email@example.com"</span></span><br></pre></td></tr></table></figure>\n\n<p>b.生成ssh</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ ssh-keygen -t rsa -b 4096 -C <span class=\"string\">"your_email@example.com"</span> //生成ssh密钥</span><br></pre></td></tr></table></figure>\n\n<p>c.添加 SSH 公钥到GitHub账户</p>\n<h4 id=\"使用Git链接远程仓库(后续会使用到)\"><a href=\"#使用Git链接远程仓库(后续会使用到)\" class=\"headerlink\" title=\"使用Git链接远程仓库(后续会使用到)\"></a>使用Git链接远程仓库(后续会使用到)</h4><p>需要替换url</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git init //初始化仓库</span><br><span class=\"line\">$ git remote add origin https://github.com/exampleuser/example.git </span><br><span class=\"line\">$ git remote -v //查看是否关联成功</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"4-创建GitHub仓库\"><a href=\"#4-创建GitHub仓库\" class=\"headerlink\" title=\"4.创建GitHub仓库\"></a>4.创建GitHub仓库</h3><p>建立一个公共仓库,仓库名:<你的 GitHub 用户名>.github.io<br>eg:Dream-verylively.github.io</p>\n<h3 id=\"5-配置并使用Hexo\"><a href=\"#5-配置并使用Hexo\" class=\"headerlink\" title=\"5.配置并使用Hexo\"></a>5.配置并使用Hexo</h3><p>a.配置hexo</p>\n<p>这个步骤将生成blog文件夹,接下来的诸多操作将围绕这个文件夹进行</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ npm install hexo-cli -g //安装 Hexo CLI(命令行工具)到全局环境</span><br><span class=\"line\">$ hexo init blog //始化 Hexo 博客,创建一个名为 <span class=\"string\">"blog"</span> 的目录,并在其中初始化 Hexo(名字可更改)</span><br><span class=\"line\">$ <span class=\"built_in\">cd</span> blog //进入到刚创建的 <span class=\"string\">"blog"</span> 目录中</span><br><span class=\"line\">$ npm install //npm install</span><br><span class=\"line\">$ hexo server //启动 Hexo 服务器,用于本地预览您的博客</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/zh-cn/\">hexo</a></p>\n<p>b.编辑你的 _config.yml</p>\n<p>第一处<br><img src=\"/articles/shuo-liu16/deploy-hexo/1.png\" alt=\"ICON\"><br>第二处<br><img src=\"/articles/shuo-liu16/deploy-hexo/2.png\" alt=\"ICON\"></p>\n<p>c.在博客文件夹下打开终端执行以下命令</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo clean //清理 Hexo 生成的静态文件和缓存</span><br><span class=\"line\">$ hexo g //使用 Hexo 生成静态文件,将 Markdown 格式的文章转换为 HTML 等静态文件</span><br><span class=\"line\">$ hexo deploy //部署生成的静态文件到指定的部署目标(例如 GitHub Pages、FTP 等)</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"GithubPages-404问题\"><a href=\"#GithubPages-404问题\" class=\"headerlink\" title=\"GithubPages 404问题\"></a>GithubPages 404问题</h3><h4 id=\"1、github-仓库名称不匹配\"><a href=\"#1、github-仓库名称不匹配\" class=\"headerlink\" title=\"1、github 仓库名称不匹配\"></a>1、github 仓库名称不匹配</h4><p>在 github 上面创建的仓库名称没有使用自己的 github 账号名称,例如你的 github 账号名称是 zhanghao,而你创建的仓库名称是 suibian.github.io,这样你是无法访问你的博客网站的。</p>\n<h4 id=\"2、配置文件错误\"><a href=\"#2、配置文件错误\" class=\"headerlink\" title=\"2、配置文件错误\"></a>2、配置文件错误</h4><p>在你的本地博客目录下(我创建的名称是 hexo,注意不是 themes 主题目录下的那个配置文件),有个配置文件 _config.yml,注意观察里边的内容是否符合条件。</p>\n<h4 id=\"3、分支错误\"><a href=\"#3、分支错误\" class=\"headerlink\" title=\"3、分支错误\"></a>3、分支错误</h4><p>注意提交的分支要与GitHub仓库中的默认分支一致</p>\n<h4 id=\"4、hexo-依赖不全\"><a href=\"#4、hexo-依赖不全\" class=\"headerlink\" title=\"4、hexo 依赖不全\"></a>4、hexo 依赖不全</h4><p>检查依赖安装是否有不全的情况,可以使用 npm list 命令</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ npm list --depth 0</span><br></pre></td></tr></table></figure>\n\n<p>如果检查有问题,会在控制台提示类似 npm ERR! missing xxxxx。</p>\n<h4 id=\"5-版本不匹配问题(node与hexo)\"><a href=\"#5-版本不匹配问题(node与hexo)\" class=\"headerlink\" title=\"5.版本不匹配问题(node与hexo)\"></a>5.版本不匹配问题(node与hexo)</h4><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ node -v //检查两者的版本</span><br><span class=\"line\">$ hexo -v</span><br></pre></td></tr></table></figure>\n\n<p>看这个:<a href=\"https://hexo.io/zh-cn/docs/#Node-js-%E7%89%88%E6%9C%AC%E9%99%90%E5%88%B6\">版本限制</a></p>\n<h6 id=\"写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\"><a href=\"#写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\" class=\"headerlink\" title=\"写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\"></a>写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。</h6>","site":{"data":{}},"excerpt":"<p>Hexo 是一个快速、简单且强大的静态博客框架,与 GitHub 结合使用可轻松搭建个人博客网站。</p>","more":"<p>Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他标记语言)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。其主题,模板也更加丰富多样,更适合创建功能丰富的个人博客或其他类型的静态网站。</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><p>接下来,我将分享我在GitHub上部署Hexo的过程步骤,并给出其中我遇到的一些困难与解决方法。。</p>\n<h3 id=\"1-安装Node\"><a href=\"#1-安装Node\" class=\"headerlink\" title=\"1.安装Node\"></a>1.安装Node</h3><p>Hexo是一个基于Node.js的静态网站生成器,需要在本地安装Node.js环境,并通过命令行来创建、编译和部署网站。</p>\n<p>下载链接: <a href=\"https://nodejs.cn/\">Node</a></p>\n<h3 id=\"2-安装Sublime-text\"><a href=\"#2-安装Sublime-text\" class=\"headerlink\" title=\"2.安装Sublime text\"></a>2.安装Sublime text</h3><p>这个算是文本编辑器,但功能更加强大,有许多妙用。</p>\n<p>下载链接: <a href=\"https://www.sublimetext.com/\">Sublime text</a></p>\n<h3 id=\"3-下载Git\"><a href=\"#3-下载Git\" class=\"headerlink\" title=\"3.下载Git\"></a>3.下载Git</h3><p>下载链接: <a href=\"https://git-scm.com/\">Git</a></p>\n<h4 id=\"基本配置Git\"><a href=\"#基本配置Git\" class=\"headerlink\" title=\"基本配置Git\"></a>基本配置Git</h4><p>打开gitbush终端输入一下指令(名字邮箱皆与GitHub相关),这将关系到你是否能将仓库推送到GitHub上</p>\n<p>a.配置昵称,邮箱</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git config --global user.name <span class=\"string\">"Your Name"</span></span><br><span class=\"line\">$ git config --global user.email <span class=\"string\">"your.email@example.com"</span></span><br></pre></td></tr></table></figure>\n\n<p>b.生成ssh</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ ssh-keygen -t rsa -b 4096 -C <span class=\"string\">"your_email@example.com"</span> //生成ssh密钥</span><br></pre></td></tr></table></figure>\n\n<p>c.添加 SSH 公钥到GitHub账户</p>\n<h4 id=\"使用Git链接远程仓库(后续会使用到)\"><a href=\"#使用Git链接远程仓库(后续会使用到)\" class=\"headerlink\" title=\"使用Git链接远程仓库(后续会使用到)\"></a>使用Git链接远程仓库(后续会使用到)</h4><p>需要替换url</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ git init //初始化仓库</span><br><span class=\"line\">$ git remote add origin https://github.com/exampleuser/example.git </span><br><span class=\"line\">$ git remote -v //查看是否关联成功</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"4-创建GitHub仓库\"><a href=\"#4-创建GitHub仓库\" class=\"headerlink\" title=\"4.创建GitHub仓库\"></a>4.创建GitHub仓库</h3><p>建立一个公共仓库,仓库名:<你的 GitHub 用户名>.github.io<br>eg:Dream-verylively.github.io</p>\n<h3 id=\"5-配置并使用Hexo\"><a href=\"#5-配置并使用Hexo\" class=\"headerlink\" title=\"5.配置并使用Hexo\"></a>5.配置并使用Hexo</h3><p>a.配置hexo</p>\n<p>这个步骤将生成blog文件夹,接下来的诸多操作将围绕这个文件夹进行</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ npm install hexo-cli -g //安装 Hexo CLI(命令行工具)到全局环境</span><br><span class=\"line\">$ hexo init blog //始化 Hexo 博客,创建一个名为 <span class=\"string\">"blog"</span> 的目录,并在其中初始化 Hexo(名字可更改)</span><br><span class=\"line\">$ <span class=\"built_in\">cd</span> blog //进入到刚创建的 <span class=\"string\">"blog"</span> 目录中</span><br><span class=\"line\">$ npm install //npm install</span><br><span class=\"line\">$ hexo server //启动 Hexo 服务器,用于本地预览您的博客</span><br></pre></td></tr></table></figure>\n\n<p>More info: <a href=\"https://hexo.io/zh-cn/\">hexo</a></p>\n<p>b.编辑你的 _config.yml</p>\n<p>第一处<br><img src=\"/articles/shuo-liu16/deploy-hexo/1.png\" alt=\"ICON\"><br>第二处<br><img src=\"/articles/shuo-liu16/deploy-hexo/2.png\" alt=\"ICON\"></p>\n<p>c.在博客文件夹下打开终端执行以下命令</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ hexo clean //清理 Hexo 生成的静态文件和缓存</span><br><span class=\"line\">$ hexo g //使用 Hexo 生成静态文件,将 Markdown 格式的文章转换为 HTML 等静态文件</span><br><span class=\"line\">$ hexo deploy //部署生成的静态文件到指定的部署目标(例如 GitHub Pages、FTP 等)</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"GithubPages-404问题\"><a href=\"#GithubPages-404问题\" class=\"headerlink\" title=\"GithubPages 404问题\"></a>GithubPages 404问题</h3><h4 id=\"1、github-仓库名称不匹配\"><a href=\"#1、github-仓库名称不匹配\" class=\"headerlink\" title=\"1、github 仓库名称不匹配\"></a>1、github 仓库名称不匹配</h4><p>在 github 上面创建的仓库名称没有使用自己的 github 账号名称,例如你的 github 账号名称是 zhanghao,而你创建的仓库名称是 suibian.github.io,这样你是无法访问你的博客网站的。</p>\n<h4 id=\"2、配置文件错误\"><a href=\"#2、配置文件错误\" class=\"headerlink\" title=\"2、配置文件错误\"></a>2、配置文件错误</h4><p>在你的本地博客目录下(我创建的名称是 hexo,注意不是 themes 主题目录下的那个配置文件),有个配置文件 _config.yml,注意观察里边的内容是否符合条件。</p>\n<h4 id=\"3、分支错误\"><a href=\"#3、分支错误\" class=\"headerlink\" title=\"3、分支错误\"></a>3、分支错误</h4><p>注意提交的分支要与GitHub仓库中的默认分支一致</p>\n<h4 id=\"4、hexo-依赖不全\"><a href=\"#4、hexo-依赖不全\" class=\"headerlink\" title=\"4、hexo 依赖不全\"></a>4、hexo 依赖不全</h4><p>检查依赖安装是否有不全的情况,可以使用 npm list 命令</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ npm list --depth 0</span><br></pre></td></tr></table></figure>\n\n<p>如果检查有问题,会在控制台提示类似 npm ERR! missing xxxxx。</p>\n<h4 id=\"5-版本不匹配问题(node与hexo)\"><a href=\"#5-版本不匹配问题(node与hexo)\" class=\"headerlink\" title=\"5.版本不匹配问题(node与hexo)\"></a>5.版本不匹配问题(node与hexo)</h4><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">$ node -v //检查两者的版本</span><br><span class=\"line\">$ hexo -v</span><br></pre></td></tr></table></figure>\n\n<p>看这个:<a href=\"https://hexo.io/zh-cn/docs/#Node-js-%E7%89%88%E6%9C%AC%E9%99%90%E5%88%B6\">版本限制</a></p>\n<h6 id=\"写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\"><a href=\"#写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\" class=\"headerlink\" title=\"写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。\"></a>写在最后:这个过程并不是一帆风顺的,很多时候甚至让我痛苦,但最后我坚持下来了,现在想想尽管痛苦,但是成功了,似乎还不错。</h6>"},{"title":"hszSoft 向大家问好","date":"2024-05-27T16:00:00.000Z","update":"2024-05-27T16:00:00.000Z","_content":"\n各位好,这里是 hszSoft,项目 StardustEngine 的参与者之一。\n\n除了程序以外,本人也爱好编曲,并常年混迹于东方圈。\n\n由于工作原因,StardustEngine 的更新进度非常慢,很长时间看不到一个提交,但这个项目是不会鸽的。\n\n因为比较忙,所以一般也很少看到我发言吧...?\n\n本人研究与游戏相关的多个方向,并会总结一些自己的心得在我的博客中 >>> [hszSoft 的博客](https://hszsoft.com) <<<\n\n早期的一些文章因为其内容不够深入,所以没有全部发布上来,对我正在做的事情感兴趣的小伙伴们,欢迎联系我 >>> https://github.com/hszSoft <<<\n\n相信总有一天,hszSoft 的成果能够让你眼前一亮。","source":"_posts/hszSoft/hello.md","raw":"---\ntitle: hszSoft 向大家问好\ndate: 2024-05-28\nupdate: 2024-05-28\npermalink: articles/hszSoft/hello/\ncategories: hszSoft\ntags: [hszSoft]\n---\n\n各位好,这里是 hszSoft,项目 StardustEngine 的参与者之一。\n\n除了程序以外,本人也爱好编曲,并常年混迹于东方圈。\n\n由于工作原因,StardustEngine 的更新进度非常慢,很长时间看不到一个提交,但这个项目是不会鸽的。\n\n因为比较忙,所以一般也很少看到我发言吧...?\n\n本人研究与游戏相关的多个方向,并会总结一些自己的心得在我的博客中 >>> [hszSoft 的博客](https://hszsoft.com) <<<\n\n早期的一些文章因为其内容不够深入,所以没有全部发布上来,对我正在做的事情感兴趣的小伙伴们,欢迎联系我 >>> https://github.com/hszSoft <<<\n\n相信总有一天,hszSoft 的成果能够让你眼前一亮。","slug":"hszSoft/hello","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/hszSoft/hello/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgk001bo8yeemd78tcv","content":"<p>各位好,这里是 hszSoft,项目 StardustEngine 的参与者之一。</p>\n<p>除了程序以外,本人也爱好编曲,并常年混迹于东方圈。</p>\n<p>由于工作原因,StardustEngine 的更新进度非常慢,很长时间看不到一个提交,但这个项目是不会鸽的。</p>\n<p>因为比较忙,所以一般也很少看到我发言吧…?</p>\n<p>本人研究与游戏相关的多个方向,并会总结一些自己的心得在我的博客中 >>> <a href=\"https://hszsoft.com/\">hszSoft 的博客</a> <<<</p>\n<p>早期的一些文章因为其内容不够深入,所以没有全部发布上来,对我正在做的事情感兴趣的小伙伴们,欢迎联系我 >>> <a href=\"https://github.com/hszSoft\">https://github.com/hszSoft</a> <<<</p>\n<p>相信总有一天,hszSoft 的成果能够让你眼前一亮。</p>\n","site":{"data":{}},"excerpt":"","more":"<p>各位好,这里是 hszSoft,项目 StardustEngine 的参与者之一。</p>\n<p>除了程序以外,本人也爱好编曲,并常年混迹于东方圈。</p>\n<p>由于工作原因,StardustEngine 的更新进度非常慢,很长时间看不到一个提交,但这个项目是不会鸽的。</p>\n<p>因为比较忙,所以一般也很少看到我发言吧…?</p>\n<p>本人研究与游戏相关的多个方向,并会总结一些自己的心得在我的博客中 >>> <a href=\"https://hszsoft.com/\">hszSoft 的博客</a> <<<</p>\n<p>早期的一些文章因为其内容不够深入,所以没有全部发布上来,对我正在做的事情感兴趣的小伙伴们,欢迎联系我 >>> <a href=\"https://github.com/hszSoft\">https://github.com/hszSoft</a> <<<</p>\n<p>相信总有一天,hszSoft 的成果能够让你眼前一亮。</p>\n"},{"title":"suang","date":"2024-05-27T16:00:00.000Z","update":"2024-06-03T16:00:00.000Z","_content":"\n这里是suang的自我介绍~\n\n<!-- More -->\n\n# 我是谁?\n\n<div style=\"text-align:center\">\n\n![是谁呢~](articles/suang/Aboutme/who_am_I.png)\n\n</div>\n\n# suang!\n\n<div style=\"text-align:center\">\n\n![是suang!](articles/suang/Aboutme/suang.png)\n\n</div>\n\n我是suang!一个永远都在追求快乐的人!\n一名很菜但正在学习的大一蒟蒻\n\n\n非常感谢大v老师建立这样一个平台\n希望能够在VSpace里和大家一起学习,共同进步啦~\n\n最后非常非常感谢帮助过我的各位,爱你们~","source":"_posts/suang/Aboutme.md","raw":"---\ntitle: suang\ndate: 2024-05-28\nupdate: 2024-06-04\npermalink: articles/suang/Aboutme/\ncategories: suang\ntags: [suang, 自我介绍]\n---\n\n这里是suang的自我介绍~\n\n<!-- More -->\n\n# 我是谁?\n\n<div style=\"text-align:center\">\n\n![是谁呢~](articles/suang/Aboutme/who_am_I.png)\n\n</div>\n\n# suang!\n\n<div style=\"text-align:center\">\n\n![是suang!](articles/suang/Aboutme/suang.png)\n\n</div>\n\n我是suang!一个永远都在追求快乐的人!\n一名很菜但正在学习的大一蒟蒻\n\n\n非常感谢大v老师建立这样一个平台\n希望能够在VSpace里和大家一起学习,共同进步啦~\n\n最后非常非常感谢帮助过我的各位,爱你们~","slug":"suang/Aboutme","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/suang/Aboutme/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgl001do8yeeffv3tdm","content":"<p>这里是suang的自我介绍~</p>\n<span id=\"more\"></span>\n\n<h1 id=\"我是谁?\"><a href=\"#我是谁?\" class=\"headerlink\" title=\"我是谁?\"></a>我是谁?</h1><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/Aboutme/who_am_I.png\" alt=\"是谁呢~\"></p>\n</div>\n\n<h1 id=\"suang!\"><a href=\"#suang!\" class=\"headerlink\" title=\"suang!\"></a>suang!</h1><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/Aboutme/suang.png\" alt=\"是suang!\"></p>\n</div>\n\n<p>我是suang!一个永远都在追求快乐的人!<br>一名很菜但正在学习的大一蒟蒻</p>\n<p>非常感谢大v老师建立这样一个平台<br>希望能够在VSpace里和大家一起学习,共同进步啦~</p>\n<p>最后非常非常感谢帮助过我的各位,爱你们~</p>\n","site":{"data":{}},"excerpt":"<p>这里是suang的自我介绍~</p>","more":"<h1 id=\"我是谁?\"><a href=\"#我是谁?\" class=\"headerlink\" title=\"我是谁?\"></a>我是谁?</h1><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/Aboutme/who_am_I.png\" alt=\"是谁呢~\"></p>\n</div>\n\n<h1 id=\"suang!\"><a href=\"#suang!\" class=\"headerlink\" title=\"suang!\"></a>suang!</h1><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/Aboutme/suang.png\" alt=\"是suang!\"></p>\n</div>\n\n<p>我是suang!一个永远都在追求快乐的人!<br>一名很菜但正在学习的大一蒟蒻</p>\n<p>非常感谢大v老师建立这样一个平台<br>希望能够在VSpace里和大家一起学习,共同进步啦~</p>\n<p>最后非常非常感谢帮助过我的各位,爱你们~</p>"},{"title":"使用EasyX制作游戏需要读写文件时遇到编码问题的解决方法","date":"2024-05-27T16:00:00.000Z","update":"2024-06-03T16:00:00.000Z","_content":"\n痛苦之子suang又遇到了什么问题呢?\n噢!原来是编码问题!\n快来帮他解决吧!\n痛苦之子~~~乔戈亚~~~~~\n\n<!-- More -->\n\n### 一、编码问题\n例如我们需要从file.txt中读取文字,再使用`outtextxy()`函数向窗口绘制文字。\n查找EasyX的官方文档可知,该函数有两个重载,分别为:`void outtextxy(int x, int y, LPCTSTR str)`和`void outtextxy(int x, int y, TCHAR c)`。\n如果我们的file.txt文件使用GBK或者GB2312编码的话,会导致VS编译器混合utf-8编码和GBK编码,导致程序不能正确绘制文字。\n编码问题一直是令人头痛的问题,这里给出通用的方法论,希望能够带来一些帮助。\n\n### 二、解决方法\n\n#### 1. 重新编码txt文件\n\n首先使用vscode打开file.txt文件,确保文件编码为utf-8。\n\n如果不是utf-8编码,点击选择编码,通过编码重新打开,选择utf-8编码,这时原来的内容会变成乱码,将原来的内容删除,重新输入,保存即可。\n\n#### 2. 代码部分\n\n首先,我们需要用到`std::wstring_convert`,这个标准库需要头文件`#include<codecvt>`,我们定义`string str`,用`static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;`定义我们所需要的从utf-8编码的字符串到宽字符串的转换器。\n\n打开文件,读取文件内容到str内,使用`from_bytes(str)`函数即可实现字符串的转换,又由于outtextxy没有使用wstring的重载,使用wstring的成员函数`c_str()`即可转换成`wchar_t`字符串,最终,我们用这样的代码将文字绘制在窗口上`outtextxy(10, 10, converter.from_bytes(str).c_str());`。\n\n完整代码如下:\n\n```cpp\n#include<fstream>\n#include<codecvt>\n#include<string>\n#include<iostream>\n#include<graphics.h>\n\nstd::string str;\n\nint main()\n{\n\tinitgraph(500, 500);\n\n\tstatic std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n\n\tstd::ifstream infile(\"file.txt\");\n\tif (!infile)\n\t{\n\t\tstd::cerr << \"无法打开文件\" << std::endl;\n\t\treturn 0;\n\t}\n\tstd::getline(infile, str);\n\tinfile.close();\n\n\twhile (true)\n\t{\n\t\touttextxy(10, 10, converter.from_bytes(str).c_str());\n\t}\n}\n```\n\n### 三、问题延伸\n\n如果我们需要在程序内使用`InputBox`对话框输入,并将输入的内容正确保存在文件里,该如何操作呢。\n首先查看`InputBox`的参数列表`bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);`,我们关注第一个参数,`InputBox`只接受`&wchar_t`的参数,因此,假设输入的字符串最大长度为256,我们定义`TCHAR buffer[256];`数组来接收输入,写下这样的代码来弹出对话框`InputBox(buffer, 256, _T(\"请输入:\"), _T(\"输入框\"), NULL, 0, 0, TRUE);`打开文件,定义`std::string str;`,仍然使用我们刚才定义的转换器,使用`to_bytes()`函数,即可将输入的内容转换为utf-8字符串。再进行输入即可。\n\n完整代码如下:\n\n```cpp\n#include<fstream>\n#include<codecvt>\n#include<string>\n#include<iostream>\n#include<graphics.h>\n\nint main()\n{\n\tinitgraph(500, 500);\n\n\tstatic std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n\n\tTCHAR buffer[256];\n\tInputBox(buffer, 256, _T(\"请输入:\"), _T(\"输入框\"), NULL, 0, 0, TRUE);\n\n\tstd::ofstream outfile(\"file.txt\");\n\tif (!outfile)\n\t{\n\t\tstd::cerr << \"无法打开文件\" << std::endl;\n\t\treturn 0;\n\t}\n\tstd::string str = converter.to_bytes(buffer);\n\toutfile << str;\n\toutfile.close();\n}\n```\n\n---\n\n说些题外话,suang心事很重,虽然表面看上去什么都不在乎,但是其实内心很脆弱很敏感。\n时常会独自emo,我的朋友跟我说啊,要把不开心的事情说出去,不能憋着。\n其实我是不想憋的,但是我说不出口,或者说我已经不知道怎么去说了,每次难受的时候,就什么都说不出来了,也许发生在我身上的事情真的那么那么复杂,也许只有亲身经历过,才能感同身受,才能知道怎么解开我的心结罢。\n可我没什么文采,写不来文章,又没那么专业,拍不了电影。所以,我想做游戏,在另一个世界里,说我想说但说不出口的,做我想做却没勇气做的,弥补我曾经的遗憾。也许这样,我就真的释然了。\n\n---\n\n做游戏的想法埋下了,我却一直都没去做,一是我确实没什么实力,二是我并不知道如何开始,直到我发现了大V老师......\n\n我真的没想到,大V老师能帮我远程解决问题,当时真的震惊到我了,我跟我的室友炫耀了好久,我真的没想到,在那些卖课的占据b站首页大部分的今天,还有大V老师这样的一股清流。来到群里之后我发现,真的有乐于分享,愿意帮助我的人,suang真的真的很感动。\n","source":"_posts/suang/EasyX_code.md","raw":"---\ntitle: 使用EasyX制作游戏需要读写文件时遇到编码问题的解决方法\ndate: 2024-05-28\nupdate: 2024-06-04\npermalink: articles/suang/EasyX_code/\ncategories: suang\ntags: [c++, 编码, EasyX]\n---\n\n痛苦之子suang又遇到了什么问题呢?\n噢!原来是编码问题!\n快来帮他解决吧!\n痛苦之子~~~乔戈亚~~~~~\n\n<!-- More -->\n\n### 一、编码问题\n例如我们需要从file.txt中读取文字,再使用`outtextxy()`函数向窗口绘制文字。\n查找EasyX的官方文档可知,该函数有两个重载,分别为:`void outtextxy(int x, int y, LPCTSTR str)`和`void outtextxy(int x, int y, TCHAR c)`。\n如果我们的file.txt文件使用GBK或者GB2312编码的话,会导致VS编译器混合utf-8编码和GBK编码,导致程序不能正确绘制文字。\n编码问题一直是令人头痛的问题,这里给出通用的方法论,希望能够带来一些帮助。\n\n### 二、解决方法\n\n#### 1. 重新编码txt文件\n\n首先使用vscode打开file.txt文件,确保文件编码为utf-8。\n\n如果不是utf-8编码,点击选择编码,通过编码重新打开,选择utf-8编码,这时原来的内容会变成乱码,将原来的内容删除,重新输入,保存即可。\n\n#### 2. 代码部分\n\n首先,我们需要用到`std::wstring_convert`,这个标准库需要头文件`#include<codecvt>`,我们定义`string str`,用`static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;`定义我们所需要的从utf-8编码的字符串到宽字符串的转换器。\n\n打开文件,读取文件内容到str内,使用`from_bytes(str)`函数即可实现字符串的转换,又由于outtextxy没有使用wstring的重载,使用wstring的成员函数`c_str()`即可转换成`wchar_t`字符串,最终,我们用这样的代码将文字绘制在窗口上`outtextxy(10, 10, converter.from_bytes(str).c_str());`。\n\n完整代码如下:\n\n```cpp\n#include<fstream>\n#include<codecvt>\n#include<string>\n#include<iostream>\n#include<graphics.h>\n\nstd::string str;\n\nint main()\n{\n\tinitgraph(500, 500);\n\n\tstatic std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n\n\tstd::ifstream infile(\"file.txt\");\n\tif (!infile)\n\t{\n\t\tstd::cerr << \"无法打开文件\" << std::endl;\n\t\treturn 0;\n\t}\n\tstd::getline(infile, str);\n\tinfile.close();\n\n\twhile (true)\n\t{\n\t\touttextxy(10, 10, converter.from_bytes(str).c_str());\n\t}\n}\n```\n\n### 三、问题延伸\n\n如果我们需要在程序内使用`InputBox`对话框输入,并将输入的内容正确保存在文件里,该如何操作呢。\n首先查看`InputBox`的参数列表`bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);`,我们关注第一个参数,`InputBox`只接受`&wchar_t`的参数,因此,假设输入的字符串最大长度为256,我们定义`TCHAR buffer[256];`数组来接收输入,写下这样的代码来弹出对话框`InputBox(buffer, 256, _T(\"请输入:\"), _T(\"输入框\"), NULL, 0, 0, TRUE);`打开文件,定义`std::string str;`,仍然使用我们刚才定义的转换器,使用`to_bytes()`函数,即可将输入的内容转换为utf-8字符串。再进行输入即可。\n\n完整代码如下:\n\n```cpp\n#include<fstream>\n#include<codecvt>\n#include<string>\n#include<iostream>\n#include<graphics.h>\n\nint main()\n{\n\tinitgraph(500, 500);\n\n\tstatic std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\n\n\tTCHAR buffer[256];\n\tInputBox(buffer, 256, _T(\"请输入:\"), _T(\"输入框\"), NULL, 0, 0, TRUE);\n\n\tstd::ofstream outfile(\"file.txt\");\n\tif (!outfile)\n\t{\n\t\tstd::cerr << \"无法打开文件\" << std::endl;\n\t\treturn 0;\n\t}\n\tstd::string str = converter.to_bytes(buffer);\n\toutfile << str;\n\toutfile.close();\n}\n```\n\n---\n\n说些题外话,suang心事很重,虽然表面看上去什么都不在乎,但是其实内心很脆弱很敏感。\n时常会独自emo,我的朋友跟我说啊,要把不开心的事情说出去,不能憋着。\n其实我是不想憋的,但是我说不出口,或者说我已经不知道怎么去说了,每次难受的时候,就什么都说不出来了,也许发生在我身上的事情真的那么那么复杂,也许只有亲身经历过,才能感同身受,才能知道怎么解开我的心结罢。\n可我没什么文采,写不来文章,又没那么专业,拍不了电影。所以,我想做游戏,在另一个世界里,说我想说但说不出口的,做我想做却没勇气做的,弥补我曾经的遗憾。也许这样,我就真的释然了。\n\n---\n\n做游戏的想法埋下了,我却一直都没去做,一是我确实没什么实力,二是我并不知道如何开始,直到我发现了大V老师......\n\n我真的没想到,大V老师能帮我远程解决问题,当时真的震惊到我了,我跟我的室友炫耀了好久,我真的没想到,在那些卖课的占据b站首页大部分的今天,还有大V老师这样的一股清流。来到群里之后我发现,真的有乐于分享,愿意帮助我的人,suang真的真的很感动。\n","slug":"suang/EasyX_code","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/suang/EasyX_code/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgm001io8ye5rbnald2","content":"<p>痛苦之子suang又遇到了什么问题呢?<br>噢!原来是编码问题!<br>快来帮他解决吧!<br>痛苦之子~~~乔戈亚~~~~~</p>\n<span id=\"more\"></span>\n\n<h3 id=\"一、编码问题\"><a href=\"#一、编码问题\" class=\"headerlink\" title=\"一、编码问题\"></a>一、编码问题</h3><p>例如我们需要从file.txt中读取文字,再使用<code>outtextxy()</code>函数向窗口绘制文字。<br>查找EasyX的官方文档可知,该函数有两个重载,分别为:<code>void outtextxy(int x, int y, LPCTSTR str)</code>和<code>void outtextxy(int x, int y, TCHAR c)</code>。<br>如果我们的file.txt文件使用GBK或者GB2312编码的话,会导致VS编译器混合utf-8编码和GBK编码,导致程序不能正确绘制文字。<br>编码问题一直是令人头痛的问题,这里给出通用的方法论,希望能够带来一些帮助。</p>\n<h3 id=\"二、解决方法\"><a href=\"#二、解决方法\" class=\"headerlink\" title=\"二、解决方法\"></a>二、解决方法</h3><h4 id=\"1-重新编码txt文件\"><a href=\"#1-重新编码txt文件\" class=\"headerlink\" title=\"1. 重新编码txt文件\"></a>1. 重新编码txt文件</h4><p>首先使用vscode打开file.txt文件,确保文件编码为utf-8。</p>\n<p>如果不是utf-8编码,点击选择编码,通过编码重新打开,选择utf-8编码,这时原来的内容会变成乱码,将原来的内容删除,重新输入,保存即可。</p>\n<h4 id=\"2-代码部分\"><a href=\"#2-代码部分\" class=\"headerlink\" title=\"2. 代码部分\"></a>2. 代码部分</h4><p>首先,我们需要用到<code>std::wstring_convert</code>,这个标准库需要头文件<code>#include<codecvt></code>,我们定义<code>string str</code>,用<code>static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;</code>定义我们所需要的从utf-8编码的字符串到宽字符串的转换器。</p>\n<p>打开文件,读取文件内容到str内,使用<code>from_bytes(str)</code>函数即可实现字符串的转换,又由于outtextxy没有使用wstring的重载,使用wstring的成员函数<code>c_str()</code>即可转换成<code>wchar_t</code>字符串,最终,我们用这样的代码将文字绘制在窗口上<code>outtextxy(10, 10, converter.from_bytes(str).c_str());</code>。</p>\n<p>完整代码如下:</p>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><fstream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><codecvt></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><string></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\">std::string str;</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"built_in\">initgraph</span>(<span class=\"number\">500</span>, <span class=\"number\">500</span>);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"type\">static</span> std::wstring_convert<std::codecvt_utf8<<span class=\"type\">wchar_t</span>>, <span class=\"type\">wchar_t</span>> converter;</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"function\">std::ifstream <span class=\"title\">infile</span><span class=\"params\">(<span class=\"string\">"file.txt"</span>)</span></span>;</span><br><span class=\"line\">\t<span class=\"keyword\">if</span> (!infile)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\tstd::cerr << <span class=\"string\">"无法打开文件"</span> << std::endl;</span><br><span class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">\t}</span><br><span class=\"line\">\tstd::<span class=\"built_in\">getline</span>(infile, str);</span><br><span class=\"line\">\tinfile.<span class=\"built_in\">close</span>();</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"keyword\">while</span> (<span class=\"literal\">true</span>)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\t<span class=\"built_in\">outtextxy</span>(<span class=\"number\">10</span>, <span class=\"number\">10</span>, converter.<span class=\"built_in\">from_bytes</span>(str).<span class=\"built_in\">c_str</span>());</span><br><span class=\"line\">\t}</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"三、问题延伸\"><a href=\"#三、问题延伸\" class=\"headerlink\" title=\"三、问题延伸\"></a>三、问题延伸</h3><p>如果我们需要在程序内使用<code>InputBox</code>对话框输入,并将输入的内容正确保存在文件里,该如何操作呢。<br>首先查看<code>InputBox</code>的参数列表<code>bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);</code>,我们关注第一个参数,<code>InputBox</code>只接受<code>&wchar_t</code>的参数,因此,假设输入的字符串最大长度为256,我们定义<code>TCHAR buffer[256];</code>数组来接收输入,写下这样的代码来弹出对话框<code>InputBox(buffer, 256, _T("请输入:"), _T("输入框"), NULL, 0, 0, TRUE);</code>打开文件,定义<code>std::string str;</code>,仍然使用我们刚才定义的转换器,使用<code>to_bytes()</code>函数,即可将输入的内容转换为utf-8字符串。再进行输入即可。</p>\n<p>完整代码如下:</p>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><fstream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><codecvt></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><string></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"built_in\">initgraph</span>(<span class=\"number\">500</span>, <span class=\"number\">500</span>);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"type\">static</span> std::wstring_convert<std::codecvt_utf8<<span class=\"type\">wchar_t</span>>, <span class=\"type\">wchar_t</span>> converter;</span><br><span class=\"line\"></span><br><span class=\"line\">\tTCHAR buffer[<span class=\"number\">256</span>];</span><br><span class=\"line\">\t<span class=\"built_in\">InputBox</span>(buffer, <span class=\"number\">256</span>, _T(<span class=\"string\">"请输入:"</span>), _T(<span class=\"string\">"输入框"</span>), <span class=\"literal\">NULL</span>, <span class=\"number\">0</span>, <span class=\"number\">0</span>, TRUE);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"function\">std::ofstream <span class=\"title\">outfile</span><span class=\"params\">(<span class=\"string\">"file.txt"</span>)</span></span>;</span><br><span class=\"line\">\t<span class=\"keyword\">if</span> (!outfile)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\tstd::cerr << <span class=\"string\">"无法打开文件"</span> << std::endl;</span><br><span class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">\t}</span><br><span class=\"line\">\tstd::string str = converter.<span class=\"built_in\">to_bytes</span>(buffer);</span><br><span class=\"line\">\toutfile << str;</span><br><span class=\"line\">\toutfile.<span class=\"built_in\">close</span>();</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<hr>\n<p>说些题外话,suang心事很重,虽然表面看上去什么都不在乎,但是其实内心很脆弱很敏感。<br>时常会独自emo,我的朋友跟我说啊,要把不开心的事情说出去,不能憋着。<br>其实我是不想憋的,但是我说不出口,或者说我已经不知道怎么去说了,每次难受的时候,就什么都说不出来了,也许发生在我身上的事情真的那么那么复杂,也许只有亲身经历过,才能感同身受,才能知道怎么解开我的心结罢。<br>可我没什么文采,写不来文章,又没那么专业,拍不了电影。所以,我想做游戏,在另一个世界里,说我想说但说不出口的,做我想做却没勇气做的,弥补我曾经的遗憾。也许这样,我就真的释然了。</p>\n<hr>\n<p>做游戏的想法埋下了,我却一直都没去做,一是我确实没什么实力,二是我并不知道如何开始,直到我发现了大V老师……</p>\n<p>我真的没想到,大V老师能帮我远程解决问题,当时真的震惊到我了,我跟我的室友炫耀了好久,我真的没想到,在那些卖课的占据b站首页大部分的今天,还有大V老师这样的一股清流。来到群里之后我发现,真的有乐于分享,愿意帮助我的人,suang真的真的很感动。</p>\n","site":{"data":{}},"excerpt":"<p>痛苦之子suang又遇到了什么问题呢?<br>噢!原来是编码问题!<br>快来帮他解决吧!<br>痛苦之子~~~乔戈亚~~~~~</p>","more":"<h3 id=\"一、编码问题\"><a href=\"#一、编码问题\" class=\"headerlink\" title=\"一、编码问题\"></a>一、编码问题</h3><p>例如我们需要从file.txt中读取文字,再使用<code>outtextxy()</code>函数向窗口绘制文字。<br>查找EasyX的官方文档可知,该函数有两个重载,分别为:<code>void outtextxy(int x, int y, LPCTSTR str)</code>和<code>void outtextxy(int x, int y, TCHAR c)</code>。<br>如果我们的file.txt文件使用GBK或者GB2312编码的话,会导致VS编译器混合utf-8编码和GBK编码,导致程序不能正确绘制文字。<br>编码问题一直是令人头痛的问题,这里给出通用的方法论,希望能够带来一些帮助。</p>\n<h3 id=\"二、解决方法\"><a href=\"#二、解决方法\" class=\"headerlink\" title=\"二、解决方法\"></a>二、解决方法</h3><h4 id=\"1-重新编码txt文件\"><a href=\"#1-重新编码txt文件\" class=\"headerlink\" title=\"1. 重新编码txt文件\"></a>1. 重新编码txt文件</h4><p>首先使用vscode打开file.txt文件,确保文件编码为utf-8。</p>\n<p>如果不是utf-8编码,点击选择编码,通过编码重新打开,选择utf-8编码,这时原来的内容会变成乱码,将原来的内容删除,重新输入,保存即可。</p>\n<h4 id=\"2-代码部分\"><a href=\"#2-代码部分\" class=\"headerlink\" title=\"2. 代码部分\"></a>2. 代码部分</h4><p>首先,我们需要用到<code>std::wstring_convert</code>,这个标准库需要头文件<code>#include<codecvt></code>,我们定义<code>string str</code>,用<code>static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;</code>定义我们所需要的从utf-8编码的字符串到宽字符串的转换器。</p>\n<p>打开文件,读取文件内容到str内,使用<code>from_bytes(str)</code>函数即可实现字符串的转换,又由于outtextxy没有使用wstring的重载,使用wstring的成员函数<code>c_str()</code>即可转换成<code>wchar_t</code>字符串,最终,我们用这样的代码将文字绘制在窗口上<code>outtextxy(10, 10, converter.from_bytes(str).c_str());</code>。</p>\n<p>完整代码如下:</p>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><fstream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><codecvt></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><string></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\">std::string str;</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"built_in\">initgraph</span>(<span class=\"number\">500</span>, <span class=\"number\">500</span>);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"type\">static</span> std::wstring_convert<std::codecvt_utf8<<span class=\"type\">wchar_t</span>>, <span class=\"type\">wchar_t</span>> converter;</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"function\">std::ifstream <span class=\"title\">infile</span><span class=\"params\">(<span class=\"string\">"file.txt"</span>)</span></span>;</span><br><span class=\"line\">\t<span class=\"keyword\">if</span> (!infile)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\tstd::cerr << <span class=\"string\">"无法打开文件"</span> << std::endl;</span><br><span class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">\t}</span><br><span class=\"line\">\tstd::<span class=\"built_in\">getline</span>(infile, str);</span><br><span class=\"line\">\tinfile.<span class=\"built_in\">close</span>();</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"keyword\">while</span> (<span class=\"literal\">true</span>)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\t<span class=\"built_in\">outtextxy</span>(<span class=\"number\">10</span>, <span class=\"number\">10</span>, converter.<span class=\"built_in\">from_bytes</span>(str).<span class=\"built_in\">c_str</span>());</span><br><span class=\"line\">\t}</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"三、问题延伸\"><a href=\"#三、问题延伸\" class=\"headerlink\" title=\"三、问题延伸\"></a>三、问题延伸</h3><p>如果我们需要在程序内使用<code>InputBox</code>对话框输入,并将输入的内容正确保存在文件里,该如何操作呢。<br>首先查看<code>InputBox</code>的参数列表<code>bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);</code>,我们关注第一个参数,<code>InputBox</code>只接受<code>&wchar_t</code>的参数,因此,假设输入的字符串最大长度为256,我们定义<code>TCHAR buffer[256];</code>数组来接收输入,写下这样的代码来弹出对话框<code>InputBox(buffer, 256, _T("请输入:"), _T("输入框"), NULL, 0, 0, TRUE);</code>打开文件,定义<code>std::string str;</code>,仍然使用我们刚才定义的转换器,使用<code>to_bytes()</code>函数,即可将输入的内容转换为utf-8字符串。再进行输入即可。</p>\n<p>完整代码如下:</p>\n<figure class=\"highlight cpp\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><fstream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><codecvt></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><string></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><iostream></span></span></span><br><span class=\"line\"><span class=\"meta\">#<span class=\"keyword\">include</span><span class=\"string\"><graphics.h></span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"type\">int</span> <span class=\"title\">main</span><span class=\"params\">()</span></span></span><br><span class=\"line\"><span class=\"function\"></span>{</span><br><span class=\"line\">\t<span class=\"built_in\">initgraph</span>(<span class=\"number\">500</span>, <span class=\"number\">500</span>);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"type\">static</span> std::wstring_convert<std::codecvt_utf8<<span class=\"type\">wchar_t</span>>, <span class=\"type\">wchar_t</span>> converter;</span><br><span class=\"line\"></span><br><span class=\"line\">\tTCHAR buffer[<span class=\"number\">256</span>];</span><br><span class=\"line\">\t<span class=\"built_in\">InputBox</span>(buffer, <span class=\"number\">256</span>, _T(<span class=\"string\">"请输入:"</span>), _T(<span class=\"string\">"输入框"</span>), <span class=\"literal\">NULL</span>, <span class=\"number\">0</span>, <span class=\"number\">0</span>, TRUE);</span><br><span class=\"line\"></span><br><span class=\"line\">\t<span class=\"function\">std::ofstream <span class=\"title\">outfile</span><span class=\"params\">(<span class=\"string\">"file.txt"</span>)</span></span>;</span><br><span class=\"line\">\t<span class=\"keyword\">if</span> (!outfile)</span><br><span class=\"line\">\t{</span><br><span class=\"line\">\t\tstd::cerr << <span class=\"string\">"无法打开文件"</span> << std::endl;</span><br><span class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"number\">0</span>;</span><br><span class=\"line\">\t}</span><br><span class=\"line\">\tstd::string str = converter.<span class=\"built_in\">to_bytes</span>(buffer);</span><br><span class=\"line\">\toutfile << str;</span><br><span class=\"line\">\toutfile.<span class=\"built_in\">close</span>();</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<hr>\n<p>说些题外话,suang心事很重,虽然表面看上去什么都不在乎,但是其实内心很脆弱很敏感。<br>时常会独自emo,我的朋友跟我说啊,要把不开心的事情说出去,不能憋着。<br>其实我是不想憋的,但是我说不出口,或者说我已经不知道怎么去说了,每次难受的时候,就什么都说不出来了,也许发生在我身上的事情真的那么那么复杂,也许只有亲身经历过,才能感同身受,才能知道怎么解开我的心结罢。<br>可我没什么文采,写不来文章,又没那么专业,拍不了电影。所以,我想做游戏,在另一个世界里,说我想说但说不出口的,做我想做却没勇气做的,弥补我曾经的遗憾。也许这样,我就真的释然了。</p>\n<hr>\n<p>做游戏的想法埋下了,我却一直都没去做,一是我确实没什么实力,二是我并不知道如何开始,直到我发现了大V老师……</p>\n<p>我真的没想到,大V老师能帮我远程解决问题,当时真的震惊到我了,我跟我的室友炫耀了好久,我真的没想到,在那些卖课的占据b站首页大部分的今天,还有大V老师这样的一股清流。来到群里之后我发现,真的有乐于分享,愿意帮助我的人,suang真的真的很感动。</p>"},{"title":"使用GitHub Desktop在论坛中发表文章的方法及注意事项","date":"2024-05-27T16:00:00.000Z","update":"2024-06-03T16:00:00.000Z","_content":"\n**suang教你用GitHub Desktop发表文章!**\n**超级简单!超级详细!超级耐心!**\n**一定要看!一看就会!**\n\n<!-- More -->\n\n### 一、提交文章的流程\n\n#### 1. 安装以下工具\n\n- **GitHub Desktop**\n- **VSCode**\n\n#### 2. 将GitHub库中的资源clone到本地\n\n进入 **VoidGameSpace** 论坛的 **GitHub** 库网站,点击 `< > Code` ,选择`Open with GitHub Desktop`将资源克隆到本地。\n\n#### 3. 使用VSCode打开库中资源并进行编辑\n\n切换到 **GitHub Desktop** ,点击 `Open in Visual Studio Code` 即可在 **VSCode** 中进行编辑。\n在左侧资源管理器中打开目录 `/GAMEDEVWEBSITE/source/_posts` 在这个目录下新建一个独立的、专属于自己的文件夹。\n在自己的文件夹中新建 `markdown` 文件,编辑完成保存后返回 **GitHub Desktop** 。 \n\n#### 4. 提交本地代码,将本地所做的更改同步到远程代码库\n\n返回 **GitHub Desktop** 后,会自动跳转到 `Changes` 界面,确认代码无误后,点击 `Commit to main` 进行提交,再点击 `Push origin` 将更改同步到远程代码库。\n\n#### 5. 进入自己的fork,拉取合并更改的请求\n\n回到 **GitHub** 中并刷新网页,此时,一定要在自己fork的文件中!!!\n按照下图方式点击,进入自己的fork,才能进行之后的操作。\n\n<div style=\"text-align:center\">\n\n![xdm一定要记得fork啊,不然我白教了](articles/suang/publish_article/fork_img.png)\n\n</div>\n\n接下来点击 `Pull requests` ,再点击 `New pull request` 拉取合并更改的请求。最后点击 `Create pull request` 生成请求。\n\n#### 6. 等待Vercel部署和大V老师的审核\n\n完成了这一步,恭喜你已经成功将你的文章提交了,接下来就是耐心地等待你的文章通过审核了。\n不过别急着高兴,关于 `markdown` 文件,还有一些注意事项。\n\n### 二、关于markdown文件\n\n#### 1. markdown文件的写法\n\nmarkdown的语法很简单,可以参考 [Markdown 官方教程](https://markdown.com.cn/basic-syntax/) 来进行查找和学习。\n\n#### 2. 注意事项\n\n***敲重点!!!!!***\n\n- **元数据一定不能少!** **元数据一定不能少!** **元数据一定不能少!**\n\n重要的事情说一万遍!\n\n元数据是用两个`---`分割线包围的数据,记录你的文章的**标题**、**上传时间**,**修改时间**、**永久链接**、**目录**、**标签** 这些信息,缺少了元数据的文章无法通过审核。写法如下:\n\n```md\n---\ntitle: 使用GitHub Desktop在论坛中发表文章的方法及注意事项\ndate: 2024-05-28\nupdate: 2024-05-29\npermalink: articles/suang/publish_article/\ncategories: suang\ntags: [suang, 教程, 发表文章]\n---\n```\n- 其中,`permalink` 项要填写 `article/你的专属目录/子目录(可选)/`\n\n虽然子目录是可选项,但是,你也不想把所有的文章都丢在同一个文件夹下吧。真的不要这样做啊!!!\n\n- 元数据中有 `title` 属性不需要写一级标题\n\n- 最好使用 `<!-- More -->` 注释添加概述否则主页文章会全部展开显得很长\n\n### 三、关于图片的插入\n\n#### 1. 导入图片资源\n\n<div style=\"text-align:center\">\n\n![图片在哪里呀?](articles/suang/publish_article/image_pos.png)\n\n</div>\n\n首先,将你所需要的图片资源导入到你的专属文件夹中,然后就可以修改markdown文件啦~\n\n像这样\n```md\n<div style=\"text-align:center\">\n\n![图片在哪里呀?](articles/suang/publish_article/image_pos.png)\n\n</div>\n```\n\n括号里面写上你的图片的相对路径就可以将图片导入啦!\n\n---\n\n真的是保姆级了,正常来说照着我的教程一步一步来应该不会出问题了。\n如果遇到了问题记得在群里@我\n\n**Yeah~**\n","source":"_posts/suang/publish_article.md","raw":"---\ntitle: 使用GitHub Desktop在论坛中发表文章的方法及注意事项\ndate: 2024-05-28\nupdate: 2024-06-04\npermalink: articles/suang/publish_article/\ncategories: suang\ntags: [suang, 教程, 发表文章]\n---\n\n**suang教你用GitHub Desktop发表文章!**\n**超级简单!超级详细!超级耐心!**\n**一定要看!一看就会!**\n\n<!-- More -->\n\n### 一、提交文章的流程\n\n#### 1. 安装以下工具\n\n- **GitHub Desktop**\n- **VSCode**\n\n#### 2. 将GitHub库中的资源clone到本地\n\n进入 **VoidGameSpace** 论坛的 **GitHub** 库网站,点击 `< > Code` ,选择`Open with GitHub Desktop`将资源克隆到本地。\n\n#### 3. 使用VSCode打开库中资源并进行编辑\n\n切换到 **GitHub Desktop** ,点击 `Open in Visual Studio Code` 即可在 **VSCode** 中进行编辑。\n在左侧资源管理器中打开目录 `/GAMEDEVWEBSITE/source/_posts` 在这个目录下新建一个独立的、专属于自己的文件夹。\n在自己的文件夹中新建 `markdown` 文件,编辑完成保存后返回 **GitHub Desktop** 。 \n\n#### 4. 提交本地代码,将本地所做的更改同步到远程代码库\n\n返回 **GitHub Desktop** 后,会自动跳转到 `Changes` 界面,确认代码无误后,点击 `Commit to main` 进行提交,再点击 `Push origin` 将更改同步到远程代码库。\n\n#### 5. 进入自己的fork,拉取合并更改的请求\n\n回到 **GitHub** 中并刷新网页,此时,一定要在自己fork的文件中!!!\n按照下图方式点击,进入自己的fork,才能进行之后的操作。\n\n<div style=\"text-align:center\">\n\n![xdm一定要记得fork啊,不然我白教了](articles/suang/publish_article/fork_img.png)\n\n</div>\n\n接下来点击 `Pull requests` ,再点击 `New pull request` 拉取合并更改的请求。最后点击 `Create pull request` 生成请求。\n\n#### 6. 等待Vercel部署和大V老师的审核\n\n完成了这一步,恭喜你已经成功将你的文章提交了,接下来就是耐心地等待你的文章通过审核了。\n不过别急着高兴,关于 `markdown` 文件,还有一些注意事项。\n\n### 二、关于markdown文件\n\n#### 1. markdown文件的写法\n\nmarkdown的语法很简单,可以参考 [Markdown 官方教程](https://markdown.com.cn/basic-syntax/) 来进行查找和学习。\n\n#### 2. 注意事项\n\n***敲重点!!!!!***\n\n- **元数据一定不能少!** **元数据一定不能少!** **元数据一定不能少!**\n\n重要的事情说一万遍!\n\n元数据是用两个`---`分割线包围的数据,记录你的文章的**标题**、**上传时间**,**修改时间**、**永久链接**、**目录**、**标签** 这些信息,缺少了元数据的文章无法通过审核。写法如下:\n\n```md\n---\ntitle: 使用GitHub Desktop在论坛中发表文章的方法及注意事项\ndate: 2024-05-28\nupdate: 2024-05-29\npermalink: articles/suang/publish_article/\ncategories: suang\ntags: [suang, 教程, 发表文章]\n---\n```\n- 其中,`permalink` 项要填写 `article/你的专属目录/子目录(可选)/`\n\n虽然子目录是可选项,但是,你也不想把所有的文章都丢在同一个文件夹下吧。真的不要这样做啊!!!\n\n- 元数据中有 `title` 属性不需要写一级标题\n\n- 最好使用 `<!-- More -->` 注释添加概述否则主页文章会全部展开显得很长\n\n### 三、关于图片的插入\n\n#### 1. 导入图片资源\n\n<div style=\"text-align:center\">\n\n![图片在哪里呀?](articles/suang/publish_article/image_pos.png)\n\n</div>\n\n首先,将你所需要的图片资源导入到你的专属文件夹中,然后就可以修改markdown文件啦~\n\n像这样\n```md\n<div style=\"text-align:center\">\n\n![图片在哪里呀?](articles/suang/publish_article/image_pos.png)\n\n</div>\n```\n\n括号里面写上你的图片的相对路径就可以将图片导入啦!\n\n---\n\n真的是保姆级了,正常来说照着我的教程一步一步来应该不会出问题了。\n如果遇到了问题记得在群里@我\n\n**Yeah~**\n","slug":"suang/publish_article","published":1,"updated":"2024-06-10T07:14:15.609Z","__permalink":"articles/suang/publish_article/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgm001jo8ye2klu8hcu","content":"<p><strong>suang教你用GitHub Desktop发表文章!</strong><br><strong>超级简单!超级详细!超级耐心!</strong><br><strong>一定要看!一看就会!</strong></p>\n<span id=\"more\"></span>\n\n<h3 id=\"一、提交文章的流程\"><a href=\"#一、提交文章的流程\" class=\"headerlink\" title=\"一、提交文章的流程\"></a>一、提交文章的流程</h3><h4 id=\"1-安装以下工具\"><a href=\"#1-安装以下工具\" class=\"headerlink\" title=\"1. 安装以下工具\"></a>1. 安装以下工具</h4><ul>\n<li><strong>GitHub Desktop</strong></li>\n<li><strong>VSCode</strong></li>\n</ul>\n<h4 id=\"2-将GitHub库中的资源clone到本地\"><a href=\"#2-将GitHub库中的资源clone到本地\" class=\"headerlink\" title=\"2. 将GitHub库中的资源clone到本地\"></a>2. 将GitHub库中的资源clone到本地</h4><p>进入 <strong>VoidGameSpace</strong> 论坛的 <strong>GitHub</strong> 库网站,点击 <code>< > Code</code> ,选择<code>Open with GitHub Desktop</code>将资源克隆到本地。</p>\n<h4 id=\"3-使用VSCode打开库中资源并进行编辑\"><a href=\"#3-使用VSCode打开库中资源并进行编辑\" class=\"headerlink\" title=\"3. 使用VSCode打开库中资源并进行编辑\"></a>3. 使用VSCode打开库中资源并进行编辑</h4><p>切换到 <strong>GitHub Desktop</strong> ,点击 <code>Open in Visual Studio Code</code> 即可在 <strong>VSCode</strong> 中进行编辑。<br>在左侧资源管理器中打开目录 <code>/GAMEDEVWEBSITE/source/_posts</code> 在这个目录下新建一个独立的、专属于自己的文件夹。<br>在自己的文件夹中新建 <code>markdown</code> 文件,编辑完成保存后返回 <strong>GitHub Desktop</strong> 。 </p>\n<h4 id=\"4-提交本地代码,将本地所做的更改同步到远程代码库\"><a href=\"#4-提交本地代码,将本地所做的更改同步到远程代码库\" class=\"headerlink\" title=\"4. 提交本地代码,将本地所做的更改同步到远程代码库\"></a>4. 提交本地代码,将本地所做的更改同步到远程代码库</h4><p>返回 <strong>GitHub Desktop</strong> 后,会自动跳转到 <code>Changes</code> 界面,确认代码无误后,点击 <code>Commit to main</code> 进行提交,再点击 <code>Push origin</code> 将更改同步到远程代码库。</p>\n<h4 id=\"5-进入自己的fork,拉取合并更改的请求\"><a href=\"#5-进入自己的fork,拉取合并更改的请求\" class=\"headerlink\" title=\"5. 进入自己的fork,拉取合并更改的请求\"></a>5. 进入自己的fork,拉取合并更改的请求</h4><p>回到 <strong>GitHub</strong> 中并刷新网页,此时,一定要在自己fork的文件中!!!<br>按照下图方式点击,进入自己的fork,才能进行之后的操作。</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/publish_article/fork_img.png\" alt=\"xdm一定要记得fork啊,不然我白教了\"></p>\n</div>\n\n<p>接下来点击 <code>Pull requests</code> ,再点击 <code>New pull request</code> 拉取合并更改的请求。最后点击 <code>Create pull request</code> 生成请求。</p>\n<h4 id=\"6-等待Vercel部署和大V老师的审核\"><a href=\"#6-等待Vercel部署和大V老师的审核\" class=\"headerlink\" title=\"6. 等待Vercel部署和大V老师的审核\"></a>6. 等待Vercel部署和大V老师的审核</h4><p>完成了这一步,恭喜你已经成功将你的文章提交了,接下来就是耐心地等待你的文章通过审核了。<br>不过别急着高兴,关于 <code>markdown</code> 文件,还有一些注意事项。</p>\n<h3 id=\"二、关于markdown文件\"><a href=\"#二、关于markdown文件\" class=\"headerlink\" title=\"二、关于markdown文件\"></a>二、关于markdown文件</h3><h4 id=\"1-markdown文件的写法\"><a href=\"#1-markdown文件的写法\" class=\"headerlink\" title=\"1. markdown文件的写法\"></a>1. markdown文件的写法</h4><p>markdown的语法很简单,可以参考 <a href=\"https://markdown.com.cn/basic-syntax/\">Markdown 官方教程</a> 来进行查找和学习。</p>\n<h4 id=\"2-注意事项\"><a href=\"#2-注意事项\" class=\"headerlink\" title=\"2. 注意事项\"></a>2. 注意事项</h4><p><em><strong>敲重点!!!!!</strong></em></p>\n<ul>\n<li><strong>元数据一定不能少!</strong> <strong>元数据一定不能少!</strong> <strong>元数据一定不能少!</strong></li>\n</ul>\n<p>重要的事情说一万遍!</p>\n<p>元数据是用两个<code>---</code>分割线包围的数据,记录你的文章的<strong>标题</strong>、<strong>上传时间</strong>,<strong>修改时间</strong>、<strong>永久链接</strong>、<strong>目录</strong>、<strong>标签</strong> 这些信息,缺少了元数据的文章无法通过审核。写法如下:</p>\n<figure class=\"highlight md\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">---</span><br><span class=\"line\">title: 使用GitHub Desktop在论坛中发表文章的方法及注意事项</span><br><span class=\"line\">date: 2024-05-28</span><br><span class=\"line\">update: 2024-05-29</span><br><span class=\"line\">permalink: articles/suang/publish<span class=\"emphasis\">_article/</span></span><br><span class=\"line\"><span class=\"emphasis\">categories: suang</span></span><br><span class=\"line\"><span class=\"emphasis\">tags: [suang, 教程, 发表文章]</span></span><br><span class=\"line\"><span class=\"emphasis\">---</span></span><br></pre></td></tr></table></figure>\n<ul>\n<li>其中,<code>permalink</code> 项要填写 <code>article/你的专属目录/子目录(可选)/</code></li>\n</ul>\n<p>虽然子目录是可选项,但是,你也不想把所有的文章都丢在同一个文件夹下吧。真的不要这样做啊!!!</p>\n<ul>\n<li><p>元数据中有 <code>title</code> 属性不需要写一级标题</p>\n</li>\n<li><p>最好使用 <code><!-- More --></code> 注释添加概述否则主页文章会全部展开显得很长</p>\n</li>\n</ul>\n<h3 id=\"三、关于图片的插入\"><a href=\"#三、关于图片的插入\" class=\"headerlink\" title=\"三、关于图片的插入\"></a>三、关于图片的插入</h3><h4 id=\"1-导入图片资源\"><a href=\"#1-导入图片资源\" class=\"headerlink\" title=\"1. 导入图片资源\"></a>1. 导入图片资源</h4><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/publish_article/image_pos.png\" alt=\"图片在哪里呀?\"></p>\n</div>\n\n<p>首先,将你所需要的图片资源导入到你的专属文件夹中,然后就可以修改markdown文件啦~</p>\n<p>像这样</p>\n<figure class=\"highlight md\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"language-xml\"><span class=\"tag\"><<span class=\"name\">div</span> <span class=\"attr\">style</span>=<span class=\"string\">"text-align:center"</span>></span></span></span><br><span class=\"line\"></span><br><span class=\"line\">![<span class=\"string\">图片在哪里呀?</span>](<span class=\"link\">articles/suang/publish_article/image_pos.png</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"language-xml\"><span class=\"tag\"></<span class=\"name\">div</span>></span></span></span><br></pre></td></tr></table></figure>\n\n<p>括号里面写上你的图片的相对路径就可以将图片导入啦!</p>\n<hr>\n<p>真的是保姆级了,正常来说照着我的教程一步一步来应该不会出问题了。<br>如果遇到了问题记得在群里@我</p>\n<p><strong>Yeah~</strong></p>\n","site":{"data":{}},"excerpt":"<p><strong>suang教你用GitHub Desktop发表文章!</strong><br><strong>超级简单!超级详细!超级耐心!</strong><br><strong>一定要看!一看就会!</strong></p>","more":"<h3 id=\"一、提交文章的流程\"><a href=\"#一、提交文章的流程\" class=\"headerlink\" title=\"一、提交文章的流程\"></a>一、提交文章的流程</h3><h4 id=\"1-安装以下工具\"><a href=\"#1-安装以下工具\" class=\"headerlink\" title=\"1. 安装以下工具\"></a>1. 安装以下工具</h4><ul>\n<li><strong>GitHub Desktop</strong></li>\n<li><strong>VSCode</strong></li>\n</ul>\n<h4 id=\"2-将GitHub库中的资源clone到本地\"><a href=\"#2-将GitHub库中的资源clone到本地\" class=\"headerlink\" title=\"2. 将GitHub库中的资源clone到本地\"></a>2. 将GitHub库中的资源clone到本地</h4><p>进入 <strong>VoidGameSpace</strong> 论坛的 <strong>GitHub</strong> 库网站,点击 <code>< > Code</code> ,选择<code>Open with GitHub Desktop</code>将资源克隆到本地。</p>\n<h4 id=\"3-使用VSCode打开库中资源并进行编辑\"><a href=\"#3-使用VSCode打开库中资源并进行编辑\" class=\"headerlink\" title=\"3. 使用VSCode打开库中资源并进行编辑\"></a>3. 使用VSCode打开库中资源并进行编辑</h4><p>切换到 <strong>GitHub Desktop</strong> ,点击 <code>Open in Visual Studio Code</code> 即可在 <strong>VSCode</strong> 中进行编辑。<br>在左侧资源管理器中打开目录 <code>/GAMEDEVWEBSITE/source/_posts</code> 在这个目录下新建一个独立的、专属于自己的文件夹。<br>在自己的文件夹中新建 <code>markdown</code> 文件,编辑完成保存后返回 <strong>GitHub Desktop</strong> 。 </p>\n<h4 id=\"4-提交本地代码,将本地所做的更改同步到远程代码库\"><a href=\"#4-提交本地代码,将本地所做的更改同步到远程代码库\" class=\"headerlink\" title=\"4. 提交本地代码,将本地所做的更改同步到远程代码库\"></a>4. 提交本地代码,将本地所做的更改同步到远程代码库</h4><p>返回 <strong>GitHub Desktop</strong> 后,会自动跳转到 <code>Changes</code> 界面,确认代码无误后,点击 <code>Commit to main</code> 进行提交,再点击 <code>Push origin</code> 将更改同步到远程代码库。</p>\n<h4 id=\"5-进入自己的fork,拉取合并更改的请求\"><a href=\"#5-进入自己的fork,拉取合并更改的请求\" class=\"headerlink\" title=\"5. 进入自己的fork,拉取合并更改的请求\"></a>5. 进入自己的fork,拉取合并更改的请求</h4><p>回到 <strong>GitHub</strong> 中并刷新网页,此时,一定要在自己fork的文件中!!!<br>按照下图方式点击,进入自己的fork,才能进行之后的操作。</p>\n<div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/publish_article/fork_img.png\" alt=\"xdm一定要记得fork啊,不然我白教了\"></p>\n</div>\n\n<p>接下来点击 <code>Pull requests</code> ,再点击 <code>New pull request</code> 拉取合并更改的请求。最后点击 <code>Create pull request</code> 生成请求。</p>\n<h4 id=\"6-等待Vercel部署和大V老师的审核\"><a href=\"#6-等待Vercel部署和大V老师的审核\" class=\"headerlink\" title=\"6. 等待Vercel部署和大V老师的审核\"></a>6. 等待Vercel部署和大V老师的审核</h4><p>完成了这一步,恭喜你已经成功将你的文章提交了,接下来就是耐心地等待你的文章通过审核了。<br>不过别急着高兴,关于 <code>markdown</code> 文件,还有一些注意事项。</p>\n<h3 id=\"二、关于markdown文件\"><a href=\"#二、关于markdown文件\" class=\"headerlink\" title=\"二、关于markdown文件\"></a>二、关于markdown文件</h3><h4 id=\"1-markdown文件的写法\"><a href=\"#1-markdown文件的写法\" class=\"headerlink\" title=\"1. markdown文件的写法\"></a>1. markdown文件的写法</h4><p>markdown的语法很简单,可以参考 <a href=\"https://markdown.com.cn/basic-syntax/\">Markdown 官方教程</a> 来进行查找和学习。</p>\n<h4 id=\"2-注意事项\"><a href=\"#2-注意事项\" class=\"headerlink\" title=\"2. 注意事项\"></a>2. 注意事项</h4><p><em><strong>敲重点!!!!!</strong></em></p>\n<ul>\n<li><strong>元数据一定不能少!</strong> <strong>元数据一定不能少!</strong> <strong>元数据一定不能少!</strong></li>\n</ul>\n<p>重要的事情说一万遍!</p>\n<p>元数据是用两个<code>---</code>分割线包围的数据,记录你的文章的<strong>标题</strong>、<strong>上传时间</strong>,<strong>修改时间</strong>、<strong>永久链接</strong>、<strong>目录</strong>、<strong>标签</strong> 这些信息,缺少了元数据的文章无法通过审核。写法如下:</p>\n<figure class=\"highlight md\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">---</span><br><span class=\"line\">title: 使用GitHub Desktop在论坛中发表文章的方法及注意事项</span><br><span class=\"line\">date: 2024-05-28</span><br><span class=\"line\">update: 2024-05-29</span><br><span class=\"line\">permalink: articles/suang/publish<span class=\"emphasis\">_article/</span></span><br><span class=\"line\"><span class=\"emphasis\">categories: suang</span></span><br><span class=\"line\"><span class=\"emphasis\">tags: [suang, 教程, 发表文章]</span></span><br><span class=\"line\"><span class=\"emphasis\">---</span></span><br></pre></td></tr></table></figure>\n<ul>\n<li>其中,<code>permalink</code> 项要填写 <code>article/你的专属目录/子目录(可选)/</code></li>\n</ul>\n<p>虽然子目录是可选项,但是,你也不想把所有的文章都丢在同一个文件夹下吧。真的不要这样做啊!!!</p>\n<ul>\n<li><p>元数据中有 <code>title</code> 属性不需要写一级标题</p>\n</li>\n<li><p>最好使用 <code><!-- More --></code> 注释添加概述否则主页文章会全部展开显得很长</p>\n</li>\n</ul>\n<h3 id=\"三、关于图片的插入\"><a href=\"#三、关于图片的插入\" class=\"headerlink\" title=\"三、关于图片的插入\"></a>三、关于图片的插入</h3><h4 id=\"1-导入图片资源\"><a href=\"#1-导入图片资源\" class=\"headerlink\" title=\"1. 导入图片资源\"></a>1. 导入图片资源</h4><div style=\"text-align:center\">\n\n<p><img src=\"/articles/suang/publish_article/image_pos.png\" alt=\"图片在哪里呀?\"></p>\n</div>\n\n<p>首先,将你所需要的图片资源导入到你的专属文件夹中,然后就可以修改markdown文件啦~</p>\n<p>像这样</p>\n<figure class=\"highlight md\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"language-xml\"><span class=\"tag\"><<span class=\"name\">div</span> <span class=\"attr\">style</span>=<span class=\"string\">"text-align:center"</span>></span></span></span><br><span class=\"line\"></span><br><span class=\"line\">![<span class=\"string\">图片在哪里呀?</span>](<span class=\"link\">articles/suang/publish_article/image_pos.png</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"language-xml\"><span class=\"tag\"></<span class=\"name\">div</span>></span></span></span><br></pre></td></tr></table></figure>\n\n<p>括号里面写上你的图片的相对路径就可以将图片导入啦!</p>\n<hr>\n<p>真的是保姆级了,正常来说照着我的教程一步一步来应该不会出问题了。<br>如果遇到了问题记得在群里@我</p>\n<p><strong>Yeah~</strong></p>"},{"title":"奥日与萤火意志2","date":"2024-05-30T16:00:00.000Z","updated":"2024-05-30T16:00:00.000Z","_content":"<!-- More -->\n\n# 玩奥日有感(真随笔)\n\n\n## 剧情上\n- 剧情上,目前是主角是一位精灵,不小心与猫头鹰库到一处森林分离,在初期的探索中初步认识了这个地方,认识了莫基小生物和地方守护者夸洛克,解决了当地的水源问题,与朋友会和但又不幸主角的朋友库在静谧森林因为攻击而晕过去,于是为了朋友和森林又踏上了整个大陆的冒险寻找森林光的碎片。\n这里分析一下主线推动和技能玩法的探索,显然在一些必备的要素技能都没有,你是探索不了主线的地图\n解锁了地底下和森林的碎片\n唤醒了底下的蜘蛛(被腐朽吞噬了心智)\n夸洛克牺牲了自我换回碎片\n\n- 剧情就不得不提到npc了\n莫基——路人角色,大大小小的任务都有承担,森林的原住民算是\n库克——地图提供者\n猴子——推动剧情,教会武器方面技能\n商人——交易升级技能\n夸洛克——沼泽的庇护神\n工匠——建造地图的一些的传送点和解锁地图的通道,建造触发剧情\n\n\n- 还有就是在设计上,制作者在获得技能前面的地图中总会遗留一些之后技能解锁的机关,延长玩家的游戏时间,有的可能会返回头探索,因为总有卡关的时候,在不看攻略的时候,这时候就是回头探索的时候\n\n\n- 前期对玩法的探索拓展可以说循序渐进了,十分缓和友好,真的是十分流畅的过渡\n\n\n- 细节方面上,对于地图map的里面功能的设置可以说非常全面了而且分类也很好,还有筛选器\n\n\n## 玩法上\n在玩法上,在前期的森林的探索中一步一步扩展开了,从单纯的跳跃到各种技能帮助拓展玩法。\n在角色系统我会介绍这些对玩法的贡献\n\n主要是——场景,场景关卡设置,物品和玩法剖析\n- 场景的关卡\n前期的最大关卡就是\n【1】找到散落的楔石打开石门\n小的关卡\n【2】\n拖拽石头来阻挡机关和帮助跳跃\n还有类似司机挡位的机关——触发一些机关,打开石门等等\n【3】\n还有全球玩家的小跑酷,也还算比较有趣,但也就一般般,扔掉也没关系,毕竟是单机游戏\n\n- 场景物品\n藤条——帮助跳跃\n竖直木棒——陷阱悬停\n水平木棒——这个真的是太amazin,可以按w转圈让后松开向上冲刺(从玩的方面来看,转速和角色的数值向上的速度有关,因为我竖直跳上去就会有转圈的行为,显然不是w是触发,向上的运动才是触发,w向上在棍子就会加速,松开就是结束转圈动画,此时决定转速的向上speed此时就是你的竖直速度)\n灯笼,苔藓,藤条,蓝色的抓钩物———不作分析了\n羽毛——\n还有库和奥日的配合玩法——\n\n补充:其实场景物品最让我惊讶的是角色动作的多样性,竖直木棍站在最顶端的单手倒立的动作,单手倒立起跳,还有竖直藤条木棍水平冲刺上去还会转几圈,真的是十分连贯\n\n\n\n\n- 玩法\n其实有的已经融合在以上或者以下的分析里面\n主要探索,打斗\n剧情的玩法——\n对话\n打斗boss等\nboss追击,我逃跑,这样完全发挥了跑图里面机制的乐趣\n\n- 场景\n第一个地图就是单纯的地图,但偶尔有几个门,进去新的场景\n\n## 从角色系统上分析\n主要分为四个部分\n\n- 蓝条和血条(在地图中寻找能量和生命碎片获得一步一步扩展,部分和技能有关,例如交换最大生命值和最大蓝条)\n\n- 武器+主动技能系统\n从光剑到弓箭到重锤,技能则有光之箭和回血等\n评价:武器不仅仅帮助我们更加轻松应对敌人,而且帮助我们能有效触发机关和障碍物,帮助探索地图。\n光剑——可以打碎一些木板障碍物\n例如弓箭——可以触发高处的机关,且技能还能扩大弓箭的特性,例如分裂和加攻速\n重锤——可以打碎石板\n光之箭——打碎一些易碎物,且伤害极高(光之箭的动作真的是让我记忆尤深,悬停瞄准,穿插在各种动作中,十分流畅帅气)\n其他目前武器目前没有看到对地图探索的作用,有再补充\n\n\n- 不可见的被动技能\n例如二连跳\n抓取——这真的amazing,流畅的难以置信,从飞行物到敌人全部都能抓取,靠近就能抓取,而且是时停性质的,可以将目标反向射出,而自己朝选的方向射出,虽然没有伤害但是极大的提高了游戏的可玩性,帮助了地图探索的乐趣还提高了打斗的技巧性,帮助玩家们在打斗中获得成就感。\n抓钩——准确的就是能飞到一些蓝色苔藓和的灯笼处,相当于蜘蛛侠吐丝吧,还行,但是印象不是特别深\n\n\n- 课拆卸购买升级的被动技能\n首先部分被动技能实在地图中寻找灵树或者在技能商人购买升级\n技能框则是探索地图一步一步的去扩展\n讲几个印象比较深的技能:\n攀爬——好吧,我已经把他默认为不可见的被动技能了,探索地图没了他不行\n三连跳——好吧也是默认了,不仅帅而且探索地图确实方便\n其他就是什么主动吸收光之碎片,减伤啥的,有印象深的再说吧\n\n\n(4)美术\n\n\n\n<div style=\"text-align:center\">\n</div>\n","source":"_posts/yang/奥日与萤火意志2.md","raw":"---\ntitle: 奥日与萤火意志2\ndate: 2024-05-31\nupdated: 2024-05-31\npermalink: articles/yang12342/奥日与萤火意志2/\ncategories: yang12342\ntags: [游戏心得]\n---\n<!-- More -->\n\n# 玩奥日有感(真随笔)\n\n\n## 剧情上\n- 剧情上,目前是主角是一位精灵,不小心与猫头鹰库到一处森林分离,在初期的探索中初步认识了这个地方,认识了莫基小生物和地方守护者夸洛克,解决了当地的水源问题,与朋友会和但又不幸主角的朋友库在静谧森林因为攻击而晕过去,于是为了朋友和森林又踏上了整个大陆的冒险寻找森林光的碎片。\n这里分析一下主线推动和技能玩法的探索,显然在一些必备的要素技能都没有,你是探索不了主线的地图\n解锁了地底下和森林的碎片\n唤醒了底下的蜘蛛(被腐朽吞噬了心智)\n夸洛克牺牲了自我换回碎片\n\n- 剧情就不得不提到npc了\n莫基——路人角色,大大小小的任务都有承担,森林的原住民算是\n库克——地图提供者\n猴子——推动剧情,教会武器方面技能\n商人——交易升级技能\n夸洛克——沼泽的庇护神\n工匠——建造地图的一些的传送点和解锁地图的通道,建造触发剧情\n\n\n- 还有就是在设计上,制作者在获得技能前面的地图中总会遗留一些之后技能解锁的机关,延长玩家的游戏时间,有的可能会返回头探索,因为总有卡关的时候,在不看攻略的时候,这时候就是回头探索的时候\n\n\n- 前期对玩法的探索拓展可以说循序渐进了,十分缓和友好,真的是十分流畅的过渡\n\n\n- 细节方面上,对于地图map的里面功能的设置可以说非常全面了而且分类也很好,还有筛选器\n\n\n## 玩法上\n在玩法上,在前期的森林的探索中一步一步扩展开了,从单纯的跳跃到各种技能帮助拓展玩法。\n在角色系统我会介绍这些对玩法的贡献\n\n主要是——场景,场景关卡设置,物品和玩法剖析\n- 场景的关卡\n前期的最大关卡就是\n【1】找到散落的楔石打开石门\n小的关卡\n【2】\n拖拽石头来阻挡机关和帮助跳跃\n还有类似司机挡位的机关——触发一些机关,打开石门等等\n【3】\n还有全球玩家的小跑酷,也还算比较有趣,但也就一般般,扔掉也没关系,毕竟是单机游戏\n\n- 场景物品\n藤条——帮助跳跃\n竖直木棒——陷阱悬停\n水平木棒——这个真的是太amazin,可以按w转圈让后松开向上冲刺(从玩的方面来看,转速和角色的数值向上的速度有关,因为我竖直跳上去就会有转圈的行为,显然不是w是触发,向上的运动才是触发,w向上在棍子就会加速,松开就是结束转圈动画,此时决定转速的向上speed此时就是你的竖直速度)\n灯笼,苔藓,藤条,蓝色的抓钩物———不作分析了\n羽毛——\n还有库和奥日的配合玩法——\n\n补充:其实场景物品最让我惊讶的是角色动作的多样性,竖直木棍站在最顶端的单手倒立的动作,单手倒立起跳,还有竖直藤条木棍水平冲刺上去还会转几圈,真的是十分连贯\n\n\n\n\n- 玩法\n其实有的已经融合在以上或者以下的分析里面\n主要探索,打斗\n剧情的玩法——\n对话\n打斗boss等\nboss追击,我逃跑,这样完全发挥了跑图里面机制的乐趣\n\n- 场景\n第一个地图就是单纯的地图,但偶尔有几个门,进去新的场景\n\n## 从角色系统上分析\n主要分为四个部分\n\n- 蓝条和血条(在地图中寻找能量和生命碎片获得一步一步扩展,部分和技能有关,例如交换最大生命值和最大蓝条)\n\n- 武器+主动技能系统\n从光剑到弓箭到重锤,技能则有光之箭和回血等\n评价:武器不仅仅帮助我们更加轻松应对敌人,而且帮助我们能有效触发机关和障碍物,帮助探索地图。\n光剑——可以打碎一些木板障碍物\n例如弓箭——可以触发高处的机关,且技能还能扩大弓箭的特性,例如分裂和加攻速\n重锤——可以打碎石板\n光之箭——打碎一些易碎物,且伤害极高(光之箭的动作真的是让我记忆尤深,悬停瞄准,穿插在各种动作中,十分流畅帅气)\n其他目前武器目前没有看到对地图探索的作用,有再补充\n\n\n- 不可见的被动技能\n例如二连跳\n抓取——这真的amazing,流畅的难以置信,从飞行物到敌人全部都能抓取,靠近就能抓取,而且是时停性质的,可以将目标反向射出,而自己朝选的方向射出,虽然没有伤害但是极大的提高了游戏的可玩性,帮助了地图探索的乐趣还提高了打斗的技巧性,帮助玩家们在打斗中获得成就感。\n抓钩——准确的就是能飞到一些蓝色苔藓和的灯笼处,相当于蜘蛛侠吐丝吧,还行,但是印象不是特别深\n\n\n- 课拆卸购买升级的被动技能\n首先部分被动技能实在地图中寻找灵树或者在技能商人购买升级\n技能框则是探索地图一步一步的去扩展\n讲几个印象比较深的技能:\n攀爬——好吧,我已经把他默认为不可见的被动技能了,探索地图没了他不行\n三连跳——好吧也是默认了,不仅帅而且探索地图确实方便\n其他就是什么主动吸收光之碎片,减伤啥的,有印象深的再说吧\n\n\n(4)美术\n\n\n\n<div style=\"text-align:center\">\n</div>\n","slug":"yang/奥日与萤火意志2","published":1,"__permalink":"articles/yang12342/奥日与萤火意志2/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgw003oo8yeh89ohgvt","content":"<span id=\"more\"></span>\n\n<h1 id=\"玩奥日有感(真随笔)\"><a href=\"#玩奥日有感(真随笔)\" class=\"headerlink\" title=\"玩奥日有感(真随笔)\"></a>玩奥日有感(真随笔)</h1><h2 id=\"剧情上\"><a href=\"#剧情上\" class=\"headerlink\" title=\"剧情上\"></a>剧情上</h2><ul>\n<li><p>剧情上,目前是主角是一位精灵,不小心与猫头鹰库到一处森林分离,在初期的探索中初步认识了这个地方,认识了莫基小生物和地方守护者夸洛克,解决了当地的水源问题,与朋友会和但又不幸主角的朋友库在静谧森林因为攻击而晕过去,于是为了朋友和森林又踏上了整个大陆的冒险寻找森林光的碎片。<br>这里分析一下主线推动和技能玩法的探索,显然在一些必备的要素技能都没有,你是探索不了主线的地图<br>解锁了地底下和森林的碎片<br>唤醒了底下的蜘蛛(被腐朽吞噬了心智)<br>夸洛克牺牲了自我换回碎片</p>\n</li>\n<li><p>剧情就不得不提到npc了<br>莫基——路人角色,大大小小的任务都有承担,森林的原住民算是<br>库克——地图提供者<br>猴子——推动剧情,教会武器方面技能<br>商人——交易升级技能<br>夸洛克——沼泽的庇护神<br>工匠——建造地图的一些的传送点和解锁地图的通道,建造触发剧情</p>\n</li>\n<li><p>还有就是在设计上,制作者在获得技能前面的地图中总会遗留一些之后技能解锁的机关,延长玩家的游戏时间,有的可能会返回头探索,因为总有卡关的时候,在不看攻略的时候,这时候就是回头探索的时候</p>\n</li>\n<li><p>前期对玩法的探索拓展可以说循序渐进了,十分缓和友好,真的是十分流畅的过渡</p>\n</li>\n<li><p>细节方面上,对于地图map的里面功能的设置可以说非常全面了而且分类也很好,还有筛选器</p>\n</li>\n</ul>\n<h2 id=\"玩法上\"><a href=\"#玩法上\" class=\"headerlink\" title=\"玩法上\"></a>玩法上</h2><p>在玩法上,在前期的森林的探索中一步一步扩展开了,从单纯的跳跃到各种技能帮助拓展玩法。<br>在角色系统我会介绍这些对玩法的贡献</p>\n<p>主要是——场景,场景关卡设置,物品和玩法剖析</p>\n<ul>\n<li><p>场景的关卡<br>前期的最大关卡就是<br>【1】找到散落的楔石打开石门<br>小的关卡<br>【2】<br>拖拽石头来阻挡机关和帮助跳跃<br>还有类似司机挡位的机关——触发一些机关,打开石门等等<br>【3】<br>还有全球玩家的小跑酷,也还算比较有趣,但也就一般般,扔掉也没关系,毕竟是单机游戏</p>\n</li>\n<li><p>场景物品<br>藤条——帮助跳跃<br>竖直木棒——陷阱悬停<br>水平木棒——这个真的是太amazin,可以按w转圈让后松开向上冲刺(从玩的方面来看,转速和角色的数值向上的速度有关,因为我竖直跳上去就会有转圈的行为,显然不是w是触发,向上的运动才是触发,w向上在棍子就会加速,松开就是结束转圈动画,此时决定转速的向上speed此时就是你的竖直速度)<br>灯笼,苔藓,藤条,蓝色的抓钩物———不作分析了<br>羽毛——<br>还有库和奥日的配合玩法——</p>\n</li>\n</ul>\n<p>补充:其实场景物品最让我惊讶的是角色动作的多样性,竖直木棍站在最顶端的单手倒立的动作,单手倒立起跳,还有竖直藤条木棍水平冲刺上去还会转几圈,真的是十分连贯</p>\n<ul>\n<li><p>玩法<br>其实有的已经融合在以上或者以下的分析里面<br>主要探索,打斗<br>剧情的玩法——<br>对话<br>打斗boss等<br>boss追击,我逃跑,这样完全发挥了跑图里面机制的乐趣</p>\n</li>\n<li><p>场景<br>第一个地图就是单纯的地图,但偶尔有几个门,进去新的场景</p>\n</li>\n</ul>\n<h2 id=\"从角色系统上分析\"><a href=\"#从角色系统上分析\" class=\"headerlink\" title=\"从角色系统上分析\"></a>从角色系统上分析</h2><p>主要分为四个部分</p>\n<ul>\n<li><p>蓝条和血条(在地图中寻找能量和生命碎片获得一步一步扩展,部分和技能有关,例如交换最大生命值和最大蓝条)</p>\n</li>\n<li><p>武器+主动技能系统<br>从光剑到弓箭到重锤,技能则有光之箭和回血等<br>评价:武器不仅仅帮助我们更加轻松应对敌人,而且帮助我们能有效触发机关和障碍物,帮助探索地图。<br>光剑——可以打碎一些木板障碍物<br>例如弓箭——可以触发高处的机关,且技能还能扩大弓箭的特性,例如分裂和加攻速<br>重锤——可以打碎石板<br>光之箭——打碎一些易碎物,且伤害极高(光之箭的动作真的是让我记忆尤深,悬停瞄准,穿插在各种动作中,十分流畅帅气)<br>其他目前武器目前没有看到对地图探索的作用,有再补充</p>\n</li>\n<li><p>不可见的被动技能<br>例如二连跳<br>抓取——这真的amazing,流畅的难以置信,从飞行物到敌人全部都能抓取,靠近就能抓取,而且是时停性质的,可以将目标反向射出,而自己朝选的方向射出,虽然没有伤害但是极大的提高了游戏的可玩性,帮助了地图探索的乐趣还提高了打斗的技巧性,帮助玩家们在打斗中获得成就感。<br>抓钩——准确的就是能飞到一些蓝色苔藓和的灯笼处,相当于蜘蛛侠吐丝吧,还行,但是印象不是特别深</p>\n</li>\n<li><p>课拆卸购买升级的被动技能<br>首先部分被动技能实在地图中寻找灵树或者在技能商人购买升级<br>技能框则是探索地图一步一步的去扩展<br>讲几个印象比较深的技能:<br>攀爬——好吧,我已经把他默认为不可见的被动技能了,探索地图没了他不行<br>三连跳——好吧也是默认了,不仅帅而且探索地图确实方便<br>其他就是什么主动吸收光之碎片,减伤啥的,有印象深的再说吧</p>\n</li>\n</ul>\n<p>(4)美术</p>\n<div style=\"text-align:center\">\n</div>\n","site":{"data":{}},"excerpt":"","more":"<h1 id=\"玩奥日有感(真随笔)\"><a href=\"#玩奥日有感(真随笔)\" class=\"headerlink\" title=\"玩奥日有感(真随笔)\"></a>玩奥日有感(真随笔)</h1><h2 id=\"剧情上\"><a href=\"#剧情上\" class=\"headerlink\" title=\"剧情上\"></a>剧情上</h2><ul>\n<li><p>剧情上,目前是主角是一位精灵,不小心与猫头鹰库到一处森林分离,在初期的探索中初步认识了这个地方,认识了莫基小生物和地方守护者夸洛克,解决了当地的水源问题,与朋友会和但又不幸主角的朋友库在静谧森林因为攻击而晕过去,于是为了朋友和森林又踏上了整个大陆的冒险寻找森林光的碎片。<br>这里分析一下主线推动和技能玩法的探索,显然在一些必备的要素技能都没有,你是探索不了主线的地图<br>解锁了地底下和森林的碎片<br>唤醒了底下的蜘蛛(被腐朽吞噬了心智)<br>夸洛克牺牲了自我换回碎片</p>\n</li>\n<li><p>剧情就不得不提到npc了<br>莫基——路人角色,大大小小的任务都有承担,森林的原住民算是<br>库克——地图提供者<br>猴子——推动剧情,教会武器方面技能<br>商人——交易升级技能<br>夸洛克——沼泽的庇护神<br>工匠——建造地图的一些的传送点和解锁地图的通道,建造触发剧情</p>\n</li>\n<li><p>还有就是在设计上,制作者在获得技能前面的地图中总会遗留一些之后技能解锁的机关,延长玩家的游戏时间,有的可能会返回头探索,因为总有卡关的时候,在不看攻略的时候,这时候就是回头探索的时候</p>\n</li>\n<li><p>前期对玩法的探索拓展可以说循序渐进了,十分缓和友好,真的是十分流畅的过渡</p>\n</li>\n<li><p>细节方面上,对于地图map的里面功能的设置可以说非常全面了而且分类也很好,还有筛选器</p>\n</li>\n</ul>\n<h2 id=\"玩法上\"><a href=\"#玩法上\" class=\"headerlink\" title=\"玩法上\"></a>玩法上</h2><p>在玩法上,在前期的森林的探索中一步一步扩展开了,从单纯的跳跃到各种技能帮助拓展玩法。<br>在角色系统我会介绍这些对玩法的贡献</p>\n<p>主要是——场景,场景关卡设置,物品和玩法剖析</p>\n<ul>\n<li><p>场景的关卡<br>前期的最大关卡就是<br>【1】找到散落的楔石打开石门<br>小的关卡<br>【2】<br>拖拽石头来阻挡机关和帮助跳跃<br>还有类似司机挡位的机关——触发一些机关,打开石门等等<br>【3】<br>还有全球玩家的小跑酷,也还算比较有趣,但也就一般般,扔掉也没关系,毕竟是单机游戏</p>\n</li>\n<li><p>场景物品<br>藤条——帮助跳跃<br>竖直木棒——陷阱悬停<br>水平木棒——这个真的是太amazin,可以按w转圈让后松开向上冲刺(从玩的方面来看,转速和角色的数值向上的速度有关,因为我竖直跳上去就会有转圈的行为,显然不是w是触发,向上的运动才是触发,w向上在棍子就会加速,松开就是结束转圈动画,此时决定转速的向上speed此时就是你的竖直速度)<br>灯笼,苔藓,藤条,蓝色的抓钩物———不作分析了<br>羽毛——<br>还有库和奥日的配合玩法——</p>\n</li>\n</ul>\n<p>补充:其实场景物品最让我惊讶的是角色动作的多样性,竖直木棍站在最顶端的单手倒立的动作,单手倒立起跳,还有竖直藤条木棍水平冲刺上去还会转几圈,真的是十分连贯</p>\n<ul>\n<li><p>玩法<br>其实有的已经融合在以上或者以下的分析里面<br>主要探索,打斗<br>剧情的玩法——<br>对话<br>打斗boss等<br>boss追击,我逃跑,这样完全发挥了跑图里面机制的乐趣</p>\n</li>\n<li><p>场景<br>第一个地图就是单纯的地图,但偶尔有几个门,进去新的场景</p>\n</li>\n</ul>\n<h2 id=\"从角色系统上分析\"><a href=\"#从角色系统上分析\" class=\"headerlink\" title=\"从角色系统上分析\"></a>从角色系统上分析</h2><p>主要分为四个部分</p>\n<ul>\n<li><p>蓝条和血条(在地图中寻找能量和生命碎片获得一步一步扩展,部分和技能有关,例如交换最大生命值和最大蓝条)</p>\n</li>\n<li><p>武器+主动技能系统<br>从光剑到弓箭到重锤,技能则有光之箭和回血等<br>评价:武器不仅仅帮助我们更加轻松应对敌人,而且帮助我们能有效触发机关和障碍物,帮助探索地图。<br>光剑——可以打碎一些木板障碍物<br>例如弓箭——可以触发高处的机关,且技能还能扩大弓箭的特性,例如分裂和加攻速<br>重锤——可以打碎石板<br>光之箭——打碎一些易碎物,且伤害极高(光之箭的动作真的是让我记忆尤深,悬停瞄准,穿插在各种动作中,十分流畅帅气)<br>其他目前武器目前没有看到对地图探索的作用,有再补充</p>\n</li>\n<li><p>不可见的被动技能<br>例如二连跳<br>抓取——这真的amazing,流畅的难以置信,从飞行物到敌人全部都能抓取,靠近就能抓取,而且是时停性质的,可以将目标反向射出,而自己朝选的方向射出,虽然没有伤害但是极大的提高了游戏的可玩性,帮助了地图探索的乐趣还提高了打斗的技巧性,帮助玩家们在打斗中获得成就感。<br>抓钩——准确的就是能飞到一些蓝色苔藓和的灯笼处,相当于蜘蛛侠吐丝吧,还行,但是印象不是特别深</p>\n</li>\n<li><p>课拆卸购买升级的被动技能<br>首先部分被动技能实在地图中寻找灵树或者在技能商人购买升级<br>技能框则是探索地图一步一步的去扩展<br>讲几个印象比较深的技能:<br>攀爬——好吧,我已经把他默认为不可见的被动技能了,探索地图没了他不行<br>三连跳——好吧也是默认了,不仅帅而且探索地图确实方便<br>其他就是什么主动吸收光之碎片,减伤啥的,有印象深的再说吧</p>\n</li>\n</ul>\n<p>(4)美术</p>\n<div style=\"text-align:center\">\n</div>"},{"title":"zExNocs自我介绍","date":"2024-05-26T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"\n这是一个zExNocs的自我介绍。\n\n<!-- More -->\n\n---\n\n# 介绍\n<div style=\"text-align:center\">\n<img src=\"https://zexnocs.github.io/img/avatar.jpg\" alt=\"去码头整点薯条。\" width=\"100\">\n\n这里是蒟蒻zExNocs:[个人小站](https://zexnocs.github.io/)\n\n欢迎各位大佬友链&&留言\n</div>\n\n---\n\n# 导航\n- 这里空空如也\n\n---\n\n这是一个神奇的公式,你知道叫什么吗?\n$$P(T)=e^{\\frac{\\Delta}{kT}}$$","source":"_posts/zExNocs/自我介绍.md","raw":"---\ntitle: zExNocs自我介绍\ndate: 2024-05-27\nupdated: 2024-05-28\npermalink: articles/zExNocs/自我介绍/\ncategories: zExNocs\ntags: \n - 自我介绍\n---\n\n这是一个zExNocs的自我介绍。\n\n<!-- More -->\n\n---\n\n# 介绍\n<div style=\"text-align:center\">\n<img src=\"https://zexnocs.github.io/img/avatar.jpg\" alt=\"去码头整点薯条。\" width=\"100\">\n\n这里是蒟蒻zExNocs:[个人小站](https://zexnocs.github.io/)\n\n欢迎各位大佬友链&&留言\n</div>\n\n---\n\n# 导航\n- 这里空空如也\n\n---\n\n这是一个神奇的公式,你知道叫什么吗?\n$$P(T)=e^{\\frac{\\Delta}{kT}}$$","slug":"zExNocs/自我介绍","published":1,"__permalink":"articles/zExNocs/自我介绍/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgx003po8ye39c50tl1","content":"<p>这是一个zExNocs的自我介绍。</p>\n<span id=\"more\"></span>\n\n<hr>\n<h1 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h1><div style=\"text-align:center\">\n<img src=\"https://zexnocs.github.io/img/avatar.jpg\" alt=\"去码头整点薯条。\" width=\"100\">\n\n<p>这里是蒟蒻zExNocs:<a href=\"https://zexnocs.github.io/\">个人小站</a></p>\n<p>欢迎各位大佬友链&&留言</p>\n</div>\n\n<hr>\n<h1 id=\"导航\"><a href=\"#导航\" class=\"headerlink\" title=\"导航\"></a>导航</h1><ul>\n<li>这里空空如也</li>\n</ul>\n<hr>\n<p>这是一个神奇的公式,你知道叫什么吗?<br>$$P(T)=e^{\\frac{\\Delta}{kT}}$$</p>\n","site":{"data":{}},"excerpt":"<p>这是一个zExNocs的自我介绍。</p>","more":"<hr>\n<h1 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h1><div style=\"text-align:center\">\n<img src=\"https://zexnocs.github.io/img/avatar.jpg\" alt=\"去码头整点薯条。\" width=\"100\">\n\n<p>这里是蒟蒻zExNocs:<a href=\"https://zexnocs.github.io/\">个人小站</a></p>\n<p>欢迎各位大佬友链&&留言</p>\n</div>\n\n<hr>\n<h1 id=\"导航\"><a href=\"#导航\" class=\"headerlink\" title=\"导航\"></a>导航</h1><ul>\n<li>这里空空如也</li>\n</ul>\n<hr>\n<p>这是一个神奇的公式,你知道叫什么吗?<br>$$P(T)=e^{\\frac{\\Delta}{kT}}$$</p>"},{"title":"随笔-如何提交文章到VoidGameSpace上","date":"2024-05-27T16:00:00.000Z","updated":"2024-05-27T16:00:00.000Z","_content":"\n关于如何提交文章到VoidGameSpace论坛上的git教程。\n\n<!-- More -->\n\n---\n本文章仅适用于[VoidGameSpace论坛](https://www.voidgame.space/)及其[GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。\n\n该教程目前仅适用于**Windows**系统。\n\n[原博客传送面板](https://zexnocs.github.io/post/%E9%9A%8F%E7%AC%94%2F%E9%9A%8F%E7%AC%94-%E5%A6%82%E4%BD%95%E6%8F%90%E4%BA%A4%E6%96%87%E7%AB%A0%E5%88%B0VoidGameSpace%E4%B8%8A)\n\n# 如何使用github进行提交\n\n## 一. 确认Git安装\n\nGit下载地址: [Link](https://git-scm.com/downloads)\n\n测试Git:打开 `cmd` 或者 `PowerShell`,输入 `git -v` 可以查看到当前Git的版本。\n\n## 二. 配置Git设置和SSH\n\n- 使用下面两个指令配置Git全局设置:\n\n```\ngit config --global user.name \"你的用户名\"\ngit config --global user.email \"你的邮箱\"\n```\n\n- 配置ssh设置:[可以参考这个文章](https://blog.csdn.net/Yaoyao2024/article/details/132123525)\n\n1. 使用 `ssh-keygen -t rsa -C \"你的邮箱\"`,一路回车生成SSH。\n2. 找到文件`C:\\User\\用户名\\.ssh\\id_rsa.pub`,使用记事本打开并复制里面的内容。\n3. 打开GitHub在`Settings`界面左边找到`SSH and GPG keys`进入。\n4. 点击 `New SSH key`,在`title`中填入合适的标题,在`SSH`中填入刚刚复制的内容。\n5. 本地指令输入 `ssh -T git@github.com` 验证是否配置成功。\n\n## 三. fork库到自己的库中\n\n打开 [GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite) 网页,点击右上角 `Fork` 按钮,复制该库到自己的库中。\n\n选择`owner`为自己的账户,`Repository name`可以设置为默认`GameDevWebsite`。\n\n`Description`用来描述这个库,可以随便写一些,例如:VoidGameSpace论坛的Fork库。\n\n点击 `Create fork` 按钮。\n\n## 四. clone库到本地\n\n进入自己的库中找到刚刚fork的`GameDevWebsite`库,一般为 `https://github.com/用户名/GameDevWebsite`\n\n找到 `<> Code` 绿色按钮,在本地中使用 `PowerShell` 打开想要部署的位置 or 在部署的位置中右键选择`在终端打开` or 使用`cmd` `cd` 到要部署的文件夹,使用下面三种方式之一克隆库到本地\n\n1. 使用`HTTPS`,复制`web URL`,输入`git clone 复制的URL`部署。这个方法需要你在终端登录到Git中。\n2. 使用`SSH`,复制`SSH key`,输入`git clone 复制的SSH_key`部署。\n3. 点击`Download ZIP`,下载压缩包到要部署的文件夹并解压。\n\n## 五. 编写自己的文档\n\n在部署的项目目录`GameDevWebsite`中,路径`source\\_posts\\`创建自己的文件夹,并在文件夹中创建`.md`文件,参考[GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)中元数据说明,编写自己的文章。\n\n另外,markdown的编写可以参考官方文档:[Link](https://markdown.com.cn/)\n\n## 六. 提交文档到自己fork的库中\n\n使用 `PowerShell` 打开项目目录`GameDevWebsite`,或者在目录中右键点击`在终端打开`,或者使用`cmd` `cd`到目录。\n\n1. 创建自己的分支(可选,新手建议直接修改`main`分支):使用 `git checkout -b 分支名` 创建并切换到新的分支。(分支的作用是保证`main`分支的干净,一般只有最终版本才会合并到`main`分支)。如果你已经创建过分支,就不需要再创建该分支了。\n2. 添加所有文件到暂存区: `git add .`\n3. 提交添加的文件: `git commit -m \"修改描述\"`。为了养成好习惯,修改描述要有一定的准则。例如你修改文档可以写 `\"docs(你的名字): 添加了xxx文章\"`。具体准则可以自行搜索学习一下。\n4. push库:如果你使用的是新建的分支,使用`git push origin 分支名` 将新分支push到库中。如果你使用的是`main`分支或者是已经创建的库,那么使用 `git push` 将提交的内容push到库中。\n \n## 七. 拉取申请\n找到自己fork的库,点击左上方 `Pull requests`按钮,进入页面点击右上方`New pull request`按钮。左边是合并的基库,右边是申请合并的库。在右边申请的库中选择自己的库和分支(如果没有创建分支就选择`main`),然后填写一些申请描述即可。\n\n## 八. 等待审核\n~~建议留言压力v佬(bushi)~~","source":"_posts/zExNocs/随笔-如何提交文章到VoidGameSpace上.md","raw":"---\ntitle: 随笔-如何提交文章到VoidGameSpace上\ndate: 2024-05-28\nupdated: 2024-05-28\npermalink: articles/zExNocs/随笔-如何提交文章到VoidGameSpace上/\ncategories: zExNocs\ntags:\n - VoidGameSpace\n - Hexo\n - Git\n---\n\n关于如何提交文章到VoidGameSpace论坛上的git教程。\n\n<!-- More -->\n\n---\n本文章仅适用于[VoidGameSpace论坛](https://www.voidgame.space/)及其[GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)。\n\n该教程目前仅适用于**Windows**系统。\n\n[原博客传送面板](https://zexnocs.github.io/post/%E9%9A%8F%E7%AC%94%2F%E9%9A%8F%E7%AC%94-%E5%A6%82%E4%BD%95%E6%8F%90%E4%BA%A4%E6%96%87%E7%AB%A0%E5%88%B0VoidGameSpace%E4%B8%8A)\n\n# 如何使用github进行提交\n\n## 一. 确认Git安装\n\nGit下载地址: [Link](https://git-scm.com/downloads)\n\n测试Git:打开 `cmd` 或者 `PowerShell`,输入 `git -v` 可以查看到当前Git的版本。\n\n## 二. 配置Git设置和SSH\n\n- 使用下面两个指令配置Git全局设置:\n\n```\ngit config --global user.name \"你的用户名\"\ngit config --global user.email \"你的邮箱\"\n```\n\n- 配置ssh设置:[可以参考这个文章](https://blog.csdn.net/Yaoyao2024/article/details/132123525)\n\n1. 使用 `ssh-keygen -t rsa -C \"你的邮箱\"`,一路回车生成SSH。\n2. 找到文件`C:\\User\\用户名\\.ssh\\id_rsa.pub`,使用记事本打开并复制里面的内容。\n3. 打开GitHub在`Settings`界面左边找到`SSH and GPG keys`进入。\n4. 点击 `New SSH key`,在`title`中填入合适的标题,在`SSH`中填入刚刚复制的内容。\n5. 本地指令输入 `ssh -T git@github.com` 验证是否配置成功。\n\n## 三. fork库到自己的库中\n\n打开 [GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite) 网页,点击右上角 `Fork` 按钮,复制该库到自己的库中。\n\n选择`owner`为自己的账户,`Repository name`可以设置为默认`GameDevWebsite`。\n\n`Description`用来描述这个库,可以随便写一些,例如:VoidGameSpace论坛的Fork库。\n\n点击 `Create fork` 按钮。\n\n## 四. clone库到本地\n\n进入自己的库中找到刚刚fork的`GameDevWebsite`库,一般为 `https://github.com/用户名/GameDevWebsite`\n\n找到 `<> Code` 绿色按钮,在本地中使用 `PowerShell` 打开想要部署的位置 or 在部署的位置中右键选择`在终端打开` or 使用`cmd` `cd` 到要部署的文件夹,使用下面三种方式之一克隆库到本地\n\n1. 使用`HTTPS`,复制`web URL`,输入`git clone 复制的URL`部署。这个方法需要你在终端登录到Git中。\n2. 使用`SSH`,复制`SSH key`,输入`git clone 复制的SSH_key`部署。\n3. 点击`Download ZIP`,下载压缩包到要部署的文件夹并解压。\n\n## 五. 编写自己的文档\n\n在部署的项目目录`GameDevWebsite`中,路径`source\\_posts\\`创建自己的文件夹,并在文件夹中创建`.md`文件,参考[GitHub库](https://github.com/VoidmatrixHeathcliff/GameDevWebsite)中元数据说明,编写自己的文章。\n\n另外,markdown的编写可以参考官方文档:[Link](https://markdown.com.cn/)\n\n## 六. 提交文档到自己fork的库中\n\n使用 `PowerShell` 打开项目目录`GameDevWebsite`,或者在目录中右键点击`在终端打开`,或者使用`cmd` `cd`到目录。\n\n1. 创建自己的分支(可选,新手建议直接修改`main`分支):使用 `git checkout -b 分支名` 创建并切换到新的分支。(分支的作用是保证`main`分支的干净,一般只有最终版本才会合并到`main`分支)。如果你已经创建过分支,就不需要再创建该分支了。\n2. 添加所有文件到暂存区: `git add .`\n3. 提交添加的文件: `git commit -m \"修改描述\"`。为了养成好习惯,修改描述要有一定的准则。例如你修改文档可以写 `\"docs(你的名字): 添加了xxx文章\"`。具体准则可以自行搜索学习一下。\n4. push库:如果你使用的是新建的分支,使用`git push origin 分支名` 将新分支push到库中。如果你使用的是`main`分支或者是已经创建的库,那么使用 `git push` 将提交的内容push到库中。\n \n## 七. 拉取申请\n找到自己fork的库,点击左上方 `Pull requests`按钮,进入页面点击右上方`New pull request`按钮。左边是合并的基库,右边是申请合并的库。在右边申请的库中选择自己的库和分支(如果没有创建分支就选择`main`),然后填写一些申请描述即可。\n\n## 八. 等待审核\n~~建议留言压力v佬(bushi)~~","slug":"zExNocs/随笔-如何提交文章到VoidGameSpace上","published":1,"__permalink":"articles/zExNocs/随笔-如何提交文章到VoidGameSpace上/","comments":1,"layout":"post","photos":[],"link":"","_id":"clx8n2hgx003so8ye8ozq9748","content":"<p>关于如何提交文章到VoidGameSpace论坛上的git教程。</p>\n<span id=\"more\"></span>\n\n<hr>\n<p>本文章仅适用于<a href=\"https://www.voidgame.space/\">VoidGameSpace论坛</a>及其<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a>。</p>\n<p>该教程目前仅适用于<strong>Windows</strong>系统。</p>\n<p><a href=\"https://zexnocs.github.io/post/%E9%9A%8F%E7%AC%94%2F%E9%9A%8F%E7%AC%94-%E5%A6%82%E4%BD%95%E6%8F%90%E4%BA%A4%E6%96%87%E7%AB%A0%E5%88%B0VoidGameSpace%E4%B8%8A\">原博客传送面板</a></p>\n<h1 id=\"如何使用github进行提交\"><a href=\"#如何使用github进行提交\" class=\"headerlink\" title=\"如何使用github进行提交\"></a>如何使用github进行提交</h1><h2 id=\"一-确认Git安装\"><a href=\"#一-确认Git安装\" class=\"headerlink\" title=\"一. 确认Git安装\"></a>一. 确认Git安装</h2><p>Git下载地址: <a href=\"https://git-scm.com/downloads\">Link</a></p>\n<p>测试Git:打开 <code>cmd</code> 或者 <code>PowerShell</code>,输入 <code>git -v</code> 可以查看到当前Git的版本。</p>\n<h2 id=\"二-配置Git设置和SSH\"><a href=\"#二-配置Git设置和SSH\" class=\"headerlink\" title=\"二. 配置Git设置和SSH\"></a>二. 配置Git设置和SSH</h2><ul>\n<li>使用下面两个指令配置Git全局设置:</li>\n</ul>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config --global user.name "你的用户名"</span><br><span class=\"line\">git config --global user.email "你的邮箱"</span><br></pre></td></tr></table></figure>\n\n<ul>\n<li>配置ssh设置:<a href=\"https://blog.csdn.net/Yaoyao2024/article/details/132123525\">可以参考这个文章</a></li>\n</ul>\n<ol>\n<li>使用 <code>ssh-keygen -t rsa -C "你的邮箱"</code>,一路回车生成SSH。</li>\n<li>找到文件<code>C:\\User\\用户名\\.ssh\\id_rsa.pub</code>,使用记事本打开并复制里面的内容。</li>\n<li>打开GitHub在<code>Settings</code>界面左边找到<code>SSH and GPG keys</code>进入。</li>\n<li>点击 <code>New SSH key</code>,在<code>title</code>中填入合适的标题,在<code>SSH</code>中填入刚刚复制的内容。</li>\n<li>本地指令输入 <code>ssh -T git@github.com</code> 验证是否配置成功。</li>\n</ol>\n<h2 id=\"三-fork库到自己的库中\"><a href=\"#三-fork库到自己的库中\" class=\"headerlink\" title=\"三. fork库到自己的库中\"></a>三. fork库到自己的库中</h2><p>打开 <a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a> 网页,点击右上角 <code>Fork</code> 按钮,复制该库到自己的库中。</p>\n<p>选择<code>owner</code>为自己的账户,<code>Repository name</code>可以设置为默认<code>GameDevWebsite</code>。</p>\n<p><code>Description</code>用来描述这个库,可以随便写一些,例如:VoidGameSpace论坛的Fork库。</p>\n<p>点击 <code>Create fork</code> 按钮。</p>\n<h2 id=\"四-clone库到本地\"><a href=\"#四-clone库到本地\" class=\"headerlink\" title=\"四. clone库到本地\"></a>四. clone库到本地</h2><p>进入自己的库中找到刚刚fork的<code>GameDevWebsite</code>库,一般为 <code>https://github.com/用户名/GameDevWebsite</code></p>\n<p>找到 <code><> Code</code> 绿色按钮,在本地中使用 <code>PowerShell</code> 打开想要部署的位置 or 在部署的位置中右键选择<code>在终端打开</code> or 使用<code>cmd</code> <code>cd</code> 到要部署的文件夹,使用下面三种方式之一克隆库到本地</p>\n<ol>\n<li>使用<code>HTTPS</code>,复制<code>web URL</code>,输入<code>git clone 复制的URL</code>部署。这个方法需要你在终端登录到Git中。</li>\n<li>使用<code>SSH</code>,复制<code>SSH key</code>,输入<code>git clone 复制的SSH_key</code>部署。</li>\n<li>点击<code>Download ZIP</code>,下载压缩包到要部署的文件夹并解压。</li>\n</ol>\n<h2 id=\"五-编写自己的文档\"><a href=\"#五-编写自己的文档\" class=\"headerlink\" title=\"五. 编写自己的文档\"></a>五. 编写自己的文档</h2><p>在部署的项目目录<code>GameDevWebsite</code>中,路径<code>source\\_posts\\</code>创建自己的文件夹,并在文件夹中创建<code>.md</code>文件,参考<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a>中元数据说明,编写自己的文章。</p>\n<p>另外,markdown的编写可以参考官方文档:<a href=\"https://markdown.com.cn/\">Link</a></p>\n<h2 id=\"六-提交文档到自己fork的库中\"><a href=\"#六-提交文档到自己fork的库中\" class=\"headerlink\" title=\"六. 提交文档到自己fork的库中\"></a>六. 提交文档到自己fork的库中</h2><p>使用 <code>PowerShell</code> 打开项目目录<code>GameDevWebsite</code>,或者在目录中右键点击<code>在终端打开</code>,或者使用<code>cmd</code> <code>cd</code>到目录。</p>\n<ol>\n<li>创建自己的分支(可选,新手建议直接修改<code>main</code>分支):使用 <code>git checkout -b 分支名</code> 创建并切换到新的分支。(分支的作用是保证<code>main</code>分支的干净,一般只有最终版本才会合并到<code>main</code>分支)。如果你已经创建过分支,就不需要再创建该分支了。</li>\n<li>添加所有文件到暂存区: <code>git add .</code></li>\n<li>提交添加的文件: <code>git commit -m "修改描述"</code>。为了养成好习惯,修改描述要有一定的准则。例如你修改文档可以写 <code>"docs(你的名字): 添加了xxx文章"</code>。具体准则可以自行搜索学习一下。</li>\n<li>push库:如果你使用的是新建的分支,使用<code>git push origin 分支名</code> 将新分支push到库中。如果你使用的是<code>main</code>分支或者是已经创建的库,那么使用 <code>git push</code> 将提交的内容push到库中。</li>\n</ol>\n<h2 id=\"七-拉取申请\"><a href=\"#七-拉取申请\" class=\"headerlink\" title=\"七. 拉取申请\"></a>七. 拉取申请</h2><p>找到自己fork的库,点击左上方 <code>Pull requests</code>按钮,进入页面点击右上方<code>New pull request</code>按钮。左边是合并的基库,右边是申请合并的库。在右边申请的库中选择自己的库和分支(如果没有创建分支就选择<code>main</code>),然后填写一些申请描述即可。</p>\n<h2 id=\"八-等待审核\"><a href=\"#八-等待审核\" class=\"headerlink\" title=\"八. 等待审核\"></a>八. 等待审核</h2><p><del>建议留言压力v佬(bushi)</del></p>\n","site":{"data":{}},"excerpt":"<p>关于如何提交文章到VoidGameSpace论坛上的git教程。</p>","more":"<hr>\n<p>本文章仅适用于<a href=\"https://www.voidgame.space/\">VoidGameSpace论坛</a>及其<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a>。</p>\n<p>该教程目前仅适用于<strong>Windows</strong>系统。</p>\n<p><a href=\"https://zexnocs.github.io/post/%E9%9A%8F%E7%AC%94%2F%E9%9A%8F%E7%AC%94-%E5%A6%82%E4%BD%95%E6%8F%90%E4%BA%A4%E6%96%87%E7%AB%A0%E5%88%B0VoidGameSpace%E4%B8%8A\">原博客传送面板</a></p>\n<h1 id=\"如何使用github进行提交\"><a href=\"#如何使用github进行提交\" class=\"headerlink\" title=\"如何使用github进行提交\"></a>如何使用github进行提交</h1><h2 id=\"一-确认Git安装\"><a href=\"#一-确认Git安装\" class=\"headerlink\" title=\"一. 确认Git安装\"></a>一. 确认Git安装</h2><p>Git下载地址: <a href=\"https://git-scm.com/downloads\">Link</a></p>\n<p>测试Git:打开 <code>cmd</code> 或者 <code>PowerShell</code>,输入 <code>git -v</code> 可以查看到当前Git的版本。</p>\n<h2 id=\"二-配置Git设置和SSH\"><a href=\"#二-配置Git设置和SSH\" class=\"headerlink\" title=\"二. 配置Git设置和SSH\"></a>二. 配置Git设置和SSH</h2><ul>\n<li>使用下面两个指令配置Git全局设置:</li>\n</ul>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">git config --global user.name "你的用户名"</span><br><span class=\"line\">git config --global user.email "你的邮箱"</span><br></pre></td></tr></table></figure>\n\n<ul>\n<li>配置ssh设置:<a href=\"https://blog.csdn.net/Yaoyao2024/article/details/132123525\">可以参考这个文章</a></li>\n</ul>\n<ol>\n<li>使用 <code>ssh-keygen -t rsa -C "你的邮箱"</code>,一路回车生成SSH。</li>\n<li>找到文件<code>C:\\User\\用户名\\.ssh\\id_rsa.pub</code>,使用记事本打开并复制里面的内容。</li>\n<li>打开GitHub在<code>Settings</code>界面左边找到<code>SSH and GPG keys</code>进入。</li>\n<li>点击 <code>New SSH key</code>,在<code>title</code>中填入合适的标题,在<code>SSH</code>中填入刚刚复制的内容。</li>\n<li>本地指令输入 <code>ssh -T git@github.com</code> 验证是否配置成功。</li>\n</ol>\n<h2 id=\"三-fork库到自己的库中\"><a href=\"#三-fork库到自己的库中\" class=\"headerlink\" title=\"三. fork库到自己的库中\"></a>三. fork库到自己的库中</h2><p>打开 <a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a> 网页,点击右上角 <code>Fork</code> 按钮,复制该库到自己的库中。</p>\n<p>选择<code>owner</code>为自己的账户,<code>Repository name</code>可以设置为默认<code>GameDevWebsite</code>。</p>\n<p><code>Description</code>用来描述这个库,可以随便写一些,例如:VoidGameSpace论坛的Fork库。</p>\n<p>点击 <code>Create fork</code> 按钮。</p>\n<h2 id=\"四-clone库到本地\"><a href=\"#四-clone库到本地\" class=\"headerlink\" title=\"四. clone库到本地\"></a>四. clone库到本地</h2><p>进入自己的库中找到刚刚fork的<code>GameDevWebsite</code>库,一般为 <code>https://github.com/用户名/GameDevWebsite</code></p>\n<p>找到 <code><> Code</code> 绿色按钮,在本地中使用 <code>PowerShell</code> 打开想要部署的位置 or 在部署的位置中右键选择<code>在终端打开</code> or 使用<code>cmd</code> <code>cd</code> 到要部署的文件夹,使用下面三种方式之一克隆库到本地</p>\n<ol>\n<li>使用<code>HTTPS</code>,复制<code>web URL</code>,输入<code>git clone 复制的URL</code>部署。这个方法需要你在终端登录到Git中。</li>\n<li>使用<code>SSH</code>,复制<code>SSH key</code>,输入<code>git clone 复制的SSH_key</code>部署。</li>\n<li>点击<code>Download ZIP</code>,下载压缩包到要部署的文件夹并解压。</li>\n</ol>\n<h2 id=\"五-编写自己的文档\"><a href=\"#五-编写自己的文档\" class=\"headerlink\" title=\"五. 编写自己的文档\"></a>五. 编写自己的文档</h2><p>在部署的项目目录<code>GameDevWebsite</code>中,路径<code>source\\_posts\\</code>创建自己的文件夹,并在文件夹中创建<code>.md</code>文件,参考<a href=\"https://github.com/VoidmatrixHeathcliff/GameDevWebsite\">GitHub库</a>中元数据说明,编写自己的文章。</p>\n<p>另外,markdown的编写可以参考官方文档:<a href=\"https://markdown.com.cn/\">Link</a></p>\n<h2 id=\"六-提交文档到自己fork的库中\"><a href=\"#六-提交文档到自己fork的库中\" class=\"headerlink\" title=\"六. 提交文档到自己fork的库中\"></a>六. 提交文档到自己fork的库中</h2><p>使用 <code>PowerShell</code> 打开项目目录<code>GameDevWebsite</code>,或者在目录中右键点击<code>在终端打开</code>,或者使用<code>cmd</code> <code>cd</code>到目录。</p>\n<ol>\n<li>创建自己的分支(可选,新手建议直接修改<code>main</code>分支):使用 <code>git checkout -b 分支名</code> 创建并切换到新的分支。(分支的作用是保证<code>main</code>分支的干净,一般只有最终版本才会合并到<code>main</code>分支)。如果你已经创建过分支,就不需要再创建该分支了。</li>\n<li>添加所有文件到暂存区: <code>git add .</code></li>\n<li>提交添加的文件: <code>git commit -m "修改描述"</code>。为了养成好习惯,修改描述要有一定的准则。例如你修改文档可以写 <code>"docs(你的名字): 添加了xxx文章"</code>。具体准则可以自行搜索学习一下。</li>\n<li>push库:如果你使用的是新建的分支,使用<code>git push origin 分支名</code> 将新分支push到库中。如果你使用的是<code>main</code>分支或者是已经创建的库,那么使用 <code>git push</code> 将提交的内容push到库中。</li>\n</ol>\n<h2 id=\"七-拉取申请\"><a href=\"#七-拉取申请\" class=\"headerlink\" title=\"七. 拉取申请\"></a>七. 拉取申请</h2><p>找到自己fork的库,点击左上方 <code>Pull requests</code>按钮,进入页面点击右上方<code>New pull request</code>按钮。左边是合并的基库,右边是申请合并的库。在右边申请的库中选择自己的库和分支(如果没有创建分支就选择<code>main</code>),然后填写一些申请描述即可。</p>\n<h2 id=\"八-等待审核\"><a href=\"#八-等待审核\" class=\"headerlink\" title=\"八. 等待审核\"></a>八. 等待审核</h2><p><del>建议留言压力v佬(bushi)</del></p>"}],"PostAsset":[{"_id":"source/_posts/Demo/HelloWorld/avatar.png","post":"clx8n2hg20000o8yegq8i0076","slug":"avatar.png","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏设计知识分享笔记-依赖性/游戏设计知识分享-依赖性-1.png","post":"clx8n2hg80005o8yea1488m2y","slug":"游戏设计知识分享-依赖性-1.png","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Blue_Joker.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Blue_Joker.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Cavendish.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Cavendish.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Four_Fingers.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Four_Fingers.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Golden_Joker.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Golden_Joker.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Hanging_Chad.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Hanging_Chad.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Joker.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Joker.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Photograph.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Photograph.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/Smiley_Face.webp","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"Smiley_Face.webp","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/四指同花顺.png","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"四指同花顺.png","modified":1,"renderable":1},{"_id":"source/_posts/FlyingfishFantasticfan/游戏评测-Balatro小丑牌/计分板.png","post":"clx8n2hg90009o8ye3b9e4vsg","slug":"计分板.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/OpenEasing/-1e69599c03b67f3a.jpg","post":"clx8n2hgf000lo8ye6hli2vre","slug":"-1e69599c03b67f3a.jpg","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/OpenEasing/OpenEasing.png","post":"clx8n2hgf000lo8ye6hli2vre","slug":"OpenEasing.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/Camera2D/1.gif","post":"clx8n2hga000eo8ye55wzathg","slug":"1.gif","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/Camera2D/2.png","post":"clx8n2hga000eo8ye55wzathg","slug":"2.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/1.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"1.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/10.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"10.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/11.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"11.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/12.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"12.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/123415231.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"123415231.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/13.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"13.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/14.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"14.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/15.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"15.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/16.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"16.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/17.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"17.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/18.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"18.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/19.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"19.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/2.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"2.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/20.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"20.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/21.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"21.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/22.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"22.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/23.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"23.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/24.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"24.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/25.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"25.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/26.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"26.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/27.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"27.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/28.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"28.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/3.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"3.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/4.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"4.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/5.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"5.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/6.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"6.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/7.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"7.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/8.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"8.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/CorrectlyReleased/9.png","post":"clx8n2hga000go8ye6epw1ygl","slug":"9.png","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/Iamme/1.jpg","post":"clx8n2hgf000ko8ye18hp6oh1","slug":"1.jpg","modified":1,"renderable":1},{"_id":"source/_posts/QiNuoTu/Iamme/2.png","post":"clx8n2hgf000ko8ye18hp6oh1","slug":"2.png","modified":1,"renderable":1},{"_id":"source/_posts/shuo-liu16/deploy-Hexo-2024-04-10/1.png","post":"clx8n2hgk0018o8yecnntceft","slug":"1.png","modified":1,"renderable":1},{"_id":"source/_posts/shuo-liu16/deploy-Hexo-2024-04-10/2.png","post":"clx8n2hgk0018o8yecnntceft","slug":"2.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/101894421252079.gif","post":"clx8n2hgh000ro8ye7fyj2j4x","slug":"101894421252079.gif","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/231573721246935.png","post":"clx8n2hgh000ro8ye7fyj2j4x","slug":"231573721246935.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/294884321256325.gif","post":"clx8n2hgh000ro8ye7fyj2j4x","slug":"294884321256325.gif","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/338824221259770.gif","post":"clx8n2hgh000ro8ye7fyj2j4x","slug":"338824221259770.gif","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/Boids集群算法浅析与实践/403754021267101.png","post":"clx8n2hgh000ro8ye7fyj2j4x","slug":"403754021267101.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/125364318267564.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"125364318267564.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/151655416259069.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"151655416259069.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/161600919246307.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"161600919246307.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/202434217267102.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"202434217267102.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/532531818252080.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"532531818252080.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/553721218256326.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"553721218256326.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/59555018265066.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"59555018265066.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/76072812230849.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"76072812230849.png","modified":1,"renderable":1},{"_id":"source/_posts/Voidmatrix/程序化游戏地图生成浅析(一)/87331419268747.png","post":"clx8n2hgi000yo8yedk2m781a","slug":"87331419268747.png","modified":1,"renderable":1},{"_id":"source/_posts/suang/Aboutme/suang.png","post":"clx8n2hgl001do8yeeffv3tdm","slug":"suang.png","modified":1,"renderable":1},{"_id":"source/_posts/suang/Aboutme/who_am_I.png","post":"clx8n2hgl001do8yeeffv3tdm","slug":"who_am_I.png","modified":1,"renderable":1},{"_id":"source/_posts/suang/publish_article/fork_img.png","post":"clx8n2hgm001jo8ye2klu8hcu","slug":"fork_img.png","modified":1,"renderable":1},{"_id":"source/_posts/suang/publish_article/image_pos.png","post":"clx8n2hgm001jo8ye2klu8hcu","slug":"image_pos.png","modified":1,"renderable":1}],"PostCategory":[{"post_id":"clx8n2hg20000o8yegq8i0076","category_id":"clx8n2hg50001o8yea90f4i5q","_id":"clx8n2hg9000bo8ye52lh0se6"},{"post_id":"clx8n2hg70003o8yeemdx6k4n","category_id":"clx8n2hg80006o8yeewzpfvxv","_id":"clx8n2hgb000ho8ye6fg89vc1"},{"post_id":"clx8n2hg70004o8yeabnyg1ae","category_id":"clx8n2hg9000co8ye8gtq5k5g","_id":"clx8n2hgg000no8yeaqbp4fsd"},{"post_id":"clx8n2hg80005o8yea1488m2y","category_id":"clx8n2hg9000co8ye8gtq5k5g","_id":"clx8n2hgh000to8yeffay3msq"},{"post_id":"clx8n2hg90009o8ye3b9e4vsg","category_id":"clx8n2hg9000co8ye8gtq5k5g","_id":"clx8n2hgi000zo8yeb3vs9tms"},{"post_id":"clx8n2hg9000ao8yebxc71iym","category_id":"clx8n2hgh000so8ye43vv9vin","_id":"clx8n2hgj0016o8ye333i250y"},{"post_id":"clx8n2hga000eo8ye55wzathg","category_id":"clx8n2hgi0010o8ye3b0i5mnm","_id":"clx8n2hgl001fo8ye44la9x27"},{"post_id":"clx8n2hga000go8ye6epw1ygl","category_id":"clx8n2hgi0010o8ye3b0i5mnm","_id":"clx8n2hgm001lo8ye6gax14qv"},{"post_id":"clx8n2hgf000ko8ye18hp6oh1","category_id":"clx8n2hgi0010o8ye3b0i5mnm","_id":"clx8n2hgn001oo8ye2bntda6e"},{"post_id":"clx8n2hgf000lo8ye6hli2vre","category_id":"clx8n2hgi0010o8ye3b0i5mnm","_id":"clx8n2hgo001so8ye1qi61oq6"},{"post_id":"clx8n2hgg000po8ye0cbe7qrr","category_id":"clx8n2hgi0010o8ye3b0i5mnm","_id":"clx8n2hgo001wo8ye26rv121q"},{"post_id":"clx8n2hgh000ro8ye7fyj2j4x","category_id":"clx8n2hgo001ro8ye7h744ueg","_id":"clx8n2hgo0020o8ye3eqc39zg"},{"post_id":"clx8n2hgh000vo8ye3fv08lzg","category_id":"clx8n2hgo001xo8ye589taadj","_id":"clx8n2hgp0027o8ye8zkhhnaf"},{"post_id":"clx8n2hgi000yo8yedk2m781a","category_id":"clx8n2hgo001ro8ye7h744ueg","_id":"clx8n2hgp0029o8ye5gvj2u8i"},{"post_id":"clx8n2hgi0012o8yebtfgesnl","category_id":"clx8n2hgp0026o8yegryw9g2u","_id":"clx8n2hgq002do8ye8hi7fxjz"},{"post_id":"clx8n2hgj0015o8ye980e2j2j","category_id":"clx8n2hgp002bo8yegnfp6dcm","_id":"clx8n2hgq002go8ye5swl2zsx"},{"post_id":"clx8n2hgk0018o8yecnntceft","category_id":"clx8n2hgq002eo8yefriq959i","_id":"clx8n2hgr002jo8ye0wt238ha"},{"post_id":"clx8n2hgk001bo8yeemd78tcv","category_id":"clx8n2hgq002ho8ye2piw2uzd","_id":"clx8n2hgr002po8ye4z3l5xrm"},{"post_id":"clx8n2hgl001do8yeeffv3tdm","category_id":"clx8n2hgr002lo8ye42fa681j","_id":"clx8n2hgs002to8ye9snn90t9"},{"post_id":"clx8n2hgm001io8ye5rbnald2","category_id":"clx8n2hgr002lo8ye42fa681j","_id":"clx8n2hgs002vo8ye1mqv5rq2"},{"post_id":"clx8n2hgm001jo8ye2klu8hcu","category_id":"clx8n2hgr002lo8ye42fa681j","_id":"clx8n2hgs002yo8ye8aswftwx"},{"post_id":"clx8n2hgw003oo8yeh89ohgvt","category_id":"clx8n2hgx003qo8yehj5hdmre","_id":"clx8n2hgy003xo8ye5dkldh2w"},{"post_id":"clx8n2hgx003po8ye39c50tl1","category_id":"clx8n2hgy003uo8ye9xgm7r7i","_id":"clx8n2hgz0040o8ye1rht2vox"},{"post_id":"clx8n2hgx003so8ye8ozq9748","category_id":"clx8n2hgy003uo8ye9xgm7r7i","_id":"clx8n2hgz0042o8ye9hnv4ky4"}],"PostTag":[{"post_id":"clx8n2hg20000o8yegq8i0076","tag_id":"clx8n2hg60002o8yeerxpcugc","_id":"clx8n2hg80008o8ye1kh25241"},{"post_id":"clx8n2hg70003o8yeemdx6k4n","tag_id":"clx8n2hg80007o8ye9mvlda35","_id":"clx8n2hga000fo8ye38h1bqbv"},{"post_id":"clx8n2hgf000lo8ye6hli2vre","tag_id":"clx8n2hg60002o8yeerxpcugc","_id":"clx8n2hgh000qo8ye1ko42bec"},{"post_id":"clx8n2hgg000po8ye0cbe7qrr","tag_id":"clx8n2hg60002o8yeerxpcugc","_id":"clx8n2hgh000uo8ye9qp2cks7"},{"post_id":"clx8n2hg70004o8yeabnyg1ae","tag_id":"clx8n2hga000do8ye3w4gcr2g","_id":"clx8n2hgi000xo8ye1x2o55ds"},{"post_id":"clx8n2hg70004o8yeabnyg1ae","tag_id":"clx8n2hgb000jo8ye2n9z7mid","_id":"clx8n2hgi0011o8ye3xecgp5i"},{"post_id":"clx8n2hg70004o8yeabnyg1ae","tag_id":"clx8n2hgg000oo8ye5o9r7t0h","_id":"clx8n2hgj0014o8yed3qt8ck7"},{"post_id":"clx8n2hgh000vo8ye3fv08lzg","tag_id":"clx8n2hgg000oo8ye5o9r7t0h","_id":"clx8n2hgk0017o8yedqm08wd2"},{"post_id":"clx8n2hg80005o8yea1488m2y","tag_id":"clx8n2hgh000wo8ye068v8eo0","_id":"clx8n2hgl001co8ye2vtbbwf2"},{"post_id":"clx8n2hg80005o8yea1488m2y","tag_id":"clx8n2hgb000jo8ye2n9z7mid","_id":"clx8n2hgl001go8ye6sunf5sz"},{"post_id":"clx8n2hg90009o8ye3b9e4vsg","tag_id":"clx8n2hgk001ao8ye8y0w1grp","_id":"clx8n2hgn001qo8ye5zi4c9l7"},{"post_id":"clx8n2hg90009o8ye3b9e4vsg","tag_id":"clx8n2hgm001ho8ye2c8uh83h","_id":"clx8n2hgo001to8ye3nwmd8f5"},{"post_id":"clx8n2hg90009o8ye3b9e4vsg","tag_id":"clx8n2hgn001mo8yeg52885ta","_id":"clx8n2hgo001vo8yecn29cou5"},{"post_id":"clx8n2hg9000ao8yebxc71iym","tag_id":"clx8n2hgn001po8yeazys4ju9","_id":"clx8n2hgo001yo8yehqmkdmi4"},{"post_id":"clx8n2hga000eo8ye55wzathg","tag_id":"clx8n2hgo001uo8yec8jw5fcn","_id":"clx8n2hgp0021o8ye1fcs9t3x"},{"post_id":"clx8n2hga000eo8ye55wzathg","tag_id":"clx8n2hg60002o8yeerxpcugc","_id":"clx8n2hgp0023o8ye7zgc9fv0"},{"post_id":"clx8n2hga000go8ye6epw1ygl","tag_id":"clx8n2hgo001uo8yec8jw5fcn","_id":"clx8n2hgp0025o8ye4ymb8yau"},{"post_id":"clx8n2hgf000ko8ye18hp6oh1","tag_id":"clx8n2hgp0024o8ye04wq48e9","_id":"clx8n2hgp002ao8ye76ktf77k"},{"post_id":"clx8n2hgh000ro8ye7fyj2j4x","tag_id":"clx8n2hgp0028o8ye46rd8rdx","_id":"clx8n2hgr002ko8ye0l7c67o0"},{"post_id":"clx8n2hgh000ro8ye7fyj2j4x","tag_id":"clx8n2hgq002co8yeaqk85e5o","_id":"clx8n2hgr002mo8ye3pp86a29"},{"post_id":"clx8n2hgh000ro8ye7fyj2j4x","tag_id":"clx8n2hgq002fo8ye6nxkajhg","_id":"clx8n2hgr002oo8yedekv0m2w"},{"post_id":"clx8n2hgi000yo8yedk2m781a","tag_id":"clx8n2hgp0028o8ye46rd8rdx","_id":"clx8n2hgs002xo8ye13l8b0fq"},{"post_id":"clx8n2hgi000yo8yedk2m781a","tag_id":"clx8n2hgq002co8yeaqk85e5o","_id":"clx8n2hgs002zo8yecuh88k0b"},{"post_id":"clx8n2hgi000yo8yedk2m781a","tag_id":"clx8n2hgq002fo8ye6nxkajhg","_id":"clx8n2hgt0031o8ye3xzvb9w6"},{"post_id":"clx8n2hgi000yo8yedk2m781a","tag_id":"clx8n2hgs002uo8ye4e4qgpq9","_id":"clx8n2hgt0032o8ye43f28wr1"},{"post_id":"clx8n2hgi0012o8yebtfgesnl","tag_id":"clx8n2hgs002wo8ye0ffxgkml","_id":"clx8n2hgt0034o8yehtivawkj"},{"post_id":"clx8n2hgj0015o8ye980e2j2j","tag_id":"clx8n2hgn001po8yeazys4ju9","_id":"clx8n2hgt0035o8ye9vfphupt"},{"post_id":"clx8n2hgk0018o8yecnntceft","tag_id":"clx8n2hgt0033o8ye2w9s28sa","_id":"clx8n2hgt0037o8yee7427g0y"},{"post_id":"clx8n2hgk001bo8yeemd78tcv","tag_id":"clx8n2hgt0036o8ye3no3fict","_id":"clx8n2hgt0039o8yediihday3"},{"post_id":"clx8n2hgl001do8yeeffv3tdm","tag_id":"clx8n2hgt0038o8ye8rzt893m","_id":"clx8n2hgu003bo8ye385h2cl0"},{"post_id":"clx8n2hgl001do8yeeffv3tdm","tag_id":"clx8n2hgg000oo8ye5o9r7t0h","_id":"clx8n2hgu003co8ye7dmf7a1w"},{"post_id":"clx8n2hgm001io8ye5rbnald2","tag_id":"clx8n2hgt003ao8yehu6o6rov","_id":"clx8n2hgu003go8ye8b7m7taj"},{"post_id":"clx8n2hgm001io8ye5rbnald2","tag_id":"clx8n2hgu003do8ye6tty88sz","_id":"clx8n2hgu003ho8yeapo6dzfg"},{"post_id":"clx8n2hgm001io8ye5rbnald2","tag_id":"clx8n2hgp0028o8ye46rd8rdx","_id":"clx8n2hgv003jo8ye6kl82l79"},{"post_id":"clx8n2hgm001jo8ye2klu8hcu","tag_id":"clx8n2hgt0038o8ye8rzt893m","_id":"clx8n2hgv003lo8yegsrebgvx"},{"post_id":"clx8n2hgm001jo8ye2klu8hcu","tag_id":"clx8n2hgo001uo8yec8jw5fcn","_id":"clx8n2hgv003mo8yedntdbxzs"},{"post_id":"clx8n2hgm001jo8ye2klu8hcu","tag_id":"clx8n2hgv003ko8ye5880dtom","_id":"clx8n2hgv003no8ye3ghqfs0m"},{"post_id":"clx8n2hgx003po8ye39c50tl1","tag_id":"clx8n2hgg000oo8ye5o9r7t0h","_id":"clx8n2hgy003to8ye8tnv6vf3"},{"post_id":"clx8n2hgw003oo8yeh89ohgvt","tag_id":"clx8n2hgx003ro8ye58o9akgw","_id":"clx8n2hgy003wo8yecrv45lx9"},{"post_id":"clx8n2hgx003so8ye8ozq9748","tag_id":"clx8n2hgy003vo8ye5dtb0ksq","_id":"clx8n2hgz0041o8ye8piugw7u"},{"post_id":"clx8n2hgx003so8ye8ozq9748","tag_id":"clx8n2hgy003zo8ye2t71gbff","_id":"clx8n2hgz0043o8yed52a92ov"},{"post_id":"clx8n2hgx003so8ye8ozq9748","tag_id":"clx8n2hga000do8ye3w4gcr2g","_id":"clx8n2hgz0044o8yehf2ihd66"}],"Tag":[{"name":"游戏开发","_id":"clx8n2hg60002o8yeerxpcugc"},{"name":"测试测试测试测试测试","_id":"clx8n2hg80007o8ye9mvlda35"},{"name":"Git","_id":"clx8n2hga000do8ye3w4gcr2g"},{"name":"学习","_id":"clx8n2hgb000jo8ye2n9z7mid"},{"name":"自我介绍","_id":"clx8n2hgg000oo8ye5o9r7t0h"},{"name":"游戏设计","_id":"clx8n2hgh000wo8ye068v8eo0"},{"name":"游戏评测","_id":"clx8n2hgk001ao8ye8y0w1grp"},{"name":"小丑牌","_id":"clx8n2hgm001ho8ye2c8uh83h"},{"name":"Balatro","_id":"clx8n2hgn001mo8yeg52885ta"},{"name":"测试","_id":"clx8n2hgn001po8yeazys4ju9"},{"name":"教程","_id":"clx8n2hgo001uo8yec8jw5fcn"},{"name":"闲聊","_id":"clx8n2hgp0024o8ye04wq48e9"},{"name":"EasyX","_id":"clx8n2hgp0028o8ye46rd8rdx"},{"name":"算法","_id":"clx8n2hgq002co8yeaqk85e5o"},{"name":"C++","_id":"clx8n2hgq002fo8ye6nxkajhg"},{"name":"PCG","_id":"clx8n2hgs002uo8ye4e4qgpq9"},{"name":"勘误","_id":"clx8n2hgs002wo8ye0ffxgkml"},{"name":"hexo","_id":"clx8n2hgt0033o8ye2w9s28sa"},{"name":"hszSoft","_id":"clx8n2hgt0036o8ye3no3fict"},{"name":"suang","_id":"clx8n2hgt0038o8ye8rzt893m"},{"name":"c++","_id":"clx8n2hgt003ao8yehu6o6rov"},{"name":"编码","_id":"clx8n2hgu003do8ye6tty88sz"},{"name":"发表文章","_id":"clx8n2hgv003ko8ye5880dtom"},{"name":"游戏心得","_id":"clx8n2hgx003ro8ye58o9akgw"},{"name":"VoidGameSpace","_id":"clx8n2hgy003vo8ye5dtb0ksq"},{"name":"Hexo","_id":"clx8n2hgy003zo8ye2t71gbff"}]}}