Skip to content

Commit

Permalink
chore: Renamed GameObjectRegistry to Registry and documented how …
Browse files Browse the repository at this point in the history
…to create custom game objects
  • Loading branch information
spuxx1701 committed Jun 9, 2024
1 parent 2624735 commit 03ac1ee
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 18 deletions.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,68 @@ The [`Modifier`](/lib/modifier/modifier.ts) class allows `GameObject`s to modify

The [`Event`](/lib/event/event.ts) class represents the base class for all sorts of events that may happen in the game. Events are stored in a global [`EventLog`](/lib/event/event-log.ts).

## Custom Game Objects

When creating your own game, you will most likely want to create custom `GameObject`s. All you need to do is create a new class that extends `GameObject` and register it:

```ts
import { GameObject } from '@satellite-games/orbit';

export class Item extends GameObject {
declare name: string;
declare cost: number;
// ...
}

// This registers your Game Object with Orbit
declare module '@satellite-games/orbit' {
interface Registry {
item: RegistryEntry<Item, string>;
}
}
```

Registering your `GameObject` enables type-safety while working with your `GameObject`. It is even possible to achieve full type-safety for all of your `Blueprint` names, which will be the possible values of the `GameObject.name` property.

```ts
import { GameObject } from '@satellite-games/orbit';

// Create a literal type with all possible item names
export type ItemName = 'item.potion' | 'item.pouch';

export class Item extends GameObject {
declare name: ItemName;
declare cost: number;
// ...
}

// This registers your GameObject with Orbit
declare module '@satellite-games/orbit' {
interface Registry {
item: RegistryEntry<Item, ItemName>;
}
}

// This will further increase type-safety, e.g. creating and maintaining Blueprints
// All of this is type-safe, even the names!
const itemBlueprints: Blueprint<Item> = [
{
name: 'item.pouch',
cost: 200,
},
{
name: 'item.potion',
cost: 50,
dependencies: {
name: 'item.pouch',
} as Dependency<Item>,
},
];
```

While it can be quite tedious to manually maintain a literal type that contains all possible names,
it's easy to write a script that'll generate those literal types for you based on your master data.

## <a name='BuildingapackagewithOrbit'></a>Building a package with Orbit

If you're building a package that is based on Orbit, you might want consumers to be able to access Orbit's features or types without having to install it separately. To achieve that, simply re-export everything from Orbit in your package. For example, in your main entrypoint file, do:
Expand Down
6 changes: 3 additions & 3 deletions lib/game-object/game-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ElementType, NumericProperty } from '@/types/private-types';
import { Modifier, applyModifiers } from '@/modifier';
import { Dependency } from '@/dependency/dependency';
import { getGameObjectKey } from './game-object.utils';
import type { GameObjectKey, GameObjectName, GameObjectRegistry } from './types';
import type { GameObjectKey, GameObjectName, Registry } from './types';

/**
* A game object is an entity in the game world. It is a container for data and functions.
Expand Down Expand Up @@ -35,15 +35,15 @@ export class GameObject implements GameObject {
/**
* Any child game objects that are stored on this game object.
*/
children: Partial<Record<GameObjectKey, Array<GameObjectRegistry[GameObjectKey]['type']>>>;
children: Partial<Record<GameObjectKey, Array<Registry[GameObjectKey]['type']>>>;

constructor(init: {
name: GameObjectName;
id?: string;
owner?: GameObject | null;
modifiers?: Modifier<any>[];
dependencies?: Dependency<any>[];
children?: Partial<Record<GameObjectKey, Array<GameObjectRegistry[GameObjectKey]['type']>>>;
children?: Partial<Record<GameObjectKey, Array<Registry[GameObjectKey]['type']>>>;
[key: string]: any;
}) {
// Perform a shallow copy of the initialization object. This also covers
Expand Down
18 changes: 9 additions & 9 deletions lib/game-object/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,36 @@ export type Saved<TGameObject extends GameObject, TOmitted extends keyof TGameOb
> &
Required<Pick<TGameObject, 'id'>>;
/**
* An entry of `GameObjectRegistry`. Use this type together with `GameObjectRegistry`
* An entry of `Registry`. Use this type together with `Registry`
* to register new `GameObject`s.
*/
export type GameObjectRegistryEntry<T extends GameObject, U extends string> = {
export type RegistryEntry<T extends GameObject, U extends string> = {
type: T;
names: U[];
};

/**
* The registry of `GameObject`s. Use this interface together with `GameObjectRegistryEntry`
* The registry of `GameObject`s. Use this interface together with `RegistryEntry`
* to register new `GameObject`s.
* @example
* class MyGameObject extends GameObject {
* // ...
* }
* type MyGameObjectName = 'my-game-object.foo' | 'my-game-object.bar';
*
* interface GameObjectRegistry {
* 'my-game-object': GameObjectRegistryEntry<MyGameObject, MyGameObjectName>;
* interface Registry {
* 'my-game-object': RegistryEntry<MyGameObject, MyGameObjectName>;
* }
*/
export interface GameObjectRegistry {}
export interface Registry {}

/**
* The key of `GameObjectRegistry`. Represents the unique key of a `GameObject` class.
* The key of `Registry`. Represents the unique key of a `GameObject` class.
*/
export type GameObjectKey = keyof GameObjectRegistry;
export type GameObjectKey = keyof Registry;

/**
* Represents all possible values for a `GameObject`s `name` property. Usually, this is a union
* of all blueprint names of a `GameObject`.
*/
export type GameObjectName = GameObjectRegistry[GameObjectKey]['names'][number];
export type GameObjectName = Registry[GameObjectKey]['names'][number];
4 changes: 2 additions & 2 deletions tests/internal-mocks/stat.go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const stats: Record<Key, Blueprint<Stat>> = {
};

declare module '@/registry' {
interface GameObjectRegistry {
stat: GameObjectRegistryEntry<Stat, StatName>;
interface Registry {
stat: RegistryEntry<Stat, StatName>;
}
}
4 changes: 2 additions & 2 deletions tests/internal-mocks/train.go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const trains: Record<Key, Blueprint<Train, 'length'>> = {
};

declare module '@/registry' {
interface GameObjectRegistry {
train: GameObjectRegistryEntry<Train, TrainName>;
interface Registry {
train: RegistryEntry<Train, TrainName>;
}
}
4 changes: 2 additions & 2 deletions tests/internal-mocks/wagon.go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const wagons: Record<Key, Blueprint<Wagon>> = {
};

declare module '@/registry' {
interface GameObjectRegistry {
wagon: GameObjectRegistryEntry<Wagon, WagonName>;
interface Registry {
wagon: RegistryEntry<Wagon, WagonName>;
}
}

0 comments on commit 03ac1ee

Please sign in to comment.