cgCody's Devlog

Preamble:

Introduction

Hi! I’m new to Godot. I’ve about two decades of non-interactive design experience under my belt and a couple years in game design, but not a ton of programming experience beyond the occasional small script. I’ve had a game concept in the back of my mind for a year now and it’s time I sit down and do something about it. I’ll reveal details as I dive deeper into the project. For now, this will serve as a place for me to document my progress as I experiment with Godot. I expect this to be a very long term process.

Currently Working On:

I’m currently prototyping out a procedural(ish) locomotion system based on this GDC Talk I watched many years ago. I thought this would be a fun diving off point to learning Godot.

Long Term Goal:

The plan down the road is to make a small sci-fi shooter with a tight gameplay loop, and simple survival mechanics. I’ve got some unique elements that will be central to the loop, but I’ll wait to reveal those at a later time.


9 Likes

Hello @cgcody!
Welcome to this cool little forum!
The game mecanic looks awesome! Is it a kind of skiing game?

4 Likes

Hi and thank you! Eventually I’ll add in a proper character with run/walk animations, so no, not skiing. But I can see what you mean. haha

I’m actually interested in exploring some procedural animation techniques from an old GDC talk (I’m sure many know the one I’m referring to.) The procedural lean is the first step in that direction.

1 Like

It’s more like ice skating.

I’d like to draw your attention to a tutorial on character creation and animation. You might find it useful.

1 Like

Thanks! I’ll give it a look when I get to the point of setting up character animation.

I went a little while without touching this project, choosing instead to work on several other mini studies and learning various parts of Godot.

I’ve now created a basic test character rig, and implemented IK and surface orientation for the feet. Now it looks even more like skiing/ice skating, but that’s still not the plan. :grin:
I also added a sort of fake suspension to the body, so that there’s a bit of delay when the feet move in elevation. From that I get some jump recovery movement as a free bonus.

Next comes the fun part. pseudo-procedural walking and running!

4 Likes

You are cooking something awesome!

1 Like

Might be of interest to you:

3 Likes

I think it’s a little too early to say that. Maybe, maybe not. :slight_smile:

It’s cool, but sort of the opposite direction I’m going. I’m basing this study on a GDC talk I watched years ago and always wanted to try. I’m not even certain I plan to use it for this project, but I thought it’d be a fun way to learn and familiarize myself with Godot.

1 Like

Nahh, it is awesome, the control is just juicy.

1 Like

Initially, I set up the foot-to-ground orientation by having the foot bones copy the orientation of the IK targets, and adjusting those targets to match the ground. But I could see how this would make adding additional corrective layers a bit awkward. So I set out to manipulate the bones directly, giving me a “ground truth” (pun intended) of the bone pose state.

1 Like

its_working.gif!!!

I’m using a movement phase to cycle between 4 poses; The so-called “stride wheel”.
Now that I’ve laid all the ground work (haha another pun), this part was really simple to drop in and just have it work. Fun seeing it come together.

Now before I dive deeper into blending poses, I think I’ll take a step back and flesh out a proper movement state machine. Right now, I just have a basic movement component, but I want to try out some ideas that @dragonforge-dev gave me a while back.

3 Likes

Just sort of thinking out loud here…
I’m not entirely convinced that this stride wheel concept has any meaningful advantage. I eventually plan to implement a blend space for strafing/back peddling, but at that point, I have to wonder if I’m just doing traditional locomotion with extra steps.

I think I just need to change my own perception of what I’m making. David Rosin’s original GDC talk spoke of it as procedural locomotion. But in today’s game design speak, what I’m doing is functionally just modern day stride warping. I guess the one advantage is that I’ll be in direct control of the locomotion cycle, vs warping baked animation. So in theory it’s more responsive. I also have some ideas about blending between multiple pose variations for on-the fly walk/run style editing. Perhaps even a parametric editor tool that would allow me to author a walk/run style and bake the final blend to keyframes. Who knows..

Either way, I’ll continue on. It’s a fun learning experience. I just felt like rambling to myself out loud a bit.

Holy crap. I’m working on a subsystem that is almost exactly what you’re doing.
I watched the same procedural animation presentation and i am currently writing my own biped dynamic poser system. On principle i’m doing whatever the talk described, however i am trying to take it to a more reactive and customizable direction. Right now i got:

  • Per-character walking poses.
  • Walking pose progression based on ground-zero distance (distance from footstep impact point).
  • Auto-configuration:
    • IK nodes, poles and targets attach to leg bones by bone-name (as in: “UpperLeg_l”, “Foot_l”)
    • Walking cycle playback speed scaled by character leg joint lengths (longer legs rotate slower for the same linear speed)

Show me some code, i’ll share some of mine too:

# ensure a clean state on the skeleton before stepping with left foot
func start_walking_step_left(delta:float)-> Callable:
	wsl_ground_zero = origin.global_position
	_release_IK_right()
	_grab_IK_left(origin.transform * skeleton.get_bone_global_pose(lf).origin + Vector3(0,-.1,0) )
	computed_pose.bone_poses = walk_pose_step_left.bone_poses.duplicate()
	#IK_controller
	return walking_step_left(delta)

# logic to compute pose during walking left-step
func walking_step_left(delta:float) -> Callable:
    # interpolate using distance, rather than time (no delta)
	var distance_to_origin = (wsl_ground_zero - origin.global_position).length()

    # footsteps end whenever travel distance is somewhere around leg-length
	var footstep_progress = distance_to_origin / (leg_length)
	if footstep_progress >= walking_wideness:
		return start_walking_step_right

    # interpolate some pose between step left and step right
	tween_bone_set([rt,rl,rf], walk_pose_step_left, walk_pose_step_right, footstep_progress)
	return walking_step_left
2 Likes

Nice! So it looks like you’re creating a traditional procedural system rather than using David Rosen’s stride wheel concept to blend between keyframed poses.

I’ve decided to keep things simple. I’ll author the look of the walk/run by adjusting the pre defined poses. I’ll not show all my code as it’s messy and in a state of flux, but I’m happy to share the stride wheel:

## 0 - 1 phase based on distance travelled - Used for stride pose swapping
func _update_stride_phase(delta: float) -> void:
	if character.speed_zx < idle_threshold:
		if animation_player.current_animation != idle_pose:
			animation_player.play(idle_pose)
		return
	
	var walk_run_blend: float = inverse_lerp(walk_speed, run_speed, character.speed_zx)
	var stride_length: float = lerpf(walk_stride_length, run_stride_length, walk_run_blend)
	
	# The stride wheel - Loops 0 to 1 every "stride_length" traveled
	stride_phase += character.speed_zx * delta / stride_length
	stride_phase = wrapf(stride_phase, 0.0, 1.0)
	
	current_pose_idx = int(stride_phase * 4.0)
	current_pose_idx = clampi(current_pose_idx, 0, 3)
	current_pose = current_pose_idx as GaitPose
	
	# Change pose
	if current_pose != previous_pose:
		_apply_gait_pose(current_pose, walk_run_blend)
		previous_pose = current_pose


## Change the character pose based on the currently active pose enum
## TODO Swap this out for pose blending
func _apply_gait_pose(pose: GaitPose, blend: float) -> void:
	var walk_pose: StringName
	var run_pose: StringName
	
	match pose:
		GaitPose.LEFT_PASS:
			walk_pose = &"proto_man_anim/walk_fwd_left_pass"
			run_pose = &"proto_man_anim/jog_fwd_left_pass"
		GaitPose.LEFT_STEP:
			walk_pose = &"proto_man_anim/walk_fwd_left_step"
			run_pose = &"proto_man_anim/jog_fwd_left_step"
		GaitPose.RIGHT_PASS:
			walk_pose = &"proto_man_anim/walk_fwd_right_pass"
			run_pose = &"proto_man_anim/jog_fwd_right_pass"
		GaitPose.RIGHT_STEP:
			walk_pose = &"proto_man_anim/walk_fwd_right_step"
			run_pose = &"proto_man_anim/jog_fwd_right_step"
	
	if character.is_on_floor() and character.speed_zx > idle_threshold:
		if blend < 0.5:
			animation_player.play(walk_pose)
		else:
			animation_player.play(run_pose)
	else:
		animation_player.play(idle_pose)
1 Like