Godot is an astonishingly feature packed development framework for creating games and graphical simulations. It can do fancy 3d modelling and physics as well as 2d and GUI elements. I am particularly impressed that the GUI of Godot itself is actually created with its own technology (presumably you could make a game that has an in-game creation feature using Godot). It is free, open source, Linux friendly, and pretty much completely wholesome.

Resources

Installation

Godot’s installation is nothing short of a miracle. You go to their web site, you get a compressed file (alas zipped) and uncompress it.

The download is astonishingly less than 20MB! It is a single 44MB executable at full size (at release of Godot3 in January 2018). This is shockingly compact and easy to deal with but it continues to impress: to run it, just execute the file and it’s running!

A good place to start is by clicking "AssetLib" which brings up all the official demos into the GUI of the editor. You can select one and download it and start playing with it. It’s actually a very clever way to teach the system.

Vim and Command Line

It looks like you can just edit the files in the project directories. The trick is how to synchronize them. You can just click on the file name in the editor to refresh. Sort of. I’d like to find a way to just not have it do any auto-syncing and do it manually.

How to use the command line to work with Godot.

Syntax highlighting was ok by default as a conf file. Install a proper syntax highlighting by doing this.

mkdir ~/.vim/syntax ; cd ~/.vim/syntax
wget https://raw.githubusercontent.com/quabug/vim-gdscript/master/syntax/gdscript.vim

Maybe add this to your ~/.vimrc.

au BufRead,BufNewFile *.gd  set filetype=gdscript

Tabs

The editor likes to use tab indentation, but it’s easy to fix.

Editor→ Editor Settings → General → Text Editor → Indent → Type

Change from evil "Tabs" to "Spaces".

Editing

  • RMB - aims camera angle from its current position

  • LMB - selects

  • [S]-MMB - pan view (translate), reposition view in display or, as I like to think of it, "shift" the view (same in Blender)

  • [C]-MMB - scale view, zoom/move view/camera closer, vertical mouse axis only (similar in Blender)

  • [S]-F1 - Contextual help for highlighted name in script editor.

Ontology

A "Scene" is a tree of "Nodes".

A Node may have these kinds of features.

  • Name

  • Properties

  • Callback

  • Extendable - You can make the actual functionality different

Physics

  • Static body - Sprite/model + collision box

  • Rigid body - Do not control position explicitly. Apply forces (gravity, add_force(), apply_impulse(), etc).

  • CollisionObject2D

    • PhysicsBody2D

      1. StaticBody2D - Efficient for things that don’t move (walls, ground, the "platform")

      2. RididBody2D - Realistic simulated physics (gravity, etc)

    • Rigid mode - Moves in response to physics forces.

    • Static mode - Behave like a static body (won’t move)

    • Character mode - similar to Rigid but no rotation

    • Kinematic - Use code for moving like KinematicBody2D.

      1. KinematicBody2D - Arcade, moves but no normal physics necessarily

    • Area2D - Detects object overlapping

Can set gravity to 0 in "Physics 2d" in Property Settings for 2d top down simulations (think Asteroids).

apply_impulse() is more abrupt than add_force()

Example of how to insert physics nodes.

Scene tab → + → Spatial → CollisionObject → PhysicsBody → RigidBody

Area2D - Sprite - add your artwork - CollisionObject2D - (don’t drag collision shapes from outside box, use blue inner box handles).

KinematicBody2D - Arcade, moves but no normal physics necessarily Use move(Vector2 real_vec) method to move it to return "remaining motion" left after a hit. Allows for a n.reflect(remaning) or a n.slide(remaining). - Sprite - CollisionShape2D

How to directly do metaphysical things with a physics object like a PhysicsBody2D. For example, you may have a space ship that reappears on the opposite side of the screen when it goes off the screen (i.e. torus). Usually the outcome of where the ship is positioned is calculated solely by the physics engine. But here’s how to reach in and make adjustments for such a situation.

# Taken from: https://www.youtube.com/watch?v=xsAyx2r1bQU
func _integrate_forces(state):
    set_applied_force(thrust.rotated(rotation))
    set_applied_torque(rotation_dir*spin_thrust)
    var xform= state.get_transform()
    if xform.origin.x > screensize.x:
        xform.origin.x= 0
    if xform.origin.x < 0:
        xform.origin.x= screensize.x
    if xform.origin.y > screensize.y:
        xform.origin.y= 0
    if xform.origin.y < 0:
        xform.origin.y= screensize.y
    state.set_transform(xform)

Also custom_integrator() looks interesting too to make your own physics systems.

set_fixed_process(true) - Force physics to 1/60 second (or whatever).

Tween

A Tween node is just a way to interpolate a continuous state transition function. Here is a nice display of what that means: http://easings.net/

bool interpolate_property(object,property,initialvalue,endingvalue)

GDScript

  • # Comments as usual

  • $ = alias for get_node(). For example, you can refer to $AnimatedSprite/Monster.local_coords. Also has_node().

  • func = Python’s def, though don’t use self in the definition (although self may be available in the functions). Functions aren’t proper types and can’t be stored in variables, etc. static func myspecialfn(x,y): can be used to make sure that x and y are not inherited from elsewhere.

  • Native vector types Vector2(x,y) and Vector3(x,y,z)

  • Single or double quotes like Python.

  • Dictionaries and lists (perhaps called arrays) seem just like Python. e.g. var moves={"right":Vector2(1,0),"left":Vector2(-1,0)} Also mydict.keys() works.

  • null is a type that can not be assigned values. Hmm.

  • Other types bool, int, float, String, Rect2, Transform2D (transform matrix type), Plane, Quat (quaternion), AABB (axis aligned bounding box), Basis (3x3 matrix for 3d transforms), Transform (the 3d version), Color, NodePath, RID (resource id), Object (base class for user created types)

  • enum MOB_BAD, MOB_GOOD=10, MOB_UGLY is the same as const MOB_BAD=0, const MOB_GOOD=10, and const MOB_UGLY=11.

  • const e= 2.71828182845904523536

  • Boolean keywords are true and false, not the Python capitalized ones.

  • Random numbers

    • randi() - random integer, best used with a modolo.

    • rand_range(minval,maxval)

  • print("Shows up in the console.")

  • clamp(x,min,max) - set x to be x or min or max if x is lower or higher than min and max respectively.

  • class MyClass and then instantiate it with var mc= MyClass.new() and use with something like print(mc.mymember); also, extends MyClass for inheritance

  • Keywords that seem mostly identical to Python: if, elif, `else, for, while, break, continue, pass, return, range

  • match is like switch in other languages; note that break is default, use continue to fall through

    match mycoin:
        true:
            print("Heads!")
        false:
            print("Tails!")
  • ~ Bitwise not, << bitshifting, [&,|] bitwise [and,or]

  • || or or boolean or. Same with and.

  • 0xCECE Hex numbers

  • """multi line string""" Like Python.

  • @"NodePath" - I’d like a better example of this

Any variable you want exposed in the editor use

export var speed= 55
  • Vector2(x,y)

Some typical expected functions for node scripts (classes).

  • func _ready() - Called every time the node is added to the scene. Often contains the line set_fixed_process(true)

  • func _process(delta) - Called every frame where node is relevant.

delta is how much time has elapsed since last frame; used for frame rate independence.

randomize() - set random seed with something really random. Or something specific?

If you have a "scene" that describes how some game element works, you can instantiate many objects of that class. Here a parent "Node" (just a simple plain Node type node) spawns 10 animated sprites.

extends Node
onready var sprite= preload("res://Sprite.tscn")
func _ready():
    for i in range(10):
        var s=sprite.instance()
        add_child(s)

UI

It seems common to start by defining your own input map entries. Start your new project then go to Project → Project Settings → Input Map tab, and enter move_up, move_left etc in the Action box. Then go to the plus on each and Add Key to add a binding (A,S,D,W, or better, k,h,j,l etc).

I think the predefined ones (e.g. ui_up, ui_right, etc) are there to support the UI (menus, etc) keybindings.

Here’s a typical control scheme for mapping arrow keys (or WASD if it’s remapped) to do the sensible thing.

func get_input():
    thrust= Vector()
    if Input.is_action_pressed("ui_up"):
        thrust= Vector2(engine_thrust,0)
    if Input.is_action_pressed("ui_down"):
        thrust= Vector2(-engine_thrust,0)
    if Input.is_action_pressed("ui_right"):
        rotation_dir += 1
    if Input.is_action_pressed("ui_right"):
        rotation_dir -= 1

Here’s another possibly better way to do the same thing.

export  var speed=100
var vel= Vector2()
func _read():
    set_fixed_process(true)
    set_pos(Vector(500,300)
func _fixed_process(delta):
    var input= Vector2(0,0)
    input.x= Input.is_action_pressed("ui_right") - Input.is_action_pressed("ui_left")
    input.y= Input.is_action_pressed("ui_down") - Input.is_action_pressed("ui_up")
    vel= input.normalized() * speed
    set_pos(get_pos() + vel * delta)

To have a complex UI display in-game you can use lots of different container nodes. This video does a very good job introducing that concept.

Nodes

Node2D is a good choice for a root node in a 2d project.

StaticBody2D is a good parent wrapper of a Sprite node for things like backgrounds.

Quit

A normal thing to want to do, especially during development, is to politely quit your game. I defined the escape button using the same menu as previously shown and then added this.

if Input.is_action_just_pressed("quit_button"):
    get_tree().quit()

Signals

_on_some_action - Godot naming convention for responding to signals.

In the item’s script.
signal item_grabbed # Alerts interested funcs that an item was grabbed.

func on_item_area_enter(area): # Run if item collision occurs.
    emit_signal("item_grabbed") # Alert other nodes.
    queue_free() # Makes this object disappear from entire process.
In the main node’s script.
func spawn_item():
    var g= item.instance()
    item_container.add_child(g)
    g.connect("item_grabbed",self,"_on_item_grabbed")
func _on_item_grabbed():
    itemcount+=1

Performance

Need to audit the frame rate? That and many other interesting performance metrics can be studied with the get_monitor function described here.

C++

Of course you can use C++ to strong arm the engine itself. http://docs.godotengine.org/en/latest/development/cpp/ Quite an advanced topic. It would definitely require a lot of knowledge about the engine in general.