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

# Packages

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

# 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