Skip to main content

GoDot (Dont Touch Spikes)


Last time i basically explained what it felt like using the GoDot engine gui while i was creating the simple game of Dont' touch the spikes. In this post i will cover how i went about setting up the scene and issues i faced.

The Scene Setup

Coming from cocos2d-x i'm used to Layers, Scenes as container objects to setup a gameplay scene. In GoDot however i was unable to find any such nodes. Instead i just had to use a Node2D. This is pretty much the starting point of the game scene structure.

I then added a RigidBody2D named it Player. This was going to be the physics body for dealing with user inputs etc. I then added a Sprite to the RigidBody. If you have used unity you would start wondering where do i add the collisionbox component to the rigid body. Simple answer is .. you dont. You actually have to add a node called CollisionShape2D as a child to the RigidBody2D to be able to detect physics collisions in the simulations. So the Scene tree looks like this:
Player Setup
There are a bunch of things we need to start setting in properties panel corresponding to the Payer Object (RigidBody2D object) to be able to get callbacks for collisions when this body collides with static / kinetic physics bodies.
Options to set on RigidBody2D
The Mode is set to Character so that the rigidbody doesn't rotate on collision. It will just use the velocity and not the angular velocity. The Contacts Report and Contact Monitor ensure that we are able to get callbacks for collisions with kinetic objects and the static objects. There is a warning about this being performance drain but its' required in this case. Now let's get to adding some game logic / input handling with

Once this is done, I setup static objects for top wall, bottom wall, left wall and then the right wall. These help us keep the object inside. The spikes that are in game are added as KineticBody2D. The spikes setup is a little complicated, ill' cover it in detail when i cover the animation. The one important thing that we do for spikes is set their group name. This will help us in the collision callback.
Full Scene Graph
Roughly speaking each wall has spikes associated with it. The spikes on the leftWall and rightWall have the spikes that animate and so they look a little more complex than the Floor and Roof objects. The one additional feature i used for handling spikes is Group Name this will enable us handle the collisions easily across multiple objects.

Scripting



Adding a script to a Node is Easy
With a node selected, click on the Edit/Create the node Script button in the scene graph panel. Once you provide the details like filename, file path of the script, you will be taken to the scripting window.
Scripting Window with Stuff filled in
The above screenshot is way ahead in the development.. when you create a new script you will just see something like this
       
#the script associated with a RigidBody2D node.

extends RigidBody2D

# member variables here, example:
# var a=2
# var b="textvar"

func _ready():
    #initialization happens here
    pass


As you can see the _ready function is the initialization function that is created by default. its' like the OnStart function in unity behavior scripts. To get callbacks on each rendered frame i.e OnUpdate function from unity you have to call set_process(true) this will make sure that you get calls to a function named func _process(delta):  this will be the equivalent of the update functions in other engines like cocos2d-x or unity.
#the script associated with a RigidBody2D node.

extends RigidBody2D

# member variables here, example:
# var a=2
# var b="textvar"

func _ready():
    #initialization happens here
    set_process(true) 
    set_fixed_process(true) #callback on each physics update.
    set_process_input(true) #enables input handling
    pass

func _process(delta):
    #callback on each frame render
    pass

func _fixed_process(delta):
    #called after each physics update cycle.
    pass

func _input(event):
    #called on any input event.
    pass


Now that we have access to the update cycles and the input events, lets' have a look at how we handle the physics collision callbacks. This is done through node connections. It's basically a observer pattern implementation similar to the one seen in Toolkits like Qt.
Node Connections Button

There are a bunch of predefined signals for each node type in GoDot. You will be able to see them listed in the connections window when you click on the connections button in the scene graph panel.

Signal List
This window shows all the signals that the selected node can emit, once you click connect you are taken to another popup shown below.

Callback selection window
Here you select the body that will receive the signal and the function for callback when the signal happens. If you leave it default settings, the callback function will be automatically added to the script associated with the selected node. So now the modified script looks like this
#the script associated with a RigidBody2D node.

extends RigidBody2D

# member variables here, example:
# var a=2
# var b="textvar"

func _ready():
    #initialization happens here
    set_process(true) 
    set_fixed_process(true) #callback on each physics update.
    set_process_input(true) #enables input handling
    pass

func _process(delta):
    #callback on each frame render
    pass

func _fixed_process(delta):
    #called after each physics update cycle.
    pass

func _input(event):
    #called on any input event.
    pass

func _on_Player_body_enter( body ):
    #your implementation goes here. this is called whenever 
    #Player object collides with another object.
    pass

In this case i selected the body_enter(Object body)  signal from the Player node in the scene and connected it to the same node so i can handle the collision response in the same script.
This says that the signal will also emit an object of type body which is basically the handle to the object that is collided with.


Custom Signals

As i mentioned earlier, the signals / connection mechanism is very useful for communicating between multiple game objects. In this game i used it to notify the walls when ever there is a change in score to change difficulty. This enabled me to decouple the difficulty of spikes from the player handling / game handling code.
#the script associated with a RigidBody2D node.

extends RigidBody2D

# member variables here, example:
# var a=2
# var b="textvar"
var gameScore = 0

func _ready():
    ....
    #setting up signals supported by the object.
    var argument = { "score" : TYPE_INT }
    var ArgumentArray = Array()
    ArgumentArray.append(argument)
    #add the newly created signal to the list
    add_user_signal("ScoreChanged", ArgumentArray)
 
    #signal handling for bg color change based on score.
    connect("ScoreChanged", get_node("../backgroundColor"), "updateColor")

func _on_Player_body_enter( body ):
    #your implementation goes here. this is called whenever
    #Player object collides with another object.
    var name = body.get_name()
    if name == "LeftWall":
        gameScore += 1
        #trigger the signal that score has changed and send parameter.
        emit_signal("ScoreChanged", gameScore)
    elif name == "RightWall":
        print("Turn Left")
        gameScore += 1
        emit_signal("ScoreChanged", gameScore)

With all these things in place i was able to quickly develop the Dont' touch Spikes game in about two days' time. Most of the time i was just searching through the documentation and tutorials trying to understand the basics.

I've uploaded the code to github so you can directly download and try it out.
https://github.com/vkbsb/godot_dts



Comments

Popular posts from this blog

Vehicle Physics (Godot 2D)

I've always been fascinated with the vehicle physics used in games. I played so many racing games / the hill climb games and every single time i would wonder wow that must be really hard to do. Thanks to the new generation of game development tools, developing physics based games has become almost a second nature to most people. I didn't want to be left out so i gave it a shot.. I tried setting up vehicle physics in GoDot Engine for a 2D vehicle. Here is what the vehicle scene looks like.. 2D vehicle setup in GoDot As you can see the body collision shape is not right but the rest of the stuff just works. The idea is simple think of what parts move along with the body vs what doesn't. I was kinda stuck setting up the pinJoint2D in GoDot, it actually clearly takes two nodes under the properties. This makes sure that the wheels are hinged to the DampingSpring2D. The Damping Spring2D takes two physics bodies(Body and the PinJoint2D) and makes it work like shock ab

Epic Games Store on Steam Deck

EGS ( Epic Games Store ) like it or hate it, has been giving away free games and if you like free games you would have picked up atleast a couple of them. So given that some of those games are Deck Verified / Playable, its fair to assume you would like to install the EGS on the Deck.  Installing EGS on Steam Deck Switch to Desktop Mode on your Steam Deck Download the EGS installer for windows from the Epic Store website: https://store.epicgames.com/en-US/download (using your web browser of choice)      Open Steam in the desktop mode and add the installer as a non-steam game                                In the browse window, switch from .desktop files to All files. Select EpicInstaller-xxx.msi and add it to steam library. Find EpicInstaller in your steam library and open its' properties by hitting the "Gear" icon on the right side of game details page. Set the proton compatibility to latest one. Now hit the play button and go through the install screens of EGS.  Once t

Flash animations in GoDot Engine

If you have not heard about GoDot game engine,.. you should check it out right away.. godotengine.org Last time, i wrote a blog post about my experience making a simple physics game to GoDot Engine. Though there are a bunch of free options announced during the GDC this year, i thought ill' contribute to the engine. The one piece that is most important for game dev is the pipeline for the engine. One of the most common tools used for 2D animations is Flash. I have been using a library called Super Animation for almost all the games we've made for android at TMG. It's  a  free tool which lets you convert swf files to .sam files. This file can then be loaded in Cocos2Dx using the Open source loader library  https://github.com/raymondlu/super-animation-samples I thought it would be a good idea to port this cpp library to GoDot so that i understand how to write custom modules for the engine. This is the video of the module in action. I have exposed