Skip to content

Sprite Components Guide

This guide explains how to use sprite components to add visual elements behind or in front of sprites in RPGJS.

Overview

RPGJS allows you to attach custom components to sprites that render either behind or in front of the main sprite graphics. This is useful for adding visual effects like shadows, health bars, status indicators, auras, or other UI elements that should be positioned relative to sprites.

Component Properties

componentsBehind

Components in this array render behind the sprite with a lower z-index. Perfect for:

  • Shadow effects
  • Aura or glow effects
  • Ground-based visual elements
  • Background decorations

componentsInFront

Components in this array render in front of the sprite with a higher z-index. Perfect for:

  • Health bars
  • Status effect indicators
  • Damage numbers
  • Name tags
  • UI overlays

Creating Sprite Components

Sprite components are Canvas Engine components (.ce files) that receive the sprite object as a prop.

Basic Component Structure

javascript
<!-- shadow.ce -->
<Ellipse 
  x={shadow.x} 
  y={shadow.y} 
  width={shadow.width} 
  height={shadow.height} 
  color="black" 
  blur={10} 
  alpha={0.5}
/>

<script>
  import { computed } from "canvasengine";
  
  const { object } = defineProps();
  
  const hitbox = object.hitbox;
  const shadow = computed(() => ({
    x: hitbox().w / 2,
    y: hitbox().h - (hitbox().h / 2),
    width: hitbox().w + 10,
    height: hitbox().h,
  }));
</script>

Health Bar Component Example

javascript
<!-- healthbar.ce -->
<Container x={healthBarX} y={healthBarY}>
  <Rect
    width={healthBarWidth} 
    height={healthBarHeight} 
    color="red" 
  />
  <Rect 
    width={healthBarWidth} 
    height={healthBarHeight} 
    color="green" 
  />
</Container>

<script>
  import { computed } from "canvasengine";
  
  const { object } = defineProps();
  const hp = object.hp;
  const maxHp = object.param.maxHp;
  const hitbox = object.hitbox;
  const healthBarX = computed(() => hitbox().w / 2 - 25);
  const healthBarY = -10
  const healthBarWidth = computed(() => {
    return (hp() / maxHp()) * 50;
  });
  const healthBarHeight = 6;
</script>

Configuration Methods

Method 1: Module Configuration

Configure components globally for all sprites in your module:

typescript
// client.ts
import { RpgClient, defineModule } from '@rpgjs/client';
import ShadowComponent from './components/shadow.ce';
import HealthBarComponent from './components/healthbar.ce';

export default defineModule<RpgClient>({
  sprite: {
    componentsBehind: [ShadowComponent],
    componentsInFront: [HealthBarComponent]
  }
})

Method 2: Engine Methods

Add components dynamically using the engine:

typescript
// During game initialization
import { RpgClientEngine, inject } from '@rpgjs/client';

const engine = inject(RpgClientEngine);

// Add components behind sprites
engine.addSpriteComponentBehind(ShadowComponent);

// Add components in front of sprites  
engine.addSpriteComponentInFront(HealthBarComponent);

Advanced Component Configuration

Sprite components support advanced configuration options that allow you to:

  • Pass static or dynamic props to components
  • Control when components are displayed using dependencies
  • Wait for data to be ready before rendering

Component Configuration Object

Instead of passing a component directly, you can use a configuration object with three optional properties:

typescript
{
  component: ComponentClass,      // Required: The component to render
  props: Object | Function,       // Optional: Props to pass to the component
  dependencies: Function          // Optional: Dependencies that must be resolved
}

Props Configuration

The props property can be either a static object or a function that receives the sprite object and returns props dynamically.

Static Props

Pass a static object that will be used for all sprites:

typescript
import { RpgClient, defineModule } from '@rpgjs/client';
import LightHalo from './components/light-halo.ce';

export default defineModule<RpgClient>({
  sprite: {
    componentsInFront: [{
      component: LightHalo,
      props: {
        radius: 25,
        color: 0xffffaa
      }
    }]
  }
})

Dynamic Props (Function)

Use a function to compute props based on the sprite's state. The function receives the sprite object as a parameter:

typescript
import { RpgClient, defineModule } from '@rpgjs/client';
import { RpgClientObject } from '@rpgjs/client';
import LightHalo from './components/light-halo.ce';

export default defineModule<RpgClient>({
  sprite: {
    componentsInFront: [{
      component: LightHalo,
      props: (object: RpgClientObject) => {
        // Access sprite properties reactively
        const level = object.param.level();
        const baseRadius = 25;
        
        // Increase radius based on level
        return {
          radius: baseRadius + (level * 2),
          color: level > 10 ? 0xffaa00 : 0xffffaa
        };
      }
    }]
  }
})

Key Points:

  • The function is called for each sprite instance
  • You can access sprite signals reactively (e.g., object.hp(), object.param.level())
  • Props are recalculated when sprite state changes
  • The returned object is passed directly to the component as props

Dependencies Configuration

The dependencies property allows you to control when a component should be displayed. This is useful for waiting until certain data is available before rendering the component.

How Dependencies Work

  • The dependencies function receives the sprite object and returns an array of signals or values
  • The component only renders when all dependencies are resolved (not undefined)
  • This prevents components from displaying with incomplete or missing data
  • Dependencies are checked reactively, so the component will appear/disappear as values change

Basic Dependencies Example

Wait for specific sprite properties to be available:

typescript
import { RpgClient, defineModule } from '@rpgjs/client';
import { RpgClientObject } from '@rpgjs/client';
import { signal } from 'canvasengine';
import HealthBar from './components/healthbar.ce';

export default defineModule<RpgClient>({
  sprite: {
    componentsInFront: [{
      component: HealthBar,
      props: (object: RpgClientObject) => ({
        hp: object.hp(),
        maxHp: object.param.maxHp()
      }),
      dependencies: (object: RpgClientObject) => {
        // Component only displays when both hp and maxHp are defined
        return [object.hp, object.param.maxHp];
      }
    }]
  }
})

Custom Dependencies with Signals

You can create custom signals to control component visibility:

typescript
import { RpgClient, defineModule } from '@rpgjs/client';
import { RpgClientObject } from '@rpgjs/client';
import { signal } from 'canvasengine';
import LightHalo from './components/light-halo.ce';

export default defineModule<RpgClient>({
  sprite: {
    componentsInFront: [{
      component: LightHalo,
      props: (object: RpgClientObject) => ({
        radius: 25
      }),
      dependencies: (object: RpgClientObject) => {
        // Create a custom signal that starts as undefined
        const isReady = signal(undefined);
        
        // Simulate async data loading
        setTimeout(() => {
          isReady.set(true);
        }, 1000);
        
        // Component won't display until isReady is set
        return [isReady];
      }
    }]
  }
})

Multiple Dependencies

You can wait for multiple conditions:

typescript
dependencies: (object: RpgClientObject) => {
  const customSignal = signal(undefined);
  const anotherValue = someAsyncOperation();
  
  // Component displays only when ALL are defined:
  // - object.hp is defined
  // - object.param.maxHp is defined
  // - customSignal is defined
  // - anotherValue is defined
  return [
    object.hp,
    object.param.maxHp,
    customSignal,
    anotherValue
  ];
}

Prebuilt Components

RPGJS includes prebuilt sprite components that you can use directly in your game without creating them from scratch. These components are ready to use and highly customizable.

Available Prebuilt Components

  • Light Halo - An animated light effect that pulses and glows around sprites, perfect for atmospheric lighting, magical auras, or ambient glow effects.

More prebuilt components will be added in future versions. Check the Prebuilt Components section for the latest additions.