Back to all projects

Samurai Fighter: A 2D Arcade Fighting Game

A cutting-edge frontend application built with React 19, TypeScript, and Tailwind CSS, powered by Vite for optimal performance.

React 19TypeScript 5.7HTML CanvasVite 6.1

Building Samurai Fighter: A 2D Battle Game with React and Canvas

Samurai Fighter Title Screen
Title screen for Samurai Fighter

In this post, I'll walk through the implementation of Samurai Fighter, a 2D battle game built with React and the HTML Canvas API. The game features two samurai warriors with animated sprites, authentic combat mechanics, and dynamic sound effects.

Play Samurai Fighter here

Key Components

1. Canvas Component

The Canvas.tsx component serves as the game container, managing:

  • Game loop using requestAnimationFrame
  • Player controls with keyboard input
  • Game state (timer, health, victory conditions)
  • Sprite rendering
// Simplified Canvas setup
const Canvas: React.FC<Props> = ({ width, height }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const requestRef = useRef<number>(0);

  // Game loop
  const animate = (time: number) => {
    const context = canvasRef.current?.getContext("2d");
    if (!context) return;

    // Clear and redraw
    context.fillStyle = "black";
    context.fillRect(0, 0, width, height);

    // Update game objects
    player.update(context);
    enemy.update(context);

    requestRef.current = requestAnimationFrame(animate);
  };

  useEffect(() => {
    requestRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(requestRef.current);
  }, []);

  return <canvas ref={canvasRef} width={width} height={height} />;
};

2. Fighter Class

Samurai Battle Scene
Two warriors locked in combat with attack effects

The Fighter class extends a base Sprite class and adds game-specific functionality:

class Fighter extends Sprite {
  health: number = 100;
  isAttacking: boolean = false;
  attackBox: AttackBoxType;

  attack() {
    if (this.dead || !this.canAttack) return;
    this.switchSprite("attack");
    this.isAttacking = true;
    this.playSound("attack");
  }

  takeHit() {
    this.health -= 10;
    if (this.health <= 0) {
      this.switchSprite("death");
    } else {
      this.switchSprite("takehit");
    }
  }
}

3. Sprite Animation System

The base Sprite class handles animation frames and rendering:

class Sprite {
  framesCurrent: number = 0;
  framesElapsed: number = 0;

  animateFrames() {
    this.framesElapsed++;
    if (this.framesElapsed % this.framesHold === 0) {
      this.framesCurrent = (this.framesCurrent + 1) % this.framesMax;
    }
  }

  draw(ctx: CanvasRenderingContext2D) {
    ctx.drawImage(
      this.image,
      this.framesCurrent * (this.image.width / this.framesMax),
      0,
      this.image.width / this.framesMax,
      this.image.height,
      this.position.x,
      this.position.y,
      (this.image.width / this.framesMax) * this.scale,
      this.image.height * this.scale
    );
  }
}

Creating Sprite Sheets with GIMP

To develop authentic samurai animations:

  1. Prepare Individual Frames

    • Draw or import each animation frame as separate layers
    • Ensure consistent character size and positioning
  2. Create Sprite Sheet

    • Use Filters > Combine > Filmstrip to auto-generate sheets
    • Set frame width/height to match your character dimensions
    • Export as PNG with transparent background
  3. Optimization Tips

    • Use indexed color mode (256 colors) to reduce file size
    • Crop unnecessary transparent areas
    • Maintain consistent frame counts for smooth animations

Pro Tip: Create a grid overlay (Image > Configure Grid) to help align frames perfectly.

Game Features

  1. Sprite Animation

    • Multiple states (idle, run, jump, attack, etc.)
    • Frame-based animation system
    • Smooth transitions between states
  2. Combat System

    • Hit detection using rectangular collision
    • Attack cooldowns
    • Health management
  3. Audio Feedback

    • Attack sounds
    • Hit reactions
    • Victory/death sounds
  4. Game States

    • Timer countdown
    • Victory/defeat conditions
    • Character death animations

Challenges and Solutions

  1. Performance Optimization Using requestAnimationFrame ensures smooth animations while being efficient.

  2. Input Handling The game tracks key states to allow for fluid combinations of movements.

  3. Sprite Management The switchSprite method handles animation transitions while preventing mid-animation interruptions.

Future Improvements

  • Add special moves and combos
  • Implement multiplayer over network
  • Add more characters and stages
  • Improve AI for single-player mode

This implementation demonstrates how React can effectively manage game state while leveraging Canvas for high-performance rendering. The object-oriented design makes it easy to add new features and characters.