diff --git a/prefab/Bullet.tscn b/prefab/Bullet.tscn
index 604ebb0..19d9c8e 100644
--- a/prefab/Bullet.tscn
+++ b/prefab/Bullet.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=4 format=2]
-[ext_resource path="res://src/gun/bullet/Bullet.cs" type="Script" id=1]
+[ext_resource path="res://src/weapon/bullet/HighSpeedBullet.cs" type="Script" id=1]
[sub_resource type="Curve" id=1]
_data = [ Vector2( 0, 0.781588 ), 0.0, 0.0, 0, 0, Vector2( 1, 1 ), 0.0, 0.0, 0, 0 ]
@@ -8,17 +8,17 @@
[sub_resource type="Gradient" id=2]
colors = PoolColorArray( 1, 1, 1, 0.313726, 1, 1, 1, 0.784314 )
-[node name="Line2D" type="Line2D"]
-points = PoolVector2Array( 0, 0, 100, 0 )
+[node name="Bullet" type="Node2D"]
+script = ExtResource( 1 )
+
+[node name="Line" type="Line2D" parent="."]
+points = PoolVector2Array( 0, 0, 0, 10 )
width = 1.0
width_curve = SubResource( 1 )
default_color = Color( 1, 1, 1, 1 )
gradient = SubResource( 2 )
begin_cap_mode = 2
end_cap_mode = 2
-script = ExtResource( 1 )
[node name="RayCast2D" type="RayCast2D" parent="."]
visible = false
-rotation = 4.71239
-enabled = true
diff --git a/prefab/Cursor.tscn b/prefab/Cursor.tscn
index 593f9e1..3c2fb6e 100644
--- a/prefab/Cursor.tscn
+++ b/prefab/Cursor.tscn
@@ -13,24 +13,24 @@
[node name="LT" type="Sprite" parent="."]
texture = ExtResource( 1 )
-offset = Vector2( -1.5, -1.5 )
+offset = Vector2( -0.5, -0.5 )
region_enabled = true
region_rect = Rect2( 0, 0, 3, 3 )
[node name="LB" type="Sprite" parent="."]
texture = ExtResource( 1 )
-offset = Vector2( -1.5, 1.5 )
+offset = Vector2( -0.5, 0.5 )
region_enabled = true
region_rect = Rect2( 0, 5, 3, 3 )
[node name="RT" type="Sprite" parent="."]
texture = ExtResource( 1 )
-offset = Vector2( 1.5, -1.5 )
+offset = Vector2( 0.5, -0.5 )
region_enabled = true
region_rect = Rect2( 5, 0, 3, 3 )
[node name="RB" type="Sprite" parent="."]
texture = ExtResource( 1 )
-offset = Vector2( 1.5, 1.5 )
+offset = Vector2( 0.5, 0.5 )
region_enabled = true
region_rect = Rect2( 5, 5, 3, 3 )
diff --git a/prefab/Gun.tscn b/prefab/Gun.tscn
index 49e675a..ef22feb 100644
--- a/prefab/Gun.tscn
+++ b/prefab/Gun.tscn
@@ -1,14 +1,12 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://resource/sprite/gun/gun1.png" type="Texture" id=1]
-[ext_resource path="res://src/gun/Gun.cs" type="Script" id=2]
+[ext_resource path="res://src/weapon/gun/Gun.cs" type="Script" id=2]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 9.5, 3.5 )
-[node name="Gun" type="Area2D"]
-collision_layer = 4
-collision_mask = 0
+[node name="Gun" type="Node2D"]
script = ExtResource( 2 )
[node name="Sprite" type="Sprite" parent="."]
@@ -25,7 +23,11 @@
position = Vector2( 11, -1.5 )
scale = Vector2( 0.8, 0.8 )
-[node name="Collision" type="CollisionShape2D" parent="."]
+[node name="Area" type="Area2D" parent="."]
+collision_layer = 4
+collision_mask = 0
+
+[node name="Collision" type="CollisionShape2D" parent="Area"]
position = Vector2( 4.2, -0.199999 )
shape = SubResource( 1 )
disabled = true
diff --git a/prefab/Player.tscn b/prefab/Player.tscn
index 8699592..dc42a64 100644
--- a/prefab/Player.tscn
+++ b/prefab/Player.tscn
@@ -9,4 +9,4 @@
GunPrefab = ExtResource( 4 )
[node name="AnimatedSprite" parent="." index="0"]
-frame = 3
+frame = 1
diff --git a/prefab/Role.tscn b/prefab/Role.tscn
index a74fa2d..2c60000 100644
--- a/prefab/Role.tscn
+++ b/prefab/Role.tscn
@@ -20,22 +20,6 @@
atlas = ExtResource( 1 )
region = Rect2( 48, 24, 16, 24 )
-[sub_resource type="AtlasTexture" id=21]
-atlas = ExtResource( 1 )
-region = Rect2( 0, 48, 16, 24 )
-
-[sub_resource type="AtlasTexture" id=22]
-atlas = ExtResource( 1 )
-region = Rect2( 16, 48, 16, 24 )
-
-[sub_resource type="AtlasTexture" id=23]
-atlas = ExtResource( 1 )
-region = Rect2( 32, 48, 16, 24 )
-
-[sub_resource type="AtlasTexture" id=24]
-atlas = ExtResource( 1 )
-region = Rect2( 48, 48, 16, 24 )
-
[sub_resource type="AtlasTexture" id=25]
atlas = ExtResource( 1 )
region = Rect2( 48, 48, 16, 24 )
@@ -52,6 +36,22 @@
atlas = ExtResource( 1 )
region = Rect2( 0, 48, 16, 24 )
+[sub_resource type="AtlasTexture" id=21]
+atlas = ExtResource( 1 )
+region = Rect2( 0, 48, 16, 24 )
+
+[sub_resource type="AtlasTexture" id=22]
+atlas = ExtResource( 1 )
+region = Rect2( 16, 48, 16, 24 )
+
+[sub_resource type="AtlasTexture" id=23]
+atlas = ExtResource( 1 )
+region = Rect2( 32, 48, 16, 24 )
+
+[sub_resource type="AtlasTexture" id=24]
+atlas = ExtResource( 1 )
+region = Rect2( 48, 48, 16, 24 )
+
[sub_resource type="SpriteFrames" id=6]
animations = [ {
"frames": [ SubResource( 17 ), SubResource( 18 ), SubResource( 19 ), SubResource( 20 ) ],
@@ -59,22 +59,22 @@
"name": "idle",
"speed": 7.0
}, {
-"frames": [ SubResource( 21 ), SubResource( 22 ), SubResource( 23 ), SubResource( 24 ) ],
-"loop": true,
-"name": "run",
-"speed": 10.0
-}, {
"frames": [ SubResource( 25 ), SubResource( 26 ), SubResource( 27 ), SubResource( 28 ) ],
"loop": true,
"name": "reverseRun",
"speed": 10.0
+}, {
+"frames": [ SubResource( 21 ), SubResource( 22 ), SubResource( 23 ), SubResource( 24 ) ],
+"loop": true,
+"name": "run",
+"speed": 10.0
} ]
[sub_resource type="RectangleShape2D" id=29]
extents = Vector2( 5, 7.5 )
[sub_resource type="RectangleShape2D" id=16]
-extents = Vector2( 5, 1.5 )
+extents = Vector2( 5, 4.5 )
[node name="Role" type="KinematicBody2D"]
collision_layer = 0
@@ -92,11 +92,12 @@
[node name="HitArea" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="HitArea"]
+visible = false
position = Vector2( 0, -7.5 )
shape = SubResource( 29 )
[node name="Collision" type="CollisionShape2D" parent="."]
-position = Vector2( 0, -1.5 )
+position = Vector2( 0, -4.5 )
shape = SubResource( 16 )
[node name="MountPoint" type="Position2D" parent="."]
diff --git a/resource/tile/itch-io-DungeonTileset4.tres b/resource/tile/itch-io-DungeonTileset4.tres
index cebaeb7..b2eceaa 100644
--- a/resource/tile/itch-io-DungeonTileset4.tres
+++ b/resource/tile/itch-io-DungeonTileset4.tres
@@ -147,16 +147,16 @@
points = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
[sub_resource type="ConvexPolygonShape2D" id=51]
-points = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
+points = PoolVector2Array( 0, 0, 16, 0, 16, 12, 0, 12 )
[sub_resource type="ConvexPolygonShape2D" id=52]
-points = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
+points = PoolVector2Array( 0, 0, 16, 0, 16, 12, 0, 12 )
[sub_resource type="ConvexPolygonShape2D" id=53]
-points = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
+points = PoolVector2Array( 0, 0, 16, 0, 16, 12, 0, 12 )
[sub_resource type="ConvexPolygonShape2D" id=54]
-points = PoolVector2Array( 0, 0, 16, 0, 16, 16, 0, 16 )
+points = PoolVector2Array( 0, 0, 16, 0, 16, 12, 0, 12 )
[resource]
0/name = "16x16 dungeon ii wall reconfig v04 spritesheet.png 0"
diff --git a/scene/Room.tscn b/scene/Room.tscn
index e93a913..1ce667c 100644
--- a/scene/Room.tscn
+++ b/scene/Room.tscn
@@ -19,6 +19,15 @@
[node name="Camera2D" type="Camera2D" parent="."]
position = Vector2( 196, 128 )
current = true
+limit_left = -40
+limit_top = -25
+limit_right = 470
+limit_bottom = 300
+drag_margin_h_enabled = true
+drag_margin_v_enabled = true
+smoothing_enabled = true
+editor_draw_limits = true
+editor_draw_drag_margin = true
[node name="Player" parent="." instance=ExtResource( 1 )]
position = Vector2( 196, 128 )
diff --git a/src/gun/Gun.cs b/src/gun/Gun.cs
deleted file mode 100644
index 85adb8f..0000000
--- a/src/gun/Gun.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-using Godot;
-using System;
-
-public class Gun : Area2D
-{
- ///
- /// 开火回调事件
- ///
- public event Action FireEvent;
-
- ///
- /// 属性数据
- ///
- public GunAttribute Attribute
- {
- get
- {
- if (_attribute == null)
- {
- throw new Exception("请先调用Init来初始化枪的属性");
- }
- return _attribute;
- }
- private set => _attribute = value;
- }
- private GunAttribute _attribute;
-
- ///
- /// 枪的图片
- ///
- public Sprite Sprite { get; private set; }
-
- ///
- /// 枪攻击的目标阵营
- ///
- public CampEnum TargetCamp { get; set; }
- ///
- /// 开火点
- ///
- public Position2D FirePoint { get; private set; }
- ///
- /// 原点
- ///
- public Position2D OriginPoint { get; private set; }
-
- ///
- /// 枪的当前散射半径
- ///
- public float CurrScatteringRange { get; private set; } = 0;
-
- //是否按下
- private bool triggerFlag = false;
- private float fireInterval = 0;
- private float fireAngle = 0;
- private float attackTimer = 0;
- private bool attackFlag = false;
- private int downFrame = 0;
- //子弹
- private PackedScene bulletPacked;
-
- public override void _EnterTree()
- {
- Sprite = GetNode("Sprite");
- FirePoint = GetNode("FirePoint");
- OriginPoint = GetNode("OriginPoint");
- }
-
- public override void _Process(float delta)
- {
- downFrame = triggerFlag ? downFrame : 0;
- // 攻击的计时器
- if (attackTimer > 0)
- {
- attackTimer -= delta;
- }
- else if (!attackFlag && attackTimer < 0)
- {
- attackTimer = 0;
- }
-
- if (!attackFlag && attackTimer <= 0)
- {
- CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
- }
- triggerFlag = false;
- attackFlag = false;
-
- //枪身回归
- Position = Position.MoveToward(Vector2.Zero, 35 * delta);
- if (fireInterval == 0)
- {
- RotationDegrees = 0;
- }
- else
- {
- RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
- }
- }
-
- public void Init(GunAttribute attribute)
- {
- Attribute = attribute;
- //更新图片
- var texture = ResourceLoader.Load(attribute.Sprite);
- Sprite.Texture = texture;
- //子弹
- bulletPacked = ResourceLoader.Load(attribute.Bullet);
- //开火位置
- FirePoint.Position = new Vector2(attribute.BarrelLength, FirePoint.Position.y);
- }
-
- ///
- /// 扳机函数, 调用即视为扣动扳机
- ///
- public void Trigger()
- {
- //是否第一帧按下
- var justDown = downFrame++ == 0;
-
- if (Attribute.ContinuousShoot || justDown)
- {
- if (attackTimer <= 0)
- {
- fireInterval = 60 / Attribute.FiringSpeed;
- attackTimer += fireInterval;
- Fire();
- //当前的散射半径
- CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
- //枪的旋转角度
- RotationDegrees -= Attribute.UpliftAngle;
- fireAngle = RotationDegrees;
- //枪身位置
- Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
-
- if (FireEvent != null)
- {
- FireEvent(this);
- }
- }
- attackFlag = true;
- }
- triggerFlag = true;
- }
-
- protected virtual void Fire()
- {
- //开火发射的子弹数量
- var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
- //枪口角度
- var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
-
- //创建子弹
- for (int i = 0; i < bulletCount; i++)
- {
- //先算枪口方向
- Rotation = (float)GD.RandRange(-angle, angle);
-
- //创建子弹
- var bullet = bulletPacked.Instance();
- bullet.GlobalPosition = FirePoint.GlobalPosition;
- bullet.Rotation = (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle();
- GetTree().CurrentScene.AddChild(bullet);
-
- //飞行距离
- var distance = MathUtils.RandRange(Attribute.MinDistance, Attribute.MaxDistance);
- //初始化子弹数据
- bullet.Init(TargetCamp, distance, Colors.White);
- }
- }
-}
\ No newline at end of file
diff --git a/src/gun/GunAttribute.cs b/src/gun/GunAttribute.cs
deleted file mode 100644
index 2437344..0000000
--- a/src/gun/GunAttribute.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using Godot;
-
-///
-/// 枪上的属性
-///
-public class GunAttribute
-{
- ///
- /// 子弹对象
- ///
- public string Bullet = "res://prefab/Bullet.tscn";
- ///
- /// 枪的图片
- ///
- public string Sprite = "res://resource/sprite/gun/gun1.png";
- ///
- /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机
- ///
- public bool ContinuousShoot = true;
- ///
- /// 连续发射最小次数, 仅当ContinuousShoot为false时生效
- ///
- public int MinContinuousCount = 3;
- ///
- /// 连续发射最大次数, 仅当ContinuousShoot为false时生效
- ///
- public int MaxContinuousCount = 3;
- ///
- /// 放开扳机后需要多少时间才能再次按下扳机
- ///
- public float TriggerInterval = 0;
- ///
- /// 射速, 每秒分钟能发射多少发子弹
- ///
- public float FiringSpeed = 300;
- ///
- /// 单次开火发射子弹最小数量
- ///
- public int MinFireBulletCount = 1;
- ///
- /// 单次开火发射子弹最大数量
- ///
- public int MaxFireBulletCount = 1;
- ///
- /// 开火前延时
- ///
- public float DelayedTime = 0f;
- ///
- /// 初始散射半径
- ///
- public float StartScatteringRange = 0;
- ///
- /// 最终散射半径
- ///
- public float FinalScatteringRange = 20;
- ///
- /// 每次发射后散射增加值
- ///
- public float ScatteringRangeAddValue = 2;
- ///
- /// 松开扳机后散射销退速率
- ///
- public float ScatteringRangeBackSpeed = 10;
- ///
- /// 子弹飞行最大距离
- ///
- public float MaxDistance = 600;
- ///
- /// 子弹飞行最小距离
- ///
- public float MinDistance = 800;
- ///
- /// 枪管长度
- ///
- public float BarrelLength = 11;
- ///
- /// 重量
- ///
- public float Weight = 11;
- ///
- /// 最大后坐力 (仅用于开火后枪身抖动)
- ///
- public float MaxBacklash = 4;
- ///
- /// 最小后坐力 (仅用于开火后枪身抖动)
- ///
- public float MinBacklash = 2;
- ///
- /// 开火后枪口上抬角度
- ///
- public float UpliftAngle = 30;
-
- public GunAttribute()
- {
-
- }
-}
\ No newline at end of file
diff --git a/src/gun/bullet/Bullet.cs b/src/gun/bullet/Bullet.cs
deleted file mode 100644
index 582e0db..0000000
--- a/src/gun/bullet/Bullet.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using Godot;
-
-///
-/// 子弹
-///
-public class Bullet : Line2D
-{
- ///
- /// 存在弹道特效存在时间
- ///
- [Export] public float LifeTime = 1f;
-
- ///
- /// 攻击目标
- ///
- public CampEnum Target;
-
- ///
- /// 最大飞行距离
- ///
- public float Distance;
-
- private float a = 1;
-
- public void Init(CampEnum target, float distance, Color color)
- {
- Target = target;
- Distance = distance;
- Modulate = color;
- SetPointPosition(1, new Vector2(distance, 0));
- }
-
- public override void _Process(float delta)
- {
- a -= 12 * delta;
- if (a <= 0) {
- QueueFree();
- return;
- }
- Color c = Modulate;
- c.a = a;
- Modulate = c;
- }
-
-}
\ No newline at end of file
diff --git a/src/role/Player.cs b/src/role/Player.cs
index b95a3af..11cfb09 100644
--- a/src/role/Player.cs
+++ b/src/role/Player.cs
@@ -30,23 +30,29 @@
var attr = new GunAttribute();
attr.FiringSpeed = 420;
- attr.StartScatteringRange = 3;
- attr.FinalScatteringRange = 30;
- attr.ScatteringRangeAddValue = 15;
+ attr.StartScatteringRange = 0;
+ attr.FinalScatteringRange = 10;
+ attr.ScatteringRangeAddValue = 5;
attr.ScatteringRangeBackSpeed = 20;
//连发
attr.ContinuousShoot = true;
+ //扳机检测间隔
+ attr.TriggerInterval = 1f;
+ //连发数量
+ attr.MinContinuousCount = 3;
+ //开火前延时
+ attr.DelayedTime = 0f;
//攻击距离
attr.MinDistance = 500;
attr.MaxDistance = 600;
//发射子弹数量
attr.MinFireBulletCount = 1;
attr.MaxFireBulletCount = 1;
- //
+ //抬起角度
attr.UpliftAngle = 10;
-
- attr.BarrelLength = 10;
- attr.Sprite = "res://resource/sprite/gun/gun3.png";
+ //枪身长度
+ attr.BarrelLength = 15;
+ attr.Sprite = "res://resource/sprite/gun/gun4.png";
gun.Init(attr);
gun.FireEvent += FireEvent_Func;
diff --git a/src/weapon/Weapon.cs b/src/weapon/Weapon.cs
new file mode 100644
index 0000000..e7816d4
--- /dev/null
+++ b/src/weapon/Weapon.cs
@@ -0,0 +1,8 @@
+
+///
+/// 武器基类
+///
+public class Weapon
+{
+
+}
\ No newline at end of file
diff --git a/src/weapon/bullet/Bullet.cs b/src/weapon/bullet/Bullet.cs
new file mode 100644
index 0000000..a56e98d
--- /dev/null
+++ b/src/weapon/bullet/Bullet.cs
@@ -0,0 +1,27 @@
+using Godot;
+
+///
+/// 子弹
+///
+public abstract class Bullet : Node2D
+{
+ ///
+ /// 攻击目标阵营
+ ///
+ public CampEnum TargetCamp { get; private set; }
+ ///
+ /// 发射该子弹的武器
+ ///
+ public Gun Gun { get; private set; }
+ ///
+ /// 发射该子弹的物体对象
+ ///
+ public Node2D Master { get; private set; }
+
+ public void Init(CampEnum target, Gun gun, Node2D master)
+ {
+ TargetCamp = target;
+ Gun = gun;
+ Master = master;
+ }
+}
\ No newline at end of file
diff --git a/src/weapon/bullet/HighSpeedBullet.cs b/src/weapon/bullet/HighSpeedBullet.cs
new file mode 100644
index 0000000..dcd7173
--- /dev/null
+++ b/src/weapon/bullet/HighSpeedBullet.cs
@@ -0,0 +1,50 @@
+using Godot;
+
+///
+/// 高速子弹
+///
+public class HighSpeedBullet : Bullet
+{
+ //射线检测节点
+ private RayCast2D RayCast2D;
+ //最大飞行距离
+ private float Distance;
+ private Line2D Line;
+ private float ca = 1;
+
+ public void InitData(float distance, Color color)
+ {
+ RayCast2D = GetNode("RayCast2D");
+ Line = GetNode("Line");
+ Distance = distance;
+ Modulate = color;
+
+ Vector2 targetPos = new Vector2(distance, 0);
+
+ //
+ RayCast2D.CastTo = targetPos;
+ RayCast2D.ForceRaycastUpdate();
+ if (RayCast2D.IsColliding()) {
+ //划线的点坐标
+ Line.SetPointPosition(1, new Vector2(Line.GlobalPosition.DistanceTo(RayCast2D.GetCollisionPoint()), 0));
+ }
+ else
+ {
+ //划线的点坐标
+ Line.SetPointPosition(1, targetPos);
+ }
+ RayCast2D.Enabled = false;
+ }
+
+ public override void _Process(float delta)
+ {
+ ca -= 12 * delta;
+ if (ca <= 0) {
+ QueueFree();
+ return;
+ }
+ Color c = Modulate;
+ c.a = ca;
+ Modulate = c;
+ }
+}
\ No newline at end of file
diff --git a/src/weapon/gun/Gun.cs b/src/weapon/gun/Gun.cs
new file mode 100644
index 0000000..8f224e8
--- /dev/null
+++ b/src/weapon/gun/Gun.cs
@@ -0,0 +1,265 @@
+using Godot;
+using System;
+
+///
+/// 枪的基类
+///
+public class Gun : Node2D
+{
+ ///
+ /// 开火回调事件
+ ///
+ public event Action FireEvent;
+
+ ///
+ /// 属性数据
+ ///
+ public GunAttribute Attribute
+ {
+ get
+ {
+ if (_attribute == null)
+ {
+ throw new Exception("请先调用Init来初始化枪的属性");
+ }
+ return _attribute;
+ }
+ private set => _attribute = value;
+ }
+ private GunAttribute _attribute;
+
+ ///
+ /// 枪的图片
+ ///
+ public Sprite Sprite { get; private set; }
+
+ ///
+ /// 枪攻击的目标阵营
+ ///
+ public CampEnum TargetCamp { get; set; }
+ ///
+ /// 开火点
+ ///
+ public Position2D FirePoint { get; private set; }
+ ///
+ /// 原点
+ ///
+ public Position2D OriginPoint { get; private set; }
+
+ ///
+ /// 枪的当前散射半径
+ ///
+ public float CurrScatteringRange { get; private set; } = 0;
+
+ //是否按下
+ private bool triggerFlag = false;
+ //扳机计时器
+ private float triggerTimer = 0;
+ //开火前延时时间
+ private float delayedTime = 0;
+ //开火间隙时间
+ private float fireInterval = 0;
+ //开火枪口角度
+ private float fireAngle = 0;
+ //攻击冷却计时
+ private float attackTimer = 0;
+ //攻击状态
+ private bool attackFlag = false;
+ //按下的时间
+ private float downTimer = 0;
+ //松开的时间
+ private float upTimer = 0;
+ //连发次数
+ private float continuousCount = 0;
+ //子弹
+ private PackedScene bulletPacked;
+
+ public override void _EnterTree()
+ {
+ Sprite = GetNode("Sprite");
+ FirePoint = GetNode("FirePoint");
+ OriginPoint = GetNode("OriginPoint");
+ }
+
+ public override void _Process(float delta)
+ {
+ if (triggerFlag)
+ {
+ if (upTimer > 0) //第一帧按下扳机
+ {
+ upTimer = 0;
+ DownTrigger();
+ }
+ downTimer += delta;
+ }
+ else
+ {
+ if (downTimer > 0) //第一帧松开扳机
+ {
+ downTimer = 0;
+ UpTriggern();
+ }
+ upTimer += delta;
+ }
+
+ // 攻击的计时器
+ if (attackTimer > 0)
+ {
+ attackTimer -= delta;
+ if (attackTimer < 0)
+ {
+ delayedTime += attackTimer;
+ attackTimer = 0;
+ }
+ }
+ else if (delayedTime > 0)
+ {
+ delayedTime -= delta;
+ if (attackTimer < 0)
+ {
+ delayedTime = 0;
+ }
+ }
+
+ //连发判断
+ if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
+ {
+ TriggernFire();
+ }
+
+ if (!attackFlag && attackTimer <= 0)
+ {
+ CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
+ }
+ triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
+ triggerFlag = false;
+ attackFlag = false;
+
+ //枪身回归
+ Position = Position.MoveToward(Vector2.Zero, 35 * delta);
+ if (fireInterval == 0)
+ {
+ RotationDegrees = 0;
+ }
+ else
+ {
+ RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
+ }
+ }
+
+ public void Init(GunAttribute attribute)
+ {
+ Attribute = attribute;
+ //更新图片
+ var texture = ResourceLoader.Load(attribute.Sprite);
+ Sprite.Texture = texture;
+ //子弹
+ bulletPacked = ResourceLoader.Load(attribute.Bullet);
+ //开火位置
+ FirePoint.Position = new Vector2(attribute.BarrelLength, FirePoint.Position.y);
+ }
+
+ ///
+ /// 扳机函数, 调用即视为扣动扳机
+ ///
+ public void Trigger()
+ {
+ //是否第一帧按下
+ var justDown = downTimer == 0;
+
+ if ((Attribute.ContinuousShoot || (justDown && triggerTimer <= 0)) && continuousCount <= 0)
+ {
+ if (justDown)
+ {
+ //开火前延时
+ delayedTime = Attribute.DelayedTime;
+ //扳机按下间隔
+ triggerTimer += Attribute.TriggerInterval;
+ //连发数量
+ if (!Attribute.ContinuousShoot)
+ {
+ continuousCount = Attribute.MinContinuousCount;
+ }
+ }
+ if (delayedTime <= 0 && attackTimer <= 0)
+ {
+ TriggernFire();
+ }
+ attackFlag = true;
+ }
+ triggerFlag = true;
+ }
+
+ ///
+ /// 刚按下扳机
+ ///
+ private void DownTrigger()
+ {
+
+ }
+
+ ///
+ /// 刚松开扳机
+ ///
+ private void UpTriggern()
+ {
+
+ }
+
+ private void TriggernFire()
+ {
+ continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
+ fireInterval = 60 / Attribute.FiringSpeed;
+ attackTimer += fireInterval;
+ Fire();
+ //当前的散射半径
+ CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
+ //枪的旋转角度
+ RotationDegrees -= Attribute.UpliftAngle;
+ fireAngle = RotationDegrees;
+ //枪身位置
+ Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
+
+ if (FireEvent != null)
+ {
+ FireEvent(this);
+ }
+ }
+
+ ///
+ /// 开火
+ ///
+ protected virtual void Fire()
+ {
+ //开火发射的子弹数量
+ var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
+ //枪口角度
+ var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
+
+ //创建子弹
+ for (int i = 0; i < bulletCount; i++)
+ {
+ //先算枪口方向
+ Rotation = (float)GD.RandRange(-angle, angle);
+
+ //创建子弹
+ var bullet = CreateBullet(bulletPacked);
+ //位置
+ bullet.GlobalPosition = FirePoint.GlobalPosition;
+ //角度
+ bullet.Rotation = (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle();
+ GetTree().CurrentScene.AddChild(bullet);
+ //飞行距离
+ var distance = MathUtils.RandRange(Attribute.MinDistance, Attribute.MaxDistance);
+ //初始化子弹数据
+ bullet.InitData(distance, Colors.White);
+ }
+ }
+
+ public T CreateBullet(PackedScene bulletPack) where T : Bullet
+ {
+ T bullet = bulletPack.Instance();
+ bullet.Init(TargetCamp, this, null);
+ return bullet;
+ }
+}
\ No newline at end of file
diff --git a/src/weapon/gun/GunAttribute.cs b/src/weapon/gun/GunAttribute.cs
new file mode 100644
index 0000000..df608a5
--- /dev/null
+++ b/src/weapon/gun/GunAttribute.cs
@@ -0,0 +1,97 @@
+using Godot;
+
+///
+/// 枪上的属性
+///
+public class GunAttribute
+{
+ ///
+ /// 子弹对象
+ ///
+ public string Bullet = "res://prefab/Bullet.tscn";
+ ///
+ /// 枪的图片
+ ///
+ public string Sprite = "res://resource/sprite/gun/gun1.png";
+ ///
+ /// 是否连续发射, 如果为false, 则每次发射都需要扣动扳机
+ ///
+ public bool ContinuousShoot = true;
+ ///
+ /// 连续发射最小次数, 仅当ContinuousShoot为false时生效
+ ///
+ public int MinContinuousCount = 3;
+ ///
+ /// 连续发射最大次数, 仅当ContinuousShoot为false时生效
+ ///
+ public int MaxContinuousCount = 3;
+ ///
+ /// 按下一次扳机后需要多长时间才能再次按下
+ ///
+ public float TriggerInterval = 0;
+ ///
+ /// 射速, 每秒分钟能发射多少发子弹
+ ///
+ public float FiringSpeed = 300;
+ ///
+ /// 单次开火发射子弹最小数量
+ ///
+ public int MinFireBulletCount = 1;
+ ///
+ /// 单次开火发射子弹最大数量
+ ///
+ public int MaxFireBulletCount = 1;
+ ///
+ /// 开火前延时
+ ///
+ public float DelayedTime = 0f;
+ ///
+ /// 初始散射半径
+ ///
+ public float StartScatteringRange = 0;
+ ///
+ /// 最终散射半径
+ ///
+ public float FinalScatteringRange = 20;
+ ///
+ /// 每次发射后散射增加值
+ ///
+ public float ScatteringRangeAddValue = 2;
+ ///
+ /// 松开扳机后散射销退速率
+ ///
+ public float ScatteringRangeBackSpeed = 10;
+ ///
+ /// 子弹飞行最大距离
+ ///
+ public float MaxDistance = 600;
+ ///
+ /// 子弹飞行最小距离
+ ///
+ public float MinDistance = 800;
+ ///
+ /// 枪管长度
+ ///
+ public float BarrelLength = 11;
+ ///
+ /// 重量
+ ///
+ public float Weight = 11;
+ ///
+ /// 最大后坐力 (仅用于开火后枪身抖动)
+ ///
+ public float MaxBacklash = 4;
+ ///
+ /// 最小后坐力 (仅用于开火后枪身抖动)
+ ///
+ public float MinBacklash = 2;
+ ///
+ /// 开火后枪口上抬角度
+ ///
+ public float UpliftAngle = 30;
+
+ public GunAttribute()
+ {
+
+ }
+}
\ No newline at end of file