source: 2014/24/EemeliK/Zombieland/Jypeli/Physics2DDotNet/PhysicsLogics/ExplosionLogic.cs @ 10335

Revision 5974, 9.5 KB checked in by empaheik, 5 years ago (diff)
Line 
1#region MIT License
2/*
3 * Copyright (c) 2005-2008 Jonathan Mark Porter. http://physics2d.googlepages.com/
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22#endregion
23
24
25#if UseDouble
26using Scalar = System.Double;
27#else
28using Scalar = System.Single;
29#endif
30using System;
31using System.Collections.Generic;
32using System.Collections.ObjectModel;
33
34using AdvanceMath;
35
36using AdvanceMath.Geometry2D;
37using Physics2DDotNet.Shapes;
38
39namespace Physics2DDotNet.PhysicsLogics
40{
41
42   
43
44    /// <summary>
45    /// Simulates a simple explosion. 
46    /// </summary>
47    public sealed class ExplosionLogic : PhysicsLogic
48    {
49        sealed class Wrapper
50        {
51            public Body body;
52            public IExplosionAffectable  affectable;
53        }
54
55        Scalar dragCoefficient;
56        Scalar radius;
57        Scalar time;
58        Scalar pressurePulseSpeed;
59        Body explosionBody;
60        List<Wrapper> items;
61
62        /// <summary>
63        /// Creates a new instance of the ExplosionLogic
64        /// </summary>
65        /// <param name="location">ground zero</param>
66        /// <param name="velocity">the velocity of the explosion (this would be from the missile or bomb that spawns it).</param>
67        /// <param name="pressurePulseSpeed">the speed at which the explosion expands</param>
68        /// <param name="dragCoefficient">the drag Coefficient</param>
69        /// <param name="mass">the mass of the expanding cloud</param>
70        /// <param name="lifetime"></param>
71        public ExplosionLogic(
72            Vector2D location,
73            Vector2D velocity,
74            Scalar pressurePulseSpeed,
75            Scalar dragCoefficient,
76            Scalar mass,
77            Lifespan lifetime)
78            : base(lifetime)
79        {
80            this.dragCoefficient = dragCoefficient;
81            this.pressurePulseSpeed = pressurePulseSpeed;
82            this.explosionBody = new Body(
83                new PhysicsState(new ALVector2D(0, location), new ALVector2D(0, velocity)),
84                new CircleShape(1, 3),
85                mass,
86                new Coefficients(1, 1), lifetime);
87            this.explosionBody.IgnoresCollisionResponse = true;
88            this.explosionBody.Collided += OnCollided;
89            this.items = new List<Wrapper>();
90        }
91        public Body ExplosionBody { get { return explosionBody; } }
92        void OnCollided(object sender, CollisionEventArgs e)
93        {
94            if (e.Other.IgnoresPhysicsLogics||
95                Scalar.IsPositiveInfinity(e.Other.Mass.Mass)) { return; }
96            IExplosionAffectable affectable = e.Other.Shape as IExplosionAffectable;
97            if (affectable != null)
98            {
99                Wrapper wrapper = new Wrapper();
100                wrapper.body = e.Other;
101                wrapper.affectable = affectable;
102                items.Add(wrapper);
103            }
104        }
105        public override ReadOnlyCollection<Body> LogicBodies
106        {
107            get
108            {
109                return new ReadOnlyCollection<Body>(new Body[] { explosionBody });
110            }
111        }
112        protected internal override void UpdateTime(TimeStep step)
113        {
114            time += step.Dt;
115            radius = 1 + time * pressurePulseSpeed;
116            explosionBody.Transformation = Matrix2x3.FromScale(new Vector2D(radius, radius));
117            base.UpdateTime(step);
118        }
119        protected internal override void RunLogic(TimeStep step)
120        {
121            Scalar area = MathHelper.Pi * radius * radius;
122            Scalar density = explosionBody.Mass.Mass / area;
123            BoundingCircle circle = new BoundingCircle(explosionBody.State.Position.Linear, radius);
124            Matrix2x3 temp;
125            ALVector2D.ToMatrix2x3(ref explosionBody.State.Position, out temp);
126
127            Matrices matrices = new Matrices();
128            matrices.SetToWorld(ref temp);
129
130
131            Vector2D relativeVelocity = Vector2D.Zero;
132            Vector2D velocityDirection = Vector2D.Zero;
133            Vector2D dragDirection = Vector2D.Zero;
134
135
136            for (int index = 0; index < items.Count; ++index)
137            {
138                Wrapper wrapper = items[index];
139                Body body = wrapper.body;
140                Matrix2x3 matrix;
141                Matrix2x3.Multiply(ref matrices.ToBody, ref body.Matrices.ToWorld, out matrix);
142                ContainmentType containmentType;
143                BoundingRectangle rect = body.Rectangle;
144                circle.Contains(ref rect, out containmentType);
145
146                if (containmentType == ContainmentType.Intersects)
147                {
148                    return;
149                    GetTangentCallback callback = delegate(Vector2D centroid)
150                    {
151                        centroid = body.Matrices.ToWorld * centroid;
152                        Vector2D p1 = centroid - explosionBody.State.Position.Linear;
153                        Vector2D p2 = centroid - body.State.Position.Linear;
154
155                        PhysicsHelper.GetRelativeVelocity(
156                            ref explosionBody.State.Velocity,
157                            ref body.State.Velocity,
158                            ref p1,
159                            ref p2,
160                            out relativeVelocity);
161                        relativeVelocity = p1.Normalized * this.pressurePulseSpeed;
162                        relativeVelocity = -relativeVelocity;
163                        velocityDirection = relativeVelocity.Normalized;
164                        dragDirection = matrices.ToBodyNormal * velocityDirection.LeftHandNormal;
165                        return dragDirection;
166                    };
167
168                    DragInfo dragInfo = wrapper.affectable.GetExplosionInfo(matrix, radius, callback);
169                    if (dragInfo == null) { continue; }
170                    if (velocityDirection == Vector2D.Zero) { continue; }
171
172                    if (dragInfo.DragArea < .01f) { continue; }
173                    Scalar speedSq = relativeVelocity.MagnitudeSq;
174                    Scalar dragForceMag = -.5f * density * speedSq * dragInfo.DragArea * dragCoefficient;
175                    Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv;
176                    if (dragForceMag < maxDrag)
177                    {
178                        dragForceMag = maxDrag;
179                    }
180
181                    Vector2D dragForce = dragForceMag * velocityDirection;
182                    wrapper.body.ApplyForce(dragForce, (body.Matrices.ToBody * matrices.ToWorld) * dragInfo.DragCenter);
183                }
184                else if (containmentType == ContainmentType.Contains)
185                {
186                    Vector2D centroid = body.Matrices.ToWorld * wrapper.affectable.Centroid;
187
188                    Vector2D p1 = centroid - explosionBody.State.Position.Linear;
189                    Vector2D p2 = centroid - body.State.Position.Linear;
190
191                    PhysicsHelper.GetRelativeVelocity(
192                        ref explosionBody.State.Velocity,
193                        ref body.State.Velocity,
194                        ref p1,
195                        ref p2,
196                        out relativeVelocity);
197                    relativeVelocity = p1.Normalized * this.pressurePulseSpeed;
198                    relativeVelocity = -relativeVelocity;
199                    velocityDirection = relativeVelocity.Normalized;
200                    dragDirection = matrices.ToBodyNormal * velocityDirection.LeftHandNormal;
201
202
203                    DragInfo dragInfo = wrapper.affectable.GetFluidInfo(dragDirection);
204                    if (dragInfo.DragArea < .01f) { continue; }
205                    Scalar speedSq = relativeVelocity.MagnitudeSq;
206                    Scalar dragForceMag = -.5f * density * speedSq * dragInfo.DragArea * dragCoefficient;
207                    Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv;
208                    if (dragForceMag < maxDrag)
209                    {
210                        dragForceMag = maxDrag;
211                    }
212
213                    Vector2D dragForce = dragForceMag * velocityDirection;
214                    wrapper.body.ApplyForce(dragForce, body.Matrices.ToWorldNormal * dragInfo.DragCenter);
215
216                    wrapper.body.ApplyTorque(
217                       -body.Mass.MomentOfInertia *
218                       (body.Coefficients.DynamicFriction + density + dragCoefficient) *
219                       body.State.Velocity.Angular);
220                }
221
222            }
223        }
224    }
225}
Note: See TracBrowser for help on using the repository browser.