Skip to content

Contribution guide

HungryProton edited this page May 4, 2021 · 5 revisions

Style

  • Prefer clarity above all

    • Just because something can be written in a single line doesn't mean it's easier to understand.
    • Performance gains from these kinds of things are basically non-existent and are not a valid excuse.
  • The code should follow these guidelines which are adapted from the official style guide.

  • Important points from the guide (but not limited to):

    • Two line breaks between functions
    • Use typing when possible
    • Respect this spacing convention for the : and := operator.
      • var myvar: float
      • var myvar := 1.0
  • Avoid trailing spaces

    • If you're using the Godot code editor, go to your Editor Settings under Text Editor > Files enable the Trim Trailing Whitespace On Save option. image
  • Use relative paths

    • Do not hard code the full add-on path in the script files.
    • This makes it possible to use the add-on even if the user renamed the folder (except for the example scenes).

Plugin structure

Feel free to open an issue if you need more information about this part.

Responsibility graph

scatter

Writing new modifiers

Modifiers can be found in the src\modifiers folder. They all inherit from base_modifier.gd.

Simple example

tool
extends "base_modifier.gd"


export var user_value := 1.0 # This will automatically appear in the modifier UI


func _init() -> void:
	display_name = "My Modifier"  # Inherited from the base class


# Called from the parent class, your logic goes here
func _process_transforms(transforms, _global_seed : int) -> void:
       if user_value == 0.0:
             warning += "Value must be different than zero. \n"
             return

	for t in transforms.list:
		t.origin /= user_value

Mandatory steps

  • Use the tool keyword.
  • Extends from .base_modifier.gd.
  • Change the display_name in _init
  • Override the _process_transforms method. This is called from the parent class to run your custom logic.

Export warning

When you export a variable from a Modifier, it's user interface will adapt to display them to the user. However, not everything is supported.

  • The following types are supported:

    • bool
    • int
    • float
    • string
    • vector3
    • vector2
  • int and float support the range hints

    • export(float, 0.0, 1.0) will constrain the value between 0 and 1. int also support this.
  • string supports the following hints:

    • export(String, "File") - Shows a dialog file
    • export(String, "Texture") - Same as File, but displays a preview of the picture
    • export(String, "Curve") - Workaround because exporting a Curve resource directly doesn't work.
      • You can use the string_to_curve method in the src/common/util.gd file to convert it to a Curve object.

Custom logic

Overriding _process_transform

This method takes two parameters:

  • global_seed which is set from the Scatter node in the inspector.
  • transforms: An object that holds all the transforms. /src/core/transforms.gd
    • list - Array of all the Transform objects after they went through the previous modifiers.
    • path - The Scatter node this modifier is attached to.
    • Three extra functions are provided to easily change how many transforms are in the list:
      • add(int) - Add x transforms at the end of the list
      • remove(int) - Remove x transforms at the end of the list
      • **resize(int) - Add or remove enough transforms to match the new size
    • You can also directly manipulate the list array to your liking.

Display warnings

Inherited from the base class, the warning property string stores a message to be displayed to the user. The Warning icon doesn't appear if this string is empty. When you want to show a message, do not override the content but simply add it at the end, unless you know exactly what you're doing. Once _process_trasnforms is done, the parent class will automatically update the modifier UI if needed.

Using ScatterPath

ScatterPath inherits from Path (see the diagram above). All the methods from the Path class are available.

Properties

  • polygon: PolygonPathFinder
    • A 2D polygon made from the 3D curve, projected on the XZ axis.
    • Mostly used to know if a 3D point is inside the 3D curve.
  • baked_points : PoolVector3Array
    • The points in 3D space sampled along the 3D curve, used to create the polygon.
  • size : Vector3
    • How large is the curve bounding box.
  • center : Vector3
    • the bounding box center.

Methods

  • is_point_inside(point: Vector3)
    • Returns true is a point is inside the 2D projected curve, false otherwise
  • distance_from_point(point: Vector3, ignore_height := false)
    • Returns the closest distance between any part of the curve and the given point.
    • If ignore_height is true, the calculation is done in the XZ plane only.
  • get_pos_and_normal(offset: float)
    • Samples the 3D curve local position at offset and its normal
    • Returns an array formatted this way: [position, normal]