Godot Version
4.7
Question
My weapon ballistics code dont working right.
I wanted to make "realistically(trying)" custom bullet mechanics with area3d and physicsserver3d raycasts for best performance. But it dont working properly. I am newbie, if anyone help I appreciate:)
I think, issue from momentum/kinetic_energy.
my code:
extends Area3D
const airdensity: float = 1.223
const world_gravity: Vector3 = Vector3(0, 9.81, 0)
@export_group("projectile Description")
@export var projectile_name: String
@export var projectile_mass: float
@export var projectile_diameter: float
@export var start_velocity: float
@export var ballistic_coefficient: float
var drag_coefficient_curve: Curve = preload("res://Weapons/DragCoefficient.tres")
var current_velocity: Vector3 = Vector3.ZERO
@onready var projectile_area: float = PI * pow(projectile_diameter * 0.5, 2)
var old_collison: RID
func _ready() -> void:
current_velocity = self.global_basis.z * start_velocity
func _process(delta: float) -> void:
drive_projectile(delta)
func detect_collisons(start_pos: Vector3, end_pos: Vector3) -> Dictionary:
var space_state: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
var query: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(start_pos, end_pos)
return space_state.intersect_ray(query)
func check_thickness(collison_point: Vector3, velocity_normal: Vector3, original_collider: RID) -> float:
var exclude_list: Array[RID] = []
var thickness: float = 0.0
var start_inside_pos: Vector3 = collison_point + (velocity_normal * 400)
var space_state: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
var query: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(start_inside_pos, collison_point)
query.hit_back_faces = true
for i: int in range(20):
query.exclude = exclude_list
var inside_ray_data: Dictionary = space_state.intersect_ray(query)
if inside_ray_data.is_empty():
break
if inside_ray_data["rid"] == original_collider:
thickness = collison_point.distance_to(inside_ray_data["position"])
break
else:
exclude_list.append(inside_ray_data["rid"])
return thickness
func apply_drag_force(delta: float) -> void:
var projectile_drag: float = 0.5 * drag_coefficient_curve.sample(1) * projectile_area * current_velocity.length_squared() * airdensity
var drag_acc: float = projectile_drag / projectile_mass
current_velocity -= (drag_acc * current_velocity.normalized() * delta)
func drive_projectile(delta: float) -> void:
var old_pos: Vector3 = self.global_position
apply_drag_force(delta)
current_velocity += world_gravity * delta
self.look_at((self.global_position + -current_velocity), Vector3.UP, false)
self.global_position += -current_velocity * delta
var detected_collison: Dictionary = detect_collisons(old_pos, self.global_position)
if not detected_collison.is_empty():
if not old_collison.is_valid() or old_collison != detected_collison["rid"]:
var projectile_momentum: float = ( current_velocity.length() * projectile_mass )
var projectile_energy: float = ( 0.5 * projectile_mass * current_velocity.length_squared() )
var loss_momentum: float = 0.0
var loss_energy: float = 0.0
if detected_collison["collider"].has_meta("mat"):
if detected_collison["collider"].get_meta("mat") is Resource:
var current_meta: Resource = detected_collison["collider"].get_meta("mat")
loss_energy = current_meta.pascal_yield_strength * projectile_area * check_thickness(detected_collison["position"], current_velocity, detected_collison["rid"])
if loss_energy < projectile_energy:
old_collison = detected_collison["rid"]
var new_energy: float = projectile_energy - loss_energy
var new_momentum: float = sqrt(2 * projectile_mass * new_energy)
loss_momentum = projectile_momentum - new_momentum
current_velocity = (new_momentum / projectile_mass) * current_velocity.normalized()
print(str(loss_momentum))
if detected_collison["collider"] is RigidBody3D:
detected_collison["collider"].apply_impulse(loss_momentum * current_velocity.normalized(), detected_collison["position"] - detected_collison["collider"].global_position)
else:
print(str(projectile_momentum))
if detected_collison["collider"] is RigidBody3D:
detected_collison["collider"].apply_impulse(projectile_momentum * current_velocity.normalized(), detected_collison["position"] - detected_collison["collider"].global_position)
self.queue_free()
else:
print("Node ", str(detected_collison["collider"]), " Not Has Material Res!!!!")
func _on_timer_timeout() -> void:
self.queue_free()