ref.dotnet - jgrey4296/jgrey4296.github.io GitHub Wiki

DotNet

Packages

Reference

Infrastructure

mcs for compiling, mono for running the compiled executable xbuild on linux instead of msbuild, using .sln and .csproj files xbuild /t:Target xbuild /p:Configuration=Release csharp for REPL

Language

Basic Data Types

// Sbyte - Signed 8-bit integer
// (-128 <= sbyte <= 127)
sbyte fooSbyte = 100;

// Byte - Unsigned 8-bit integer
// (0 <= byte <= 255)
byte fooByte = 100;

// Short - 16-bit integer
// Signed - (-32,768 <= short <= 32,767)
// Unsigned - (0 <= ushort <= 65,535)
short fooShort = 10000;
ushort fooUshort = 10000;

// Integer - 32-bit integer
int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647)
uint fooUint = 1; // (0 <= uint <= 4,294,967,295)

// Long - 64-bit integer
long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807)
ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615)
// Numbers default to being int or uint depending on size.
// L is used to denote that this variable value is of type long or ulong

// Double - Double-precision 64-bit IEEE 754 Floating Point
double fooDouble = 123.4; // Precision: 15-16 digits

// Float - Single-precision 32-bit IEEE 754 Floating Point
float fooFloat = 234.5f; // Precision: 7 digits
// f is used to denote that this variable value is of type float

// Decimal - a 128-bits data type, with more precision than other floating-point types,
// suited for financial and monetary calculations
decimal fooDecimal = 150.3m;

// Boolean - true & false
bool fooBoolean = true; // or false

// Char - A single 16-bit Unicode character
char fooChar = 'A';

// Strings -- unlike the previous base types which are all value types,
// a string is a reference type. That is, you can set it to null
string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)";
Console.WriteLine(fooString);

// You can access each character of the string with an indexer:
char charFromString = fooString[1]; // => 'e'
// Strings are immutable: you can't do fooString[1] = 'X';

// Compare strings with current culture, ignoring case
string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase);

// Formatting, based on sprintf
string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2);

// Dates & Formatting
DateTime fooDate = DateTime.Now;
Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy"));

// You can split a string over two lines with the @ symbol. To escape " use ""
string bazString = @"Here's some stuff
on a new line! ""Wow!"", the masses cried";

// Use const or read-only to make a variable immutable
// const values are calculated at compile time
const int HOURS_I_WORK_PER_WEEK = 9001;

Classes

// Class Declaration Syntax: // <public/private/protected/internal> class <class name>{ // //data fields, constructors, functions all inside. // //functions are called as methods in Java. // }

public class Bicycle {
    // Bicycle's Fields/Variables
    public int Cadence { // Public: Can be accessed from anywhere
        get {// get - define a method to retrieve the property
            return _cadence;
        }
        set { // set - define a method to set a proprety
            _cadence = value; // Value is the value passed in to the setter
        }
    }
    private int _cadence;

    protected virtual int Gear // Protected: Accessible from the class and subclasses
    {
        get; // creates an auto property so you don't need a member field
        set;
    }

    internal int Wheels // Internal: Accessible from within the assembly
    {
        get;
        private set; // You can set modifiers on the get/set methods
    }

    int _speed; // Everything is private by default: Only accessible from within this class.
    // can also use keyword private
    public string Name { get; set; }

    // Enum is a value type that consists of a set of named constants
    // It is really just mapping a name to a value (an int, unless specified otherwise).
    // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
    // An enum can't contain the same value twice.
    public enum BikeBrand
    {
        AIST,
        BMC,
        Electra = 42, //you can explicitly set a value to a name
        Gitane // 43
    }
    // We defined this type inside a Bicycle class, so it is a nested type
    // Code outside of this class should reference this type as Bicycle.Brand

    public BikeBrand Brand; // After declaring an enum type, we can declare the field of this type

    // Static members belong to the type itself rather then specific object.
    // You can access them without a reference to any object:
    // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated);
    static public int BicyclesCreated = 0;

    // readonly values are set at run time
    // they can only be assigned upon declaration or in a constructor
    readonly bool _hasCardsInSpokes = false; // read-only private

    // Constructors are a way of creating classes
    // This is a default constructor
    public Bicycle()
    {
        this.Gear = 1; // you can access members of the object with the keyword this
        Cadence = 50;  // but you don't always need it
        _speed = 5;
        Name = "Bontrager";
        Brand = BikeBrand.AIST;
        BicyclesCreated++;
    }

    // This is a specified constructor (it contains arguments)
    public Bicycle(int startCadence, int startSpeed, int startGear,
                   string name, bool hasCardsInSpokes, BikeBrand brand)
        : base() // calls base first
    {
        Gear = startGear;
        Cadence = startCadence;
        _speed = startSpeed;
        Name = name;
        _hasCardsInSpokes = hasCardsInSpokes;
        Brand = brand;
    }

    // Constructors can be chained
    public Bicycle(int startCadence, int startSpeed, BikeBrand brand) :
        this(startCadence, startSpeed, 0, "big wheels", true, brand)
    {
    }

    // Function Syntax:
    // <public/private/protected> <return type> <function name>(<args>)

    // classes can implement getters and setters for their fields
    // or they can implement properties (this is the preferred way in C#)

    // Method parameters can have default values.
    // In this case, methods can be called with these parameters omitted
    public void SpeedUp(int increment = 1)
    {
        _speed += increment;
    }

    public void SlowDown(int decrement = 1)
    {
        _speed -= decrement;
    }

    // properties get/set values
    // when only data needs to be accessed, consider using properties.
    // properties may have either get or set, or both
    private bool _hasTassles; // private variable
    public bool HasTassles // public accessor
    {
        get { return _hasTassles; }
        set { _hasTassles = value; }
    }

    // You can also define an automatic property in one line
    // this syntax will create a backing field automatically.
    // You can set an access modifier on either the getter or the setter (or both)
    // to restrict its access:
    public bool IsBroken { get; private set; }

    // Properties can be auto-implemented
    public int FrameSize
    {
        get;
        // you are able to specify access modifiers for either get or set
        // this means only Bicycle class can call set on Framesize
        private set;
    }

    //Method to display the attribute values of this Object.
    public virtual string Info()
    {
        return "Gear: " + Gear +
            " Cadence: " + Cadence +
            " Speed: " + _speed +
            " Name: " + Name +
            " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") +
            "\n------------------------------\n"
            ;
    }

    // Methods can also be static. It can be useful for helper methods
    public static bool DidWeCreateEnoughBycles()
    {
        // Within a static method, we only can reference static class members
        return BicyclesCreated > 9000;
    } // If your class only needs static members, consider marking the class itself as static.


} // end class Bicycle

// PennyFarthing is a subclass of Bicycle
class PennyFarthing : Bicycle
{
    // (Penny Farthings are those bicycles with the big front wheel.
    // They have no gears.)

    // calling parent constructor
    public PennyFarthing(int startCadence, int startSpeed) :
        base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra)
    {
    }

    protected override int Gear
    {
        get
        {
            return 0;
        }
        set
        {
            throw new ArgumentException("You can't change gears on a PennyFarthing");
        }
    }

    public override string Info()
    {
        string result = "PennyFarthing bicycle ";
        result += base.ToString(); // Calling the base version of the method
        return result;
    }
}

// Interfaces only contain signatures of the members, without the implementation.
interface IJumpable
{
    void Jump(int meters); // all interface members are implicitly public
}

interface IBreakable
{
    bool Broken { get; } // interfaces can contain properties as well as methods & events
}

// Class can inherit only one other class, but can implement any amount of interfaces
class MountainBike : Bicycle, IJumpable, IBreakable
{
    int damage = 0;

    public void Jump(int meters)
    {
        damage += meters;
    }

    public bool Broken
    {
        get
        {
            return damage > 100;
        }
    }
}

/// <summary>
/// Used to connect to DB for LinqToSql example.
/// EntityFramework Code First is awesome (similar to Ruby's ActiveRecord, but bidirectional)
/// http://msdn.microsoft.com/en-us/data/jj193542.aspx
/// </summary>
public class BikeRespository : DbSet
{
    public BikeRespository()
        : base()
    {
    }

    public DbSet<Bicycle> Bikes { get; set; }
}

Control Structures

IF

if(true || false){} else {};
// Ternary operators
// A simple if/else can be written as follows
// <condition> ? <true> : <false>
string isTrue = (true) ? "True" : "False";

WHILE

while(true){};
do {} while(true);

FOR

for(var i = 0; i < 5; i++){}

// For Each Loop foreach loop structure => foreach(<iteratorType>
// <iteratorName> in <enumerable>)
// The foreach loop loops over any
// object implementing IEnumerable or IEnumerable<T> All the
// collection types (Array, List, Dictionary...) in the .Net framework
// implement one or both of these interfaces.  (The ToCharArray()
// could be removed, because a string also implements IEnumerable)
foreach (char character in "Hello World".ToCharArray())
{
    //Iterated over all the characters in the string
}

Switch Case

// A switch works with the byte, short, char, and int data types.
// It also works with enumerated types (discussed in Enum Types),
// the String class, and a few special classes that wrap
// primitive types: Character, Byte, Short, and Integer.
int month = 3;
string monthString;
switch (month)
{
    case 1:
        monthString = "January";
        break;
    case 2:
        monthString = "February";
        break;
    case 3:
        monthString = "March";
        break;
        // You can assign more than one case to an action
        // But you can't add an action without a break before another case
        // (if you want to do this, you would have to explicitly add a goto case x
    case 6:
    case 7:
    case 8:
        monthString = "Summer time!!";
        break;
    default:
        monthString = "Some other month";
        break;
}

Data Structures

// Others data structures to check out: // Stack/Queue // Dictionary (an implementation of a hash map) // HashSet // Read-only Collections // Tuple (.Net 4+) //Stack,Queue,Dictionary,HashSet,Tuple

Arrays

// Arrays - zero indexed
// The array size must be decided upon declaration
// The format for declaring an array is follows:
// <datatype>[] <var name> = new <datatype>[<array size>];
int[] intArray = new int[10];

// Another way to declare & initialize an array
int[] y = { 9000, 1000, 1337 };

// Indexing an array - Accessing an element
Console.WriteLine("intArray @ 0: " + intArray[0]);
// Arrays are mutable.
intArray[1] = 1;

int[] array1 = new int[5];
int[,] array2 = new int[4,6];
int[][] array3;

Lists

// Lists are used more frequently than arrays as they are more flexible
// The format for declaring a list is follows:
// List<datatype> <var name> = new List<datatype>();
List<int> intList = new List<int>();
List<string> stringList = new List<string>();
List<int> z = new List<int> { 9000, 1000, 1337 }; // intialize
// The <> are for generics - Check out the cool stuff section

// Lists don't default to a value;
// A value must be added before accessing the index
intList.Add(1);
Console.WriteLine("intList @ 0: " + intList[0]);

Objects/Classes

class Person : InheritClass, AndAnInterface
{
    private string myName ="N/A";
    private int myAge = 0;

    // Declare a Name property of type string:
    public string Name
    {
        get
        {
            return myName;
        }
        set
        {
            myName = value;
        }
    }

    public override string ToString()
    {
        return "Name = " + Name + ", Age = " + Age;
    }

}
Object Creation:
//use new
Person blah = new Person();
Methods:
blah.something();

Delegates:

A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked. Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and secure.

// Declare a delegate type for processing a book:
public delegate void ProcessBookDelegate(Book book);

// Call a passed-in delegate on each paperback book to process it:
public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
{
    foreach (Book b in list)
    {
        if (b.Paperback)
            // Calling the delegate:
            processBook(b);
    }
}

// Create a new delegate object associated with the static
// method Test.PrintTitle:
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));

// Print the title of the book.
static void PrintTitle(Book b)
{
    Console.WriteLine("   {0}", b.Title);
}

Dynamic Objects

// DYNAMIC OBJECTS (great for working with other languages)
dynamic student = new ExpandoObject();
student.FirstName = "First Name"; // No need to define class first!

// You can even add methods (returns a string, and takes in a string)
student.Introduce = new Func<string, string>(
(introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo));
Console.WriteLine(student.Introduce("Beth"));

Generics

// The classes for TKey and TValue is specified by the user calling this function.
// This method emulates the SetDefault of Python
public static TValue SetDefault<TKey, TValue>(
    IDictionary<TKey, TValue> dictionary,
    TKey key,
    TValue defaultItem)
{
    TValue result;
    if (!dictionary.TryGetValue(key, out result))
        return dictionary[key] = defaultItem;
    return result;
}

// You can narrow down the objects that are passed in
public static void IterateAndPrint<T>(T toPrint) where T: IEnumerable<int>
{
    // We can iterate, since T is a IEnumerable
    foreach (var item in toPrint)
        // Item is an int
        Console.WriteLine(item.ToString());
}

Heap or Stack?

When you call the New operator on a class, it will be allocated on the heap. When you instantiate a struct, it gets created on the stack. This will yield performance gains. Also, you will not be dealing with references to an instance of a struct as you would with classes. You will be working directly with the struct instance. Because of this, when passing a struct to a method, it’s passed by value instead of as a reference.

Inspection and Output:

// Print out the name and the age associated with the person:
Console.WriteLine("Person details - {0}", person);

Lambdas

// LAMBDA EXPRESSIONS - allow you to write code in line
Func<int, int> square = (x) => x * x; // Last T item is the return value
Console.WriteLine(square(3)); // 9

Memory Management

//Automatic, uses destructors: ~A(){}

Namespaces

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Threading.Tasks;
using System.IO;

Networking

On the C# side, breaks down to using System.Net.Sockets, and System for [Serializable] flag for data classes.

using System;
using System.Net.Sockets;

[Serializable]
public class MyData {
    public int age;
    public string name;
}

public String host = "localhost";
public Int32 port = 50000;

TcpClient tcp_socket = new TcpClient(host, port);
NetworkStream net_stream = tcp_socket.GetStream();
StreamWriter socket_writer = new StreamWriter(net_stream);
StreamReader socket_reader = new StreamReader(net_stream);
socket_writer.AutoFlush = true;

With Actual Transmission being:

MyData example = new MyData(23, "Bob");
string data = JsonUtility.ToJson(example);
socket_writer.Writer(dataAsJson);

And Reading being:

string readString = socket_reader.ReadLine();
JsonUtility.FromJsonOverwrite(example, readString);

Closing:

socket_writer.Close();
socket_reader.Close();
tcp_socket.Close();

Nullables, Defaults and Generics

// NULLABLE TYPES - great for database interaction / return values
// any value type (i.e. not a class) can be made nullable by suffixing a ?
// <type>? <var name> = <value>
int? nullable = null; // short hand for Nullable<int>
Console.WriteLine("Nullable variable: " + nullable);
bool hasValue = nullable.HasValue; // true if not null

// ?? is syntactic sugar for specifying default value (coalesce)
// in case variable is null
int notNullable = nullable ?? 0; // 0

// IMPLICITLY TYPED VARIABLES - you can let the compiler work out what the type is:
var magic = "magic is a string, at compile time, so you still get type safety";
// magic = 9; will not work as magic is a string, not an int

// GENERICS
//
var phonebook = new Dictionary<string, string>() {
    {"Sarah", "212 555 5555"} // Add some entries to the phone book
};

Operators

int i1 = 1, i2 = 2; // Shorthand for multiple declarations

// Arithmetic is straightforward
Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3

// Modulo
Console.WriteLine("11%3 = " + (11 % 3)); // => 2

// Comparison operators
Console.WriteLine("3 == 2? " + (3 == 2)); // => false
Console.WriteLine("3 != 2? " + (3 != 2)); // => true
Console.WriteLine("3 > 2? " + (3 > 2)); // => true
Console.WriteLine("3 < 2? " + (3 < 2)); // => false
Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true
Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true

// Bitwise operators!
/*
  ~       Unary bitwise complement
  <<      Signed left shift
  >>      Signed right shift
  &       Bitwise AND
  ^       Bitwise exclusive OR
  |       Bitwise inclusive OR
*/

// Incrementations
int i = 0;
Console.WriteLine("\n->Inc/Dec-rementation");
Console.WriteLine(i++); //i = 1. Post-Incrementation
Console.WriteLine(++i); //i = 2. Pre-Incrementation
Console.WriteLine(i--); //i = 1. Post-Decrementation
Console.WriteLine(--i); //i = 0. Pre-Decrementation

Resource Management

// DISPOSABLE RESOURCES MANAGEMENT - let you handle unmanaged resources easily.
// Most of objects that access unmanaged resources (file handle, device contexts, etc.)
// implement the IDisposable interface. The using statement takes care of
// cleaning those IDisposable objects for you.
using (StreamWriter writer = new StreamWriter("log.txt"))
{
    writer.WriteLine("Nothing suspicious here");
    // At the end of scope, resources will be released.
    // Even if an exception is thrown.
}

Sorting

List<Order> SortedList = objListOrder.OrderBy(o => o.OrderDate).ToList();

//Alt, using LINQ:
var x = from x in list orderBy x.val select x

Type Casting

// Converting data

// Convert String To Integer
// this will throw an Exception on failure
int.Parse("123");//returns an integer version of "123"

// try parse will default to type default on failure
// in this case: 0
int tryInt;
if (int.TryParse("123", out tryInt)) // Function is boolean
    Console.WriteLine(tryInt);       // 123

// Convert Integer To String
// Convert class has a number of methods to facilitate conversions
Convert.ToString(123);
// or
tryInt.ToString();

Value vs Reference

A value type is either a struct type or an enumeration type. C# provides a set of predefined struct types called the simple types. The simple types are identified through reserved words.

A reference type is a class type, an interface type, an array type, or a delegate type.

Unity:

CMD-’ will bring up documentation in monodevelop

GUI Text: requires a gui layer on the camera, and uses camera coordinates so 0.0 -> 1.0

Typical base class: Monobehaviour using UnityEngine;

Templates: GetComponent.<Rigidbody>();

Standard Functions:

#pragma strict

//Called before first frame
function Start () {
    //Get a component of the gameobject the script is attached to
    var rb = GetComponent.<Rigidbody>();
    //Finds a specific child object
    transform.Find("gun");
    //Get a game object from anywhere in the scene.
    GameObject.Find("something");
    player = GameObject.FindWithTag("Player");
    enemies = GameObject.FindGameObjectsWithTag("Enemy");
    //Instantiation:
    public GameObject enemy;
    Instantiate(enemy);
    //Destroy: (can destroy individual components)
    Destroy(enemy,0.5f);//time delay
}

//Called for each object at scene load
function Awake(){}

//called before frame is rendered or animations calculated
function Update () {}

//Called before each physics step
function FixedUpdate(){}


//Called periodically for guis
function OnGUI(){}

//Mouse event functions: Over,Down...
function OnMouseOver(){}

function OnDestroy(){}

//physics events
//CollisionEnter,Stay,Exit
//OnTriggerEnter,Stay,Exit when as a trigger
function OnCollisionEnter(otherObj: Collision){}

Debug:

Debug.Log()

Coroutines:

yield //optional: WaitForSeconds(0.1);

Vector2:

//Array: Add, Clear, Concat, Join, Pop, Push, RemoveAt, Shift, Unshift, Sort
// Exposes an float array in the inspector,
// which you can edit there.
//Typed arrays are fast but unresizable
var values : float[];
// Copy the js array into a builtin array
var builtinArray : Vector3[] = array.ToBuiltin(Vector3) as Vector3[];
// Assign the builtin array to a js Array
var newarr = new Array (builtinArray);

one, right, up, zero, magnitude, normalized, x, y Static : Max,Min, Lerp, Dot, Distance, Angle, Scale

Editor stuff

Example class to edit:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JGBezier : MonoBehaviour {
    private static class Bezier {
        public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, float t){
            //Vector3 firstLerp = Vector3.Lerp (p0, p1, t);
            //Vector3 secondLerp = Vector3.Lerp (p1, p2, t);
            //return Vector3.Lerp (firstLerp, secondLerp, t);
            t = Mathf.Clamp01(t);
            float oneMinusT = 1f - t;
            return oneMinusT * oneMinusT * p0 +
                2f * oneMinusT * t * p1 +
                t * t * p2;

        }

        public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, float t){
            return 2f * (1f - t) * (p1 - p0) +
                2f * t * (p2 - p1);
        }
    }

    public Vector3[] points;

    public void Reset () {
        points = new Vector3[] {
            new Vector3 (1f, 0f, 0f),
            new Vector3 (2f, 0f, 0f),
            new Vector3 (3f, 0f, 0f)
        };
    }

    public Vector3 GetPoint (float t) {
        return transform.TransformPoint (Bezier.GetPoint (points [0], points [1], points [2], t));
    }

    public Vector3 GetVelocity( float t){
        return transform.TransformPoint(Bezier.GetFirstDerivative(points[0], points[1], points[2], t)) -
            transform.position;
    }
}

Code for the editor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(JGBezier))]
public class BezierInspector : Editor {

    private JGBezier curve;
    private Transform cTransform;
    private Quaternion cRotation;
    private const int lineSteps = 10;

    private void OnSceneGUI () {
        curve = target as JGBezier;
        cTransform = curve.transform;
        cRotation = Tools.pivotRotation == PivotRotation.Local ? cTransform.rotation : Quaternion.identity;

        Vector3 p0 = ShowPoint (0);
        Vector3 p1 = ShowPoint (1);
        Vector3 p2 = ShowPoint (2);

        Handles.color = Color.grey;
        Handles.DrawLine (p0, p1);
        Handles.DrawLine (p1, p2);

        Handles.color = Color.green;
        Vector3 lineStart = curve.GetPoint (0f);
        Handles.DrawLine (lineStart, lineStart + curve.GetVelocity (0f));
        for (int i = 1; i <= lineSteps; i++) {
            Handles.color = Color.red;
            Vector3 lineEnd = curve.GetPoint (i / (float)lineSteps);
            Handles.DrawLine (lineStart, lineEnd);
            Handles.color = Color.green;
            Handles.DrawLine (lineEnd, lineEnd + curve.GetVelocity (i / (float)lineSteps));
            lineStart = lineEnd;
        }

    }

    private Vector3 ShowPoint (int index){
        Vector3 point = cTransform.TransformPoint (curve.points [index]);
        EditorGUI.BeginChangeCheck ();
        point = Handles.DoPositionHandle (point, cRotation);
        if (EditorGUI.EndChangeCheck ()) {
            Undo.RecordObject (curve, "Move Point");
            EditorUtility.SetDirty (curve);
            curve.points [index] = cTransform.InverseTransformPoint (point);
        }
        return point;
    }
}

Splines

Base Spline class:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JGSpline : MonoBehaviour {
    private static class Bezier {
        public static Vector3 GetPoint3 (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){
            t = Mathf.Clamp01 (t);
            float oneMinusT = 1f - t;
            return oneMinusT * oneMinusT * oneMinusT * p0 +
                3f * oneMinusT * oneMinusT * t * p1 +
                3f * oneMinusT * t * t * p2 +
                t * t * t * p3;
        }

        public static Vector3 GetFirstDerivative3 (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){
            t = Mathf.Clamp01 (t);
            float oneMinusT = 1f - t;
            return 3f * oneMinusT * oneMinusT * (p1 - p0) +
                6f * oneMinusT * t * (p2 - p1) +
                3f * t * t * (p3 - p2);
        }

    }


    public Vector3[] points;

    public void Reset () {
        points = new Vector3[] {
            new Vector3 (1f, 0f, 0f),
            new Vector3 (2f, 0f, 0f),
            new Vector3 (3f, 0f, 0f),
            new Vector3 (4f, 0f, 0f)
        };
    }

    public Vector3 GetPoint (float t) {
        int i;
        if (t >= 1f) {
            t = 1f;
            i = points.Length - 4;
        } else {
            t = Mathf.Clamp01 (t) * CurveCount;
            i = (int)t;
            t -= i;
            i *= 3;
        }
        return transform.TransformPoint (Bezier.GetPoint3 (points [i], points [i+1], points [i+2], points[3], t));
    }

    public Vector3 GetVelocity( float t){
        int i;
        if (t >= 1f) {
            t = 1f;
            i = points.Length - 4;
        } else {
            t = Mathf.Clamp01 (t) * CurveCount;
            i = (int)t;
            t -= i;
            i *= 3;
        }
        return transform.TransformPoint(Bezier.GetFirstDerivative3(points[0], points[1], points[2], points[3], t)) -
            transform.position;
    }

    public Vector3 GetDirection (float t){
        return GetVelocity (t).normalized * 2;
    }

    public void AddCurve(){
        Vector3 point = points [points.Length - 1];
        System.Array.Resize (ref points, points.Length + 3);
        point.x += 1f;
        points [points.Length - 3] = point;
        point.x += 1f;
        points [points.Length - 2] = point;
        point.x += 1f;
        points [points.Length - 1] = point;
    }

    public int CurveCount {
        get {
            return (points.Length - 1) / 3;
        }
    }

}

Inspector:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(JGSpline))]
public class SplineInspector : Editor {

    private JGSpline curve;
    private Transform cTransform;
    private Quaternion cRotation;
    private const int lineSteps = 10;
    private const float directionScale = 0.5f;
    private const int stepsPerCurve = 10;
    private const float handleSize = 0.04f;
    private const float pickSize = 0.06f;
    private int selectedIndex = -1;

    public override void OnInspectorGUI (){
        DrawDefaultInspector ();
        curve = target as JGSpline;
        if (GUILayout.Button ("Add Curve")) {
            Undo.RecordObject (curve, "Add Curve");
            curve.AddCurve ();
            EditorUtility.SetDirty (curve);
        }
    }

    private void OnSceneGUI () {
        curve = target as JGSpline;
        cTransform = curve.transform;
        cRotation = Tools.pivotRotation == PivotRotation.Local ? cTransform.rotation : Quaternion.identity;

        //Loop
        Vector3 p0 = ShowPoint (0);
        for (int i = 1; i < curve.points.Length; i += 3) {
            Vector3 p1 = ShowPoint (i);
            Vector3 p2 = ShowPoint (i + 1);
            Vector3 p3 = ShowPoint (i + 2);

            Handles.color = Color.grey;
            Handles.DrawLine (p0, p1);
            Handles.DrawLine (p2, p3);

            Handles.DrawBezier (p0, p3, p1, p2, Color.white, null, 2f);
            p0 = p3;
        }

        ShowDirections ();
        /* not needed because of Handles.DrawBezier
           Handles.color = Color.green;
           Vector3 lineStart = curve.GetPoint (0f);
           Handles.DrawLine (lineStart, lineStart + curve.GetDirection (0f));
           for (int i = 1; i <= lineSteps; i++) {
           Handles.color = Color.red;
           Vector3 lineEnd = curve.GetPoint (i / (float)lineSteps);
           Handles.DrawLine (lineStart, lineEnd);
           Handles.color = Color.green;
           Handles.DrawLine (lineEnd, lineEnd + curve.GetDirection (i / (float)lineSteps));
           lineStart = lineEnd;
           }
        */

    }

    //get s a value while registering for changes
    private Vector3 ShowPoint (int index){
        Vector3 point = cTransform.TransformPoint (curve.points [index]);
        float size = HandleUtility.GetHandleSize (point);
        Handles.color = Color.white;
        if (Handles.Button (point, cRotation, size * handleSize, size * pickSize, Handles.DotHandleCap)) {
            selectedIndex = index;
        }
        if (selectedIndex == index) {
            EditorGUI.BeginChangeCheck ();
            point = Handles.DoPositionHandle (point, cRotation);
            if (EditorGUI.EndChangeCheck ()) {
                Undo.RecordObject (curve, "Move Point");
                EditorUtility.SetDirty (curve);
                curve.points [index] = cTransform.InverseTransformPoint (point);
            }
        }
        return point;
    }

    private void ShowDirections(){
        Handles.color = Color.green;
        Vector3 point = curve.GetPoint (0f);
        Handles.DrawLine (point, point + curve.GetDirection (0f) * directionScale);
        int steps = stepsPerCurve * curve.CurveCount;
        for (int i = 1; i <= steps; i++) {
            point = curve.GetPoint(i / (float)steps);
            Handles.DrawLine(point, point + curve.GetDirection( i / (float) steps) * directionScale);
        }
    }


}

Blender Import

Unity loads blender files natively. Set ‘Material Naming’ in the imported prefabs to ‘From Model’s Material’ To use Sprytile tilesets, import the texture and add them to the albedo of the shader for the object.

Shaders

Notes based on Alan Zucconi’s tutorials secondary tutorial tertiary tutorial cg wikibook hlsl Types: 32 bit float is rarely needed, 16 bit half preferred 10 bit fixed goes from -2 to +2

Basic layout:

Shader "MyShader"
{
  Properties
  {
      // The properties of your shaders
      // - textures
      // - colours
      // - parameters
      // ...
  }

  SubShader
  {
      // The code of your shaders
      // - surface shader
      //    OR
      // - vertex and fragment shader
      //    OR
      // - fixed function shader
  }
}

Properties

Provides unity inspector access to variables

Properties
{
    // Type "2D" indicates texture parameters
    // the subshader type corresponding to "2D" == "sampler2D"
    _MyTexture ("My texture", 2D) = "white" {}
    //bump to indicate a normal map
    _MyNormalMap ("My normal map", 2D) = "bump" {}	// Grey

    _MyInt ("My integer", Int) = 2
        _MyFloat ("My float", Float) = 1.5
        _MyRange ("My range", Range(0.0, 1.0)) = 0.5

        //Colours are RGBA,
        //subshader corresponding type: "float4" or "half4"
        _MyColor ("My colour", Color) = (1, 0, 0, 1)	// (R, G, B, A)
        _MyVector ("My Vector4", Vector) = (0, 0, 0, 0)	// (x, y, z, w)
}

Shader Body

SubShader
{
    Tags
    {
        "Queue"      = "Geometry"
        "RenderType" = "Opaque"
    }
    CGPROGRAM
    // Cg / HLSL code of the shader
    // ...
    ENDCG
}

Tags

Tags define properties of the shader to unity.

Queue : The order to render the shader Rendertype : How to render the shader LightMode : ForwardBase rendering.

Queue Values are an int: Background: 1000, Geometry : 2000, Transparent : 3000, Overlay : 4000

Can also specify offsets: Background+2

Imports

To access global variables: #include “UnityCG.cginc”

Surface Shaders

uses #pragma surface [functionName] [params]

CGPROGRAM
// Uses the Labertian lighting model
#pragma surface surf Lambert
    sampler2D _MainTex;	// The input texture
struct Input {
    float2 uv_MainTex;
};

void surf (Input IN, inout SurfaceOutput o) {
    o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
Shader "Example/Diffuse Simple" {
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
    #pragma surface surf Lambert
            struct Input {
            float4 color : COLOR;
        };
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = 1; // 1 = (1,1,1,1) = white
        }
        ENDCG
            }
    Fallback "Diffuse"
}
Shader "Example/Diffuse Texture" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
    #pragma surface surf Lambert
            struct Input {
            float2 uv_MainTex;
        };
        sampler2D _MainTex;
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        }
        ENDCG
            }
    Fallback "Diffuse"
}

Struct SurfaceOutput:

fixed3 Albedo fixed3 Normal fixed3 Emission half Specular fixed Glass fixed Alpha

Vertex Shaders

uses #pragma vertex [funcName] Where function has the form: vertOutput vert(vertInput)

Pass {
CGPROGRAM

#pragma vertex vert
#pragma fragment frag

struct vertInput {
float4 pos : POSITION;
};

struct vertOutput {
float4 pos : SV_POSITION;
};

vertOutput vert(vertInput input) {
vertOutput o;
o.pos = mul(UNITY_MATRIX_MVP, input.pos);
return o;
}

half4 frag(vertOutput output) : COLOR {
return half4(1.0, 0.0, 0.0, 1.0);
}
ENDCG
}

Fragment Shaders

uses #pragma fragment [functionName] Where the function has form: half4 frag(vertOutput)

Functions and Values

functions in hlsl built in variables vertex data

UNITY_MATRIX_MVP : A Matrix multiplier to convert 3d space to 2d screen position mul : Multiplies two matrices

tex2D : takes a texture and uv coordinate, returns RGBA

_Time, _SinTime, _CosTime : Floats.

Examples

Debug shaders

DebugUVs:

Shader "Custom/DebugUVs" {
 Properties {
     _Amnt ("Amount", float) = 1.0
 }

 SubShader {
     Pass {
         CGPROGRAM
         #include "UnityCG.cginc"
         #pragma target 2.0
         #pragma vertex vert
         #pragma fragment frag

         float4 _LightColor0;
         float _Amnt;

         struct vsIn {
             float4 position : POSITION;
             float3 normal : NORMAL;
             float2 uv : TEXCOORD0;
         };

         struct vsOut {
             float4 position : SV_POSITION;
             float3 normal : NORMAL;
             float4 uv : TEXCOORD0;
         };

         vsOut vert(vsIn v){
             vsOut o;
             o.position = UnityObjectToClipPos(v.position);
             o.uv = float4 ( v.uv.xy, 0, 0);
             return o;
         }

         float4 frag(vsOut psIn) : SV_TARGET {
             half4 c = frac( psIn.uv );
             if (any(saturate(psIn.uv) - psIn.uv)){
                 c.b = 0.5;
             }
             return c;
         }
         ENDCG
     }
 }
}

DebugVerts

Shader "Custom/DebugVerts" {
    Properties {
        _Amnt ("Amount", float) = 1.0
    }

    SubShader {
        Pass {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            float4 _LightColor0;
            float _Amnt;

            struct vsIn {
                float4 position : POSITION;
                float4 color : COLOR;
                float2 uv : TEXCOORD0;
            };

            struct vsOut {
                float4 position : SV_POSITION;
                float4 color : COLOR;
            };

            vsOut vert(vsIn v){
                vsOut o;
                o.position = UnityObjectToClipPos(v.position);
                o.color = v.color;
                return o;
            }

            float4 frag(vsOut psIn) : SV_TARGET {
                return psIn.color;
            }
            ENDCG
        }
    }
}

DebugNormals

Shader "Custom/DebugNormals" {
    Properties {
        _Amnt ("Amount", float) = 1.0
    }

    SubShader {
        Pass {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            float4 _LightColor0;
            float _Amnt;

            struct vsIn {
                float4 position : POSITION;
                float3 normal : NORMAL;
            };

            struct vsOut {
                float4 position : SV_POSITION;
                fixed4 color : COLOR;
            };

            vsOut vert(vsIn v){
                vsOut o;
                o.position = UnityObjectToClipPos(v.position);
                o.color.xyz = v.normal * 0.5 + 0.5;
                o.color.w = 1.0;
                return o;
            }

            float4 frag(vsOut psIn) : SV_TARGET {
                return psIn.color;
            }
            ENDCG
        }
    }
}

Simple lighting

Shader "Custom/DiffuseSimpleWGlobals" {
    SubShader {
        Tags { "LightMode" = "ForwardBase" }
        Pass {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            float4 _LightColor0;

            struct vsIn {
                float4 position : POSITION;
                float3 normal : NORMAL;
            };

            struct vsOut {
                float4 position : SV_POSITION;
                float3 normal : NORMAL;
            };

            vsOut vert(vsIn v){
                vsOut o;
                o.position = UnityObjectToClipPos(v.position);
                o.normal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject));
                return o;
            }

            float4 frag(vsOut psIn) : SV_TARGET {
                float4 ambientLight = UNITY_LIGHTMODEL_AMBIENT;

                float4 LightDirection = normalize(_WorldSpaceLightPos0);
                float4 diffuseTerm = saturate(dot(LightDirection, psIn.normal));
                float4 diffuseLight = diffuseTerm * _LightColor0;

                return ambientLight + diffuseLight;
            }
            ENDCG
        }
    }
}

Simple textured

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/TextureSimple" {
    Properties {
        _MainTexture ("Main Texture", 2D) = "white" {}
        _TexChange ("Tex Change", float) = 0
    }

    SubShader {
        Tags { "LightMode" = "ForwardBase" }
        Pass {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            sampler2D _MainTexture;
            float4 _LightColor0;
            float _TexChange;

            struct vsIn {
                float4 position : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct vsOut {
                float4 position : SV_POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            vsOut vert(vsIn v){
                vsOut o;
                o.position = UnityObjectToClipPos(v.position);
                o.normal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject));
                o.uv = v.uv;
                return o;
            }

            float4 frag(vsOut psIn) : SV_TARGET {
                float4 ambientLight = UNITY_LIGHTMODEL_AMBIENT;

                float4 LightDirection = normalize(_WorldSpaceLightPos0);
                float4 diffuseTerm = saturate(dot(LightDirection, psIn.normal));
                float4 diffuseLight = diffuseTerm * _LightColor0;

                float csin = _SinTime[0] + _SinTime[1] + _SinTime[2];

                //float4 tex = tex2D(_MainTexture, sin(20*(psIn.uv + csin)));
                float4 tex = tex2D(_MainTexture, psIn.uv);
                return ambientLight + diffuseLight + tex;
            }
            ENDCG
        }
    }
}

Simple vertex shader

Shader "Custom/VertMovement" {
    Properties {
        _Amnt ("Amount", float) = 1.0
    }

    SubShader {
        Pass {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma target 2.0
            #pragma vertex vert
            #pragma fragment frag

            float4 _LightColor0;
            float _Amnt;

            struct vsIn {
                float4 position : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct vsOut {
                float4 position : SV_POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            vsOut vert(vsIn v){
                vsOut o;
                o.normal = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject));
                o.uv = v.uv;
                o.position = UnityObjectToClipPos(v.position);
                o.position += float4(o.normal * ((1 + _SinTime[1]) * _Amnt),0);
                return o;
            }

            float4 frag(vsOut psIn) : SV_TARGET {
                float4 ambientLight = UNITY_LIGHTMODEL_AMBIENT;

                float4 LightDirection = normalize(_WorldSpaceLightPos0);
                float4 diffuseTerm = saturate(dot(LightDirection, psIn.normal));
                float4 diffuseLight = diffuseTerm * _LightColor0;

                float csin = _SinTime[0] + _SinTime[1] + _SinTime[2];

                //float4 tex = tex2D(_MainTexture, sin(20*(psIn.uv + csin)));
                return ambientLight + diffuseLight;
            }
            ENDCG
        }
    }
}

Sandbox

class HelloWorld{

    public static void Main(){
        foreach (char character in "hello world".ToCharArray()) {
            System.Console.WriteLine(character);
        }
    }
}

https://github.com/dotnet/csharplang https://github.com/dotnet/csharplang/tree/main/meetings

⚠️ **GitHub.com Fallback** ⚠️