Characters
How to define, use, and customize characters in Pixi’VN, including storage, emotions, and custom properties.
What are characters? Characters are the actors that appear in a visual novel. In Pixi’VN, characters are created using the CharacterBaseModel class or a custom class.
Initialize
To initialize a character, create a new instance of the CharacterBaseModel class (or your custom class) and add it to the game character dictionary when the game is initialized.
It is recommended to import the instances at project startup.
RegisteredCharacters.add is required to save the characters in the game.
import { CharacterBaseModel, RegisteredCharacters } from "@drincs/pixi-vn";
export const liam = new CharacterBaseModel("liam", {
name: "Liam",
surname: "Smith",
age: 25,
icon: "https://example.com/liam.png",
color: "#9e2e12",
});
export const emma = new CharacterBaseModel("emma", {
name: "Emma",
surname: "Johnson",
age: 23,
icon: "https://example.com/emma.png",
color: "#9e2e12",
});
RegisteredCharacters.add([liam, emma]);Get
To get a character by its id, use the RegisteredCharacters.get function.
import { RegisteredCharacters } from "@drincs/pixi-vn";
const liam = RegisteredCharacters.get("liam");Get all
To get all characters, use the RegisteredCharacters.values function.
import { RegisteredCharacters } from "@drincs/pixi-vn";
const characters = RegisteredCharacters.values();Use
ink
You can use this method with the ink syntax. See more here.
You can use a game character, for example, to link it to the current dialogue. You can use the character's id or the character's instance, but it is recommended to use the instance.
import { liam } from "@/content/characters";
narration.dialogue = { character: liam, text: "Hello" };
// or
narration.dialogue = { character: "liam_id", text: "Hello" };Edit
ink
You can use this method with the ink syntax. See more here.
CharacterBaseModel is a stored class, which means its properties are saved in game storage. For example, if you change the character's name during the game, the new name will be saved in the game storage and linked to its id.
If the character's id is changed from one version to another, the system will not move the data linked from the previous id to the new id.
To get the properties used when instantiating the class, you can use the default properties.
Here's a simplified implementation of the CharacterBaseModel class for better understanding of the properties that are stored in the game storage:
export default class CharacterBaseModel
extends StoredClassModel
implements CharacterBaseModelProps
{
constructor(id: string, props: CharacterBaseModelProps) {
super();
// ...
this.defaultName = props.name;
this.icon = props.icon;
// ...
}
// name property is stored in the game storage
private defaultName: string = "";
get name(): string {
return this.getStorageProperty<string>("name") || this.defaultName;
}
set name(value: string) {
this.setStorageProperty("name", value);
}
// icon property is not stored in the game storage
icon: string = "";
// ...
}Character emotions
ink
You can use this method with the ink syntax. See more here.
It is often useful to have multiple types of the same character. For example, a character "Alice" and a subtype related to her emotional state, like "Angry Alice". The character and the subtype have the same characteristics, except for one or more properties, such as the icon.
With Pixi’VN, you can create a "character with an emotion" by passing an object instead of the id:
import { CharacterBaseModel, RegisteredCharacters } from "@drincs/pixi-vn";
export const alice = new CharacterBaseModel("alice", {
name: "Alice",
icon: "https://example.com/alice.png",
color: "#9e2e12",
});
export const angryAlice = new CharacterBaseModel(
{ id: "alice", emotion: "angry" },
{
icon: "https://example.com/angryAlice.png",
},
);
RegisteredCharacters.add([alice, angryAlice]);console.log(alice.name); // Alice
alice.name = "Eleonora";
console.log(alice.name); // Eleonora
console.log(angryAlice.name); // Eleonora
angryAlice.name = "Angry Eleonora";
console.log(alice.name); // Eleonora
console.log(angryAlice.name); // Angry EleonoraCustom class
Templates
In all templates, the Character class is already defined in the file models/Character.ts. You can use it directly or modify it to suit your needs.
It is recommended to create your own class Character that extends CharacterStoredClass and "override" the interface CharacterInterface to add, edit, or remove properties or methods.
For example, if you want to create a class Character, you must "override" the interface CharacterInterface to use your properties or methods. (See the file pixi-vn.d.ts)
Now you can create a class Character that extends CharacterStoredClass and implements the CharacterInterface. (For more information on how to create a class in TypeScript, read the official documentation)
To create a property that stores its value in the game storage, you can create Getters/Setters and use the this.getStorageProperty()/this.setStorageProperty() methods. (See the file Character.ts)
import { CharacterInterface, CharacterStoredClass } from "@drincs/pixi-vn";
export class Character
extends CharacterStoredClass
implements CharacterInterface
{
constructor(
id: string | { id: string; emotion: string },
props: CharacterProps,
) {
super(
typeof id === "string" ? id : id.id,
typeof id === "string" ? "" : id.emotion,
);
this._icon = props.icon;
this._color = props.color;
this.defaultName = props.name;
this.defaultSurname = props.surname;
this.defaultAge = props.age;
}
// Not stored properties
readonly icon?: string;
readonly color?: string | undefined;
// Stored properties
private defaultName?: string;
get name(): string {
return (
this.getStorageProperty<string>("name") ||
this.defaultName ||
this.id
);
}
set name(value: string | undefined) {
this.setStorageProperty("name", value);
}
private defaultSurname?: string;
get surname(): string | undefined {
return (
this.getStorageProperty<string>("surname") || this.defaultSurname
);
}
set surname(value: string | undefined) {
this.setStorageProperty("surname", value);
}
private defaultAge?: number | undefined;
get age(): number | undefined {
return this.getStorageProperty<number>("age") || this.defaultAge;
}
set age(value: number | undefined) {
this.setStorageProperty("age", value);
}
}
interface CharacterProps {
/**
* The name of the character.
*/
name?: string;
/**
* The surname of the character.
*/
surname?: string;
/**
* The age of the character.
*/
age?: number;
/**
* The icon of the character.
*/
icon?: string;
/**
* The color of the character.
*/
color?: string;
}