Categorygithub.com/arran4/golang-rpg-textbox
modulepackage
0.0.0-20240405055746-b51601afa8c4
Repository: https://github.com/arran4/golang-rpg-textbox.git
Documentation: pkg.go.dev

# README

Golang RPG Textbox

This is a "simple" library / cli application to generate animated and static RPG style text boxes from a theme and text.

The library uses:

In order to use this library you will need:

  • To know what font you will be using
  • To have your own theme

Usage

Requirement: A theme

You need to setup a theme, that can can be done using something that adheres to the interfaces (found theme/interface.go):

type Theme interface {
	Chevron() image.Image
	Avatar() image.Image
	FontFace() font.Face
	FontDrawer() *font.Drawer
}

type Frame interface {
	Frame() image.Image
	FrameCenter() image.Rectangle
}

Where frame is defined by the requirements for: https://github.com/arran4/golang-frame

For an example implementation of a theme checkout the contents of the theme/*/ directories.

Using the library

First off you need to construct the *TextBox object:

tb, err := rpgtextbox.NewSimpleTextBox(theme, text, image.Pt(width, height), ops...)

Ops will be discussed later.

There are 2 ways of using the library, one for animations and one for just the frame.

Just the frame:

To just generate the frame, you call the function DrawNextPageFrame on a *TextBox object.

            tb, err := rpgtextbox.NewSimpleTextBox(theme, text, image.Pt(width, height), ops...)
                if err != nil {
                log.Panicf("Error %s", err)
            }
			i := image.NewRGBA(image.Rect(0, 0, *width, *height))
			if _, err := tb.DrawNextPageFrame(i); err != nil {
				log.Panicf("Draw next frame error: %s", err)
			}
			if err := util.SavePngFile(i, "out.png"); err != nil {
				log.Panicf("Error with saving file: %s", err)
			}
			log.Printf("Saving %s", ofn)

The core function is:

func (tb *TextBox) DrawNextPageFrame(target wordwrap.Image, opts ...wordwrap.DrawOption) (bool, error)

The target is where it will draw the image. It will attempt to consume all the space available, so if you need it to only target a smaller portion of it, be sure to use the SubImage function like so:

offset := image.Pt(344,100)
target.SubImage(image.Rect(0, 0, *width, *height).Add(offset)).(wordwrap.Image)

This will just generate one frame, the first page. Each time you call the function it will produce the next page of data. (Ie the next text box / speech dialog.)

An animation

You can also use it to generate an animation, this can be wrapped up in your harness any way you like.

DrawNextFrame works very similar to the DrawNextPageFrame function except that it also returns a WaitTime and a UserInput.

WaitTime is the time before the next animation frame.

UserInput is if the animation has finished and that you should call the next frame generation to ensure smooth rendering. However, you do not need to, you can call in any sequence.

In order for DrawNextFrame to work you must specify an animation, see the option section below for a list. Or read the code directly.

Example:

            ops = some options and an animation option
            tb, err := rpgtextbox.NewSimpleTextBox(theme, text, image.Pt(width, height), ops...)
            if err != nil {
                log.Panicf("Error %s", err)
            }
            for {
                i := image.NewRGBA(image.Rect(0, 0, width, height))
                if done, ui, w, err := tb.rtb.DrawNextFrame(i); err != nil {
                    log.Panicf("Draw next frame error: %s", err)
                } else if done && !ui && w <= 0 {
					// The whole thing is done and there is no input
                    break
                } else if ui {
					// We are awaiting user input
                    break
                } else {
                    if w <= 0 {
                        w = time.Second / 2
                    }
                    f++
                    if ui && w <= 0 {
                        page++
                    }
                    log.Printf("%s: Adding frame %d for page %d", tb.Filename, f, page)
                    bounds := i.Bounds()
                    palettedImage := image.NewPaletted(bounds, palette.Plan9)
                    draw.Draw(palettedImage, palettedImage.Rect, i, bounds.Min, draw.Over)
                    gifo.Image = append(gifo.Image, palettedImage) // add the image to a gif
                    gifo.Delay = append(gifo.Delay, int(w/(time.Second/100))) // add the wait time too
                }
            }
            log.Printf("Saving %s", ofn)
            if err := util.SaveGifFile(ofn, gifo); err != nil {
                log.Panicf("Error with saving file: %s", err)
            }
            log.Printf("Saved %s", ofn)

Use it as CLI application

Download it from the releases tab, or compile it yourself using Go. Once you have built it you can run rpgtextbox with the following flags:

rpgtextbox.exe:
  -animation string
    	Use help for list
  -avatar-pos string
    	Use help for list
  -avatar-scale string
    	Use help for list
  -chevron string
    	Use help for list
  -dpi float
    	Doc dpi (default 75)
  -font string
    	Text font (default "goregular")
  -height int
    	Doc height (default 150)
  -out string
    	Prefix of filename to output (default "out-")
  -size float
    	font size (default 16)
  -text string
    	File in, or - for std input
  -themedir string
    	Directory to find the theme (default "./theme")
  -width int
    	Doc width (default 600)

If the arguments are successful it will create the contents in location/filename specified in out-prefix.

Options

There are a bunch of options, options are used in the following way:

    tb, err := rpgtextbox.NewSimpleTextBox(theme, text, image.Pt(width, height), rpgtextbox.LeftAvatar, rpgtextbox.CenterAvatar)
    if err != nil {
        log.Panicf("Error %s", err)
    }

Chevron Location Options

OptionExample Image
rpgtextbox.CenterBottomInsideTextFrame
rpgtextbox.CenterBottomInsideFrame
rpgtextbox.CenterBottomOnFrameTextFrame
rpgtextbox.CenterBottomOnFrameFrame
rpgtextbox.RightBottomInsideTextFrame
rpgtextbox.RightBottomInsideFrame
rpgtextbox.RightBottomOnFrameTextFrame
rpgtextbox.RightBottomOnFrameFrame
rpgtextbox.TextEndChevron

Avatar Location Options

OptionExample Image
rpgtextbox.LeftAvatar
rpgtextbox.RightAvatar

Avatar Scaling Options

OptionExample Image
rpgtextbox.CenterAvatar
rpgtextbox.NearestNeighbour
rpgtextbox.ApproxBiLinear

Animation Options

OptionExample Image
rpgtextbox.NewFadeAnimation()
rpgtextbox.NewBoxByBoxAnimation()
rpgtextbox.NewLetterByLetterAnimation()

Other options

OptionExample Image / Description
rpgtextbox.Avatar(i image.Image)Replace the theme avatar for a special purpose avatar
rpgtextbox.Name(name string)
rpgtextbox.Name(name string), rpgtextbox.NameTopLeftAboveTextInFrame
rpgtextbox.Name(name string), rpgtextbox.NameTopCenterInFrame
rpgtextbox.Name(name string), rpgtextbox.NameLeftAboveAvatarInFrame

License

TBH I really haven't thought about it. Contact me

# Packages

No description provided by the author
No description provided by the author
No description provided by the author

# Functions

Avatar override the default theme avatar.
BoxTextBox Creates a function to draw a box around the area where the text box will be.
NewAlphaSourceImageMapper Creates a proxy image which will provide a source.
NewBoxByBoxAnimation creates an animation style where one block comes on at one time.
NewFadeAnimation constructs FadeAnimation.
NewLetterByLetterAnimation creates an animation style where one block comes on at one time.
NewSimpleLayout constructs SimpleLayout simply as possible (for the user.).
NewSimpleTextBox as simple as possible constructor for the RPG TextBox, Theme is required destSize can be modified on a per frame basis but is the intended size of hte image options see readme.

# Constants

ApproxBiLinear Resizes the avatar using the ApproxBiLinear algorithm from experimental go draw package.
CenterAvatar as the name suggests.
CenterBottomInsideFrame Name says it all.
CenterBottomInsideTextFrame Name says it all.
CenterBottomOnFrameFrame Name says it all.
CenterBottomOnFrameTextFrame Name says it all.
FadeIn picture is going to fade in or is fading in.
FadeOut picture is going to fade out or is fading out.
LeftAvatar Avatar on the left.
NameLeftAboveAvatarInFrame on the right.
NameTopCenterInFrame on the left.
NameTopLeftAboveTextInFrame on the left.
NearestNeighbour Resizes the avatar using the NearestNeighbour algorithm from experimental go draw package.
NoAvatar default show no avatar.
NoAvatarFit Don't attempt to do anything, will have undefined behavior.
NoMoreChevron default.
NoName default show no name tag.
RightAvatar on the right.
RightBottomInsideFrame Name says it all.
RightBottomInsideTextFrame Name says it all.
RightBottomOnFrameFrame Name says it all.
RightBottomOnFrameTextFrame Name says it all.
TextEndChevron Puts the reader marker at the end of text inline as though it were a character.

# Structs

AlphaSourceImageMapper is a draw.Image compatible source image, that allows an image to fade.
BoxByBoxAnimation is an animation style in which each non-whitespace box comes into visibility one by one.
FadeAnimation The animation for fading.
LetterByLetterAnimation is an animation style in which each non-whitespace letter comes into visibility one by one.
Page where a page of lines is stored with some statistical information.
SimpleLayout simple as possible layout.
TextBox is the core class.

# Interfaces

AnimationMode interface defining the optional animation.
Layout the positioning algorithm output for the layout of the elements on the page.
Option are the configuration arguments.
PostDrawer allows custom components to be drawn after all other elements have.

# Type aliases

AvatarFit is an enum of how to handle the avatar not fitting.
AvatarLocations Positioning locations for avatars.
FadeState is the current picture fading in or out.
MoreChevronLocations Position to put the "more text" marker.
Name the name of the character to show.
NamePositions Positioning locations for the name tag.