You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.3 KiB
102 lines
3.3 KiB
class_name Bullet |
|
extends Node2D |
|
|
|
const LIFE_TIME := 0.6 |
|
const FADE_TIME := 0.6 |
|
|
|
var direction : Vector2 |
|
var effective_range : float |
|
var maximum_range : float |
|
var velocity : float |
|
var damage : float |
|
var color : Color |
|
|
|
var _start_position : Vector2 |
|
var _age := 0.0 |
|
var _distance := 0.0 |
|
|
|
func _init( |
|
position : Vector2, |
|
direction : Vector2, |
|
effective_range : float, |
|
maximum_range : float, |
|
velocity : float, |
|
damage : float, |
|
color : Color, |
|
) -> void: |
|
_start_position = position |
|
self.position = position |
|
self.direction = direction |
|
self.effective_range = effective_range |
|
self.maximum_range = maximum_range |
|
self.velocity = velocity |
|
self.damage = damage |
|
self.color = color |
|
|
|
func _on_collide(obj: CollisionObject2D, hit_position: Vector2) -> void: |
|
# TODO: Add a global game setting to specify whether shooter or server announces successful hit. |
|
# For now, server is the most straight-forward. Eventually, support client predictive movement? |
|
pass |
|
|
|
# protected virtual void OnCollide(CollisionObject2D obj, Vector2 hitPosition) |
|
# { |
|
# // TODO: Add a global game setting to specify whether shooter or server announces successful hit. |
|
# // For now, server is the most straight-forward. Eventually, support client predictive movement? |
|
# if (!(this.GetGame() is Server) || !(obj.GetNodeOrNull("Sprite2D") is Sprite2D sprite)) return; |
|
# var world = this.GetWorld3d(); |
|
# var path = world.GetPathTo(sprite); |
|
# var color = new Color(Color, (1 + Color.a) / 2); |
|
# RPC.Reliable(world.GetPlayersTracking(BlockPos.FromVector(obj.GlobalPosition).ToChunkPos()), |
|
# world.SpawnHit, path, hitPosition, color); |
|
# if (obj is Player player) { |
|
# var rangeFactor = Math.Min(1.0F, (MaximumRange - _distance) / (MaximumRange - EffectiveRange)); |
|
# player.Health -= Damage * rangeFactor; |
|
# } |
|
# // TODO: Also spawn a ghost of the player who was hit so they can see where they got shot? |
|
# } |
|
|
|
func _process(delta: float) -> void: |
|
if _age > LIFE_TIME: |
|
modulate = Color(modulate, modulate.a - delta / FADE_TIME) |
|
if modulate.a <= 0: queue_free() |
|
_age += delta |
|
|
|
func _physics_process(delta: float) -> void: |
|
var previous_position := position |
|
_distance = min(maximum_range, velocity * _age) |
|
position = _start_position + direction * _distance |
|
|
|
var mask := PhysicsLayer.WORLD | PhysicsLayer.PLAYERS |
|
var ray := PhysicsRayQueryParameters2D.create(previous_position, position, mask) |
|
var result := get_world_2d().direct_space_state.intersect_ray(ray) |
|
if !result.is_empty(): |
|
position = result.position as Vector2 |
|
_distance = _start_position.distance_to(position) |
|
var obj := result.collider as CollisionObject2D |
|
if obj: _on_collide(obj, position - obj.global_position) |
|
set_physics_process(false) |
|
|
|
if _distance > maximum_range: |
|
set_physics_process(false) |
|
|
|
queue_redraw() |
|
|
|
func _draw() -> void: |
|
var points: Array[Vector2] |
|
var colors: Array[Color] |
|
|
|
if _distance > 16: |
|
points.append(Vector2.ZERO) |
|
colors.append(Color(color, color.a * minf(1, 1 - (_distance - effective_range) / (maximum_range - effective_range)))) |
|
|
|
if _distance > effective_range: |
|
points.append(direction * -(_distance - effective_range)) |
|
colors.append(color) |
|
|
|
points.append(direction * -maxf(0.0, _distance - 16)) |
|
colors.append(color) |
|
|
|
points.append(direction * -_distance) |
|
colors.append(Color(color, 0.0)) |
|
|
|
draw_polyline_colors(points, colors, 1.5, true)
|
|
|