generated from krampus/template-godot4
Compare commits
No commits in common. "0931abce560c382afee90a8743445f1d6d73cd4a" and "96c73c5587fad53583752d5112d557248f1697d3" have entirely different histories.
0931abce56
...
96c73c5587
Binary file not shown.
BIN
assets/ui/lifebar_fill_damage.png (Stored with Git LFS)
BIN
assets/ui/lifebar_fill_damage.png (Stored with Git LFS)
Binary file not shown.
|
@ -1,34 +0,0 @@
|
||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://dv8757eh7bgmm"
|
|
||||||
path="res://.godot/imported/lifebar_fill_damage.png-844591e686129d7c89c44d44c5c8df44.ctex"
|
|
||||||
metadata={
|
|
||||||
"vram_texture": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/ui/lifebar_fill_damage.png"
|
|
||||||
dest_files=["res://.godot/imported/lifebar_fill_damage.png-844591e686129d7c89c44d44c5c8df44.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=0
|
|
||||||
compress/high_quality=false
|
|
||||||
compress/lossy_quality=0.7
|
|
||||||
compress/hdr_compression=1
|
|
||||||
compress/normal_map=0
|
|
||||||
compress/channel_pack=0
|
|
||||||
mipmaps/generate=false
|
|
||||||
mipmaps/limit=-1
|
|
||||||
roughness/mode=0
|
|
||||||
roughness/src_normal=""
|
|
||||||
process/fix_alpha_border=true
|
|
||||||
process/premult_alpha=false
|
|
||||||
process/normal_map_invert_y=false
|
|
||||||
process/hdr_as_srgb=false
|
|
||||||
process/hdr_clamp_exposure=false
|
|
||||||
process/size_limit=0
|
|
||||||
detect_3d/compress_to=1
|
|
|
@ -22,9 +22,6 @@ const IRON_DAMPING := 9999.0
|
||||||
physics_material_override = normal_physics
|
physics_material_override = normal_physics
|
||||||
iron_ball = value
|
iron_ball = value
|
||||||
|
|
||||||
## Base damage inflicted on impact with a player
|
|
||||||
@export var base_damage := 15.0
|
|
||||||
|
|
||||||
var _zones: Array[BallZone] = []
|
var _zones: Array[BallZone] = []
|
||||||
|
|
||||||
@onready var normal_physics: PhysicsMaterial = preload(
|
@onready var normal_physics: PhysicsMaterial = preload(
|
||||||
|
|
|
@ -35,7 +35,6 @@ class ScenePromise:
|
||||||
extends Promise
|
extends Promise
|
||||||
|
|
||||||
func resolve(res: Variant) -> void:
|
func resolve(res: Variant) -> void:
|
||||||
@warning_ignore("unsafe_cast")
|
|
||||||
var instance: Node = (res as PackedScene).instantiate()
|
var instance: Node = (res as PackedScene).instantiate()
|
||||||
super.resolve(instance)
|
super.resolve(instance)
|
||||||
|
|
||||||
|
@ -80,6 +79,16 @@ func _finish_scene_load(instance: Node) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
|
# REMOVEME
|
||||||
|
if Input.is_action_just_pressed("debug_1"):
|
||||||
|
viewport.hit_lag(1)
|
||||||
|
if Input.is_action_just_pressed("debug_2"):
|
||||||
|
viewport.hit_lag_small()
|
||||||
|
if Input.is_action_just_pressed("debug_3"):
|
||||||
|
viewport.hit_lag_big()
|
||||||
|
if Input.is_action_just_pressed("debug_4"):
|
||||||
|
viewport.hit_lag_huge()
|
||||||
|
|
||||||
if _loading_resources and not loading_screen.visible:
|
if _loading_resources and not loading_screen.visible:
|
||||||
loader_transition.play("fade_in")
|
loader_transition.play("fade_in")
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,7 @@ script = ExtResource("3_rmm5i")
|
||||||
|
|
||||||
[node name="Viewport" type="SubViewport" parent="RootControl/Rumbler/ViewportContainer"]
|
[node name="Viewport" type="SubViewport" parent="RootControl/Rumbler/ViewportContainer"]
|
||||||
handle_input_locally = false
|
handle_input_locally = false
|
||||||
|
msaa_2d = 3
|
||||||
msaa_3d = 3
|
msaa_3d = 3
|
||||||
screen_space_aa = 1
|
screen_space_aa = 1
|
||||||
use_taa = true
|
use_taa = true
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
extends Area3D
|
|
||||||
## World player hitbox
|
|
||||||
|
|
||||||
signal ball_collision(ball: GameBall)
|
|
||||||
|
|
||||||
@export var ignored_balls: Array[GameBall] = []
|
|
||||||
|
|
||||||
@onready var shot_setup: ShotSetup = $".."
|
|
||||||
@onready var physics_ball: GameBall = %PhysicsBall
|
|
||||||
|
|
||||||
|
|
||||||
func _on_ball_entered(ball: GameBall) -> void:
|
|
||||||
if not ball in ignored_balls:
|
|
||||||
ball_collision.emit(ball)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_body_entered(body: Node3D) -> void:
|
|
||||||
if body is GameBall:
|
|
||||||
_on_ball_entered(body as GameBall)
|
|
|
@ -31,9 +31,6 @@ const WASTED_BALL_RETURN_DELAY := 3.5
|
||||||
## Shots above this threshold trigger a "big power" effect
|
## Shots above this threshold trigger a "big power" effect
|
||||||
const BIG_POWER_THRESHOLD := 0.7
|
const BIG_POWER_THRESHOLD := 0.7
|
||||||
|
|
||||||
## Amount of life lost when landing in water
|
|
||||||
const WATER_DAMAGE := 10.0
|
|
||||||
|
|
||||||
## In Driving Range mode, the ball can be retrieved in the shot phase.
|
## In Driving Range mode, the ball can be retrieved in the shot phase.
|
||||||
@export var driving_range := false
|
@export var driving_range := false
|
||||||
|
|
||||||
|
@ -161,7 +158,7 @@ func _init_deferred() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_init_deferred.call_deferred()
|
call_deferred("_init_deferred")
|
||||||
|
|
||||||
|
|
||||||
func _set_camera_distance(value: float) -> void:
|
func _set_camera_distance(value: float) -> void:
|
||||||
|
@ -503,7 +500,6 @@ func _on_ball_entered_water() -> void:
|
||||||
if phase == Phase.SHOT:
|
if phase == Phase.SHOT:
|
||||||
physics_ball.freeze = true
|
physics_ball.freeze = true
|
||||||
hud.play_wasted_animation()
|
hud.play_wasted_animation()
|
||||||
player.life -= WATER_DAMAGE
|
|
||||||
ball_return_timer.start(WASTED_BALL_RETURN_DELAY)
|
ball_return_timer.start(WASTED_BALL_RETURN_DELAY)
|
||||||
|
|
||||||
|
|
||||||
|
@ -524,11 +520,6 @@ func _on_ball_return_timer_timeout() -> void:
|
||||||
return_ball()
|
return_ball()
|
||||||
|
|
||||||
|
|
||||||
func _on_hitbox_ball_collision(ball: GameBall) -> void:
|
|
||||||
# TODO play animation
|
|
||||||
player.life -= ball.base_damage
|
|
||||||
|
|
||||||
|
|
||||||
## Create a new instance for the given player.
|
## Create a new instance for the given player.
|
||||||
static func create(_player: WorldPlayer) -> ShotSetup:
|
static func create(_player: WorldPlayer) -> ShotSetup:
|
||||||
var instance: ShotSetup = ShotSetup.scene.instantiate()
|
var instance: ShotSetup = ShotSetup.scene.instantiate()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=19 format=3 uid="uid://cy7t2tc4y3b4"]
|
[gd_scene load_steps=17 format=3 uid="uid://cy7t2tc4y3b4"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/player/shot_setup/shot_setup.gd" id="1_r6ei4"]
|
[ext_resource type="Script" path="res://src/player/shot_setup/shot_setup.gd" id="1_r6ei4"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dfttci386ohip" path="res://src/equipment/balls/physics_ball/physics_ball.tscn" id="2_1i5j5"]
|
[ext_resource type="PackedScene" uid="uid://dfttci386ohip" path="res://src/equipment/balls/physics_ball/physics_ball.tscn" id="2_1i5j5"]
|
||||||
|
@ -6,7 +6,6 @@
|
||||||
[ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="3_e4aur"]
|
[ext_resource type="PackedScene" uid="uid://1s3gywmoi20e" path="res://src/characters/player_characters/gfolf_girl/gfolf_girl.tscn" id="3_e4aur"]
|
||||||
[ext_resource type="PackedScene" uid="uid://fht6j87o8ecr" path="res://src/ui/3d/projectile_arc/projectile_arc.tscn" id="4_ry2ho"]
|
[ext_resource type="PackedScene" uid="uid://fht6j87o8ecr" path="res://src/ui/3d/projectile_arc/projectile_arc.tscn" id="4_ry2ho"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dbdul15c4oblg" path="res://src/ui/3d/projected_target.tscn" id="6_mynqj"]
|
[ext_resource type="PackedScene" uid="uid://dbdul15c4oblg" path="res://src/ui/3d/projected_target.tscn" id="6_mynqj"]
|
||||||
[ext_resource type="Script" path="res://src/player/shot_setup/hitbox.gd" id="7_uh8kn"]
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lnol1"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lnol1"]
|
||||||
albedo_color = Color(0, 0.537255, 1, 1)
|
albedo_color = Color(0, 0.537255, 1, 1)
|
||||||
|
@ -204,9 +203,6 @@ _data = {
|
||||||
"swing_delay": SubResource("Animation_u8k07")
|
"swing_delay": SubResource("Animation_u8k07")
|
||||||
}
|
}
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_xvvdi"]
|
|
||||||
radius = 1.5
|
|
||||||
|
|
||||||
[node name="ShotSetup" type="Node3D"]
|
[node name="ShotSetup" type="Node3D"]
|
||||||
script = ExtResource("1_r6ei4")
|
script = ExtResource("1_r6ei4")
|
||||||
|
|
||||||
|
@ -364,16 +360,7 @@ libraries = {
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
one_shot = true
|
one_shot = true
|
||||||
|
|
||||||
[node name="Hitbox" type="Area3D" parent="." node_paths=PackedStringArray("ignored_balls")]
|
|
||||||
script = ExtResource("7_uh8kn")
|
|
||||||
ignored_balls = [NodePath("../BallPoint/PhysicsBall")]
|
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Hitbox"]
|
|
||||||
shape = SubResource("SphereShape3D_xvvdi")
|
|
||||||
|
|
||||||
[connection signal="body_entered" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_body_entered"]
|
[connection signal="body_entered" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_body_entered"]
|
||||||
[connection signal="entered_water" from="BallPoint/PhysicsBall" to="." method="_on_ball_entered_water"]
|
[connection signal="entered_water" from="BallPoint/PhysicsBall" to="." method="_on_ball_entered_water"]
|
||||||
[connection signal="sleeping_state_changed" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_sleeping_state_changed"]
|
[connection signal="sleeping_state_changed" from="BallPoint/PhysicsBall" to="." method="_on_physics_ball_sleeping_state_changed"]
|
||||||
[connection signal="timeout" from="BallReturnTimer" to="." method="_on_ball_return_timer_timeout"]
|
[connection signal="timeout" from="BallReturnTimer" to="." method="_on_ball_return_timer_timeout"]
|
||||||
[connection signal="ball_collision" from="Hitbox" to="." method="_on_hitbox_ball_collision"]
|
|
||||||
[connection signal="body_entered" from="Hitbox" to="Hitbox" method="_on_body_entered"]
|
|
||||||
|
|
|
@ -1,547 +0,0 @@
|
||||||
[gd_resource type="Shader" format=3 uid="uid://dcbswuorsomae"]
|
|
||||||
|
|
||||||
[resource]
|
|
||||||
code = "shader_type spatial;
|
|
||||||
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform;
|
|
||||||
|
|
||||||
/* This shader is generated based upon the debug views you have selected.
|
|
||||||
* The terrain function depends on this shader. So don't change:
|
|
||||||
* - vertex positioning in vertex()
|
|
||||||
* - terrain normal calculation in fragment()
|
|
||||||
* - the last function being fragment() as the editor injects code before the closing }
|
|
||||||
*
|
|
||||||
* Most will only want to customize the material calculation and PBR application in fragment()
|
|
||||||
*
|
|
||||||
* Uniforms that begin with _ are private and will not display in the inspector. However,
|
|
||||||
* you can set them via code. You are welcome to create more of your own hidden uniforms.
|
|
||||||
*
|
|
||||||
* This system only supports albedo, height, normal, roughness. Most textures don't need the other
|
|
||||||
* PBR channels. Height can be used as an approximation for AO. For the rare textures do need
|
|
||||||
* additional channels, you can add maps for that one texture. e.g. an emissive map for lava.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Private uniforms
|
|
||||||
|
|
||||||
uniform float _region_size = 1024.0;
|
|
||||||
uniform float _region_texel_size = 0.0009765625; // = 1/1024
|
|
||||||
uniform float _vertex_spacing = 1.0;
|
|
||||||
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
|
|
||||||
uniform int _region_map_size = 32;
|
|
||||||
uniform int _region_map[1024];
|
|
||||||
uniform vec2 _region_locations[1024];
|
|
||||||
uniform highp sampler2DArray _height_maps : repeat_disable;
|
|
||||||
uniform highp usampler2DArray _control_maps : repeat_disable;
|
|
||||||
uniform highp sampler2DArray _color_maps : source_color, filter_nearest_mipmap_anisotropic, repeat_disable;
|
|
||||||
uniform highp sampler2DArray _texture_array_albedo : source_color, filter_nearest_mipmap_anisotropic, repeat_enable;
|
|
||||||
uniform highp sampler2DArray _texture_array_normal : hint_normal, filter_nearest_mipmap_anisotropic, repeat_enable;
|
|
||||||
uniform highp sampler2D noise_texture : source_color, filter_nearest_mipmap_anisotropic, repeat_enable;
|
|
||||||
|
|
||||||
uniform float _texture_uv_scale_array[32];
|
|
||||||
uniform float _texture_detile_array[32];
|
|
||||||
uniform vec4 _texture_color_array[32];
|
|
||||||
uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2
|
|
||||||
uniform uint _mouse_layer = 0x80000000u; // Layer 32
|
|
||||||
|
|
||||||
// Public uniforms
|
|
||||||
uniform float vertex_normals_distance : hint_range(0, 1024) = 128.0;
|
|
||||||
uniform bool height_blending = true;
|
|
||||||
uniform float blend_sharpness : hint_range(0, 1) = 0.87;
|
|
||||||
uniform float auto_slope : hint_range(0, 10) = 1.0;
|
|
||||||
uniform float auto_height_reduction : hint_range(0, 1) = 0.1;
|
|
||||||
uniform int auto_base_texture : hint_range(0, 31) = 0;
|
|
||||||
uniform int auto_overlay_texture : hint_range(0, 31) = 1;
|
|
||||||
|
|
||||||
uniform vec3 macro_variation1 : source_color = vec3(1.);
|
|
||||||
uniform vec3 macro_variation2 : source_color = vec3(1.);
|
|
||||||
|
|
||||||
// Generic noise at 3 scales, which can be used for anything
|
|
||||||
uniform float noise1_scale : hint_range(0.001, 1.) = 0.04; // Used for macro variation 1. Scaled up 10x
|
|
||||||
uniform float noise1_angle : hint_range(0, 6.283) = 0.;
|
|
||||||
uniform vec2 noise1_offset = vec2(0.5);
|
|
||||||
uniform float noise2_scale : hint_range(0.001, 1.) = 0.076; // Used for macro variation 2. Scaled up 10x
|
|
||||||
uniform float noise3_scale : hint_range(0.001, 1.) = 0.225; // Used for texture blending edge.
|
|
||||||
|
|
||||||
// Varyings & Types
|
|
||||||
|
|
||||||
struct Material {
|
|
||||||
vec4 alb_ht;
|
|
||||||
vec4 nrm_rg;
|
|
||||||
int base;
|
|
||||||
int over;
|
|
||||||
float blend;
|
|
||||||
};
|
|
||||||
|
|
||||||
varying flat vec3 v_vertex; // World coordinate vertex location
|
|
||||||
varying flat vec3 v_camera_pos;
|
|
||||||
varying float v_vertex_xz_dist;
|
|
||||||
varying flat ivec3 v_region;
|
|
||||||
varying flat vec2 v_uv_offset;
|
|
||||||
varying flat vec2 v_uv2_offset;
|
|
||||||
varying vec3 v_normal;
|
|
||||||
varying float v_region_border_mask;
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
// Vertex
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
// Takes in UV world space coordinates, returns ivec3 with:
|
|
||||||
// XY: (0 to _region_size) coordinates within a region
|
|
||||||
// Z: layer index used for texturearrays, -1 if not in a region
|
|
||||||
ivec3 get_region_uv(const vec2 uv) {
|
|
||||||
ivec2 pos = ivec2(floor(uv * _region_texel_size)) + (_region_map_size / 2);
|
|
||||||
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
|
|
||||||
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
|
|
||||||
return ivec3(ivec2(mod(uv,_region_size)), layer_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes in UV2 region space coordinates, returns vec3 with:
|
|
||||||
// XY: (0 to 1) coordinates within a region
|
|
||||||
// Z: layer index used for texturearrays, -1 if not in a region
|
|
||||||
vec3 get_region_uv2(const vec2 uv2) {
|
|
||||||
// Remove Texel Offset to ensure correct region index.
|
|
||||||
ivec2 pos = ivec2(floor(uv2 - vec2(_region_texel_size * 0.5))) + (_region_map_size / 2);
|
|
||||||
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
|
|
||||||
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
|
|
||||||
return vec3(uv2 - _region_locations[layer_index], float(layer_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
// World Noise
|
|
||||||
uniform float world_noise_region_blend : hint_range(0.05, 0.95, 0.01) = 0.33;
|
|
||||||
uniform int world_noise_max_octaves : hint_range(0, 15) = 4;
|
|
||||||
uniform int world_noise_min_octaves : hint_range(0, 15) = 2;
|
|
||||||
uniform float world_noise_lod_distance : hint_range(0, 40000, 1) = 7500.;
|
|
||||||
uniform float world_noise_scale : hint_range(0.25, 20, 0.01) = 5.0;
|
|
||||||
uniform float world_noise_height : hint_range(0, 1000, 0.1) = 64.0;
|
|
||||||
uniform vec3 world_noise_offset = vec3(0.0);
|
|
||||||
|
|
||||||
// Takes in UV2 region space coordinates, returns 1.0 or 0.0 if a region is present or not.
|
|
||||||
float check_region(const vec2 uv2) {
|
|
||||||
ivec2 pos = ivec2(floor(uv2)) + (_region_map_size / 2);
|
|
||||||
int layer_index = 0;
|
|
||||||
if (uint(pos.x | pos.y) < uint(_region_map_size)) {
|
|
||||||
layer_index = clamp(_region_map[ pos.y * _region_map_size + pos.x ] - 1, -1, 0) + 1;
|
|
||||||
}
|
|
||||||
return float(layer_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes in UV2 region space coordinates, returns a blend value (0 - 1 range) between empty, and valid regions
|
|
||||||
float region_blend(vec2 uv2) {
|
|
||||||
uv2 -= 0.5;
|
|
||||||
const vec2 offset = vec2(0.0,1.0);
|
|
||||||
float a = check_region(uv2 + offset.xy);
|
|
||||||
float b = check_region(uv2 + offset.yy);
|
|
||||||
float c = check_region(uv2 + offset.yx);
|
|
||||||
float d = check_region(uv2 + offset.xx);
|
|
||||||
vec2 w = smoothstep(vec2(0.0), vec2(1.0), fract(uv2));
|
|
||||||
float blend = mix(mix(d, c, w.x), mix(a, b, w.x), w.y);
|
|
||||||
return 1.0 - blend;
|
|
||||||
}
|
|
||||||
|
|
||||||
float hashf(float f) {
|
|
||||||
return fract(sin(f) * 1e4);
|
|
||||||
}
|
|
||||||
|
|
||||||
float hashv2(vec2 v) {
|
|
||||||
return fract(1e4 * sin(fma(17.0, v.x, v.y * 0.1)) * (0.1 + abs(sin(fma(v.y, 13.0, v.x)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://iquilezles.org/articles/morenoise/
|
|
||||||
vec3 noise2D(vec2 x) {
|
|
||||||
vec2 f = fract(x);
|
|
||||||
// Quintic Hermine Curve. Similar to SmoothStep()
|
|
||||||
vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0);
|
|
||||||
vec2 du = 30.0*f*f*(f*(f-2.0)+1.0);
|
|
||||||
|
|
||||||
vec2 p = floor(x);
|
|
||||||
|
|
||||||
// Four corners in 2D of a tile
|
|
||||||
float a = hashv2( p+vec2(0,0) );
|
|
||||||
float b = hashv2( p+vec2(1,0) );
|
|
||||||
float c = hashv2( p+vec2(0,1) );
|
|
||||||
float d = hashv2( p+vec2(1,1) );
|
|
||||||
|
|
||||||
// Mix 4 corner percentages
|
|
||||||
float k0 = a;
|
|
||||||
float k1 = b - a;
|
|
||||||
float k2 = c - a;
|
|
||||||
float k3 = a - b - c + d;
|
|
||||||
return vec3( k0 + k1 * u.x + k2 * u.y + k3 * u.x * u.y,
|
|
||||||
du * ( vec2(k1, k2) + k3 * u.yx) );
|
|
||||||
}
|
|
||||||
|
|
||||||
float world_noise(vec2 p) {
|
|
||||||
float a = 0.0;
|
|
||||||
float b = 1.0;
|
|
||||||
vec2 d = vec2(0.0);
|
|
||||||
|
|
||||||
int octaves = int( clamp(
|
|
||||||
float(world_noise_max_octaves) - floor(v_vertex_xz_dist/(world_noise_lod_distance)),
|
|
||||||
float(world_noise_min_octaves), float(world_noise_max_octaves)) );
|
|
||||||
|
|
||||||
for( int i=0; i < octaves; i++ ) {
|
|
||||||
vec3 n = noise2D(p);
|
|
||||||
d += n.yz;
|
|
||||||
a += b * n.x / (1.0 + dot(d,d));
|
|
||||||
b *= 0.5;
|
|
||||||
p = mat2( vec2(0.8, -0.6), vec2(0.6, 0.8) ) * p * 2.0;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
float get_noise_height(const vec2 uv) {
|
|
||||||
float weight = region_blend(uv);
|
|
||||||
// only calculate world noise when it could be visibile.
|
|
||||||
if (weight <= 1.0 - world_noise_region_blend) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
//TODO: Offset/scale UVs are semi-dependent upon region size 1024. Base on v_vertex.xz instead
|
|
||||||
float noise = world_noise((uv + world_noise_offset.xz * 1024. / _region_size) * world_noise_scale * _region_size / 1024. * .1) *
|
|
||||||
world_noise_height * 10. + world_noise_offset.y * 100.;
|
|
||||||
weight = smoothstep(1.0 - world_noise_region_blend, 1.0, weight);
|
|
||||||
return mix(0.0, noise, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// World Noise end
|
|
||||||
|
|
||||||
// 1 lookup
|
|
||||||
float get_height(vec2 uv) {
|
|
||||||
highp float height = 0.0;
|
|
||||||
vec3 region = get_region_uv2(uv);
|
|
||||||
if (region.z >= 0.) {
|
|
||||||
height = texture(_height_maps, region).r;
|
|
||||||
}
|
|
||||||
// World Noise
|
|
||||||
if (_background_mode == 2u) {
|
|
||||||
height += get_noise_height(uv);
|
|
||||||
}
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vertex() {
|
|
||||||
// Get camera pos in world vertex coords
|
|
||||||
v_camera_pos = INV_VIEW_MATRIX[3].xyz;
|
|
||||||
|
|
||||||
// Get vertex of flat plane in world coordinates and set world UV
|
|
||||||
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
|
||||||
|
|
||||||
// Camera distance to vertex on flat plane
|
|
||||||
v_vertex_xz_dist = length(v_vertex.xz - v_camera_pos.xz);
|
|
||||||
|
|
||||||
// UV coordinates in world space. Values are 0 to _region_size within regions
|
|
||||||
UV = round(v_vertex.xz * _vertex_density);
|
|
||||||
|
|
||||||
// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
|
|
||||||
UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size));
|
|
||||||
|
|
||||||
// Discard vertices for Holes. 1 lookup
|
|
||||||
v_region = get_region_uv(UV);
|
|
||||||
uint control = texelFetch(_control_maps, v_region, 0).r;
|
|
||||||
bool hole = bool(control >>2u & 0x1u);
|
|
||||||
|
|
||||||
// Show holes to all cameras except mouse camera (on exactly 1 layer)
|
|
||||||
if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) &&
|
|
||||||
(hole || (_background_mode == 0u && (get_region_uv(UV - _region_texel_size) & v_region).z < 0))) {
|
|
||||||
VERTEX.x = 0. / 0.;
|
|
||||||
} else {
|
|
||||||
// Set final vertex height & calculate vertex normals. 3 lookups.
|
|
||||||
VERTEX.y = get_height(UV2);
|
|
||||||
v_vertex.y = VERTEX.y;
|
|
||||||
v_normal = vec3(
|
|
||||||
v_vertex.y - get_height(UV2 + vec2(_region_texel_size, 0)),
|
|
||||||
_vertex_spacing,
|
|
||||||
v_vertex.y - get_height(UV2 + vec2(0, _region_texel_size))
|
|
||||||
);
|
|
||||||
// Due to a bug caused by the GPUs linear interpolation across edges of region maps,
|
|
||||||
// mask region edges and use vertex normals only across region boundaries.
|
|
||||||
v_region_border_mask = mod(UV.x + 2.5, _region_size) - fract(UV.x) < 5.0 || mod(UV.y + 2.5, _region_size) - fract(UV.y) < 5.0 ? 1. : 0.;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform UVs to local to avoid poor precision during varying interpolation.
|
|
||||||
v_uv_offset = MODEL_MATRIX[3].xz * _vertex_density;
|
|
||||||
UV -= v_uv_offset;
|
|
||||||
v_uv2_offset = v_uv_offset * _region_texel_size;
|
|
||||||
UV2 -= v_uv2_offset;
|
|
||||||
|
|
||||||
// Convert model space to view space w/ skip_vertex_transform render mode
|
|
||||||
VERTEX = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
|
||||||
VERTEX = (VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
|
||||||
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
|
|
||||||
BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
|
|
||||||
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////
|
|
||||||
// Fragment
|
|
||||||
////////////////////////
|
|
||||||
|
|
||||||
// 0 - 3 lookups
|
|
||||||
vec3 get_normal(vec2 uv, out vec3 tangent, out vec3 binormal) {
|
|
||||||
float u, v, height;
|
|
||||||
vec3 normal;
|
|
||||||
// Use vertex normals within radius of vertex_normals_distance, and along region borders.
|
|
||||||
if ((v_region_border_mask > 0.5 || v_vertex_xz_dist < vertex_normals_distance) && v_region.z >= 0) {
|
|
||||||
normal = normalize(v_normal);
|
|
||||||
} else {
|
|
||||||
height = get_height(uv);
|
|
||||||
u = height - get_height(uv + vec2(_region_texel_size, 0));
|
|
||||||
v = height - get_height(uv + vec2(0, _region_texel_size));
|
|
||||||
normal = normalize(vec3(u, _vertex_spacing, v));
|
|
||||||
}
|
|
||||||
tangent = normalize(cross(normal, vec3(0, 0, 1)));
|
|
||||||
binormal = normalize(cross(normal, tangent));
|
|
||||||
return normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 unpack_normal(vec4 rgba) {
|
|
||||||
vec3 n = fma(rgba.xzy, vec3(2.0, 2.0, -2.0), vec3(-1.0, -1.0, 1.0));
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 pack_normal(vec3 n, float a) {
|
|
||||||
return vec4(fma(n.xzy, vec3(0.5, -0.5, 0.5), vec3(0.5)), a);
|
|
||||||
}
|
|
||||||
|
|
||||||
float random(in vec2 xy) {
|
|
||||||
return fract(sin(dot(xy, vec2(12.9898, 78.233))) * 43758.5453);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 rotate(vec2 v, float cosa, float sina) {
|
|
||||||
return vec2(fma(cosa, v.x, - sina * v.y), fma(sina, v.x, cosa * v.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moves a point around a pivot point.
|
|
||||||
vec2 rotate_around(vec2 point, vec2 pivot, float angle){
|
|
||||||
float x = pivot.x + (point.x - pivot.x) * cos(angle) - (point.y - pivot.y) * sin(angle);
|
|
||||||
float y = pivot.y + (point.x - pivot.x) * sin(angle) + (point.y - pivot.y) * cos(angle);
|
|
||||||
return vec2(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 height_blend(vec4 a_value, float a_height, vec4 b_value, float b_height, float blend) {
|
|
||||||
if(height_blending) {
|
|
||||||
float ma = max(a_height + (1.0 - blend), b_height + blend) - (1.001 - blend_sharpness);
|
|
||||||
float b1 = max(a_height + (1.0 - blend) - ma, 0.0);
|
|
||||||
float b2 = max(b_height + blend - ma, 0.0);
|
|
||||||
return (a_value * b1 + b_value * b2) / (b1 + b2);
|
|
||||||
} else {
|
|
||||||
float contrast = 1.0 - blend_sharpness;
|
|
||||||
float factor = (blend - contrast) / contrast;
|
|
||||||
return mix(a_value, b_value, clamp(factor, 0.0, 1.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 detiling(vec2 uv, vec2 uv_center, int mat_id, inout float normal_rotation){
|
|
||||||
if (_texture_detile_array[mat_id] >= 0.001){
|
|
||||||
uv_center = floor(uv_center) + 0.5;
|
|
||||||
float detile = fma(random(uv_center), 2.0, -1.0) * TAU * _texture_detile_array[mat_id]; // -180deg to 180deg
|
|
||||||
uv = rotate_around(uv, uv_center, detile);
|
|
||||||
// Accumulate total rotation for normal rotation
|
|
||||||
normal_rotation += detile;
|
|
||||||
}
|
|
||||||
return uv;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 rotate_normal(vec2 normal, float angle) {
|
|
||||||
angle = fma(PI, 0.5, angle);
|
|
||||||
float new_y = dot(vec2(cos(angle), sin(angle)), normal);
|
|
||||||
angle = fma(PI, -0.5, angle);
|
|
||||||
float new_x = dot(vec2(cos(angle) ,sin(angle)) ,normal);
|
|
||||||
return vec2(new_x, new_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2-4 lookups
|
|
||||||
void get_material(vec2 base_uv, uint control, ivec3 iuv_center, vec3 normal, out Material out_mat) {
|
|
||||||
out_mat = Material(vec4(0.), vec4(0.), 0, 0, 0.0);
|
|
||||||
vec2 uv_center = vec2(iuv_center.xy);
|
|
||||||
int region = iuv_center.z;
|
|
||||||
|
|
||||||
// Enable Autoshader if outside regions or painted in regions, otherwise manual painted
|
|
||||||
bool auto_shader = region < 0 || bool(control & 0x1u);
|
|
||||||
out_mat.base = int(auto_shader) * auto_base_texture + int(!auto_shader) * int(control >>27u & 0x1Fu);
|
|
||||||
out_mat.over = int(auto_shader) * auto_overlay_texture + int(!auto_shader) * int(control >> 22u & 0x1Fu);
|
|
||||||
out_mat.blend = float(auto_shader) * clamp(
|
|
||||||
dot(vec3(0., 1., 0.), normal * auto_slope * 2. - (auto_slope * 2. - 1.))
|
|
||||||
- auto_height_reduction * .01 * v_vertex.y // Reduce as vertices get higher
|
|
||||||
, 0., 1.) +
|
|
||||||
float(!auto_shader) * float(control >>14u & 0xFFu) * 0.003921568627450; // 1./255.0
|
|
||||||
|
|
||||||
// Control map scale & rotation, apply to both base and
|
|
||||||
// uv_center. Translate uv center to the current region.
|
|
||||||
uv_center += _region_locations[region] * _region_size;
|
|
||||||
// Define base scale from control map value as array index. 0.5 as baseline.
|
|
||||||
float[8] scale_array = { 0.5, 0.4, 0.3, 0.2, 0.1, 0.8, 0.7, 0.6};
|
|
||||||
float control_scale = scale_array[(control >>7u & 0x7u)];
|
|
||||||
base_uv *= control_scale;
|
|
||||||
uv_center *= control_scale;
|
|
||||||
// calculate baseline derivatives
|
|
||||||
vec2 ddx = dFdxCoarse(base_uv);
|
|
||||||
vec2 ddy = dFdyCoarse(base_uv);
|
|
||||||
// Apply global uv rotation from control map.
|
|
||||||
float uv_rotation = float(control >>10u & 0xFu) / 16. * TAU;
|
|
||||||
base_uv = rotate_around(base_uv, vec2(0), uv_rotation);
|
|
||||||
uv_center = rotate_around(uv_center, vec2(0), uv_rotation);
|
|
||||||
|
|
||||||
vec2 matUV = base_uv;
|
|
||||||
vec4 albedo_ht = vec4(0.);
|
|
||||||
vec4 normal_rg = vec4(0.5f, 0.5f, 1.0f, 1.0f);
|
|
||||||
vec4 albedo_far = vec4(0.);
|
|
||||||
vec4 normal_far = vec4(0.5f, 0.5f, 1.0f, 1.0f);
|
|
||||||
float mat_scale = _texture_uv_scale_array[out_mat.base];
|
|
||||||
float normal_angle = uv_rotation;
|
|
||||||
vec2 ddx1 = ddx;
|
|
||||||
vec2 ddy1 = ddy;
|
|
||||||
|
|
||||||
matUV = detiling(base_uv * mat_scale, uv_center * mat_scale, out_mat.base, normal_angle);
|
|
||||||
ddx1 *= mat_scale;
|
|
||||||
ddy1 *= mat_scale;
|
|
||||||
albedo_ht = textureGrad(_texture_array_albedo, vec3(matUV, float(out_mat.base)), ddx1, ddy1);
|
|
||||||
normal_rg = textureGrad(_texture_array_normal, vec3(matUV, float(out_mat.base)), ddx1, ddy1);
|
|
||||||
|
|
||||||
// Unpack & rotate base normal for blending
|
|
||||||
normal_rg.xz = unpack_normal(normal_rg).xz;
|
|
||||||
normal_rg.xz = rotate_normal(normal_rg.xz, normal_angle);
|
|
||||||
|
|
||||||
// Apply color to base
|
|
||||||
albedo_ht.rgb *= _texture_color_array[out_mat.base].rgb;
|
|
||||||
|
|
||||||
// Setup overlay texture to blend
|
|
||||||
float mat_scale2 = _texture_uv_scale_array[out_mat.over];
|
|
||||||
float normal_angle2 = uv_rotation;
|
|
||||||
vec2 matUV2 = detiling(base_uv * mat_scale2, uv_center * mat_scale2, out_mat.over, normal_angle2);
|
|
||||||
vec2 ddx2 = ddx * mat_scale2;
|
|
||||||
vec2 ddy2 = ddy * mat_scale2;
|
|
||||||
vec4 albedo_ht2 = textureGrad(_texture_array_albedo, vec3(matUV2, float(out_mat.over)), ddx2, ddy2);
|
|
||||||
vec4 normal_rg2 = textureGrad(_texture_array_normal, vec3(matUV2, float(out_mat.over)), ddx2, ddy2);
|
|
||||||
|
|
||||||
// Though it would seem having the above lookups in this block, or removing the branch would
|
|
||||||
// be more optimal, the first introduces artifacts #276, and the second is noticably slower.
|
|
||||||
// It seems the branching off dual scaling and the color array lookup is more optimal.
|
|
||||||
if (out_mat.blend > 0.f) {
|
|
||||||
// Unpack & rotate overlay normal for blending
|
|
||||||
normal_rg2.xz = unpack_normal(normal_rg2).xz;
|
|
||||||
normal_rg2.xz = rotate_normal(normal_rg2.xz, normal_angle2);
|
|
||||||
|
|
||||||
// Apply color to overlay
|
|
||||||
albedo_ht2.rgb *= _texture_color_array[out_mat.over].rgb;
|
|
||||||
|
|
||||||
// Blend overlay and base
|
|
||||||
albedo_ht = height_blend(albedo_ht, albedo_ht.a, albedo_ht2, albedo_ht2.a, out_mat.blend);
|
|
||||||
normal_rg = height_blend(normal_rg, albedo_ht.a, normal_rg2, albedo_ht2.a, out_mat.blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repack normals and return material
|
|
||||||
normal_rg = pack_normal(normal_rg.xyz, normal_rg.a);
|
|
||||||
out_mat.alb_ht = albedo_ht;
|
|
||||||
out_mat.nrm_rg = normal_rg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float blend_weights(float weight, float detail) {
|
|
||||||
weight = smoothstep(0.0, 1.0, weight);
|
|
||||||
weight = sqrt(weight * 0.5);
|
|
||||||
float result = max(0.1 * weight, fma(10.0, (weight + detail), 1.0f - (detail + 10.0)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fragment() {
|
|
||||||
// Recover UVs
|
|
||||||
vec2 uv = UV + v_uv_offset;
|
|
||||||
vec2 uv2 = UV2 + v_uv2_offset;
|
|
||||||
|
|
||||||
// Calculate Terrain Normals. 4 lookups
|
|
||||||
vec3 w_tangent, w_binormal;
|
|
||||||
vec3 w_normal = get_normal(uv2, w_tangent, w_binormal);
|
|
||||||
NORMAL = mat3(VIEW_MATRIX) * w_normal;
|
|
||||||
TANGENT = mat3(VIEW_MATRIX) * w_tangent;
|
|
||||||
BINORMAL = mat3(VIEW_MATRIX) * w_binormal;
|
|
||||||
|
|
||||||
// Idenfity 4 vertices surrounding this pixel
|
|
||||||
vec2 texel_pos = uv;
|
|
||||||
highp vec2 texel_pos_floor = floor(uv);
|
|
||||||
|
|
||||||
// Create a cross hatch grid of alternating 0/1 horizontal and vertical stripes 1 unit wide in XY
|
|
||||||
vec4 mirror = vec4(fract(texel_pos_floor * 0.5) * 2.0, 1.0, 1.0);
|
|
||||||
// And the opposite grid in ZW
|
|
||||||
mirror.zw = vec2(1.0) - mirror.xy;
|
|
||||||
|
|
||||||
// Get the region and control map ID for the vertices
|
|
||||||
ivec3 indexUV[4] = {
|
|
||||||
get_region_uv(texel_pos_floor + mirror.xy),
|
|
||||||
get_region_uv(texel_pos_floor + mirror.xw),
|
|
||||||
get_region_uv(texel_pos_floor + mirror.zy),
|
|
||||||
get_region_uv(texel_pos_floor + mirror.zw)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lookup adjacent vertices. 4 lookups
|
|
||||||
uint control[4] = {
|
|
||||||
texelFetch(_control_maps, indexUV[0], 0).r,
|
|
||||||
texelFetch(_control_maps, indexUV[1], 0).r,
|
|
||||||
texelFetch(_control_maps, indexUV[2], 0).r,
|
|
||||||
texelFetch(_control_maps, indexUV[3], 0).r
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the textures for each vertex. 8-16 lookups (2-4 ea)
|
|
||||||
Material mat[4];
|
|
||||||
get_material(uv, control[0], indexUV[0], w_normal, mat[0]);
|
|
||||||
get_material(uv, control[1], indexUV[1], w_normal, mat[1]);
|
|
||||||
get_material(uv, control[2], indexUV[2], w_normal, mat[2]);
|
|
||||||
get_material(uv, control[3], indexUV[3], w_normal, mat[3]);
|
|
||||||
|
|
||||||
// Calculate weight for the pixel position between the vertices
|
|
||||||
// Bilinear interpolation of difference of uv and floor(uv)
|
|
||||||
vec2 weights1 = clamp(texel_pos - texel_pos_floor, 0, 1);
|
|
||||||
weights1 = mix(weights1, vec2(1.0) - weights1, mirror.xy);
|
|
||||||
vec2 weights0 = vec2(1.0) - weights1;
|
|
||||||
// Adjust final weights by texture's height/depth + noise. 1 lookup
|
|
||||||
float noise3 = texture(noise_texture, uv*noise3_scale).r;
|
|
||||||
vec4 weights;
|
|
||||||
weights.x = blend_weights(weights0.x * weights0.y, clamp(mat[0].alb_ht.a + noise3, 0., 1.));
|
|
||||||
weights.y = blend_weights(weights0.x * weights1.y, clamp(mat[1].alb_ht.a + noise3, 0., 1.));
|
|
||||||
weights.z = blend_weights(weights1.x * weights0.y, clamp(mat[2].alb_ht.a + noise3, 0., 1.));
|
|
||||||
weights.w = blend_weights(weights1.x * weights1.y, clamp(mat[3].alb_ht.a + noise3, 0., 1.));
|
|
||||||
float weight_sum = weights.x + weights.y + weights.z + weights.w;
|
|
||||||
float weight_inv = 1.0 / weight_sum;
|
|
||||||
|
|
||||||
// Weighted average of albedo & height
|
|
||||||
vec4 albedo_height = weight_inv * (
|
|
||||||
mat[0].alb_ht * weights.x +
|
|
||||||
mat[1].alb_ht * weights.y +
|
|
||||||
mat[2].alb_ht * weights.z +
|
|
||||||
mat[3].alb_ht * weights.w );
|
|
||||||
|
|
||||||
// Weighted average of normal & rough
|
|
||||||
vec4 normal_rough = weight_inv * (
|
|
||||||
mat[0].nrm_rg * weights.x +
|
|
||||||
mat[1].nrm_rg * weights.y +
|
|
||||||
mat[2].nrm_rg * weights.z +
|
|
||||||
mat[3].nrm_rg * weights.w );
|
|
||||||
|
|
||||||
// Determine if we're in a region or not (region_uv.z>0)
|
|
||||||
vec3 region_uv = get_region_uv2(uv2);
|
|
||||||
|
|
||||||
// Colormap. 1 lookup
|
|
||||||
vec4 color_map = vec4(1., 1., 1., .5);
|
|
||||||
if (region_uv.z >= 0.) {
|
|
||||||
float lod = textureQueryLod(_color_maps, uv2.xy).y;
|
|
||||||
color_map = textureLod(_color_maps, region_uv, lod);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Macro variation. 2 Lookups
|
|
||||||
float noise1 = texture(noise_texture, rotate(uv*noise1_scale * .1, cos(noise1_angle), sin(noise1_angle)) + noise1_offset).r;
|
|
||||||
float noise2 = texture(noise_texture, uv*noise2_scale * .1).r;
|
|
||||||
vec3 macrov = mix(macro_variation1, vec3(1.), clamp(noise1 + v_vertex_xz_dist * .0002, 0., 1.));
|
|
||||||
macrov *= mix(macro_variation2, vec3(1.), clamp(noise2 + v_vertex_xz_dist * .0002, 0., 1.));
|
|
||||||
|
|
||||||
// Wetness/roughness modifier, converting 0-1 range to -1 to 1 range
|
|
||||||
float roughness = fma(color_map.a - 0.5, 2.0, normal_rough.a);
|
|
||||||
|
|
||||||
// Apply PBR
|
|
||||||
ALBEDO = albedo_height.rgb * color_map.rgb * macrov;
|
|
||||||
ROUGHNESS = roughness;
|
|
||||||
SPECULAR = 1. - normal_rough.a;
|
|
||||||
NORMAL_MAP = normal_rough.rgb;
|
|
||||||
NORMAL_MAP_DEPTH = 1.0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
"
|
|
|
@ -34,8 +34,6 @@ func set_state_for_player(player: WorldPlayer) -> void:
|
||||||
wedge_label.set_enabled(player.wedge != null)
|
wedge_label.set_enabled(player.wedge != null)
|
||||||
special_label.set_enabled(player.special != null)
|
special_label.set_enabled(player.special != null)
|
||||||
putter_label.set_enabled(player.putter != null)
|
putter_label.set_enabled(player.putter != null)
|
||||||
if player.shot_setup:
|
|
||||||
value = player.shot_setup.club
|
|
||||||
|
|
||||||
|
|
||||||
func _get_club_label(club: Club.Type) -> Label:
|
func _get_club_label(club: Club.Type) -> Label:
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
@tool
|
|
||||||
extends TextureProgressBar
|
|
||||||
|
|
||||||
@export var damage_delay := 1.0
|
|
||||||
@export var damage_tween_time := 0.4
|
|
||||||
|
|
||||||
@onready var damage_bar: TextureProgressBar = %DamageBar
|
|
||||||
@onready var damage_update_timer: Timer = $DamageUpdateTimer
|
|
||||||
|
|
||||||
|
|
||||||
func _on_value_changed(_value: float) -> void:
|
|
||||||
damage_update_timer.start(damage_delay)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_damage_update_timer_timeout() -> void:
|
|
||||||
var tween := get_tree().create_tween()
|
|
||||||
(
|
|
||||||
tween
|
|
||||||
. tween_property(damage_bar, "value", value, damage_tween_time)
|
|
||||||
. set_trans(Tween.TRANS_CUBIC)
|
|
||||||
. set_ease(Tween.EASE_OUT)
|
|
||||||
)
|
|
|
@ -1,46 +0,0 @@
|
||||||
[gd_scene load_steps=5 format=3 uid="uid://dmciuk3pbjsae"]
|
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://dtdqninlnu10o" path="res://assets/ui/lifebar_fill_grey.png" id="1_nhls1"]
|
|
||||||
[ext_resource type="Script" path="res://src/ui/shot_hud/life_bar/life_bar.gd" id="2_6jpmf"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://bvwh0yunmvirp" path="res://assets/ui/lifebar_patch.png" id="3_8s5ot"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://dv8757eh7bgmm" path="res://assets/ui/lifebar_fill_damage.png" id="4_ohduq"]
|
|
||||||
|
|
||||||
[node name="LifeBar" type="TextureProgressBar"]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
step = 0.01
|
|
||||||
nine_patch_stretch = true
|
|
||||||
stretch_margin_left = 32
|
|
||||||
stretch_margin_top = 16
|
|
||||||
stretch_margin_right = 32
|
|
||||||
stretch_margin_bottom = 16
|
|
||||||
texture_progress = ExtResource("1_nhls1")
|
|
||||||
script = ExtResource("2_6jpmf")
|
|
||||||
damage_tween_time = 0.6
|
|
||||||
|
|
||||||
[node name="DamageBar" type="TextureProgressBar" parent="."]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
show_behind_parent = true
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
step = 0.01
|
|
||||||
nine_patch_stretch = true
|
|
||||||
stretch_margin_left = 32
|
|
||||||
stretch_margin_top = 16
|
|
||||||
stretch_margin_right = 32
|
|
||||||
stretch_margin_bottom = 16
|
|
||||||
texture_under = ExtResource("3_8s5ot")
|
|
||||||
texture_progress = ExtResource("4_ohduq")
|
|
||||||
tint_progress = Color(0.9, 0, 0, 1)
|
|
||||||
|
|
||||||
[node name="DamageUpdateTimer" type="Timer" parent="."]
|
|
||||||
|
|
||||||
[connection signal="value_changed" from="." to="." method="_on_value_changed"]
|
|
||||||
[connection signal="timeout" from="DamageUpdateTimer" to="." method="_on_damage_update_timer_timeout"]
|
|
|
@ -1,13 +1,6 @@
|
||||||
class_name ShotHUD extends Control
|
class_name ShotHUD extends Control
|
||||||
## HUD for main gameplay loop
|
## HUD for main gameplay loop
|
||||||
|
|
||||||
## Scale factor for the life bar rumble intensity on taking damage
|
|
||||||
const LIFE_BAR_DAMAGE_RUMBLE_SCALE := 0.2
|
|
||||||
## Time it takes to dampen the life bar rumble on taking damage, in seconds
|
|
||||||
const LIFE_BAR_DAMAGE_RUMBLE_TIME := 0.2
|
|
||||||
|
|
||||||
var _life_signal: Signal
|
|
||||||
|
|
||||||
@onready var power_bar: TextureProgressBar = %PowerBar
|
@onready var power_bar: TextureProgressBar = %PowerBar
|
||||||
@onready var curve_bar: ProgressBar = %CurveBar
|
@onready var curve_bar: ProgressBar = %CurveBar
|
||||||
@onready var life_bar: TextureProgressBar = %LifeBar
|
@onready var life_bar: TextureProgressBar = %LifeBar
|
||||||
|
@ -24,8 +17,6 @@ var _life_signal: Signal
|
||||||
|
|
||||||
@onready var _player_name: Label = %PlayerName
|
@onready var _player_name: Label = %PlayerName
|
||||||
|
|
||||||
@onready var _life_bar_rumbler: Rumbler = %LifeBarRumbler
|
|
||||||
|
|
||||||
@onready var _state: AnimationNodeStateMachinePlayback = hud_state_machine["parameters/playback"]
|
@onready var _state: AnimationNodeStateMachinePlayback = hud_state_machine["parameters/playback"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,14 +28,6 @@ func set_state_for_player(player: WorldPlayer) -> void:
|
||||||
# TODO animate on life loss?
|
# TODO animate on life loss?
|
||||||
life_bar.value = player.life
|
life_bar.value = player.life
|
||||||
life_bar.tint_progress = player.color
|
life_bar.tint_progress = player.color
|
||||||
|
|
||||||
# TODO this is soooooo wack...
|
|
||||||
# TODO we should just revert to having distinct ShotHUDs for each player
|
|
||||||
if _life_signal and _life_signal.is_connected(set_life_value):
|
|
||||||
_life_signal.disconnect(set_life_value)
|
|
||||||
_life_signal = player.on_life_changed
|
|
||||||
_life_signal.connect(set_life_value)
|
|
||||||
|
|
||||||
# TODO special equipment
|
# TODO special equipment
|
||||||
# TODO abilities
|
# TODO abilities
|
||||||
|
|
||||||
|
@ -87,24 +70,3 @@ func play_nice_animation() -> void:
|
||||||
|
|
||||||
func play_wasted_animation() -> void:
|
func play_wasted_animation() -> void:
|
||||||
_wasted_animation.play("display")
|
_wasted_animation.play("display")
|
||||||
|
|
||||||
|
|
||||||
## Set the value of the life bar, potentially playing some kind of effect in response.
|
|
||||||
##
|
|
||||||
## To set the life bar without triggering an effect, set it directly with `life_bar.value`
|
|
||||||
func set_life_value(new_value: float) -> void:
|
|
||||||
var difference := new_value - life_bar.value
|
|
||||||
if difference < 0:
|
|
||||||
# Taking damage
|
|
||||||
_life_bar_rumbler.intensity = LIFE_BAR_DAMAGE_RUMBLE_SCALE * abs(difference)
|
|
||||||
var tween := get_tree().create_tween()
|
|
||||||
(
|
|
||||||
tween
|
|
||||||
. tween_property(_life_bar_rumbler, "intensity", 0, LIFE_BAR_DAMAGE_RUMBLE_TIME)
|
|
||||||
. set_trans(Tween.TRANS_CUBIC)
|
|
||||||
)
|
|
||||||
elif difference > 0:
|
|
||||||
# Restoring health
|
|
||||||
# TODO: something for this?
|
|
||||||
pass
|
|
||||||
life_bar.value = new_value
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=33 format=3 uid="uid://c4ifdiohng830"]
|
[gd_scene load_steps=34 format=3 uid="uid://c4ifdiohng830"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ui/shot_hud/shot_hud.gd" id="1_x5b4c"]
|
[ext_resource type="Script" path="res://src/ui/shot_hud/shot_hud.gd" id="1_x5b4c"]
|
||||||
[ext_resource type="Shader" path="res://src/shaders/canvas_retro.gdshader" id="1_ybxxp"]
|
[ext_resource type="Shader" path="res://src/shaders/canvas_retro.gdshader" id="1_ybxxp"]
|
||||||
|
@ -8,7 +8,8 @@
|
||||||
[ext_resource type="Texture2D" uid="uid://76fjx2ukavqe" path="res://assets/ui/power_gauge_fill.png" id="5_3i1yq"]
|
[ext_resource type="Texture2D" uid="uid://76fjx2ukavqe" path="res://assets/ui/power_gauge_fill.png" id="5_3i1yq"]
|
||||||
[ext_resource type="Texture2D" uid="uid://4a8tvjgwegv3" path="res://assets/ui/power_gauge_tab.png" id="6_sw48q"]
|
[ext_resource type="Texture2D" uid="uid://4a8tvjgwegv3" path="res://assets/ui/power_gauge_tab.png" id="6_sw48q"]
|
||||||
[ext_resource type="FontFile" uid="uid://dsa0oh7c0h4pu" path="res://assets/fonts/Racing_Sans_One/RacingSansOne-Regular.ttf" id="8_bejx4"]
|
[ext_resource type="FontFile" uid="uid://dsa0oh7c0h4pu" path="res://assets/fonts/Racing_Sans_One/RacingSansOne-Regular.ttf" id="8_bejx4"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dmciuk3pbjsae" path="res://src/ui/shot_hud/life_bar/life_bar.tscn" id="9_w1fiw"]
|
[ext_resource type="Texture2D" uid="uid://bvwh0yunmvirp" path="res://assets/ui/lifebar_patch.png" id="9_4f1d7"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dtdqninlnu10o" path="res://assets/ui/lifebar_fill_grey.png" id="10_130v7"]
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_3xds6"]
|
[sub_resource type="Animation" id="Animation_3xds6"]
|
||||||
resource_name = "RESET"
|
resource_name = "RESET"
|
||||||
|
@ -275,7 +276,7 @@ _data = {
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_afsun"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_afsun"]
|
||||||
shader = ExtResource("1_ybxxp")
|
shader = ExtResource("1_ybxxp")
|
||||||
shader_parameter/change_color_depth = true
|
shader_parameter/change_color_depth = true
|
||||||
shader_parameter/target_color_depth = 4
|
shader_parameter/target_color_depth = 3
|
||||||
shader_parameter/dithering = true
|
shader_parameter/dithering = true
|
||||||
shader_parameter/scale_resolution = true
|
shader_parameter/scale_resolution = true
|
||||||
shader_parameter/target_resolution_scale = 3
|
shader_parameter/target_resolution_scale = 3
|
||||||
|
@ -697,15 +698,16 @@ theme_override_fonts/font = ExtResource("8_bejx4")
|
||||||
theme_override_font_sizes/font_size = 32
|
theme_override_font_sizes/font_size = 32
|
||||||
text = "PLAYER NAME"
|
text = "PLAYER NAME"
|
||||||
|
|
||||||
[node name="MarginContainer" type="MarginContainer" parent="SouthWest/VBoxContainer"]
|
[node name="LifeBar" type="TextureProgressBar" parent="SouthWest/VBoxContainer"]
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="LifeBarRumbler" type="Control" parent="SouthWest/VBoxContainer/MarginContainer"]
|
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
custom_minimum_size = Vector2(0, 48)
|
custom_minimum_size = Vector2(0, 48)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
script = ExtResource("3_6groq")
|
min_value = -4.0
|
||||||
|
step = 0.01
|
||||||
[node name="LifeBar" parent="SouthWest/VBoxContainer/MarginContainer/LifeBarRumbler" instance=ExtResource("9_w1fiw")]
|
nine_patch_stretch = true
|
||||||
unique_name_in_owner = true
|
stretch_margin_left = 32
|
||||||
layout_mode = 1
|
stretch_margin_top = 16
|
||||||
|
stretch_margin_right = 32
|
||||||
|
stretch_margin_bottom = 16
|
||||||
|
texture_under = ExtResource("9_4f1d7")
|
||||||
|
texture_progress = ExtResource("10_130v7")
|
||||||
|
|
Loading…
Reference in New Issue