Cleanups.

This commit is contained in:
Relintai 2024-04-28 12:47:32 +02:00
parent 80d98eb678
commit dadbb6ba5d
25 changed files with 404 additions and 819 deletions

View File

@ -1,7 +1,6 @@
Introduction to the animation features
======================================
# Introduction to the animation features
The `AnimationPlayer` node allows you to create anything
from simple to complex animations.
@ -18,8 +17,7 @@ Node transforms, sprites, UI elements, particles, visibility and color
of materials, and so on. You can also modify values of script variables
and call any function.
Create an AnimationPlayer node
------------------------------
## Create an AnimationPlayer node
To use the animation tools we first have to create an
`AnimationPlayer` node.
@ -28,25 +26,22 @@ The AnimationPlayer node type is the data container for your animations.
One AnimationPlayer node can hold multiple animations, that can
automatically transition to one another.
.. figure:: img/animation_create_animationplayer.png)
:alt: The AnimationPlayer node
![The AnimationPlayer node](img/animation_create_animationplayer.png)
The AnimationPlayer node
The AnimationPlayer node
After creating one click on the AnimationPlayer node in the Node tab to
open the Animation Panel at the bottom of the viewport.
.. figure:: img/animation_animation_panel.png)
:alt: The animation panel position
![The animation panel position](img/animation_animation_panel.png)
The animation panel position
The animation panel position
It consists of four parts:
.. figure:: img/animation_animation_panel_overview.png)
:alt: The animation panel
![The animation panel](img/animation_animation_panel_overview.png)
The animation panel
The animation panel
- Animation controls (i.e. add, load, save, and delete animations)
- The tracks listing
@ -54,69 +49,59 @@ It consists of four parts:
- The timeline and track controls, where you can zoom the timeline and
edit tracks for example.
Computer animation relies on keyframes
--------------------------------------
## Computer animation relies on keyframes
A keyframe defines the value of a property at a certain point in time.
Diamond shapes represent keyframes in the timeline. A line between two
keyframes indicates that the value hasn't changed.
.. figure:: img/animation_keyframes.png)
:alt: Keyframes in Pandemonium
![Keyframes in Pandemonium](img/animation_keyframes.png)
Keyframes in Pandemonium
Keyframes in Pandemonium
The engine interpolates values between keyframes, resulting in a gradual
change in values over time.
.. figure:: img/animation_illustration.png)
:alt: Two keyframes are all it takes to obtain a smooth motion
![Two keyframes are all it takes to obtain a smooth motion](img/animation_illustration.png)
Two keyframes are all it takes to obtain a smooth motion
Two keyframes are all it takes to obtain a smooth motion
The timeline lets you insert keyframes and change their timing. It also
defines how long the animation is.
.. figure:: img/animation_timeline.png)
:alt: The timeline in the animation panel
![The timeline in the animation panel](img/animation_timeline.png)
The timeline in the animation panel
The timeline in the animation panel
Each line of the Animation Panel is an animation track. Normal and
Transform tracks reference node properties. Their name or id is a path
to the node and the affected property.
.. figure:: img/animation_normal_track.png)
:alt: Example of Normal animation tracks
![Example of Normal animation tracks](img/animation_normal_track.png)
Example of Normal animation tracks
Example of Normal animation tracks
Tip:
If you animate the wrong property, you can edit a track's path anytime.
Double click on it and type the new path. Play the animation using the
"Play from beginning" button |Play from beginning| (or pressing
:kbd:`Shift + D` on keyboard) to see the changes instantly.
Tutorial: Creating a simple animation
-------------------------------------
## Tutorial: Creating a simple animation
Scene setup
~~~~~~~~~~~
### Scene setup
For this tutorial, we'll create a Sprite node with an AnimationPlayer as
its child. We will animate the sprite to move between two points on the screen.
.. figure:: img/animation_animation_player_tree.png)
:alt: Our scene setup
![Our scene setup](img/animation_animation_player_tree.png)
Our scene setup
Our scene setup
Warning:
AnimationPlayer inherits from Node instead of Node2D or Spatial, which means
that the child nodes will not inherit the transform from the parent nodes
due to a bare Node being present in the hierarchy.
@ -134,21 +119,18 @@ animation editor. From the list select "New" (|Add
Animation|) to add a new animation. And Enter a name for the animation in the
dialog box.
.. figure:: img/animation_create_new_animation.png)
:alt: Add a new animation
![Add a new animation](img/animation_create_new_animation.png)
Add a new animation
Add a new animation
Adding a track
~~~~~~~~~~~~~~
### Adding a track
To add a new track for our sprite, select it and take a look in the
toolbar:
.. figure:: img/animation_convenience_buttons.png)
:alt: Convenience buttons
![Convenience buttons](img/animation_convenience_buttons.png)
Convenience buttons
Convenience buttons
These switches and buttons allow you to add keyframes for the selected
node's location, rotation, and scale respectively.
@ -162,13 +144,11 @@ property, Pandemonium asks whether it should set it up for us. Click **Create**.
This creates a new track and our first keyframe at the beginning of
the timeline:
.. figure:: img/animation_track.png)
:alt: The sprite track
![The sprite track](img/animation_track.png)
The sprite track
The sprite track
The second keyframe
~~~~~~~~~~~~~~~~~~~
### The second keyframe
Now we need to set the destination where our sprite should be headed and
how much time it takes to get there.
@ -177,10 +157,9 @@ Let's say, we want it to take 2 seconds to go to the other point. By
default the animation is set to last only 1 second, so change this in
the timeline controls in animation panel's lower panel to 2.
.. figure:: img/animation_set_length.png)
:alt: Animation length
![Animation length](img/animation_set_length.png)
Animation length
Animation length
Click on the timeline header near the 2-second mark and move the sprite
to the target destination on the right side.
@ -188,45 +167,39 @@ to the target destination on the right side.
Again, click the key button in the toolbar. This creates our second
keyframe.
Run the animation
~~~~~~~~~~~~~~~~~
### Run the animation
Click on the "Play from beginning" (|Play from beginning|) button.
Yay! Our animation runs:
.. figure:: img/animation_simple.gif)
:alt: The animation
![The animation](img/animation_simple.gif)
The animation
The animation
Back and forth
~~~~~~~~~~~~~~
### Back and forth
Pandemonium has an additional feature here. Like said before,
Pandemonium always calculates the frames between two keyframes. In a loop, the
first keyframe is also the last keyframe, if no keyframe is specified at
the end.
.. figure:: img/animation_loop.png)
:alt: Animation loop
![Animation loop](img/animation_loop.png)
Animation loop
Animation loop
If you set the animation length to 4 seconds now, the animation moves
back and forth. You can change this behavior if you change the track's
loop mode. This is covered in the next chapter.
Track settings
~~~~~~~~~~~~~~
### Track settings
Each track has a settings panel at the end, where you can set the update
mode, the track interpolation, and the loop mode.
.. figure:: img/animation_track_settings.png)
:alt: Track settings
![Track settings](img/animation_track_settings.png)
Track settings
Track settings
The update mode of a track tells Pandemonium when to update the property
values. This can be:
@ -243,10 +216,9 @@ values. This can be:
could use the Capture mode to move a node that's located anywhere
to a specific location.
.. figure:: img/animation_track_rate.png)
:alt: Track mode
![Track mode](img/animation_track_rate.png)
Track mode
Track mode
In normal animations, you usually use "Continuous". The other types are
used to script complex animations.
@ -260,10 +232,9 @@ the keyframes. These interpolation modes are supported:
- Cubic: Set the value based on a cubic function calculation between
the two keyframes
.. figure:: img/animation_track_interpolation.png)
:alt: Track interpolation
![Track interpolation](img/animation_track_interpolation.png)
Track interpolation
Track interpolation
Cubic interpolation leads to a more natural movement, where the
animation is slower at a keyframe and faster between keyframes. This is
@ -273,10 +244,9 @@ of a robotic movement.
Pandemonium supports two loop modes, which affect the animation if it's set to
loop:
.. figure:: img/animation_track_loop_modes.png)
:alt: Loop modes
![Loop modes](img/animation_track_loop_modes.png)
Loop modes
Loop modes
- Clamp loop interpolation: When this is selected, the animation stops
after the last keyframe for this track. When the first keyframe is
@ -285,8 +255,7 @@ loop:
animation after the last keyframe to reach the values of the first
keyframe again.
Keyframes for other properties
------------------------------
## Keyframes for other properties
Pandemonium doesn't restrict you to only edit transform properties. Every
property can be used as a track where you can set keyframes.
@ -296,22 +265,19 @@ a small keyframe button for all the sprite's properties. Click on
this button and Pandemonium automatically adds a track and keyframe to the
current animation.
.. figure:: img/animation_properties_keyframe.png)
:alt: Keyframes for other properties
![Keyframes for other properties](img/animation_properties_keyframe.png)
Keyframes for other properties
Keyframes for other properties
Edit keyframes
--------------
## Edit keyframes
For advanced use and to edit keyframes in detail, You can click on them
to bring up the keyframe editor in the inspector. You can use this to
directly edit its values.
.. figure:: img/animation_keyframe_editor_key.png)
:alt: Keyframe editor editing a key
![Keyframe editor editing a key](img/animation_keyframe_editor_key.png)
Keyframe editor editing a key
Keyframe editor editing a key
Additionally, you can also edit the easing value for this keyframe by
clicking and dragging the easing setting. This tells Pandemonium, how to change
@ -320,8 +286,7 @@ the property values when it reaches this keyframe.
You usually tweak your animations this way, when the movement doesn't
"look right".
Advanced: Call Method tracks
----------------------------
## Advanced: Call Method tracks
Pandemonium's animation engine doesn't stop here. If you're already
comfortable with Pandemonium's scripting language
@ -350,18 +315,16 @@ controls.
Select "Add Call Method Track" from the list of possible track types.
.. figure:: img/animation_add_call_method_track.png)
:alt: Add Call Method Track
![Add Call Method Track](img/animation_add_call_method_track.png)
Add Call Method Track
Add Call Method Track
Select the `AudioStreamPlayer` node in the selection
window. Pandemonium adds the track with the reference to the node.
.. figure:: img/animation_select_audiostreamplayer.png)
:alt: Select AudioStreamPlayer
![Select AudioStreamPlayer](img/animation_select_audiostreamplayer.png)
Select AudioStreamPlayer
Select AudioStreamPlayer
Right click the timeline where Pandemonium should play the sample and
click the "Insert Key" option. This will bring up a list of methods
@ -379,12 +342,17 @@ click on the keyframe and use the keyframe settings in the inspector.
![](img/animation_call_method_keyframe.png)
.. |Play from beginning| image:: img/animation_play_from_beginning.png)
.. |Add Animation| image:: img/animation_add.png)
.. |Add track| image:: img/animation_add_track.png)
![Play from beginning](img/animation_play_from_beginning.png)
Using RESET tracks
------------------
Play from beginning
![Add Animation](img/animation_add.png)
Add Animation
![Add track](img/animation_add_track.png)
## Using RESET tracks
You can set up a special *RESET* animation to contain the "default pose".
This is used to ensure that the default pose is restored when you save

View File

@ -1,10 +1,8 @@
Cutout animation
================
# Cutout animation
What is it?
~~~~~~~~~~~
### What is it?
Traditionally, `cutout animation ( https://en.wikipedia.org/wiki/Cutout_animation )`
is a type of `stop motion animation ( https://en.wikipedia.org/wiki/Stop_motion )`
@ -23,8 +21,7 @@ In video games, this technique has also become popular. Examples of
this are `Paper Mario ( https://en.wikipedia.org/wiki/Super_Paper_Mario )` or
`Rayman Origins ( https://en.wikipedia.org/wiki/Rayman_Origins )` .
Cutout animation in Pandemonium
~~~~~~~~~~~~~~~~~~~~~~~~~
### Cutout animation in Pandemonium
Pandemonium provides tools for working with cutout rigs, and is ideal for the workflow:
@ -50,8 +47,7 @@ Pandemonium provides tools for working with cutout rigs, and is ideal for the wo
And much more!
Making of GBot
~~~~~~~~~~~~~~
### Making of GBot
For this tutorial, we will use as demo content the pieces of the
`GBot ( https://www.youtube.com/watch?v=S13FrWuBMx4&list=UUckpus81gNin1aV8WSffRKw )`
@ -61,8 +57,7 @@ character, created by Andreas Esau.
Get your assets: :download:`gbot_resources.zip (files/gbot_resources.zip )`.
Setting up the rig
~~~~~~~~~~~~~~~~~~
### Setting up the rig
Create an empty Node2D as root of the scene, we will work under it:
@ -92,8 +87,7 @@ the rotation pivot:
![](img/tuto_cutout4.png)
Adjusting the pivot
~~~~~~~~~~~~~~~~~~~
### Adjusting the pivot
The pivot can be adjusted by changing the *offset* property in the
Sprite:
@ -128,8 +122,7 @@ Note:
You can also fix depth ordering problems by adjusting the Z property
of any node inheriting from Node2D.
RemoteTransform2D node
~~~~~~~~~~~~~~~~~~~~~~
### RemoteTransform2D node
The `RemoteTransform2D` node transforms nodes
somewhere else in the hierarchy. This node applies its own transform (including
@ -150,8 +143,7 @@ animations by adjusting the `RemoteTransform2D` transforms:
![](img/tutovec_torso4.gif)
Completing the skeleton
~~~~~~~~~~~~~~~~~~~~~~~
### Completing the skeleton
Complete the skeleton by following the same steps for the rest of the
parts. The resulting scene should look similar to this:
@ -170,8 +162,7 @@ For simple objects and rigs this is fine, but there are limitations:
To solve these problems we'll use Pandemonium's skeletons.
Skeletons
~~~~~~~~~
### Skeletons
In Pandemonium there is a helper to create "bones" between nodes. The bone-linked
nodes are called skeletons.
@ -229,8 +220,7 @@ sense soon.
Now that the whole figure is rigged, the next step is setting up the IK
chains. IK chains allow for more natural control of extremities.
IK chains
~~~~~~~~~
### IK chains
IK stands for inverse kinematics. It's a convenient technique for animating the
position of hands, feet and other extremities of rigs like the one we've made.
@ -261,15 +251,13 @@ adjust its position.
![](img/tutovec_torso5.gif)
Animation tips
~~~~~~~~~~~~~~
### Animation tips
The following section will be a collection of tips for creating animation for
your cutout rigs. For more information on how the animation system in Pandemonium
works, see `doc_introduction_animation`.
Setting keyframes and excluding properties
------------------------------------------
## Setting keyframes and excluding properties
Special contextual elements appear in the top toolbar when the animation editor
window is open:
@ -291,8 +279,7 @@ You can use the toggle buttons to have only rotation information added when you
add a new keyframe. This way, you can avoid adding unwanted scale keyframes
which would disrupt the existing scale animation.
Creating a rest pose
~~~~~~~~~~~~~~~~~~~~
## Creating a rest pose
Think of a rest pose as a default pose that your cutout rig should be set to
when no other pose is active in your game. Create a rest pose as follows:
@ -313,8 +300,7 @@ your game by playing the "rest" animation you've created.
![](img/tuto_cutout21.png)
Modifying rotation only
~~~~~~~~~~~~~~~~~~~~~~~
### Modifying rotation only
When animating a cutout rig, often it's only the rotation of the nodes that
needs to change.
@ -328,15 +314,13 @@ toggle active most of the time:
This will avoid the creation of unwanted animation tracks for position
and scale.
Keyframing IK chains
~~~~~~~~~~~~~~~~~~~~
### Keyframing IK chains
When editing IK chains, it's not necessary to select the whole chain to
add keyframes. Selecting the endpoint of the chain and inserting a
keyframe will automatically insert keyframes for all other parts of the chain too.
Visually move a sprite behind its parent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Visually move a sprite behind its parent
Sometimes it is necessary to have a node change its visual depth relative to
its parent node during an animation. Think of a character facing the camera,
@ -351,8 +335,7 @@ and/or RemoteTransform2D nodes. They provide overlapping functionality.
![](img/tuto_cutout23.png)
Setting easing curves for multiple keys
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Setting easing curves for multiple keys
To apply the same easing curve to multiple keyframes at once:
@ -363,8 +346,7 @@ To apply the same easing curve to multiple keyframes at once:
![](img/tuto_cutout24.png)
2D Skeletal deform
~~~~~~~~~~~~~~~~~~
### 2D Skeletal deform
Skeletal deform can be used to augment a cutout rig, allowing single pieces to
deform organically (e.g. antennae that wobble as an insect character walks).

View File

@ -1,10 +1,8 @@
2D skeletons
============
# 2D skeletons
Introduction
------------
## Introduction
When working with 3D, skeletal deforms are common for characters and creatures
and most 3D modelling applications support it. For 2D, as this function is not
@ -26,8 +24,7 @@ that there are many advantages to it:
The following tutorial will, then, explain 2D skeletal deformations.
Setup
-----
## Setup
See also:
@ -48,8 +45,7 @@ for putting the different pieces together.
![](img/gBot_complete.png)
Creating the polygons
---------------------
## reating the polygons
Create a new scene for your model (if it's going to be an animated character,
you may want to use a `KinematicBody2D`). For ease of use, an empty 2D node is
@ -108,8 +104,7 @@ wrong pieces. Rearrange the order of the nodes to fix this:
And there you go! It was definitely much easier than in the cutout tutorial.
Creating the skeleton
---------------------
## Creating the skeleton
Create a `Skeleton2D` node as a child of the root node. This will be the base
of our skeleton:
@ -151,8 +146,7 @@ want (which is very handy for animating):
The warnings will go away. If you modify the skeleton (add/remove bones) you
will need to set the rest pose again.
Deforming the polygons
----------------------
## Deforming the polygons
Select the previously created polygons and assign the skeleton node to their
`Skeleton` property. This will ensure that they can eventually be deformed by
@ -205,8 +199,7 @@ when drawing the polygon. They don't always bend the way you would expect. To
solve this, you need to set hints in the geometry to clarify how you expect it
to deform.
Internal vertices
-----------------
## Internal vertices
Open the UV menu for each bone again and go to the *Points* section. Add some
internal vertices in the regions where you expect the geometry to bend:

View File

@ -1,10 +1,8 @@
Using AnimationTree
===================
# Using AnimationTree
Introduction
------------
## Introduction
With `AnimationPlayer`, Pandemonium has one of the most flexible animation systems that you can find in any game engine.
The ability to animate almost any property in any node or resource, as well as having dedicated transform, bezier,
@ -15,8 +13,7 @@ However, the support for blending those animations via `AnimationPlayer` is rela
`AnimationTree` is a new node introduced in Pandemonium 3.1 to deal with advanced transitions.
It supersedes the ancient `AnimationTreePlayer`, while adding a huge amount of features and flexibility.
Creating an AnimationTree
-------------------------
## Creating an AnimationTree
Before starting, it must be made clear that an `AnimationTree` node does not contain its own animations.
Instead, it uses animations contained in an `AnimationPlayer` node. This way, you can edit your animations (or import them from a 3D scene)
@ -36,8 +33,7 @@ This is how it's done in the `Third Person Shooter demo ( https://github.com/pan
A new scene was created for the player with a `KinematicBody` as root. Inside this scene, the original `.dae` (Collada) file was instantiated
and an `AnimationTree` node was created.
Creating a tree
---------------
## Creating a tree
There are three main types of nodes that can be used in `AnimationTree`:
@ -55,8 +51,7 @@ To set a root node in `AnimationTree`, a few types are available:
* `AnimationNodeBlendSpace2D`: Allows placing root nodes in a 2D blend space. Control the blend position in 2D to mix between multiple animations.
* `AnimationNodeBlendSpace1D`: Simplified version of the above (1D).
Blend tree
----------
## Blend tree
An `AnimationNodeBlendTree` can contain both root and regular nodes used for blending. Nodes are added to the graph from a menu:
@ -72,8 +67,7 @@ This will simply play back the animation. Make sure that the `AnimationTree` is
Following is a short description of available nodes:
Blend2 / Blend3
^^^^^^^^^^^^^^^
#### Blend2 / Blend3
These nodes will blend between two or three inputs by a user-specified blend value:
@ -86,15 +80,13 @@ This is very useful for layering animations on top of each other.
![](img/animtree6.png)
OneShot
^^^^^^^
#### OneShot
This node will execute a sub-animation and return once it finishes. Blend times for fading in and out can be customized, as well as filters.
![](img/animtree6b.gif)
Seek
^^^^
#### Seek
This node can be used to cause a seek command to happen to any sub-children of the animation graph. Use this node type to play an `Animation` from the start or a certain playback position inside the `AnimationNodeBlendTree`.
@ -114,18 +106,15 @@ gdscript GDScript
anim_tree["parameters/Seek/seek_position"] = 12.0
```
TimeScale
^^^^^^^^^
#### TimeScale
Allows scaling the speed of the animation (or reverse it) in any children nodes. Setting it to 0 will pause the animation.
Transition
^^^^^^^^^^
#### Transition
Very simple state machine (when you don't want to cope with a `StateMachine` node). Animations can be connected to the outputs and transition times can be specified.
BlendSpace2D
^^^^^^^^^^^^
#### BlendSpace2D
`BlendSpace2D` is a node to do advanced blending in two dimensions. Points are added to a two-dimensional space and then a position
can be controlled to determine blending:
@ -148,13 +137,11 @@ This mode can be changed in the *Blend* menu:
![](img/animtree10.png)
BlendSpace1D
^^^^^^^^^^^^
#### BlendSpace1D
This is similar to 2D blend spaces, but in one dimension (so triangles are not needed).
StateMachine
^^^^^^^^^^^^
#### StateMachine
This node acts as a state machine with root nodes as states. Root nodes can be created and connected via lines. States are connected via *Transitions*,
which are connections with special properties. Transitions are uni-directional, but two can be used to connect in both directions.
@ -182,8 +169,7 @@ Transitions also have a few properties. Click any transition and it will be disp
* *Disabled* toggles disabling this transition (when disabled, it will not be used during travel or auto advance).
Root motion
-----------
## Root motion
When working with 3D animations, a popular technique is for animators to use the root skeleton bone to give motion to the rest of the skeleton.
This allows animating characters in a way where steps actually match the floor below. It also allows precise interaction with objects during cinematics.
@ -209,8 +195,7 @@ character and animations (this node is disabled by default during the game).
![](img/animtree15.gif)
Controlling from code
---------------------
## Controlling from code
After building the tree and previewing it, the only question remaining is "How is all this controlled from code?".
@ -242,8 +227,7 @@ gdscript GDScript
```
State machine travel
--------------------
## State machine travel
One of the nice features in Pandemonium's `StateMachine` implementation is the ability to travel. The graph can be instructed to go from the
current state to another one, while visiting all the intermediate ones. This is done via the A\* algorithm.

View File

@ -1,12 +1,10 @@
Playing videos
==============
# Playing videos
Pandemonium supports video playback with the `VideoPlayer` node.
Supported playback formats
--------------------------
## Supported playback formats
The only supported format in core is **Ogg Theora** (not to be confused with Ogg
Vorbis audio). It's possible for extensions to bring support for additional
@ -31,8 +29,7 @@ Note:
imported in Pandemonium. However, not all files with `.ogg` or `.ogx`
extensions are videos - some of them may only contain audio.
Setting up VideoPlayer
----------------------------
## Setting up VideoPlayer
1. Create a VideoPlayer node using the Create New Node dialog.
2. Select the VideoPlayer node in the scene tree dock, go to the inspector
@ -46,8 +43,7 @@ Setting up VideoPlayer
`play()` on the VideoPlayer node in a script to start playback when
desired.
Handling resizing and different aspect ratios
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Handling resizing and different aspect ratios
By default in Pandemonium 4.0, the VideoPlayer will automatically be resized to match
the video's resolution. You can make it follow usual `Control` sizing
@ -86,8 +82,7 @@ See also:
See `doc_multiple_resolutions` for more tips on supporting multiple
aspect ratios in your project.
Displaying a video on a 3D surface
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Displaying a video on a 3D surface
Using a VideoPlayer node as a child of a `Viewport` node,
it's possible to display any 2D node on a 3D surface. For example, this can be
@ -118,8 +113,7 @@ See `doc_viewports` and the
`GUI in 3D demo ( https://github.com/Relintai/pandemonium_engine-demo-projects/tree/master/viewport/gui_in_3d )`
for more information on setting this up.
Video decoding conditions and recommended resolutions
-----------------------------------------------------
## Video decoding conditions and recommended resolutions
Video decoding is performed on the CPU, as GPUs don't have hardware acceleration
for decoding Theora videos. Modern desktop CPUs can decode Ogg Theora videos at
@ -137,8 +131,7 @@ To ensure your videos decode smoothly on varied hardware:
between 720p and 1080p videos on a mobile device is usually not that
noticeable.
Playback limitations
--------------------
## Playback limitations
There are several limitations with the current implementation of video playback in Pandemonium:
@ -156,8 +149,7 @@ There are several limitations with the current implementation of video playback
Recommended Theora encoding settings
------------------------------------
## Recommended Theora encoding settings
A word of advice is to **avoid relying on built-in Ogg Theora exporters** (most of the time).
There are 2 reasons you may want to favor using an external program to encode your video:
@ -193,8 +185,7 @@ Note:
You can check this by running `ffmpeg` without any arguments, then looking
at the `configuration:` line in the command output.
Balancing quality and file size
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Balancing quality and file size
The **video quality** level (`-q:v`) must be between `1` and `10`. Quality
`6` is a good compromise between quality and file size. If encoding at a high
@ -213,8 +204,7 @@ valuable if your input file already uses lossy audio compression. See
for a table listing Ogg Vorbis audio quality presets and their respective
variable bitrates.
FFmpeg: Convert while preserving original video resolution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### FFmpeg: Convert while preserving original video resolution
The following command converts the video while keeping its original resolution.
The video and audio's bitrate will be variable to maximize quality while saving
@ -225,8 +215,7 @@ static scenes).
ffmpeg -i input.mp4 -q:v 6 -q:a 6 output.ogv
```
FFmpeg: Resize the video then convert it
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### FFmpeg: Resize the video then convert it
The following command resizes a video to be 720 pixels tall (720p), while
preserving its existing aspect ratio. This helps decrease the file size

View File

@ -1,10 +1,8 @@
Using InputEvent
================
# Using InputEvent
What is it?
-----------
## What is it?
Managing input is usually complex, no matter the OS or platform. To ease
this a little, a special built-in type is provided, `InputEvent`.
@ -39,8 +37,7 @@ gdscript GDScript
# Move right.
```
How does it work?
-----------------
## How does it work?
Every input event is originated from the user/player (though it's
possible to generate an InputEvent and feed them back to the engine,
@ -100,8 +97,7 @@ specialized child nodes to handle and consume particular events, while
their ancestors, and ultimately the scene root, can provide more
generalized behavior if needed.
Anatomy of an InputEvent
------------------------
## Anatomy of an InputEvent
`InputEvent` is just a base built-in type, it does not represent
anything and only contains some basic information, such as event ID
@ -109,40 +105,31 @@ anything and only contains some basic information, such as event ID
There are several specialized types of InputEvent, described in the table below:
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| Event | Type Index | Description |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEvent` | NONE | Empty Input Event. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventKey` | KEY | Contains a scancode and Unicode value, |
| | | as well as modifiers. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventMouseButton` | MOUSE_BUTTON | Contains click information, such as |
| | | button, modifiers, etc. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventMouseMotion` | MOUSE_MOTION | Contains motion information, such as |
| | | relative, absolute positions and speed. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventJoypadMotion` | JOYSTICK_MOTION | Contains Joystick/Joypad analog axis |
| | | information. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventJoypadButton` | JOYSTICK_BUTTON | Contains Joystick/Joypad button |
| | | information. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventScreenTouch` | SCREEN_TOUCH | Contains multi-touch press/release |
| | | information. (only available on mobile |
| | | devices) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventScreenDrag` | SCREEN_DRAG | Contains multi-touch drag information. |
| | | (only available on mobile devices) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| `InputEventAction` | SCREEN_ACTION | Contains a generic action. These events |
| | | are often generated by the programmer |
| | | as feedback. (more on this below) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
Actions
-------
| Event | Type Index | Description |
|-----------------------------|--------------------|-----------------------------------------|
| `InputEvent` | NONE | Empty Input Event. |
| `InputEventKey` | KEY | Contains a scancode and Unicode value, |
| | | as well as modifiers. |
| `InputEventMouseButton` | MOUSE_BUTTON | Contains click information, such as |
| | | button, modifiers, etc. |
| `InputEventMouseMotion` | MOUSE_MOTION | Contains motion information, such as |
| | | relative, absolute positions and speed. |
| `InputEventJoypadMotion` | JOYSTICK_MOTION | Contains Joystick/Joypad analog axis |
| | | information. |
| `InputEventJoypadButton` | JOYSTICK_BUTTON | Contains Joystick/Joypad button |
| | | information. |
| `InputEventScreenTouch` | SCREEN_TOUCH | Contains multi-touch press/release |
| | | information. (only available on mobile |
| | | devices) |
| `InputEventScreenDrag` | SCREEN_DRAG | Contains multi-touch drag information. |
| | | (only available on mobile devices) |
| `InputEventAction` | SCREEN_ACTION | Contains a generic action. These events |
| | | are often generated by the programmer |
| | | as feedback. (more on this below) |
## Actions
An InputEvent may or may not represent a pre-defined action. Actions are
useful because they abstract the input device when programming the game
@ -174,8 +161,7 @@ gdscript GDScript
Input.parse_input_event(ev)
````
InputMap
--------
## InputMap
Customizing and re-mapping input from code is often desired. If your
whole workflow depends on actions, the `InputMap` singleton is

View File

@ -1,10 +1,8 @@
Input examples
==============
# Input examples
Introduction
------------
## Introduction
In this tutorial, you'll learn how to use Pandemonium's `InputEvent`
system to capture player input. There are many different types of input your
@ -17,8 +15,7 @@ Note:
For a detailed overview of how Pandemonium's input event system works,
see `doc_inputevent`.
Events versus polling
---------------------
## Events versus polling
Sometimes you want your game to respond to a certain input event - pressing
the "jump" button, for example. For other situations, you might want something
@ -49,8 +46,7 @@ you do.
For the remainder of this tutorial, we'll focus on capturing individual
events in `input()`.
Input events
------------
## Input events
Input events are objects that inherit from `InputEvent`.
Depending on the event type, the object will contain specific properties
@ -108,8 +104,7 @@ gdscript GDScript
print("mouse button event at ", event.position)
```
InputMap
--------
## InputMap
The `InputMap` is the most flexible way to handle a
variety of inputs. You use this by creating named input *actions*, to which
@ -120,8 +115,7 @@ the InputMap tab:
![](img/inputs_inputmap.png)
Capturing actions
~~~~~~~~~~~~~~~~~
### Capturing actions
Once you've defined your actions, you can process them in your scripts using
`is_action_pressed()` and `is_action_released()` by passing the name of
@ -135,8 +129,7 @@ gdscript GDScript
print("my_action occurred!")
```
Keyboard events
---------------
## Keyboard events
Keyboard events are captured in `InputEventKey`.
While it's recommended to use input actions instead, there may be cases where
@ -170,8 +163,7 @@ Warning:
`this Gamedev Stack Exchange question ( https://gamedev.stackexchange.com/a/109002 )`
for more information.
Keyboard modifiers
~~~~~~~~~~~~~~~~~~
### Keyboard modifiers
Modifier properties are inherited from
`InputEventWithModifiers`. This allows
@ -195,16 +187,14 @@ Tip:
See `@GlobalScope_KeyList ( enum_@GlobalScope_KeyList )` for a list of scancode
constants.
Mouse events
------------
## Mouse events
Mouse events stem from the `InputEventMouse` class, and
are separated into two types: `InputEventMouseButton`
and `InputEventMouseMotion`. Note that this
means that all mouse events will contain a `position` property.
Mouse buttons
~~~~~~~~~~~~~
### Mouse buttons
Capturing mouse buttons is very similar to handling key events. `@GlobalScope_ButtonList ( enum_@GlobalScope_ButtonList )`
contains a list of `BUTTON_*` constants for each possible button, which will
@ -223,8 +213,7 @@ gdscript GDScript
print("Wheel up")
```
Mouse motion
~~~~~~~~~~~~
### Mouse motion
`InputEventMouseMotion` events occur whenever
the mouse moves. You can find the move's distance with the `relative`
@ -258,8 +247,7 @@ gdscript GDScript
$Sprite.position = event.position
```
Touch events
------------
## Touch events
If you are using a touchscreen device, you can generate touch events.
`InputEventScreenTouch` is equivalent to

View File

@ -1,24 +1,20 @@
Mouse and input coordinates
===========================
# Mouse and input coordinates
About
-----
## About
The reason for this small tutorial is to clear up many common mistakes
about input coordinates, obtaining mouse position and screen resolution,
etc.
Hardware display coordinates
----------------------------
## Hardware display coordinates
Using hardware coordinates makes sense in the case of writing complex
UIs meant to run on PC, such as editors, MMOs, tools, etc. However, it does
not make as much sense outside of that scope.
Viewport display coordinates
----------------------------
## Viewport display coordinates
Pandemonium uses viewports to display content, and viewports can be scaled by
several options (see `doc_multiple_resolutions` tutorial). Use, then, the

View File

@ -1,7 +1,6 @@
Customizing the mouse cursor
============================
# Customizing the mouse cursor
You might want to change the appearance of the mouse cursor in your game in order to suit the overall design. There are two ways to customize the mouse cursor:
@ -22,8 +21,7 @@ Note:
If you have to use the "software" approach, consider adding an extrapolation step
to better display the actual mouse input.
Using project settings
----------------------
## Using project settings
Open project settings, go to Display>Mouse Cursor. You will see Custom Image and Custom Image Hotspot.
@ -35,8 +33,7 @@ Custom Hotspot is the point in the image that you would like to use as the curso
Note:
The custom image **must** be less than 256x256.
Using a script
--------------
## Using a script
Create a Node and attach the following script.
@ -65,13 +62,11 @@ Note:
Check `Input.set_custom_mouse_cursor()`.
Demo project
------------
## Demo project
Find out more by studying this demo project:
https://github.com/guilhermefelipecgs/custom_hardware_cursor
Cursor list
-----------
## Cursor list
As documented in the `Input` class (see the **CursorShape** enum), there are multiple mouse cursors you can define. Which ones you want to use depends on your use case.

View File

@ -1,18 +1,14 @@
# Handling quit requests
Handling quit requests
======================
Quitting
--------
## Quitting
Most platforms have the option to request the application to quit. On
desktops, this is usually done with the "x" icon on the window title bar.
On Android, the back button is used to quit when on the main screen (and
to go back otherwise).
Handling the notification
-------------------------
## Handling the notification
On desktop platforms, the `MainLoop`
has a special `MainLoop.NOTIFICATION_WM_QUIT_REQUEST` notification that is
@ -51,8 +47,7 @@ gdscript GDScript
get_tree().set_auto_accept_quit(false)
```
Sending your own quit notification
----------------------------------
## Sending your own quit notification
While forcing the application to close can be done by calling `SceneTree.quit`,
doing so will not send the quit *notification*. This means the function

View File

@ -1,7 +1,6 @@
Controllers, gamepads, and joysticks
====================================
# Controllers, gamepads, and joysticks
Pandemonium supports hundreds of controller models thanks to the community-sourced
`SDL game controller database ( https://github.com/gabomdq/SDL_GameControllerDB )`.
@ -21,8 +20,7 @@ In this guide, you will learn:
- **How controllers can behave differently from keyboard/mouse input.**
- **Troubleshooting issues with controllers in Pandemonium.**
Supporting universal input
--------------------------
## Supporting universal input
Thanks to Pandemonium's input action system, Pandemonium makes it possible to support both
keyboard and controller input without having to write separate code paths.
@ -39,8 +37,7 @@ Note:
action (such as looking around in a first-person game) will require
different code paths since these have to be handled separately.
Which Input singleton method should I use?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Which Input singleton method should I use?
There are 3 ways to get input in an analog-aware way:
@ -101,14 +98,12 @@ In Pandemonium versions before 3.4, such as 3.3, `Input.get_vector()` and
`Input.get_axis()` aren't available. Only `Input.get_action_strength()`
and `Input.is_action_pressed()` are available in Pandemonium 3.3.
Differences between keyboard/mouse and controller input
-------------------------------------------------------
## Differences between keyboard/mouse and controller input
If you're used to handling keyboard and mouse input, you may be surprised by how
controllers handle specific situations.
Dead zone
^^^^^^^^^
#### Dead zone
Unlike keyboards and mice, controllers offer axes with *analog* inputs. The
upside of analog inputs is that they offer additional flexibility for actions.
@ -135,8 +130,7 @@ in the Project Settings' Input Map tab.
For `Input.get_vector()`, the deadzone can be specified, or otherwise it
will calculate the average deadzone value from all of the actions in the vector.
"Echo" events
^^^^^^^^^^^^^
#### "Echo" events
Unlike keyboard input, holding down a controller button such as a D-pad
direction will **not** generate repeated input events at fixed intervals (also
@ -149,25 +143,21 @@ If you want controller buttons to send echo events, you will have to generate
at regular intervals. This can be accomplished
with the help of a `Timer` node.
Troubleshooting
---------------
## Troubleshooting
See also:
You can view a list of
`known issues with controller support ( https://github.com/Relintai/pandemonium_engine/issues?q=is%3Aopen+is%3Aissue+label%3Atopic%3Ainput+gamepad )`
on GitHub.
My controller isn't recognized by Pandemonium.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### My controller isn't recognized by Pandemonium.
First, check that your controller is recognized by other applications. You can
use the `Gamepad Tester ( https://gamepad-tester.com/ )` website to confirm that
your controller is recognized.
My controller has incorrectly mapped buttons or axes.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### My controller has incorrectly mapped buttons or axes.
If buttons are incorrectly mapped, this may be due to an erroneous mapping from
the `SDL game controller database ( https://github.com/gabomdq/SDL_GameControllerDB )`.
@ -205,19 +195,16 @@ additional controller mappings, you can add them by calling
`Input.add_joy_mapping()`
as early as possible in a script's `ready()` function.
My controller works on a given platform, but not on another platform.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### My controller works on a given platform, but not on another platform.
Linux
~~~~~
### Linux
Prior to Pandemonium 3.3, official Pandemonium binaries were compiled with udev support
but self-compiled binaries were compiled *without* udev support unless
`udev=yes` was passed on the SCons command line. This made controller
hotplugging support unavailable in self-compiled binaries.
HTML5
~~~~~
### HTML5
HTML5 controller support is often less reliable compared to "native" platforms.
The quality of controller support tends to vary wildly across browsers. As a

View File

@ -1,7 +1,6 @@
Background loading
==================
# Background loading
When switching the main scene of your game (e.g. going to a new
level), you might want to show a loading screen with some indication
@ -11,8 +10,7 @@ thread, making your game appear frozen and unresponsive while the resource is be
document discusses the alternative of using the `ResourceInteractiveLoader` class for smoother
load screens.
ResourceInteractiveLoader
-------------------------
## ResourceInteractiveLoader
The `ResourceInteractiveLoader` class allows you to load a resource in
stages. Every time the method `poll` is called, a new stage is loaded,
@ -20,13 +18,11 @@ and control is returned to the caller. Each stage is generally a
sub-resource that is loaded by the main resource. For example, if you're
loading a scene that loads 10 images, each image will be one stage.
Usage
-----
## Usage
Usage is generally as follows
Obtaining a ResourceInteractiveLoader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Obtaining a ResourceInteractiveLoader
```
Ref( ResourceInteractiveLoader> ResourceLoader::load_interactive(String p_path);
@ -35,8 +31,7 @@ Obtaining a ResourceInteractiveLoader
This method will give you a ResourceInteractiveLoader that you will use
to manage the load operation.
Polling
~~~~~~~
### Polling
```
Error ResourceInteractiveLoader::poll();
@ -50,8 +45,7 @@ so it will take several frames to load.
Returns `OK` on no errors, `ERR_FILE_EOF` when loading is finished.
Any other return value means there was an error and loading has stopped.
Load progress (optional)
~~~~~~~~~~~~~~~~~~~~~~~~
### Load progress (optional)
To query the progress of the load, use the following methods:
@ -63,8 +57,7 @@ To query the progress of the load, use the following methods:
`get_stage_count` returns the total number of stages to load.
`get_stage` returns the current stage being loaded.
Forcing completion (optional)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Forcing completion (optional)
```
Error ResourceInteractiveLoader::wait();
@ -73,8 +66,7 @@ Forcing completion (optional)
Use this method if you need to load the entire resource in the current
frame, without any more steps.
Obtaining the resource
~~~~~~~~~~~~~~~~~~~~~~
### Obtaining the resource
```
Ref<Resource> ResourceInteractiveLoader::get_resource();
@ -83,8 +75,7 @@ Obtaining the resource
If everything goes well, use this method to retrieve your loaded
resource.
Example
-------
## Example
This example demonstrates how to load a new scene. Consider it in the
context of the `doc_singletons_autoload` example.
@ -195,20 +186,17 @@ loader.
get_node("/root").add_child(current_scene)
```
Using multiple threads
----------------------
## Using multiple threads
ResourceInteractiveLoader can be used from multiple threads. A couple of
things to keep in mind if you attempt it:
Use a semaphore
~~~~~~~~~~~~~~~
### Use a semaphore
While your thread waits for the main thread to request a new resource,
use a `Semaphore` to sleep (instead of a busy loop or anything similar).
Not blocking main thread during the polling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Not blocking main thread during the polling
If you have a mutex to allow calls from the main thread to your loader
class, don't lock the main thread while you call `poll` on your loader class. When a
@ -218,8 +206,7 @@ thread to acquire them. This might cause a deadlock if the main thread
is waiting for your mutex while your thread is waiting to load a
resource.
Example class
-------------
## Example class
You can find an example class for loading resources in threads here:
:download:`resource_queue.gd ( files/resource_queue.gd )`. Usage is as follows:
@ -268,8 +255,7 @@ not fully loaded (`is_ready` returns `false`), it will block your thread
and finish the load. If the resource is not on the queue, it will call
`ResourceLoader::load` to load it normally and return it.
Example:
~~~~~~~~
### Example:
```
# Initialize.

View File

@ -1,14 +1,12 @@
File paths in Pandemonium projects
============================
# File paths in Pandemonium projects
This page explains how file paths work inside Pandemonium projects. You will learn how
to access paths in your projects using the `res://` and `user://` notations,
and where Pandemonium stores project and editor files on your and your users' systems.
Path separators
---------------
## Path separators
To make supporting multiple platforms easier, Pandemonium uses **UNIX-style path
separators** (forward slash `/`). These work on all platforms, **including
@ -25,8 +23,7 @@ This makes it possible to work with paths returned by other Windows
applications. We still recommend using only forward slashes in your own code to
guarantee that everything will work as intended.
Accessing files in the project folder (`res://`)
--------------------------------------------------
## Accessing files in the project folder (`res://`)
Pandemonium considers that a project exists in any folder that contains a
`project.pandemonium` text file, even if the file is empty. The folder that contains
@ -37,8 +34,7 @@ You can access any file relative to it by writing paths starting with
file `character.png)` located in the project's root folder in code with the
following path: `res://character.png)`.
Accessing persistent user data (`user://`)
--------------------------------------------
## Accessing persistent user data (`user://`)
To store persistent data files, like the player's save or settings, you want to
use `user://` instead of `res://` as your path's prefix. This is because
@ -68,21 +64,17 @@ Project Settings:
On desktop platforms, the actual directory paths for `user://` are:
+---------------------+------------------------------------------------------------------------------+
| Type | Location |
+=====================+==============================================================================+
| Default | | Windows: `%APPDATA%\Pandemonium\app_userdata\[project_name]` |
| | | macOS: `~/Library/Application Support/Pandemonium/app_userdata/[project_name]` |
| | | Linux: `~/.local/share/pandemonium/app_userdata/[project_name]` |
+---------------------+------------------------------------------------------------------------------+
| Custom dir | | Windows: `%APPDATA%\[project_name]` |
| | | macOS: `~/Library/Application Support/[project_name]` |
| | | Linux: `~/.local/share/[project_name]` |
+---------------------+------------------------------------------------------------------------------+
| Custom dir and name | | Windows: `%APPDATA%\[custom_user_dir_name]` |
| | | macOS: `~/Library/Application Support/[custom_user_dir_name]` |
| | | Linux: `~/.local/share/[custom_user_dir_name]` |
+---------------------+------------------------------------------------------------------------------+
| Type | Location |
|---------------------|--------------------------------------------------------------------------------|
| Default | Windows: `%APPDATA%\Pandemonium\app_userdata\[project_name]` |
| | macOS: `~/Library/Application Support/Pandemonium/app_userdata/[project_name]` |
| | Linux: `~/.local/share/pandemonium/app_userdata/[project_name]` |
| Custom dir | Windows: `%APPDATA%\[project_name]` |
| | macOS: `~/Library/Application Support/[project_name]` |
| | Linux: `~/.local/share/[project_name]` |
| Custom dir and name | Windows: `%APPDATA%\[custom_user_dir_name]` |
| | macOS: `~/Library/Application Support/[custom_user_dir_name]` |
| | Linux: `~/.local/share/[custom_user_dir_name]` |
`[project_name]` is based on the application name defined in the Project Settings, but
you can override it on a per-platform basis using `feature tags ( doc_feature_tags )`.
@ -94,8 +86,7 @@ On HTML5 exports, `user://` will refer to a virtual filesystem stored on the
device via IndexedDB. (Interaction with the main filesystem can still be performed
through the `JavaScript` singleton.)
Converting paths to absolute paths or "local" paths
---------------------------------------------------
## Converting paths to absolute paths or "local" paths
You can use `ProjectSettings.globalize_path()`
to convert a "local" path like `res://path/to/file.txt` to an absolute OS path.
@ -111,27 +102,22 @@ project's root or `user://` folders.
Editor data paths
-----------------
## Editor data paths
The editor uses different paths for editor data, editor settings, and cache,
depending on the platform. By default, these paths are:
+-----------------+---------------------------------------------------+
| Type | Location |
+=================+===================================================+
| Editor data | | Windows: `%APPDATA%\Pandemonium\` |
| | | macOS: `~/Library/Application Support/Pandemonium/` |
| | | Linux: `~/.local/share/pandemonium/` |
+-----------------+---------------------------------------------------+
| Editor settings | | Windows: `%APPDATA%\Pandemonium\` |
| | | macOS: `~/Library/Application Support/Pandemonium/` |
| | | Linux: `~/.config/pandemonium/` |
+-----------------+---------------------------------------------------+
| Cache | | Windows: `%TEMP%\Pandemonium\` |
| | | macOS: `~/Library/Caches/Pandemonium/` |
| | | Linux: `~/.cache/pandemonium/` |
+-----------------+---------------------------------------------------+
| Type | Location |
|-----------------|-----------------------------------------------------|
| Editor data | Windows: `%APPDATA%\Pandemonium\` |
| | macOS: `~/Library/Application Support/Pandemonium/` |
| | Linux: `~/.local/share/pandemonium/` |
| Editor settings | Windows: `%APPDATA%\Pandemonium\` |
| | macOS: `~/Library/Application Support/Pandemonium/` |
| | Linux: `~/.config/pandemonium/` |
| Cache | Windows: `%TEMP%\Pandemonium\` |
| | macOS: `~/Library/Caches/Pandemonium/` |
| | Linux: `~/.cache/pandemonium/` |
- **Editor data** contains export templates and project-specific data.
- **Editor settings** contains the main editor settings configuration file as
@ -153,8 +139,7 @@ Note:
Self-contained mode
~~~~~~~~~~~~~~~~~~~
### Self-contained mode
If you create a file called `._sc_` or `sc_` in the same directory as the
editor binary (or in `MacOS/Contents/` for a macOS editor .app bundle), Pandemonium

View File

@ -1,10 +1,8 @@
Saving games
============
# Saving games
Introduction
------------
## Introduction
Save games can be complicated. For example, it may be desirable
to store information from multiple objects across multiple levels.
@ -18,8 +16,7 @@ Note:
If you're looking to save user configuration, you can use the
`ConfigFile` class for this purpose.
Identify persistent objects
---------------------------
## Identify persistent objects
Firstly, we should identify what objects we want to keep between game
sessions and what information we want to keep from those objects. For
@ -43,8 +40,7 @@ gdscript GDScript
# Now, we can call our save function on each node.
```
Serializing
-----------
## Serializing
The next step is to serialize the data. This makes it much easier to
read from and store to disk. In this case, we're assuming each member of
@ -87,8 +83,7 @@ This gives us a dictionary with the style
`{ "variable_name":value_of_variable }`, which will be useful when
loading.
Saving and reading data
-----------------------
## Saving and reading data
As covered in the `doc_filesystem` tutorial, we'll need to open a file
so we can write to it or read from it. Now that we have a way to
@ -178,8 +173,7 @@ Now we can save and load an arbitrary number of objects laid out
almost anywhere across the scene tree! Each object can store different
data depending on what it needs to save.
Some notes
----------
## Some notes
We have glossed over setting up the game state for loading. It's ultimately up
to the project creator where much of this logic goes.

View File

@ -1,10 +1,8 @@
Binary serialization API
========================
# Binary serialization API
Introduction
------------
## Introduction
Pandemonium has a simple serialization API based on Variant. It's used for
converting data types to an array of bytes efficiently. This API is used
@ -12,8 +10,7 @@ in the functions `get_var` and `store_var` of `File`
as well as the packet APIs for `PacketPeer`. This format
is *not* used for binary scenes and resources.
Packet specification
--------------------
## Packet specification
The packet is designed to be always padded to 4 bytes. All values are
little-endian-encoded. All packets have a 4-byte header representing an
@ -27,65 +24,36 @@ two bytes contain flags
flags = val >> 16;
```
+--------+--------------------------+
| Type | Value |
+========+==========================+
|--------|--------------------------|
| 0 | null |
+--------+--------------------------+
| 1 | bool |
+--------+--------------------------+
| 2 | integer |
+--------+--------------------------+
| 3 | float |
+--------+--------------------------+
| 4 | string |
+--------+--------------------------+
| 5 | vector2 |
+--------+--------------------------+
| 6 | rect2 |
+--------+--------------------------+
| 7 | vector3 |
+--------+--------------------------+
| 8 | transform2d |
+--------+--------------------------+
| 9 | plane |
+--------+--------------------------+
| 10 | quat |
+--------+--------------------------+
| 11 | aabb |
+--------+--------------------------+
| 12 | basis |
+--------+--------------------------+
| 13 | transform |
+--------+--------------------------+
| 14 | color |
+--------+--------------------------+
| 15 | node path |
+--------+--------------------------+
| 16 | rid |
+--------+--------------------------+
| 17 | object |
+--------+--------------------------+
| 18 | dictionary |
+--------+--------------------------+
| 19 | array |
+--------+--------------------------+
| 20 | raw array |
+--------+--------------------------+
| 21 | int array |
+--------+--------------------------+
| 22 | real array |
+--------+--------------------------+
| 23 | string array |
+--------+--------------------------+
| 24 | vector2 array |
+--------+--------------------------+
| 25 | vector3 array |
+--------+--------------------------+
| 26 | color array |
+--------+--------------------------+
| 27 | max |
+--------+--------------------------+
Following this is the actual packet contents, which varies for each type of
packet. Note that this assumes Pandemonium is compiled with single-precision floats,
@ -94,419 +62,293 @@ length of "Float" fields within data structures should be 8, and the offset
should be `(offset - 4) * 2 + 4`. The "float" type itself always uses double
precision.
0: null
~~~~~~~
### 0: null
1: `bool( bool )`
~~~~~~~~~~~~~~~~~~~~~~~~~~
### 1: `bool( bool )`
+----------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+===========================+
|----------|-------|-----------|---------------------------|
| 4 | 4 | Integer | 0 for False, 1 for True |
+----------+-------+-----------+---------------------------+
2: `int( int )`
~~~~~~~~~~~~~~~~~~~~~~~~
### 2: `int( int )`
If no flags are set (flags == 0), the integer is sent as a 32 bit integer:
+----------+-------+-----------+--------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+==========================+
|----------|-------|-----------|--------------------------|
| 4 | 4 | Integer | 32-bit signed integer |
+----------+-------+-----------+--------------------------+
If flag `ENCODE_FLAG_64` is set (`flags & 1 == 1`), the integer is sent as
a 64-bit integer:
+----------+-------+-----------+--------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+==========================+
|----------|-------|-----------|--------------------------|
| 4 | 8 | Integer | 64-bit signed integer |
+----------+-------+-----------+--------------------------+
3: `float( float )`
### 3: `float( float )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If no flags are set (flags == 0), the float is sent as a 32 bit single precision:
+----------+-------+---------+-----------------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===================================+
|----------|-------|---------|-----------------------------------|
| 4 | 4 | Float | IEEE 754 single-precision float |
+----------+-------+---------+-----------------------------------+
If flag `ENCODE_FLAG_64` is set (`flags & 1 == 1`), the float is sent as
a 64-bit double precision number:
+----------+-------+---------+-----------------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===================================+
|----------|-------|---------|-----------------------------------|
| 4 | 8 | Float | IEEE 754 double-precision float |
+----------+-------+---------+-----------------------------------+
4: `String( string )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 4: `String( string )`
+----------+-------+-----------+----------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+============================+
|----------|-------|-----------|----------------------------|
| 4 | 4 | Integer | String length (in bytes) |
+----------+-------+-----------+----------------------------+
| 8 | X | Bytes | UTF-8 encoded string |
+----------+-------+-----------+----------------------------+
This field is padded to 4 bytes.
5: `Vector2( vector2 )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 5: `Vector2( vector2 )`
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
|----------|-------|---------|----------------|
| 4 | 4 | Float | X coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y coordinate |
+----------+-------+---------+----------------+
6: `Rect2( rect2 )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 6: `Rect2( rect2 )`
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
|----------|-------|---------|----------------|
| 4 | 4 | Float | X coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | X size |
+----------+-------+---------+----------------+
| 16 | 4 | Float | Y size |
+----------+-------+---------+----------------+
7: `Vector3( vector3 )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 7: `Vector3( vector3 )`
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
|----------|-------|---------|----------------|
| 4 | 4 | Float | X coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | Z coordinate |
+----------+-------+---------+----------------+
8: `Transform2D( transform2d )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 8: `Transform2D( transform2d )`
+----------+-------+---------+---------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============================================================+
|----------|-------|---------|---------------------------------------------------------------|
| 4 | 4 | Float | The X component of the X column vector, accessed via [0][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 8 | 4 | Float | The Y component of the X column vector, accessed via [0][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 12 | 4 | Float | The X component of the Y column vector, accessed via [1][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 16 | 4 | Float | The Y component of the Y column vector, accessed via [1][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 20 | 4 | Float | The X component of the origin vector, accessed via [2][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 24 | 4 | Float | The Y component of the origin vector, accessed via [2][1] |
+----------+-------+---------+---------------------------------------------------------------+
9: `Plane( plane )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 9: `Plane( plane )`
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
|----------|-------|---------|---------------|
| 4 | 4 | Float | Normal X |
+----------+-------+---------+---------------+
| 8 | 4 | Float | Normal Y |
+----------+-------+---------+---------------+
| 12 | 4 | Float | Normal Z |
+----------+-------+---------+---------------+
| 16 | 4 | Float | Distance |
+----------+-------+---------+---------------+
10: `Quat( quat )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+---------+---------------+
### 10: `Quat( quat )`
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
|----------|-------|---------|---------------|
| 4 | 4 | Float | Imaginary X |
+----------+-------+---------+---------------+
| 8 | 4 | Float | Imaginary Y |
+----------+-------+---------+---------------+
| 12 | 4 | Float | Imaginary Z |
+----------+-------+---------+---------------+
| 16 | 4 | Float | Real W |
+----------+-------+---------+---------------+
11: `AABB( aabb )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+---------+----------------+
### 11: `AABB( aabb )`
| Offset | Len | Type | Description |
+==========+=======+=========+================+
|----------|-------|---------|----------------|
| 4 | 4 | Float | X coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | Z coordinate |
+----------+-------+---------+----------------+
| 16 | 4 | Float | X size |
+----------+-------+---------+----------------+
| 20 | 4 | Float | Y size |
+----------+-------+---------+----------------+
| 24 | 4 | Float | Z size |
+----------+-------+---------+----------------+
12: `Basis( basis )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+---------+---------------------------------------------------------------+
### 12: `Basis( basis )`
| Offset | Len | Type | Description |
+==========+=======+=========+===============================================================+
|----------|-------|---------|---------------------------------------------------------------|
| 4 | 4 | Float | The X component of the X column vector, accessed via [0][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 8 | 4 | Float | The Y component of the X column vector, accessed via [0][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 12 | 4 | Float | The Z component of the X column vector, accessed via [0][2] |
+----------+-------+---------+---------------------------------------------------------------+
| 16 | 4 | Float | The X component of the Y column vector, accessed via [1][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 20 | 4 | Float | The Y component of the Y column vector, accessed via [1][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 24 | 4 | Float | The Z component of the Y column vector, accessed via [1][2] |
+----------+-------+---------+---------------------------------------------------------------+
| 28 | 4 | Float | The X component of the Z column vector, accessed via [2][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 32 | 4 | Float | The Y component of the Z column vector, accessed via [2][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 36 | 4 | Float | The Z component of the Z column vector, accessed via [2][2] |
+----------+-------+---------+---------------------------------------------------------------+
13: `Transform( transform )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+---------+---------------------------------------------------------------+
### 13: `Transform( transform )`
| Offset | Len | Type | Description |
+==========+=======+=========+===============================================================+
|----------|-------|---------|---------------------------------------------------------------|
| 4 | 4 | Float | The X component of the X column vector, accessed via [0][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 8 | 4 | Float | The Y component of the X column vector, accessed via [0][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 12 | 4 | Float | The Z component of the X column vector, accessed via [0][2] |
+----------+-------+---------+---------------------------------------------------------------+
| 16 | 4 | Float | The X component of the Y column vector, accessed via [1][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 20 | 4 | Float | The Y component of the Y column vector, accessed via [1][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 24 | 4 | Float | The Z component of the Y column vector, accessed via [1][2] |
+----------+-------+---------+---------------------------------------------------------------+
| 28 | 4 | Float | The X component of the Z column vector, accessed via [2][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 32 | 4 | Float | The Y component of the Z column vector, accessed via [2][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 36 | 4 | Float | The Z component of the Z column vector, accessed via [2][2] |
+----------+-------+---------+---------------------------------------------------------------+
| 40 | 4 | Float | The X component of the origin vector, accessed via [3][0] |
+----------+-------+---------+---------------------------------------------------------------+
| 44 | 4 | Float | The Y component of the origin vector, accessed via [3][1] |
+----------+-------+---------+---------------------------------------------------------------+
| 48 | 4 | Float | The Z component of the origin vector, accessed via [3][2] |
+----------+-------+---------+---------------------------------------------------------------+
14: `Color( color )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 14: `Color( color )`
+----------+-------+---------+--------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+==============================================================+
|----------|-------|---------|--------------------------------------------------------------|
| 4 | 4 | Float | Red (typically 0..1, can be above 1 for overbright colors) |
+----------+-------+---------+--------------------------------------------------------------+
| 8 | 4 | Float | Green (typically 0..1, can be above 1 for overbright colors) |
+----------+-------+---------+--------------------------------------------------------------+
| 12 | 4 | Float | Blue (typically 0..1, can be above 1 for overbright colors) |
+----------+-------+---------+--------------------------------------------------------------+
| 16 | 4 | Float | Alpha (0..1) |
+----------+-------+---------+--------------------------------------------------------------+
15: `NodePath( nodepath )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+-----------+-----------------------------------------------------------------------------------------+
### 15: `NodePath( nodepath )`
| Offset | Len | Type | Description |
+==========+=======+===========+=========================================================================================+
|----------|-------|-----------|-----------------------------------------------------------------------------------------|
| 4 | 4 | Integer | String length, or new format (val&0x80000000!=0 and NameCount=val&0x7FFFFFFF) |
+----------+-------+-----------+-----------------------------------------------------------------------------------------+
For old format:
^^^^^^^^^^^^^^^
#### For old format:
+----------+-------+---------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+========================+
|----------|-------|---------|------------------------|
| 8 | X | Bytes | UTF-8 encoded string |
+----------+-------+---------+------------------------+
Padded to 4 bytes.
For new format:
^^^^^^^^^^^^^^^
#### For new format:
+----------+-------+-----------+-------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================+
|----------|-------|-----------|-------------------------------------|
| 4 | 4 | Integer | Sub-name count |
+----------+-------+-----------+-------------------------------------+
| 8 | 4 | Integer | Flags (absolute: val&1 != 0 ) |
+----------+-------+-----------+-------------------------------------+
For each Name and Sub-Name
+----------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+========================+
|----------|-------|-----------|------------------------|
| X+0 | 4 | Integer | String length |
+----------+-------+-----------+------------------------+
| X+4 | X | Bytes | UTF-8 encoded string |
+----------+-------+-----------+------------------------+
Every name string is padded to 4 bytes.
16: `RID( rid )` (unsupported)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 16: `RID( rid )` (unsupported)
17: `Object( object )` (unsupported)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 17: `Object( object )` (unsupported)
18: `Dictionary( dictionary )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 18: `Dictionary( dictionary )`
+----------+-------+-----------+---------------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================================================+
|----------|-------|-----------|---------------------------------------------------------------------|
| 4 | 4 | Integer | val&0x7FFFFFFF = elements, val&0x80000000 = shared (bool) |
+----------+-------+-----------+---------------------------------------------------------------------+
Then what follows is, for amount of "elements", pairs of key and value,
one after the other, using this same format.
19: `Array( array )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 19: `Array( array )`
+----------+-------+-----------+---------------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================================================+
|----------|-------|-----------|---------------------------------------------------------------------|
| 4 | 4 | Integer | val&0x7FFFFFFF = elements, val&0x80000000 = shared (bool) |
+----------+-------+-----------+---------------------------------------------------------------------+
Then what follows is, for amount of "elements", values one after the
other, using this same format.
20: `PoolByteArray( poolbytearray )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 20: `PoolByteArray( poolbytearray )`
+---------------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+===============+=======+===========+========================+
|---------------|-------|-----------|------------------------|
| 4 | 4 | Integer | Array length (Bytes) |
+---------------+-------+-----------+------------------------+
| 8..8+length | 1 | Byte | Byte (0..255) |
+---------------+-------+-----------+------------------------+
The array data is padded to 4 bytes.
21: `PoolIntArray( poolintarray )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 21: `PoolIntArray( poolintarray )`
+------------------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==================+=======+===========+===========================+
|------------------|-------|-----------|---------------------------|
| 4 | 4 | Integer | Array length (Integers) |
+------------------+-------+-----------+---------------------------+
| 8..8+length\*4 | 4 | Integer | 32-bit signed integer |
+------------------+-------+-----------+---------------------------+
22: `PoolRealArray( poolrealarray )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 22: `PoolRealArray( poolrealarray )`
+------------------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==================+=======+===========+===========================+
|------------------|-------|-----------|---------------------------|
| 4 | 4 | Integer | Array length (Floats) |
+------------------+-------+-----------+---------------------------+
| 8..8+length\*4 | 4 | Integer | 32-bits IEEE 754 float |
+------------------+-------+-----------+---------------------------+
23: `PoolStringArray( poolstringarray )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 23: `PoolStringArray( poolstringarray )`
+----------+-------+-----------+--------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+==========================+
|----------|-------|-----------|--------------------------|
| 4 | 4 | Integer | Array length (Strings) |
+----------+-------+-----------+--------------------------+
For each String:
+----------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+========================+
|----------|-------|-----------|------------------------|
| X+0 | 4 | Integer | String length |
+----------+-------+-----------+------------------------+
| X+4 | X | Bytes | UTF-8 encoded string |
+----------+-------+-----------+------------------------+
Every string is padded to 4 bytes.
24: `PoolVector2Array( poolvector2array )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### 24: `PoolVector2Array( poolvector2array )`
+-------------------+-------+-----------+----------------+
| Offset | Len | Type | Description |
+===================+=======+===========+================+
|-------------------|-------|-----------|----------------|
| 4 | 4 | Integer | Array length |
+-------------------+-------+-----------+----------------+
| 8..8+length\*8 | 4 | Float | X coordinate |
+-------------------+-------+-----------+----------------+
| 8..12+length\*8 | 4 | Float | Y coordinate |
+-------------------+-------+-----------+----------------+
25: `PoolVector3Array( poolvector3array )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------+-------+-----------+----------------+
### 25: `PoolVector3Array( poolvector3array )`
| Offset | Len | Type | Description |
+====================+=======+===========+================+
|--------------------|-------|-----------|----------------|
| 4 | 4 | Integer | Array length |
+--------------------+-------+-----------+----------------+
| 8..8+length\*12 | 4 | Float | X coordinate |
+--------------------+-------+-----------+----------------+
| 8..12+length\*12 | 4 | Float | Y coordinate |
+--------------------+-------+-----------+----------------+
| 8..16+length\*12 | 4 | Float | Z coordinate |
+--------------------+-------+-----------+----------------+
26: `PoolColorArray( poolcolorarray )`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------+-------+-----------+--------------------------------------------------------------+
### 26: `PoolColorArray( poolcolorarray )`
| Offset | Len | Type | Description |
+====================+=======+===========+==============================================================+
|--------------------|-------|-----------|--------------------------------------------------------------|
| 4 | 4 | Integer | Array length |
+--------------------+-------+-----------+--------------------------------------------------------------+
| 8..8+length\*16 | 4 | Float | Red (typically 0..1, can be above 1 for overbright colors) |
+--------------------+-------+-----------+--------------------------------------------------------------+
| 8..12+length\*16 | 4 | Float | Green (typically 0..1, can be above 1 for overbright colors) |
+--------------------+-------+-----------+--------------------------------------------------------------+
| 8..16+length\*16 | 4 | Float | Blue (typically 0..1, can be above 1 for overbright colors) |
+--------------------+-------+-----------+--------------------------------------------------------------+
| 8..20+length\*16 | 4 | Float | Alpha (0..1) |
+--------------------+-------+-----------+--------------------------------------------------------------+

View File

@ -1,10 +1,8 @@
High-level multiplayer
======================
# High-level multiplayer
High-level vs low-level API
---------------------------
## High-level vs low-level API
The following explains the differences of high- and low-level networking in Pandemonium as well as some fundamentals. If you want to jump in head-first and add networking to your first nodes, skip to `Initializing the network` below. But make sure to read the rest later on!
@ -54,8 +52,7 @@ Warning:
You can of course experiment, but when you release a networked application,
always take care of any possible security concerns.
Mid level abstraction
---------------------
## Mid level abstraction
Before going into how we would like to synchronize a game across the network, it can be helpful to understand how the base network API for synchronization works.
@ -73,8 +70,7 @@ mobile APIs (for ad hoc WiFi, Bluetooth) or custom device/console-specific netwo
For most common cases, using this object directly is discouraged, as Pandemonium provides even higher level networking facilities.
Yet it is made available in case a game has specific needs for a lower level API.
Initializing the network
------------------------
## Initializing the network
The object that controls networking in Pandemonium is the same one that controls everything tree-related: `SceneTree`.
@ -126,8 +122,7 @@ Warning:
using one-click deploy. Otherwise, network communication of any kind will be
blocked by Android.
Managing connections
--------------------
## Managing connections
Some games accept connections at any time, others during the lobby phase. Pandemonium can be requested to no longer accept
connections at any point (see `set_refuse_new_network_connections(bool)` and related methods on `SceneTree`). To manage who connects, Pandemonium provides the following signals in SceneTree:
@ -156,8 +151,7 @@ player information about other already connected players (e.g. their names, stat
Lobbies can be implemented any way you want, but the most common way is to use a node with the same name across scenes in all peers.
Generally, an autoloaded node/singleton is a great fit for this, to always have access to, e.g. "/root/lobby".
RPC
---
## RPC
To communicate between peers, the easiest way is to use RPCs (remote procedure calls). This is implemented as a set of functions
in `Node`:
@ -184,8 +178,7 @@ and if a packet is lost, it's not that bad because a new one will eventually arr
There is also `SceneTree.get_rpc_sender_id()`, which can be used to check which peer (or peer ID) sent an RPC.
Back to lobby
-------------
## Back to lobby
Let's get back to the lobby. Imagine that each player that connects to the server will tell everyone about it.
@ -274,14 +267,12 @@ With this, lobby management should be more or less explained. Once you have your
extra security to make sure clients don't do anything funny (just validate the info they send from time to time, or before
game start). For the sake of simplicity and because each game will share different information, this is not shown here.
Starting the game
-----------------
## Starting the game
Once enough players have gathered in the lobby, the server should probably start the game. This is nothing
special in itself, but we'll explain a few nice tricks that can be done at this point to make your life much easier.
Player scenes
^^^^^^^^^^^^^
#### Player scenes
In most games, each player will likely have its own scene. Remember that this is a multiplayer game, so in every peer
you need to instance **one scene for each player connected to it**. For a 4 player game, each peer needs to instance 4 player nodes.
@ -322,8 +313,7 @@ Note:
Depending on when you execute pre_configure_game(), you may need to change any calls to `add_child()`
to be deferred via `call_deferred()`, as the SceneTree is locked while the scene is being created (e.g. when `ready()` is being called).
Synchronizing game start
^^^^^^^^^^^^^^^^^^^^^^^^
#### Synchronizing game start
Setting up players might take different amounts of time for every peer due to lag, different hardware, or other reasons.
To make sure the game will actually start when everyone is ready, pausing the game until all players are ready can be useful:
@ -358,14 +348,12 @@ When the server gets the OK from all the peers, it can tell them to start, as fo
```
Synchronizing the game
----------------------
## Synchronizing the game
In most games, the goal of multiplayer networking is that the game runs synchronized on all the peers playing it.
Besides supplying an RPC and remote member variable set implementation, Pandemonium adds the concept of network masters.
Network master
^^^^^^^^^^^^^^
#### Network master
The network master of a node is the peer that has the ultimate authority over it.
@ -403,8 +391,7 @@ To clarify, here is an example of how this looks in the
![](img/nmms.png)
Master and puppet keywords
^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Master and puppet keywords
.. FIXME: Clarify the equivalents to the GDScript keywords in C# and Visual Script.
@ -473,8 +460,7 @@ This may not make much sense for an area-of-effect case like the bomb, but might
rpc_id(TARGET_PEER_ID, "stun") # Only stun the target peer
```
Exporting for dedicated servers
-------------------------------
## Exporting for dedicated servers
Once you've made a multiplayer game, you may want to export it to run it on
a dedicated server with no GPU available. See

View File

@ -1,7 +1,6 @@
Making HTTP requests
====================
# Making HTTP requests
The `HTTPRequest` node is the easiest way to make HTTP requests in Pandemonium.
It is backed by the more low-level `HTTPClient`.
@ -16,8 +15,7 @@ Warning:
using one-click deploy. Otherwise, network communication of any kind will be
blocked by Android.
Preparing scene
---------------
## Preparing scene
Create a new empty scene, add a CanvasLayer as the root node and add a script to it. Then add two child nodes to it: a Button and an HTTPRequest node. You will need to connect the following signals to the CanvasLayer script:
@ -26,8 +24,7 @@ Create a new empty scene, add a CanvasLayer as the root node and add a script to
![](img/rest_api_scene.png)
Scripting
---------
## Scripting
Below is all the code we need to make it work. The URL points to an online API mocker; it returns a pre-defined JSON string, which we will then parse to get access to the data.
@ -67,8 +64,7 @@ Please note that, for SSL/TLS encryption and thus HTTPS URLs to work, you may ne
Also, when calling APIs using authorization, be aware that someone might analyse and decompile your released application and thus may gain access to any embedded authorization information like tokens, usernames or passwords.
That means it is usually not a good idea to embed things such as database access credentials inside your game. Avoid providing information useful to an attacker whenever possible.
Sending data to server
----------------------
## Sending data to server
Until now, we have limited ourselves to requesting data from a server. But what if you need to send data to the server? Here is a common way of doing it:

View File

@ -1,7 +1,6 @@
HTTP client class
=================
# HTTP client class
`HTTPClient` provides low-level access to HTTP communication.
For a higher-level interface, you may want to take a look at `HTTPRequest` first,

View File

@ -1,10 +1,8 @@
SSL certificates
================
# SSL certificates
Introduction
------------
## Introduction
It is often desired to use SSL connections for communications to avoid
"man in the middle" attacks. Pandemonium has a connection wrapper,
@ -28,8 +26,7 @@ this when exporting your project.
There are two ways to obtain certificates:
Approach 1: self signed cert
----------------------------
## Approach 1: self signed cert
The first approach is the simplest: generate a private and public
key pair and add the public key (in PEM format) to the .crt file.
@ -41,8 +38,7 @@ this. This approach also **does not require domain validation** nor
requires you to spend a considerable amount of money in purchasing
certificates from a CA.
Approach 2: CA cert
-------------------
## Approach 2: CA cert
The second approach consists of using a certificate authority (CA)
such as Verisign, Geotrust, etc. This is a more cumbersome process,

View File

@ -1,10 +1,8 @@
WebSocket
=========
# WebSocket
HTML5 and WebSocket
-------------------
## HTML5 and WebSocket
The WebSocket protocol was standardized in 2011 with the original goal of allowing browsers to create stable and bidirectional connections with a server.
Before that, browsers used to only support HTTPRequests, which is not well-suited for bidirectional communication.
@ -15,8 +13,7 @@ Due to its simplicity, its wide compatibility, and being easier to use than a ra
Pandemonium supports WebSocket in both native and HTML5 exports.
Using WebSocket in Pandemonium
------------------------
## Using WebSocket in Pandemonium
WebSocket is implemented in Pandemonium via three main classes `WebSocketClient` for more details.
@ -28,8 +25,7 @@ Warning:
using one-click deploy. Otherwise, network communication of any kind will be
blocked by Android.
Minimal client example
^^^^^^^^^^^^^^^^^^^^^^
#### Minimal client example
This example will show you how to create a WebSocket connection to a remote server, and how to send and receive data.
@ -93,8 +89,7 @@ This will print:
Got data from server: Test packet
```
Minimal server example
^^^^^^^^^^^^^^^^^^^^^^
#### Minimal server example
This example will show you how to create a WebSocket server that listens for remote connections, and how to send and receive data.
@ -161,7 +156,6 @@ This will print (when a client connects) something similar to this:
Got data from client 1348090059: Test packet ... echoing
```
Advanced chat demo
^^^^^^^^^^^^^^^^^^
#### Advanced chat demo
A more advanced chat demo which optionally uses the multiplayer mid-level abstraction and a high level multiplayer demo are available in the `pandemonium demo projects ( https://github.com/Relintai/pandemonium_engine-demo-projects )` under `networking/websocket_chat` and `networking/websocket_multiplayer`.

View File

@ -1,24 +1,20 @@
WebRTC
======
# WebRTC
HTML5, WebSocket, WebRTC
------------------------
## HTML5, WebSocket, WebRTC
One of Pandemonium's great features is its ability to export to the HTML5/WebAssembly platform, allowing your game to run directly in the browser when a user visit your webpage.
This is a great opportunity for both demos and full games, but used to come with some limitations. In the area of networking, browsers used to support only HTTPRequests until recently, when first WebSocket and then WebRTC were proposed as standards.
WebSocket
^^^^^^^^^
#### WebSocket
When the WebSocket protocol was standardized in December 2011, it allowed browsers to create stable and bidirectional connections to a WebSocket server. The protocol is quite simple, but a very powerful tool to send push notifications to browsers, and has been used to implement chats, turn-based games, etc.
WebSockets, though, still use a TCP connection, which is good for reliability but not for latency, so not good for real-time applications like VoIP and fast-paced games.
WebRTC
^^^^^^
#### WebRTC
For this reason, since 2010, Google started working on a new technology called WebRTC, which later on, in 2017, became a W3C candidate recommendation. WebRTC is a much more complex set of specifications, and relies on many other technologies behind the scenes (ICE, DTLS, SDP) to provide fast, real-time, and secure communication between two peers.
@ -30,8 +26,7 @@ However, this comes at a price, which is that some media information must be exc
Peers connect to a signaling server (for example a WebSocket server) and send their media information. The server then relays this information to other peers, allowing them to establish the desired direct communication. Once this step is done, peers can disconnect from the signaling server and keep the direct Peer-to-Peer (P2P) connection open.
Using WebRTC in Pandemonium
---------------------
## Using WebRTC in Pandemonium
WebRTC is implemented in Pandemonium via two main classes `WebRTCPeerConnection` for more details.
@ -46,8 +41,7 @@ Warning:
using one-click deploy. Otherwise, network communication of any kind will be
blocked by Android.
Minimal connection example
^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Minimal connection example
This example will show you how to create a WebRTC connection between two peers in the same application.
This is not very useful in real life, but will give you a good overview of how a WebRTC connection is set up.
@ -104,8 +98,7 @@ This will print:
P2 received: Hi from P2
```
Local signaling example
^^^^^^^^^^^^^^^^^^^^^^^
#### Local signaling example
This example expands on the previous one, separating the peers in two different scenes, and using a `singleton ( doc_singletons_autoload )` as a signaling server.
@ -212,7 +205,6 @@ This will print something similar to this:
/root/main/@@2 received: Hi from /root/main/@@3
```
Remote signaling with WebSocket
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#### Remote signaling with WebSocket
A more advanced demo using WebSocket for signaling peers and `WebRTCMultiplayer` under `networking/webrtc_signaling`.

View File

@ -1,10 +1,8 @@
Audio buses
===========
# Audio buses
Introduction
------------
## Introduction
Pandemonium's audio processing code has been written with games in mind, with the aim
of achieving an optimal balance between performance and sound quality.
@ -14,8 +12,7 @@ number of effect processors can be added to each bus. Only the hardware of the
device running your game will limit the number of buses and effects that can be
used before performance starts to suffer.
Decibel scale
-------------
## Decibel scale
Pandemonium's sound interface is designed to meet the expectations of sound design
professionals. To this end, it primarily uses the decibel scale.
@ -44,8 +41,7 @@ For those unfamiliar with it, it can be explained with a few facts:
This can take a bit getting used to, but it's friendlier in the end
and will allow you to communicate better with audio professionals.
Audio buses
-----------
## Audio buses
Audio buses can be found in the bottom panel of the Pandemonium editor:
@ -69,8 +65,7 @@ to the left. This avoids infinite routing loops.
In the above image, the output of *Bus 2* has been routed to the *Master* bus.
Playback of audio through a bus
-------------------------------
## Playback of audio through a bus
To test passing audio to a bus, create an AudioStreamPlayer node, load an
AudioStream and select a target bus for playback:
@ -84,8 +79,7 @@ See also:
You may also be interested in reading about `doc_audio_streams` now.
Adding effects
--------------
## Adding effects
Audio buses can contain all sorts of effects. These effects modify the sound in
one way or another and are applied in order.
@ -95,15 +89,13 @@ one way or another and are applied in order.
Try them all out to get a sense of how they alter sound. Here follows a short
description of the available effects:
Amplify
~~~~~~~
### Amplify
Amplify changes the amplitude of the signal. Some care needs to be taken.
Setting the level too high can make the sound clip, which is usually
undesirable.
BandLimit and BandPass
~~~~~~~~~~~~~~~~~~~~~~
### BandLimit and BandPass
These are resonant filters which block frequencies around the *Cutoff* point.
BandPass can be used to simulate sound passing through an old telephone line or
@ -111,23 +103,20 @@ megaphone. Modulating the BandPass frequency can simulate the sound of a wah-wah
guitar pedal, think of the guitar in Jimi Hendrix's *Voodoo Child (Slight
Return)*.
Capture
~~~~~~~
### Capture
The Capture effect copies the audio frames of the audio bus that it is on into
an internal buffer. This can be used to capture data from the microphone
or to transmit audio over the network in real-time.
Chorus
~~~~~~
### Chorus
The Chorus effect duplicates the incoming audio, delays the duplicate slightly
and uses an LFO to continuously modulate the pitch of the duplicated signal
before mixing the duplicated signal(s) and the original together again. This
creates a shimmering effect and adds stereo width to the sound.
Compressor
~~~~~~~~~~
### Compressor
A dynamic range compressor automatically attenuates the level of the incoming
signal when its amplitude exceeds a certain threshold. The level of attenuation
@ -157,106 +146,88 @@ Note:
than a compressor.
Delay
~~~~~
### Delay
Adds an "echo" effect with a feedback loop. It can be used together
with *Reverb* to simulate wide rooms, canyons, etc. where sound bounces
are far apart.
Distortion
~~~~~~~~~~
### Distortion
Makes the sound distorted. Pandemonium offers several types of distortion: *overdrive*,
*tan* and *bit crushing*. Distortion can be used to simulate sound coming through
a low-quality speaker or device.
EQ
~~
### EQ
EQ is what all other equalizers inherit from. It can be extended with with Custom
scripts to create an equalizer with a custom number of bands.
EQ6, EQ10, EQ21
~~~~~~~~~~~~~~~
### EQ6, EQ10, EQ21
Pandemonium provides three equalizers with different numbers of bands. An equalizer on
the Master bus can be useful to cut frequencies that the device's speakers can't
reproduce well (e.g. a mobile phone's speakers won't reproduce bass content
well). The equalizer effect can be disabled when headphones are plugged in.
Filter
~~~~~~
### Filter
Filter is what all other filters inherit from and should not be used directly.
HighPassFilter
~~~~~~~~~~~~~~
### HighPassFilter
Cuts frequencies below a specific *Cutoff* frequency.
HighPassFilter is used to reduce the bass content of a
signal.
HighShelfFilter
~~~~~~~~~~~~~~~
### HighShelfFilter
Reduces all frequencies above a specific *Cutoff* frequency.
Limiter
~~~~~~~
### Limiter
A limiter is similar to a compressor, but it's less flexible and designed to
prevent a signal's amplitude exceeding a given dB threshold. Adding a limiter to
the Master bus is a safeguard against clipping.
LowPassFilter
~~~~~~~~~~~~~
### LowPassFilter
Cuts frequencies above a specific *Cutoff* frequency and can also resonate
(boost frequencies close to the *Cutoff* frequency). Low pass filters can be
used to simulate "muffled" sound. For instance, underwater sounds, sounds
blocked by walls, or distant sounds.
LowShelfFilter
~~~~~~~~~~~~~~
### LowShelfFilter
Reduces all frequencies below a specific *Cutoff* frequency.
NotchFilter
~~~~~~~~~~~
### NotchFilter
The opposite of the BandPassFilter, it removes a band of sound from the
frequency spectrum at a given *Cutoff* frequency.
Panner
~~~~~~
### Panner
The Panner allows the stereo balance of a signal to be adjusted between
the left and right channels (wear headphones to audition this effect).
Phaser
~~~~~~
### Phaser
It probably does not make much sense to explain that this effect is formed by
two signals being dephased and cancelling each other out. You can make a Darth
Vader voice with it, or jet-like sounds.
PitchShift
~~~~~~~~~~
### PitchShift
This effect allows the adjustment of the signal's pitch independently of its
speed. All frequencies can be increased/decreased with minimal effect on
transients. PitchShift can be useful to create unusually high or deep voices.
Record
~~~~~~
### Record
The Record effect allows the user to record sound from a microphone.
Reverb
~~~~~~
### Reverb
Reverb simulates rooms of different sizes. It has adjustable parameters that can
be tweaked to obtain the sound of a specific room. Reverb is commonly outputted
@ -264,31 +235,27 @@ from `Areas`
(see `Reverb buses ( doc_audio_streams_reverb_buses )`), or to apply
a "chamber" feel to all sounds.
SpectrumAnalyzer
~~~~~~~~~~~~~~~~
### SpectrumAnalyzer
This effect doesn't alter audio, instead, you add this effect to buses you want
a spectrum analysis of. This would typically be used for audio visualization. A
demo project using this can be found `here ( https://github.com/Relintai/pandemonium_engine-demo-projects/tree/master/audio/spectrum )`.
StereoEnhance
~~~~~~~~~~~~~
### StereoEnhance
This effect uses a few algorithms to enhance a signal's stereo spectrum.
Automatic bus disabling
-----------------------
## Automatic bus disabling
There is no need to disable buses manually when not in use. Pandemonium detects
that the bus has been silent for a few seconds and disables it (including
all effects).
.. figure:: img/audio_buses5.png)
![](img/audio_buses5.png)
Disabled buses have a blue VU meter instead of a red-green one.
Disabled buses have a blue VU meter instead of a red-green one.
Bus rearrangement
-----------------
## Bus rearrangement
Stream Players use bus names to identify a bus, which allows adding, removing
and moving buses around while the reference to them is kept. However, if a bus
@ -296,8 +263,7 @@ is renamed, the reference will be lost and the Stream Player will output
to Master. This system was chosen because rearranging buses is a more common
process than renaming them.
Default bus layout
------------------
## Default bus layout
The default bus layout is automatically saved to the
`res://default_bus_layout.tres` file. Custom bus arrangements can be saved

View File

@ -1,17 +1,14 @@
Audio streams
=============
# Audio streams
Introduction
------------
## Introduction
As you might have already read in `doc_audio_buses`, sound is sent to
each bus via an AudioStreamPlayer node. There are different kinds
of AudioStreamPlayers. Each one loads an AudioStream and plays it back.
AudioStream
-----------
## AudioStream
An audio stream is an abstract object that emits sound. The sound can come from
many places, but is most commonly loaded from the filesystem. Audio files can be
@ -23,16 +20,14 @@ This one makes a random adjustment to the sound's pitch every time it's
played back. This can be helpful for adding variation to sounds that are
played back often.
AudioStreamPlayer
-----------------
## AudioStreamPlayer
![](img/audio_stream_player.png)
This is the standard, non-positional stream player. It can play to any bus.
In 5.1 sound setups, it can send audio to stereo mix or front speakers.
AudioStreamPlayer2D
-------------------
## AudioStreamPlayer2D
![](img/audio_stream_2d.png)
@ -50,8 +45,7 @@ Note:
![](img/audio_stream_2d_area.png)
AudioStreamPlayer3D
-------------------
## AudioStreamPlayer3D
![](img/audio_stream_3d.png)
@ -67,8 +61,7 @@ Unlike for 2D, the 3D version of AudioStreamPlayer has a few more advanced optio
Reverb buses
~~~~~~~~~~~~
### Reverb buses
Pandemonium allows for 3D audio streams that enter a specific Area node to send dry
and wet audio to separate buses. This is useful when you have several reverb
@ -89,8 +82,7 @@ reverberation can be heard almost uniformly across the room even though the
source may be far away. Playing around with this parameter can simulate
that effect.
Doppler
~~~~~~~
### Doppler
When the relative velocity between an emitter and listener changes, this is
perceived as an increase or decrease in the pitch of the emitted sound.

View File

@ -1,10 +1,8 @@
Sync the gameplay with audio and music
=======================================
# Sync the gameplay with audio and music
Introduction
------------
## Introduction
In any application or game, sound and music playback will have a slight delay. For games, this delay is often so small that it is negligible. Sound effects will come out a few milliseconds after any play() function is called. For music this does not matter as in most games it does not interact with the gameplay.
@ -23,8 +21,7 @@ This is a common tradeoff, so Pandemonium ships with sensible defaults that shou
The problem, in the end, is not this slight delay but synchronizing graphics and audio for games that require it. Beginning with Pandemonium 3.2, some helpers were added to obtain more precise playback timing.
Using the system clock to sync
------------------------------
## Using the system clock to sync
As mentioned before, If you call `AudioStreamPlayer.play()( AudioStreamPlayer_method_play )`, sound will not begin immediately, but when the audio thread processes the next chunk.
@ -62,8 +59,7 @@ In the long run, though, as the sound hardware clock is never exactly in sync wi
For a rhythm game where a song begins and ends after a few minutes, this approach is fine (and it's the recommended approach). For a game where playback can last a much longer time, the game will eventually go out of sync and a different approach is needed.
Using the sound hardware clock to sync
--------------------------------------
## Using the sound hardware clock to sync
Using `AudioStreamPlayer.get_playback_position()( AudioStreamPlayer_method_get_playback_position )` to obtain the current position for the song sounds ideal, but it's not that useful as-is. This value will increment in chunks (every time the audio callback mixed a block of sound), so many calls can return the same value. Added to this, the value will be out of sync with the speakers too because of the previously mentioned reasons.

View File

@ -1,7 +1,6 @@
Recording with microphone
=========================
# Recording with microphone
Pandemonium supports in-game audio recording for Windows, macOS, Linux, Android and
iOS.
@ -12,8 +11,7 @@ support for this tutorial:
You will need to enable audio input in the project settings, or you'll just get empty audio files.
The structure of the demo
-------------------------
## The structure of the demo
The demo consists of a single scene. This scene includes two major parts: the
GUI and the audio.