source: 2013/30/MiskaK/MW2(My Warfare 2)/Paranneltu Jypeli/Game/PhysicsGameBase.cs @ 4507

Revision 4507, 20.2 KB checked in by anlakane, 6 years ago (diff)

Talletus.

Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using Physics2DDotNet;
6using Physics2DDotNet.Joints;
7
8namespace Jypeli
9{
10    /// <summary>
11    /// Kantaluokka fysiikkapeleille.
12    /// </summary>
13    public abstract class PhysicsGameBase : Game
14    {
15        protected struct CollisionRecord
16        {
17            public IPhysicsObject obj;
18            public IPhysicsObject target;
19            public object targetTag;
20            public Delegate handler;
21
22            public CollisionRecord( IPhysicsObject obj, IPhysicsObject target, object targetTag, Delegate handler )
23            {
24                this.obj = obj;
25                this.target = target;
26                this.targetTag = targetTag;
27                this.handler = handler;
28            }
29        }
30
31        protected PhysicsEngine phsEngine;
32        private SynchronousList<Joint> Joints = new SynchronousList<Joint>();
33        protected Dictionary<CollisionRecord, CollisionHandler<IPhysicsObject, IPhysicsObject>> collisionHandlers =
34            new Dictionary<CollisionRecord, CollisionHandler<IPhysicsObject, IPhysicsObject>>();
35        protected Dictionary<CollisionRecord, CollisionHandler<IPhysicsObject, IPhysicsObject>> protectedCollisionHandlers =
36            new Dictionary<CollisionRecord, CollisionHandler<IPhysicsObject, IPhysicsObject>>();
37
38        /// <summary>
39        /// Onko fysiikan laskenta käytössä vai ei.
40        /// </summary>
41        public bool PhysicsEnabled { get; set; }
42
43        /// <summary>
44        /// Alustaa uuden fysiikkapelin.
45        /// </summary>
46        /// <param name="device">Mikä monitori käytössä, 1=ensimmäinen</param>
47        public PhysicsGameBase( int device )
48            : base( device )
49        {
50            PhysicsEnabled = true;
51            phsEngine = new PhysicsEngine();
52
53            Joints.ItemAdded += OnJointAdded;
54            Joints.ItemRemoved += OnJointRemoved;
55        }
56
57        void OnJointAdded( Joint j )
58        {
59            j.Lifetime.IsExpired = false;
60            phsEngine.AddJoint( j );
61        }
62
63        void OnJointRemoved( Joint j )
64        {
65            j.Lifetime.IsExpired = true;
66        }
67
68        protected override void OnObjectAdded( IGameObject obj )
69        {
70            if ( obj is PhysicsObject )
71            {
72                AddToEngine( (PhysicsObject)obj );
73            }
74
75            base.OnObjectAdded( obj );
76        }
77
78        protected override void OnObjectRemoved( IGameObject obj )
79        {
80            if ( obj is PhysicsObject )
81            {
82                RemoveFromEngine( (PhysicsObject)obj );
83            }
84
85            base.OnObjectRemoved( obj );
86        }
87
88        /// <summary>
89        /// Pysäyttää kaiken liikkeen.
90        /// </summary>
91        public void StopAll()
92        {
93            foreach ( var layer in Layers )
94            {
95                foreach ( var obj in layer.Objects )
96                {
97                    if ( obj is PhysicsObject )
98                        ( (PhysicsObject)obj ).Stop();
99                }
100            }
101        }
102
103        /// <summary>
104        /// Nollaa kaiken (kontrollit, näyttöobjektit, ajastimet ja fysiikkamoottorin).
105        /// </summary>
106        public override void ClearAll()
107        {
108            ClearPhysics();
109            base.ClearAll();
110        }
111
112        /// <summary>
113        /// Nollaa fysiikkamoottorin.
114        /// </summary>
115        private void ClearPhysics()
116        {
117            phsEngine.Clear();
118        }
119
120        private void AddToEngine( PhysicsObject po )
121        {
122            if ( po.Body.Engine != null )
123                return;
124
125            po.Body.Lifetime.IsExpired = false;
126            phsEngine.AddBody( po.Body );
127        }
128
129        private void RemoveFromEngine( PhysicsObject po )
130        {
131            if ( po.Body.Engine == null )
132                return;
133
134            po.Body.Lifetime.IsExpired = true;
135        }
136
137        /// <summary>
138        /// Lisää liitoksen peliin.
139        /// </summary>
140        public void Add( Physics2DDotNet.Joints.Joint j )
141        {
142            Joints.Add( j );
143        }
144
145        /// <summary>
146        /// Poistaa liitoksen pelistä.
147        /// </summary>
148        /// <param name="j"></param>
149        internal void Remove( Physics2DDotNet.Joints.Joint j )
150        {
151            Joints.Remove( j );
152        }
153
154        /// <summary>
155        /// Poistaa liitoksen pelistä.
156        /// </summary>
157        /// <param name="j"></param>
158        internal void Remove( AxleJoint j )
159        {
160            Joints.Remove( j.innerJoint );
161        }
162
163        /// <summary>
164        /// Lisää liitoksen peliin.
165        /// </summary>
166        public void Add( AxleJoint j )
167        {
168            bool obj1ok = j.Object1.IsAddedToGame;
169            bool obj2ok = j.Object2 == null || j.Object2.IsAddedToGame;
170
171            if ( obj1ok && obj2ok )
172            {
173                Add( j.innerJoint );
174            }
175            else
176            {
177                if ( !obj1ok ) j.Object1.AddedToGame += j.DelayedAddJoint;
178                if ( !obj2ok ) j.Object2.AddedToGame += j.DelayedAddJoint;
179            }
180        }
181
182        /// <summary>
183        /// Ajetaan kun pelin tilannetta päivitetään. Päivittämisen voi toteuttaa perityssä luokassa
184        /// toteuttamalla tämän metodin. Perityn luokan metodissa tulee kutsua kantaluokan metodia.
185        /// </summary>
186        /// <param name="time"></param>
187        protected override void Update( Time time )
188        {
189            double dt = time.SinceLastUpdate.TotalSeconds;
190
191            if ( PhysicsEnabled )
192            {
193                phsEngine.Update( dt );
194            }
195
196            base.Update( time );
197
198            // Updating joints must be after base.Update so that the bodies
199            // are added to the engine before the joints
200            Joints.Update( time );
201        }
202
203        #region Collision handlers
204
205        /// <summary>
206        /// Määrää, mihin aliohjelmaan siirrytään kun olio <code>obj</code> törmää johonkin toiseen olioon.
207        /// </summary>
208        /// <typeparam name="T">Kohdeolion tyyppi.</typeparam>
209        /// <param name="obj">Törmäävä olio</param>
210        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
211        public void AddCollisionHandler<O, T>( O obj, CollisionHandler<O, T> handler )
212            where O : IPhysicsObject
213            where T : IPhysicsObject
214        {
215            if ( obj == null ) throw new NullReferenceException( "Colliding object must not be null" );
216            if ( handler == null ) throw new NullReferenceException( "Handler must not be null" );
217
218            CollisionHandler<IPhysicsObject, IPhysicsObject> targetHandler =
219                delegate( IPhysicsObject collider, IPhysicsObject collidee )
220                {
221                    if ( collidee is T )
222                        handler( (O)collider, (T)collidee );
223                };
224
225            obj.Collided += targetHandler;
226            collisionHandlers.Add( new CollisionRecord( obj, null, null, handler ), targetHandler );
227        }
228
229        /// <summary>
230        /// Määrää, mihin aliohjelmaan siirrytään kun olio <code>obj</code> törmää johonkin toiseen olioon.
231        /// Jypelin sisäiseen käyttöön!
232        /// </summary>
233        /// <typeparam name="T">Kohdeolion tyyppi.</typeparam>
234        /// <param name="obj">Törmäävä olio</param>
235        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
236        internal void AddProtectedCollisionHandler<O, T>( O obj, CollisionHandler<O, T> handler )
237            where O : IPhysicsObject
238            where T : IPhysicsObject
239        {
240            if ( obj == null ) throw new NullReferenceException( "Colliding object must not be null" );
241            if ( handler == null ) throw new NullReferenceException( "Handler must not be null" );
242
243            CollisionHandler<IPhysicsObject, IPhysicsObject> targetHandler =
244                delegate( IPhysicsObject collider, IPhysicsObject collidee )
245                {
246                    if ( collidee is T )
247                        handler( (O)collider, (T)collidee );
248                };
249
250            obj.Collided += targetHandler;
251            protectedCollisionHandlers.Add( new CollisionRecord( obj, null, null, handler ), targetHandler );
252        }
253
254        /// <summary>
255        /// Määrää, mihin aliohjelmaan siirrytään kun yleinen fysiikkaolio <code>obj</code>
256        /// törmää johonkin toiseen yleiseen fysiikkaolioon.
257        /// </summary>
258        /// <param name="obj">Törmäävä olio</param>
259        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
260        public void AddCollisionHandler( IPhysicsObject obj, CollisionHandler<IPhysicsObject, IPhysicsObject> handler )
261        {
262            AddCollisionHandler<IPhysicsObject, IPhysicsObject>( obj, handler );
263        }
264
265        /// <summary>
266        /// Määrää, mihin aliohjelmaan siirrytään kun fysiikkaolio <code>obj</code> törmää johonkin toiseen fysiikkaolioon.
267        /// </summary>
268        /// <param name="obj">Törmäävä olio</param>
269        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
270        public void AddCollisionHandler( PhysicsObject obj, CollisionHandler<PhysicsObject, PhysicsObject> handler )
271        {
272            AddCollisionHandler<PhysicsObject, PhysicsObject>( obj, handler );
273        }
274
275        /// <summary>
276        /// Määrää, mihin aliohjelmaan siirrytään kun fysiikkaolio <code>obj</code> törmää johonkin fysiikkarakenteeseen.
277        /// </summary>
278        /// <param name="obj">Törmäävä olio</param>
279        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
280        public void AddCollisionHandler( PhysicsObject obj, CollisionHandler<PhysicsObject, PhysicsStructure> handler )
281        {
282            AddCollisionHandler<PhysicsObject, PhysicsStructure>( obj, handler );
283        }
284
285        /// <summary>
286        /// Määrää, mihin aliohjelmaan siirrytään kun fysiikkarakenne <code>o</code> törmää johonkin fysiikkaolioon.
287        /// </summary>
288        /// <param name="obj">Törmäävä fysiikkarakenne</param>
289        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
290        public void AddCollisionHandler( PhysicsStructure obj, CollisionHandler<PhysicsStructure, PhysicsObject> handler )
291        {
292            AddCollisionHandler<PhysicsStructure, PhysicsObject>( obj, handler );
293        }
294
295        /// <summary>
296        /// Määrää, mihin aliohjelmaan siirrytään kun fysiikkarakenne <code>o</code> törmää toiseen fysiikkarakenteeseen.
297        /// </summary>
298        /// <param name="obj">Törmäävä fysiikkarakenne</param>
299        /// <param name="handler">Törmäyksen käsittelevä aliohjelma.</param>
300        public void AddCollisionHandler( PhysicsStructure obj, CollisionHandler<PhysicsStructure, PhysicsStructure> handler )
301        {
302            AddCollisionHandler<PhysicsStructure, PhysicsStructure>( obj, handler );
303        }
304
305        /// <summary>
306        /// Määrää, mihin aliohjelmaan siirrytään kun
307        /// olio <code>obj</code> törmää tiettyyn toiseen olioon <code>target</code>.
308        /// </summary>
309        /// <param name="obj">Törmäävä olio.</param>
310        /// <param name="target">Olio johon törmätään.</param>
311        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
312        public void AddCollisionHandler<O, T>( O obj, T target, CollisionHandler<PhysicsObject, T> handler )
313            where O : IPhysicsObject
314            where T : IPhysicsObject
315        {
316            if ( obj == null ) throw new NullReferenceException( "Colliding object must not be null" );
317            if ( target == null ) throw new NullReferenceException( "Collision target must not be null" );
318            if ( handler == null ) throw new NullReferenceException( "Handler must not be null" );
319
320            CollisionHandler<IPhysicsObject, IPhysicsObject> targetHandler =
321                delegate( IPhysicsObject collider, IPhysicsObject collidee )
322                {
323                    if ( object.ReferenceEquals( collidee, target ) )
324                        handler( (PhysicsObject)collider, (T)collidee );
325                };
326
327            obj.Collided += targetHandler;
328            collisionHandlers.Add( new CollisionRecord( obj, target, null, handler ), targetHandler );
329        }
330
331        /// <summary>
332        /// Määrää, mihin aliohjelmaan siirrytään kun
333        /// olio <code>obj</code> törmää toiseen olioon, jolla on tietty tagi <code>tag</code>.
334        /// </summary>
335        /// <param name="obj">Törmäävä olio.</param>
336        /// <param name="tag">Törmättävän olion tagi.</param>
337        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
338        public void AddCollisionHandler<O, T>( O obj, object tag, CollisionHandler<O, T> handler )
339            where O : IPhysicsObject
340            where T : IPhysicsObject
341        {
342            if ( obj == null ) throw new NullReferenceException( "Colliding object must not be null" );
343            if ( tag == null ) throw new NullReferenceException( "Tag must not be null" );
344            if ( handler == null ) throw new NullReferenceException( "Handler must not be null" );
345
346            CollisionHandler<IPhysicsObject, IPhysicsObject> targetHandler =
347                delegate( IPhysicsObject collider, IPhysicsObject collidee )
348                {
349                    if ( collidee is T && StringHelpers.StringEquals( collidee.Tag, tag ) )
350                        handler( (O)collider, (T)collidee );
351                };
352
353            obj.Collided += targetHandler;
354            collisionHandlers.Add( new CollisionRecord( obj, null, tag, handler ), targetHandler );
355        }
356
357        /// <summary>
358        /// Määrää, mihin aliohjelmaan siirrytään kun
359        /// yleinen fysiikkaolio <code>obj</code> törmää toiseen yleiseen fysiikkaolioon, jolla on tietty tagi <code>tag</code>.
360        /// </summary>
361        /// <param name="obj">Törmäävä olio.</param>
362        /// <param name="tag">Törmättävän olion tagi.</param>
363        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
364        public void AddCollisionHandler( IPhysicsObject obj, object tag, CollisionHandler<IPhysicsObject, IPhysicsObject> handler )
365        {
366            AddCollisionHandler<IPhysicsObject, IPhysicsObject>( obj, tag, handler );
367        }
368
369        /// <summary>
370        /// Määrää, mihin aliohjelmaan siirrytään kun
371        /// fysiikkaolio <code>obj</code> törmää toiseen fysiikkaolioon, jolla on tietty tagi <code>tag</code>.
372        /// </summary>
373        /// <param name="obj">Törmäävä olio.</param>
374        /// <param name="tag">Törmättävän olion tagi.</param>
375        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
376        public void AddCollisionHandler( PhysicsObject obj, object tag, CollisionHandler<PhysicsObject, PhysicsObject> handler )
377        {
378            AddCollisionHandler<PhysicsObject, PhysicsObject>( obj, tag, handler );
379        }
380
381        /// <summary>
382        /// Määrää, mihin aliohjelmaan siirrytään kun
383        /// fysiikkaolio <code>obj</code> törmää fysiikkarakenteeseen, jolla on tietty tagi <code>tag</code>.
384        /// </summary>
385        /// <param name="obj">Törmäävä olio.</param>
386        /// <param name="tag">Törmättävän olion tagi.</param>
387        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
388        public void AddCollisionHandler( PhysicsObject obj, object tag, CollisionHandler<PhysicsObject, PhysicsStructure> handler )
389        {
390            AddCollisionHandler<PhysicsObject, PhysicsStructure>( obj, tag, handler );
391        }
392
393        /// <summary>
394        /// Määrää, mihin aliohjelmaan siirrytään kun
395        /// fysiikkarakenne <code>obj</code> törmää fysiikkaolioon, jolla on tietty tagi <code>tag</code>.
396        /// </summary>
397        /// <param name="obj">Törmäävä rakenne.</param>
398        /// <param name="tag">Törmättävän olion tagi.</param>
399        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
400        public void AddCollisionHandler( PhysicsStructure obj, object tag, CollisionHandler<PhysicsStructure, PhysicsObject> handler )
401        {
402            AddCollisionHandler<PhysicsStructure, PhysicsObject>( obj, tag, handler );
403        }
404
405        /// <summary>
406        /// Määrää, mihin aliohjelmaan siirrytään kun
407        /// fysiikkarakenne <code>obj</code> törmää toiseen fysiikarakenteeseen, jolla on tietty tagi <code>tag</code>.
408        /// </summary>
409        /// <param name="obj">Törmäävä rakenne.</param>
410        /// <param name="tag">Törmättävän rakenteen tagi.</param>
411        /// <param name="handler">Metodi, joka käsittelee törmäyksen (ei parametreja).</param>
412        public void AddCollisionHandler( PhysicsStructure obj, object tag, CollisionHandler<PhysicsStructure, PhysicsStructure> handler )
413        {
414            AddCollisionHandler<PhysicsStructure, PhysicsStructure>( obj, tag, handler );
415        }
416
417        /// <summary>
418        /// Poistaa kaikki ehdot täyttävät törmäyksenkäsittelijät.
419        /// </summary>
420        /// <param name="obj">Törmäävä olio. null jos ei väliä.</param>
421        /// <param name="target">Törmäyksen kohde. null jos ei väliä.</param>
422        /// <param name="tag">Törmäyksen kohteen tagi. null jos ei väliä.</param>
423        /// <param name="handler">Törmäyksenkäsittelijä. null jos ei väliä.</param>
424        public void RemoveCollisionHandlers( PhysicsObject obj = null, PhysicsObject target = null, object tag = null, Delegate handler = null )
425        {
426            Predicate<CollisionRecord> pred = rec =>
427                ( obj == null || object.ReferenceEquals( obj, rec.obj ) ) &&
428                ( target == null || target == rec.target ) &&
429                ( tag == null || StringHelpers.StringEquals( tag, rec.targetTag ) ) &&
430                ( handler == null || object.ReferenceEquals( handler, rec.handler ) );
431
432            List<CollisionRecord> remove = new List<CollisionRecord>();
433
434            foreach (var key in collisionHandlers.Keys)
435            {
436                if (pred(key)) remove.Add(key);
437            }
438
439            foreach (var key in remove)
440            {
441                key.obj.Collided -= collisionHandlers[key];
442                collisionHandlers.Remove(key);
443            }
444        }
445
446        /// <summary>
447        /// Poistaa kaikki ehdot täyttävät törmäyksenkäsittelijät.
448        /// Jypelin sisäiseen käyttöön!
449        /// </summary>
450        /// <param name="obj">Törmäävä olio. null jos ei väliä.</param>
451        /// <param name="target">Törmäyksen kohde. null jos ei väliä.</param>
452        /// <param name="tag">Törmäyksen kohteen tagi. null jos ei väliä.</param>
453        /// <param name="handler">Törmäyksenkäsittelijä. null jos ei väliä.</param>
454        internal void RemoveProtectedCollisionHandlers( PhysicsObject obj = null, PhysicsObject target = null, object tag = null, Delegate handler = null )
455        {
456            Predicate<CollisionRecord> pred = rec =>
457                ( obj == null || object.ReferenceEquals( obj, rec.obj ) ) &&
458                ( target == null || target == rec.target ) &&
459                ( tag == null || tag.Equals( rec.targetTag ) ) &&
460                ( handler == null || object.ReferenceEquals( handler, rec.handler ) );
461
462            List<CollisionRecord> remove = new List<CollisionRecord>();
463
464            foreach ( var key in collisionHandlers.Keys )
465            {
466                if ( pred( key ) ) remove.Add( key );
467            }
468
469            foreach ( var key in remove )
470            {
471                key.obj.Collided -= protectedCollisionHandlers[key];
472                protectedCollisionHandlers.Remove( key );
473            }
474        }
475
476        #endregion
477    }
478}
Note: See TracBrowser for help on using the repository browser.