Crosshair Design: Subtle but Crucial
The crosshair is one of those UI elements players stare at for hours. It needs to be visible but not distracting, responsive but not jumpy. Here's how we built ours in Unity.
🔗
Looking for ready-made crosshairs?
Check out our Crosshair UI component in UnityUIBuilder — 5 designs ready to drop into your project.
Check out our Crosshair UI component in UnityUIBuilder — 5 designs ready to drop into your project.
The Philosophy
A good crosshair disappears until you need it. It shows you what you're aiming at without blocking the view. It changes to tell you something — "you can interact" or "you're aiming at an enemy". subtlety is key.
UI Toolkit Setup
We're using Unity's UI Toolkit for runtime UI. Here's the basic structure:
The USS Styles
/* Crosshair.uss */
.crosshair {
position: absolute;
width: 32px;
height: 32px;
left: 50%;
top: 50%;
translate: -50% -50%;
}
.crosshair-line {
position: absolute;
background-color: rgba(255, 255, 255, 0.8);
transition: all 0.1s ease-out;
}
.crosshair-line.top {
width: 2px;
height: 8px;
top: 0;
left: 50%;
translate: -50% 0;
}
.crosshair-line.bottom {
width: 2px;
height: 8px;
bottom: 0;
left: 50%;
translate: -50% 0;
}
.crosshair-line.left {
width: 8px;
height: 2px;
left: 0;
top: 50%;
translate: 0 -50%;
}
.crosshair-line.right {
width: 8px;
height: 2px;
right: 0;
top: 50%;
translate: 0 -50%;
}
.crosshair-dot {
width: 4px;
height: 4px;
background-color: rgba(255, 255, 255, 0.6);
border-radius: 50%;
position: absolute;
left: 50%;
top: 50%;
translate: -50% -50%;
}
/* Dynamic states */
.crosshair.interactable .crosshair-line {
background-color: rgba(74, 222, 128, 0.9);
scale: 1.1;
}
.crosshair.target-enemy .crosshair-line {
background-color: rgba(244, 67, 54, 0.9);
}
.interaction-hint {
position: absolute;
top: 40px;
left: 50%;
translate: -50% 0;
color: rgba(255, 255, 255, 0.8);
font-size: 12px;
-unity-text-align: middle-center;
}
The Controller Script
The crosshair responds to game state. Here's the C# controller:
using UnityEngine;
using UnityEngine.UIElements;
public class CrosshairController : MonoBehaviour
{
[SerializeField] private UIDocument uiDocument;
[SerializeField] private PlayerInteraction playerInteraction;
private VisualElement crosshairRoot;
private Label interactionHint;
void Start()
{
var root = uiDocument.rootVisualElement;
crosshairRoot = root.Q("crosshair-root");
interactionHint = root.Q
Context-Aware Design
The crosshair changes based on what you're looking at:
- Default: White, small, unobtrusive
- Interactable: Green, slightly larger, with text hint
- Enemy: Red tint for combat feedback
Connection to Our Open World
This crosshair ties directly into our raycasting system. The visual feedback reinforces what the raycast detects. It's a small detail that makes the world feel responsive.
🎨
Want to customize this?
Browse 5 crosshair designs you can modify and export for your own projects.
Browse 5 crosshair designs you can modify and export for your own projects.