save code
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: celyk
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
polar: # Replace with a single Polar username
|
||||||
|
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||||
|
thanks_dev: # Replace with a single thanks.dev username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
@tool
|
||||||
|
@icon("bounce.svg")
|
||||||
|
class_name GPUTrail3D extends GPUParticles3D
|
||||||
|
|
||||||
|
## [br]A node for creating a ribbon trail effect.
|
||||||
|
## [br][color=purple]Made by celyk[/color]
|
||||||
|
##
|
||||||
|
## This node serves as an alternative to CPU based trails.[br]
|
||||||
|
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# Add flipbook support
|
||||||
|
# Hide the actual GPUParticles3D node
|
||||||
|
# Restructure code, use enums for flags
|
||||||
|
# Add more polygons, make trail smoother
|
||||||
|
# Add an acceleration parameter
|
||||||
|
# Port to Godot 3.5
|
||||||
|
# Port to 2D
|
||||||
|
# Allow custom material
|
||||||
|
|
||||||
|
# PUBLIC
|
||||||
|
|
||||||
|
## Length is the number of steps in the trail
|
||||||
|
@export var length : int = 100 : set = _set_length
|
||||||
|
@export var length_seconds : float : set = _set_length
|
||||||
|
|
||||||
|
@export_category("Color / Texture")
|
||||||
|
|
||||||
|
## The main texture of the trail.[br]
|
||||||
|
## [br]Set [member vertical_texture] to adjust for orientation[br]
|
||||||
|
##
|
||||||
|
## [br]Enable [member use_red_as_alpha] to use the red color channel as alpha
|
||||||
|
@export var texture : Texture : set = _set_texture
|
||||||
|
|
||||||
|
## Scolls the texture by applying an offset to the UV
|
||||||
|
@export var scroll : Vector2 : set = _set_scroll
|
||||||
|
|
||||||
|
## A color ramp for modulating the color along the length of the trail
|
||||||
|
@export var color_ramp : GradientTexture1D : set = _set_color_ramp
|
||||||
|
|
||||||
|
## A curve for modulating the width along the length of the trail
|
||||||
|
@export var curve : CurveTexture : set = _set_curve
|
||||||
|
|
||||||
|
## Set [member vertical_texture] to adjust for orientation
|
||||||
|
@export var vertical_texture := false : set = _set_vertical_texture
|
||||||
|
|
||||||
|
## Enable [member use_red_as_alpha] to use the red color channel of [member texture] as alpha
|
||||||
|
@export var use_red_as_alpha := false : set = _set_use_red_as_alpha
|
||||||
|
|
||||||
|
|
||||||
|
@export_category("Mesh tweaks")
|
||||||
|
|
||||||
|
## Makes trail face camera. I haven't finished this yet
|
||||||
|
@export var billboard := false : set = _set_billboard
|
||||||
|
|
||||||
|
## Enable to improve the mapping of [member texture] to the trail
|
||||||
|
@export var dewiggle := true : set = _set_dewiggle
|
||||||
|
|
||||||
|
## Enable to improve the mapping of [member texture] to the trail
|
||||||
|
@export var clip_overlaps := true : set = _set_clip_overlaps
|
||||||
|
|
||||||
|
## Enable [member snap_to_transform] to snap the start of the trail to the nodes position. This may not be noticeable unless you
|
||||||
|
## have changed [member fixed_fps], which you can use to optimize the trail
|
||||||
|
@export var snap_to_transform := false : set = _set_snap_to_transform
|
||||||
|
|
||||||
|
|
||||||
|
# PRIVATE
|
||||||
|
|
||||||
|
const _DEFAULT_TEXTURE = "defaults/texture.tres"
|
||||||
|
const _DEFAULT_CURVE = "defaults/curve.tres"
|
||||||
|
|
||||||
|
var _defaults_have_been_set = false
|
||||||
|
func _get_property_list():
|
||||||
|
return [{"name": "_defaults_have_been_set","type": TYPE_BOOL,"usage": PROPERTY_USAGE_NO_EDITOR}]
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
if not _defaults_have_been_set:
|
||||||
|
_defaults_have_been_set = true
|
||||||
|
|
||||||
|
|
||||||
|
amount = length
|
||||||
|
lifetime = length
|
||||||
|
explosiveness = 1 # emits all particles at once
|
||||||
|
|
||||||
|
# the main fps is default
|
||||||
|
fixed_fps = int( DisplayServer.screen_get_refresh_rate(DisplayServer.MAIN_WINDOW_ID) )
|
||||||
|
|
||||||
|
if DisplayServer.screen_get_refresh_rate(DisplayServer.MAIN_WINDOW_ID) < 0.0:
|
||||||
|
push_warning("Could not find screen refresh rate. Using fixed_fps = 60")
|
||||||
|
fixed_fps = 60
|
||||||
|
|
||||||
|
process_material = ShaderMaterial.new()
|
||||||
|
process_material.shader = preload("shaders/trail.gdshader")
|
||||||
|
|
||||||
|
draw_pass_1 = QuadMesh.new()
|
||||||
|
draw_pass_1.material = ShaderMaterial.new()
|
||||||
|
draw_pass_1.material.shader = preload("shaders/trail_draw_pass.gdshader")
|
||||||
|
|
||||||
|
color_ramp = preload(_DEFAULT_TEXTURE).duplicate(true)
|
||||||
|
curve = preload(_DEFAULT_CURVE).duplicate(true)
|
||||||
|
|
||||||
|
draw_pass_1.material.resource_local_to_scene = true
|
||||||
|
|
||||||
|
length = length
|
||||||
|
vertical_texture = vertical_texture
|
||||||
|
use_red_as_alpha = use_red_as_alpha
|
||||||
|
billboard = billboard
|
||||||
|
dewiggle = dewiggle
|
||||||
|
clip_overlaps = clip_overlaps
|
||||||
|
snap_to_transform = snap_to_transform
|
||||||
|
|
||||||
|
func _set_length(value):
|
||||||
|
if value is int: # length is being set
|
||||||
|
length = value
|
||||||
|
length = max(length, 1)
|
||||||
|
length_seconds = float(length) / get_fixed_fps()
|
||||||
|
elif value is float: # length_seconds is being set
|
||||||
|
length = int(value * get_fixed_fps())
|
||||||
|
length = max(length, 1)
|
||||||
|
length_seconds = float(length) / get_fixed_fps()
|
||||||
|
|
||||||
|
if _defaults_have_been_set:
|
||||||
|
amount = length
|
||||||
|
lifetime = length
|
||||||
|
|
||||||
|
restart()
|
||||||
|
|
||||||
|
func _set_texture(value):
|
||||||
|
texture = value
|
||||||
|
_uv_offset = Vector2(0,0) # Reset the scroll when a new texture is assigned
|
||||||
|
if value:
|
||||||
|
draw_pass_1.material.set_shader_parameter("tex", texture)
|
||||||
|
else:
|
||||||
|
draw_pass_1.material.set_shader_parameter("tex", preload(_DEFAULT_TEXTURE))
|
||||||
|
func _set_scroll(value):
|
||||||
|
scroll = value
|
||||||
|
func _set_color_ramp(value):
|
||||||
|
color_ramp = value
|
||||||
|
draw_pass_1.material.set_shader_parameter("color_ramp", color_ramp)
|
||||||
|
func _set_curve(value):
|
||||||
|
curve = value
|
||||||
|
if value:
|
||||||
|
draw_pass_1.material.set_shader_parameter("curve", curve)
|
||||||
|
else:
|
||||||
|
draw_pass_1.material.set_shader_parameter("curve", preload(_DEFAULT_CURVE))
|
||||||
|
func _set_vertical_texture(value):
|
||||||
|
vertical_texture = value
|
||||||
|
_flags = _set_flag(_flags,0,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
func _set_use_red_as_alpha(value):
|
||||||
|
use_red_as_alpha = value
|
||||||
|
_flags = _set_flag(_flags,1,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
func _set_billboard(value):
|
||||||
|
billboard = value
|
||||||
|
_flags = _set_flag(_flags,2,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
if value && _defaults_have_been_set:
|
||||||
|
_update_billboard_transform( global_transform.basis[0] )
|
||||||
|
|
||||||
|
restart()
|
||||||
|
func _set_dewiggle(value):
|
||||||
|
dewiggle = value
|
||||||
|
_flags = _set_flag(_flags,3,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
func _set_snap_to_transform(value):
|
||||||
|
snap_to_transform = value
|
||||||
|
_flags = _set_flag(_flags,4,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
func _set_clip_overlaps(value):
|
||||||
|
clip_overlaps = value
|
||||||
|
_flags = _set_flag(_flags,5,value)
|
||||||
|
draw_pass_1.material.set_shader_parameter("flags", _flags)
|
||||||
|
|
||||||
|
|
||||||
|
@onready var _old_pos : Vector3 = global_position
|
||||||
|
@onready var _billboard_transform : Transform3D = global_transform
|
||||||
|
var _uv_offset : Vector2
|
||||||
|
func _process(delta):
|
||||||
|
if(snap_to_transform):
|
||||||
|
draw_pass_1.material.set_shader_parameter("emmission_transform", global_transform)
|
||||||
|
|
||||||
|
# Handle UV scrolling
|
||||||
|
_uv_offset += scroll * delta
|
||||||
|
_uv_offset = _uv_offset.posmod(1.0)
|
||||||
|
draw_pass_1.material.set_shader_parameter("uv_offset", _uv_offset)
|
||||||
|
|
||||||
|
await RenderingServer.frame_pre_draw
|
||||||
|
|
||||||
|
if(billboard):
|
||||||
|
var delta_position = global_position - _old_pos
|
||||||
|
|
||||||
|
if delta_position:
|
||||||
|
var tangent = global_transform.basis[1].length() * (delta_position).normalized()
|
||||||
|
_update_billboard_transform(tangent)
|
||||||
|
|
||||||
|
RenderingServer.instance_set_transform(get_instance(), _billboard_transform)
|
||||||
|
|
||||||
|
_old_pos = global_position
|
||||||
|
|
||||||
|
func _update_billboard_transform(tangent : Vector3):
|
||||||
|
_billboard_transform = global_transform
|
||||||
|
var p : Vector3 = _billboard_transform.basis[1]
|
||||||
|
var x : Vector3 = tangent
|
||||||
|
var angle : float = p.angle_to(x)
|
||||||
|
var rotation_axis : Vector3 = p.cross(x).normalized()
|
||||||
|
if rotation_axis != Vector3():
|
||||||
|
_billboard_transform.basis = _billboard_transform.basis.rotated(rotation_axis,angle)
|
||||||
|
_billboard_transform.basis = _billboard_transform.basis.scaled(Vector3(0.5,0.5,0.5))
|
||||||
|
_billboard_transform.origin += _billboard_transform.basis[1]
|
||||||
|
|
||||||
|
var _flags = 0
|
||||||
|
func _set_flag(i, idx : int, value : bool):
|
||||||
|
return (i & ~(1 << idx)) | (int(value) << idx)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cx8ohpp5vs5os
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
.import/
|
||||||
|
export.cfg
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
.mono/
|
||||||
|
data_*/
|
||||||
|
mono_crash.*.json
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 celyk
|
||||||
|
|
||||||
|
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,70 @@
|
|||||||
|
# GPUTrail
|
||||||
|
|
||||||
|
GPUTrail is a GPU-based trail plugin for Godot 4, offering an efficient alternative to CPU-based trails for creating ribbon trail effects in your games and applications.
|
||||||
|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- GPU-accelerated trail rendering for improved performance
|
||||||
|
- Customizable trail length, texture, and color
|
||||||
|
- Support for color ramps and width curves
|
||||||
|
- Options for texture orientation and alpha channel handling
|
||||||
|
- Billboard mode for camera-facing trails
|
||||||
|
- Dewiggle and clip overlaps features for improved trail appearance
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Clone or download this repository
|
||||||
|
2. Copy the `addons/GPUTrail` folder into your Godot project's `addons` folder
|
||||||
|
3. Enable the plugin in your project settings: Project -> Project Settings -> Plugins -> GPUTrail
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Add a new `GPUTrail3D` node to your scene
|
||||||
|
2. Customize the trail properties in the Inspector panel
|
||||||
|
3. Attach the `GPUTrail3D` node to the object you want to trail
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
- `length`: Number of steps in the trail
|
||||||
|
- `texture`: Main texture of the trail
|
||||||
|
- `color_ramp`: Color gradient along the trail's length
|
||||||
|
- `curve`: Width modulation along the trail's length
|
||||||
|
- `vertical_texture`: Adjust texture orientation
|
||||||
|
- `use_red_as_alpha`: Use the red channel of the texture as alpha
|
||||||
|
- `billboard`: Make the trail face the camera (experimental)
|
||||||
|
- `dewiggle`: Improve texture mapping to the trail
|
||||||
|
- `clip_overlaps`: Prevent trail self-intersectionis
|
||||||
|
- `snap_to_transform`: Snap the trail start to the node's position, and regardless of the particles own framerate
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
var trail = GPUTrail3D.new()
|
||||||
|
trail.length = 100
|
||||||
|
trail.texture = preload("res://trail_texture.png")
|
||||||
|
add_child(trail)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
- Tutorial by Le Lu: [YouTube Video](https://www.youtube.com/watch?v=0VsEfP4XFCM)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- Add flipbook support
|
||||||
|
- Hide the actual GPUParticles3D node
|
||||||
|
- Restructure code, use enums for flags
|
||||||
|
- Add more polygons, make trail smoother
|
||||||
|
- Add an acceleration parameter
|
||||||
|
- Port to Godot 3.5
|
||||||
|
- Port to 2D
|
||||||
|
- Allow custom material
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.699 12.31"><title>Bounce_ForExport</title><path d="M11.028,5A5.5,5.5,0,0,0,5.912,8.827c-.16-.259-.343-.658-.616-1.074,0,.04,0,.08,0,.121-.023.314-.064.627-.111.94-.021.3-.034.61-.051.916A5.02,5.02,0,0,1,4.9,11.223c.059.727.087,1.486.109,2.245-.006.226-.027.451-.016,1.124h2.22c.095-1.627.091-4.022,2.63-5.909a1.71,1.71,0,0,1-.079-.727A3.09,3.09,0,0,1,11.028,5Z" transform="translate(-0.091 -2.282)" style="fill:#ee478b"/><path d="M12.115,4.921a2.041,2.041,0,1,1-1.443.6,2.024,2.024,0,0,1,1.443-.6m0-1.23a3.271,3.271,0,1,0,2.312.958,3.26,3.26,0,0,0-2.312-.958Z" transform="translate(-0.091 -2.282)" style="fill:#ee478b;stroke:#ee478b;stroke-miterlimit:10;stroke-width:0.5px"/><path d="M14.87,4.251l-.086-.091c-.324-.34-1.29-1.574-1.29-1.574q-.058.057-.114.123l-.231.281L12.8,2.9a5.633,5.633,0,0,0-.787-.123,3.131,3.131,0,0,1-1.6-.5,1.463,1.463,0,0,0-.129.418l-.042.451-.448.061A7.231,7.231,0,0,0,5.819,5.068a1.664,1.664,0,0,1,1.364.49,2.151,2.151,0,0,1,.275.354A6.139,6.139,0,0,0,5.9,8.16a10.051,10.051,0,0,0-.727-.9A5.076,5.076,0,0,0,3.82,6.246a2.8,2.8,0,0,0-1.652-.273,2.479,2.479,0,0,0-1.441.765,2.414,2.414,0,0,1,1.457-.625,2.594,2.594,0,0,1,1.5.382,4.728,4.728,0,0,1,1.169,1.05,10.417,10.417,0,0,1,.809,1.232,11.688,11.688,0,0,0-.346,1.264,17.747,17.747,0,0,0-.326,4.551,17.567,17.567,0,0,1,.691-4.458A7.155,7.155,0,0,1,7.7,6.712a1.963,1.963,0,0,1-.067.385A2.746,2.746,0,0,1,6.443,8.56l.325.031a3.134,3.134,0,0,1,2.119.91,3.072,3.072,0,0,0-.725.378,3.07,3.07,0,0,1,2,.793,1.253,1.253,0,0,1,.413,1.039,4.356,4.356,0,0,0,.852-.39,6.453,6.453,0,0,1,1.076-.5l.03-.01.031-.006A4.069,4.069,0,0,0,14.87,4.251Zm-.583,4.883a3.072,3.072,0,1,1,0-4.345A3.072,3.072,0,0,1,14.287,9.134Z" transform="translate(-0.091 -2.282)" style="fill:#ffcc2c"/><path d="M.8,6.667c-.01.01-.025.016-.036.027s-.016.021-.026.031C.76,6.7.784,6.687.8,6.667Z" transform="translate(-0.091 -2.282)" style="fill:#ee478b"/><path d="M5.319,10.041a11.688,11.688,0,0,1,.346-1.264,10.417,10.417,0,0,0-.809-1.232A4.728,4.728,0,0,0,3.687,6.5a2.594,2.594,0,0,0-1.5-.382,2.413,2.413,0,0,0-1.448.618c-.854.873-1.077,2.33.691,3.262L.744,11.24c.116.043,1.109-.451,1.6.035.16.186.156.714-.354,1.189.382-.294.725-1.08.463-1.328s-.361-.31-1.108-.293a9.978,9.978,0,0,1,1.3-1.817C.485,10.472.591,5.812,3.277,7.105c1.448.945,1.631,3.318,1.712,5.757A16.51,16.51,0,0,1,5.319,10.041Z" transform="translate(-0.091 -2.282)" style="fill:#ee478b"/><path d="M6.82,11.769a8.9,8.9,0,0,1-.811-2.556c-.123.3-.232.609-.325.921a17.567,17.567,0,0,0-.691,4.458l1.035-1.073c.032-.568.759-.53.881-1.231C6.692,12.013,6.981,12.092,6.82,11.769Z" transform="translate(-0.091 -2.282)" style="fill:#ee478b"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bm2sig4cnve21"
|
||||||
|
path="res://.godot/imported/bounce.svg-1c60b713fc682b9c790d587bf0715690.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://GPUTrail-main/bounce.svg"
|
||||||
|
dest_files=["res://.godot/imported/bounce.svg-1c60b713fc682b9c790d587bf0715690.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
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[gd_resource type="CurveTexture" load_steps=2 format=3 uid="uid://ct31fhxvcragr"]
|
||||||
|
|
||||||
|
[sub_resource type="Curve" id="Curve_7ufs5"]
|
||||||
|
bake_resolution = 16
|
||||||
|
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.1), 0.0, 0.0, 0, 0]
|
||||||
|
point_count = 2
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
curve = SubResource("Curve_7ufs5")
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://crk6pkb7e5rwc"]
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_nk704"]
|
||||||
|
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
gradient = SubResource("Gradient_nk704")
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorNode3DGizmoPlugin
|
||||||
|
|
||||||
|
var editor_plugin : EditorPlugin
|
||||||
|
|
||||||
|
func _init(_editor_plugin:EditorPlugin):
|
||||||
|
editor_plugin = _editor_plugin
|
||||||
|
create_material("main", Color(1,1,1), false, true, true)
|
||||||
|
|
||||||
|
func _has_gizmo(node):
|
||||||
|
return node is GPUTrail3D
|
||||||
|
|
||||||
|
# show gizmo name in visibility list
|
||||||
|
func _get_gizmo_name():
|
||||||
|
return "GPUTrail3DGizmo"
|
||||||
|
|
||||||
|
func _redraw(gizmo):
|
||||||
|
gizmo.clear()
|
||||||
|
|
||||||
|
var node3d : Node3D = gizmo.get_node_3d()
|
||||||
|
|
||||||
|
var lines = PackedVector3Array()
|
||||||
|
|
||||||
|
lines.push_back(Vector3(0,1,0))
|
||||||
|
lines.push_back(Vector3(0,-1,0))
|
||||||
|
|
||||||
|
gizmo.add_lines(lines, get_material("main", gizmo), false, Color(1,1,1,1))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://k7rm0xjg8f61
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="GPUTrail"
|
||||||
|
description="temporary desc"
|
||||||
|
author="celyk"
|
||||||
|
version="0.1"
|
||||||
|
script="plugin.gd"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
const MyCustomGizmoPlugin = preload("gizmos/gizmo.gd")
|
||||||
|
var gizmo_plugin = MyCustomGizmoPlugin.new(self)
|
||||||
|
|
||||||
|
func _enter_tree():
|
||||||
|
# Initialization of the plugin goes here.
|
||||||
|
# Add the new type with a name, a parent type, a script and an icon.
|
||||||
|
add_custom_type("GPUTrail3D", "GPUParticles3D", preload("GPUTrail3D.gd"), preload("bounce.svg"))
|
||||||
|
|
||||||
|
add_node_3d_gizmo_plugin(gizmo_plugin)
|
||||||
|
|
||||||
|
func _exit_tree():
|
||||||
|
# Clean-up of the plugin goes here.
|
||||||
|
# Always remember to remove it from the engine when deactivated.
|
||||||
|
remove_custom_type("GPUTrail3D")
|
||||||
|
|
||||||
|
remove_node_3d_gizmo_plugin(gizmo_plugin)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://wqdljanamd5c
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
|
||||||
|
#define GPU_TRAIL
|
||||||
|
#include "res://addons/GPUTrail/shaders/gputrail_lib.gdshaderinc"
|
||||||
|
|
||||||
|
varying vec2 trail_uv;
|
||||||
|
void vertex(){
|
||||||
|
PREPARE_TRAIL();
|
||||||
|
|
||||||
|
// Save the trail UV coordaintes for later
|
||||||
|
trail_uv = UV;
|
||||||
|
|
||||||
|
// Scroll textures slowly along the length of the trail
|
||||||
|
//UV.x -= fract(TIME*.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment(){
|
||||||
|
PREPARE_TRAIL_TEXTURES();
|
||||||
|
|
||||||
|
// Alpha erosion
|
||||||
|
ALPHA = max(ALPHA - trail_uv.x, 0.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b0um4dniff5cs
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
|
||||||
|
#define GPU_TRAIL
|
||||||
|
#include "res://addons/GPUTrail/shaders/gputrail_lib.gdshaderinc"
|
||||||
|
|
||||||
|
varying vec2 trail_uv;
|
||||||
|
void vertex(){
|
||||||
|
PREPARE_TRAIL();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment(){
|
||||||
|
PREPARE_TRAIL_TEXTURES();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://df5unx54alf3g
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#ifdef GPU_TRAIL
|
||||||
|
//#define GPU_TRAIL
|
||||||
|
|
||||||
|
// TODO make optional
|
||||||
|
render_mode unshaded,world_vertex_coords,cull_disabled;
|
||||||
|
|
||||||
|
uniform sampler2D tex : repeat_enable, source_color, hint_default_white;
|
||||||
|
uniform vec2 uv_offset = vec2(0);
|
||||||
|
uniform sampler2D color_ramp : repeat_disable, source_color, hint_default_white;
|
||||||
|
uniform sampler2D curve : repeat_disable, hint_default_white;
|
||||||
|
uniform mat4 emmission_transform = mat4(1);
|
||||||
|
uniform int flags = 0;
|
||||||
|
|
||||||
|
/*uniform bool vertical_texture = false;
|
||||||
|
uniform bool use_red_as_alpha = false;
|
||||||
|
uniform bool billboard = false;
|
||||||
|
uniform bool dewiggle = false;
|
||||||
|
uniform bool snap_to_transform = false;*/
|
||||||
|
#define vertical_texture bool(flags & 1)
|
||||||
|
#define use_red_as_alpha bool(flags & 2)
|
||||||
|
#define billboard bool(flags & 4)
|
||||||
|
#define dewiggle bool(flags & 8)
|
||||||
|
#define snap_to_transform bool(flags & 16)
|
||||||
|
#define clip_overlaps bool(flags & 32)
|
||||||
|
|
||||||
|
varying float scale_interp;
|
||||||
|
varying vec2 clip;
|
||||||
|
varying vec2 mesh_uv;
|
||||||
|
|
||||||
|
void missing_parens(){}
|
||||||
|
|
||||||
|
#define PREPARE_TRAIL { \
|
||||||
|
mesh_uv = UV; \
|
||||||
|
\
|
||||||
|
mat4 my_model_matrix = MODEL_MATRIX; \
|
||||||
|
if(snap_to_transform && INSTANCE_CUSTOM.w==2.0){ \
|
||||||
|
my_model_matrix[1] = emmission_transform * vec4(0,1,0,1); \
|
||||||
|
my_model_matrix[2] = emmission_transform * vec4(0,-1,0,1); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if(billboard){ \
|
||||||
|
vec3 t0 = my_model_matrix[0].xyz-my_model_matrix[3].xyz; \
|
||||||
|
vec3 t1 = my_model_matrix[1].xyz-my_model_matrix[2].xyz; \
|
||||||
|
\
|
||||||
|
vec3 up0 = length(t0)*normalize( \
|
||||||
|
cross( \
|
||||||
|
my_model_matrix[3].xyz-INV_VIEW_MATRIX[3].xyz, \
|
||||||
|
t0)); \
|
||||||
|
vec3 up1 = length(t1)*normalize( \
|
||||||
|
cross( \
|
||||||
|
my_model_matrix[2].xyz-INV_VIEW_MATRIX[3].xyz, \
|
||||||
|
t1)); \
|
||||||
|
\
|
||||||
|
my_model_matrix[0] = my_model_matrix[3]; \
|
||||||
|
my_model_matrix[1] = my_model_matrix[2]; \
|
||||||
|
\
|
||||||
|
my_model_matrix[0].xyz += up0; \
|
||||||
|
my_model_matrix[3].xyz -= up0; \
|
||||||
|
\
|
||||||
|
my_model_matrix[1].xyz += up1; \
|
||||||
|
my_model_matrix[2].xyz -= up1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
vec3 a = mix(my_model_matrix[1].xyz,my_model_matrix[0].xyz,UV.x); \
|
||||||
|
vec3 b = mix(my_model_matrix[2].xyz,my_model_matrix[3].xyz,UV.x); \
|
||||||
|
\
|
||||||
|
UV.x = (UV.x + INSTANCE_CUSTOM.w-1.0 - 2.0)/(INSTANCE_CUSTOM.z-1.0); \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
float h = textureLod(curve, vec2(UV.x), 0.0).x; \
|
||||||
|
\
|
||||||
|
VERTEX = mix(a,b,(UV.y-0.5)*h + 0.5); \
|
||||||
|
\
|
||||||
|
if(dewiggle){ \
|
||||||
|
scale_interp = h; \
|
||||||
|
UV *= scale_interp; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
\
|
||||||
|
clip.x = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[1].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[2].xyz - INV_VIEW_MATRIX[3].xyz)); \
|
||||||
|
clip.y = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[3].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[0].xyz - INV_VIEW_MATRIX[3].xyz)); \
|
||||||
|
} missing_parens
|
||||||
|
|
||||||
|
#define PREPARE_TRAIL_TEXTURES { \
|
||||||
|
vec2 clip0 = clip; \
|
||||||
|
float ababab = clip0.x*clip0.y; \
|
||||||
|
\
|
||||||
|
if(clip_overlaps && ababab < 0.0) { \
|
||||||
|
if(abs(mesh_uv.x-0.5)<0.5) \
|
||||||
|
discard; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
vec2 base_uv = UV; \
|
||||||
|
\
|
||||||
|
if(dewiggle){ \
|
||||||
|
base_uv /= scale_interp; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
vec2 raw_uv = base_uv; \
|
||||||
|
\
|
||||||
|
base_uv -= uv_offset; \
|
||||||
|
\
|
||||||
|
if(vertical_texture){ \
|
||||||
|
base_uv = base_uv.yx; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
vec4 T = textureLod(tex, base_uv, 0.0); \
|
||||||
|
ALBEDO = T.rgb; \
|
||||||
|
ALPHA = T.a; \
|
||||||
|
\
|
||||||
|
if(use_red_as_alpha){ \
|
||||||
|
ALBEDO = vec3(1); \
|
||||||
|
ALPHA = T.r; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
T = textureLod(color_ramp, raw_uv, 0.0); \
|
||||||
|
ALBEDO *= T.rgb; \
|
||||||
|
ALPHA *= T.a; \
|
||||||
|
} missing_parens
|
||||||
|
|
||||||
|
#endif /*GPU_TRAIL*/
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://lxfndmjp47ua
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
shader_type particles;
|
||||||
|
|
||||||
|
render_mode keep_data,disable_force,disable_velocity;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void process() {
|
||||||
|
// CUSTOM.w tracks the particles place in the trail, in range (0..LIFETIME]
|
||||||
|
// requires that LIFETIME = number of particles
|
||||||
|
float amount = LIFETIME;
|
||||||
|
|
||||||
|
vec4 a = EMISSION_TRANSFORM * vec4(0,1,0,1);
|
||||||
|
vec4 b = EMISSION_TRANSFORM * vec4(0,-1,0,1);
|
||||||
|
|
||||||
|
// start
|
||||||
|
if(CUSTOM.w == 0.0){
|
||||||
|
CUSTOM.w = float(INDEX)+1.0;
|
||||||
|
|
||||||
|
// needed to pass to draw pass
|
||||||
|
CUSTOM.z = amount;
|
||||||
|
|
||||||
|
// needed to initialize in case of CUSTOM.w == 2.0
|
||||||
|
TRANSFORM = mat4(a,a,b,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restart
|
||||||
|
if(CUSTOM.w == amount+1.0){
|
||||||
|
CUSTOM.w = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CUSTOM.w == 1.0){
|
||||||
|
// sets the quad to the line to cache this frame, it is not yet visible
|
||||||
|
TRANSFORM = mat4(a,a,b,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CUSTOM.w == 2.0){
|
||||||
|
// sets the right edge of the quad
|
||||||
|
TRANSFORM[1] = a;
|
||||||
|
TRANSFORM[2] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUSTOM.w++;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://x3g5fson40t2
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
|
||||||
|
render_mode unshaded,world_vertex_coords,cull_disabled;
|
||||||
|
|
||||||
|
uniform sampler2D tex : repeat_enable, source_color, hint_default_white;
|
||||||
|
uniform vec2 uv_offset = vec2(0);
|
||||||
|
uniform sampler2D color_ramp : repeat_disable, source_color, hint_default_white;
|
||||||
|
uniform sampler2D curve : repeat_disable, hint_default_white;
|
||||||
|
uniform mat4 emmission_transform = mat4(1);
|
||||||
|
uniform int flags = 0;
|
||||||
|
/*uniform bool vertical_texture = false;
|
||||||
|
uniform bool use_red_as_alpha = false;
|
||||||
|
uniform bool billboard = false;
|
||||||
|
uniform bool dewiggle = false;
|
||||||
|
uniform bool snap_to_transform = false;*/
|
||||||
|
|
||||||
|
#define vertical_texture bool(flags & 1)
|
||||||
|
#define use_red_as_alpha bool(flags & 2)
|
||||||
|
#define billboard bool(flags & 4)
|
||||||
|
#define dewiggle bool(flags & 8)
|
||||||
|
#define snap_to_transform bool(flags & 16)
|
||||||
|
#define clip_overlaps bool(flags & 32)
|
||||||
|
|
||||||
|
|
||||||
|
varying float scale_interp;
|
||||||
|
varying vec2 clip;
|
||||||
|
varying vec2 mesh_uv;
|
||||||
|
void vertex(){
|
||||||
|
mesh_uv = UV;
|
||||||
|
|
||||||
|
mat4 my_model_matrix = MODEL_MATRIX;
|
||||||
|
if(snap_to_transform && INSTANCE_CUSTOM.w==2.0){
|
||||||
|
my_model_matrix[1] = emmission_transform * vec4(0,1,0,1);
|
||||||
|
my_model_matrix[2] = emmission_transform * vec4(0,-1,0,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(billboard){
|
||||||
|
vec3 t0 = my_model_matrix[0].xyz-my_model_matrix[3].xyz;
|
||||||
|
vec3 t1 = my_model_matrix[1].xyz-my_model_matrix[2].xyz;
|
||||||
|
|
||||||
|
//vec3 up1 = up0;
|
||||||
|
vec3 up0 = length(t0)*normalize(
|
||||||
|
cross(
|
||||||
|
my_model_matrix[3].xyz-INV_VIEW_MATRIX[3].xyz,
|
||||||
|
//-INV_VIEW_MATRIX[2].xyz,
|
||||||
|
t0));
|
||||||
|
vec3 up1 = length(t1)*normalize(
|
||||||
|
cross(
|
||||||
|
my_model_matrix[2].xyz-INV_VIEW_MATRIX[3].xyz,
|
||||||
|
//-INV_VIEW_MATRIX[2].xyz,
|
||||||
|
t1));
|
||||||
|
|
||||||
|
my_model_matrix[0] = my_model_matrix[3];
|
||||||
|
my_model_matrix[1] = my_model_matrix[2];
|
||||||
|
|
||||||
|
my_model_matrix[0].xyz += up0;
|
||||||
|
my_model_matrix[3].xyz -= up0;
|
||||||
|
|
||||||
|
my_model_matrix[1].xyz += up1;
|
||||||
|
my_model_matrix[2].xyz -= up1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 a = mix(my_model_matrix[1].xyz,my_model_matrix[0].xyz,UV.x);
|
||||||
|
vec3 b = mix(my_model_matrix[2].xyz,my_model_matrix[3].xyz,UV.x);
|
||||||
|
|
||||||
|
UV.x = (UV.x + INSTANCE_CUSTOM.w-1.0 - 2.0)/(INSTANCE_CUSTOM.z-1.0);
|
||||||
|
|
||||||
|
float h = textureLod(curve, vec2(UV.x), 0.0).x;//h=1.0;
|
||||||
|
|
||||||
|
VERTEX = mix(a,b,(UV.y-0.5)*h + 0.5);
|
||||||
|
|
||||||
|
if(dewiggle){
|
||||||
|
scale_interp = h;
|
||||||
|
UV *= scale_interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
clip.x = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[1].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[2].xyz - INV_VIEW_MATRIX[3].xyz));
|
||||||
|
clip.y = dot(VERTEX - INV_VIEW_MATRIX[3].xyz,cross(my_model_matrix[3].xyz - INV_VIEW_MATRIX[3].xyz,my_model_matrix[0].xyz - INV_VIEW_MATRIX[3].xyz));
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment(){
|
||||||
|
//if(billboard && !FRONT_FACING) discard;
|
||||||
|
|
||||||
|
vec2 clip0 = clip;
|
||||||
|
float ababab = clip0.x*clip0.y;
|
||||||
|
//ababab += dFdx(ababab) + dFdy(ababab);
|
||||||
|
//clip0 -= fwidth(clip0);
|
||||||
|
if(clip_overlaps && ababab < 0.0) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(abs(mesh_uv.x-0.5)<0.5)
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 base_uv = UV;
|
||||||
|
|
||||||
|
if(dewiggle){
|
||||||
|
base_uv /= scale_interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 raw_uv = base_uv;
|
||||||
|
|
||||||
|
// Handle UV scrolling
|
||||||
|
base_uv -= uv_offset;
|
||||||
|
|
||||||
|
if(vertical_texture){
|
||||||
|
base_uv = base_uv.yx;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 T = textureLod(tex, base_uv, 0.0);
|
||||||
|
ALBEDO = T.rgb;
|
||||||
|
ALPHA = T.a;
|
||||||
|
|
||||||
|
if(use_red_as_alpha){
|
||||||
|
ALBEDO = vec3(1);
|
||||||
|
ALPHA = T.r;
|
||||||
|
}
|
||||||
|
|
||||||
|
T = textureLod(color_ramp, raw_uv, 0.0);
|
||||||
|
ALBEDO *= T.rgb;
|
||||||
|
ALPHA *= T.a;
|
||||||
|
|
||||||
|
//ALBEDO = vec3(UV,0);
|
||||||
|
|
||||||
|
if((base_uv.x < .01) || (.99 < base_uv.x)){
|
||||||
|
//ALBEDO = vec3(1,0,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://7xkxpgsmixhn
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Blender 3.6.0 MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
+62867
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wavefront_obj"
|
||||||
|
importer_version=1
|
||||||
|
type="Mesh"
|
||||||
|
uid="uid://cmswy8js5ghvq"
|
||||||
|
path="res://.godot/imported/Mountains.obj-081ad0e719bf659be14b6580f50c05b4.mesh"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
files=["res://.godot/imported/Mountains.obj-081ad0e719bf659be14b6580f50c05b4.mesh"]
|
||||||
|
|
||||||
|
source_file="res://Models/Mountains.obj"
|
||||||
|
dest_files=["res://.godot/imported/Mountains.obj-081ad0e719bf659be14b6580f50c05b4.mesh", "res://.godot/imported/Mountains.obj-081ad0e719bf659be14b6580f50c05b4.mesh"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
generate_tangents=true
|
||||||
|
generate_lods=true
|
||||||
|
generate_shadow_mesh=true
|
||||||
|
generate_lightmap_uv2=false
|
||||||
|
generate_lightmap_uv2_texel_size=0.2
|
||||||
|
scale_mesh=Vector3(1, 1, 1)
|
||||||
|
offset_mesh=Vector3(0, 0, 0)
|
||||||
|
force_disable_mesh_compression=false
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
[gd_scene load_steps=11 format=3 uid="uid://cvwb0xnja8txj"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bkdqbagbitktv" path="res://Scripts/SpawnAoE.gd" id="1_uhfrq"]
|
||||||
|
[ext_resource type="Script" uid="uid://dq7h3nectp4hy" path="res://Scripts/camera.gd" id="3_ufqdh"]
|
||||||
|
[ext_resource type="ArrayMesh" uid="uid://cmswy8js5ghvq" path="res://Models/Mountains.obj" id="4_ulx4j"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_uhfrq"]
|
||||||
|
metadata/__load_path__ = "res://Prefabs/vfx_aoe_02.tscn"
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_338y4"]
|
||||||
|
sky_energy_multiplier = 0.65
|
||||||
|
|
||||||
|
[sub_resource type="Sky" id="Sky_s2m6d"]
|
||||||
|
sky_material = SubResource("ProceduralSkyMaterial_338y4")
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_01qi8"]
|
||||||
|
background_mode = 2
|
||||||
|
background_energy_multiplier = 0.38
|
||||||
|
sky = SubResource("Sky_s2m6d")
|
||||||
|
glow_enabled = true
|
||||||
|
glow_levels/6 = 0.13
|
||||||
|
glow_levels/7 = 0.25
|
||||||
|
glow_intensity = 0.1
|
||||||
|
glow_blend_mode = 0
|
||||||
|
glow_hdr_threshold = 0.5
|
||||||
|
glow_hdr_scale = 1.5
|
||||||
|
volumetric_fog_enabled = true
|
||||||
|
volumetric_fog_density = 0.0811
|
||||||
|
volumetric_fog_albedo = Color(0.243137, 0.243137, 0.243137, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_s4vrp"]
|
||||||
|
dof_blur_far_enabled = true
|
||||||
|
dof_blur_far_distance = 100.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_vf5wh"]
|
||||||
|
size = Vector3(150, 0, 150)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_4gkui"]
|
||||||
|
size = Vector3(150, 1.93747, 150)
|
||||||
|
|
||||||
|
[node name="World" type="Node3D" node_paths=PackedStringArray("camera")]
|
||||||
|
script = ExtResource("1_uhfrq")
|
||||||
|
camera = NodePath("Scene/Camera3D")
|
||||||
|
aoe_prefab = SubResource("Resource_uhfrq")
|
||||||
|
|
||||||
|
[node name="Scene" type="Node" parent="."]
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="Scene"]
|
||||||
|
environment = SubResource("Environment_01qi8")
|
||||||
|
camera_attributes = SubResource("CameraAttributesPractical_s4vrp")
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Scene/WorldEnvironment"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.941294, 0.337588, 0, -0.337588, 0.941294, 0, 2.72096, 3.90772)
|
||||||
|
script = ExtResource("3_ufqdh")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.84934, 0.527846, 0, -0.527846, 0.84934, 0, 2.9349, 0)
|
||||||
|
light_energy = 0.5
|
||||||
|
|
||||||
|
[node name="Mountains" type="MeshInstance3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.27348, 0, 0, 0, 1.26814, -21.5595, -3.87235, 0)
|
||||||
|
mesh = ExtResource("4_ulx4j")
|
||||||
|
skeleton = NodePath("../..")
|
||||||
|
|
||||||
|
[node name="Ground" type="StaticBody3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Scene/Ground"]
|
||||||
|
mesh = SubResource("BoxMesh_vf5wh")
|
||||||
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Scene/Ground"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.468733, 0)
|
||||||
|
shape = SubResource("BoxShape3D_4gkui")
|
||||||
|
|
||||||
|
[node name="SpotLight3D" type="SpotLight3D" parent="Scene"]
|
||||||
|
transform = Transform3D(0.714169, 0.238575, -0.658061, 0.196049, 0.834321, 0.515241, 0.671958, -0.496982, 0.549074, 3.08513, 6.69863, 4.07749)
|
||||||
|
spot_range = 60.629
|
||||||
|
spot_attenuation = 0.67
|
||||||
|
spot_angle = 55.0
|
||||||
|
spot_angle_attenuation = 2.82843
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Scene"]
|
||||||
|
transform = Transform3D(0.827962, 0.25459, -0.499662, 0, 0.891007, 0.45399, 0.560784, -0.375887, 0.73772, -8.97652, 8.79728, 11.4697)
|
||||||
|
current = true
|
||||||
|
fov = 50.0
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
[gd_scene load_steps=14 format=3 uid="uid://jf6lhabdtxqs"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://gs00msx4i83u" path="res://Scripts/SpawnProjectile.gd" id="1_idti0"]
|
||||||
|
[ext_resource type="Script" uid="uid://dq7h3nectp4hy" path="res://Scripts/camera.gd" id="3_ynfkw"]
|
||||||
|
[ext_resource type="ArrayMesh" uid="uid://cmswy8js5ghvq" path="res://Models/Mountains.obj" id="4_qjsfk"]
|
||||||
|
[ext_resource type="Script" uid="uid://b86hxdolpatb8" path="res://Scripts/RotateToMouse2.gd" id="5_5wsiv"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_h7mdb"]
|
||||||
|
metadata/__load_path__ = "res://Prefabs/vfx_projectile_01.tscn"
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_338y4"]
|
||||||
|
sky_energy_multiplier = 0.65
|
||||||
|
|
||||||
|
[sub_resource type="Sky" id="Sky_s2m6d"]
|
||||||
|
sky_material = SubResource("ProceduralSkyMaterial_338y4")
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_01qi8"]
|
||||||
|
background_mode = 2
|
||||||
|
background_energy_multiplier = 0.38
|
||||||
|
sky = SubResource("Sky_s2m6d")
|
||||||
|
glow_enabled = true
|
||||||
|
glow_levels/6 = 0.13
|
||||||
|
glow_levels/7 = 0.25
|
||||||
|
glow_intensity = 0.1
|
||||||
|
glow_blend_mode = 0
|
||||||
|
glow_hdr_threshold = 0.5
|
||||||
|
glow_hdr_scale = 1.5
|
||||||
|
volumetric_fog_enabled = true
|
||||||
|
volumetric_fog_density = 0.0811
|
||||||
|
volumetric_fog_albedo = Color(0.243137, 0.243137, 0.243137, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_s4vrp"]
|
||||||
|
dof_blur_far_enabled = true
|
||||||
|
dof_blur_far_distance = 100.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_vf5wh"]
|
||||||
|
size = Vector3(150, 0, 150)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_4gkui"]
|
||||||
|
size = Vector3(150, 1, 150)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_appbf"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_nckwn"]
|
||||||
|
size = Vector3(1.34387, 1, 1)
|
||||||
|
|
||||||
|
[node name="World" type="Node3D" node_paths=PackedStringArray("rotate_to_mouse", "fire_point")]
|
||||||
|
script = ExtResource("1_idti0")
|
||||||
|
projectile_prefab = SubResource("Resource_h7mdb")
|
||||||
|
rotate_to_mouse = NodePath("Scene/CSGSphere3D")
|
||||||
|
fire_point = NodePath("Scene/CSGSphere3D/CSGBox3D/FirePoint")
|
||||||
|
|
||||||
|
[node name="Scene" type="Node" parent="."]
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="Scene"]
|
||||||
|
environment = SubResource("Environment_01qi8")
|
||||||
|
camera_attributes = SubResource("CameraAttributesPractical_s4vrp")
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Scene/WorldEnvironment"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.941294, 0.337588, 0, -0.337588, 0.941294, 0, 2.72096, 3.90772)
|
||||||
|
script = ExtResource("3_ynfkw")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.84934, 0.527846, 0, -0.527846, 0.84934, 0, 2.9349, 0)
|
||||||
|
light_energy = 0.5
|
||||||
|
|
||||||
|
[node name="Mountains" type="MeshInstance3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.27348, 0, 0, 0, 1.26814, -21.5595, -3.87235, 0)
|
||||||
|
mesh = ExtResource("4_qjsfk")
|
||||||
|
skeleton = NodePath("../..")
|
||||||
|
|
||||||
|
[node name="Ground" type="StaticBody3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Scene/Ground"]
|
||||||
|
mesh = SubResource("BoxMesh_vf5wh")
|
||||||
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Scene/Ground"]
|
||||||
|
shape = SubResource("BoxShape3D_4gkui")
|
||||||
|
|
||||||
|
[node name="Wall" type="StaticBody3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 11.0298, 0, 0)
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Scene/Wall"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 5.4, 0, 0, 0, 11, 0.470179, 1.658, 0)
|
||||||
|
mesh = SubResource("BoxMesh_appbf")
|
||||||
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Scene/Wall"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 5.4, 0, 0, 0, 11, 0.298243, 1.658, 0)
|
||||||
|
shape = SubResource("BoxShape3D_nckwn")
|
||||||
|
|
||||||
|
[node name="SpotLight3D" type="SpotLight3D" parent="Scene"]
|
||||||
|
transform = Transform3D(0.714169, 0.238575, -0.658061, 0.196049, 0.834321, 0.515241, 0.671958, -0.496982, 0.549074, 3.08513, 6.69863, 4.07749)
|
||||||
|
spot_range = 60.629
|
||||||
|
spot_attenuation = 0.67
|
||||||
|
spot_angle = 55.0
|
||||||
|
spot_angle_attenuation = 2.82843
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Scene"]
|
||||||
|
transform = Transform3D(0.827962, 0.25459, -0.499662, 0, 0.891007, 0.45399, 0.560784, -0.375887, 0.73772, -8.97652, 8.79728, 11.4697)
|
||||||
|
current = true
|
||||||
|
fov = 50.0
|
||||||
|
|
||||||
|
[node name="CSGSphere3D" type="CSGSphere3D" parent="Scene" node_paths=PackedStringArray("camera")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, 1, 0)
|
||||||
|
script = ExtResource("5_5wsiv")
|
||||||
|
camera = NodePath("../Camera3D")
|
||||||
|
rotation_speed = 50.0
|
||||||
|
|
||||||
|
[node name="CSGBox3D" type="CSGBox3D" parent="Scene/CSGSphere3D"]
|
||||||
|
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0, -0.6)
|
||||||
|
|
||||||
|
[node name="FirePoint" type="Node3D" parent="Scene/CSGSphere3D/CSGBox3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.0331)
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
[gd_scene load_steps=10 format=3 uid="uid://cvb1vgt52x0cy"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dq7h3nectp4hy" path="res://Scripts/camera.gd" id="1_r84vf"]
|
||||||
|
[ext_resource type="ArrayMesh" uid="uid://cmswy8js5ghvq" path="res://Models/Mountains.obj" id="2_tbjhe"]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_338y4"]
|
||||||
|
sky_energy_multiplier = 0.65
|
||||||
|
|
||||||
|
[sub_resource type="Sky" id="Sky_s2m6d"]
|
||||||
|
sky_material = SubResource("ProceduralSkyMaterial_338y4")
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_01qi8"]
|
||||||
|
background_mode = 2
|
||||||
|
background_energy_multiplier = 0.38
|
||||||
|
sky = SubResource("Sky_s2m6d")
|
||||||
|
glow_enabled = true
|
||||||
|
glow_levels/6 = 0.13
|
||||||
|
glow_levels/7 = 0.25
|
||||||
|
glow_intensity = 0.1
|
||||||
|
glow_blend_mode = 0
|
||||||
|
glow_hdr_threshold = 0.5
|
||||||
|
glow_hdr_scale = 1.5
|
||||||
|
volumetric_fog_enabled = true
|
||||||
|
volumetric_fog_density = 0.0811
|
||||||
|
volumetric_fog_albedo = Color(0.243137, 0.243137, 0.243137, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_s4vrp"]
|
||||||
|
dof_blur_far_enabled = true
|
||||||
|
dof_blur_far_distance = 100.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_vf5wh"]
|
||||||
|
size = Vector3(150, 0, 150)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_4gkui"]
|
||||||
|
size = Vector3(150, 1, 150)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_appbf"]
|
||||||
|
|
||||||
|
[node name="World" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Scene" type="Node" parent="."]
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="Scene"]
|
||||||
|
environment = SubResource("Environment_01qi8")
|
||||||
|
camera_attributes = SubResource("CameraAttributesPractical_s4vrp")
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Scene/WorldEnvironment"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.941294, 0.337588, 0, -0.337588, 0.941294, 0, 2.72096, 3.90772)
|
||||||
|
script = ExtResource("1_r84vf")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.84934, 0.527846, 0, -0.527846, 0.84934, 0, 2.9349, 0)
|
||||||
|
light_energy = 0.5
|
||||||
|
|
||||||
|
[node name="Mountains" type="MeshInstance3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.27348, 0, 0, 0, 1.26814, -21.5595, -3.87235, 0)
|
||||||
|
mesh = ExtResource("2_tbjhe")
|
||||||
|
skeleton = NodePath("../..")
|
||||||
|
|
||||||
|
[node name="Ground" type="StaticBody3D" parent="Scene"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Scene/Ground"]
|
||||||
|
mesh = SubResource("BoxMesh_vf5wh")
|
||||||
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Scene/Ground"]
|
||||||
|
shape = SubResource("BoxShape3D_4gkui")
|
||||||
|
|
||||||
|
[node name="Cube" type="MeshInstance3D" parent="Scene"]
|
||||||
|
transform = Transform3D(0.7, 0, 0, 0, 2, 0, 0, 0, 0.7, -3.27909, -0.131935, 0)
|
||||||
|
mesh = SubResource("BoxMesh_appbf")
|
||||||
|
skeleton = NodePath("../..")
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
@tool
|
||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var play_particles: bool = false:
|
||||||
|
set(value):
|
||||||
|
if value:
|
||||||
|
_find_particles() # Always scan for new particles
|
||||||
|
_cleanup_delays() # Remove deleted particles from the list
|
||||||
|
_start_delays() # Ensure delays exist for new particles
|
||||||
|
_play_particles()
|
||||||
|
play_particles = false # Reset the checkbox immediately
|
||||||
|
|
||||||
|
var particle_systems: Array
|
||||||
|
@export var delays: Dictionary
|
||||||
|
|
||||||
|
@export var cleanDelays: bool = false:
|
||||||
|
set(value):
|
||||||
|
if value:
|
||||||
|
delays.clear()
|
||||||
|
cleanDelays = false
|
||||||
|
|
||||||
|
func _find_particles():
|
||||||
|
particle_systems.clear() # Always clear and re-detect
|
||||||
|
var existing_delays = delays.duplicate() # Preserve existing delays
|
||||||
|
|
||||||
|
for child in get_children():
|
||||||
|
if child is GPUParticles3D:
|
||||||
|
particle_systems.append(child)
|
||||||
|
if not existing_delays.has(child.name):
|
||||||
|
existing_delays[child.name] = 0.0 # Assign default delay
|
||||||
|
|
||||||
|
delays = existing_delays # Restore old delays + new ones
|
||||||
|
|
||||||
|
func _cleanup_delays(): # Remove delays for particles that no longer exist
|
||||||
|
var valid_particle_names = particle_systems.map(func(p): return p.name)
|
||||||
|
for key in delays.keys():
|
||||||
|
if key not in valid_particle_names:
|
||||||
|
delays.erase(key) # Remove old particle system references
|
||||||
|
|
||||||
|
func _start_delays():
|
||||||
|
for particle in particle_systems:
|
||||||
|
if not delays.has(particle.name):
|
||||||
|
delays[particle.name] = 0.0 # Keep existing delays, add new ones
|
||||||
|
|
||||||
|
func _play_particles():
|
||||||
|
for particle in particle_systems:
|
||||||
|
var delay = delays.get(particle.name, 0.0)
|
||||||
|
_playDelay(particle, delay)
|
||||||
|
|
||||||
|
func _playDelay(ps: GPUParticles3D, delay: float):
|
||||||
|
ps.emitting = false # Reset first (prevents issues)
|
||||||
|
await get_tree().create_timer(delay).timeout
|
||||||
|
ps.restart() # Works in play mode
|
||||||
|
ps.emitting = true # Start emitting
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dxhfn5g0spoim
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
extends RigidBody3D
|
||||||
|
|
||||||
|
@export var speed: float = 10.0
|
||||||
|
@export var muzzle_prefab: PackedScene
|
||||||
|
@export var impact_prefab: PackedScene
|
||||||
|
@export var delay_trails_start: float = 0.1
|
||||||
|
@export var trails: Array[GPUTrail3D]
|
||||||
|
|
||||||
|
var direction: Vector3 = Vector3.FORWARD
|
||||||
|
var fire_point_position: Vector3
|
||||||
|
|
||||||
|
func set_fire_point(fp_position: Vector3):
|
||||||
|
fire_point_position = fp_position
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
delay_trails()
|
||||||
|
spawn_muzzle()
|
||||||
|
contact_monitor = true
|
||||||
|
max_contacts_reported = 1
|
||||||
|
|
||||||
|
func _integrate_forces(state):
|
||||||
|
linear_velocity = direction * speed
|
||||||
|
|
||||||
|
var collision = state.get_contact_count()
|
||||||
|
if collision > 0:
|
||||||
|
var contact = state.get_contact_collider_position(0)
|
||||||
|
var normal = state.get_contact_local_normal(0)
|
||||||
|
spawn_impact(contact, normal)
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func spawn_muzzle():
|
||||||
|
if muzzle_prefab:
|
||||||
|
var muzzle_instance = muzzle_prefab.instantiate()
|
||||||
|
call_deferred("add_child", muzzle_instance)
|
||||||
|
await get_tree().create_timer(0.001).timeout
|
||||||
|
muzzle_instance.global_transform.origin = fire_point_position
|
||||||
|
muzzle_instance.play_particles = true
|
||||||
|
|
||||||
|
await get_tree().create_timer(3.0).timeout
|
||||||
|
if is_instance_valid(muzzle_instance):
|
||||||
|
muzzle_instance.queue_free()
|
||||||
|
|
||||||
|
func spawn_impact(contact_point: Vector3 = Vector3.ZERO, contact_normal: Vector3 = Vector3.ZERO):
|
||||||
|
if impact_prefab:
|
||||||
|
var impact_instance = impact_prefab.instantiate()
|
||||||
|
get_tree().current_scene.add_child(impact_instance)
|
||||||
|
impact_instance.play_particles = true
|
||||||
|
|
||||||
|
impact_instance.global_transform.origin = contact_point
|
||||||
|
impact_instance.look_at(contact_point + contact_normal, Vector3.UP)
|
||||||
|
|
||||||
|
await get_tree().create_timer(3.0).timeout
|
||||||
|
if is_instance_valid(impact_instance):
|
||||||
|
impact_instance.queue_free()
|
||||||
|
|
||||||
|
func delay_trails():
|
||||||
|
if trails.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
for trail in trails:
|
||||||
|
if is_instance_valid(trail):
|
||||||
|
trail.speed_scale = 0 # Stop movement initially, avoids glitches
|
||||||
|
|
||||||
|
await get_tree().create_timer(delay_trails_start).timeout
|
||||||
|
|
||||||
|
for trail in trails:
|
||||||
|
if is_instance_valid(trail):
|
||||||
|
trail.speed_scale = 1 # Resume movement
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://srxbm3tbdhyu
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var camera: Camera3D = null
|
||||||
|
@export var rotation_speed: float = 5.0
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
if camera:
|
||||||
|
var mouse_pos = get_viewport().get_mouse_position()
|
||||||
|
var ray_origin = camera.project_ray_origin(mouse_pos)
|
||||||
|
var ray_dir = camera.project_ray_normal(mouse_pos)
|
||||||
|
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_dir * 1000.0)
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
var target_position = result["position"] if result else ray_origin + ray_dir * 10.0
|
||||||
|
var direction = (target_position - global_transform.origin).normalized()
|
||||||
|
var target_rotation = Quaternion(Vector3.FORWARD, direction)
|
||||||
|
transform.basis = Basis(transform.basis.get_rotation_quaternion().slerp(target_rotation, delta * rotation_speed))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b86hxdolpatb8
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var camera: Camera3D = null
|
||||||
|
@export var fire_rate: float = 0.5
|
||||||
|
@export var aoe_lifetime: float = 7.0
|
||||||
|
@export var aoe_prefab: PackedScene
|
||||||
|
|
||||||
|
var can_fire: bool = true
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
if Input.is_action_pressed("fire") and can_fire:
|
||||||
|
fire_aoe()
|
||||||
|
can_fire = false
|
||||||
|
await get_tree().create_timer(fire_rate).timeout
|
||||||
|
can_fire = true
|
||||||
|
|
||||||
|
func fire_aoe():
|
||||||
|
if not (aoe_prefab and camera):
|
||||||
|
return
|
||||||
|
|
||||||
|
var mouse_position = get_viewport().get_mouse_position()
|
||||||
|
var ray_origin = camera.project_ray_origin(mouse_position)
|
||||||
|
var ray_direction = camera.project_ray_normal(mouse_position) * 1000 # Long ray
|
||||||
|
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_direction)
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
if result.has("position"):
|
||||||
|
var aoe_instance = aoe_prefab.instantiate()
|
||||||
|
get_parent().add_child(aoe_instance)
|
||||||
|
aoe_instance.global_position = result["position"] # Spawn at hit position
|
||||||
|
aoe_instance.play_particles = true # Start particle effect
|
||||||
|
|
||||||
|
await get_tree().create_timer(aoe_lifetime).timeout
|
||||||
|
if is_instance_valid(aoe_instance):
|
||||||
|
aoe_instance.queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bkdqbagbitktv
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var fire_rate: float = 0.5
|
||||||
|
@export var projectile_lifetime: float = 4.0
|
||||||
|
@export var projectile_prefab: PackedScene
|
||||||
|
@export var rotate_to_mouse: Node3D
|
||||||
|
@export var fire_point: Node3D
|
||||||
|
|
||||||
|
var can_fire: bool = true
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
if Input.is_action_pressed("fire") and can_fire:
|
||||||
|
fire_projectile()
|
||||||
|
can_fire = false
|
||||||
|
await get_tree().create_timer(fire_rate).timeout
|
||||||
|
can_fire = true
|
||||||
|
|
||||||
|
func fire_projectile():
|
||||||
|
if projectile_prefab and fire_point and rotate_to_mouse:
|
||||||
|
var projectile_instance = projectile_prefab.instantiate()
|
||||||
|
get_parent().add_child(projectile_instance)
|
||||||
|
projectile_instance.global_position = fire_point.global_position
|
||||||
|
projectile_instance.set_fire_point(fire_point.global_transform.origin)
|
||||||
|
|
||||||
|
var direction = -rotate_to_mouse.global_transform.basis.z.normalized()
|
||||||
|
projectile_instance.direction = direction
|
||||||
|
projectile_instance.look_at(fire_point.global_position + -direction)
|
||||||
|
|
||||||
|
await get_tree().create_timer(projectile_lifetime).timeout
|
||||||
|
if projectile_instance:
|
||||||
|
projectile_instance.queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://gs00msx4i83u
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
class_name FreeLookCamera extends Camera3D
|
||||||
|
|
||||||
|
# Modifier keys' speed multiplier
|
||||||
|
const SHIFT_MULTIPLIER = 2.5
|
||||||
|
const ALT_MULTIPLIER = 1.0 / SHIFT_MULTIPLIER
|
||||||
|
|
||||||
|
|
||||||
|
@export_range(0.0, 1.0) var sensitivity: float = 0.25
|
||||||
|
|
||||||
|
# Mouse state
|
||||||
|
var _mouse_position = Vector2(0.0, 0.0)
|
||||||
|
var _total_pitch = 0.0
|
||||||
|
|
||||||
|
# Movement state
|
||||||
|
var _direction = Vector3(0.0, 0.0, 0.0)
|
||||||
|
var _velocity = Vector3(0.0, 0.0, 0.0)
|
||||||
|
var _acceleration = 30
|
||||||
|
var _deceleration = -10
|
||||||
|
var _vel_multiplier = 4
|
||||||
|
|
||||||
|
# Keyboard state
|
||||||
|
var _w = false
|
||||||
|
var _s = false
|
||||||
|
var _a = false
|
||||||
|
var _d = false
|
||||||
|
var _q = false
|
||||||
|
var _e = false
|
||||||
|
var _shift = false
|
||||||
|
var _alt = false
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
# Receives mouse motion
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
_mouse_position = event.relative
|
||||||
|
|
||||||
|
# Receives mouse button input
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
match event.button_index:
|
||||||
|
MOUSE_BUTTON_RIGHT: # Only allows rotation if right click down
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE)
|
||||||
|
MOUSE_BUTTON_WHEEL_UP: # Increases max velocity
|
||||||
|
_vel_multiplier = clamp(_vel_multiplier * 1.1, 0.2, 20)
|
||||||
|
MOUSE_BUTTON_WHEEL_DOWN: # Decereases max velocity
|
||||||
|
_vel_multiplier = clamp(_vel_multiplier / 1.1, 0.2, 20)
|
||||||
|
|
||||||
|
# Receives key input
|
||||||
|
if event is InputEventKey:
|
||||||
|
match event.keycode:
|
||||||
|
KEY_W:
|
||||||
|
_w = event.pressed
|
||||||
|
KEY_S:
|
||||||
|
_s = event.pressed
|
||||||
|
KEY_A:
|
||||||
|
_a = event.pressed
|
||||||
|
KEY_D:
|
||||||
|
_d = event.pressed
|
||||||
|
KEY_Q:
|
||||||
|
_q = event.pressed
|
||||||
|
KEY_E:
|
||||||
|
_e = event.pressed
|
||||||
|
KEY_SHIFT:
|
||||||
|
_shift = event.pressed
|
||||||
|
KEY_ALT:
|
||||||
|
_alt = event.pressed
|
||||||
|
|
||||||
|
# Updates mouselook and movement every frame
|
||||||
|
func _process(delta):
|
||||||
|
_update_mouselook()
|
||||||
|
_update_movement(delta)
|
||||||
|
|
||||||
|
# Updates camera movement
|
||||||
|
func _update_movement(delta):
|
||||||
|
# Computes desired direction from key states
|
||||||
|
_direction = Vector3(
|
||||||
|
(_d as float) - (_a as float),
|
||||||
|
(_e as float) - (_q as float),
|
||||||
|
(_s as float) - (_w as float)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Computes the change in velocity due to desired direction and "drag"
|
||||||
|
# The "drag" is a constant acceleration on the camera to bring it's velocity to 0
|
||||||
|
var offset = _direction.normalized() * _acceleration * _vel_multiplier * delta \
|
||||||
|
+ _velocity.normalized() * _deceleration * _vel_multiplier * delta
|
||||||
|
|
||||||
|
# Compute modifiers' speed multiplier
|
||||||
|
var speed_multi = 1
|
||||||
|
if _shift: speed_multi *= SHIFT_MULTIPLIER
|
||||||
|
if _alt: speed_multi *= ALT_MULTIPLIER
|
||||||
|
|
||||||
|
# Checks if we should bother translating the camera
|
||||||
|
if _direction == Vector3.ZERO and offset.length_squared() > _velocity.length_squared():
|
||||||
|
# Sets the velocity to 0 to prevent jittering due to imperfect deceleration
|
||||||
|
_velocity = Vector3.ZERO
|
||||||
|
else:
|
||||||
|
# Clamps speed to stay within maximum value (_vel_multiplier)
|
||||||
|
_velocity.x = clamp(_velocity.x + offset.x, -_vel_multiplier, _vel_multiplier)
|
||||||
|
_velocity.y = clamp(_velocity.y + offset.y, -_vel_multiplier, _vel_multiplier)
|
||||||
|
_velocity.z = clamp(_velocity.z + offset.z, -_vel_multiplier, _vel_multiplier)
|
||||||
|
|
||||||
|
translate(_velocity * delta * speed_multi)
|
||||||
|
|
||||||
|
# Updates mouse look
|
||||||
|
func _update_mouselook():
|
||||||
|
# Only rotates mouse if the mouse is captured
|
||||||
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||||
|
_mouse_position *= sensitivity
|
||||||
|
var yaw = _mouse_position.x
|
||||||
|
var pitch = _mouse_position.y
|
||||||
|
_mouse_position = Vector2(0, 0)
|
||||||
|
|
||||||
|
# Prevents looking up/down too far
|
||||||
|
pitch = clamp(pitch, -90 - _total_pitch, 90 - _total_pitch)
|
||||||
|
_total_pitch += pitch
|
||||||
|
|
||||||
|
rotate_y(deg_to_rad(-yaw))
|
||||||
|
rotate_object_local(Vector3(1,0,0), deg_to_rad(-pitch))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dq7h3nectp4hy
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 950 B |
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://f2tnjkmyapp0"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="GAP_VFX_BeginnerCourse"
|
||||||
|
run/main_scene="uid://jf6lhabdtxqs"
|
||||||
|
config/features=PackedStringArray("4.4", "Forward Plus")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[dotnet]
|
||||||
|
|
||||||
|
project/assembly_name="VFX_Fire"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
fire={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user