考古XNA,上手FNA

前言

        最近灵感枯竭,精力不再,想什么都想不出来,于是就想随便学点什么东西。回想起这段时间真的是被游戏程序框架搞郁闷了,因为看不到Godot的全部(其实看得到,但是懒得看,看了也动不了),然后加上自己才疏识浅,想破脑袋也想不出能很好适配Godot的程序框架。

        于是动了不用引擎做游戏的念头。其实我也早就这么干过了,不过当时是用C++写的,写得一坨,后面当然还是老老实实用游戏引擎开发。直到我玩了蔚蓝Celeste,在游戏初次启动时,我不经意间瞟到Steam正在帮我下载XNA的一些支持,这玩意也就是蔚蓝使用的游戏框架。

        这就是我第一次遇见它,然后感兴趣搜了一下发现是个做游戏的玩意,但是已经很老了,而且停止维护了。

        再后来,也就是最近几天,我一直在网上高强度搜索游戏程序框架企图收集“灵感”。结果就在知乎的某个评论里看到了XNA这个字眼,然后更关键的是它的“孩子”——FNA。

        FNA很有意思,我看着像是一个孤傲的开发者捍卫自己的爱好而诞生的产物,具体一点可以直接去FNA的官网看看。总而言之FNA尽可能保留了和XNA相同的API,但是底层做了不少重写,可以很好帮助XNA项目移植。

        其实XNA还有另一个“孩子”,MonoGame。而且似乎比FNA要更出名,虽然FNA更XNA名字接近,但是内在改了不少,主打一个叛逆,尤其是在XNA原本那个被FNA作者怒喷的ContentPipline上面,这玩意简单来讲就是用来管理游戏资源的。MonoGame的选择是继承并发扬XNA的衣钵,而FNA则是尽力摆脱ContentPipline,转向支持原生的文件格式。我也是因为这个在MonoGame和FNA两者之间选择了后者。

        为什么是FNA?首先因为用C#习惯了,不想用C++,其次是引擎用烦了,想找罪受。好吧,其实本质目的是想看看自己的一些想法能不能实现,包括但不限于一些游戏程序设计理念,所以不想受引擎限制,转而尝试使用轻量级的游戏框架。

FNA基操

1.获取

        FNA的创始人非常有个性,不愿意用Nuget包,所以大家需要自行去Github上扒下来。这个过程还是比较简单的,略了。

        值得一提的是,FNA建议大家不要build库,直接甩到解决方案里面跟着一起build。我个人也是觉得最好直接把项目复制(克隆)一份到自己项目的文件夹下,不仅因为可以看源码,还能更好的调整各个csproj之间的引用,这一点很重要,因为跟其他库的使用有关,比如后面会介绍的FontStashSharp库。

2.创建项目

        我用的是VSCode开发,没有用到VS,不过如果连VSCode都能配置好,那VS肯定更简单好吧。

        首先,新建文件夹。

        然后按照个人喜欢准备好项目结构。我个人是喜欢这样子:这是一个VSCode工作区,我把FNA一整个项目,我的实际项目,还有引用FNA的其他项目,放在一同级目录。

        然后在一个解决方案中,添加这些项目。如果你不知道解决方案到底有什么用,那么恭喜你,我也不知道。我只知道它是用来方便项目管理的,就像我们这种有多个项目的情况。

        总之先把这些个项目都加到解决方案里面吧。 可以直接控制台:

dotnet sln add <csproj_path>

        也可以在VSCode中手动添加引用,就像在VS里一样(等等,你应该不会没装.NET的拓展吧?!)。 

        需要注意的是,现在.NET8.0时代我们需要添加的FNA项目是FNA.Core.csproj。其他的是用于低版本或者VS的。

        最后记得在你的游戏项目中引用 FNA.Core.csproj:

        可以在.csproj里加上几个项(Item):

<ItemGroup>
    <ProjectReference Include = <FNA.Core.csproj相对于该项目的路径> />
</ItemGroup>

        当然同样可以可视化操作:

        然后项目就配置好了!试着写几行代码:

using Microsoft.Xna.Framework;

namespace MyGame
{
    public class MyGame : Game
    {        
        private GraphicsDeviceManager gdm;
        
        public MyGame()
        {            
            gdm = new GraphicsDeviceManager(this);
            gdm.PreferredBackBufferWidth = 1280;
            gdm.PreferredBackBufferHeight = 720;

            Content.RootDirectory = "res";
        }    

        [STAThread]
        public static void Main()
        {
            using MyGame game = new();
            game.Run();
        }
    }
}

        启动!

        然后就崩了。

        因为你还没有添加FNA用到的Bin:比如x64用到的是下面这几位。

        你可以自己准备,也可以很逆天地从创始人的个人网页上扒下来。 

        具体操作只要跟着FNA的官方文档进行就好了,我这里只做简述。

        在把所需的bin放在输出目录后,再次运行不出意外的话应该没什么问题了,吧。

3.运行与调试        

        VSCode的调试比较麻烦,如果它提示你没有加载C#项目的话,可以用下面这个指令:

        生成一下用于调试的配置。 

        当然你可以直接Build!甚至publish!

dotnet build
dotnet publish

        更复杂的指令请自己去参考文档吧,因为我实在记不清了! 

FNA使用体验

1.非常不推荐

         以下人群适合使用FNA开发:

        1.经验丰富的高技术开发者;

        2.喜欢《从零开始的游戏世界生活》的开发者(轮子人)。

        3.自讨苦吃的白痴;

        4.具有SM倾向的受虐狂;

        我是第3个。

        为什么这么说呢?因为FNA真的很难上手,尤其新手开发者。首先一个很重要的问题:

        FNA没有官方API文档,是的,它只有官方文档,没有API文档。或者说没有“FNA的文档”,

因为FNA是XNA的延续,我们可以参考XNA的文档:

Writing Game Code | Microsoft Learn

这只是其中一个,因为实在是太太太难找到了,XNA是十几年前的东西了,所以FNA的使用者在FNA官方看来都是一些老手了,它们在FNA文档里也提到让新手开发者放弃使用FNA,所以大家见仁见智,如果是新手的话还是得听劝,节省时间。

2.清晰又折磨

        FNA的框架很清晰,没什么难用的,再配合上C#的简洁语法。在某种程度上也是有开发优势的。前提是你能忍受没有可视化编辑,没有调试,没有UI控件,没有字体支持......

        真的是给了多大的自由就有多大的限制。

        好就好在,这回的游戏逻辑可就真正的由你做主了,每一帧怎么渲染,物理怎么更新都得自己设计好,没有了游戏引擎的便利同时失去了它们的冗杂,这大概就是轻量级的魅力吧。

        我这里并不打算多讲怎么写游戏逻辑,FNA已经讲清楚了,能用上FNA的人应该都有自己的想法。

3.开发优势

        因为FNA的引用方式是直接COPY到项目文件夹里,所以我们可以很方便的查看,修改源代码,这点对于我这种控制狂来讲是福音。

        虽然平时不喜欢改源码,不过想到这只是个几十兆的小项目,随便复制随便改,大不了就再从Github上再扒下来一次。所以可以畅快的乱改源码,再加上C#编译优势,应该是可以比C++编译好受些,不会太慢的。

        所以FNA开发优势最主要的就是一览无余,自由自在,同样也是最大劣势。

FNA使用技巧

1.FontStashSharp               

         这是一个C#封装的库,主要用于字体渲染。为什么我要提一嘴这个呢,因为我在使用FNA是发现FNA不支持ttf字体加载啊啊啊,所以找了半天,找到了这个库,做游戏没有字体实属难受。

        这个库不是专门用于FNA的,但是它里面有专门的一个csproj可以拓展FNA。再具体一点可以自己去GitHub上看看。

        具体的使用方法就是和FNA一样把整个文件夹扔到游戏项目文件夹里,跟FNA不同,因为需要拓展的是FNA的内容,所以这个csproj必须持有对FNA的引用,比如这里它需要引用FNA.Core.csproj,才能正常运行,不然就等着一顿报错吧。

        一定一定要注意设置好正确的引用!!!

        可以直接点开它们的csproj看看它们到底有没有引用到FNA,如果没有,可以直接修改,和上面说的一样,反正都是COPY过来的,改了也不心疼。

        所以其实怎么拜访这些文件夹都无所谓,只要确定好引用关系就好了。

2.资源管理

        FNA开发需要指定一个文件夹作为资源文件夹,导出(这里应该说build或publish)后的exe也需要能找到这个文件夹。所以我们需要一个好的手段来协助我们导出资源,当然你也可以每次build完后复制粘贴。

        这里我推荐的是直接配置项目文件:        

<ItemGroup>
    <ProjectReference Include="..\FNA\FNA.Core.csproj" />
    <ProjectReference Include="..\FontStashSharp-main\src\XNA\FontStashSharp.FNA.Core.csproj" />    

    <Content Include = "*.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <None Update = "res\**">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
</ItemGroup>

前两个Item是项目引用,Content和None都是MSbuild预留Item,重点是里面的内容,Include = " *.dll' ",意味着包含所有.dll文件,然后 <CopyToOutputDirectory> 故名思意就是复制到输出目录。

具体的含义请参考官方文档。总而言之,我们可以通过这种手段协助导出项目时资源跟依赖一起导出,就像游戏引擎一样。

3.导出配置

        .NET的导出还是挺有说法的,下面是我认为比较简单的一种适合游戏应用的导出属性配置:

<PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>disable</Nullable>    
    <PublishTrimmed>true</PublishTrimmed>    
    <PublishAot>true</PublishAot>
    <DebugType>None</DebugType>
    <DebugSymbols>false</DebugSymbols>
    <Optimize>true</Optimize>    
</PropertyGroup>

        上面的OutType,如果是控制台程序Exe,发布后打开游戏仍会打开控制台,如过你像保留到导出后DEBUG用,那可以给PropertyGroup加条件:

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

        然后构建时会根据条件变化。 

        这里我还用到了AOT,也是非常适合C#游戏程序,也是借助.NET的优势了。

4.修改图标

        如果你也有Godot开发经历,肯定会对Rcedit有印象,这个东西是一个开源工具,主要用于修改Windows的PE等。

        Godot就是用它来修改游戏的图标的,哦对了,还有一个工具ImageMagick,可以用来生成.ico文件。两者结合起来就可以像Godot一样修改我们exe的图标了。

        可以试着写一个小程序规范化这个过程,就像Godot为我们做的那样。

结语

        FNA是真的新手劝退,我之前没有死磕FNA现在看来相当明知,只有在了解足够的游戏引擎之后才会想着自己实现一些东西,所以适合对自己游戏需求比较清晰,对游戏引擎理解比较全面的开发者。

        反正不是我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moweiii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值