Add the triple shot spell.

加入三重射击法术。
This commit is contained in:
Cold-Mint 2024-10-05 16:19:31 +08:00
parent 407798b13b
commit 3f96519ac0
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
11 changed files with 227 additions and 16 deletions

View File

@ -7,4 +7,8 @@
- id: necromancy
scene_path: res://prefab/magics/curseOfTheUndead.tscn
icon_path: res://sprites/projectile/curseOfTheUndead.png
max_stack_value: 1
- id: x3
scene_path: res://prefab/magics/x3.tscn
icon_path: res://sprites/projectile/x3.png
max_stack_value: 1

View File

@ -4,4 +4,6 @@ item_staff_necromancy_desc,发射诅咒,可将敌人转化为邪恶的怪物
item_portable_backpacks,便携式背包,PortableBackpacks,ポータブルバックパック
item_portable_backpacks_desc,为玩家提供9个物品槽。,Provides 9 item slots for the player.,プレイヤーに9つのアイテムスロットを提供します。
item_necromancy,死灵法术,necromancy,ネクロマンシー
item_necromancy_desc,法术的实体化弹丸。,The materialized projectile of a spell.,術の実体化した弾丸です。
item_necromancy_desc,法术的实体化弹丸。,The materialized projectile of a spell.,術の実体化した弾丸です。
item_x3,三重射击法术,Triple shot spell,三重射撃術です
item_x3_desc,使发射器一次射出三颗弹丸。,Make the launcher shoot three pellets at a time.,発射機から一度に三つの弾丸を発射させます。
1 id zh en ja
4 item_portable_backpacks 便携式背包 PortableBackpacks ポータブルバックパック
5 item_portable_backpacks_desc 为玩家提供9个物品槽。 Provides 9 item slots for the player. プレイヤーに9つのアイテムスロットを提供します。
6 item_necromancy 死灵法术 necromancy ネクロマンシー
7 item_necromancy_desc 法术的实体化弹丸。 The materialized projectile of a spell. 術の実体化した弾丸です。
8 item_x3 三重射击法术 Triple shot spell 三重射撃術です
9 item_x3_desc 使发射器一次射出三颗弹丸。 Make the launcher shoot three pellets at a time. 発射機から一度に三つの弾丸を発射させます。

46
prefab/magics/x3.tscn Normal file
View File

@ -0,0 +1,46 @@
[gd_scene load_steps=6 format=3 uid="uid://cg75t3fw5c6er"]
[ext_resource type="Script" path="res://scripts/spell/MultipleFireSpell.cs" id="1_cnhod"]
[ext_resource type="Texture2D" uid="uid://mb5yijtw7sw5" path="res://sprites/projectile/x3.png" id="3_b3s8h"]
[ext_resource type="AudioStream" uid="uid://cak6chjjsu7wo" path="res://sounds/fire.wav" id="4_ffr2k"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_3eq4k"]
size = Vector2(30, 30)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_i3lbq"]
size = Vector2(30, 31)
[node name="x3" type="RigidBody2D"]
collision_layer = 8
collision_mask = 34
angular_damp = -1.0
script = ExtResource("1_cnhod")
[node name="DamageArea2D" type="Area2D" parent="."]
collision_layer = 8
collision_mask = 102
[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageArea2D"]
shape = SubResource("RectangleShape2D_3eq4k")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0, -0.5)
shape = SubResource("RectangleShape2D_i3lbq")
[node name="Marker2D" type="Marker2D" parent="."]
position = Vector2(65, 0)
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="Marker2D"]
stream = ExtResource("4_ffr2k")
bus = &"SoundEffect"
[node name="TipLabel" type="Label" parent="."]
offset_left = -19.0
offset_top = 23.0
offset_right = 21.0
offset_bottom = 48.0
[node name="CurseOfTheUndead" type="Sprite2D" parent="."]
[node name="X3" type="Sprite2D" parent="."]
texture = ExtResource("3_b3s8h")

View File

@ -45,6 +45,16 @@ position = Vector2(142, 84)
script = ExtResource("3_v1tlc")
ItemId = "staff_necromancy"
[node name="ItemMarker2D3" type="Marker2D" parent="."]
position = Vector2(214, 83)
script = ExtResource("3_v1tlc")
ItemId = "x3"
[node name="ItemMarker2D4" type="Marker2D" parent="."]
position = Vector2(366, 90)
script = ExtResource("3_v1tlc")
ItemId = "necromancy"
[node name="ItemMarker2D2" type="Marker2D" parent="."]
position = Vector2(321, 118)
script = ExtResource("3_v1tlc")

View File

@ -17,6 +17,7 @@ collision_mask = 34
angular_damp = -1.0
script = ExtResource("1_w8hhv")
_numberSlots = 5
_fireSequentially = true
FiringIntervalAsMillisecond = 300
_recoilStrength = 5
UniqueIcon = ExtResource("3_31iau")

View File

@ -33,12 +33,23 @@ public interface ISpell
/// </summary>
/// <param name="projectileWeapon"></param>
void RestoreWeapon(ProjectileWeapon projectileWeapon);
/// <summary>
/// <para>Modify the projectile</para>
/// <para>修改抛射体</para>
/// </summary>
/// <param name="projectile"></param>
void ModifyProjectile(Projectile projectile);
/// <param name="index">
///<para>What is the current projectile? For example, a weapon can fire three projectiles at once, with indexes 0,1,2</para>
///<para>当前抛射体是第几个例如武器可一下发射3个抛射体索引为0,1,2</para>
/// </param>
/// <param name="projectile">
///<para>Projectile object</para>
///<para>抛射体对象</para>
/// </param>
/// <param name="velocity">
///<para>The velocity of the projectile</para>
///<para>抛射体的飞行速度</para>
/// </param>
void ModifyProjectile(int index,Projectile projectile, ref Vector2 velocity);
}

View File

@ -0,0 +1,82 @@
using ColdMint.scripts.projectile;
using ColdMint.scripts.utils;
using ColdMint.scripts.weapon;
using Godot;
namespace ColdMint.scripts.spell;
/// <summary>
/// <para>MultipleFireSpell</para>
/// <para>多重射击法术</para>
/// </summary>
/// <remarks>
///<para>Use this spell to create shotgun effects</para>
///<para>通过此法术打造霰弹枪的效果</para>
/// </remarks>
public partial class MultipleFireSpell : SpellPickAble
{
/// <summary>
/// <para>How many projectiles are generated per fire</para>
/// <para>每次开火生成多少个抛射体</para>
/// </summary>
[Export]
public int NumberOfProjectiles { get; set; } = 3;
/// <summary>
/// <para>RandomAngle</para>
/// <para>随机角度</para>
/// </summary>
[Export]
public bool RandomAngle { get; set; }
/// <summary>
/// <para>Unit radian</para>
/// <para>单位弧度</para>
/// </summary>
/// <remarks>
///<para>Unit radian of correction for the projectile Angle.Suppose there are three bullets fired at once, and this is the arc between the two bullets.</para>
///<para>对抛射体角度修正的单位弧度。假定有三颗子弹一次发射,这是两颗子弹之间的弧度。</para>
/// </remarks>
[Export]
public float UnitRadian { get; set; } = 0.069813f;
/// <summary>
/// <para>initial Radian</para>
/// <para>起始弧度</para>
/// </summary>
///<remarks>
///<para>The Angle of the first bullet, and subsequent bullets will be offset in unit radians.</para>
///<para>第一颗子弹的角度,随后的子弹会以单位弧度偏移。</para>
/// </remarks>
private float _initialRadian;
private float _maxRadian;
private int _oldNumberOfProjectiles;
public override void ModifyWeapon(ProjectileWeapon projectileWeapon)
{
base.ModifyWeapon(projectileWeapon);
_oldNumberOfProjectiles = projectileWeapon.NumberOfProjectiles;
projectileWeapon.NumberOfProjectiles = NumberOfProjectiles;
_initialRadian = -(NumberOfProjectiles / 2f * UnitRadian);
_maxRadian = NumberOfProjectiles * UnitRadian;
}
public override void RestoreWeapon(ProjectileWeapon projectileWeapon)
{
base.RestoreWeapon(projectileWeapon);
projectileWeapon.NumberOfProjectiles = _oldNumberOfProjectiles;
}
public override void ModifyProjectile(int index, Projectile projectile, ref Vector2 velocity)
{
base.ModifyProjectile(index, projectile, ref velocity);
if (RandomAngle)
{
velocity = velocity.Rotated(_initialRadian + _maxRadian * RandomUtils.Instance.NextSingle());
}
else
{
velocity = velocity.Rotated(_initialRadian + UnitRadian * index);
}
}
}

View File

@ -38,17 +38,17 @@ public partial class SpellPickAble : PickAbleTemplate, ISpell
return _projectileScene;
}
public void ModifyWeapon(ProjectileWeapon projectileWeapon)
public virtual void ModifyWeapon(ProjectileWeapon projectileWeapon)
{
}
public void RestoreWeapon(ProjectileWeapon projectileWeapon)
public virtual void RestoreWeapon(ProjectileWeapon projectileWeapon)
{
}
public void ModifyProjectile(Projectile projectile)
public virtual void ModifyProjectile(int index, Projectile projectile, ref Vector2 velocity)
{
}

View File

@ -216,36 +216,57 @@ public partial class ProjectileWeapon : WeaponTemplate
LogCat.LogError("projectile_scene_is_null");
return false;
}
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.ModifyWeapon(this);
}
ModifyWeapon(spellScope);
for (var i = 0; i < NumberOfProjectiles; i++)
{
var projectile = NodeUtils.InstantiatePackedScene<Projectile>(packedScene);
if (projectile == null)
{
LogCat.LogError("projectile_is_null");
RestoreWeapon(spellScope);
return false;
}
var velocity = _marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed;
for (var s = spellScope[0]; s <= spellScope[1]; s++)
{
var spell = _spells[s];
spell.ModifyProjectile(projectile);
spell.ModifyProjectile(i, projectile, ref velocity);
}
NodeUtils.CallDeferredAddChild(GameSceneDepend.ProjectileContainer, projectile);
projectile.Owner = owner;
projectile.TargetNode = GameSceneDepend.TemporaryTargetNode;
projectile.Velocity =
_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed;
projectile.Velocity = velocity;
projectile.Position = _marker2D.GlobalPosition;
}
RestoreWeapon(spellScope);
return true;
}
/// <summary>
/// <para>Modify weapon attributes</para>
/// <para>修改武器属性</para>
/// </summary>
/// <param name="spellScope"></param>
private void ModifyWeapon(int[] spellScope)
{
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.ModifyWeapon(this);
}
}
/// <summary>
/// <para>Restores modifications to weapons</para>
/// <para>恢复对武器的修改</para>
/// </summary>
/// <param name="spellScope"></param>
private void RestoreWeapon(int[] spellScope)
{
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.RestoreWeapon(this);
}
return true;
}
}

BIN
sprites/projectile/x3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mb5yijtw7sw5"
path="res://.godot/imported/x3.png-096b2fc27f9da2412a5f72aad28677de.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://sprites/projectile/x3.png"
dest_files=["res://.godot/imported/x3.png-096b2fc27f9da2412a5f72aad28677de.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1