Skip to content

Commit 6170767

Browse files
committed
[upstream] Sensor clean up (box2d #953)
- Removed b2BodyDef::enableSensorHits - Added access to joint event thresholds - Removed b2SensorData - motion locks no longer affect mass - all visitors now do continuous checks against static sensors - bullets visitors do continuous checks against all non-bullet sensors - gave up on supporting fast moving sensors or collecting sensor collision data - instead people should use ray and shape casts to get detailed swept collision data or use contact events - added sample that shows how to make an exploding projectile
1 parent 436cce7 commit 6170767

21 files changed

+361
-168
lines changed

src/Box2D.NET.Samples/Samples/Events/FootSensor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class FootSensor : Sample
2929

3030
private B2BodyId m_playerId;
3131
private B2ShapeId m_sensorId;
32-
private List<B2SensorData> m_sensorData = new List<B2SensorData>();
32+
private List<B2ShapeId> m_visitorIds = new List<B2ShapeId>();
3333
private int m_overlapCount;
3434

3535
private static Sample Create(SampleContext context)
@@ -138,13 +138,13 @@ public override void Draw(Settings settings)
138138
base.Draw(settings);
139139

140140
int capacity = b2Shape_GetSensorCapacity(m_sensorId);
141-
m_sensorData.Clear();
142-
m_sensorData.Resize(capacity);
141+
m_visitorIds.Clear();
142+
m_visitorIds.Resize(capacity);
143143

144-
int count = b2Shape_GetSensorData(m_sensorId, CollectionsMarshal.AsSpan(m_sensorData), capacity);
144+
int count = b2Shape_GetSensorData(m_sensorId, CollectionsMarshal.AsSpan(m_visitorIds), capacity);
145145
for (int i = 0; i < count; ++i)
146146
{
147-
B2ShapeId shapeId = m_sensorData[i].visitorId;
147+
B2ShapeId shapeId = m_visitorIds[i];
148148
B2AABB aabb = b2Shape_GetAABB(shapeId);
149149
B2Vec2 point = b2AABB_Center(aabb);
150150
m_draw.DrawPoint(point, 10.0f, B2HexColor.b2_colorWhite);
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// SPDX-FileCopyrightText: 2025 Erin Catto
2+
// SPDX-FileCopyrightText: 2025 Ikpil Choi([email protected])
3+
// SPDX-License-Identifier: MIT
4+
5+
using Silk.NET.GLFW;
6+
using static Box2D.NET.B2Ids;
7+
using static Box2D.NET.B2Geometries;
8+
using static Box2D.NET.B2Types;
9+
using static Box2D.NET.B2MathFunction;
10+
using static Box2D.NET.B2Bodies;
11+
using static Box2D.NET.B2Shapes;
12+
using static Box2D.NET.B2Worlds;
13+
using static Box2D.NET.B2Contacts;
14+
using static Box2D.NET.B2Joints;
15+
16+
namespace Box2D.NET.Samples.Samples.Events;
17+
18+
// This shows how to create a projectile that explodes on impact
19+
class ProjectileEvent : Sample
20+
{
21+
private static readonly int sampleProjectileEvent = SampleFactory.Shared.RegisterSample("Events", "Projectile Event", Create);
22+
23+
private B2BodyId m_projectileId;
24+
private B2ShapeId m_projectileShapeId;
25+
private B2Vec2 m_point1;
26+
private B2Vec2 m_point2;
27+
private bool m_dragging;
28+
29+
private static Sample Create(SampleContext context)
30+
{
31+
return new ProjectileEvent(context);
32+
}
33+
34+
public ProjectileEvent(SampleContext context) : base(context)
35+
{
36+
if (m_context.settings.restart == false)
37+
{
38+
m_context.camera.m_center = new B2Vec2(-7.0f, 9.0f);
39+
m_context.camera.m_zoom = 14.0f;
40+
}
41+
42+
{
43+
B2BodyDef bodyDef = b2DefaultBodyDef();
44+
bodyDef.position = new B2Vec2(0.0f, 0.0f);
45+
B2BodyId groundId = b2CreateBody(m_worldId, ref bodyDef);
46+
47+
B2ShapeDef shapeDef = b2DefaultShapeDef();
48+
shapeDef.enableSensorEvents = true;
49+
50+
B2Segment segment = new B2Segment(new B2Vec2(10.0f, 0.0f), new B2Vec2(10.0f, 20.0f));
51+
b2CreateSegmentShape(groundId, ref shapeDef, ref segment);
52+
53+
segment = new B2Segment(new B2Vec2(-30.0f, 0.0f), new B2Vec2(30.0f, 0.0f));
54+
b2CreateSegmentShape(groundId, ref shapeDef, ref segment);
55+
}
56+
57+
m_projectileId = new B2BodyId();
58+
m_projectileShapeId = new B2ShapeId();
59+
m_dragging = false;
60+
m_point1 = b2Vec2_zero;
61+
m_point2 = b2Vec2_zero;
62+
63+
{
64+
B2Polygon box = b2MakeRoundedBox(0.45f, 0.45f, 0.05f);
65+
66+
B2ShapeDef shapeDef = b2DefaultShapeDef();
67+
shapeDef.enableSensorEvents = true;
68+
69+
float offset = 0.01f;
70+
71+
float x = 8.0f;
72+
B2BodyDef bodyDef = b2DefaultBodyDef();
73+
bodyDef.type = B2BodyType.b2_dynamicBody;
74+
75+
for (int i = 0; i < 8; ++i)
76+
{
77+
float shift = (i % 2 == 0 ? -offset : offset);
78+
bodyDef.position = new B2Vec2(x + shift, 0.5f + 1.0f * i);
79+
80+
B2BodyId bodyId = b2CreateBody(m_worldId, ref bodyDef);
81+
82+
b2CreatePolygonShape(bodyId, ref shapeDef, ref box);
83+
}
84+
}
85+
}
86+
87+
void FireProjectile()
88+
{
89+
if (B2_IS_NON_NULL(m_projectileId))
90+
{
91+
b2DestroyBody(m_projectileId);
92+
}
93+
94+
B2BodyDef bodyDef = b2DefaultBodyDef();
95+
bodyDef.type = B2BodyType.b2_dynamicBody;
96+
bodyDef.position = m_point1;
97+
bodyDef.linearVelocity = 4.0f * (m_point2 - m_point1);
98+
bodyDef.isBullet = true;
99+
100+
m_projectileId = b2CreateBody(m_worldId, ref bodyDef);
101+
102+
B2Circle circle = new B2Circle(new B2Vec2(0.0f, 0.0f), 0.25f);
103+
B2ShapeDef shapeDef = b2DefaultShapeDef();
104+
shapeDef.enableContactEvents = true;
105+
m_projectileShapeId = b2CreateCircleShape(m_projectileId, ref shapeDef, ref circle);
106+
}
107+
108+
public override void MouseDown(B2Vec2 p, MouseButton button, KeyModifiers mod)
109+
{
110+
if (button == MouseButton.Left)
111+
{
112+
if (mod == KeyModifiers.Control)
113+
{
114+
m_dragging = true;
115+
m_point1 = p;
116+
}
117+
}
118+
}
119+
120+
public override void MouseUp(B2Vec2 p, MouseButton button)
121+
{
122+
if (button == MouseButton.Left)
123+
{
124+
if (m_dragging)
125+
{
126+
m_dragging = false;
127+
FireProjectile();
128+
}
129+
}
130+
}
131+
132+
public override void MouseMove(B2Vec2 p)
133+
{
134+
if (m_dragging)
135+
{
136+
m_point2 = p;
137+
}
138+
}
139+
140+
public override void Step()
141+
{
142+
base.Step();
143+
144+
145+
B2ContactEvents contactEvents = b2World_GetContactEvents(m_worldId);
146+
for (int i = 0; i < contactEvents.beginCount; ++i)
147+
{
148+
ref B2ContactBeginTouchEvent @event = ref contactEvents.beginEvents[i];
149+
150+
if (B2_ID_EQUALS(@event.shapeIdA, m_projectileShapeId) || B2_ID_EQUALS(@event.shapeIdB, m_projectileShapeId))
151+
{
152+
if (b2Contact_IsValid(@event.contactId))
153+
{
154+
B2ContactData data = b2Contact_GetData(@event.contactId);
155+
156+
if (data.manifold.pointCount > 0)
157+
{
158+
B2ExplosionDef explosionDef = b2DefaultExplosionDef();
159+
explosionDef.position = data.manifold.points[0].point;
160+
explosionDef.radius = 1.0f;
161+
explosionDef.impulsePerLength = 20.0f;
162+
b2World_Explode(m_worldId, ref explosionDef);
163+
164+
b2DestroyBody(m_projectileId);
165+
m_projectileId = b2_nullBodyId;
166+
}
167+
}
168+
169+
break;
170+
}
171+
}
172+
}
173+
174+
public override void Draw(Settings settings)
175+
{
176+
base.Draw(settings);
177+
178+
DrawTextLine("Use Ctrl + Left Mouse to drag and shoot a projectile");
179+
180+
if (m_dragging)
181+
{
182+
m_draw.DrawLine(m_point1, m_point2, B2HexColor.b2_colorWhite);
183+
m_draw.DrawPoint(m_point1, 5.0f, B2HexColor.b2_colorGreen);
184+
m_draw.DrawPoint(m_point2, 5.0f, B2HexColor.b2_colorRed);
185+
}
186+
}
187+
}

src/Box2D.NET.Samples/Samples/Events/SensorHits.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public class SensorHits : Sample
3838
private B2Transform[] m_transforms = new B2Transform[m_transformCapacity];
3939

4040
private bool m_isBullet;
41-
private bool m_enableSensorHits;
4241
private int m_beginCount;
4342
private int m_endCount;
4443

@@ -138,7 +137,6 @@ public SensorHits(SampleContext context) : base(context)
138137
m_bodyId = new B2BodyId();
139138
m_shapeId = new B2ShapeId();
140139
m_transformCount = 0;
141-
m_enableSensorHits = true;
142140
m_isBullet = true;
143141

144142
Launch();
@@ -161,7 +159,6 @@ void Launch()
161159
float speed = RandomFloatRange(200.0f, 300.0f);
162160
bodyDef.linearVelocity = new B2Vec2(speed, 0.0f);
163161
bodyDef.isBullet = m_isBullet;
164-
bodyDef.enableSensorHits = m_enableSensorHits;
165162
m_bodyId = b2CreateBody(m_worldId, ref bodyDef);
166163

167164
B2ShapeDef shapeDef = b2DefaultShapeDef();
@@ -181,7 +178,6 @@ public override void UpdateGui()
181178

182179
ImGui.Begin("Sensor Hit", ImGuiWindowFlags.NoResize);
183180

184-
ImGui.Checkbox("Enable Hits", ref m_enableSensorHits);
185181
ImGui.Checkbox("Bullet", ref m_isBullet);
186182

187183
if (ImGui.Button("Launch") || GetKey(Keys.B) == InputAction.Press)
@@ -195,12 +191,13 @@ public override void UpdateGui()
195191
void CollectTransforms(B2ShapeId sensorShapeId)
196192
{
197193
const int capacity = 5;
198-
Span<B2SensorData> sensorData = stackalloc B2SensorData[capacity];
199-
int count = b2Shape_GetSensorData(sensorShapeId, sensorData, capacity);
194+
Span<B2ShapeId> visitorIds = stackalloc B2ShapeId[capacity];
195+
int count = b2Shape_GetSensorData(sensorShapeId, visitorIds, capacity);
200196

201197
for (int i = 0; i < count && m_transformCount < m_transformCapacity; ++i)
202198
{
203-
m_transforms[m_transformCount] = sensorData[i].visitTransform;
199+
B2BodyId sensorBodyId = b2Shape_GetBody(sensorShapeId);
200+
m_transforms[m_transformCount] = b2Body_GetTransform(sensorBodyId);
204201
m_transformCount += 1;
205202
}
206203
}
@@ -237,7 +234,10 @@ public override void Step()
237234
for (int i = 0; i < sensorEvents.beginCount; ++i)
238235
{
239236
ref readonly B2SensorBeginTouchEvent @event = ref sensorEvents.beginEvents[i];
240-
CollectTransforms(@event.sensorShapeId);
237+
if (b2Shape_IsValid(@event.sensorShapeId) == true)
238+
{
239+
CollectTransforms(@event.sensorShapeId);
240+
}
241241
}
242242
}
243243

src/Box2D.NET.Samples/Samples/Events/SensorTypes.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class SensorTypes : Sample
2929

3030
private B2BodyId m_kinematicBodyId;
3131

32-
private List<B2SensorData> m_sensorData = new List<B2SensorData>();
32+
private List<B2ShapeId> m_visitorIds = new List<B2ShapeId>();
3333

3434

3535
private static Sample Create(SampleContext context)
@@ -142,16 +142,16 @@ void PrintOverlaps(B2ShapeId sensorShapeId, string prefix)
142142
{
143143
// Determine the necessary capacity
144144
int capacity = b2Shape_GetSensorCapacity(sensorShapeId);
145-
m_sensorData.Resize(capacity);
145+
m_visitorIds.Resize(capacity);
146146

147147
// Get all overlaps and record the actual count
148-
int count = b2Shape_GetSensorData(sensorShapeId, CollectionsMarshal.AsSpan(m_sensorData), capacity);
149-
m_sensorData.Resize(count);
148+
int count = b2Shape_GetSensorData(sensorShapeId, CollectionsMarshal.AsSpan(m_visitorIds), capacity);
149+
m_visitorIds.Resize(count);
150150

151151
var builder = new StringBuilder();
152152
for (int i = 0; i < count; ++i)
153153
{
154-
B2ShapeId visitorId = m_sensorData[i].visitorId;
154+
B2ShapeId visitorId = m_visitorIds[i];
155155
if (b2Shape_IsValid(visitorId) == false)
156156
{
157157
continue;

0 commit comments

Comments
 (0)