FACEOFF_SYSTEM_README.md 8.9 KB

Hockey Faceoff System Documentation

Overview

A complete faceoff and puck possession system for your hockey game with realistic physics, visual indicators, and AI-ready mechanics.


📦 Components Created

1. PuckController.cs

Controls the puck physics and possession mechanics.

Features:

  • Realistic hockey puck physics (170g mass, low friction)
  • Automatic possession detection via trigger colliders
  • Visual feedback (different materials for possessed/free states)
  • Smooth carrying while player has possession
  • Physics-based shooting and passing

Key Properties:

  • possessionRadius: Distance within which players can pick up the puck (default: 1.5m)
  • carrierOffset: How far in front of player the puck stays when carried (default: 1.0m)

2. FaceoffManager.cs

Manages the entire faceoff sequence and outcome determination.

Faceoff Outcomes:

  • Home Win: Home center wins cleanly, puck passed to teammate (usually defender)
  • Away Win: Away center wins cleanly, puck passed to teammate (usually defender)
  • Struggle: Close contest, puck bounces loose, scramble ensues

How Outcomes Are Determined:

Faceoff Strength = (Strength × 0.3) + (Stick Handling × 0.3) + 
                   (Awareness × 0.2) + (Agility × 0.2)

Plus random variation (±10 points) for unpredictability.

Testing: Press F key during play mode to trigger a faceoff.

3. PlayerController.cs (Updated)

Enhanced with puck interaction methods.

New Methods:

  • GainPuck(PuckController): Called when player gains possession
  • ReleasePuck(): Called when player loses possession
  • CanPickupPuck(): Checks if player can currently pick up puck
  • SetFrozen(bool): Freeze/unfreeze player during faceoff
  • Shoot(direction, power): Fire the puck with physics
  • Pass(targetPlayer): Pass to specific teammate
  • Check(targetPlayer): Body check opponent to dislodge puck

Visual Feedback:

  • Yellow rotating ring appears around player with possession
  • Makes it instantly clear who controls the puck

🎮 Setup Instructions

Method 1: Manual Setup

  1. Create the Puck:

    - Create GameObject → name it "Puck"
    - Add PuckController component
    - Position at center ice (y ≈ 0.5 for ice level)
    
  2. Tag Your Players:

    - Edit → Project Settings → Tags & Layers
    - Add tags: "HomeTeam" and "AwayTeam"
    - Select home team players → Inspector → Tag: "HomeTeam"
    - Select away team players → Inspector → Tag: "AwayTeam"
    
  3. Create Faceoff Manager:

    - Create Empty GameObject → name it "FaceoffManager"
    - Add FaceoffManager component
    - Drag Puck into the "Puck" field in Inspector
    
  4. Verify Centers:

    • Ensure one player on each team has Position = "C" (Center)
    • The FaceoffManager auto-detects centers by tag and position

Method 2: Auto Setup (Recommended)

  1. Create an empty GameObject
  2. Add FaceoffSetupGuide component
  3. Drag home team players into "Home Team Players" array
  4. Drag away team players into "Away Team Players" array
  5. Right-click component → "Auto-Setup Faceoff System"
  6. Right-click component → "Validate Setup" to check everything

🏒 How It Works

Possession System

Puck States:

  • Loose: No one has possession, slides freely on ice
  • Carried: Attached to a player, moves with them

Gaining Possession: Player automatically picks up puck when:

  1. Player is within possessionRadius (1.5m)
  2. Puck is loose (not carried by anyone)
  3. Player can pickup (not on cooldown, not frozen)
  4. Puck enters player's trigger collider

Visual Indicator:

  • Yellow ring with emission around player = has puck
  • Ring rotates continuously for visibility

Faceoff Sequence

1. FaceoffManager.StartFaceoff() called
   ↓
2. Puck positioned at faceoff spot
   ↓
3. All players frozen (prevent movement)
   ↓
4. Calculate outcome based on center stats
   ↓
5. Execute outcome:
   - Clean Win: Puck passed to defender
   - Struggle: Puck bounces loose
   ↓
6. Unfreeze all players
   ↓
7. Game continues

Timing:

  • Wind-up: 1 second
  • Faceoff duration: 2 seconds
  • Struggle duration: 3 additional seconds

Physics Details

Puck Properties:

  • Mass: 0.17 kg (170g, regulation weight)
  • Radius: 0.038m (76mm diameter)
  • Friction: 0.3 (simulates ice)
  • Bounciness: 0.2 (minimal bounce)

Force Ranges:

  • Pass: 10-25 N (scales with distance)
  • Shot: ~30 N × power stat
  • Faceoff launch: 5-15 N

🎯 Integration Examples

Example 1: Start Faceoff at Game Start

public class GameManager : MonoBehaviour
{
    private FaceoffManager faceoffManager;
    
    void Start()
    {
        faceoffManager = FindObjectOfType<FaceoffManager>();
        
        // Start game with center ice faceoff
        Vector3 centerIce = new Vector3(0, 0.5f, 0);
        faceoffManager.InitiateFaceoff(centerIce);
    }
}

Example 2: Player Shoots on Goal

public class PlayerAI : MonoBehaviour
{
    private PlayerController playerController;
    private Transform goal;
    
    void ShootAtGoal()
    {
        if (playerController.HasPuck())
        {
            Vector3 shootDirection = (goal.position - transform.position).normalized;
            playerController.Shoot(shootDirection, powerMultiplier: 1.0f);
        }
    }
}

Example 3: Pass to Open Teammate

public void PassToOpenPlayer()
{
    if (!playerController.HasPuck()) return;
    
    PlayerController[] teammates = FindTeammates();
    PlayerController bestTarget = FindMostOpen(teammates);
    
    if (bestTarget != null)
    {
        playerController.Pass(bestTarget);
    }
}

Example 4: Defensive Check

void OnCollisionEnter(Collision collision)
{
    PlayerController opponent = collision.gameObject.GetComponent<PlayerController>();
    
    if (opponent != null && opponent.HasPuck() && IsOpponent(opponent))
    {
        playerController.Check(opponent);
    }
}

🔧 Customization

Adjust Faceoff Difficulty

In FaceoffManager.cs:

[SerializeField] private float struggleChance = 0.3f; // 30% base struggle chance
[SerializeField] private float winThreshold = 0.7f;    // Higher = more clear wins needed

Change Puck Physics

In PuckController.cs:

[SerializeField] private float friction = 0.3f;  // Lower = slides further
[SerializeField] private float drag = 0.5f;      // Higher = stops faster

Modify Possession Range

In PuckController.cs:

[SerializeField] private float possessionRadius = 1.5f; // Detection range

🐛 Troubleshooting

Puck doesn't get picked up

  • Check that player has trigger collider
  • Verify CanPickupPuck() returns true
  • Check pickup cooldown hasn't expired

Faceoff doesn't start

  • Verify both centers are tagged correctly
  • Check console for error messages
  • Run "Validate Setup" in FaceoffSetupGuide

Players don't freeze during faceoff

  • Ensure PlayerController has SetFrozen() method
  • Check that player movement script respects frozen state

Possession indicator doesn't show

  • Verify possessionIndicator GameObject is created in PlayerController.Start()
  • Check that Update() is being called

📊 Stats That Matter

For Faceoffs:

  • Strength (30%): Physical dominance
  • Stick Handling (30%): Puck control
  • Awareness (20%): Reading the drop
  • Agility (20%): Quick reactions

For Shooting:

  • Shot Accuracy: Determines spread angle
  • Shot Power: Determines puck velocity

For Passing:

  • Pass Accuracy: Determines pass precision

For Checking:

  • Checking: Success rate of dislodging puck

🎨 Visual Enhancements (Optional)

Add Trail to Puck:

TrailRenderer trail = puck.gameObject.AddComponent<TrailRenderer>();
trail.time = 0.5f;
trail.startWidth = 0.1f;
trail.endWidth = 0.02f;

Add Particles When Puck is Hit:

// In PuckController.OnCollisionEnter()
ParticleSystem.Emit(5); // Ice spray effect

Change Possession Ring Color by Team:

if (CompareTag("HomeTeam"))
    possessionIndicator.GetComponent<Renderer>().material.color = Color.blue;
else
    possessionIndicator.GetComponent<Renderer>().material.color = Color.red;

🚀 Next Steps

  1. Add Goalie: Extend PlayerController for goalie-specific behavior
  2. Implement Offsides: Check puck/player positions
  3. Add Icing: Detect long-range clears
  4. Improve AI: Use puck position in decision-making
  5. Add Penalties: Faceoff after penalty ends
  6. Post-Goal Faceoffs: Return to center after scoring

Summary

You now have: ✅ Physics-based puck with realistic ice behavior
✅ Clear visual indication of possession (yellow ring)
✅ Faceoff system with 3 outcomes based on player stats
✅ Ready-to-use shooting, passing, and checking mechanics
✅ Easy integration with your existing player system

Test it: Press F in play mode to see a faceoff in action!