这是我用不到 370 行代码,从零开始控制台创建 Win32 窗口,再挂上交换链,在窗口上使用 D2D 绘制界面内容。最后使用 AOT 方式发布的测试应用。成品文件体积不超过 10MB 且运行内存稳定在 60MB 以内,满帧率运行但 CPU 近乎不动
整个测试应用采用了 .NET 8 的框架,用于更好的支持 AOT 发布
使用了 Vortice 系列库用于对 DirectX 的封装,方便让编写调用 DirectX 的代码
使用了 Microsoft.Windows.CsWin32 方便进行 Win32 方法的调用
所有的代码都写在 Program.cs 文件里面,代码长度不到 370 行,更有趣的是,可以强行算是都写在 Main 方法里面,由 Main 方法以及放在 Main 方法里面的局部方法构成。整体实现非常简单。我将会在本文末尾告诉大家本文的代码的下载方法
本文仅仅是分享我的开发经验,不包含 DirectX 的前置知识。如果不熟悉 D2D 和 DirectX 还请以看着玩的心态阅读本文
一开始采用了 DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色 和 dotnet DirectX 通过 Vortice 控制台使用 ID2D1DeviceContext 绘制画面 博客提供的方法搭建了基础的应用框架
为了让界面更加的丰富,我准备在界面添加多个圆形。然后为了让界面动起来,我添加了名为 DrawingInfo 的结构体,用于存放每个圆形的坐标和大小等信息
readonly record struct DrawingInfo(System.Numerics.Vector2 Offset, Size Size, D2D.ID2D1SolidColorBrush Brush);
先在绘制的循环外对 DrawingInfo 进行随机设置值
var ellipseInfoList = new List<DrawingInfo>();
for (int i = 0; i < 3000; i++)
{
// 随意创建颜色
var color = new Color4((byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255), (byte) Random.Shared.Next(255));
D2D.ID2D1SolidColorBrush brush = renderTarget.CreateSolidColorBrush(color);
ellipseInfoList.Add(new DrawingInfo(new System.Numerics.Vector2(Random.Shared.Next(clientSize.Width), Random.Shared.Next(clientSize.Height)), new Size(Random.Shared.Next(10, 100)), brush));
}
进入循环之后,再每次修改 Offset 的值,这样就可以让每次绘制的圆形动起来
while (true)
{
// 开始绘制逻辑
renderTarget.BeginDraw();
// 清空画布
renderTarget.Clear(new Color4(0xFF, 0xFF, 0xFF));
// 在下面绘制漂亮的界面
for (var i = 0; i < ellipseInfoList.Count; i++)
{
var drawingInfo = ellipseInfoList[i];
var vector2 = drawingInfo.Offset;
vector2.X += Random.Shared.Next(200) - 100;
vector2.Y += Random.Shared.Next(200) - 100;
while (vector2.X < 100 || vector2.X > clientSize.Width - 100)
{
vector2.X = Random.Shared.Next(clientSize.Width);
}
while (vector2.Y < 100 || vector2.Y > clientSize.Height - 100)
{
vector2.Y = Random.Shared.Next(clientSize.Height);
}
ellipseInfoList[i] = drawingInfo with { Offset = vector2 };
// 忽略其他代码
}
// 忽略其他代码
}
以上的修改坐标代码只是为了让圆形每次都在其附近移动
附带就在里层循环将每个圆形绘制,代码如下
// 在下面绘制漂亮的界面
for (var i = 0; i < ellipseInfoList.Count; i++)
{
// 忽略其他代码
renderTarget.FillEllipse(new D2D.Ellipse(vector2, drawingInfo.Size.Width, drawingInfo.Size.Height), drawingInfo.Brush);
}
大概的改动如此,接下来咱需要改造一下 csproj 项目文件,让此项目可以构建出 AOT 版本的应用
先修改 TargetFramework 为 net8.0 使用 .NET 8 可以更好构建 AOT 应用
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
接着为了减少不断提示的平台警告,添加以下代码忽略 CA1416 警告
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<NoWarn>CA1416</NoWarn>
</PropertyGroup>
接着再添加 PublishAot 属性,这样调用发布命令之后,就可以自动创建 AOT 应用的文件
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<NoWarn>CA1416</NoWarn>
<PublishAot>true</PublishAot>
</PropertyGroup>
此时运行起来将不会成功,将会提示大概如下的错误
Unhandled Exception: System.MissingMethodException: No parameterless constructor defined for type 'Vortice.DXGI.IDXGIFactory2'.
at System.ActivatorImplementation.CreateInstance(Type, BindingFlags, Binder, Object[], Cultu