game: add weapon base and sword
This commit is contained in:
42
scenes/weapons/weapon_base.gd
Normal file
42
scenes/weapons/weapon_base.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
class_name WeaponBase
|
||||
extends Node2D
|
||||
|
||||
@export var attack_cd: float
|
||||
@export var attack_damage: float
|
||||
@export var attack_aoe: float
|
||||
@export var attack_duration: float
|
||||
@export var attack_range: float
|
||||
|
||||
|
||||
func _on_attack_cd_timer_timeout() -> void:
|
||||
do_attack()
|
||||
|
||||
|
||||
func do_attack() -> void:
|
||||
push_error("%s does not implement do_attack" % self)
|
||||
|
||||
|
||||
func find_target_in_radius() -> EnemyBase:
|
||||
var space_state: PhysicsDirectSpaceState2D = get_world_2d().direct_space_state
|
||||
var shape := CircleShape2D.new()
|
||||
shape.radius = attack_range
|
||||
|
||||
var query := PhysicsShapeQueryParameters2D.new()
|
||||
query.shape = shape
|
||||
query.transform = Transform2D(0, global_position)
|
||||
query.collision_mask = 2
|
||||
query.collide_with_bodies = true
|
||||
var results := space_state.intersect_shape(query)
|
||||
if len(results) < 1:
|
||||
return null
|
||||
var closest: PhysicsBody2D = results[0]["collider"]
|
||||
for r in results:
|
||||
var c: PhysicsBody2D = r["collider"]
|
||||
if not c.is_in_group(GlobalConst.GROUP_ENEMY):
|
||||
continue
|
||||
if (
|
||||
c.global_position.distance_to(global_position)
|
||||
< closest.global_position.distance_to(global_position)
|
||||
):
|
||||
closest = c
|
||||
return closest
|
1
scenes/weapons/weapon_base.gd.uid
Normal file
1
scenes/weapons/weapon_base.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d6nwfhyethdw
|
11
scenes/weapons/weapon_base.tscn
Normal file
11
scenes/weapons/weapon_base.tscn
Normal file
@@ -0,0 +1,11 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://i8mtky2req41"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d6nwfhyethdw" path="res://scenes/weapons/weapon_base.gd" id="1_v4xn6"]
|
||||
|
||||
[node name="WeaponBase" type="Node2D"]
|
||||
script = ExtResource("1_v4xn6")
|
||||
|
||||
[node name="AttackCDTimer" type="Timer" parent="."]
|
||||
autostart = true
|
||||
|
||||
[connection signal="timeout" from="AttackCDTimer" to="." method="_on_attack_cd_timer_timeout"]
|
42
scenes/weapons/weapon_sword.gd
Normal file
42
scenes/weapons/weapon_sword.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
class_name WeaponSword
|
||||
extends WeaponBase
|
||||
|
||||
const WEAPON_SWORD_PROJECTILE = preload("res://scenes/weapons/weapon_sword_projectile.tscn")
|
||||
|
||||
@onready var targeting_range: Area2D = $TargetingRange
|
||||
@onready var targeting_range_shape: CollisionShape2D = $TargetingRange/CollisionShape2D
|
||||
|
||||
signal projectile_hit(projectile: WeaponSwordProjectile, enemy: EnemyBase)
|
||||
|
||||
var _player: Player
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
targeting_range_shape.shape.radius = attack_range
|
||||
projectile_hit.connect(_on_projectile_hit)
|
||||
_player = get_tree().get_first_node_in_group(GlobalConst.GROUP_PLAYER)
|
||||
|
||||
|
||||
func do_attack() -> void:
|
||||
var target: EnemyBase = find_target_in_radius()
|
||||
if not target:
|
||||
return
|
||||
|
||||
var projectile = WEAPON_SWORD_PROJECTILE.instantiate()
|
||||
projectile.damage = attack_damage
|
||||
projectile.target = target
|
||||
projectile.on_hit_sig = projectile_hit
|
||||
add_child(projectile)
|
||||
|
||||
|
||||
func deal_damage(enemy: EnemyBase):
|
||||
var crit_chance = _player.player_stats.get_final("crit_chance", _player.modifiers)
|
||||
var damage_dealt = attack_damage
|
||||
var is_crit = randf() >= 1 - crit_chance
|
||||
if is_crit:
|
||||
damage_dealt *= _player.player_stats.get_final("crit_multiplier", _player.modifiers)
|
||||
enemy.take_damage(damage_dealt, is_crit)
|
||||
|
||||
|
||||
func _on_projectile_hit(projectile: WeaponSwordProjectile, enemy: EnemyBase):
|
||||
deal_damage(enemy)
|
1
scenes/weapons/weapon_sword.gd.uid
Normal file
1
scenes/weapons/weapon_sword.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b072d866r4usq
|
22
scenes/weapons/weapon_sword.tscn
Normal file
22
scenes/weapons/weapon_sword.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dfikvj27k01tu"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://i8mtky2req41" path="res://scenes/weapons/weapon_base.tscn" id="1_2dti5"]
|
||||
[ext_resource type="Script" uid="uid://b072d866r4usq" path="res://scenes/weapons/weapon_sword.gd" id="2_ruf80"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_ruf80"]
|
||||
|
||||
[node name="WeaponSword" instance=ExtResource("1_2dti5")]
|
||||
script = ExtResource("2_ruf80")
|
||||
attack_cd = 1.0
|
||||
attack_damage = 5.0
|
||||
attack_aoe = 1.0
|
||||
attack_duration = 1.0
|
||||
attack_range = 150.0
|
||||
|
||||
[node name="TargetingRange" type="Area2D" parent="." index="1"]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetingRange" index="0"]
|
||||
shape = SubResource("CircleShape2D_ruf80")
|
40
scenes/weapons/weapon_sword_projectile.gd
Normal file
40
scenes/weapons/weapon_sword_projectile.gd
Normal file
@@ -0,0 +1,40 @@
|
||||
class_name WeaponSwordProjectile
|
||||
extends Node2D
|
||||
|
||||
@export var speed: float = 500.0
|
||||
@export var range: float = 200.0
|
||||
@export var target: Node2D
|
||||
@export var damage: float
|
||||
@export var on_hit_sig: Signal
|
||||
|
||||
var _direction: Vector2
|
||||
var _traveled: float = 0.0
|
||||
var _already_hit: Array[PhysicsBody2D] = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_direction = global_position.direction_to(target.global_position).normalized()
|
||||
_traveled = 0.0
|
||||
rotation = _direction.angle()
|
||||
if _direction.x < 0:
|
||||
rotation += PI
|
||||
var proj_manager = get_tree().get_first_node_in_group(GlobalConst.GROUP_PROJ_MANAGER)
|
||||
if not proj_manager:
|
||||
return
|
||||
reparent(proj_manager, true)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var step = _direction * speed * delta
|
||||
global_position += step
|
||||
_traveled += step.length()
|
||||
|
||||
if _traveled >= range:
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_area_2d_body_entered(body: Node2D) -> void:
|
||||
if body in _already_hit:
|
||||
return
|
||||
on_hit_sig.emit(self, body)
|
||||
_already_hit.append(body)
|
1
scenes/weapons/weapon_sword_projectile.gd.uid
Normal file
1
scenes/weapons/weapon_sword_projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c40iaqdubwl0p
|
24
scenes/weapons/weapon_sword_projectile.tscn
Normal file
24
scenes/weapons/weapon_sword_projectile.tscn
Normal file
@@ -0,0 +1,24 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://bv5f47x3ishmf"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c40iaqdubwl0p" path="res://scenes/weapons/weapon_sword_projectile.gd" id="1_asuu4"]
|
||||
[ext_resource type="Texture2D" uid="uid://dycw7c3484dir" path="res://assets/sprites/sword.png" id="2_pxap4"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ygc1t"]
|
||||
size = Vector2(16, 46)
|
||||
|
||||
[node name="WeaponSwordProjectile" type="Node2D"]
|
||||
script = ExtResource("1_asuu4")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("2_pxap4")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
|
||||
position = Vector2(0, -5)
|
||||
shape = SubResource("RectangleShape2D_ygc1t")
|
||||
|
||||
[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]
|
Reference in New Issue
Block a user