Compare commits

..

No commits in common. "master" and "1d0935e6886491026b790a9cfb582e941fc6107f" have entirely different histories.

19 changed files with 131 additions and 672 deletions

View File

@ -6,14 +6,21 @@ var target := Vector3.ZERO
var acceleration := Vector3.ZERO var acceleration := Vector3.ZERO
var velocity := Vector3.ZERO var velocity := Vector3.ZERO
export var acceleration_factor = 5.0
export var accelerating := false
export var coefficient_of_restitution := 0.5 export var coefficient_of_restitution := 0.5
func _physics_process(delta): func _physics_process(delta):
if accelerating:
var direction = (target - global_transform.origin).normalized()
acceleration += direction * acceleration_factor * delta
velocity += acceleration
var collision = move_and_collide(velocity * delta) var collision = move_and_collide(velocity * delta)
if collision: if collision:
# Reflect the bullet and decrease the velocity according to the coefficient of restitution
var normal = collision.normal var normal = collision.normal
velocity = coefficient_of_restitution * (velocity - 2 * velocity.dot(normal) * normal) velocity = coefficient_of_restitution * (velocity - 2 * velocity.dot(normal) * normal)

View File

@ -1,40 +0,0 @@
extends Object
class_name DeadzoneInput
static func get_input(type, outer_deadzone, inner_deadzone, min_length = 0.0, normalized = true):
var input = Vector2(Input.get_action_strength(type + "_up") -
Input.get_action_strength(type + "_down"),
Input.get_action_strength(type + "_right") -
Input.get_action_strength(type + "_left"))
# Remove signs to reduce the number of cases
var signs = Vector2(sign(input.x), sign(input.y))
input = Vector2(abs(input.x), abs(input.y))
if input.length() < min_length:
return Vector2.ZERO
# Deazones for each axis
if input.x > outer_deadzone:
input.x = 1.0
elif input.x < inner_deadzone:
input.x = 0.0
else:
input.x = inverse_lerp(inner_deadzone, outer_deadzone, input.x)
if input.y > outer_deadzone:
input.y = 1.0
elif input.y < inner_deadzone:
input.y = 0.0
else:
input.y = inverse_lerp(inner_deadzone, outer_deadzone, input.y)
# Re-apply signs
input *= signs
# Limit at length 1
if normalized and input.length() > 1.0:
input /= input.length()
return input

View File

@ -3,7 +3,7 @@
[ext_resource path="res://Resources/gas_planet_flowmap.png" type="Texture" id=1] [ext_resource path="res://Resources/gas_planet_flowmap.png" type="Texture" id=1]
[ext_resource path="res://Resources/gas_planet_base.png" type="Texture" id=2] [ext_resource path="res://Resources/gas_planet_base.png" type="Texture" id=2]
[sub_resource type="Shader" id=1] [sub_resource type="Shader" id=14]
resource_local_to_scene = true resource_local_to_scene = true
code = "shader_type spatial; code = "shader_type spatial;
@ -38,7 +38,7 @@ void fragment(){
" "
[resource] [resource]
shader = SubResource( 1 ) shader = SubResource( 14 )
shader_param/color = Color( 1, 0.890196, 0.172549, 1 ) shader_param/color = Color( 1, 0.890196, 0.172549, 1 )
shader_param/flow_speed = 0.2 shader_param/flow_speed = 0.2
shader_param/flow_intensity = 0.8 shader_param/flow_intensity = 0.8

View File

@ -31,7 +31,7 @@ func _process(delta):
velocity = (translation - translation_before) / delta velocity = (translation - translation_before) / delta
# Rotate according to gravity # Rotate according to gravity
var gravity_acceleration = get_node(solar_system).get_closest_gravity_acceleration(global_transform.origin) var gravity_acceleration = get_node(solar_system).get_gravitation_acceleration(global_transform.origin)
# Rotate down vector to face center of gravity # Rotate down vector to face center of gravity
var down = gravity_acceleration var down = gravity_acceleration

View File

@ -1,39 +0,0 @@
extends KinematicBody
# Orbits the parent planet by velocity.
var time_passed := 0.0
var velocity := Vector3.ZERO
export(float) var move_speed_factor = 1.0
export(NodePath) var solar_system
func _ready():
var velocity_value = get_node(solar_system).get_orbit_velocity(global_transform.origin, get_parent())
# We need a vector perpendicular to the gravity acceleration to apply the velocity along.
# So we get the cross product of that and some arbitrary other vector, in this case Vector3.RIGHT
var gravity_acceleration = get_node(solar_system).get_closest_gravity_acceleration(global_transform.origin)
var other = Vector3.RIGHT
# Apply the velocity
velocity = gravity_acceleration.cross(other).normalized() * velocity_value
func _process(delta):
# Apply gravity as acceleration to velocity, then velocity to position
var gravity_acceleration = get_node(solar_system).get_closest_gravity_acceleration(global_transform.origin)
velocity += gravity_acceleration * delta
move_and_slide(velocity)
# Rotate down vector to face center of gravity -> tidally locked
var down = gravity_acceleration
var local_down = transform.basis * Vector3.DOWN
var angle = local_down.angle_to(down)
var axis = local_down.cross(down).normalized()
if axis != Vector3.ZERO: # Happens if we're perfectly aligned already (local_down and down are equal)
rotate(axis, angle)

View File

@ -13,36 +13,9 @@ const distance_multiplier = 318550 # thus, a radius of 20 results in an earth-
const gravity_multiplier = 10.0 const gravity_multiplier = 10.0
# Return the gravity acceleration vector to the closest planet, not taking all other planets into func get_gravitation_acceleration(position: Vector3) -> Vector3:
# account.
# This is useful for keeping something firmly on the planet while it is touching it, or for creating
# a predictable orbit.
func get_closest_gravity_acceleration(position: Vector3) -> Vector3:
var closest_planet_distance = INF
var closest_force = 0.0
# Iterate through all planets to find the closest one
for planet in get_children():
var pos_to_center = (planet.transform.origin - position)
var distance = pos_to_center.length()
if distance < closest_planet_distance:
# This planet is closer than the previous ones -> calculate and save the values
var force = _gravity(planet.mass * mass_multiplier, distance * distance_multiplier)
force *= gravity_multiplier
# Multiply by the normalized vector towards the center to give the force a direction
closest_force = (pos_to_center / distance) * force
closest_planet_distance = distance
return closest_force
# Return the total gravity acceleration vector experienced at that position.
func get_gravity_acceleration(position: Vector3) -> Vector3:
var total_force = Vector3.ZERO var total_force = Vector3.ZERO
# Add each planet's gravity force to the total force
for planet in get_children(): for planet in get_children():
var pos_to_center = (planet.transform.origin - position) var pos_to_center = (planet.transform.origin - position)
var distance = pos_to_center.length() var distance = pos_to_center.length()
@ -55,18 +28,6 @@ func get_gravity_acceleration(position: Vector3) -> Vector3:
return total_force return total_force
# Return the velocity needed to orbit the given planet
func get_orbit_velocity(position: Vector3, planet):
var pos_to_center = (planet.global_transform.origin - position)
var distance = pos_to_center.length()
# raw_velocity is the velocity according to the formula, but we also need to account for the gravity_multiplier.
var raw_velocity = -sqrt((G * planet.mass * mass_multiplier) / (distance * distance_multiplier))
var gravity_scale_factor = sqrt(gravity_multiplier / distance_multiplier)
return raw_velocity * gravity_scale_factor
# Formula for gravity # Formula for gravity
static func _gravity(mass, distance): static func _gravity(mass, distance):
return (G * mass) / (distance * distance) return (G * mass) / (distance * distance)

141
Player.gd
View File

@ -3,34 +3,29 @@ extends KinematicBody
const MAX_VEL = 500.0 const MAX_VEL = 500.0
var acceleration := Vector3.ZERO var acceleration := Vector3(0.0, -9.81, 0.0)
var velocity := Vector3.ZERO var velocity := Vector3(0.0, 0.0, 0.0)
export var move_accel = 60.0 var move_accel = 60.0
export var rotate_speed = 2.0 var rotate_speed = 2.0
export var drag = 0.05 var drag = 0.05
# Jumping # Jumping
var jumping := false var jumping := false
var on_ground := false
var time_since_jump_start := 0.0 var time_since_jump_start := 0.0
export var initial_jump_burst = 10.0 var initial_jump_burst = 10.0
export var jump_exponent = 0.05 var jump_exponent = 0.05
export var almost_on_ground_length = 1.0
var current_target_velocity := Vector3.ZERO var current_target_velocity := Vector3.ZERO
var has_inherited_velocity := false
export(NodePath) var solar_system export(NodePath) var solar_system
func _ready():
$GroundCheckRay.cast_to = Vector3.DOWN * almost_on_ground_length
func _input(event): func _input(event):
if event.is_action_pressed("jump") and is_on_ground(): if event.is_action_pressed("jump") and on_ground:
on_ground = false
jumping = true jumping = true
time_since_jump_start = 0.0 time_since_jump_start = 0.0
elif event.is_action_released("jump"): elif event.is_action_released("jump"):
@ -44,89 +39,38 @@ func get_center():
func apply_acceleration(acceleration): func apply_acceleration(acceleration):
# First drag, then add the new acceleration # First drag, then add the new acceleration
# For drag: Lerp towards the target velocity # For drag: Lerp towards the target velocity
# This is usually 0, unless we're on something that's moving, in which case it is that object's velocity # This is usually 0, unless we're on something that's moving, in which case it is that object's
# velocity
velocity = lerp(velocity, current_target_velocity, drag) velocity = lerp(velocity, current_target_velocity, drag)
velocity += acceleration velocity += acceleration
func get_gravity_acceleration():
var total_gravity = get_node(solar_system).get_gravity_acceleration(transform.origin)
# If we're (almost) on the ground, accelerate only towards the planet we're on the ground of.
# Otherwise, get the total gravity of the solar system.
if $GroundCheckRay.is_colliding():
# Lerp between the planet's own gravity and the
var planet_gravity = get_node(solar_system).get_closest_gravity_acceleration(transform.origin)
var distance_to_collision = ($GroundCheckRay.get_collision_point()
- $GroundCheckRay.global_transform.origin).length()
# This factor is 0.0 if the player is exactly on the ground, and 1.0 if they're just barely almost grounded
var factor = inverse_lerp(0.0, almost_on_ground_length, distance_to_collision)
return lerp(planet_gravity, total_gravity, factor)
else:
# If the player is not grounded: return the whole acceleration caused by the entire solar
# system.
return total_gravity
# Returns true if the player is currently (almost) on the ground.
# Surfaces with an angle of 45° or less are considered a ground.
func is_on_ground():
if $GroundCheckRay.is_colliding():
var normal = $GroundCheckRay.get_collision_normal()
# An angle of >45° to the local up vector counts as grounded
if normal.dot(global_transform.basis.y) > 0.5:
return true
return false
# Returns true if the player is (almost) on the ground and that ground is a moving platform.
func is_on_moving_platform():
return is_on_ground() and $GroundCheckRay.get_collider().is_in_group("MovingPlatform")
# Set the current target velocity to the moving platform that is currently below the player.
# If this was the first collision frame, also inherit the platform's velocity.
func apply_moving_platform_velocity():
if not has_inherited_velocity:
velocity += $GroundCheckRay.get_collider().velocity
has_inherited_velocity = true
current_target_velocity = $GroundCheckRay.get_collider().velocity
# Reset the current target velocity and other variables relevant for moving platforms.
func reset_moving_platform_velocity():
current_target_velocity = Vector3.ZERO
has_inherited_velocity = false
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta): func _physics_process(delta):
var move_velocity := Vector3.ZERO var move_velocity := Vector3.ZERO
var move_acceleration := Vector3.ZERO var move_acceleration := Vector3.ZERO
# Apply input # Movement and rotation
var input = DeadzoneInput.get_input("move", 0.65, 0.2, 0.0, false) if Input.is_action_pressed("move_up"):
move_acceleration.z -= move_accel
# Either do velocity-based movement or force-based movement if Input.is_action_pressed("move_down"):
if Input.is_action_pressed("movement_modifier"): move_acceleration.z += move_accel
move_velocity = transform.basis * Vector3.FORWARD * 15.0 * input.x if Input.is_action_pressed("move_left"):
else: rotate(transform.basis.y, delta * rotate_speed)
move_acceleration += transform.basis * Vector3.FORWARD * move_accel * input.x if Input.is_action_pressed("move_right"):
rotate(transform.basis.y, -delta * rotate_speed)
rotate(transform.basis.y, delta * rotate_speed * -input.y)
# Make movement local # Make movement local
move_acceleration = move_acceleration move_acceleration = transform.basis * move_acceleration
# Get acceleration caused by gravity print(on_ground)
var gravity_acceleration = get_gravity_acceleration()
# Jumping and Gravity
var gravity_acceleration = get_node(solar_system).get_gravitation_acceleration(transform.origin)
#if on_ground:
# FIXME: This breaks some things, but seems to be the right principle
#gravity_acceleration = Vector3.ZERO
# Apply both acceleration types
apply_acceleration((move_acceleration + gravity_acceleration) * delta) apply_acceleration((move_acceleration + gravity_acceleration) * delta)
# Handle jumping # Handle jumping
@ -140,15 +84,26 @@ func _physics_process(delta):
velocity += -gravity_acceleration.normalized() * e_section velocity += -gravity_acceleration.normalized() * e_section
time_since_jump_start += delta time_since_jump_start += delta
# Check for moving platforms and lerp towards that
if is_on_moving_platform():
apply_moving_platform_velocity()
else:
reset_moving_platform_velocity()
# Apply movement to position # Apply movement to position
# Add and subtract the move_velocity (used for velocity-based movement) because we do want to apply it, but not remember it for next frame velocity = move_and_slide(velocity, -gravity_acceleration.normalized(), true)
velocity = move_and_slide(velocity + move_velocity) - move_velocity on_ground = false
if get_slide_count() > 0:
var collision = get_slide_collision(0)
if collision.collider.is_in_group("MovingPlatform"):
# Inherit the moving platform's velocity and apply the initial velocity
if current_target_velocity != collision.collider.velocity / 6.0:
current_target_velocity = collision.collider.velocity / 6.0
velocity = current_target_velocity
if not jumping:
# Check the collision normal and set to grounded if it's close to the player's up vector
if collision.normal.dot(global_transform.basis.y) > 0.5: # an angle of >45° counts as grounded
on_ground = true
else:
# We're not colliding with anything, so drag takes us towards 0
current_target_velocity = Vector3.ZERO
# Clamp the velocity just to be save # Clamp the velocity just to be save
velocity.x = clamp(velocity.x, -MAX_VEL, MAX_VEL) velocity.x = clamp(velocity.x, -MAX_VEL, MAX_VEL)

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,5 @@
extends KinematicBody extends KinematicBody
# An enemy which shoots at the future player position and moves between two targets within a given
# amount of time.
export(NodePath) var player_node export(NodePath) var player_node
onready var player = get_node(player_node) onready var player = get_node(player_node)
@ -10,83 +7,46 @@ onready var player = get_node(player_node)
export(NodePath) var solar_system_node export(NodePath) var solar_system_node
onready var solar_system = get_node(solar_system_node) onready var solar_system = get_node(solar_system_node)
export(Array, NodePath) var target_paths
export var target_fly_time := 5.0
var time_passed_since_fly_start := 0.0
var current_target_index = 0
var bullet_scene = preload("res://Bullet.tscn") var bullet_scene = preload("res://Bullet.tscn")
var bullet_velocity = 40.0 var bullet_velocity = 40.0
var shoot_target var target
var velocity := Vector3.ZERO var velocity := Vector3(0.0, 1.0, 1.0)
func _ready(): func _ready():
# Shoot everytime the timer times out
$ShotTimer.connect("timeout", self, "shoot_bullet") $ShotTimer.connect("timeout", self, "shoot_bullet")
# Set up pathing: Start at the first target
global_transform.origin = get_node(target_paths[0]).global_transform.origin
_set_velocity_to_fly_towards_next_target()
# Picks the next target position from the `target_paths` list and sets the `velocity` appropriately
# so that the target will be reached after `target_fly_time`.
func _set_velocity_to_fly_towards_next_target():
current_target_index = (current_target_index + 1) % target_paths.size()
# Vector from here to the new target
var vector_to_next = (get_node(target_paths[current_target_index]).global_transform.origin
- global_transform.origin)
# s = v * t --> v = s / t
velocity = vector_to_next / target_fly_time
time_passed_since_fly_start = 0.0
func _physics_process(delta): func _physics_process(delta):
# Project the player's position into the future # Project the player's position into the future
shoot_target = _get_future_position( target = _get_future_position(
player.get_center(), player.get_center(),
player.velocity - velocity player.velocity - velocity
) )
# Look at the target that will be shot at, with the gravity as the down vector if target:
if shoot_target: var gravity = solar_system.get_gravitation_acceleration(global_transform.origin)
var gravity = solar_system.get_gravity_acceleration(global_transform.origin) look_at(target, gravity)
look_at(shoot_target, gravity)
# Have we rearched the target?
time_passed_since_fly_start += delta
if time_passed_since_fly_start >= target_fly_time:
# If so, fly towards the next target
_set_velocity_to_fly_towards_next_target()
# Apply velocity
global_transform.origin += velocity * delta global_transform.origin += velocity * delta
func shoot_bullet(): func shoot_bullet():
if not shoot_target: if not target:
# Player can't be hit right now, abort # Player can't be hit right now, abort
return return
# Add a bullet
var instance = bullet_scene.instance() var instance = bullet_scene.instance()
get_tree().get_root().add_child(instance) get_tree().get_root().add_child(instance)
# Make the bullet start at the current position of this object and fly towards the target.
# The own velocity is added because of galilean relativity.
instance.global_transform.origin = global_transform.origin - global_transform.basis.z instance.global_transform.origin = global_transform.origin - global_transform.basis.z
instance.velocity = velocity + (shoot_target - global_transform.origin).normalized() * bullet_velocity instance.velocity = velocity + (target - global_transform.origin).normalized() * bullet_velocity
# Return the position at which a bullet fired forwards and with the velocity `bullet_velocity` would
# intersect with the object that is at `position` and moving with the given `velocity`
func _get_future_position(position, velocity): func _get_future_position(position, velocity):
# Solution to the quadratic formula gives us the time at which the player would be hit # Solution to the quadratic formula gives us the time at which the player would be hit
# TODO: Take acceleration into account as well!
var a = pow(velocity.x, 2) + pow(velocity.y, 2) + pow(velocity.z, 2) - pow(bullet_velocity, 2) var a = pow(velocity.x, 2) + pow(velocity.y, 2) + pow(velocity.z, 2) - pow(bullet_velocity, 2)
var b = 2 * (velocity.x * (position.x - global_transform.origin.x) var b = 2 * (velocity.x * (position.x - global_transform.origin.x)
+ velocity.y * (position.y - global_transform.origin.y) + velocity.y * (position.y - global_transform.origin.y)
@ -107,5 +67,4 @@ func _get_future_position(position, velocity):
var t = min(t1, t2) var t = min(t1, t2)
if t < 0: t = max(t1, t2) if t < 0: t = max(t1, t2)
# Return the position given by the time we calculated
return position + t * velocity return position + t * velocity

View File

@ -1,26 +0,0 @@
extends Spatial
const ray_length = 2000
func _physics_process(delta):
if Input.is_mouse_button_pressed(1):
# If the left mouse button was pressed, cast a ray towards the mouse position
var mouse_pos = get_viewport().get_mouse_position()
var camera = $LerpedFollow/LerpedCamera
var from = camera.project_ray_origin(mouse_pos)
var to = from + camera.project_ray_normal(mouse_pos) * ray_length
var result = get_world().direct_space_state.intersect_ray(from, to)
if not result.empty():
# If there was a collision, set the depth of the water at that position
$Water.set_depth_at_position(result.position, 0.0)
func _ready():
# Create some initial waves
for i in range(0, 11):
$Water.set_depth_at_position(Vector3(-50 + i * 10, -66, -50), 0.0)

File diff suppressed because one or more lines are too long

View File

@ -1,21 +0,0 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/interactive_water/WaterHeights.gd" type="Script" id=1]
[node name="PersistentShaderTexture" type="Node"]
script = ExtResource( 1 )
[node name="Viewport" type="Viewport" parent="."]
size = Vector2( 1, 1 )
transparent_bg = true
handle_input_locally = false
hdr = false
disable_3d = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 3
[node name="Texture" type="ColorRect" parent="Viewport"]
margin_right = 128.0
margin_bottom = 128.0
rect_min_size = Vector2( 128, 128 )

View File

@ -1,72 +0,0 @@
extends Spatial
# Saves every frame as a PNG in the project directory. Use for debugging (with caution)
export var output_debug_textures := false
export var first_output_frame := 0
export var plane_size := 2.0
var _frame_number := 0
var _positions_to_set = []
func set_depth_at_position(pos: Vector3, depth: float):
# Transform the global position into 2D points on the water surface with values between 0 and 1
pos -= translation
var position_2d = Vector2(pos.x, pos.z)
position_2d += Vector2(plane_size, plane_size) / 2.0
position_2d /= plane_size
if position_2d.x < 1.0 and position_2d.y < 1.0 \
and position_2d.x >= 0.0 and position_2d.y >= 0.0:
_positions_to_set.append([position_2d, depth])
func _ready():
$WaterMesh.mesh.size = Vector2(plane_size, plane_size)
# Apply the scale and positioning to the collider
$WaterMesh/StaticBody.scale.x = plane_size / 2.0
$WaterMesh/StaticBody.scale.y = plane_size / 2.0
$WaterMesh/StaticBody.scale.z = plane_size / 2.0
$WaterMesh/StaticBody.translation.y = 0.6 * 40.0
func _physics_process(delta):
# Get result of previous frame
var result = $WaterHeights.get_texture()
# Set it as the data of the water mesh
$WaterMesh.material_override.set_shader_param("water_heights", result)
# Calculate a new frame. First, get the data of the last frame and modify it accordingly
var image_data = result.get_data()
# Set outstanding pixels (after some frames, since the texture isn't initialized until then)
if _frame_number >= 60:
for position_and_depth in _positions_to_set:
var pos = position_and_depth[0]
var depth = position_and_depth[1]
image_data.lock()
image_data.set_pixel(floor(pos.x * 512), floor(pos.y * 512), Color(depth, 0.0, 0.0, 0.0))
image_data.unlock()
_positions_to_set.clear()
# Create an ImageTexture for this new frame
var previous_frame = ImageTexture.new()
previous_frame.create_from_image(image_data)
# Set the previous texture in the shader so that a new texture will be available next frame
$WaterHeights.set_previous_texture(previous_frame)
# Debug output if needed
if output_debug_textures and _frame_number > first_output_frame:
image_data.save_png("res://debugframes/frame%s.png" % [_frame_number])
_frame_number += 1

View File

@ -1,18 +0,0 @@
shader_type spatial;
uniform sampler2D water_heights;
float read_height(sampler2D tex, vec2 uv) {
return texture(tex, uv).r + texture(tex, uv).g / 255.0;
}
void fragment() {
ALBEDO = vec3(0.5, 0.7, 1.0) * (read_height(water_heights, UV) - 0.6) * 3.0;
}
void vertex() {
float vertex_distance = length(VERTEX) * 0.06;
VERTEX += NORMAL * (read_height(water_heights, UV) * 40.0 - pow(2, vertex_distance));
}

View File

@ -1,38 +0,0 @@
[gd_scene load_steps=9 format=2]
[ext_resource path="res://addons/interactive_water/Water.shader" type="Shader" id=1]
[ext_resource path="res://addons/interactive_water/Water.gd" type="Script" id=3]
[ext_resource path="res://addons/interactive_water/WaterUpdateMaterial.tres" type="Material" id=4]
[ext_resource path="res://addons/interactive_water/PersistentShaderTexture.tscn" type="PackedScene" id=5]
[sub_resource type="ViewportTexture" id=1]
viewport_path = NodePath("WaterHeightViewport")
[sub_resource type="ShaderMaterial" id=2]
resource_local_to_scene = true
shader = ExtResource( 1 )
shader_param/water_heights = SubResource( 1 )
[sub_resource type="PlaneMesh" id=3]
subdivide_width = 512
subdivide_depth = 512
[sub_resource type="PlaneShape" id=4]
[node name="Water" type="Spatial"]
script = ExtResource( 3 )
[node name="WaterMesh" type="MeshInstance" parent="."]
material_override = SubResource( 2 )
mesh = SubResource( 3 )
material/0 = null
[node name="StaticBody" type="StaticBody" parent="WaterMesh"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0 )
[node name="CollisionShape" type="CollisionShape" parent="WaterMesh/StaticBody"]
shape = SubResource( 4 )
[node name="WaterHeights" parent="." instance=ExtResource( 5 )]
size = Vector2( 512, 512 )
shader_material = ExtResource( 4 )

View File

@ -1,30 +0,0 @@
extends Node
# A texture which is continuously (statefully) updated by a shader.
#
# Typical usage: Retrieve the current result with `get_texture` and, at the end of the frame,
# re-insert that texture (updated if needed) with `set_previous_texture`.
#
# Note that the given shader needs to accept a `previous_frame` sampler2D. This represents the
# result of the last frame which is used for generating the new result.
export var size := Vector2(64, 64)
export var shader_material: ShaderMaterial
func _ready():
$Viewport/Texture.rect_min_size = size
$Viewport/Texture.rect_size = size
$Viewport.size = size
assert(shader_material)
$Viewport/Texture.material = shader_material
func get_texture():
return $Viewport.get_texture()
func set_previous_texture(texture):
$Viewport/Texture.material.set_shader_param("previous_frame", texture)

View File

@ -1,63 +0,0 @@
shader_type canvas_item;
render_mode unshaded, blend_disabled;
uniform sampler2D previous_frame;
uniform float water_height = 0.6;
uniform float height_damping = 0.13;
uniform float velocity_damping = 0.8;
uniform float spread = 0.94;
// Height and Velocity are encoded in two components each, so RG is height and BA is velocity.
// This is needed to get a workable accuracy.
float read_height(sampler2D tex, vec2 uv) {
return texture(tex, uv).r + texture(tex, uv).g / 255.0;
}
float read_velocity(sampler2D tex, vec2 uv) {
return texture(tex, uv).b + texture(tex, uv).a / 255.0;
}
float get_encoded_remainder(float num) {
return fract(num * 255.0);
}
void fragment() {
// Read values here
float height_here = read_height(previous_frame, UV);
float velocity_here = read_velocity(previous_frame, UV);
// Apply force towards the base height
// This follows from the damped harmonic oscillator equation F = -kx-bv
float force = -height_damping * (height_here - water_height) - velocity_here * velocity_damping;
float acceleration_here = force;
// In addition to each individual height behaving like a spring, neighbouring heights are
// "connected by springs" as well:
// Read more samples
float uv_mod = 1.0 / float(textureSize(previous_frame, 0).x);
float height_up = read_height(previous_frame, UV + vec2(0.0, uv_mod));
float height_down = read_height(previous_frame, UV + vec2(0.0, -uv_mod));
float height_left = read_height(previous_frame, UV + vec2(-uv_mod, 0.0));
float height_right = read_height(previous_frame, UV + vec2(uv_mod, 0.0));
// Calculate differences
float up_delta = spread * (height_up - height_here);
float down_delta = spread * (height_down - height_here);
float left_delta = spread * (height_left - height_here);
float right_delta = spread * (height_right - height_here);
// Use the biggest delta to apply to this height
float sum_delta = max(max(left_delta, right_delta), max(up_delta, down_delta));
// Apply velocity and height
velocity_here += sum_delta + acceleration_here;
height_here += velocity_here;
// Write to the texture
COLOR = vec4(
height_here, get_encoded_remainder(height_here),
velocity_here, get_encoded_remainder(velocity_here)
);
}

View File

@ -1,10 +0,0 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=2]
[ext_resource path="res://addons/interactive_water/WaterUpdate.shader" type="Shader" id=1]
[resource]
shader = ExtResource( 1 )
shader_param/water_height = 0.6
shader_param/height_damping = 0.13
shader_param/velocity_damping = 0.8
shader_param/spread = 0.94

View File

@ -9,11 +9,6 @@
config_version=4 config_version=4
_global_script_classes=[ { _global_script_classes=[ {
"base": "Object",
"class": "DeadzoneInput",
"language": "GDScript",
"path": "res://DeadzoneInput.gd"
}, {
"base": "KinematicBody", "base": "KinematicBody",
"class": "MovingPlatform", "class": "MovingPlatform",
"language": "GDScript", "language": "GDScript",
@ -30,7 +25,6 @@ _global_script_classes=[ {
"path": "res://Planets.gd" "path": "res://Planets.gd"
} ] } ]
_global_script_class_icons={ _global_script_class_icons={
"DeadzoneInput": "",
"MovingPlatform": "", "MovingPlatform": "",
"Planet": "", "Planet": "",
"SolarSystem": "" "SolarSystem": ""
@ -69,38 +63,28 @@ ui_down={
] ]
} }
move_up={ move_up={
"deadzone": 0.0, "deadzone": 0.5,
"events": [ 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) "events": [ 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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
] ]
} }
move_down={ move_down={
"deadzone": 0.0, "deadzone": 0.5,
"events": [ 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) "events": [ 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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
] ]
} }
move_left={ move_left={
"deadzone": 0.0, "deadzone": 0.5,
"events": [ 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) "events": [ 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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
] ]
} }
move_right={ move_right={
"deadzone": 0.0, "deadzone": 0.5,
"events": [ 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) "events": [ 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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
] ]
} }
jump={ jump={
"deadzone": 0.5, "deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null) "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
]
}
movement_modifier={
"deadzone": 0.5,
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":6,"pressure":0.0,"pressed":false,"script":null)
] ]
} }