Win2D 是 DirectX 的一个高层封装,提供了极大 DirectX 性能的同时,又具有很好用的 API 设计。

用 Win2D 除了能做出高性能的视觉效果之外,还可以轻而易举地搭建一个游戏循环出来。使用 Win2D 的游戏循环,你可以直接做出一个简单的游戏出来。


使用 Win2D 做出来的游戏

我在 GitHub 上开源了我正在做的一个基于 Win2D 的小游戏 —— GravityMaze,可以翻译为重力迷宫。本意是使用手机的重力感应器借助于自然重力的方式玩这款游戏,不过考虑到 Windows 10 Mobile 的手机太少,用户数量太少,其实我还是直接展示 UWP 桌面版好了。使用方向键可以控制桌面的倾斜角度,以便间接控制小球的运动方向。

当然,我自己是有一部 Lumia 950XL 的,你可以在 使用 Windows 10 中的加速度计(Accelerometer,重力传感器) 一文中看到它的身影。


▲ 重力迷宫

这张图的红色背景是我自己拍摄的,所以绝不可能存在版权问题。

准备工作

要使用 Win2D 进行简单的游戏开发,你需要先配置好一些 UWP 的开发环境,并且在你的项目中安装 Win2D.uwp 的 NuGet 包。阅读 win10 uwp win2d 入门 看这一篇就够了 - 林德熙 了解如何在你的项目中安装 Win2D,并且了解 Win2D 基本的知识。

Win2D 中的画布控件

Win2D 中的画布有 CanvasControlCanvasVirtualControlCanvasAnimatedControl

  • CanvasControl 用于进行一次性绘制,或者那些不常更新的画面内容。例如进行软件的 UI 绘制,或者软件中所得图形的绘制。
  • CanvasVirtualControl 适用于在一个很大的画面中,只显示一个小部分的情况。例如显示大地图的一部分,或者显示大量超界的笔迹内容。
  • CanvasAnimatedControl 适用于显示频繁更新的画面。典型的例子就是游戏。

CanvasAnimatedControl

我们使用 CanvasAnimatedControl 来做游戏循环,因为这是 Win2D 这几个控件中最适合做游戏循环的控件了。

要在你的项目中使用 CanvasAnimatedControl,你需要在 XAML 中添加 using:Microsoft.Graphics.Canvas.UI.Xaml

  1. <Page x:Class="Walterlv.GravityMaze.Pages.GamePage"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml">
  5. <xaml:CanvasAnimatedControl Update="OnUpdate" Draw="OnDraw" />
  6. </Page>

然后,我们订阅 CanvasAnimatedControl 的两个事件:

  • Update

    • 用于更新游戏中的数据,更新参考的是游戏时间线。
  • Draw
    • 用于绘制游戏的内容。

这是游戏循环最必要的两个事件了,其他虽然也是需要的,但也可以不写。

  1. private MazeGame _game;
  2. private void OnUpdate(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs e)
  3. {
  4. // 根据时间线更新游戏数据。
  5. _game.Update(e.Timing);
  6. }
  7. private void OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs e)
  8. {
  9. // 绘制游戏画面。
  10. using (var ds = e.DrawingSession)
  11. {
  12. _game.Draw(ds);
  13. }
  14. }

CanvasAnimatedControl 在游戏中的使用

你在我的 GamePage 中其实看不到对 UpdateDraw 事件的实际使用,因为我把它们都封装到了 MazeGame 中了。

有些信息需要注意:

  1. UpdateDraw 运行于相同的线程,但都不是主线程;所以你不可以从这里去获取主线程中的 UI 资源。
  2. 正常情况下 Update 调用一次之后,Draw 就会调用一次;但如果当前运行缓慢,那么多次 Update 调用之后才会调用一次 Draw
  3. 如果 UWP 窗口最小化了,那么只会调用 Update 方法,而不会调用 Draw 方法。


▲ 线程

在 GravityMaze 重力迷宫中,主要是 Player 也就是你在上面动图中看到的那个小球需要在 Update 中更新数据,其他其实只需要画就好了。Update 中我需要计算速度、加速度以及进行碰撞检测。

  1. private void OnUpdate(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs e)
  2. {
  3. var seconds = timing.ElapsedTime.TotalSeconds;
  4. // 1. 根据重力感应器或者键盘计算这一帧桌面的倾斜角度。
  5. // 2. 计算这一倾角带来的加速度。
  6. // 3. 计算是否跌入黑洞。
  7. // 4. 将加速度叠加阻力。
  8. // 5. 计算此速度和加速度下的位置。
  9. // 6. 进行边缘检测和碰撞检测。
  10. }

而在 Draw 中,只绘制了那个球:

  1. private void OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs e)
  2. {
  3. // 绘制游戏画面。
  4. using (var ds = e.DrawingSession)
  5. {
  6. ds.FillEllipse(_xPosition, _yPosition, _radius, _radius, Colors.Gray);
  7. }
  8. }

事实上你在上面动图看到的球并不是一个毫无生机的灰球,而是一个具有特效的半透明塑料弹球。你可以阅读 使用 Win2D 绘制带图片纹理的圆(或椭圆) 了解如何绘制这样的塑料弹球。

CanvasAnimatedControl 中 CreateResources 事件

CanvasAnimatedControl 中还有 CreateResources 事件,对更复杂的游戏循环有所帮助。当需要创建资源的时候会引发此事件。

第一次使用的时候就需要创建资源;除此之外,如果设备丢失,也需要创建资源。阅读 Win2D 官方文章系列翻译 - 处理设备丢失 - void² - 博客园 了解更多关于设备丢失的内容。

  1. private CanvasBitmap _boardMaterial;
  2. private async void OnCreateResources(CanvasAnimatedControl sender, CanvasCreateResourcesEventArgs e)
  3. {
  4. // 其中,GameCanvas 是 XAML 中 CanvasAnimatedControl 的名称。
  5. _boardMaterial = await CanvasBitmap.LoadAsync(GameCanvas, new Uri("{ms-appx:///Assets/Game/Boards/table.jpg}"));
  6. }

这里的 _boardMaterial 就是你在上面动图中看到的后面那张红色背景。

这样,便可以在需要的时候创建资源。

不过,这时你需要在 Draw 中先判空再绘制。

  1. private void OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs e)
  2. {
  3. using (var ds = e.DrawingSession)
  4. {
  5. // 其中,FullBounds 是 Rect 类型,我在 Page 的 SizeChanged 中给它赋的值。
  6. if (_boardMaterial != null)
  7. {
  8. ds.DrawImage(_boardMaterial, FullBounds);
  9. }
  10. else
  11. {
  12. ds.FillRectangle(FullBounds, Colors.White);
  13. }
  14. }
  15. }

你也可以使用事件参数 CanvasCreateResourcesEventArgs 来追踪这个异步加载任务,这样能够在绘制之前确保资源被加载完毕。

  1. private async void OnCreateResources(CanvasAnimatedControl sender, CanvasCreateResourcesEventArgs e)
  2. {
  3. e.TrackAsyncAction(CreateResourcesAsync().AsAsyncAction());
  4. async Task CreateResourcesAsync()
  5. {
  6. _boardMaterial = await CanvasBitmap.LoadAsync(GameCanvas, new Uri("{ms-appx:///Assets/Game/Boards/table.jpg}"));
  7. }
  8. }

参考资料

Win2D 中的游戏循环:CanvasAnimatedControl的更多相关文章

  1. C#游戏开发中快速的游戏循环

    C#游戏开发中快速的游戏循环的实现.参考<精通C#游戏编程>一书. using System; using System.Collections.Generic; using System ...

  2. cocos2d-x游戏循环与调度

    每一个游戏程序都有一个循环在不断运行,它是有导演对象来管理很维护.如果需要场景中的精灵运动起来,我们可以在游戏循环中使用定时器(Scheduler)对精灵等对象的运行进行调度.因为Node类封装了Sc ...

  3. cocos2d-x游戏循环和日程安排

    每场比赛有一个程序执行周期继续.这是导演对象来管理非常维修.在运动假设需要的场景精神,我们可以使用计时器在游戏圈(Scheduler)精灵和其他对象进行调度. 由于Node类封装了Scheduler类 ...

  4. 【Visual C++】游戏编程学习笔记之三:游戏循环的使用

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44208419 作者:Zee ...

  5. 18063-圈中的游戏-(第九章第4题)-"数组指针的使用"-数学分析

    代码借鉴CSDN大佬https://blog.csdn.net/weixin_41409140/article/details/88071047(对大佬的大佬代码进行分析) 18063 圈中的游戏 时 ...

  6. 你真的会python中的for循环吗

    for 循环是 Python 中的通用序列迭代器:它可以单步遍历任何有序序列中的元素.for 语句适用于字符串.列表.元组.其他内置可迭代对象和类创建的新对象. for 通常比 while 循环更容易 ...

  7. 3.pygame快速入门-游戏循环及动画实现

    游戏循环的开始,意味着游戏的正式开始,游戏循环的作用如下 1.保证游戏不会直接退出 2.变化图像的位置--动画效果 3.检测用户交互--按键.鼠标等     游戏时钟 pyagame提供了一个pyga ...

  8. 地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了

    地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了 四叉树对于区域查询,效率比较高. 原理图

  9. Oracle中三种循环(For、While、Loop)

    1.ORACLE中的GOTO用法 DECLARE x number; BEGIN x := 9; <<repeat_loop>> --循环点 x := x - 1; DBMS_ ...

随机推荐

  1. Qt emit的使用

    1. 假设现在我定义了一个类A,现在想在A的一个函数void A::function1()当中的结尾处emit一个信号signal1(),然后利用这个信号触发另一个类B进行某项操作void B::fu ...

  2. cocos代码研究(20)Widget子类LoadingBar学习笔记

    理论基础 在一些操作中可视化指示进度条.显示给用户一个条表示操作已经完成了多少,继承自 Widget. 代码实践 static LoadingBar * create ()创建一个空的LoadingB ...

  3. 手把手教你学node.js之学习使用外部模块

    学习使用外部模块 目标 建立一个 lesson2 项目,在其中编写代码. 当在浏览器中访问 http://localhost:3000/?q=alsotang 时,输出 alsotang 的 md5 ...

  4. Educational Codeforces Round 59 Solution

    A. Digits Sequence Dividing 签. #include <bits/stdc++.h> using namespace std; #define N 1010 ch ...

  5. cocos2dx 3.x 蒙板 遮罩 点击圆功能

    //注册触摸 EventListenerTouchOneByOne *listener = EventListenerTouchOneByOne::create(); listener->onT ...

  6. Ruby 安装和gem配置

    在linux或mac等*unix系统下可以使用rvm来进行ruby的配置和管理. 安装方法 (需要curl) curl -L get.rvm.io | bash -s stable rvm官方网站: ...

  7. centOS下升级python版本,详细步骤

    1.可利用linux自带下载工具wget下载,如下所示:(  笔者安装的是最小centos系统,所以使用编译命令前,必须安装wget服务,读者如果安装的是界面centos系统,或者使用过编译工具则可跳 ...

  8. python openpyxl 封装Execl常用操作的方法

    封装Excel操作方法:先装openpyxl:pip install openpyxl==2.4.5(可以指定版本) 封装脚本:#encoding=utf-8 from openpyxl import ...

  9. IP地址与MAC地址

    作者:知乎用户链接:https://www.zhihu.com/question/21546408/answer/28155896来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  10. JS地址自动返填技术

    系统设计地址为省市县三级联动,规范是规范了,但是无形中增加了系统操作的时间成本,因此设计地址自动返填技术,只要把地址拷贝到详细地址框中,可以自动返填到省市县三级联动的下拉框中. 还好洒家的大学不是混过 ...