3D submarine propelled by 'thrusters' - without physics ... local/global translation is a b****

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Ole

Imagine a cube with 4 thrusters on each face, like on a small space-capsule.
These generate thrust in 12 directions (Forward, Backward, Left, Right, Up, Down, +Yaw, -Yaw, +Pitch, -Pitch, +Roll, -Roll)

Thrust for each direction is calculated and (should be) implemented each frame.

My rotations (Yaw, Pitch and Roll) work like a charm … but I’m too stupid to integrate the linear thrust (generated local to object’s orientation) into a single global translation for my object.

Please help!

extends KinematicBody

var Decay:float = 2.0;
var CurrDecay:float = 0.0;

var ThrustX:float = 0.0;
var ThrustY:float = 0.0;
var ThrustZ:float = 0.0;
var ThrustMax:float = 50.0;#Meters/Second

var RotateY:float = 0.0;
var RotateX:float = 0.0;
var RotateZ:float = 0.0;
var RotateMax:float = 10.0;#Degrees/Second

onready var Velocity:Vector3 = transform.origin;

func _process(delta):
	
	if Input.is_action_pressed("Shift"):
		
		if Input.is_action_pressed("Pitch+"):
			RotateX -= (RotateMax-abs(RotateX)) * delta;
		if Input.is_action_pressed("Pitch-"):
			RotateX += (RotateMax-RotateX) * delta;
			
		if Input.is_action_pressed("ThrustLeft"):
			ThrustX -= (ThrustMax-abs(ThrustX)) * delta;
		if Input.is_action_pressed("ThrustRight"):
			ThrustX += (ThrustMax-ThrustX) * delta;

```
	if Input.is_action_pressed("ThrustUp"):
		ThrustY += (ThrustMax-ThrustY) * delta;
	if Input.is_action_pressed("ThrustDown"):
		ThrustY -= (ThrustMax-abs(ThrustY)) * delta;

else:
	
	if Input.is_action_pressed("ThrustFront"):
		ThrustZ -= (ThrustMax-abs(ThrustZ)) * delta;
	if Input.is_action_pressed("ThrustBack"):
		ThrustZ += (ThrustMax-ThrustZ) * delta;
	
	if Input.is_action_pressed("Yaw+"):
		RotateY += (RotateMax-RotateY) * delta;
	if Input.is_action_pressed("Yaw-"):
		RotateY -= (RotateMax-abs(RotateY)) * delta;

	if Input.is_action_pressed("Roll+"):
		RotateZ -= (RotateMax-abs(RotateZ)) * delta;
	if Input.is_action_pressed("Roll-"):
		RotateZ += (RotateMax-RotateZ) * delta;

#DAMPEN
CurrDecay = delta*Decay;
RotateX = lerp(RotateX,0.0,CurrDecay);
RotateY = lerp(RotateY,0.0,CurrDecay);
RotateZ = lerp(RotateZ,0.0,CurrDecay);
ThrustX = lerp(ThrustX,0.0,CurrDecay);
ThrustY = lerp(ThrustY,0.0,CurrDecay);
ThrustZ = lerp(ThrustZ,0.0,CurrDecay);

#EXECUTE	
rotate_object_local(Vector3.FORWARD,deg2rad(RotateZ));
rotate_object_local(Vector3.RIGHT,deg2rad(RotateX));
rotate_object_local(Vector3.UP,deg2rad(RotateY));

#CRAPPY MISGUIDED LOW-IQ ATTEMPT OF TRANSLATION:
var ThrustVector = Vector3(ThrustX,ThrustY,ThrustZ);# ???
Velocity = Velocity * ThrustVector;# ???
global_translate(Velocity);# ???
#move_and_collide(Velocity);# ???
#translate(Velocity);# ???
```

:bust_in_silhouette: Reply From: wombatstampede

If in your submarine (yellow, isn’t it?) the forward direction is -z then you get the global vector3 with global_transform.basis.z * -1.

You can exchange z with i.e. y if you want an up/down vector.

Thanks for your response … but it dosn’t help me, as I don’t know what to do with the information.
And yes, it might be yellow :stuck_out_tongue:

Ole | 2019-05-01 12:28

That is your"Thrustvector" (gdscript style)

wombatstampede | 2019-05-01 17:44

Oh, I see. I just checked your code a bit closer. I am more used to the physics approach where you can add multiple impulses.

So, if you got Thrust values for the 3 axes then you can multiply each value with each global_transform.basis.x/y/z. Then you could add thee resulting vector3’s to get one vector3.

So similar to this:
(global_transform.basis.x * ThrustX) + (global_transform.basis.y * ThrustY) + (global_transform.basis.z * ThrustZ)

You could add this summed up vector to your velocity but you should reduce/damp your velocity at the same time (draft of water). Reducing of the velocity should be a small value relative to delta and the square of your velocity.

Here’s the “official” info about working with Transforms:
Using 3D transforms — Godot Engine (stable) documentation in English

And here’s my attempt to create a kind of “cheat sheet” for transforms:
https://godotforums.org/discussion/18480/godot-3d-vector-physics-cheat-sheet

Perhaps it helps.

wombatstampede | 2019-05-02 06:17

Thank you! … your input guided me to a working solution:

extends KinematicBody#User/Model

var Drag:float = 1.0;

var ThrustX:float = 0.0;
var ThrustY:float = 0.0;
var ThrustZ:float = 0.0;
var ThrustMax:float = 5.0;#Meters/Second?
var ThrustDecay:float = 2.0;

var ThrustVector:Vector3 = Vector3(0,0,0);
var MoveVector:Vector3 = Vector3(0,0,0);
var Velocity:Vector3 = Vector3(1,1,1);

var RotateY:float = 0.0;
var RotateX:float = 0.0;
var RotateZ:float = 0.0;
var RotateMax:float = 8.0;#Degrees/Second?

func _physics_process(delta:float) -> void:
	
	if Input.is_action_pressed("Shift"):
		
		if Input.is_action_pressed("Pitch+"):
			RotateX -= (RotateMax-abs(RotateX)) * delta;
		if Input.is_action_pressed("Pitch-"):
			RotateX += (RotateMax-RotateX) * delta;
			
		if Input.is_action_pressed("ThrustLeft"):
			ThrustX -= (ThrustMax-abs(ThrustX)) * delta;
		if Input.is_action_pressed("ThrustRight"):
			ThrustX += (ThrustMax-ThrustX) * delta;
			
		if Input.is_action_pressed("ThrustUp"):
			ThrustY += (ThrustMax-ThrustY) * delta;
		if Input.is_action_pressed("ThrustDown"):
			ThrustY -= (ThrustMax-abs(ThrustY)) * delta;
		
	else:
			
		if Input.is_action_pressed("ThrustFront"):
			ThrustZ -= (ThrustMax-abs(ThrustZ)) * delta;
		if Input.is_action_pressed("ThrustBack"):
			ThrustZ += (ThrustMax-ThrustZ) * delta;
			
		if Input.is_action_pressed("Yaw+"):
			RotateY += (RotateMax-RotateY) * delta;
		if Input.is_action_pressed("Yaw-"):
			RotateY -= (RotateMax-abs(RotateY)) * delta;
			
		if Input.is_action_pressed("Roll+"):
			RotateZ += (RotateMax-RotateZ) * delta;
		if Input.is_action_pressed("Roll-"):
			RotateZ -= (RotateMax-abs(RotateZ)) * delta;
	
	#DAMPEN THRUST
	var CurrDecay:float = delta*ThrustDecay;
	RotateX = lerp(RotateX,0.0,CurrDecay);
	RotateY = lerp(RotateY,0.0,CurrDecay);
	RotateZ = lerp(RotateZ,0.0,CurrDecay);
	ThrustX = lerp(ThrustX,0.0,CurrDecay);
	ThrustY = lerp(ThrustY,0.0,CurrDecay);
	ThrustZ = lerp(ThrustZ,0.0,CurrDecay);
	
	#INTEGRATE FORCES
	ThrustVector = (global_transform.basis.x*ThrustX) + (global_transform.basis.y*ThrustY) + (global_transform.basis.z*ThrustZ)
	MoveVector = Velocity+ThrustVector;
	MoveVector = lerp(MoveVector,Vector3(0,0,0),Drag*delta);#Water-drag
	
	#EXECUTE
	rotate_object_local(Vector3.RIGHT,deg2rad(RotateX));
	rotate_object_local(Vector3.UP,deg2rad(RotateY));
	rotate_object_local(Vector3.BACK,deg2rad(RotateZ));
	Velocity = move_and_slide(MoveVector);

All I lack now, is somehow subtracting water-drag from the physical rotations as well … that will come, as my knowledge increases (along with some refactoring I guess) :slight_smile:

Ole | 2019-05-03 08:42

Wonderful! Good luck on your project!

wombatstampede | 2019-05-03 10:16