Text Console Tutorial

Abstract

We can display text information to a user with a text console. This is usefull for things such as detailed attack roll information.

Prerequisites

Text Input
Split Lines
Text Wrap
Countdown Timer

Set Up

Create a plane for the background. Call it TextConsole. Give it a material. Enable Shadeless, Object Color, and Transparency. Set its Object Color, giving it partial alpha. Give the background the shown nodes and properties. Create a Text object. Name it TextConsole Text. Parent it to the background object. Give it the same material. Set its Object Color but give it full alpha. Add a TextInput object according to its directions.

text-console-tutorial-img0.png

Code

import bge
# http://upbge.wikidot.com/timer-tutorial
from timer import CountdownTimer as Timer
# https://docs.python.org/3/library/textwrap.html#textwrap.wrap
from textwrap import wrap
# https://docs.python.org/3/library/json.html#json.load
import json
 
class TextConsole(bge.types.KX_GameObject):
 
  def __init__(self, DNU):
    self.text = self.child('Text')
    # Fixes buggy text.
    self.text.localScale *= self['scaleFix']
    # Clear the text.
    self.text.text = ''
    self.row = self['row']
    self.collum = self['collum']
    # Converts the string to a list of floats.
    self.fade = json.loads(self['fade'])
    # Record the objects starting transparency.
    self.baseAlpha = self.color.w
    # Make the object invisable.
    self.color.w = 0
    # Tell the console that its currently off.
    self.stage = None
 
  def input(self):
    # If the mouse is hovering over the object, keep restarting the timer.
    if self.sensors['MouseOver'].positive:  self.startTimer()
 
  def message(self, subject, body):
    # Separate the current text into a list of lines.
    lines = self.text.text.splitlines()
    # Split the received message into multiple lines if its too long for just one line.
    body = wrap(body, self.collum)
    # Add the body to the end of the list.
    lines += body
    # Get the last lines that will fit.
    lines = lines[-self.row:]
    # Convert the list back into a string.
    text = ''
    for line in lines:
      # '\n' tells the text object where the new lines should be.
      text += line+'\n'
    # Set the text object to the new text.
    self.text.text = text
 
    # Start the objects fading.
    self.startTimer()
 
  def run(self):
    # Stage zero.
    if self.stage == 0:
      # Get how much time has elapsed for this stage.
      elapse = self.timer.elapsePercent
      # Max elapse at one hundred percent.
      if elapse > 1:  elapse = 1
      # This fades the object up to its base transparency.
      self.color.w = elapse * self.baseAlpha
      # Were assuming the text always maxes at one hundred percent transparency.
      self.text.color.w = elapse
 
      # If the object has fully faded in.
      if elapse == 1:
        # Goto the next stage.
        self.stage = 1
        # Start a new timer based off the next stages fade duration.
        self.timer = Timer(self.fade[1])
 
    # Stage one.
    if self.stage == 1:
      # Stage one sits at max alpha.
      self.color.w = self.baseAlpha
      self.text.color.w = 1
      if self.timer.elapsePercent >= 1:
        self.stage = 2
        self.timer = Timer(self.fade[2])
 
    # Stage two.
    if self.stage == 2:
      # We do the same as stage zero but in reverse.
      elapse = self.timer.remainPercent
      if elapse < 0:  elapse = 0
      self.color.w = elapse * self.baseAlpha
      self.text.color.w = elapse
 
      # Turn it all off.
      if elapse == 0:
        self.stage = None
        self.timer = None
        self['_run'] = False
 
  def startTimer(self):
    # If the fade is currently not running, start it.
    if self.stage == None:
      self.stage = 0
      # Start a new timer based off the next stages fade duration.
      self.timer = Timer(self.fade[0])
      # When this property is True, the run script will run.
      self['_run'] = True
 
    elif self.stage == 1:
      # If your aready in stage one, just reset the timer.
      # This keeps it suck in stage one.
      self.timer = Timer(self.fade[1])
 
    elif self.stage == 2:
      # This caouses it to jump back to stage one.
      self.stage = 1
      self.timer = Timer(self.fade[1])
 
# http://upbge.wikidot.com/child-by-name-tutorial
  def child(obj, child):
    name = obj.name.split('.')
    try:    suffix = '.'+name[1]
    except IndexError: suffix = ''
    return obj.childrenRecursive[name[0] +' '+child+ suffix]
 
# http://upbge.wikidot.com/oop-in-bge-tutorial
BASE_CLASS = TextConsole
import json as JSON_CODER
SEN_MESSAGE = 'Message'
 
def sub(cont):
  self = cont.owner
  if isinstance(self, BASE_CLASS):  return self
  else:  return BASE_CLASS(self)
 
def message(cont):
  sen = cont.sensors[SEN_MESSAGE]
  for i in range(sen.frameMessageCount):
    subject = sen.subjects[i]
    body = sen.bodies[i]
    try:  body = JSON_CODER.loads(body)
    except:
      print(body)
    cont.owner.message(subject, body)
 
def input(cont):  cont.owner.input()
def run(cont):  cont.owner.run()

Questions

Log in and edit this page to ask and answer questions.

Further Reading

String Methods
Wrap

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License