Skip to content

Latest commit

 

History

History
365 lines (221 loc) · 9.8 KB

README.rst

File metadata and controls

365 lines (221 loc) · 9.8 KB
Automated test status (Linux and MacOS) Automated test status (Windows) Code style: black

Godot Python, because you want Python on Godot !

The goal of this project is to provide Python language support as a scripting module for the Godot game engine.

/!\ Rework in progresse /!\

Current version of Godot-Python (0.11.3) is working but has some flaws (mainly cumbersome memory management and the impossibility of using Godot release builds).

So a rework is under way with new ideas (using static binding based on Cython instead of dynamic binding with CFFI, this should simplify the code base and improve performances).

See branch cython-rewrite ;-)

Quickstart

By order of simplicity:

  • Directly download the project from within Godot with the asset library tab.
  • Download from the asset library website.
  • Finally you can also head to the project release page if you want to only download one specific platform build

Building

To build the project from source, first checkout the repo or download the latest tarball.

Godot-Python requires Python >= 3.6 and a C compiler.

Godot GDNative header

The Godot GDNative headers are provided as git submodule:

$ git submodule init
$ git submodule update

Alternatly, you can get them from github.

Linux

On a fresh Ubuntu install, you will need to install these:

$ apt install python3 python3-pip python3-venv build-essential

On top of that build the CPython interpreter requires development headers of it extension modules (for instance if you lack sqlite dev headers, your Godot-Python build won't contain the sqlite3 python module)

The simplest way is to uncomment the main deb-src in /etc/apt/sources.list:

deb-src http://archive.ubuntu.com/ubuntu/ artful main

and instruct apt to install the needed packages:

$ apt update
$ apt build-dep python3.6

See the Python Developer's Guide for instructions on additional platforms.

MacOS

With MacOS, you will need XCode installed and install the command line tools.

$ xcode-select --install

If you are using CPython as your backend, you will need these. To install with Homebrew:

$ brew install python3 openssl zlib

You will also need virtualenv for your python.

Windows

Install VisualStudio and Python3, then submit a PR to improve this paragraph ;-)

Create the virtual env

Godot-Python build system is heavily based on Python (mainly Scons, Cython and Jinja2). Hence we have to create a Python virtual env to install all those dependencies without clashing with your global Python configuration.

$ cd <godot-python-dir>
godot-python$ python3 -m venv venv

Now you need to activate the virtual env, this is something you should do every time you want to use the virtual env.

For Linux/MacOS:

godot-python$ . ./venv/bin/activate

For Windows:

godot-python$ ./venv/bin/activate.bat

Finally we can install dependencies:

godot-python(venv)$ pip install -r requirements.txt

Running the build

For Linux:

godot-python(venv)$ scons platform=x11-64 release

For Windows:

godot-python(venv)$ scons platform=windows-64 release

For MacOS:

godot-python(venv)$ scons platform=osx-64 release

Valid platforms are x11-64, x11-32, windows-64, windows-32 and osx-64. Check Travis or Appveyor links above to see the current status of your platform.

This command will checkout CPython repo, move to a pinned commit and build CPython from source.

It will then generate pythonscript/godot/bindings.pyx (Godot api bindings) from GDNative's api.json and compile it. This part is long and really memory demanding so be patient ;-) When hacking godot-python you can heavily speedup this step by passing sample=true to scons in order to build only a small subset of the bindings.

Eventually the rest of the source will be compiled and a zip build archive will be available in the build directory.

Testing your build

godot-python(venv)$ scons platform=<platform> test

This will run pytests defined in tests/bindings inside the Godot environment. If not present, will download a precompiled Godot binary (defined in SConstruct and platform specific SCSub files) to and set the correct library path for the GDNative wrapper.

Running the example project

godot-python(venv)$ scons platform=<platform> example

This will run the converted pong example in examples/pong inside the Godot environment. If not present, will download a precompiled Godot binary (defined in SConstruct) to and set the correct library path for the GDNative wrapper.

Using a local Godot version

If you have a pre-existing version of godot, you can instruct the build script to use that the static library and binary for building and tests.

godot-python(venv)$ scons platform=x11-64 godot_binary=../godot/bin/godot.x11.opt.64

Additional build options

You check out all the build options in this file.

API

example:

# Explicit is better than implicit
from godot import exposed, export, Vector2, Node2D

SPEED = Vector2(10, 10)

@exposed
class Player(Node2D):
        """
        This is the file's main class which will be made available to Godot. This
        class must inherit from `godot.Node` or any of its children (i.g.
        `godot.KinematicBody`).

        Because Godot scripts only accept file paths, you can't have two `exposed` classes in the same file.
        """
        # Exposed class can define some attributes as export(<type>) to achieve
        # similar goal than GDSscript's `export` keyword
        name = export(str)

        # Can export property as well
        @export(int)
        @property
        def age(self):
                return self._age

        @age.setter
        def age(self, value):
                self._age = value

        # All methods are exposed to Godot
        def talk(self, msg):
                print("I'm saying %s" % msg)

        def _ready(self):
                # Don't confuse `__init__` with Godot's `_ready`!
                self._age = 42
                # Of course you can access property & methods defined in the parent
                name = self.get_name()
                print('%s position x=%s, y=%s' % (name, self.position.x, self.position.y))

        def _process(self, delta):
                self.position += SPEED * delta

        ...


class Helper:
        """
        Other classes are considered helpers and cannot be called from outside
        Python. However they can be imported from another python module.
        """
        ...

FAQ

How can I debug my project with PyCharm?

This can be done using "Attach to Local Process", but first you have to change the Godot binary filename to include python, for example Godot_v3.0.2-stable_win64.exe to python_Godot_v3.0.2-stable_win64.exe. For more detailed guide and explanation see this external blog post.

How can I autoload a python script without attaching it to a Node?

In your project.godot file, add the following section:

[autoload]
autoloadpy="*res://autoload.py"

In addition to the usual:

[gdnative]
singletons=[ "res://pythonscript.gdnlib" ]

You can use any name for the python file and the class name autoloadpy.

Then autoload.py can expose a Node:

from godot import exposed, export
from godot.bindings import *

@exposed
class autoload(Node):

    def hi(self, to):
        return 'Hello %s from Python !' % to

which can then be called from your gdscript code as an attribute of the autoloadpy class (use the name defined in your project.godot):

print(autoloadpy.hi('root'))

How can I efficiently access PoolArrays?

PoolIntArray, PoolFloatArray, PoolVector3Array and the other pool arrays can't be accessed directly because they must be locked in memory first. Use the arr.raw_access() context manager to lock it:

arr = PoolIntArray() # create the array
arr.resize(10000)

with arr.raw_access() as ptr:
    for i in range(10000):
        ptr[i] = i # this is fast

# read access:
with arr.raw_access() as ptr:
    for i in range(10000):
        assert ptr[i] == i # so is this

Keep in mind great performances comes with great responsabilities: there is no boundary check so you may end up with memory corruption if you don't take care ;-)

See the godot-python issue.