最近使有和 Three.js 開發三維頁面,覺得很有趣。以前在做WP應用的時候使用過MonoGame做過一點東西,后來Windows 10上來,MonoGame好像不怎么支持了,也沒用了。最近在看Windows 下的C# 3D繪圖,發現了SharpDx,隨藤摸瓜又爬到來了MonoGame 和發現Xenko.
MonoGame:當前又支持UWP應用,但提供的模板指定的是 14393的SDK。(下次再試試,這今試Xenko)
教程:https://docs.microsoft.com/zh-cn/xamarin/graphics-games/monogame/
Xenko:也是通過Xamarin進行跨平台,現在已是MIT開源。原生支持UWP,但用GameStudio 3.0.0.5生成的項目指定的是 10240的SDK,所以做UWP的話,用新SDK,則要改改。今天折騰一翻:
(為什么不用流行的Unity 3D呢?因為不懂,個人喜歡VS的編碼方式,什么引用都看得見,何況Unity3D免費版有限制)
以下使用Xenko創建Windows/Uwp項目:
1.安裝SDK:https://xenko.com/
2.啟動Xenko 新建項目 MyGame2

3、創建的已是完整可運行的項目

切換UWP運行:

刷了一下,沒有運行成功
使用VS 2017打開,提示沒有安裝 10240的SDK(然則我就是不想安裝)

點擊確定更新
VS不干了:

那就手動來,文本形式打開項目,修改成當前版本

重新加載項目:

出來了,此時重新生成項目。居然成功了。如果不成功,可以做以下嘗試:
把nuget的Direct3D11的文件拷到UWP下:

其實不知道有沒有用。因為我建第一個項目的時候是不行了,被我修改一翻后,第二個項目居然行了。
4、代碼結構
甚是熟悉的UWP代碼結構

MyGame2.UWP引用MyGame2.Game的游戲項目。UWP只是一個殼,實際游戲在MyGame2.Game中
看 BasicCameraController.cs 文件源碼
using System;
using Xenko.Core;
using Xenko.Core.Mathematics;
using Xenko.Engine;
using Xenko.Input;
namespace MyGame2
{
/// <summary>
/// A script that allows to move and rotate an entity through keyboard, mouse and touch input to provide basic camera navigation.
/// </summary>
/// <remarks>
/// The entity can be moved using W, A, S, D, Q and E, arrow keys or dragging/scaling using multi-touch.
/// Rotation is achieved using the Numpad, the mouse while holding the right mouse button, or dragging using single-touch.
/// </remarks>
public class BasicCameraController : SyncScript
{
private const float MaximumPitch = MathUtil.PiOverTwo * 0.99f;
private Vector3 upVector;
private Vector3 translation;
private float yaw;
private float pitch;
public Vector3 KeyboardMovementSpeed { get; set; } = new Vector3(5.0f);
public Vector3 TouchMovementSpeed { get; set; } = new Vector3(40, 40, 20);
public float SpeedFactor { get; set; } = 5.0f;
public Vector2 KeyboardRotationSpeed { get; set; } = new Vector2(3.0f);
public Vector2 MouseRotationSpeed { get; set; } = new Vector2(90.0f, 60.0f);
public Vector2 TouchRotationSpeed { get; set; } = new Vector2(60.0f, 40.0f);
public override void Start()
{
base.Start();
// Default up-direction
upVector = Vector3.UnitY;
// Configure touch input
if (!Platform.IsWindowsDesktop)
{
Input.Gestures.Add(new GestureConfigDrag());
Input.Gestures.Add(new GestureConfigComposite());
}
}
public override void Update()
{
ProcessInput();
UpdateTransform();
}
private void ProcessInput()
{
translation = Vector3.Zero;
yaw = 0;
pitch = 0;
// Move with keyboard
if (Input.IsKeyDown(Keys.W) || Input.IsKeyDown(Keys.Up))
{
translation.Z = -KeyboardMovementSpeed.Z;
}
else if (Input.IsKeyDown(Keys.S) || Input.IsKeyDown(Keys.Down))
{
translation.Z = KeyboardMovementSpeed.Z;
}
if (Input.IsKeyDown(Keys.A) || Input.IsKeyDown(Keys.Left))
{
translation.X = -KeyboardMovementSpeed.X;
}
else if (Input.IsKeyDown(Keys.D) || Input.IsKeyDown(Keys.Right))
{
translation.X = KeyboardMovementSpeed.X;
}
if (Input.IsKeyDown(Keys.Q))
{
translation.Y = -KeyboardMovementSpeed.Y;
}
else if (Input.IsKeyDown(Keys.E))
{
translation.Y = KeyboardMovementSpeed.Y;
}
// Alternative translation speed
if (Input.IsKeyDown(Keys.LeftShift) || Input.IsKeyDown(Keys.RightShift))
{
translation *= SpeedFactor;
}
// Rotate with keyboard
if (Input.IsKeyDown(Keys.NumPad2))
{
pitch = KeyboardRotationSpeed.X;
}
else if (Input.IsKeyDown(Keys.NumPad8))
{
pitch = -KeyboardRotationSpeed.X;
}
if (Input.IsKeyDown(Keys.NumPad4))
{
yaw = KeyboardRotationSpeed.Y;
}
else if (Input.IsKeyDown(Keys.NumPad6))
{
yaw = -KeyboardRotationSpeed.Y;
}
// Rotate with mouse
if (Input.IsMouseButtonDown(MouseButton.Right))
{
Input.LockMousePosition();
Game.IsMouseVisible = false;
yaw = -Input.MouseDelta.X * MouseRotationSpeed.X;
pitch = -Input.MouseDelta.Y * MouseRotationSpeed.Y;
}
else
{
Input.UnlockMousePosition();
Game.IsMouseVisible = true;
}
// Handle gestures
foreach (var gestureEvent in Input.GestureEvents)
{
switch (gestureEvent.Type)
{
// Rotate by dragging
case GestureType.Drag:
var drag = (GestureEventDrag)gestureEvent;
var dragDistance = drag.DeltaTranslation;
yaw = -dragDistance.X * TouchRotationSpeed.X;
pitch = -dragDistance.Y * TouchRotationSpeed.Y;
break;
// Move along z-axis by scaling and in xy-plane by multi-touch dragging
case GestureType.Composite:
var composite = (GestureEventComposite)gestureEvent;
translation.X = -composite.DeltaTranslation.X * TouchMovementSpeed.X;
translation.Y = -composite.DeltaTranslation.Y * TouchMovementSpeed.Y;
translation.Z = -(float)Math.Log(composite.DeltaScale + 1) * TouchMovementSpeed.Z;
break;
}
}
}
private void UpdateTransform()
{
var elapsedTime = (float)Game.UpdateTime.Elapsed.TotalSeconds;
translation *= elapsedTime;
yaw *= elapsedTime;
pitch *= elapsedTime;
// Get the local coordinate system
var rotation = Matrix.RotationQuaternion(Entity.Transform.Rotation);
// Enforce the global up-vector by adjusting the local x-axis
var right = Vector3.Cross(rotation.Forward, upVector);
var up = Vector3.Cross(right, rotation.Forward);
// Stabilize
right.Normalize();
up.Normalize();
// Adjust pitch. Prevent it from exceeding up and down facing. Stabilize edge cases.
var currentPitch = MathUtil.PiOverTwo - (float)Math.Acos(Vector3.Dot(rotation.Forward, upVector));
pitch = MathUtil.Clamp(currentPitch + pitch, -MaximumPitch, MaximumPitch) - currentPitch;
// Move in local coordinates
Entity.Transform.Position += Vector3.TransformCoordinate(translation, rotation);
// Yaw around global up-vector, pitch and roll in local space
Entity.Transform.Rotation *= Quaternion.RotationAxis(right, pitch) * Quaternion.RotationAxis(upVector, yaw);
}
}
}
5、運行看看

