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.

RestSharp returns 0 for custom ASP.NET Core middleware response

A normal behavior of RestSharp is to return StatusCode = 0 for responses that won’t go through (e.g. unreachable server). However, a tricky behavior of RestSharp is to also return 0 if the response has content, but the Content-Length is undefined.

If you are confused why your RestSharp is returning 0 while Postman and Chrome work fine, make sure you are setting the response Content-Length to the actual content length.


public async Task Invoke(HttpContext context)
{
//instead of await next(context);
var result = JsonConvert.SerializeObject(new
{
Message = "Hello, World!"
});
context.Response.ContentType = "application/json; charset=utf-8";
context.Response.StatusCode = 200;
context.Response.ContentLength = result.Length + 2;
await context.Response.WriteAsync("\r\n" + result);
await context.Response.Body.FlushAsync();
}

mpc.exe outputs an empty Resolver

In order to use MessagePack on the iOS or in general with AOT, you need to use mpc.exe to generate a resolver before building your main projects. Since Xamarin and ASP.NET are all about code sharing, usually a good practice is to create a shared project or a library containing model definitions, and referencing it in both server and client projects.

This raises the question as where to embed the script to run mpc.exe in order to facilitate the automatic generation and updating the resolver class.

One problem is that mpc.exe does not work with Shared Projects (.shproj), and as of now only accepts .csproj files as the input. So one thing to do is to create a stub/dummy project containing only the model classes, and feeding it to mpc.exe.

The frustration comes when mpc.exe doesn’t like an input. In such cases, it merely generates a blank useless resolver class (e.g. MessagePackGenerated.cs) without giving any errors. You have to manually investigate everything in order to find out what goes wrong.

One of the main cases in which I realized that mpc.exe doesn’t work properly, is when you don’t have the correct version of MessagePack NuGet installed on the stub project. Make sure you install MessagePack in that project.

Solve “The “User7ZipPath” parameter is not supported”

This can happen when building a Xamarin project while using certain libraries. What can help is:

  1. Update or install the latest version of Xamarin.Build.Download NuGet.
  2. Close all Visual Studio windows.
  3. Delete all the obj, bin, .vs folders, as well as the local packages folder in your solution root.
  4. Delete the global NuGet cache from ~\.nuget
  5. Load the Solution again, Rebuild, and hopefully the problem will go away!

EF / SQL Server writes too slow?

I was using Entity Framework Core on a project which required a large amount of writes (inserts and updates) to a SQL Server 2017 database. The operation was extremely slow, in the order of several hours/half a day. I figured out that it was due to the EF overhead for tracking changes. Setting the following boolean to false saves a lot of time, if you have to do a lot of writes:

using (var db = new MyContext())
{
db.ChangeTracker.AutoDetectChangesEnabled = false;
//Do Stuff
db.ChangeTracker.AutoDetectChangesEnabled = true;
}