UrhoSharp Tutorial: How to create your first project with Xamarin.Forms

Home / UrhoSharp Tutorial: How to create your first project with Xamarin.Forms

In this tutorial I’ll show you how to create a UrhoSharp project using Xamarin.Forms. This UrhoSharp project will run on Android, iOS and UWP.

A basic game I’ve created using UrhaSharp

Don’t worry if the code seems complicated, it’s not. To help you, I’ll include the source code of this project at the end of the tutorial.

The first step consists in creating a cross-platform project with Xamarin.Forms:

Creating a new cross platform Xamarin project

I suggest you to use a Blank template. Select the platform you need (Android, iOS, UWP to cover everything). Select the .NET Standard code sharing strategy.

Our new Cross Platform Solution

I suggest you to update all the Nuget packages before we start. After that, a nice clean and rebuild should guarantee us a clean start!

INSTALL URHOSHARP

The next step is to add the UrhoSharp.Forms nuget package to our solution. At the time of writing the latest version is 1.9.67. We must install this package in all our projects (.net standard, Android, iOS and UWP).

LET’S START WITH URHOSHARP

As you can imagine, UrhoSharp need a surface where it can draw our world. We can create this surface inside the MainPage.xaml file we have in our project. The MainPage will be similar to this:

As you can imagine, UrhoSharp need a surface where it can draw our world. We can create this surface inside the MainPage.xaml file we have in our project. The MainPage will be similar to this:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:UrhoSharpTutorial"
             xmlns:forms="clr-namespace:Urho.Forms;assembly=UrhoSharp.Forms"
             x:Class="UrhoSharpTutorial.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <forms:UrhoSurface x:Name="urhoSurface" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        </forms:UrhoSurface>
    </StackLayout>

</ContentPage>

Basically we have added an UrhoSurface calling it urhoSurface. This surface will fill our entire screen. Now we need to edit the MainPage.cs to load our UrhoSharp application. The code will be this:

using Xamarin.Forms;

namespace UrhoSharpTutorial
{
    public partial class MainPage : ContentPage
    {
        XamarinExpertApp urhoApp;

        public MainPage()
        {
            InitializeComponent();
        }

        protected override async void OnAppearing()
        {
            StartUrhoApp();
        }

        async void StartUrhoApp()
        {
            urhoApp = await urhoSurface.Show<XamarinExpertApp>(new Urho.ApplicationOptions("Data") { Orientation = Urho.ApplicationOptions.OrientationType.LandscapeAndPortrait });
        }
    }
}

This code will load our XamarinExpert UrhoSharp app inside the urhoSurface when the MainPage appears. Let’s see now how to create the XamarinExpertApp class.

This XamarinExpertApp should inherit from Urho.Application. The code of this class is:

using System.Diagnostics;
using Urho;
using UrhoSharpTutorial.Scenes;

namespace UrhoSharpTutorial
{
    public class XamarinExpertApp : Application
    {
        private BaseScene _mainScene;

        [Preserve]
        public XamarinExpertApp(ApplicationOptions options = null) : base(options)
        {
        }

        static XamarinExpertApp()
        {
            UnhandledException += (s, e) =>
            {
                if (Debugger.IsAttached)
                    Debugger.Break();
                e.Handled = true;
            };
        }

        protected override void Start()
        {
            base.Start();
            Input.Enabled = true;
            Input.SetMouseVisible(true, false);
            Input.TouchEmulation = true;

            StartMainScene();
        }

        private void StartMainScene()
        {
            _mainScene?.Destroy();
            Current.UI.Root.RemoveAllChildren();
            _mainScene = new MainScene(Graphics.Width, Graphics.Height);
        }

        protected override void OnUpdate(float timeStep)
        {
            base.OnUpdate(timeStep);
            _mainScene.OnUpdate(timeStep);
        }
    }
}

This class is our UrhoSharp project. It handles the exceptions and initialises the Input of our project. Inside the Start method, we load our scene. We also override the OnUpdate method so that we can decide what will happen every time that the screen is refreshed.

At this point we should create the mainScene. In this project we have only a scene, but in a more complex project we can have multiple scenes. Maybe one for the menu, another for the game, another for the settings and so on. Because of this, I prefer to create a basic scene calling it BaseScene. The code of this class is this:

using Urho;

namespace UrhoSharpTutorial.Scenes
{
    public class BaseScene
    {
        private int width;
        private int height;
        public Scene Scene;
        public Node CameraNode { get; set; }

        public BaseScene(int width, int height)
        {
            this.width = width;
            this.height = height;
        }

        public void InitScene()
        {
            Scene = new Scene();
            Scene.CreateComponent<Octree>();
        }

        public void CreateCamera(Vector3 vector3)
        {
            CameraNode = Scene.CreateChild("Camera");
            CameraNode.Position = vector3;
            Camera camera = CameraNode.CreateComponent<Camera>();
            camera.Orthographic = true;

            camera.OrthoSize = (float)Application.Current.Graphics.Height * Application.PixelSize;
        }

        public void SetupViewport()
        {
            var renderer = Application.Current.Renderer;
            Viewport vp = new Viewport(Application.Current.Context, Scene, CameraNode.GetComponent<Camera>());
            renderer.SetViewport(0, vp);
            vp.SetClearColor(Color.White);
        }

        public virtual void OnUpdate(float timeStep)
        {
        }

        public virtual void Destroy()
        {
        }
    }
}

In this base class we store the width and the height of our surface (it’s not necessary but it could be handy). Here we have several methods to create our Scene (it’s mandatory to create a Scene, so don’t forget it), to create our Camera (again mandatory, and in this case it’s an orthographic camera) and to setup our viewport (again mandatory). We must do these things every time we need to create a scene and this is why I’ve created this base class.

Now we can finally create our mainScene. I’ll show you a basic code for a mainScene and then a more complex one where I’ll add some methods to handle the inputs and interact with the objects in our scene.

The basic scene is this:

using Urho;

namespace UrhoSharpTutorial.Scenes
{
    public class MainScene : BaseScene
    {
        public MainScene(int width, int height) : base(width, height)
        {
            CreateScene();
        }

        private void CreateScene()
        {
            InitScene();
            CreateCamera(new Vector3(0f, 0f, -15));
         
            SetupViewport();
        }
    }
}

Here we just initialise the scene, create the camera and set the Viewport. Now I can show you a more useful mainScene:

using Urho;

namespace UrhoSharpTutorial.Scenes
{
    public class MainScene : BaseScene
    {
        private MainSceneInput _mainInput;
        public float movementSize = 0.8f;
        public float movementSpeed = 0.25f;

        public MainScene(int width, int height) : base(width, height)
        {
            CreateScene();
        }

        private void CreateScene()
        {
            InitScene();
            CreateCamera(new Vector3(0f, 0f, -15));

            _mainInput = new MainSceneInput(this);
            _mainInput.OnEvaluateNode += MainInput_OnEvaluateNode;

            SetupViewport();
            CreateEvents();
        }

        private void MainInput_OnEvaluateNode(object sender, Node node)
        {
            
        }

        private void CreateEvents()
        {
            Application.Current.Input.TouchBegin += _mainInput.Input_TouchBegin;
            Application.Current.Input.TouchMove += _mainInput.Input_TouchMove;
            Application.Current.Input.TouchEnd += _mainInput.Input_TouchEnd;
            Application.Current.Input.KeyUp += _mainInput.Input_KeyUp;
        }
        
        public override void Destroy()
        {
            base.Destroy();
            Application.Current.Input.TouchBegin -= _mainInput.Input_TouchBegin;
            Application.Current.Input.TouchMove -= _mainInput.Input_TouchMove;
            Application.Current.Input.TouchEnd -= _mainInput.Input_TouchEnd;
            Application.Current.Input.KeyUp -= _mainInput.Input_KeyUp;
        }
    }
}

What I’ve added here is some logic to interact with our world. Precisely I’ve created several methods to handle the touches on the screen. I’ve implemented all the methods inside another class called MainSceneInput. The code of this class is:

using System;
using Urho;
using Urho.Actions;

namespace UrhoSharpTutorial.Scenes
{
    internal class MainSceneInput
    {
        private readonly MainScene _scene;

        public event EventHandler<Node> OnEvaluateNode;

        public MainSceneInput(MainScene scene)
        {
            _scene = scene;
        }

        private Node GetSelectedNode(float objX, float objY)
        {
            Ray cameraRay = _scene.CameraNode.GetComponent<Camera>().GetScreenRay(objX / Application.Current.Graphics.Width, objY / Application.Current.Graphics.Height);
            var result = _scene.Scene.GetComponent<Octree>().RaycastSingle(cameraRay, RayQueryLevel.Triangle, 100);
            return result?.Node;
        }

        public void Input_TouchBegin(TouchBeginEventArgs obj)
        {
            Node selectedNode = GetSelectedNode((float)obj.X, (float)obj.Y);
            OnEvaluateNode?.Invoke(this, selectedNode);
        }

        public void Input_TouchMove(TouchMoveEventArgs obj)
        {
            Node selectedNode = GetSelectedNode((float)obj.X, (float)obj.Y);
            OnEvaluateNode?.Invoke(this, selectedNode);
        }

        public async void Input_TouchEnd(TouchEndEventArgs obj)
        {

        }

        internal void Input_KeyUp(KeyUpEventArgs obj)
        {
            if (obj.Key == Key.I)
            {
                var camera = _scene.CameraNode.GetComponent<Camera>();
                camera.Zoom += 0.05f;
            }
            else if (obj.Key == Key.O)
            {
                var camera = _scene.CameraNode.GetComponent<Camera>();
                camera.Zoom -= 0.05f;
            }
            else if (obj.Key == Key.W)
            {
                _scene.CameraNode.RunActions(new MoveTo(_scene.movementSpeed, new Vector3(_scene.CameraNode.Position2D.X, _scene.CameraNode.Position2D.Y + _scene.movementSize, -1.0f)));
            }
            else if (obj.Key == Key.S)
            {
                _scene.CameraNode.RunActions(new MoveTo(_scene.movementSpeed, new Vector3(_scene.CameraNode.Position2D.X, _scene.CameraNode.Position2D.Y - _scene.movementSize, -1.0f)));
            }
            else if (obj.Key == Key.A)
            {
                _scene.CameraNode.RunActions(new MoveTo(_scene.movementSpeed, new Vector3(_scene.CameraNode.Position2D.X - _scene.movementSize, _scene.CameraNode.Position2D.Y, -1.0f)));
            }
            else if (obj.Key == Key.D)
            {
                _scene.CameraNode.RunActions(new MoveTo(_scene.movementSpeed, new Vector3(_scene.CameraNode.Position2D.X + _scene.movementSize, _scene.CameraNode.Position2D.Y, -1.0f)));
            }
        }
    }
}

In this class I have a method to evaluate which object the user has touched (in that case the OnEvaluateNode method will be called with the selected node). And another method to move the camera using the keyboard (of course you can change this as you want, this is just an example on how to intercept these events).

Conclusion

All the code added until now is a basic empty template for every UrhoSharp project you want to create. You can use this template as a starting point for your UrhoSharp projects.

I’ve added on bitbucket this source code with just a simple code to add a sprite to our scene, so from there it can be easier for you to add all the sprites you need. The link is: https://bitbucket.org/marcojak81/urhosharpbasictemplate/src/master/

I’ll create later other more advanced tutorial on UrhoSharp.

As usual, if you have questions, please ask me and I’ll try to help you.

, , , , , , ,

About Author

about author

Marco Troncone

.Net Developer
Xamarin Lover

2 Comments
  1. UrhoSharp – Add 3D and Augmented Reality to your Xamarin apps | Xamarin eXpert

    […] If instead of the preview version you want to use a stable one, give a look here: http://www.xamarinexpert.it/2018/03/05/vs2017-version-15-6-just-released/ […]

  2. Ram

    I am HAVING ONE ISSUE, SCENE IS ALWAYS RENDERED IN LANDSCAPE mode irrespective of device orientation when UrhoSurface / forms is used. If i don’t use xamarin forms it works fine. Is there anything i am missing.

Leave a Reply to UrhoSharp – Add 3D and Augmented Reality to your Xamarin apps | Xamarin eXpert Cancel reply

%d bloggers like this: