Code Samples

Sample 1: A shader in Unity (using HLSL), to create a repeating, translucent holographic pattern shown on objects in the world. Written for my project Tunnels.

Shader "Unlit/Hologram"
{
    Properties
    {
        _Color("Color", Color) = (1, 0, 0, 1)
        _Brightness("Brightness", Range(0, 1)) = 0.16
        _Contrast("Contrast", Range(0, 10)) = 1
        _Proximity("Band Proximity", Range(1, 50)) = 10 //Related to size of the grid in world space: larger means bands are closer together
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent Cutout" }
        LOD 100
        Blend SrcAlpha One
        Cull Off
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                float4 objVertex : TEXCOORD2;
            };

            fixed4 _Color;
            float _Brightness;
            float _Contrast;
            float _Proximity;

            //Gets each vertex in the object to color
            v2f vert (appdata v)
            {
                v2f o;
                o.objVertex = mul(unity_ObjectToWorld, v.vertex); //Needed to tie shader to the world, rather than object, coordinates
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            //Applies a formula to a specific coordinate for use in the frag function
            float modCoordVal(float c, float mult)            { return max(0.35, cos(c * _Proximity * mult)); }
            float modCoordVal(float c, float mult, float exp)	{ return max(0.35, pow(cos(c * _Proximity * mult), exp)); }

            //This function creates the repeating pattern using cosine and powers to color the object.
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = _Color * (modCoordVal(i.objVertex.y, 0.2) + modCoordVal(i.objVertex.z, 0.1, 5) + modCoordVal(i.objVertex.x, 0.1, 5));
                col += _Color * (modCoordVal(i.objVertex.y, 1) + modCoordVal(i.objVertex.z, 0.5, 5) + modCoordVal(i.objVertex.x, 0.5, 5));
                col = pow(col * _Brightness, _Contrast);
                return col;
            }
            ENDCG
        }
    }
}

Sample 2: A first person camera control script written in C# for Unity. Used in my project Dim.

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

public class ControlCamera : MonoBehaviour
{
    float lookSpeed = 0.5f;
    int smoothAmount = 8;
    Vector2[] lookVectors;
    private Vector2 averageLookVector = Vector2.zero;

    //Start is called before the first frame update
    void Start()
    {
        lookVectors = new Vector2[smoothAmount];
        for (int i = 0; i < smoothAmount; i++) lookVectors[i] = Vector2.zero;
    }

    //Update is called once per frame
    void Update()
    {
        averageLookVector = Vector2.zero;
        Vector2 currLookVec = new Vector2(Input.GetAxis("Mouse X") * lookSpeed, Input.GetAxis("Mouse Y") * -lookSpeed);

        //Smooths camera rotation by averaging the raw mouse delta out over a number of frames
        for (int i = 0; i < lookVectors.Length-1; i++)
        {
            lookVectors[i] = lookVectors[i + 1];
            averageLookVector += lookVectors[i];
        }
        lookVectors[lookVectors.Length-1] = currLookVec;
        averageLookVector += currLookVec;
        averageLookVector /= smoothAmount;
        
        
        transform.parent.Rotate(0f, averageLookVector.x, 0f); //Rotate the camera's parent (the player game object) on the horizontal axis to fit with WASD controls
        transform.Rotate(averageLookVector.y, 0f, 0f);

        transform.localRotation = Quaternion.Euler(ClampAngle(transform.rotation.eulerAngles.x, -80f, 80f), 0f, 0f); //Clamp vertical look rotation
    }

    /// <summary> Clamps an angle between a minimum and maximum value. </summary>
    float ClampAngle(float angle, float min, float max)
    {
        if (angle < 0f) angle += 360f;
        if (angle < 180f) return Mathf.Min(angle, min + 360f);
        else return Mathf.Max(angle, max);
    }
}

Sample 3: The main loop of my tower defense o, written in Java/Processing.

import processing.sound.*;

//This file contains the main functions, variables, and game loop

color[][] schemes;
Enemy[][] gameWaves;

//declare enums for color scheme, game screen, etc.
enum ColorScheme
{
  NEON (0), DARK (1), LIGHT (2), EYESORE (3);
  
  private int index;
  private ColorScheme(int index) { this.index = index; }
}
enum Screen { MENU, GAME, TUTORIAL, VICTORY, GAMEOVER, PAUSE }
enum Building { WALL, TURRET, MORTAR, CALTROP };
enum Music { MENUTRACK, GAMETRACK };
enum GameState { NOTENDED, LOSS, VICTORY };

ColorScheme scheme = ColorScheme.NEON;
Screen screen = Screen.MENU;
Building buildIndex = Building.WALL;
Music musIndex = Music.MENUTRACK;
GameState state = GameState.NOTENDED;

//Initialize lists of game objects
ArrayList<Wall> walls = new ArrayList<Wall>();
ArrayList<Turret> turrets = new ArrayList<Turret>();
ArrayList<Mortar> mortars = new ArrayList<Mortar>();
ArrayList<Caltrop> caltrops = new ArrayList<Caltrop>();
ArrayList<Enemy> enemies = new ArrayList<Enemy>();
ArrayList<TurretProjectile> tShots = new ArrayList<TurretProjectile>();
ArrayList<MortarProjectile> mShots = new ArrayList<MortarProjectile>();

//Declare game screen objects
OLetter oLetter;
MenuScreen menuScreen;
TutorialScreen tutorialScreen;
GameScreen gameScreen;
VictoryScreen victoryScreen;
GameOverScreen gameOverScreen;
PauseScreen pauseScreen;

int wave = 0; //declare and init wave number
int orium = 100; //declare and init amount of orium
float gameAnimSize = 0; //the starting size of the game end animation

SoundFile menuMusic; //declare menu and game music
SoundFile gameMusic;
Sound soundMaster;
float volume = 0.4;
float targetVolume = 0.4;

PImage icon;

//Setup is called when the game starts
void setup()
{
  size(960, 720);
  icon = loadImage("o_icon.png");
  refreshScheme(); //initializes color schemes
  refreshWaves(); //inits the schedule of enemies
  oLetter = new OLetter(); //inits o and the screen objects
  menuScreen = new MenuScreen();
  tutorialScreen = new TutorialScreen();
  gameScreen = new GameScreen();
  victoryScreen = new VictoryScreen();
  gameOverScreen = new GameOverScreen();
  pauseScreen = new PauseScreen();
  
  menuMusic = new SoundFile(this, "ombience.wav");
  gameMusic = new SoundFile(this, "sonorance.wav");
  soundMaster = new Sound(this);
  soundMaster.volume(volume);
}

//Draw is called every frame
void draw()
{
  background(schemes[scheme.index][0]); //color background according to the scheme
  oLetter.update(); //update the o object
  //Adjust volume if necessary
  if (volume < targetVolume)
  {
    volume += 0.05;
    if (volume > targetVolume) volume = targetVolume;
  }
  else if (volume > targetVolume)
  {
    volume -= 0.05;
    if (volume < targetVolume) volume = targetVolume;
  }
  soundMaster.volume(volume);
  
  //update UI and music according to the screen
  switch(screen)
  {
    case MENU: menuScreen.update();
            musIndex = Music.MENUTRACK;
            break;
    case TUTORIAL: tutorialScreen.update();
            musIndex = Music.MENUTRACK;
            break;
    case VICTORY: victoryScreen.update();
            musIndex = Music.GAMETRACK;
            break;
    case GAMEOVER: gameOverScreen.update();
            musIndex = Music.GAMETRACK;
            break;
    case PAUSE: pauseScreen.update();
            musIndex = Music.GAMETRACK;
            break;
    case GAME:
    //Here all objects in play in the main game screen are displayed
      for (Wall w : walls)       w.display();
      for (Turret t : turrets)   t.update();
      for (Mortar m : mortars)   m.update();
      for (Caltrop c : caltrops) c.display();
      for (Enemy e : enemies)    e.update();
      for (TurretProjectile tp : tShots) tp.update();
      for (MortarProjectile mp : mShots) mp.update();
      gameScreen.update(); //update the UI
      
      //These are actions dependent on whether the game is won, lost, or still going
      switch(state)
      {
        case NOTENDED:
          //go through objects that need to be deleted and remove them
          for (int i = 0; i < enemies.size(); i++) if (enemies.get(i).hp <= 0) enemies.remove(i); 
          for (int i = 0; i < tShots.size(); i++) if (tShots.get(i).doDestroy) tShots.remove(i);
          for (int i = 0; i < mShots.size(); i++) if (mShots.get(i).stage == 2) mShots.remove(i);
          if (enemies.size() == 0) //if the wave is over
          {
            if (wave + 1 < gameWaves.length) //if it isn't the end of the game
            {
              wave++;
              for (Enemy e : gameWaves[wave]) //set and add all the enemies in the next wave to the list
              {
                e.startTime = millis();
                enemies.add(e);
              }
              refreshScheme(); //randomize the colors again
            }
            else state = GameState.VICTORY; //if it is, set the end condition
          }
          break;
        //On a loss or victory, a short animation plays before transferring to the appropriate screen
        case LOSS:
          gameAnimSize += 20;
          noStroke();
          fill(schemes[scheme.index][3]);
          circle(width/2, height/2, gameAnimSize);
          if (gameAnimSize > 1450) screen = Screen.GAMEOVER;
          break;
        case VICTORY:
          gameAnimSize += 20;
          strokeWeight(10);
          fill(schemes[scheme.index][0]);
          stroke(schemes[scheme.index][2]);
          circle(width/2, height/2, gameAnimSize);
          if (gameAnimSize > 1450) screen = Screen.VICTORY;
          break;
      }
      musIndex = Music.GAMETRACK;
      break;
  }
  //Switch out currently playing music if necessary
  if (musIndex == Music.MENUTRACK)
  {
    if  (gameMusic.isPlaying()) gameMusic.stop();
    if (!menuMusic.isPlaying()) menuMusic.play();
  }
  else
  {
    if  (menuMusic.isPlaying()) menuMusic.stop();
    if (!gameMusic.isPlaying()) gameMusic.play();
  }
}

//Called when any key is pressed
void keyPressed()
{
  //In the game and tutorial screens, 1-4 are hotkeys to select buildings.
  if (screen == Screen.GAME || screen == Screen.TUTORIAL)
  {
    switch(key)
    {
      case '1': buildIndex = Building.WALL;
                break;
      case '2': buildIndex = Building.TURRET;
                break;
      case '3': buildIndex = Building.MORTAR;
                break;
      case '4': buildIndex = Building.CALTROP;
                break;
    }
  }
  //In the menu screen, those same keys may be used to set a color scheme
  else if (screen == Screen.MENU)
  {
    switch(key)
    {
      case '1': scheme = ColorScheme.NEON;
                break;
      case '2': scheme = ColorScheme.DARK;
                break;
      case '3': scheme = ColorScheme.LIGHT;
                break;
      case '4': scheme = ColorScheme.EYESORE;
                break;
    }
  }
  //The Escape key may either bring up the pause menu or return to the main menu, depending on the screen.
  if (keyCode == 27)
  {
    key = 0;
    switch(screen)
    {
      case GAME: screen = Screen.PAUSE;
              pauseScreen.pauseTime = millis();
              targetVolume = 0.1;
              break;
      case TUTORIAL: screen = Screen.MENU;
              break;
      case VICTORY: screen = Screen.MENU;
              break;
      case GAMEOVER: screen = Screen.MENU;
              break;
      case PAUSE: screen = Screen.GAME;
              for (Enemy e : enemies) e.startTime += pauseScreen.pauseDuration;
              targetVolume = 0.4;
              break;
      default: break;
    }
  }
}

//Called when the mouse is released
void mouseReleased()
{
  //Left clicking will either press buttons, or in the game screen place buildings.
  if (mouseButton == LEFT)
  {
    switch(screen)
    {
      case MENU:
        if (menuScreen.playButton.mouseOver())
        {
          screen = Screen.GAME;
          gameScreen.init();
        }
        else if (menuScreen.tutorialButton.mouseOver())
        {
          screen = Screen.TUTORIAL;
          tutorialScreen.init();
        }
        else if (menuScreen.neonSchemeButton.mouseOver()) scheme = ColorScheme.NEON;
        else if (menuScreen.darkSchemeButton.mouseOver()) scheme = ColorScheme.DARK;
        else if (menuScreen.lightSchemeButton.mouseOver()) scheme = ColorScheme.LIGHT;
        else if (menuScreen.eyesoreSchemeButton.mouseOver()) scheme = ColorScheme.EYESORE;
        break;
      case GAME:
      //This is where buildings are placed
      //Aligns click position to a grid, and checks to see whether you can build there first
        float placeX = floor(mouseX / 40) * 40;
        float placeY = floor(mouseY / 40) * 40;
        if (!buildingCollision(placeX, placeY) && calculateOrium() >= 0)
        {
          switch (buildIndex)
          {
            case WALL: Wall w = new Wall(placeX, placeY);
                    walls.add(w);
                    orium -= 10;
                    break;
            case TURRET: Turret t = new Turret(placeX, placeY);
                    turrets.add(t);
                    orium -= 25;
                    break;
            case MORTAR: Mortar m = new Mortar(placeX, placeY);
                    mortars.add(m);
                    orium -= 35;
                    break;
            case CALTROP: Caltrop c = new Caltrop(placeX, placeY);
                    caltrops.add(c);
                    orium -= 15;
                    break;
          }
        }
        else //These are the buttons on the game screen
        {
          if (gameScreen.wallButton.mouseOver()) buildIndex = Building.WALL;
          else if (gameScreen.turretButton.mouseOver()) buildIndex = Building.TURRET;
          else if (gameScreen.mortarButton.mouseOver()) buildIndex = Building.MORTAR;
          else if (gameScreen.caltropButton.mouseOver()) buildIndex = Building.CALTROP;
        }
        break;
      case TUTORIAL:
        if (tutorialScreen.returnButton.mouseOver()) screen = Screen.MENU;
        else if (tutorialScreen.wallButton.mouseOver()) buildIndex = Building.WALL;
        else if (tutorialScreen.turretButton.mouseOver()) buildIndex = Building.TURRET;
        else if (tutorialScreen.mortarButton.mouseOver()) buildIndex = Building.MORTAR;
        else if (tutorialScreen.caltropButton.mouseOver()) buildIndex = Building.CALTROP;
        break;
      case VICTORY:
        if (victoryScreen.returnButton.mouseOver()) screen = Screen.MENU;
        break;
      case GAMEOVER:
        if (gameOverScreen.returnButton.mouseOver()) screen = Screen.MENU;
        break;
      case PAUSE:
        if (pauseScreen.unpauseButton.mouseOver())
        {
          for (Enemy e : enemies) e.startTime += pauseScreen.pauseDuration;
          screen = Screen.GAME;
          targetVolume = 0.4;
        }
        else if (pauseScreen.menuButton.mouseOver())
        {
          targetVolume = 0.4;
          screen = Screen.MENU;
        }
        break;
    }
  }
  //Delete any placed buildings on right click
  else if (mouseButton == RIGHT && screen == Screen.GAME && mouseY > 80) deleteBuilding();
}