Douglas Adams

“I may not have gone where I intended to go, but I think I have ended up where I needed to be”

– Douglas Adams

Get a free custom email address for your domain

I found this great guide (with video!) from Elliott Callender that shows you how to link your domain with a personal gmail account. You can send and receive emails from a custom email address directly from gmail.

It only takes a few minutes and it's completely free. You can also set up multiple addresses. Perfect for side projects.

Here's the guide on Notion: https://www.notion.so/Hook-Up-Custom-Domains-To-Gmail-f227238798244f7abb69290e3691d54d

You can find Elliott on Twitter: @nu_elliot

Unity Game – Weapons and Damage

This is the second in a series of posts about a first-person shooter project I worked on during lockdown. In this post I'm going to give an overview of the weapon and damage systems. The idea was to make a 'retro' shooter loosely based on Half Life 1.

I wasn't sure exactly what weapons would be in the game so I tried to keep the system fairly flexible, allowing for a wide range of different types of weapons. I started with a PlayerWeapon.cs base class that all weapons could inherit from:

public class PlayerWeapon : MonoBehaviour
{
    // Weapon attributes are held in this scriptable object
    public WeaponData data;

    public virtual void Init(Player player) { }
    public virtual void Equip() { }
    public virtual void Unequip() { }
    public virtual void OnPrimaryHold() { }
    public virtual void OnPrimaryRelease() { }
    public virtual void Reload() { }
    public virtual void UpdateHUD() { }
}

WeaponData holds attributes like range, damage per shot etc. Below you can see a snippet of the WeaponData.cs ScriptableObject file. ScriptableObjects are data containers that you can use to save large amounts of data, independent of class instances. Storing weapon data this way makes it easy to tweak values while testing and quickly create lots of variants.

[CreateAssetMenu(fileName="New Weapon Data", menuName="Data/Weapon Data")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public WeaponType weaponType;
    [Tooltip("Lower is more accurate. Higher is less accurate. 0 is perfect accuracy.")]
    public float accuracy;
    ...
    public float damagePerShot;
    ...
}

Guns. Lots of Guns

All guns work in roughly the same way so rather than writing bespoke code for every gun I wrote one big(ish) class that covered all the variations I could think of. PlayerGun.cs handles:

  • hitscan weapons (instant hit)
  • projectiles (e.g. rockets)
  • single or multiple 'pellets' per shot (shotguns)
  • modifiable accuracy
  • reloading
  • tracer fire every n shots

The same script can be used for a pistol, assault rifle, shotgun, sniper rifle or rocket launcher.

I'm not going to go through it line by line because it's quite long and not all that interesting (a simple state machine triggered by input from the Player class). The code is available on GitHub:
https://github.com/DavidJAbb/unity-shooter/blob/main/Weapons/PlayerGun.cs

How to simulate accuracy

It's not very realistic if every weapon has pinpoint accuracy so the function below was my simple way of introducing some inaccuracy.

public Vector3 ReturnAttackPointWithModifiedAccuracy() {
    Vector2 accuracyModifier = UnityEngine.Random.insideUnitCircle * data.accuracy;
    Vector3 modifiedAttackPos = _hitTarget;
    modifiedAttackPos.x += accuracyModifier.x;
    modifiedAttackPos.y += accuracyModifier.y;
    return modifiedAttackPos;
}

It works by picking a random point inside a circle (the size of which is based on an accuracy value in the scriptable object data file), then it uses that to modify the position of the hitTarget (the centre of the screen). It gives pretty convincing results. An improvement would be to increase the size of the circle if the fire button is held down.

Bullet hits

The Hit class was my way passing data about a bullet hit from a gun to another object, like an enemy. This is useful because as well as just passing damage values, you can do things like applying force in the correct direction or calculate where a blood decal should be placed. And it can be expanded if you decide you want different damage types etc. for now it's just the amount of damage, the hit point, and the hit direction.

[System.Serializable]
public class Hit
{
    public float damage;
    public Vector3 point;
    public Vector3 direction;

    public Hit(float hitDamage, Vector3 hitPoint, Vector3 hitDirection)
    {
        this.damage = hitDamage;
        this.point = hitPoint;
        this.direction = hitDirection;
    }
}

Damage

So we have a PlayerGun that can fire bullets and create Hits. To actually affect other characters or bits of the environment we need a few more elements. First is the IDamageable interface:

public interface IDamageable
{
    void TakeHit(Hit hit);
    void TakeDamage(float damage);
}

IDamageable can be implemented by any class that needs to take damage. Here's an example – DamageablePart a generic class that can be used for anything from a crate to a soldier's head. It uses a C# action delegate to communicate the hit to any subscribed scripts:

public class DamageablePart : MonoBehaviour, IDamageable
{
    public float damageMultiplier = 1; // e.g. Head does double damage / arm does half.
    public Action<Hit> OnDamage;

    public void TakeDamage(float damageAmount) { }

    public void TakeHit(Hit hit) {
        if(OnDamage != null)
        {
            hit.damage *= damageMultiplier;
            OnDamage(hit);
        }
    }
}

Then finally in a script for an object like DestructibleProp that has child objects with DamageablePart scripts attached you subscribe the parts to a function like Damage

// DestructibleProp.cs
private void Awake()
{
    // Get all of the DamageableParts and subscribe them to Damage
    DamageablePart[] parts = GetComponentsInChildren<DamageablePart>();
    foreach (DamageablePart part in parts)
    {
        part.OnDamage += Damage;
    }
}

private void Damage(Hit hit)
{
    health -= hit.damage;
    // Explode when health is at 0
}

All of this comes together to create a robust system of being able to shoot stuff and have that stuff react. And there's lots of room for expansion.

You can find all of the weapon code in /Weapons along with everything else in the project's GitHub repository:
https://github.com/DavidJAbb/unity-shooter

Unity Game – Interaction System

Screenshot of an enemy soldier – model by Polygon Blacksmith

This is the first in a (planned) series of posts about a first-person shooter project I worked on during lockdown. I wanted to make a 'retro' shooter a little like Half Life 1, my favourite game as a kid. I used Unity 2019.4.3f1 and the code is all C#.

In this post I'm going to give an overview of the interaction system. I wanted a simple, modular system that enabled the player to interact with lots of different things – i.e. doors, buttons, health pickups, non-player characters etc.

Player Input and Raycasting

The following code in the Player.cs class lets the player press a key to try to interact with objects. When the key is pressed we fire a ray through the centre of the screen into the world. The ray length is limited so the player can only interact with things that are roughly in arms length. With a layer mask we also limit the layers that can be interacted with. I set all interactable object colliders to an 'Interactable' layer. If the ray hits an object on the 'Interactable' layer we try to get its IInteractable component. If the IInteractable component exists, we call its Interact function.

// Player presses 'E' to interact
if (Input.GetKeyDown(KeyCode.E))
{
  Vector3 screenCentre = new Vector3(cam.pixelWidth * 0.5f, cam.pixelHeight * 0.5f, 0)
  Ray ray = cam.ScreenPointToRay(screenCentre);
  RaycastHit hit;

  if (Physics.Raycast(ray, out hit, interactDistance, interactLayerMask))
  {
    IInteractable interactable = hit.collider.GetComponent<IInteractable>();

    if (interactable != null)
    {
      interactable.Interact();
    }
  }
}

Using Interfaces

IInteractable is an interface that can be implemented in lots of different classes. I used interfaces rather than inheritance because I felt it would keep the code fairly clean, even as the requirements for different objects became more complex. For example, a door could be 'interactable' to allow the player to open and close it, but it could also be 'damageable' to allow the player to destroy it.

The code needed for an interface is simple – here is IInteractable.cs:

public interface IInteractable
{
  void Interact();
}

Then in the interactable object itself, in this case PickupHealth.cs, we add the interface and write the 'try to add player health' code in the Interact function:

public class PickupHealth : MonoBehaviour, IInteractable
{
  public float healthAmount;

  public void Interact()
  {
    if(GameManager.Instance.player.Health < GameManager.Instance.player.maxHealth)
    {
      GameManager.Instance.player.Heal(healthAmount);
      Destroy(gameObject, 0.05f);
    }
  }
}

I used this simple but effective interaction method for doors, switches, lifts (elevators), ammo pickups, health pickups, weapon pickups, readable objects, and conversations with friendly characters.

You can find examples in /Interactables in the project's GitHub repository: https://github.com/DavidJAbb/unity-shooter

Implementing dark mode with CSS variables

Light mode / dark mode comparison

When researching how to implement dark mode on my site I found this excellent explanation of a css variable method.

The principle is simple – you set colour variables, then provide an alternate 'dark mode' set of colours with a data-theme on the html root element:

:root {
  --bg-colour: white;
}

[data-theme="dark"] {
  --bg-colour: black;
}

Then you set the data-theme with javascript (with a toggle, a button, or whatever you like):

...
document.documentElement.setAttribute('data-theme', 'dark');

Read Ananya Neogi's article for a very clear explanation of the method: https://dev.to/ananyaneogi/create-a-dark-light-mode-switch-with-css-variables-34l8

I added a few extra touches too, like dimming images a little using the css brightness filter.

If you want to go beyond just switching colours you can add custom css on dark-mode elements using [data-theme='your-data-theme-name']:

[data-theme='dark'] ::selection {
  color: var(--bg-color);
  background: #fff2a8;
}

You can definitely go down a rabbit hole when it comes to light / dark mode stuff but this approach seemed pretty simple and scalable.

Custom 404 error pages in Django

It's pretty straightforward to add a custom 404 page to your Django site.

Create a 404.html template in your templates folder. It can be named whatever you want, just make sure you use the same name in your view.

Add the following to your views.py file:

def entry_not_found(
  request,
  exception,
  template_name='404.html'
):
  return render(request, template_name)

Then in urls.py add the following outside of the urlpatterns list:

handler404 = 'your_app.views.entry_not_found'

Remember to set DEBUG = False in your settings to see the results.