removed trackball camera addon

added new addon for gimbal
set up gimbal in main project
master
Zac 5 years ago
parent f992abc9df
commit 57840ab860

@ -0,0 +1,650 @@
#GimbalControl Node v0.1.0
# Notes:
# - To use as a camera gimbal, just place a camera inside and reset it's rotation if it was rotated.
# - All offsets/transforms of it's children are kept.
# - Do not scale parent nodes though, everything gets messed up.
# - If the target is a sibling of the node, it MUST be above the node in the hierarchy (so that it moves first).
# - Technically this script could be made to extend a camera node, but this way you could move anything
# with the gimbal (e.g. change lighting by rotating a light around a point)
# - An interpolated camera can be used to target the node itself, but it zooms in a bit weird when rotating around.
# - While running, you can't change the "origin/basis".
# - To "reset" the rotation (relative to it's current target or real transform), you should use set_rotation_to(right/left in degrees,up/down in degrees).
# - Note that keyboard ghosting can prevent multiple keys being registered (as might be the case if you're moving/looking only with keys)
extends Spatial
signal look_right(amount)
signal look_left(amount)
signal first_person_entered(distance)
signal first_person_exited(distance)
#PROPERTIES
#optional, can also just be parented to target
export (NodePath) var target setget set_target, get_target
#whether when we change a target as we move closer to it or stay the same distance
#or min/max distance if out of range
export (bool) var move_to_target_on_change = true
#whether to interpolate target changes (rotation, location optional)
export (bool) var interpolate_target_change = true
#if move_to_target_on_change is true, allow zooming to stop the distance interpolation (rotation can't be stopped)
export (bool) var allow_stop_move_interpolation = true
#whether to interpolate the set_rotation_to method
#this will correctly rotate around the target/origin in an arc
#the translation is not interpolated, it will move with the target at the speed the target moves
export (bool) var interpolate_set_rotation_to = true
#when you use set_rotation_to and interpolate_set_rotation_to is true, allows any movement to stop the interpolation
#will not stop rotations when interpolating between targets
export (bool) var allow_stop_rotation_interpolation = true
#multiplier for interpolations, higher is faster.
export (float) var interpolation_speed = 2
#whether it tilts with it's parent/target or stays aligned to the global axis
export (bool) var rotate_globally = false setget set_rotate_globally, get_rotate_globally
#regular speed
export (int) var move_speed = 2
#speed when mouse look is on
export (int) var look_speed = 0.3
#zoom can seem slow
export (int) var zoom_multiplier = 3
#because of how the scroll button is triggered, it seems even slower than regular zoom
#is multiplied by zoom_multiplier
export (int) var scroll_zoom_multiplier = 5
#zoom/distances (used interchangeably, initally this was just a camera gimbal)
export (int) var default_distance = 10
export (int) var min_distance = 0
export (int) var max_distance = 50
#note that the zoom toggles ignores min/max distances
export var zoom_toggle_distances = [0, 20, 40]
#a convenient way to change the array order, in this case true causes it to go from 40 to 0, far to near
export (bool) var reverse_zoom_toggle_order = true
#the distance at which the first person signal is triggered
export (int) var first_person_distance = 1
#rotation limits (the signal emitted ignores these)
#unlimit by setting to 360
export (int, 0, 360) var rotation_limit_up_in_degrees = 90 #technically negative
export (int, 0, 360) var rotation_limit_down_in_degrees = 90
#default unlimited
export (int, 0, 360) var rotation_limit_right_in_degrees = 360
export (int, 0, 360) var rotation_limit_left_in_degrees = 360 #technicall negative
#initial start rotaion (-x = left, -y = down, around target/origin)
export (Vector2) var start_rotation_in_degrees = Vector2(0,30)
#whether to invert movement
export (bool) var reverse_up_down = false
export (bool) var reverse_left_right = false
#reverse mouse wheel zoom (regular zoom keys work the same)
export (bool) var reverse_mouse_zoom = false
#move by dragging (enable mouse look should be off)
export (bool) var enable_mouse_dragging = false
#whether to hide the mouse when enable mouse look isn't on
export (bool) var hide_mouse = true
#enable mouse look, hides mouse by default
export (bool) var enable_mouse_look = true
#to control the a parent character's rotation with look right/left:
#- disable right left rotations in the node
#- connect the signal emitted to your character
#to disable right/left completely (no checking right/left input), disable = true and emit = false
export (bool) var disable_right_left = false
export (bool) var emit_right_left = true
#change the action names (note some options handle mouse vs key inputs differently e.g. reverse_mouse_zoom)
export (String) var look_right_action_name = "look_right"
export (String) var look_left_action_name = "look_left"
export (String) var look_up_action_name = "look_up"
export (String) var look_down_action_name = "look_down"
export (String) var look_click_action_name = "look_click"
export (String) var look_zoom_in_action_name = "look_zoom_in"
export (String) var look_zoom_out_action_name = "look_zoom_out"
export (String) var look_zoom_toggle_action_name = "look_zoom_toggle"
#PRIVATE VARIABLES
#shorthand variables for my sanity
var look_right #look_right_action_name
var look_left #look_left_action_name
var look_up #look_up_action_name
var look_down #look_down_action_name
var look_click #look_click_action_name
var look_zoom_in #look_zoom_in_action_name
var look_zoom_out #look_zoom_out_action_name
var look_zoom_toggle #look_zoom_toggle_action_name
var rot_limit_up #rotation_limit_up_in_degrees
var rot_limit_down #rotation_limit_down_in_degrees
var rot_limit_left #rotation_limit_left_in_degrees
var rot_limit_right #rotation_limit_right_in_degrees
#movement vector, used as (left/right, up/down, distance/zoom)
var movement = Vector3(0,0,0)
#whether we have a target
var target_mode = false
#so we can do things differently during initial ready (e.g. getsets)
var ready = false
#in set_target and align_to_target function we need to know the first time it was called
var first_call_target = true
#whether the mouse is zooming/dragging/looking
var mouse_wheel_zooming = false
var mouse_dragging = false
var mouse_looking = false
#whether we're in first person distance
var in_first_person = false
#zoom related variables for toggle
var zoom_toggled = false
var zoom_levels #array
var zoom_level #index
#to keep track of key states
var key_right = false
var key_left = false
var key_up = false
var key_down = false
var key_zoom_in = false
var key_zoom_out = false
#for when we change from having a target to not, and are not in global mode
#we have to have some way to reset our orientation to the initial "local" orientation
var original_global_transform
#we also need a reference to the transform origin to move with parent
var original_transform
#helps keep track of whether our target moved
var target_last_location
#the distance we need to be from the target
var current_distance
#interpolation_related
var forcing_transform = false
var interpo_end = {
"basis": null,
"look_target": null
}
var interpo_start #initial transform
var interpo_is_rotation = false
var slerp_value = 0
var lerp_value = 0
var lerp_stop = false
var rotation_stop = false
func set_rotation_to(rotation_vector):
var start = {
"origin": original_global_transform.origin if !target else target.global_transform.origin,
"basis": global_transform.basis
}
if target_mode:
global_transform.origin = target.global_transform.origin
else:
global_transform.origin = original_global_transform.origin
#to set angle, start with a "default" vector (pointing forward)
var start_position = Vector3(0,0,1)
#rotate right/left then up/down
start_position = start_position.rotated(Vector3(0,1,0), deg2rad(rotation_vector.x))
start_position = start_position.rotated(Vector3(-1,0,0), deg2rad(rotation_vector.y))
if !rotate_globally:
#apply correct basis if not rotating globally
var basis = target.global_transform.basis if target_mode else original_global_transform.basis
start_position = basis * start_position
global_transform.origin = original_global_transform.origin if !target else target.global_transform.origin
global_translate(start_position * current_distance)
#must be set like this otherwise end is a Transform and other properties can't be assigned
var end = {
"origin": global_transform.origin
}
if interpolate_set_rotation_to:
interpo_is_rotation = true
align_to_target(start, end)
else:
interpo_is_rotation = false
align_to_target()
func get_target():
return target
func set_target(value):
if ready:
if value != null and value != "Null":
target = get_node(value)
if target != null:
target_mode = true
target_last_location = target.global_transform.origin
else:
target = null
target_mode = false
else:
target_mode = false
#align_to_target takes care of looking at our new target with interpolation if needed
if !first_call_target:
align_to_target()
else:
target = value
func get_rotate_globally():
return rotate_globally
func set_rotate_globally(value):
rotate_globally = value
if ready:
align_to_target()
func align_to_target(start = null, end = null):
var look_target_transform = target.global_transform if target_mode else original_global_transform
var look_target = look_target_transform.origin
var vector_up = Vector3(0,1,0) #global
if !rotate_globally: #replace vector_up if not in global mode
var target_basis = look_target_transform.basis
vector_up = target_basis * Vector3(0,1,0)
var initial_transform = global_transform
#will handle looking at target and setting orientation correctly
if look_target != global_transform.origin:
#if we're directly above/beneath our target, look at doesn't work
var dir_to_target = (global_transform.origin - look_target).normalized()
if dir_to_target != vector_up and -dir_to_target != vector_up:
look_at(look_target, vector_up)
else:
#in which case we just rotate forward/backward 90 degrees to face it
rotate_object_local(Vector3(-1,0,0) if dir_to_target.y > 0 else Vector3(1,0,0), deg2rad(90))
else:
#in the event we're already at the target, we can use other ways to get the "correct" rotation
if !rotate_globally:
global_transform.basis = look_target_transform.basis #todo mix with rotation, just change z?
else:
rotation.z = 0 #we just need to untilt the node
var new_distance
if !move_to_target_on_change:
new_distance = look_target.distance_to(initial_transform.origin)
if new_distance < min_distance:
current_distance = min_distance
elif new_distance > max_distance:
current_distance = max_distance
else:
current_distance = current_distance
global_transform.origin = look_target + (initial_transform.origin - look_target).normalized() * current_distance
var final_transform = global_transform
if interpo_is_rotation or (!first_call_target and interpolate_target_change):
#reset the transform so now we can slowly transition to the new one
global_transform.origin = initial_transform.origin
global_transform.basis = initial_transform.basis
if start == null:
start = {
"basis": global_transform.basis,
"origin": global_transform.origin
}
if end == null:
end = {}
end.origin = final_transform.origin
end.basis = final_transform.basis
end.look_target = look_target
force_transform(start, end)
func force_transform(start, end):
interpo_start = start
interpo_end = end
lerp_value = 0
slerp_value = 0
forcing_transform = true #must be set last
func rotation_slerp(delta):
slerp_value += delta * interpolation_speed
if slerp_value > 1:
slerp_value = 1
if !rotation_stop:
var current_rotation = Quat(interpo_start.basis).slerp(interpo_end.basis, slerp_value)
global_transform.basis = Basis(current_rotation)
if slerp_value == 1 or rotation_stop:
#only slerp should reset these
forcing_transform = false
rotation_stop = false
movement = Vector3()
slerp_value = 0
func location_lerp(delta):
lerp_value += delta * interpolation_speed
if lerp_value > 1:
lerp_value = 1
if !lerp_stop and !rotation_stop:
#if we're not changing targets we want the interpolation to be at the correct distance from the target/origin
#to make it travel in an arc we do the same thing as when we move normally, and translate after rotating
#this is why the slerp has to be called first
#there's no need to actually interpolate
if interpo_is_rotation:
if !target_mode:
global_transform.origin = interpo_start.origin
else:
global_transform.origin = target.global_transform.origin #we can't use interpo start because this can have changed
translate(Vector3(0,0, current_distance))
# regular interpolation
elif target_mode: #there should never be any reason why we're not in target mode
global_transform.origin = interpo_start.origin.linear_interpolate(target.global_transform.origin + interpo_end.basis * Vector3(0,0,current_distance), lerp_value)
if lerp_value == 1:
lerp_value = 0
#lerp should rest this one as only it uses it
interpo_is_rotation = false
func _ready():
ready = true
#set shorthand variables
rot_limit_up = -deg2rad(rotation_limit_up_in_degrees)
rot_limit_down = deg2rad(rotation_limit_down_in_degrees)
rot_limit_left = -deg2rad(rotation_limit_left_in_degrees)
rot_limit_right = deg2rad(rotation_limit_right_in_degrees)
look_right = look_right_action_name
look_left = look_left_action_name
look_up = look_up_action_name
look_down = look_down_action_name
look_click = look_click_action_name
look_zoom_in = look_zoom_in_action_name
look_zoom_out = look_zoom_out_action_name
look_zoom_toggle = look_zoom_toggle_action_name
zoom_levels = zoom_toggle_distances
zoom_level = 1 if reverse_zoom_toggle_order else 0 #zoom_toggle_distances.size() if reverse_zoom_toggle_order else 0
if zoom_levels.size() <= 1:
print("WARNING in " + str(name) + ": Zoom Toggle Distances array should contain at least 2 values.")
current_distance = default_distance
#set transforms
#reset scale because scale will messes with a bunch of things
#to scale things, scale within a child node
scale = Vector3(1,1,1)
original_global_transform = global_transform
original_transform = transform
#properly set target variable (setget just does the path of target)
#align_to_target will not be called
set_target(target)
#because we need to know where the target is then do the start rotation relative to that
set_rotation_to(start_rotation_in_degrees)
#THEN align to the target
align_to_target()
#now we can set this to false
first_call_target = false
if enable_mouse_dragging and enable_mouse_look:
print("WARNING in " + str(name) + ": Enable Mouse Dragging and Enable Mouse Look cannot be enabled at the same time, Mouse Dragging has been disabled.")
enable_mouse_dragging = false
if enable_mouse_look:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
if hide_mouse and !enable_mouse_look: #only one input mode can be set
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
#PROCESS INPUT
#using _input both to separate this logic and because sometimes we need event.is_action_pressed (which only fires on first press)
#as opposed to Input.is_action_pressed (which fires when held)
func _input(event):
#MOUSE LOOK
if enable_mouse_look and event.is_class("InputEventMouseMotion") and event.relative:
movement = Vector3(event.relative.x if reverse_left_right else -event.relative.x, event.relative.y if reverse_up_down else -event.relative.y, movement.z)
mouse_looking = true
else:
mouse_looking = false
movement = Vector3(0,0, movement.z)
#RIGHT/LEFT
if !disable_right_left or (disable_right_left and emit_right_left):
if event.is_action_released(look_right):
movement.x = 0
key_right = false
if event.is_action_released(look_left):
movement.x = 0
key_left = false
if Input.is_action_pressed(look_right):
movement.x = 1 if reverse_left_right else -1
key_right = true
if Input.is_action_pressed(look_left):
movement.x = -1 if reverse_left_right else 1
key_left = true
if key_right and key_left:
movement.x = 0
#UP/DOWN
if event.is_action_released(look_up):
movement.y = 0
key_up = false
if event.is_action_released(look_down):
movement.y = 0
key_down = false
if Input.is_action_pressed(look_up):
movement.y = 1 if reverse_up_down else -1
key_up = true
if Input.is_action_pressed(look_down):
movement.y = -1 if reverse_up_down else 1
key_down = true
if key_up and key_down:
movement.y = 0
#ZOOM IN/OUT
#because of how scroll is registered (it looks like _input fires twice quickly and _process is never reached)
#movement/keys must be reset later, so we use mouse_wheel_zooming to trigger that
#there might be other types of input this happens to?
if !event.is_class("InputEventMouseButton"):
if event.is_action_released(look_zoom_in):
movement.z = 0
key_zoom_in = false
if event.is_action_released(look_zoom_out):
movement.z = 0
key_zoom_out = false
elif event.is_action(look_zoom_out) or event.is_action(look_zoom_in):
mouse_wheel_zooming = true
if Input.is_action_pressed(look_zoom_in):
movement.z = 1 if reverse_mouse_zoom and event.is_class("InputEventMouseButton") else -1
key_zoom_in = true
if Input.is_action_pressed(look_zoom_out):
movement.z = -1 if reverse_mouse_zoom and event.is_class("InputEventMouseButton") else 1
key_zoom_out = true
if key_zoom_in and key_zoom_out:
movement.z = 0
#ZOOM TOGGLE
if event.is_action_pressed(look_zoom_toggle):
movement.z = 0
zoom_toggled = true
zoom_level += -1 if reverse_zoom_toggle_order else 1
if zoom_level >= zoom_levels.size():
zoom_level = 0
elif zoom_level < 0:
zoom_level = zoom_levels.size() - 1
else:
zoom_toggled = false
#CLICKING/DRAGGING
if enable_mouse_dragging:
if event.is_action_pressed(look_click):
mouse_dragging = true
if event.is_action_released(look_click):
mouse_dragging = false
movement.x = 0
movement.y = 0
if mouse_dragging and event.is_class("InputEventMouseMotion"):
var mouse_move = event.relative
movement = Vector3(mouse_move.x if reverse_left_right else -mouse_move.x, mouse_move.y if reverse_up_down else -mouse_move.y, movement.z)
#APPLY MOVEMENT
#once input has processed we get a vector (right/left, up/down, zoomin/out) to change movement
#and can apply delta from here
func _process(delta):
var target_moved = target_mode and target_last_location != target.global_transform.origin
if !forcing_transform and (movement.length() != 0 or target_moved):
if target_mode:
target_last_location = target.global_transform.origin
var speed
#change speed if looking with mouse
if mouse_looking:
speed = look_speed * delta
else:
speed = move_speed * delta
#get our target location (or initial local transform if no target)
var look_target_transform = target.global_transform if target_mode else original_global_transform
var look_target = look_target_transform.origin
#record how far away we are from the target
var distance = global_transform.origin.distance_to(look_target)
#move our object to the target (all rotations happen around the object's center)
if target_mode:
global_transform.origin = look_target
else:
transform.origin = original_transform.origin
#get real rotation, used to calculate new rotation and check limits
#orthonormalized needed because after a few rotations we have messed up floats
var start_rotation
if rotate_globally:
start_rotation = global_transform.basis.orthonormalized().get_euler()
else:
#gets the rotation as if local to target
if target:
#if we're local to ourselves, change the transform (later used to rotate around)
start_rotation = (look_target_transform.affine_inverse() * global_transform).basis.orthonormalized().get_euler()
else:
start_rotation = (look_target_transform.affine_inverse() * transform).basis.orthonormalized().get_euler()
#LEFT/RIGHT
if movement.x != 0:
var difference = movement.x * speed
var new_rot = start_rotation.y + difference
if !disable_right_left:
if new_rot < rot_limit_right and new_rot > rot_limit_left:
if !rotate_globally:
#if we want the node to tilt with the character
#we can get the relative axis to tilt about by applying it's global basis to an up vector
if target:
#so here Vector3(0,1,0) is the target's y axis
global_rotate((look_target_transform.basis * Vector3(0,1,0)).normalized(), difference)
else:
#if we have no target, we can just rotate around the local y axis
rotate(Vector3(0,1,0), difference)
else:
#if we don't want the node to tilt with a parent node, we can just rotate around the global y axis
global_rotate(Vector3(0,1,0), difference)
if emit_right_left:
emit_signal("look_right" if movement.x > 0 else "look_left", difference)
#UP/DOWN
if movement.y != 0:
var difference = movement.y * speed
var new_rot = start_rotation.x + difference
if new_rot > rot_limit_up and new_rot < rot_limit_down:
#to understand why just rotate_object_local is enough
#imagine the cube is alone at 0,0,0, it's pole tilted as rotated by any parent nodes
#that's our starting point always, so using any rotation method can cause tilting problems in global mode
#to get around this for both modes, if we're in global mode
#we can set the rotation so the pole is aligned with global y axis in _ready
#otherwise we leave it alone, rotated/tilted with it's parent
#and the axis/pole we're rotating up/down towards will stay put
rotate_object_local(Vector3(1,0,0), difference)
#now that the object is rotated, we push it back along it's z axis
#this works because the push is relative to it's rotation
if !zoom_toggled:
speed = speed * zoom_multiplier
speed = speed * scroll_zoom_multiplier if mouse_wheel_zooming else speed
var new_distance = current_distance + movement.z * speed
if new_distance > min_distance and new_distance < max_distance:
current_distance += movement.z * speed
else:
current_distance = zoom_levels[zoom_level]
translate(Vector3(0,0,current_distance))
#FIRST PERSON SIGNAL
if !in_first_person and current_distance <= first_person_distance:
in_first_person = true
emit_signal("first_person_entered", current_distance )
elif in_first_person and current_distance > first_person_distance:
in_first_person = false
emit_signal("first_person_exited", current_distance )
#SPECIAL INPUT CASES
if mouse_wheel_zooming: #special reset
key_zoom_in = false
key_zoom_out = false
mouse_wheel_zooming = false
movement.z = 0
if mouse_dragging or enable_mouse_look: #special reset
movement = Vector3(0,0, movement.z)
elif forcing_transform:
#in mid transform, zooming can stop the distance interpolation if allowed
if movement.z !=0:
if move_to_target_on_change and allow_stop_move_interpolation:
var new_distance = global_transform.origin.distance_to(target.global_transform.origin if target else interpo_end.look_target)
if new_distance > min_distance < max_distance:
lerp_stop = true
current_distance = new_distance
if allow_stop_rotation_interpolation and interpo_is_rotation and movement.length() !=0:
rotation_stop = true
#if forcing_transform we call the interpolations
#rotation must be called first
rotation_slerp(delta)
location_lerp(delta)

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2018 Alan North
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,29 @@
# Gimbal Control Node
This is a gimbal node (for use with a camera, a light, or any other object) for Godot. It supports using keys, clicking and dragging, or mouse movement to look around. It also supports zooming, either with keys/mousewheel or with a toggle key (e.g. Joystick R3). And it doesn't have to be parented, it can track any target and even switch to targets with different rotations, and interpolated between them smoothly.
You can change any of the keys, set limits to the up/down rotation and distances, disable/emit right/left movements, and emit a first person signal.
The look_left/right signals are there so you can, for example, parent the gimbal (containing a camera) to a character then use the look left/right signal to rotate the character instead of the camera itself if you want to (see Demos).
The first person signal tells you when the camera has come within a certain range, so you can, for example, show a specific HUD element on screen.
### Note
I'm new to Godot and game development/programming in general (I didn't know what a Transform was when I started this), so there might be a few bugs. Everything seems to be working as I intended, but if you find any problems or you think there's a better way to do something, don't hesitate to file an issue.
## How to Install
You can download it from the AssetLib (search for Gimbal Control Node), or you can clone/download this repository then copy the addons folder to your project, or the folder inside that to your addons folder if you already have one.
From there you can enable it in `Project > Project Settings > Plugins`
The plugin requires certain `look_*` actions in the input map to work. If you want to use your own actions, you can specify them in the node. Or to quickly get started, you can copy them from the `project.godot` file in the demo project.
## Documentation
For now most of the documentation is in the actual script, including common issues to be aware of. I will eventually get around to formatting everything nicely here. If anything is unclear don't hesitate to file an issue.
## Demos
I have also made a project with various demo scenes for testing/demonstrating possible configurations, you can find it [here](https://github.com/AlansCodeLog/godot-gimbal-control-node-demos).

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

@ -2,12 +2,12 @@
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-d8104086c24314fbd510b502e5d9423c.stex"
path="res://.import/icon.png-83edda6cbcfbeeac4380914db4f28a35.stex"
[deps]
source_file="res://addons/goutte.camera.trackball/icon.png"
dest_files=[ "res://.import/icon.png-d8104086c24314fbd510b502e5d9423c.stex" ]
source_file="res://addons/alanscodelog.gimbalcontrol/icon.png"
dest_files=[ "res://.import/icon.png-83edda6cbcfbeeac4380914db4f28a35.stex" ]
[params]

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg6"
sodipodi:docname="icon.svg"
inkscape:version="0.92.1 r15371"
inkscape:export-filename="A:\User Folders\Documents\Godot\Tools\GimbalControl\addons\alanscodelog.gimbalcontrol\icon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1388"
inkscape:window-height="757"
id="namedview8"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8.7666449"
inkscape:cy="10.18377"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="g4" />
<g
transform="translate(0,-1036.4)"
id="g4">
<path
inkscape:connector-curvature="0"
id="path4564"
d="m 2.1620488,1044.441 a 5.8379326,1.9057292 0 0 1 0,-0.041 5.8379326,1.9057292 0 0 1 5.8379,-1.9058 5.8379326,1.9057292 0 0 1 5.8380002,1.9058 v 0 a 5.8379326,1.9057292 0 0 1 0,0.041"
mask="none"
style="opacity:1;fill:none;fill-opacity:0;stroke:#3dff49;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.87878788;paint-order:stroke fill markers" />
<path
style="opacity:1;fill:none;fill-opacity:0;stroke:#ff3d3d;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.82828283;paint-order:stroke fill markers"
mask="none"
d="m 7.95897,1038.562 a 1.9057292,5.8379326 0 0 1 0.04103,0 1.9057292,5.8379326 0 0 1 1.905729,5.8379 A 1.9057292,5.8379326 0 0 1 8,1050.2379 v 0 a 1.9057292,5.8379326 0 0 1 -0.04118,0"
id="path4562"
inkscape:connector-curvature="0" />
<circle
style="opacity:1;fill:#000000;fill-opacity:0;stroke:#007cff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.84343435;paint-order:stroke fill markers"
id="path4519"
cx="8"
cy="1044.4"
r="5.8379326" />
<path
inkscape:connector-curvature="0"
id="path4566"
d="m 13.835249,1044.4411 a 5.8379326,1.9057292 0 0 1 -5.8367002,1.8646 5.8379326,1.9057292 0 0 1 -5.8365,-1.8647"
mask="none"
style="opacity:1;fill:none;fill-opacity:0;stroke:#3dff49;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.87878788;paint-order:stroke fill markers" />
<path
style="opacity:1;fill:none;fill-opacity:0;stroke:#ff3d3d;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.82828283;paint-order:stroke fill markers"
mask="none"
d="m 7.958819,1050.2352 a 1.9057292,5.8379326 0 0 1 -1.864548,-5.8367 1.9057292,5.8379326 0 0 1 1.864699,-5.8365"
id="ellipse4533"
inkscape:connector-curvature="0" />
</g>
<g
id="g4513"
transform="translate(0,-1036.4)" />
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

@ -2,12 +2,12 @@
importer="texture"
type="StreamTexture"
path="res://.import/icon_trackball_camera.png-1f67d96a7a375568005a510700dba68a.stex"
path="res://.import/icon.svg-ff8e4076f0baed2eb77098bf4191ff8d.stex"
[deps]
source_file="res://addons/goutte.camera.trackball/icon_trackball_camera.png"
dest_files=[ "res://.import/icon_trackball_camera.png-1f67d96a7a375568005a510700dba68a.stex" ]
source_file="res://addons/alanscodelog.gimbalcontrol/icon.svg"
dest_files=[ "res://.import/icon.svg-ff8e4076f0baed2eb77098bf4191ff8d.stex" ]
[params]

@ -0,0 +1,7 @@
[plugin]
name="Plugin Name"
description="A highly customizable gimbal node for controlling cameras and other nodes. Supports dragging, mouse look, zoom, transform limits, custom keys, etc."
author="Alan North"
version="0.1.0"
script="plugin_load.gd"

@ -0,0 +1,13 @@
tool
extends EditorPlugin
func _enter_tree():
add_custom_type(
"GimbalControl",
"Spatial",
preload("GimbalControl.gd"),
preload("icon.png")
)
func _exit_tree():
remove_custom_type("test")

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Ξ0xB48C3B718a1FF3a280f574Ad36F04068d7EAf498
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,55 +0,0 @@
TrackballCamera for Godot
-------------------------
[![MIT](https://img.shields.io/github/license/Goutte/godot-trackball-camera.svg)](https://github.com/Goutte/godot-trackball-camera)
[![Release](https://img.shields.io/github/release/Goutte/godot-trackball-camera.svg)](https://github.com/Goutte/godot-trackball-camera/releases)
[![Donate](https://img.shields.io/badge/%CE%9E-%E2%99%A5-blue.svg)](https://etherscan.io/address/0xB48C3B718a1FF3a280f574Ad36F04068d7EAf498)
A simple [Godot](https://godotengine.org/) `3.x` addon that adds a `TrackballCamera` without gimbal lock.
The `TrackballCamera` responds to input from mouse, keyboard, joystick and touch, in order to rotate around its parent node while facing it.
A version for Godot `2.x` [is available as well](https://github.com/Goutte/godot-trackball-camera/releases/tag/v1.0).
Features
--------
- stays around its parent node, even if it moves
- no gimbal lock (quaternions FTW)
- camera inertia for a smoother experience
- the parent node does not have to be centered in the camera's view
- a bunch of parameters to configure everything as you want it
Install
-------
The installation is as usual, through the Assets Lib.
Then, enable the plugin in `Scene > Project Settings > Plugins`.
You can also simply copy the files of this project into yours, it should work.
Usage
-----
Make the `TrackballCamera` a child of the node to trackball around.
Make sure your camera initially faces said node, and is at a proper distance from it.
The initial position of your camera matters. The node does not need to be in the center.
You can also use this camera to look around you if you place it atop its parent node, spatially.
It's going to rotate around itself, and that amounts to looking around.
You'll probably want to set `mouseInvert` and `keyboardInvert` to true in that case.
Todo
----
- [ ] Test if touch works on android and html5, try `SCREEN_DRAG` otherwise.
Feedback and contributions are welcome!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

@ -1,126 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg4493"
sodipodi:docname="icon_trackball_camera.svg"
inkscape:export-filename="/home/goutte/code/cyx-godot/addons/TrackballCamera/icon_trackball_camera.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
inkscape:version="0.92.1 r15371">
<metadata
id="metadata4499">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4497" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1107"
id="namedview4495"
showgrid="false"
inkscape:zoom="29.5"
inkscape:cx="13.200433"
inkscape:cy="6.6601584"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4493" />
<g
transform="translate(0 -1036.4)"
id="g4491">
<path
d="m9 1038.4a3 3 0 0 0 -2.9883 2.7774 3 3 0 0 0 -2.0117 -0.7774 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8243v2.1757c0 0.554 0.44599 1 1 1h6c0.55401 0 1-0.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1 -2.2305 3 3 0 0 0 -3 -3z"
id="path4489"
fill="#fc9c9c" />
</g>
<g
id="g5308"
transform="matrix(0.00720063,0,0,0.00720063,5.1086782,7.4877507)"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
inkscape:export-xdpi="418.2641"
inkscape:export-ydpi="418.2641">
<g
id="g5251"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1">
<g
id="language"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1">
<path
id="path5248"
d="M 255,0 C 114.75,0 0,114.75 0,255 0,395.25 114.75,510 255,510 395.25,510 510,395.25 510,255 510,114.75 395.25,0 255,0 Z M 430.95,153 H 357 C 349.35,119.85 336.6,91.8 321.3,61.2 367.2,79.05 408,109.65 430.95,153 Z M 255,51 c 20.4,30.6 38.25,63.75 48.45,102 h -96.9 C 216.75,117.3 234.6,81.6 255,51 Z M 58.65,306 C 53.55,290.7 51,272.85 51,255 c 0,-17.85 2.55,-35.7 7.65,-51 h 86.7 c -2.55,17.85 -2.55,33.15 -2.55,51 0,17.85 2.55,33.15 2.55,51 z m 20.4,51 H 153 c 7.65,33.15 20.4,61.2 35.7,91.8 C 142.8,430.95 102,400.35 79.05,357 Z M 153,153 H 79.05 C 104.55,109.65 142.8,79.05 188.7,61.2 173.4,91.8 160.65,119.85 153,153 Z M 255,459 C 234.6,428.4 216.75,395.25 206.55,357 h 96.9 C 293.25,392.7 275.4,428.4 255,459 Z m 58.65,-153 h -117.3 c -2.55,-17.85 -5.1,-33.15 -5.1,-51 0,-17.85 2.55,-33.15 5.1,-51 H 316.2 c 2.55,17.85 5.1,33.15 5.1,51 0,17.85 -5.1,33.15 -7.65,51 z m 7.65,142.8 C 336.6,420.75 349.35,390.151 357,357 h 73.95 C 408,400.35 367.2,430.95 321.3,448.8 Z M 367.2,306 c 2.55,-17.85 2.55,-33.15 2.55,-51 0,-17.85 -2.55,-33.15 -2.55,-51 h 86.7 c 5.1,15.3 7.649,33.15 7.649,51 0,17.85 -2.55,35.7 -7.649,51 z"
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
</g>
</g>
<g
id="g5253"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5255"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5257"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5259"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5261"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5263"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5265"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5267"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5269"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5271"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5273"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5275"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5277"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5279"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
<g
id="g5281"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

@ -1,29 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon_trackball_camera.svg-87202336c371094f2871b6de2f8005f0.stex"
[deps]
source_file="res://addons/goutte.camera.trackball/icon_trackball_camera.svg"
dest_files=[ "res://.import/icon_trackball_camera.svg-87202336c371094f2871b6de2f8005f0.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

@ -1,7 +0,0 @@
[plugin]
name="TrackballCamera"
description="A simple trackball camera that responds to input from mouse, keyboard, joystick and touch, in order to rotate around its parent node while continuously facing it. Has inertia, no gimbal lock, and can be used to look around when rotating around itself."
author="Goutte"
version="4.0"
script="trackball_camera_plugin.gd"

@ -1,135 +0,0 @@
extends Camera
# Makes this Camera respond to input from mouse, keyboard, joystick and touch,
# in order to rotate around its parent node while facing it.
# We're using quaternions, so no infamous gimbal lock.
# The camera has inertia for a smoother experience.
# todo: test if touch works on android and html5, try SCREEN_DRAG otherwise
# Requirements
# ------------
# Godot 3.x
# Usage
# -----
# Attach as script to a Camera, and make the camera a child of the node to trackball around.
# Make sure your camera initially faces said node, and is at a proper distance from it.
# The initial position of your camera matters. The node does not need to be in the center.
# You can also use this camera to look around you if you place it atop its parent node, spatially.
# It's going to rotate around itself, and that amounts to looking around.
# You'll probably want to set mouseInvert and keyboardInvert to true in that case.
# License
# -------
# Same as Godot, ie. permissive MIT. (https://godotengine.org/license)
# If you feel generous and want to feed me so I can math more of those,
# I enjoy the taste of ETH Ξ 0xB48C3B718a1FF3a280f574Ad36F04068d7EAf498
# You can blame antoine@goutenoir.com for the bugs, crashes and burns.
# Seriously, useful feedback is always appreciated we can't test everything.
export var mouseEnabled = true
export var mouseInvert = false
export var mouseStrength = 1.111
export var keyboardEnabled = true
export var keyboardInvert = false
export var keyboardStrength = 1.111
export var joystickEnabled = true
export var joystickInvert = false
export var joystickStrength = 1.111
export var joystickThreshold = 0.09 # the resting state of my joystick's x-axis is -0.05 T.T
export var joystickDevice = 0
export var inertiaStrength = 1.0 # multiplier applied to all strengths
export(float, 0, 1, 0.005) var friction = 0.07
var _iKnowWhatIAmDoing = false # should we skip assertions?
var _cameraUp = Vector3(0, 1, 0)
var _cameraRight = Vector3(1, 0, 0)
var _epsilon = 0.0001
var _mouseDragStart
var _mouseDragPosition
var _dragInertia = Vector2(0, 0)
func _ready():
set_process_input(true)
set_process(true)
# It's best to catch future divisions by 0 before they happen.
# Note that we don't need this check if the mouse support is disabled.
# In case you know what you're doing, there's a property you can change.
assert _iKnowWhatIAmDoing or get_viewport().get_visible_rect().get_area()
#print("Trackball Camera around %s is ready. ♥" % get_parent().get_name())
func _input(ev):
if mouseEnabled and ev is InputEventMouseButton:
if ev.pressed:
_mouseDragStart = getNormalizedMousePosition()
else:
_mouseDragStart = null
_mouseDragPosition = _mouseDragStart
func _process(delta):
if mouseEnabled and _mouseDragPosition != null:
var _currentDragPosition = getNormalizedMousePosition()
_dragInertia += (_currentDragPosition - _mouseDragPosition) \
* mouseStrength * (-0.1 if mouseInvert else 0.1)
_mouseDragPosition = _currentDragPosition
if keyboardEnabled:
var key_i = -1 if keyboardInvert else 1
var key_s = keyboardStrength / 1000.0 # exported floats get truncated
if Input.is_key_pressed(KEY_LEFT):
_dragInertia += Vector2(key_i * key_s, 0)
if Input.is_key_pressed(KEY_RIGHT):
_dragInertia += Vector2(-1 * key_i * key_s, 0)
if Input.is_key_pressed(KEY_UP):
_dragInertia += Vector2(0, key_i * key_s)
if Input.is_key_pressed(KEY_DOWN):
_dragInertia += Vector2(0, -1 * key_i * key_s)
if joystickEnabled:
var joy_h = Input.get_joy_axis(joystickDevice, 0) # left stick horizontal
var joy_v = Input.get_joy_axis(joystickDevice, 1) # left stick vertical
var joy_i = -1 if joystickInvert else 1
var joy_s = joystickStrength / 1000.0 # exported floats get truncated
if abs(joy_h) > joystickThreshold:
_dragInertia += Vector2(joy_i * joy_h * joy_h * sign(joy_h) * joy_s, 0)
if abs(joy_v) > joystickThreshold:
_dragInertia += Vector2(0, joy_i * joy_v * joy_v * sign(joy_v) * joy_s)
var inertia = _dragInertia.length()
if inertia > _epsilon:
applyRotationFromTangent(_dragInertia * inertiaStrength)
_dragInertia = _dragInertia * (1 - friction)
elif inertia > 0:
_dragInertia.x = 0
_dragInertia.y = 0
# Convenience method for you to move the camera around.
# inertia is a Vector2 in the normalized right-handed x/y of the screen.
func addInertia(inertia):
_dragInertia += inertia
func getNormalizedMousePosition():
return get_viewport().get_mouse_position() / get_viewport().get_visible_rect().size
func applyRotationFromTangent(tangent):
var tr = get_transform() # not get_camera_transform, unsure why
var up = tr.basis.xform(_cameraUp)
var rg = tr.basis.xform(_cameraRight)
var upQuat = Quat(up, -1 * tangent.x * TAU)
var rgQuat = Quat(rg, -1 * tangent.y * TAU)
set_transform(Transform(upQuat * rgQuat) * tr) # money shot!

@ -1,12 +0,0 @@
tool
extends EditorPlugin
func _enter_tree():
add_custom_type(
"TrackballCamera", "Camera",
preload("res://addons/goutte.camera.trackball/trackball_camera.gd"),
preload("res://addons/goutte.camera.trackball/icon_trackball_camera.png")
)
func _exit_tree():
remove_custom_type("TrackballCamera")

@ -15,17 +15,31 @@ config/icon="res://icon.png"
[editor_plugins]
enabled=PoolStringArray( "goutte.camera.trackball" )
enabled=PoolStringArray( "alanscodelog.gimbalcontrol" )
[input]
player_up=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
move_up=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
]
player_down=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
move_down=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null)
]
player_left=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
move_left=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
]
player_right=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
move_right=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
]
look_zoom_in=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
]
look_zoom_out=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
]
look_up=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null)
]
look_right=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null)
]
look_left=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null)
]
look_down=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null)
]
look_click=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
]
[rendering]

File diff suppressed because one or more lines are too long

@ -0,0 +1,124 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://scenes/Player.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/alanscodelog.gimbalcontrol/GimbalControl.gd" type="Script" id=2]
[ext_resource path="res://addons/alanscodelog.gimbalcontrol/icon.png" type="Texture" id=3]
[sub_resource type="QuadMesh" id=1]
custom_aabb = AABB( 0, 0, 0, 0, 0, 0 )
size = Vector2( 10, 10 )
[sub_resource type="ConvexPolygonShape" id=2]
points = PoolVector3Array( -5, -5, 0, -5, 5, 0, 5, 5, 0, 5, -5, 0 )
[node name="Spatial" type="Spatial" index="0"]
[node name="StaticBody" type="StaticBody" parent="." index="0"]
editor/display_folded = true
input_ray_pickable = true
input_capture_on_drag = false
collision_layer = 1
collision_mask = 1
friction = 1.0
bounce = 0.0
constant_linear_velocity = Vector3( 0, 0, 0 )
constant_angular_velocity = Vector3( 0, 0, 0 )
[node name="MeshInstance" type="MeshInstance" parent="StaticBody" index="0"]
transform = Transform( 1, 0, 0, 0, -4.37114e-008, 1, 0, -1, -4.37114e-008, 0, 0, 0 )
layers = 1
material_override = null
cast_shadow = 1
extra_cull_margin = 0.0
use_in_baked_light = false
lod_min_distance = 0.0
lod_min_hysteresis = 0.0
lod_max_distance = 0.0
lod_max_hysteresis = 0.0
mesh = SubResource( 1 )
skeleton = NodePath("..")
material/0 = null
[node name="CollisionShape" type="CollisionShape" parent="StaticBody" index="1"]
transform = Transform( 1, 0, 0, 0, -4.37114e-008, 1, 0, -1, -4.37114e-008, 0, 0, 0 )
shape = SubResource( 2 )
disabled = false
[node name="Player" parent="." index="1" instance=ExtResource( 1 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
_sections_unfolded = [ "Transform" ]
[node name="GimbalControl" type="Spatial" parent="Player" index="2"]
script = ExtResource( 2 )
__meta__ = {
"_editor_icon": ExtResource( 3 )
}
target = NodePath("..")
move_to_target_on_change = true
interpolate_target_change = true
allow_stop_move_interpolation = true
interpolate_set_rotation_to = true
allow_stop_rotation_interpolation = true
interpolation_speed = 2
rotate_globally = false
move_speed = 2
look_speed = 0.3
zoom_multiplier = 3
scroll_zoom_multiplier = 5
default_distance = 10
min_distance = 0
max_distance = 50
zoom_toggle_distances = [ 0, 20, 40 ]
reverse_zoom_toggle_order = false
first_person_distance = 1
rotation_limit_up_in_degrees = 90
rotation_limit_down_in_degrees = 90
rotation_limit_right_in_degrees = 360
rotation_limit_left_in_degrees = 360
start_rotation_in_degrees = Vector2( 0, 0 )
reverse_up_down = false
reverse_left_right = false
reverse_mouse_zoom = false
enable_mouse_dragging = false
hide_mouse = true
enable_mouse_look = true
disable_right_left = true
emit_right_left = true
look_right_action_name = "look_right"
look_left_action_name = "look_left"
look_up_action_name = "look_up"
look_down_action_name = "look_down"
look_click_action_name = "look_click"
look_zoom_in_action_name = "look_zoom_in"
look_zoom_out_action_name = "look_zoom_out"
look_zoom_toggle_action_name = "ui_up"
[node name="Camera" type="Camera" parent="Player/GimbalControl" index="0"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
keep_aspect = 1
cull_mask = 1048575
environment = null
h_offset = 0.0
v_offset = 0.0
doppler_tracking = 0
projection = 0
current = true
fov = 70.0
size = 1.0
near = 0.05
far = 100.0
_sections_unfolded = [ "Transform" ]
[connection signal="look_left" from="Player/GimbalControl" to="Player" method="_on_look_left"]
[connection signal="look_right" from="Player/GimbalControl" to="Player" method="_on_look_right"]

@ -2,22 +2,31 @@ extends KinematicBody
const UP = Vector3(0, 1, 0)
export var Speed = 10
var Velocity = Vector3()
func _process(delta):
var vel = Vector3()
var b = get_global_transform().basis
if Input.is_action_pressed("player_up"):
vel.x = 1
elif Input.is_action_pressed("player_down"):
vel.x = -1
if Input.is_action_pressed("move_up"):
vel -= b.z
elif Input.is_action_pressed("move_down"):
vel += b.z
if Input.is_action_pressed("player_right"):
vel.z = 1
elif Input.is_action_pressed("player_left"):
vel.z = -1
if Input.is_action_pressed("move_right"):
vel += b.x
elif Input.is_action_pressed("move_left"):
vel -= b.x
Velocity = vel
Velocity = vel * Speed
func _physics_process(delta):
move_and_slide(Velocity, UP)
move_and_slide(Velocity, UP)
func _on_look_left(amount):
rotate_y(amount)
func _on_look_right(amount):
rotate_y(amount)

Loading…
Cancel
Save