Pixi’VN
Make your first

Erstelle dein erstes Visual Novel

Schritt-für-Schritt-Anleitung zur Erstellung eines Visual Novels mit Pixi’VN, die Projekteinrichtung, Erzählung, Assets und Interaktivität behandelt.

Dieses Tutorial führt dich durch den Prozess der Erstellung deines ersten Visual Novels.

Zu Testzwecken werden wir in diesem Leitfaden das Visual Novel Breakdown mit Pixi’VN nachbauen. Breakdown ist eine Kurzgeschichte, die alle Merkmale aufweist, die ein Visual Novel haben sollte. Josh Powlison, der Schöpfer von Breakdown, hat uns die Erlaubnis erteilt, seine Erzählung zu Bildungszwecken zu verwenden❤️.

Da Pixi’VN dir die Möglichkeit gibt, deine eigene Erzählung zu schreiben, indem du eine oder mehrere verfügbare Erzählsprachen wählst, werden bei jedem Entwicklungsschritt Beispiele für jede derzeit verfügbare Sprache erstellt.

Neues Projekt erstellen

Bevor du beginnst, stelle sicher, dass du die Voraussetzungen installiert hast.

Der erste Schritt besteht darin, ein neues Projekt zu erstellen. Du kannst dies tun, indem du Folgendes ausführst:

npm create pixi-vn@latest

und die Vorlage Visual Novel auswählst.

VS Code

Wenn du das Projekt mit VS Code öffnest, wirst du gebeten, der Ausführung einiger Workspace-Tasks zuzustimmen und die empfohlenen Erweiterungen für das Projekt zu installieren. Es wird dringend empfohlen, beides zu akzeptieren.

Weitere Informationen zu Vorlagen, Tasks und Erweiterungen findest du hier.

Erstellung der Charaktere

Jetzt werden wir die Charaktere dieser Geschichte definieren. Dazu definieren wir in der Datei /content/characters.ts die Charaktere, die wir verwenden werden.

Weitere Informationen zur Erstellung und Verwendung von Charakteren findest du unter: Charaktere

content/characters.ts
import Character from "@/models/Character";
import { RegisteredCharacters } from "@drincs/pixi-vn";

export const mc = new Character("mc", {
    name: "Me",
});

export const james = new Character("james", {
    name: "James",
    color: "#0084ac",
});

export const steph = new Character("steph", {
    name: "Steph",
    color: "#ac5900",
});

export const sly = new Character("sly", {
    name: "Sly",
    color: "#6d00ac",
});

RegisteredCharacters.add([mc, james, steph, sly]);

Erster Entwurf der Erzählung

Markup

Alle Vorlagen unterstützen Markdown und Tailwind CSS, daher werden wir es für unsere Erzählung verwenden.

Jetzt können wir mit dem Schreiben des „ersten Entwurfs“ der Erzählung des Visual Novels beginnen. Wir werden das erste label namens start erstellen, das den Anfang des Spiels darstellt. Danach können wir die Dialoge schreiben, die in unserem Visual Novel folgen werden.

Dies ist das Beispiel:

file_type_ink
ink/start.ink
=== start ===
james: You're my roommate's replacement, huh?
james: Don't worry, you don't have much to live up to. Just don't use heroin like the last guy, and you' fine!
mc: ...

He thrusts out his hand.

james: James!
mc: ...Peter.

I take his hand and shake.

james: Ooh, Peter! Nice, firm handshake! The last quy always gave me the dead fish. I already think we'r gonna get along fine.
james: Come on in and...
james: ...
james: I know you're both watching, come on out already!

sly: I just wanted to see what the new guy was like. Hey, you, Peter- be nice to our little brother, or you'll have to deal with *us*.
mc: ...
james: Peter, this is Sly. Yes, that is her real name.

I put out my hand.

sly: I'm not shakin' your hand until I decide you're an all-right dude. Sorry, policy.
mc: Fair enough, I'm a pretty scary guy, or so l've been told.
james: The redhead behind her is Stephanie.
// Example of using Tailwind CSS
steph: <span class="inline-block motion-translate-y-loop-25">Hey</span>! Everyone calls me Steph. I'll shake your hand.

// ...
-> DONE

Teile die Erzählung in labels auf

Es ist nicht ratsam, sehr lange labels zu erstellen (auch nicht für lineare Visual Novels), sondern es ist ratsam, mehrere kleine labels zu erstellen und sie bei Bedarf mithilfe der Funktionen zur Steuerung des Erzählflusses „aufzurufen“.

Aus diesem Grund wird unsere Geschichte, auch wenn sie in unserem Fall linear ist, in zwei labels unterteilt: Das erste ist das, das wir gerade erstellt haben (start), während das zweite second_part heißen wird.

Dies ist das Beispiel:

file_type_ink
ink/start.ink
=== start ===
james: You're my roommate's replacement, huh?
james: Don't worry, you don't have much to live up to. Just don't use heroin like the last guy, and you' fine!
mc: ...

He thrusts out his hand.

james: James!
mc: ...Peter.

// ...
-> second_part

=== second_part ===

She enters my room before I'VE even had a chance to. \\n\\n...I could've just come back and gotten the platter later...
She sets it on a desk. I throw my two paper bags down beside the empty bed.

steph: They got you a new mattress, right? That last guy was a druggie, did James tell you that?
sly: *We're* the reason he got expelled!
steph: Sly! If word gets out about that... well, actually, it wouldn't matter, *he's* the one who shot himself up.

I'm fumbling for a new subject.

// ...
-> DONE

Auswahlmenüs

Jetzt werden wir den Spieler fragen, ob er mit dem zweiten Teil des Visual Novels fortfahren möchte.

Dazu setzen wir narration.choices auf ein Array von Auswahloptionen, die mit newChoiceOption (um zu einem label zu springen oder es aufzurufen) und newCloseChoiceOption (um das Auswahlmenü zu schließen, ohne irgendwohin zu navigieren) erstellt wurden.

Weitere Informationen zu Auswahlmenüs findest du hier.

Dies ist das Beispiel:

file_type_ink
ink/start.ink
=== start ===
// ...

You want continue to the next part?
* Yes, I want to continue
-> second_part
* No, I want to stop here
-> END

=== second_part ===

// ...
-> DONE

Charakterinformationen bearbeiten und als Variable verwenden

Jetzt gebe ich dem Spieler die Möglichkeit, den Namen des mc zu ändern. Dazu werde ich den Spieler bitten, ein Eingabefeld mithilfe der Funktionen von Pixi’VN auszufüllen.

Nachdem der Eingabewert ermittelt wurde, kannst du den Charakternamen setzen, indem du den erhaltenen Wert verwendest.

In ink ist _input_value_ eine spezielle Variable, die den vom Spieler eingegebenen Wert enthält. Mehr darüber erfährst du hier.

Dies ist das Beispiel:

file_type_ink
ink/start.ink
=== start ===
// ...

He thrusts out his hand.
# request input type string default Peter
What is your name?
# rename mc { _input_value_ }

// ...
-> DONE

Jetzt könnten wir Charakternamen innerhalb von Dialogen verwenden.

In ink kannst du eckige Klammern (z. B. [sly]) verwenden, um den Mechanismus der Textersetzung zu nutzen: Standardmäßig prüfen die Vorlagen, ob der Text zwischen den Klammern mit einer Charakter-id übereinstimmt, und ersetzen ihn gegebenenfalls durch den Namen dieses Charakters.

In JS/TS kannst du das gleiche Ergebnis erzielen, indem du Template-Literale mit ${} verwendest (z. B. `${sly.name}`).

Dies ist das Beispiel:

file_type_ink
ink/start.ink
VAR steph_fullname = "Stephanie"

=== start ===
// ...

sly: I just wanted to see what the new guy was like. Hey, you, [mc]- be nice to our little brother, or you'll have to deal with *us*.
mc: ...
james: [mc], this is [sly]. Yes, that is her real name.

I put out my hand.

sly: I'm not shakin' your hand until I decide you're an all-right dude. Sorry, policy.
mc: Fair enough, I'm a pretty scary guy, or so l've been told.
james: The redhead behind her is [steph_fullname].
steph: Hey! Everyone calls me [steph]. I'll shake your hand.

She puts out her hand, and I take it.

mc: Thanks, good to meet you, [steph_fullname].
steph: WOW, that is, like, the most perfect handshake I've ever had! Firm, but also gentle. [sly], you *gotta* shake his hand!

// ...
-> DONE

Assets definieren und laden

Um Assets (Bilder, GIFs, Videos...) zu laden und zu verarbeiten, müssen Sie Assets verwenden. Assets ist eine Klasse mit vielen Funktionen aus der PixiJS-Bibliothek. Wenn du mehr Informationen möchtest, lies hier.

Einer der ersten Schritte besteht darin, zu entscheiden, wo du die Assets deines Visual Novels speicherst: Du kannst einen Online-Hosting-Dienst verwenden oder sie lokal im Projekt speichern. Weitere Informationen zu beiden Optionen findest du hier.

Wenn du dich entscheidest, die Assets lokal zu speichern, musst du sie nur in src/assets ablegen: Die Vorlage verwendet automatisch AssetPack, um die Dateien zu analysieren und sie in src/assets/manifest.gen.json zu definieren. Wenn du dich stattdessen dafür entscheidest, sie online zu behalten, musst du assets/index.ts manuell bearbeiten, um sie zu registrieren.

In beiden Fällen wird jedem Asset ein oder mehrere alias zugewiesen, die du dann in deinem Code verwenden kannst, um auf dieses Asset zu verweisen.

icon.png
manifest.gen.json
index.ts
assets/manifest.gen.json
{
  "bundles": [
    {
      "name": "images",
      "assets": [
        {
          "alias": [
            "images_icon",
            "icon"
          ],
          "src": [
            "images/[email protected]",
            "images/icon-VA-NtA.webp",
            "images/[email protected]",
            "images/icon-E_ZC2g.png"
          ],
          "data": {
            "tags": {}
          }
        }
      ]
    }
  ]
}

Hintergrund- und Charakterbilder hinzufügen

Jetzt ist es an der Zeit, auch über den visuellen Teil nachzudenken. Wir werden die Hintergrund- und Charakterbilder zur Canvas des Visual Novels hinzufügen.

In unserem Fall besteht jeder Charakter aus 3 Sprites: dem Körper, den Augen und dem Mund. Wir verwenden ImageContainer, einen Container, der Sprite-Kinder gruppiert, um sie zusammenzufassen und den Charakter zusammenzusetzen. Weitere Informationen zum Hinzufügen von Canvas-Komponenten findest du in dieser Dokumentation.

Dies ist das Beispiel:

file_type_ink
ink/start.ink
=== start ===
# show image bg bg01-hallway
# show imagecontainer james [m01-body m01-eyes-smile m01-mouth-neutral01] xAlign 0.5 yAlign 1
james: You're my roommate's replacement, huh?
# show imagecontainer james [m01-body m01-eyes-grin m01-mouth-smile01]
james: Don't worry, you don't have much to live up to. Just don't use heroin like the last guy, and you'll be fine!
# show imagecontainer james [m01-body m01-eyes-smile m01-mouth-grin00]
mc: ...

// ...
-> DONE

Sounds und Musik

Um deinem Visual Novel Sounds und Musik hinzuzufügen, kannst du das sound-Utility verwenden.

Du kannst Sound-Kanäle definieren, um verschiedene Arten von Sounds (z. B. BGM, SFX) zu verwalten und ihre Lautstärke, Pause, Fortsetzung usw. zu steuern. Es wird empfohlen, die Kanäle zu Beginn des Spiels zu definieren, zum Beispiel im then-Callback der Funktion Game.init.

In diesem Beispiel definiere ich zwei Kanäle: einen für die Hintergrundmusik (BGM) und einen für die Soundeffekte (SFX). Außerdem setze ich defaultChannelAlias auf den SFX-Kanal, sodass ein Sound, wenn ich beim Abspielen keinen Kanal angebe, standardmäßig im SFX-Kanal abgespielt wird. Um den Hintergrundkanal zu definieren, setze ich die Eigenschaft background auf true, sodass die Sounds im Gegensatz zu den anderen Kanälen nicht am Ende jedes narrativen step gestoppt werden, sondern weiterlaufen, bis sie pausiert oder gestoppt werden.

main.ts
import { Game, sound } from "@drincs/pixi-vn";
import { BGM_CHANNEL_NAME, SFX_CHANNEL_NAME } from "@/constans";

Game.init(body, {
    // ...
}).then(() => {
    sound.channels.add(BGM_CHANNEL_NAME, { background: true });
    sound.channels.add(SFX_CHANNEL_NAME);
    sound.defaultChannelAlias = SFX_CHANNEL_NAME;
});

Schließlich kannst du die Sounds und die Musik in den labels mithilfe der Funktion sound.play abspielen. Du kannst auch Kanäle verwenden, um verschiedene Arten von Sounds (z. B. BGM, SFX) zu verwalten und ihre Lautstärke, Pause, Fortsetzung usw. zu steuern.

Weitere Informationen zur Verwendung findest du hier.

file_type_ink
ink/start.ink
=== start ===
# show image bg bg01-hallway
# play sound sfx_whoosh delay 0.1
# show imagecontainer james [m01-body m01-eyes-smile m01-mouth-neutral01] xAlign 0.5 yAlign 1 with movein direction right ease circInOut type spring
james: You're my roommate's replacement, huh?
# play sound sfx_whoosh channel bgm loop true
# show imagecontainer james [m01-body m01-eyes-grin m01-mouth-smile01]
james: Don't worry, you don't have much to live up to. Just don't use heroin like the last guy, and you'll be fine!
# show imagecontainer james [m01-body m01-eyes-smile m01-mouth-grin00]
mc: ...

// ...

# pause all sounds
# show imagecontainer steph [fm02-body fm02-eyes-smile fm02-mouth-smile00]
# play sound sfx_whoosh delay 0.1
# remove image james with moveout direction right ease circInOut type spring duration 0.5 delay 0.05
# remove image sly with moveout direction right ease anticipate duration 0.5
# remove image steph with moveout direction left ease easeInOut duration 0.5 delay 0.1

You want continue to the next part?<># continue
* Yes, I want to continue
-> second_part
* No, I want to stop here
-> END

=== second_part ===
# show text bg "(A few minutes later...)" style { fontFamily: "Arial", dropShadow: { alpha: 0.8, angle: 2.1, blur: 4, color: "0x111111", distance: 10, }, fill: "\#ffffff", stroke: { color: "\#004620", width: 12, join: "round" }, fontSize: 60, fontWeight: "lighter" } with fade
# edit text bg align 0.5
# pause

# resume all sounds
# show image bg bg02-dorm align 0 with fade
# play sound sfx_whoosh delay 0.4
// ...
She enters my room before I'VE even had a chance to.

// ...

-> DONE

Fazit

Nun, jetzt weißt du, wie man ein Visual Novel mit Pixi’VN erstellt. Mit großer Macht kommt große Verantwortung, also nutze sie weise und erschaffe eine großartige Geschichte! 🚀

Auf dieser Seite