game: add weapon base and sword

This commit is contained in:
2025-08-21 00:32:18 +02:00
parent 156da4898e
commit 8bd7bfa406
21 changed files with 200 additions and 163 deletions

View 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

View File

@@ -0,0 +1 @@
uid://d6nwfhyethdw

View 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"]

View 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)

View File

@@ -0,0 +1 @@
uid://b072d866r4usq

View 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")

View 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)

View File

@@ -0,0 +1 @@
uid://c40iaqdubwl0p

View 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"]