Mini game projects to get better understanding of Vectors

Just looking for some YouTube maybe course or documentation where is demonstrated how use Vector4 , Vector 3 inheritance to achieve independence from global coordinate system .

Was trying to make Kula World clone , but unfortunately for some things I never done before I couldn’t find how to do it in code or what order of pivots should use to achieve desired mechanics .

Yes I looked into docs , there is a two pages about projection .

I tried Claude but this seem to giving some over complicated info which I got feeling get be achieved easier .

Searching online I found some clone’s , but none with published code in Godot for study ( one on Reddit but it’s only video )

Mechanics are interesting because it looks like the world in game itself is rotated instead of camera nor player .

Kula World in fact looks like the only thing that rotates is the camera. The movement basis is constructed from the camera basis.

The most important concept to understand regarding 3D transformations is the basis. There are many videos of varying quality and complexity that touch upon this. Recommending anything specific is hard as it may not fit your learning style.

This video seems quite pragmatic. It looks at 3D transforms in Godot context. Maybe you can start there:

1 Like

Like normally I do follow GameDev.TV Acerola Zenva StayHomeDev GDQuest ( free ones ) , Brackeys I saw a few concepts explained closest one was camera rotation with two pivots but nothing a much about how gridmap and vector4 to make projection to something like that .

You don’t really need Vector4 for things like this. If you’re serious about learning this, best to find an introductory course on linear algebra. It’s a branch of math that deals with vector spaces and matrices.

3 Likes

Well it’s challenge :sign_of_the_horns:, I look into more math . Lots of people recommend Brilliant for learning .

By any chance do you know if some shader could reveal raw mesh of this Kula World to confirm if is really camera or it’s smart vertices manipulation .

It’s camera. Doing it like that is the simplest way. “Smart” vertex manipulation would just complicate things. It wouldn’t make much sense using a more complicated approach.

It really is simple. The ball can move in a regular 3D grid in all 6 directions and camera just rotates in 90 degree increments. The orientation of the camera defines what is currently “horizontal” and what is “up”. This game is a textbook example of basis manipulation.

1 Like

Thank you , I probably watched too much Crah Bandicoot breakdowns from PS1 suspecting some clever tricks rom developers .

Well it is somewhat clever. If you’re not fully familiar with how 3D transformations work, you still might think some vertex shader black magic is taking place :wink:

Well it tricks me and like to get to core of it , if I find what shader was used to check quads of crash I try it just in case how they did ending scene

Shaders are purely visual. They can’t really “check” for anything.

This is just (practically turn based) movement inside 3d grid and some “clever” usage of basis/orientation.

1 Like

, I meant only by it render out wireframe but yeah you got the point it’s visual , i watched explanation of Transform 3d and it start making sense can user basis and not euler , but need to more dive into it .


For old Crash I saw someone made triangulation shader which could check what is being render out and what hidden , i thought in Kula be cool check it .

But I haven’t found it yet .


Cleanest part from it manual matrix 4x3 .

I gave it a hour and a half and made a small prototype. It emulates pretty much everything Kula World does except jumping, and adding that too wouldn’t be much of a deal. It’s about 60 lines of code in total. Everything important happens on lines 13-26 which handle stepped movement through gridmap cells and basis orientation. The rest is just beautifying it with smooth transitions. Exiting at line 27 would make it into a stepped version. So the whole schtick takes less than 30 lines of code. As you can see; no shaders whatsoever :smiley:

4 Likes

Amazing work :fire:

Thank you :folded_hands:

Use it wisely :wink:

1 Like

I tried it without animation part , but can’t figure out why T is not updates even when condition is met .

extends Node3D

@onready var T: Transform3D = global_transform

func _ready() -> void:
	print("start value of T:",T)
func _process(_dt) -> void:
	var occupied_forward = is_cell_occupied(T.origin - T.basis.z)
	var occupied_forward_down = is_cell_occupied(T.origin - T.basis.z - T.basis.y)
	
	if Input.is_action_just_pressed("forward"):
		print("pressed forward ","T.origin",T.origin,"T.basis.z", T.basis.z, "T.basis.y", T.basis.y)
		print("occupied_forward = ", occupied_forward)
		print("occupied_forward_down = ", occupied_forward_down)
		print("grid size cell ", %grid.cell_size)
		if not occupied_forward and occupied_forward_down:
			T = T.translated_local(Vector3.FORWARD * %grid.cell_size)
			print("not occupied_forward and occupied_forward_down")
			print("T value ",T)
		elif occupied_forward:
			T = T.rotated_local(Vector3.RIGHT, PI /2.0)
		elif not occupied_forward and not occupied_forward_down:
			T = T.translated_local((Vector3.FORWARD * Vector3.DOWN) * %grid.cell_size)
			T = T.rotated_local(Vector3.RIGHT, -PI/ 2.0)
			
	elif Input.is_action_just_pressed("left_camera"):
		print("pressed left_camera", T.basis)
		T = T.rotated_local(Vector3.UP, PI/ 2.0)
	elif Input.is_action_just_pressed("right_camera"):
		print("pressed right_camera", T.basis)
		T = T.rotated_local(Vector3.UP, -PI /2.0)
	T = T.orthonormalized()
	
	if T.is_equal_approx(global_transform):
		return
	
func is_cell_occupied(pos: Vector3) -> bool:
	return %grid.get_cell_item(%grid.local_to_map(pos)) != GridMap.INVALID_CELL_ITEM

return this on forward

start value of T:[X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (-2.5, 1.5, 0.5)]
pressed forward T.origin(-2.5, 1.5, 0.5)T.basis.z(0.0, 0.0, 1.0)T.basis.y(0.0, 1.0, 0.0)
occupied_forward = false
occupied_forward_down = true
grid size cell (1.0, 1.0, 1.0)
not occupied_forward and occupied_forward_down
T value [X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (-2.5, 1.5, -0.5)]

T is just floating in the vacuum. You need to assign it to global_transform after you’ve changed it. My example code interpolates towards it so there’s no direct assignment there. Do it after orthonormalized() call.

1 Like

I still digging through functions/Methods how they works

.as_relative()
.is_equal_approx() - # I always thoughts only approximately zero only exist 
.orthonormalized() -
sign( .signed_angle_to)
.project() 

but I discovered something interesting , is your debugger went crazy on tween_spin ?

E 0:00:01:714   step: Tween (bound to /root/Node3D/ball): started with no Tweeners.
  <C++ Error>   Method/function failed. Returning: false
  <C++ Source>  scene/animation/tween.cpp:352 @ step()

Error message `step: <Tween#->: started with no Tweeners` missing essential information · Issue #79055 · godotengine/godot · GitHub - so does it need to exist outside of condition ?

Ah yeah, it’s the position tween. Just put the tween object creation under the if block so it doesn’t create the tween object if end values are the same.

You can also add the condition for the orientation tween. That way only needed tweens will be created. However since different tweens will run for different moves best to not rely on a finished signal of either of them, but instead put the reset of the animating flag on a scene tree timer.

1 Like

Its a camera which makes me a wonder for a bit

  • if there is some extra setting to bypass rendering meshes between ball_mesh and cam.

I tried change material settings ( cull and blending ) but this “work only partially”

Should SpringArm3D added or some easier solution with different position of camera ?

Not sure if spring arm is a good solution here as the space between the ball and the wall could get really tight. I’d use a shader(aha!) that makes stuff inbetween half transparent, or render the silhouette of the ball over the geometry, possibly using the stencil buffer.

1 Like