Scripting languages

Czech technical University in Prague
Faculty of Information Technology
Department of Software Engineering
© Adam Vesecký, MI-APH, 2019

Scripts

Script

  • a piece of code that performs a specific task
  • originally, scripts were simple languages for punch-cards processing

Scripting language

  • common definition: a scripting language is a high-level language that can be interpreted by another program at runtime
  • it is more about an environment than the language itself - even C/C++ can be considered as a scripting language if loaded by an interpreter
  • C# is compiled into byte-code that is interpreted at runtime by .NET, yet most people don't consider it as a scripting language

Common characteristics

  • economy of expression
  • flexible dynamic typing
  • easy access to other programs

Scripting languages in games

  • as games grow in size, the time required to compile the code increases

Scripts in games

  • allow rapid prototyping
  • can be reloaded at runtime
  • can separate gameplay and core components
  • can be exposed to the end users to mod the game
  • can be used as a quick way of reading variables and game data

Monkey Island 2

Example: Arma 2 SQS script

// Creates boards and markers around mission Area

_xPos = position (_this select 0) select 0;

_yPos = position (_this select 0) select 1;

 

_howBigA = _this select 1;

_howBigB = _this select 2;

_tablesC = _this select 3;

_angle = _this select 4;

_i = 0;

 

while (_i < 360do {

  _x = (_howBighA * (sin _i));

  _y = (_howBigB * (cos _i));

  _x_rot = _xPos + _x*(cos _angle) - _y*(sin _angle);

  _y_rot = _yPos + _x*(sin _angle) + _y*(cos _angle);

  _k = createVehicle ["Danger", [_x_rot, _y_rot, 0], [], 0"NONE"];

  _m = createMarker [format ["Marker" + str _i], [_x_rot, _y_rot, 0]];

  format ["Marker" + str _i] setMarkerType "Dot";

  _k setDir _i;

  format ["Marker" + str _i] setMarkerDir(_i - _angle);

  _i = _i + 360/_tablesC;

};

Example: Hexen ACS script

script 137 (int dir)

{

    if(!dir)

    {

        Floor_LowerByValue(DoorTag, 1664)

        Ceiling_RaiseByValue(DoorTag, 1664)

        Delay(120);

        Floor_RaiseByValue(DoorTag, 1664)

        Ceiling_LowerByValue(DoorTag, 1664)

    }

}

Example: Godot script

func _process(delta):

    # Get ball position and pad rectangles

    var ball_pos = get_node("ball").get_pos()

    var left_rect = Rect2(get_node("left").get_pos() - pad_size*0.5, pad_size)

    var right_rect = Rect2(get_node("right").get_pos() - pad_size*0.5, pad_size)

    

    # Integrate new ball position

    ball_pos += direction*ball_speed*delta

    

    # Flip, change direction and increase speed when touching pads

    if ((left_rect.has_point(ball_pos) and direction.x < 0

    or (right_rect.has_point(ball_pos) and direction.x > 0)):

        direction.x = -direction.x

        ball_speed *= 1.1

        direction.y = randf()*2.0 - 1

        direction = direction.normalized()

    ...

Scripting languages in games

Game Marker Language

Java

C#

TorqueScript

JavaScript

AngelScript

Squirrel

Python

Lua

GDScript

UnrealScript

Kotlin

TypeScript

ActionScript

Javascript engines

Duktape

  • small footprint, easily embeddable ECMAScript 5.1 engine (limited support of ECMA2015)
  • used in Atomic Game Engine

MuJS

  • lightweight embeddable JavaScript interpreter

Tiny-JS

  • minimal interpreter written in C++

SpiderMonkey

  • Mozilla's engine written in C/C++

Chrome V8 (7.9)

  • used in Couchbase, Chrome, MongoDB, NodeJS
  • compiles JavaScript directly into native code
  • X86, ARM, MIPS, ported to PowerPC

Scripting architectures

Scripted callbacks

  • the engine's functionality is hard-coded in the native programming language, but certain functions are customizable (Blender)

Scripted event handler

  • a hook function whose purpose is to allow a game object to respond to some relevant occurrence within the game world (in-game scripts)

Scripted components or properties

  • new components or property objects may be constructed partially or entirely in script
  • used in Dungeon Siege

Script-driven engine

  • script drives the entire engine system (PixiJS, p5.js)

Script-driven game

  • script is running the show and the native engine code acts as a library
  • in this case, the engine can be used as a stand-alone library

Game Engine script API

Game Engine script API

  • the engine needs to communicate with the scripting part - provided by bridges
    • JNI (Java - C++)
    • P/Invoke (.NET - C++)
    • LuaBridge (Lua - C++)
    • Dukbind (Duktape JS - C++)
  • bridge is a performance bottleneck, especially for per-frame calls
  • more scripting languages -> more bridges to maintain
    • crossing the boundary between C++ and the script is slow while marshalling a large amount of data
  • Marshalling
    • transforming the memory representation of an object between two domains (different programming languages)
  • Semantic gap
    • descriptive difference of an object in various representations (relational database, object-oriented structure)

Atomic Game Engine JS API

// Duktape JS mapping

static void jsb_class_define_FileSystem(JSVM* vm) {

  duk_context* ctx = vm->GetJSContext();

  js_class_get_constructor(ctx, "Atomic""FileSystem");

  js_class_get_prototype(ctx, "Atomic""FileSystem");

  duk_pop_2(ctx);

  js_class_get_prototype(ctx, "Atomic""FileSystem");

  duk_push_c_function(ctx, jsb_class_FileSystem_SetCurrentDir, 1);

  duk_put_prop_string(ctx, -2"setCurrentDir");

  duk_push_c_function(ctx, jsb_class_FileSystem_CreateDir, 1);

  duk_put_prop_string(ctx, -2"createDir");

...

}

 

// CreateDir method

static int jsb_class_FileSystem_CreateDir(duk_context* ctx) {

  String __arg0 = duk_to_string(ctx, 0);

  duk_push_this(ctx);

  FileSystem* native = js_to_class_instance<FileSystem>(ctx, -10);

  bool retValue = native->CreateDir(__arg0);

  duk_push_boolean(ctx, retValue ? 1 : 0);

  return 1;

}

Example: Atomic Game Engine C# API

// C++ <-> C# binding is much simpler

ATOMIC_EXPORT_API bool csb_Atomic_FileSystem_SetCurrentDir_4667(FileSystem* self, const char* pathName)

   return self->SetCurrentDir(pathName ? String(pathName) : String::EMPTY);

}

 

 

ATOMIC_EXPORT_API bool csb_Atomic_FileSystem_CreateDir_4668(FileSystem* self, const char* pathName)

{

   return self->CreateDir(pathName ? String(pathName) : String::EMPTY);

}

 

 

ATOMIC_EXPORT_API void csb_Atomic_FileSystem_SetExecuteConsoleCommands_4669(FileSystem* self, bool enable)

{

   self->SetExecuteConsoleCommands(enable);

}

Example: Openframeworks Lua API

 // ofvec2f 2D vectors mapping via luabridge library

luabridge::getGlobalNamespace(L)

  .beginClass<ofVec2f>("ofVec2f")

  .addConstructor<void(*)(floatfloat)>()

  .addFunction(LUA_OPERATOR_PLUS, 

      static_cast<ofVec2f(ofVec2f::*)(const ofVec2f &)const>(&ofVec2f::operator+))

  .addFunction(LUA_OPERATOR_MULT, 

      static_cast<ofVec2f(ofVec2f::*)(const ofVec2f &)const>(&ofVec2f::operator*))

  .addFunction(LUA_OPERATOR_EQ, 

      static_cast<bool(ofVec2f::*)(const ofVec2f &)const>(&ofVec2f::operator==))

  .addData("x"&ofVec2f::x)

  .addData("y"&ofVec2f::y)

  .addFunction("length"&ofVec2f::length)

  .addFunction("lengthSquared"&ofVec2f::lengthSquared)

  .endClass();

Lua

  • lightweight, multi-paradigm programming language
  • started as an in-house C/C++ extension language for several projects
  • offers object-oriented, functional and data-driven programming
  • written in ANSI C, MIT license
  • Lua engine
    • from its authors, current version 5.3.4
  • Lua JIT engine
    • Just-in-time compiler for Lua (uses DynASM)
    • API-compatible with Lua 5.1
    • ~10x faster than pure Lua
  • Features
    • closures
    • coroutines
    • first-class functions
    • size under 200KB

Lua usages

Adobe Photoshop Lightroom

Simcity 4

VLC Media Player

Far Cry

Civilization 5

Trading platforms

Wireshark

Supreme Commander

Angry Birds

World of Warcraft

Baldur's gate

Apache HTTP Server

MySQL Workbench

Escape From Monkey Island

Example: World of Warcraft

local total, completed =  GetNumCompletedAchievements(); 

 

if total > completed then 

  print("You have completed ", completed, " out of " ,total," achievements"); 

  x= completed/total*100;

  print("That is only ",x," percent"); 

end 

Example: Arkanoid Typescript

export class IntroComponent extends Component {

  private model: Model;

  private factory: Factory;

 

  onInit() {

      this.model = this.scene.getGlobalAttribute(ATTR_MODEL);

      this.sendMessage(MSG_GAME_STARTED);

      this.factory = this.scene.getGlobalAttribute(ATTR_FACTORY);

 

      this.scene.invokeWithDelay(5000, () => {

          // set first level and reset the game

          this.model.currentLevel = 1

          this.factory.resetGame(this.scenethis.model);

      });

  }

}

Example: Arkanoid C++

class ArkanoidIntroComponent : public Component {

  private:

      int introShowDelay = 5000;

      int introShowTime = 0;

      ArkanoidModel* model;

  public:

    virtual void Init() {

      model = owner->GetRoot()->GetAttr<ArkanoidModel*>(ATTR_MODEL);

      SendMsg(MSG_GAME_STARTED); // notify other components

    }

 

    virtual void Update(uint64_t deltauint64_t absolute) {

      introShowTime += delta;

 

      if (introShowTime > introShowDelay) {

        // go to the first level

        model->currentLevel = 1;

        owner->GetContext()->ResetGame();

      }

    }

  };

Example: Arkanoid Lua

ArkanoidIntroComponent = Component:Extend("ArkanoidIntroComponent")

 

function ArkanoidIntroComponent:Init()

  self.model = self.owner:GetRoot():GetAttr_ARKANOID_MODEL()

  self:SendMsg("MSG_GAME_STARTED")

 

  local function reset()

    self.model.currentLevel = 1

    self.owner:GetContext():ResetGame()

  end

 

  self.scene.invokeWithDelay(5000, reset)

end

Lecture 10 summary

  • Script: a piece of code that performs a specific task
  • Scripting language: a high-level language that can be interpreted at runtime
  • Marshalling: transforming a memory representation of an object between two domains
  • Semantic gap: descriptive difference of an object in various representations

Goodbye quote

M-M-M-MONSTER KILL!Unreal Tournament