Godot-Community-Games-Org / game1

First community game let's go!
GNU General Public License v3.0
22 stars 5 forks source link

Add styleguide to base repo #15

Open StrawberrySmoothieDev opened 2 weeks ago

StrawberrySmoothieDev commented 2 weeks ago

The styleguide vote has been posted and pinned for the last week or so, so I'm going to assume that people are clear on it. This is just setting in stone the best practices for the repo. I'll probably make some edits down the line, but this is a good starting point. Lmk if there's anything you want changed or added :3 (Also fixed some typos in .gitignore)

Yonodactyl commented 2 weeks ago

Kind of a nit-pick, but the styling on the markdown doesn't seem to look right; is this a github preview thing, or do we need to format the doc a bit? Besides that, I like it.

StrawberrySmoothieDev commented 2 weeks ago

Kind of a nit-pick, but the styling on the markdown doesn't seem to look right; is this a github preview thing, or do we need to format the doc a bit? Besides that, I like it.

What specifically? Looking at the commit view the markdown formatting isn't applied.

TheFlagCourier commented 2 weeks ago

The markdown syntax is malformed.

@StrawberrySmoothieDev : Something like this should work. If you have comment edit access, Here's a copy: STYLEGUIDE.md. Feel free to just rip it out of here and modify it further. I took some editorial liberties.


Godot Community Game Development Project Style Guide

[!WARNING] Please read through all of this before working on code. It saves everyone time. Thanks! :3

Comments & Documentation

GDScript Comment Markers

The following keywords are highlighted by the Godot editor when writing comments and are highlighted corresponding to a severity level.

These make them an excelent tool for communicating with other developers performing QA through the comments you write.

[!IMPORTANT] Please keep in mind that these are case-sensitive, and must be UPPERCASE for the editor to recognize them.

Severity Default Highlight Color KEYWORDS
Critical Red ALERT, ATTENTION, CAUTION, CRITICAL, DANGER, SECURITY
Warning Yellow BUG, DEPRECATED, FIXME, HACK, TASK, TBD, TODO, WARNING
Notice Green INFO, NOTE, NOTICE, TEST, TESTING

References

Naming Conventions

Generally, you should familiarize yourself with the following documents.

Tips

  1. Avoid abreviations and short-form acronyms, unless they are strictly standardized (such as UTC being Coordinated Universal Time.) It is better to name your functions and variables definitively in relation to their scope.

    • Example: Prefer to use var {entity}_health, or var hit_points, instead of var hp.
  2. Watch for cyclical references (ie when x depends on y while y also depends on x)

  3. Keep usage of while loops to a minimum to prevent stack overflows.

    • If you must use a while, either reconsider your approach or add a variable that limits the max iterations.
  4. Refactor with respect to the original contributors. Don't arbitrarily tear appart and rewrite someone else's code.

    • If something lacks documentation, is broken, or performs poorly then consider raising a Discussion or Issue around it before hammering away at someone else's contribution.
  5. Use the various PackedArrays whenever possible. This will save tons of memory in the long run.

[!CAUTION] There are differences between how PackedArrays are handled between GDScript and C#.

  1. A Dictionary IS PASSED BY REFERENCE, NOT COPY.

  2. Try not to transfer objects (scenes, resources, etc.) over functions. Not only is this just good practice, but will make multiplayer stupidly easy if we ever go that direction.

  3. If you can do it via composition, do it via composition.

  4. Make it simple.

  5. Don't be afraid to ask for help. We're a community for a reason :3

GDScript Example

class_name NameHere ##In PascelCase
extends Node ##What you want to extend
##Documentation for script goes here

const CONSTANT_VALUE: int = 0451 ##in MACRO_CASE
enum ENUMERATION {VALUE1,VALUE2} ##In MACRO_CASE

signal signal_name ##in snake_case
signal signal_with_arguments(arg1: int) ##Remember to type your arguments

@export var exported_var: Node ##(snake_case) Also type your variables PLEASE

var unexported_var: float = 1.0 ##If possible, always give a default value
var set_get_var: String = "This is a styleGuide!":
    set(val): ##Function that is called whenever the variable is set to something.
        set_get_var = val
        set_function(val)
    get: ##Function that is called whenever the var is retrieved. Whatever it returns is what is retrieved
        return set_get_var

@onready var onready_var: Node2D = $Root/onreadyNode2D ##Onreadies used for refs to nodes in scene.

func _init() -> void: ##Make sure to specify the return values of your functions. Done via "-> <TYPE_RETURNED>"
    print("Do your initialization code (code that should run when the node is INSTANTIATED NOT ADDED TO SCENE) here! This is rarely needed.")

func _ready() -> void: ##Do double hashes to document things. This comment is documentation for this function as it starts on the same line.
    print("Do your start code here!")
    signal_with_arguments.connect(_signal_call_func) ##Connecting signal to func

func initialize(variable_in: String, scene_root: Node) -> void: #user defined init function for dependency injection
    set_get_var = variable_in #Runs the set function defined above

func _unhandled_input(_event) -> void:
    pass #Do your input code here

func _physics_process(_delta) -> void:
    pass #Do your NON-FPS-DEPENDENT update logic here (runs every physics tick, or 60 times per second by default)

func _process(_delta) -> void:
    pass #Do your FPS-DEPENDENT update logic here (runs every frame)

func my_function() -> float: ##Basic function that returns a float.
    return 32.0

func my_function_with_args(argument1: int) -> String: ##Basic functions that takes in an argument and returns something dependant on it.
    match argument1:
        1:
            return "Case 1"
        2:
            return "Case 2"
        _: #If argument1 doesn't match any of the other cases, defaults to this one
            return "Default case"

func set_function(value: String) -> void: ##Called in the above setter for set_get_var
    print("set_get_var was set to "+value)

func _my_private_function() -> void: ##Cannot be accessed outside of this script.
    print("This function cannot be accessed outside of this script")

func _signal_call_func(value_in: int): ##Function called by signal. Generally these should be private, however there are _rare_ exceptions.
    print(str(value_in))

class MyClass: ##Kinda like a struct. Can be instanced like an object.
    var foo: int = 0
    func _init():
        print("new MyClass instantiated!")
    static func constructor(value: int): ##Java-esque Constructor. Not required, but good practice.
        var inst: MyClass  = MyClass.new()
        inst.foo = value
        return inst
StrawberrySmoothieDev commented 2 weeks ago

Holy shit that's beautiful. Well done! I'll make some small edits but overall it looks amazing. I've never really touched markdown outside of some basic personal projects and it's crazy to see what it can do.