Xenko C#開源遊戲引擎入門
最近使有和 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、運行看看
Xenko C#開源遊戲引擎入門