-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEmitter.cs
133 lines (109 loc) · 4.68 KB
/
Emitter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using Godot;
using System;
using Godot.Collections;
using PerformantPhysicsEntities;
public partial class Emitter : Node2D
{
[Export] public Godot.Collections.Array<Texture2D> Textures { get; set; }
[Export] public float ProjectileMaxLifetime { get; set; } = 5.0f;
public Rect2 BoundingBox = new Rect2();
private Array<Projectile> _projectiles = new Array<Projectile>();
private Area2D _sharedArea;
private Color _debugColor = Color.Color8(0,0,0);
public override void _Ready()
{
_sharedArea = GetNode<Area2D>("SharedArea");
Array<Color> debugColors = new Array<Color>() { Colors.Azure, Colors.Blue, Colors.Lime, Colors.ForestGreen, Colors.Violet};
_debugColor = debugColors[(int)GD.Randi() % debugColors.Count];
}
public override void _PhysicsProcess(double delta)
{
Transform2D transform2D = new Transform2D();
Array<Projectile> projectilesMarkedForDeletion = new Array<Projectile>();
int i = 0;
foreach (var p in _projectiles)
{
// filter out projectiles that should be destroyed
if (p.Lifetime >= ProjectileMaxLifetime || !BoundingBox.HasPoint(p.Position))
{
projectilesMarkedForDeletion.Add(p);
continue;
}
// calculate new position
Vector2 offset = p.Direction.Normalized() * p.Speed * (float)delta;
p.Position += offset;
transform2D.Origin = p.Position;
// While the creation/destruction process of shapes created by the physics server is done directly via the
// generated resource id, actually "moving" it inside the area requires us to use the offset number under
// which it was registered (think of it as the child offset, if we were using CollisionShape2D nodes).
// That's why we pass "i" as the second parameter to the method, and why It is very important to ensure a
// consistent order between the registration offset and the bullet's offset inside the array, otherwise
// detection shapes can overlap.
PhysicsServer2D.AreaSetShapeTransform(_sharedArea.GetRid(), i, transform2D);
p.Lifetime += (float)delta;
i++;
}
// delete all marked projectiles before redraw
foreach (var p in projectilesMarkedForDeletion)
{
PhysicsServer2D.FreeRid(p.ShapeId);
_projectiles.Remove(p); // method acts in-place and doesn't return a value.
}
QueueRedraw(); // former Update()
}
public override void _Draw()
{
foreach (var p in _projectiles)
{
Vector2 offset = Textures[0].GetSize() / 2.0f;
DrawTexture(Textures[0], p.Position - offset);
}
DrawRect(BoundingBox, _debugColor, false, 1.0f);
}
public void SpawnProjectile()
{
var p1 = RegisterProjectile(this.GlobalPosition, Vector2.Down, 1000.0f);
ConfigureProjectile(p1);
_projectiles.Add(p1);
var p2 = RegisterProjectile(this.GlobalPosition, Vector2.Up, 1000.0f);
ConfigureProjectile(p2);
_projectiles.Add(p2);
var p3 = RegisterProjectile(this.GlobalPosition, Vector2.Right, 1000.0f);
ConfigureProjectile(p3);
_projectiles.Add(p3);
var p4 = RegisterProjectile(this.GlobalPosition, Vector2.Left, 1000.0f);
ConfigureProjectile(p4);
_projectiles.Add(p4);
}
private void ConfigureProjectile(Projectile projectile)
{
Transform2D transform = new Transform2D(0, this.Position);
transform.Origin = projectile.Position;
// set up collision-shape
Rid shapeId = PhysicsServer2D.CircleShapeCreate();
PhysicsServer2D.ShapeSetData(shapeId, 8);
PhysicsServer2D.AreaAddShape(_sharedArea.GetRid(), shapeId, transform);
//
projectile.ShapeId = shapeId;
}
Projectile RegisterProjectile(Vector2 initialPosition, Vector2 initialDirection, float initialSpeed)
{
return new Projectile(initialPosition, initialDirection, initialSpeed);
}
}
public partial class Projectile : GodotObject, IProjectile
{
public Projectile(Vector2 position, Vector2 direction, float speed)
{
Position = position;
Direction = direction;
Speed = speed;
}
public Vector2 Position { get; set; }
public Vector2 Direction { get; set; }
public float Speed { get; set; }
public Rid ShapeId { get; set; }
public float Lifetime { get; set; }
public event OnLifetimeBeginEventHandler LifetimeBegin;
public event OnDestroyEventHandler Destroy;
}