• Andrew Jonhardt

Aaaannnndddd moving on

Before last weekend, I had decided I needed a break from board and card game design. As you can probably guess, I proceeded to design the makings of a new card game. I'm not going to go into alot of detail about this new project yet, because I'm still not confident in my ability to accurately judge a board game idea before it's received some real testing. Still, I feel like the design is already stronger for my experiences with FTR/Redline/Psychic Racers, and I'm very hopeful.

Speaking of things that occurred recently, I got the FTR prototype back in the mail today:

I have no plans for the cards for now, other than to set them aside somewhere, but I felt like sharing them anyway.

On the Godot front, I'm annoyed to say I'm still not done with the Ghost Text game. I was compelled to rethink my design of the enemies, as the original design was rushed anyway.

Originally, there were only 3 foes: Bubble (moves in straight lines and bounces around), Hand (launches itself at the player's last position in a straight line), and Mirror (mirrors the player's movements). Now, if I say there was never a plan for any walls or floor, some of the design issues should make themselves clear. Hand was never a problem; it just launches itself like a missile in 1 direction and doesn't stop. Mirror, however, in mimicking the player in an otherwise empty space, would never actually touch the player. And, with Bubble, what's the point if bouncing if you've got nothing to bounce off of?

So, wondering exactly where my head was at when I designed these foes originally, I redesigned them again and added a 4th: the Rock. The Rock doesn't do anything on it's own, but serves as a static obstacle to impede and protect the player.

The Bubble now moves in a straight line. I originally learned how to set up this kind of movement system using a Godot animation, and I was extremely dissatisfied with this approach. Animations can be used to move objects, but require you to lock down the distance traveled and the duration of the travel for every animation. This is too much work, so I figured out how to move in straight lines in a script for greater freedom in movement planning:

extends "res://Scripts/Destory.gd"
export var move_horizontal = false
export var move_vertical = false
export var wait_time = 1

The above values are exported to allow for free changing in the editor view. This also helps with instancing, allowing for different values for every instance. I had to make Boolean values for when I want a Bubble to move horizontally vs vertically, because (unlike with some other engines) simply rotating an imported node doesn't change its movement on the X/Y axis. I assume this means I'm using global position by default, and I don't actually care enough to try and change this behavior. I just have a switch to activate movement in the direction I want.

The wait_time variable is tied to a timer, and allows for extending the time a given Bubble will move in both directions. For more control over how long the Bubble moves in a given direction, all I'd need is more timers.

var travel = 1
func _ready():

The _ready(): function in this script simply sets the starting time for the timer that runs continuously in the background.

func _process(delta):
if move_horizontal:
var motion = travel * (SPEED/2) * delta
position.x += motion
if move_vertical:
var motion = travel * (SPEED/2) * delta
position.y += motion

The _process(delta) function is where all the movement is being handled. The Bubble is an Area2D node, instead of a Kinematic or Rigidbody, and thus moves outside of Godot's built-in physics system. Operations that move Area2Ds have to occur under _process(delta) instead of _physics_process(delta), as far as I'm aware.

The _process(delta) function in this case is altering the Bubble's position. It checks whether the switch for moving horizontally or vertically is true, then alters Bubble's position by travel, set to 1, multiplied by half of the SPEED constant all foes are set to, multiplied again by delta, delta being some constant that ensures everything executes at the same time. I don't understand exactly what delta is, but I do know it's supposed to ensure that your game doesn't go too fast or too slow due to hardware differences.

func _on_DirectionChange_timeout():
if travel != -travel:
travel = -travel
travel = abs(travel)

The _on_DirectionChange_timeout(): function is where the travel value (set in the above script to alternate between1 and -1) is modified to allow travel up (negative direction in Godot) or down (positive direction in Godot) on a given axis.

Mirror has received a complete re-design. The only things it does now are:

  • Wait for the player to come into "view" (be within a certain distance).

  • Unceasingly pursue the player once in range.

Here's the code for it:

extends "res://Scripts/Destory.gd"
export var distant_check = 0
var player = Global.player_pos
var motion
var distance
var timeout = false
func _process(delta):
var self_pos = self.get_global_position()
distance = self_pos.distance_to(Global.Player.get_global_position())
if distance <= distant_check:
if timeout == true:
if player.distance_to(self.position) > 0:
var direction = (player - position).normalized()
var motion = direction * SPEED * delta
position += motion
func _on_Wait_timeout():
timeout = true

The Mirror script is actually simpler than Bubble's. The Mirror tracks the player's current position through a value that gets fed to it via a separate script. In this case, the value is actually extracted by 1 script, fed to a Global script, and then fed again to all foes that need player positioning information. It's kinda ugly, but I haven't found a way to do it better due to how the player and the Mirror are instanced into a level versus being a part of a level scene.

The rest of the script is all about throwing the Mirror at the player every scene until one or both are dead.

I don't actually remember what that last timer does, which is a failure on my part. I became very frustrated and impatient this last weekend, and I let it affect my documentation. The timer may actually do nothing, because the value is set to 1 and the timer is set to execute exactly 1 time (timers are typically the most useful when they repeat in Godot). I'm not going to mess with it.

My plan is to finish Ghost Text this weekend. The project was spawned from a jam I attempted with the Love2D engine, and my overall passion for it is waning. I had originally planned to attempt a score system. However, I don't believe a scoring system would teach me anything I don't know already, so I've cut the idea.

The final version of Ghost Text will have a better name, use basic sprites, possess some light animations, not use any sounds or music, feature 3 levels (an easy level, a medium difficulty level, and a hard level), feature a start menu, and that's about it. As things stand, I've got sprites, animations, level design, and level transitions left to finalize. The main character, or ghost, in addition to all of the foes, the UI, and the start menu, have been completed.

The itch to develop a commercial video game has been growing stronger recently. However, I will not give in yet. There are still ideas I'd prefer to prototype.

My next prototype, A Beginning for Pointman, will feature sounds, possibly music, and a greater action focus. I'm going to give myself the months of August and September to work on it, with October as a backup. If Pointman extends into November, I'll cut out something resembling a game and put it out into the world whether it's completely ready or not. All the more reason to do as much as I can in August and September, right?

Whether all goes according to plan or not, I'm going to finish out this year with jams, board game work, tutorials, and general attempts to get all my ducks in a row. My gut tells me the best time to start on a commercial project would be after I file my taxes, but I haven't talked anything over officially with any accountants or lawyers yet.

Look at me and my long term plans. Let me know if you like the new format I'm using to present my code, or if you preferred the old format. I haven't found a way to present code cleanly through the tools available as yet, and I'm planning to continue looking into it as a low priority.

© 2023 by Andrew Jonhardt. Proudly created with Wix.com