Godot Lesson 3: Entity Class

Summary

This lesson moves a lot of the player movement loops into a separate entity class to be used my enemies and NPCs as well.

Prerequisites

  • A moving player with animations (Lessons 1 and 2)

Video

Code

Repository: https://github.com/los-alamos-steam-lab/godot-tutorial/tree/3-entity-class

Directions Code

Major Changes from the Video:

  • Relies on built in Vector2 enums instead of declaring dir.UP and so forth

  • class_name at the top makes this callable from other functions

class_name directions
extends Node

# We didn't add the constants here because they are built into
# Vector2 after 3.1

# return a random direction
func rand():
    var d = randi() % 4
    match d:
        0:
            return Vector2.LEFT
        1:
            return Vector2.RIGHT
        2:
            return Vector2.UP
        3:
            return Vector2.DOWN

Entity Code

Major Changes from the Video:

  • dir isn’t an autoload, since we didn’t include the vector directions in it

  • class_name at the top makes this callable by other functions

  • const is switched to var since 3.1 does not allow for child scripts to update const values

  • We added a _ready function because we need it in the child scripts

class_name entity
extends KinematicBody2D

# we put this here instead of autoloading it
# nothing wrong with autoload, but I prefer things in the code
var dir = directions.new()

# MOVEMENT
var movedir = Vector2.ZERO
var spritedir = "down"

var SPEED = 0

# Putting this here so that we can setup future calls from the
# child scripts and not have them fail
func _ready():
    pass

func movement_loop():
    # .normalized makes it so that diagonal movement is
    # the same length as 4-driectional movement
    var motion = movedir.normalized() * SPEED

    # move_and_slide takes care of collisions and has you slide
    # along walls that are blocking your path
    move_and_slide(motion, Vector2.ZERO)

func spritedir_loop():
    match movedir:
        Vector2.LEFT:
            spritedir = "left"
        Vector2.RIGHT:
            spritedir = "right"
        Vector2.UP:
            spritedir = "up"
        Vector2.DOWN:
            spritedir = "down"

# This changes our player animation.  "animation" is a string
# of the sort "idle", "push", or "walk"
func anim_switch(animation):
    var newanim = str(animation, spritedir)
    if $anim.current_animation != newanim:
        $anim.play(newanim)

Player Code

Major Changes from the Video:

  • Makes use of entity class by just extending entity instead of a file path

  • The _ready func is used to set SPEED and other “constants”

  • Still prioritizing idle

  • Using built in Vector2 enums

extends entity

# ready function lets us set "constants" when the file loads
func _ready():
    SPEED = 70

# _physics_process is called by the game engine
func _physics_process(delta):
    controls_loop()
    movement_loop()
    spritedir_loop()

    # We're setting our animation here.  I've replaced Vector2(0,-1)
    # with Vector2.UP for readability, and so forth.  These are new to godot 3.1
    # I've also changed the order of the if statement to prioritize being
    # idle if movedir is zero and created a single (very long) if statement
    # for testing the push animation.

    if movedir == Vector2.ZERO:
        anim_switch("idle")
    elif is_on_wall():
        if (spritedir == "left" and test_move(transform, Vector2.LEFT))\
        or (spritedir == "right" and test_move(transform, Vector2.RIGHT))\
        or (spritedir == "up" and test_move(transform, Vector2.UP))\
        or (spritedir == "down" and test_move(transform, Vector2.DOWN)):
            anim_switch("push")
    else:
        anim_switch("walk")



# controls_loop looks for player input
func controls_loop():
    var LEFT                = Input.is_action_pressed("ui_left")
    var RIGHT       = Input.is_action_pressed("ui_right")
    var UP          = Input.is_action_pressed("ui_up")
    var DOWN                = Input.is_action_pressed("ui_down")

    # By adding our values together, we make it so that one key
    # stroke does not take precidence over another, i.e. pushing
    # left and right keys at the same time
    movedir.x = -int(LEFT) + int(RIGHT)
    movedir.y = -int(UP) + int(DOWN)

Stalfos Code

Major Changes from the Video:

  • Makes use of entity class by just extending entity instead of a file path

  • The _ready func is used to set SPEED and other “constants”

extends entity

var movetimer_length = 15
var movetimer = 0

# ready function lets us set "constants" and perform
# other actions when the file loads
func _ready():
    SPEED = 40
    $anim.play("default")
    movedir = dir.rand()

func _physics_process(delta):
    movement_loop()

    # count down the movetimer every tick
    if movetimer > 0:
        movetimer -= 1

    # if the movetime reaches zero or the stalfos is on a wall
    # change direction and reset the timer
    if movetimer == 0 || is_on_wall():
        movedir = dir.rand()
        movetimer = movetimer_length