Lines in Unity

Tl;Dr: Download NeatLine from https://github.com/saeedafshari/NeatLine!

It is sometimes amazing how you want to do a very simple task, but you cannot find a simple and to-the-point library that does it for you. A few of my games require basic 2D lines, and Unity itself does not have the functionality to create 2D lines. There are a few complex assets on the Asset Store, but their licensing is not quite obvious, and I hesitate to open source my projects when using those assets.

Therefore I went ahead and created a simple dependencyless component that does one thing: Drawing 2D lines.

You can get it from GitHub using the link above. The main component is called NeatLine, which can be added to your Scene by clicking on the GameObject>2D Object>NeatLine menu item.

You can control four things about your line:

  • Vector2 HeadLocalPosition: Position of the first point, relative to the local transform.
  • Vector2 TailLocalPosition: Position of the second point, relative to the local transform.
  • float Thickness: Line’s thickness.
  • Color Color: Line’s color.

All four properties can be modified at edit or runtime.

Here’s how it works:

To draw a custom shape in Unity, we need three things: MeshRenderer, MeshFilter and Material.


meshFilter = gameObject.AddComponent();
meshRenderer = gameObject.AddComponent();
material = Resources.Load("NeatLineMaterial");

But before drawing a shape, we need to create the shape (Mesh) itself, i.e. calculating vertices, triangles and indices.

Calculating vertices is easy. We need to get the normal vector, add thickness to it and get the four corners of the line:


Vector3[] GetPolygon()
{
var vec = TailLocalPosition - HeadLocalPosition;
var unit = vec.normalized;
var halfCross = new Vector3(unit.y, -unit.x, 0) * 0.5f * Thickness;

return new[]
{
new Vector3(HeadLocalPosition.x, HeadLocalPosition.y) - halfCross,
new Vector3(HeadLocalPosition.x, HeadLocalPosition.y) + halfCross,
new Vector3(TailLocalPosition.x, TailLocalPosition.y) + halfCross,
new Vector3(TailLocalPosition.x, TailLocalPosition.y) - halfCross
};
}

Based on these four vertices, the indices of our line are:

new[] { 0, 1, 2, 2, 3, 0 };

And these are enough for us to create the Mesh:

var mesh = new Mesh();
meshFilter.mesh = mesh;
mesh.vertices = GetPolygon();
mesh.triangles = new[] { 0, 1, 2, 2, 3, 0 };
mesh.RecalculateNormals();
mesh.RecalculateBounds();

The last step is to assign the color to the Material:

material.color = Color;

Alternatively, you can assign individual colors to each vertex:

mesh.colors = new[] { Color, Color, Color, Color };

And there we go. We have a line!

NeatPolyline

If you are seeking some more advanced features, such as multiple vertices per line, or individual color and thickness settings per vertex, you can use NeatPolyline.

For more information, please check out the GitHub page of the project.

Xamarin.Android Rounded Corners Masked Layout

If you want to create a FrameLayout that has real rounded corners and clips its children beyond its corners, you can use the following class, which is a port of an answer on StackOverflow. You should replace Constants.PackageName with your Android package name, e.g. com.mycompany.myapp.

using Android.Content;
using Android.Graphics;
using Android.Runtime;
using Android.Util;
using Android.Widget;

namespace UIWidgets.Android
{
[Register(Constants.PackageName + ".UIWidgets.Android.RoundedCornerLayout")]
public class RoundedCornerLayout : FrameLayout
{
const float CornerRadius = 20.0f;

Bitmap maskBitmap;
Paint paint, maskPaint;
float cornerRadius;

public RoundedCornerLayout(Context context) : base(context)
{
Init(context);
}

public RoundedCornerLayout(Context context, IAttributeSet attrs) : base(context, attrs)
{
Init(context, attrs);
}

public RoundedCornerLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
Init(context, attrs, defStyle);
}

void Init(Context context, IAttributeSet attrs = null, int defStyle = 0)
{
DisplayMetrics metrics = Context.Resources.DisplayMetrics;
cornerRadius = TypedValue.ApplyDimension(ComplexUnitType.Dip, CornerRadius, metrics);
paint = new Paint(PaintFlags.AntiAlias);
maskPaint = new Paint(PaintFlags.AntiAlias | PaintFlags.FilterBitmap);
maskPaint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
SetWillNotDraw(false);
}

public override void Draw(Canvas canvas)
{
Bitmap offscreenBitmap = Bitmap.CreateBitmap(canvas.Width, canvas.Height, Bitmap.Config.Argb8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);

base.Draw(offscreenCanvas);

maskBitmap = maskBitmap ?? CreateMask(canvas.Width, canvas.Height);
offscreenCanvas.DrawBitmap(maskBitmap, 0.0f, 0.0f, maskPaint);
canvas.DrawBitmap(offscreenBitmap, 0.0f, 0.0f, paint);
}

Bitmap CreateMask(int width, int height)
{
Bitmap mask = Bitmap.CreateBitmap(width, height, Bitmap.Config.Alpha8);
Canvas canvas = new Canvas(mask);

Paint paint = new Paint(PaintFlags.AntiAlias);
paint.Color = Color.White;

canvas.DrawRect(0, 0, width, height, paint);

paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));
canvas.DrawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);

return mask;
}
}
}

And to use it in your AXML:

 <UIWidgets.Android.RoundedCornerLayout
 android:layout_width="150dp"
 android:layout_height="150dp">

 <RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="#FFDDAA"
 />
 </UIWidgets.Android.RoundedCornerLayout>

REST requests with Xamarin and RestSharp

RestSharp (available on NuGet) is a clean way to send HTTP requests and handle their response. As a portable package, you can use it in your Xamarin.iOS and Xamarin.Android applications. The following example, POSTs a serialized JSON body, created automatically from a C# class, to an endpoint located at https://myserver.com/api/messages/message. It also sends a token parameter inside the query string:

public class MessageDTO : DTO
{
    public string Sender { get; set; }
    public string Recipient { get; set; }
    public string Body { get; set; }
}
public static class PinHelper
{
    async void SendMessage(MessageDTO dto)
    {
        const string ApiPath = "https://myserver.com/api/";
        var client = new RestClient (ApiPath);
        var request = new RestRequest ("messages/message", Method.POST);
        request.AddQueryParameter ("token", Settings.Token);
        request.AddJsonBody (dto);

        try
        {
            var result = await client.ExecuteTaskAsync(request);
            Debug.WriteLine($"Result Status Code: {result.StatusCode} - {result.Content}");
        }
        catch (Exception e) {
            Debug.WriteLine ($"Error: {e.Message}");
        }
    }
}

On an ASP.NET WebApi controller with EntityFramework, this request can be received and stored using a function that looks like this:

[HttpPost][Route("message")]
public IHTTPActionResult AddMessage(string token, [FromBody] MessageDTO dto)
{
    Message message = new Message ();
    dto.Inject (message);
    db.Messages.Add (message);
    db.SaveChanges ();

    return Ok ();
}

Tips and Tricks on Using SQLite-Net with Xamarin.iOS

SQLite-Net is a nice library compatible with Xamarin that lets you create and use a SQLite database as the local data source of your application. It is ultra portable as it comes in only two C# files, one of which is for asynchronous operations. You can easily get it from NuGet and get started with it.

Creating a database (if not exists)

The first step in using SQLite-Net is creating a database, and its tables. This is automatically done by creating a SQLiteAsyncConnection and calling its CreateTableAsync<T> method, in which T is your model class. This method checks for the existence of a table with the same name as the model class, and creates it if it does not exist. For example, if we want to make a database named map.db containing a table based on the model class Pin, we can do the following:


var path = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), "map.db");
var connection = new SQLiteAsyncConnection(PATH, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex, true);
await connection.CreateTableAsync<Pin>();

You can keep the connection variable in case you’d like to use the database in the future, but be careful from which thread you access it. Many of the issues with SQLite-net come from accessing the database from a wrong thread, and the error messages usually give no hint regarding this.

Model classes

SQLite-Net takes care of serializing and deserializing data between queries and .NET objects. A model class can look like this:


using System;

using SQLite;


namespace Mapp.Models

{
    


        public class Pin
 

        {

        
        [PrimaryKey, AutoIncrement]


                public int Id { get; set; }
        
        public int ServerId { get; set; }

        
        public string Name { get; set; }

        
        public string Description { get; set; }


                public double Latitude { get; set; }


                public double Longitude { get; set; }


        }
}

In this example, the Id field is an auto-incremented primary key for table Pin.

Injecting DTO values into a model object

You can use the neat reflection features of .NET to automatically inject values from a Data Transfer Object (DTO) that is a subset of your model fields. Here is a helper method that does this for you:


using System.Linq;

using System.Reflection;


namespace Mapp

{

    public class DTO

    {

        public void Inject(object destination)

        {

            var destFields = destination.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            var myFields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);


            foreach (var item in myFields)

            {

                var matchingFields = from x in destFields where x.Name == item.Name select x;

                if (matchingFields.Count() == 0) continue;

                matchingFields.First().SetValue(destination, item.GetValue(this));

            }

        }

    }

}

For example if you have the following DTO, you can inject its values into a Pin object using the Inject method:


public class PinDTO : DTO

{
    public int ServerId { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public double Latitude { get; set; }

    public double Longitude { get; set; }
}

...

Pin pin = new Pin();
pinDto.Inject(pin);

Querying, inserting and updating records

You can use LINQ syntax to query the database and get a list of objects of the type of your model class. For example to find a pin with a certain ServerId and update it (or create it if it does not exist) you can write:


var query = connection.Table<Pin>().Where(x => x.Id == dto.ServerId).ToListAsync().Result;
var pin = Query.Count > 0 ? query[0] : new Pin { ServerId = dto.ServerId };
dto.Inject(pin);

if (pin.Id > 0)
{
    // Record exists. Update it.
    await connection.UpdateAsync(pin);
}
else
{
    // Record does not exist. Create it.
    await connection.InsertAsync(pin);
}

Again, you have to be careful from which thread you are accessing the database. To delete a record you can use the DeleteAsync method:


await connection.DeleteAsync(pin);