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

Revision 4507, 21.3 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.Ignorers;
7using AdvanceMath;
8using Jypeli.Controls;
9
10namespace Jypeli
11{
12    /// <summary>
13    /// Rakenne, joka pitää fysiikkaoliot kiinteän matkan päässä toisistaan.
14    /// </summary>
15    public class PhysicsStructure : GameObjects.GameObjectBase, IPhysicsObjectInternal
16    {
17        private double _softness = 0;
18        private List<PhysicsObject> objects;
19
20        /// <summary>
21        /// Onko rakenne lisätty peliin.
22        /// </summary>
23        public bool IsAddedToGame { get; set; }
24
25        /// <summary>
26        /// Rakenteeseen kuuluvat oliot.
27        /// </summary>
28        public IList<PhysicsObject> Objects
29        {
30            get { return objects.AsReadOnly(); }
31        }
32
33        /// <summary>
34        /// Rakenteeseen kuuluvat liitokset.
35        /// </summary>
36        internal List<AxleJoint> Joints { get; private set; }
37
38        /// <summary>
39        /// Olioiden välisten liitosten pehmeys.
40        /// </summary>
41        public double Softness
42        {
43            get { return _softness; }
44            set
45            {
46                _softness = value;
47
48                for ( int i = 0; i < Joints.Count; i++ )
49                {
50                    Joints[i].Softness = value;
51                }
52            }
53        }
54
55        public BoundingRectangle BoundingRectangle
56        {
57            get
58            {
59                if ( objects.Count == 0 )
60                    return new BoundingRectangle();
61
62                double top = objects[0].Top;
63                double left = objects[0].Left;
64                double bottom = objects[0].Bottom;
65                double right = objects[0].Right;
66
67                for ( int i = 1; i < objects.Count; i++ )
68                {
69                    if ( objects[i].Top > top ) top = objects[i].Top;
70                    if ( objects[i].Left < left ) left = objects[i].Left;
71                    if ( objects[i].Bottom < bottom ) bottom = objects[i].Bottom;
72                    if ( objects[i].Right > right ) right = objects[i].Right;
73                }
74
75                return new BoundingRectangle( new Vector( left, top ), new Vector( right, bottom ) );
76            }
77        }
78
79        #region Tagged
80       
81        public object Tag { get; set; }
82
83        #endregion
84
85        #region IGameObject
86
87        public event Action AddedToGame;
88
89        bool _isVisible = true;
90        PhysicsObject centerObject;
91
92        public bool IsVisible
93        {
94            get { return false; }
95            set
96            {
97                foreach ( var obj in objects )
98                {
99                    obj.IsVisible = value;
100                }
101
102                _isVisible = value;
103            }
104        }
105
106        public List<Listener> AssociatedListeners { get; private set; }
107
108        /// <summary>
109        /// Rakenteen paikka pelimaailmassa.
110        /// </summary>
111        public override Vector Position
112        {
113            get
114            {
115                return centerObject.Position;
116            }
117            set
118            {
119                Vector delta = value - Position;
120
121                foreach ( var obj in objects )
122                {
123                    obj.Position += delta;
124                }
125
126                centerObject.Position = value;
127            }
128        }
129
130        public override Vector Size
131        {
132            get
133            {
134                return BoundingRectangle.Size;
135            }
136            set
137            {
138                throw new NotImplementedException( "Setting size for a structure is not implemented." );
139            }
140        }
141
142        public override Animation Animation
143        {
144            get { return null; }
145            set
146            {
147                throw new InvalidOperationException( "Physics structure has no image or animation." );
148            }
149        }
150
151        public Vector TextureWrapSize
152        {
153            get { return new Vector( 1, 1 ); }
154            set { throw new NotImplementedException(); }
155        }
156
157        public bool TextureFillsShape
158        {
159            get { return false; }
160            set { throw new NotImplementedException(); }
161        }
162
163        public Color Color
164        {
165            get
166            {
167                throw new NotImplementedException();
168            }
169            set
170            {
171                foreach ( var obj in objects )
172                    obj.Color = value;
173            }
174        }
175
176        public Shape Shape
177        {
178            get { return Shape.Rectangle; }
179            set { throw new NotImplementedException(); }
180        }
181
182        public override Angle Angle
183        {
184            // TODO: Rotation
185            get { return Angle.Zero; }
186            set { throw new NotImplementedException(); }
187        }
188
189        #endregion
190
191        #region IPhysicsObject
192
193        bool _ignoresGravity = false;
194        bool _ignoresCollisionResponse = false;
195        bool _ignoresExplosions = false;
196        bool _ignoresPhysicsLogics = false;
197        Ignorer _collisionIgnorer = null;
198        int _collisionIgnoreGroup = 0;
199        Coefficients _coeffs = PhysicsObject.DefaultCoefficients.Duplicate();
200        double _linearDamping = 1;
201        double _angularDamping = 1;
202        double? _setMomentOfInertia = null;
203        double _calcMomentOfInertia = 0;
204
205        /// <summary>
206        /// Tapahtuu kun olio törmää toiseen.
207        /// </summary>
208        public event CollisionHandler<IPhysicsObject, IPhysicsObject> Collided;
209
210        /// <summary>
211        /// Rakenneolio, johon tämä olio kuuluu.
212        /// </summary>
213        public PhysicsStructure ParentStructure
214        {
215            // No nested physics structures for now
216            get { return null; }
217        }
218
219        public double Mass
220        {
221            get
222            {
223                double totalMass = 0;
224                foreach ( var part in objects )
225                    totalMass += part.Mass;
226                return totalMass;
227            }
228            set
229            {
230                throw new NotImplementedException( "Setting mass for a structure is not implemented." );
231            }
232        }
233
234        public Body Body
235        {
236            get
237            {
238                throw new InvalidOperationException( "Structure has no body." );
239            }
240        }
241
242        public bool IgnoresGravity
243        {
244            get { return _ignoresGravity; }
245            set
246            {
247                foreach ( var obj in objects )
248                    obj.IgnoresGravity = value;
249
250                _ignoresGravity = value;
251            }
252        }
253
254        public bool IgnoresCollisionResponse
255        {
256            get { return _ignoresCollisionResponse; }
257            set
258            {
259                foreach ( var obj in objects )
260                    obj.IgnoresCollisionResponse = value;
261
262                _ignoresCollisionResponse = value;
263            }
264        }
265
266        public bool IgnoresExplosions
267        {
268            get { return _ignoresExplosions; }
269            set
270            {
271                foreach ( var obj in objects )
272                    obj.IgnoresExplosions = value;
273
274                _ignoresExplosions = value;
275            }
276        }
277
278        public bool IgnoresPhysicsLogics
279        {
280            get { return _ignoresPhysicsLogics; }
281            set
282            {
283                foreach ( var obj in objects )
284                    obj.IgnoresPhysicsLogics = value;
285
286                _ignoresPhysicsLogics = value;
287            }
288        }
289
290        public Ignorer CollisionIgnorer
291        {
292            get { return _collisionIgnorer; }
293            set
294            {
295                foreach ( var obj in objects )
296                    obj.CollisionIgnorer = value;
297
298                _collisionIgnorer = value;
299            }
300        }
301
302        public int CollisionIgnoreGroup
303        {
304            get { return _collisionIgnoreGroup; }
305            set
306            {
307                foreach ( var obj in objects )
308                    obj.CollisionIgnoreGroup = value;
309
310                _collisionIgnoreGroup = value;
311            }
312        }
313
314        public double StaticFriction
315        {
316            get { return _coeffs.StaticFriction; }
317            set
318            {
319                foreach ( var obj in objects )
320                    obj.StaticFriction = value;
321
322                _coeffs.StaticFriction = value;
323            }
324        }
325
326        public double KineticFriction
327        {
328            get { return _coeffs.DynamicFriction; }
329            set
330            {
331                foreach ( var obj in objects )
332                    obj.KineticFriction = value;
333
334                _coeffs.DynamicFriction = value;
335            }
336        }
337
338        public double Restitution
339        {
340            get { return _coeffs.Restitution; }
341            set
342            {
343                foreach ( var obj in objects )
344                    obj.Restitution = value;
345
346                _coeffs.Restitution = value;
347            }
348        }
349
350        public double LinearDamping
351        {
352            get { return _linearDamping; }
353            set
354            {
355                foreach ( var obj in objects )
356                    obj.LinearDamping = value;
357
358                _linearDamping = value;
359            }
360        }
361
362        public double AngularDamping
363        {
364            get { return _angularDamping; }
365            set
366            {
367                foreach ( var obj in objects )
368                    obj.AngularDamping = value;
369
370                _angularDamping = value;
371            }
372        }
373
374        public Vector Velocity
375        {
376            get
377            {
378                var velocities = objects.ConvertAll<PhysicsObject, Vector>( delegate( PhysicsObject o ) { return o.Velocity; } );
379                return Vector.Average( velocities );
380            }
381            set
382            {
383                foreach ( var obj in objects )
384                    obj.Velocity = value;
385            }
386        }
387
388        public double AngularVelocity
389        {
390            get
391            {
392                IEnumerable<double> velocities = objects.ConvertAll<PhysicsObject, double>( delegate( PhysicsObject o ) { return o.AngularVelocity; } );
393                return velocities.Average();
394            }
395            set
396            {
397                foreach ( var obj in objects )
398                    obj.AngularVelocity = value;
399            }
400        }
401
402        public Vector Acceleration
403        {
404            get
405            {
406                var accs = objects.ConvertAll<PhysicsObject, Vector>( delegate( PhysicsObject o ) { return o.Acceleration; } );
407                return Vector.Average( accs );
408            }
409            set
410            {
411                foreach ( var obj in objects )
412                    obj.Acceleration = value;
413            }
414        }
415
416        public double AngularAcceleration
417        {
418            get
419            {
420                IEnumerable<double> accs = objects.ConvertAll<PhysicsObject, double>( delegate( PhysicsObject o ) { return o.AngularAcceleration; } );
421                return accs.Average();
422            }
423            set
424            {
425                foreach ( var obj in objects )
426                    obj.AngularAcceleration = value;
427            }
428        }
429
430        public double MomentOfInertia
431        {
432            get
433            {
434                return _setMomentOfInertia.HasValue ? _setMomentOfInertia.Value : _calcMomentOfInertia;
435            }
436            set
437            {
438                _setMomentOfInertia = value;
439            }
440        }
441
442        /// <summary>
443        /// Jos <c>false</c>, olio ei voi pyöriä.
444        /// </summary>
445        public bool CanRotate
446        {
447            get { return !double.IsPositiveInfinity( MomentOfInertia ); }
448            set
449            {
450                if ( !value )
451                {
452                    MomentOfInertia = double.PositiveInfinity;
453                }
454                else
455                {
456                    CalculateMomentOfInertia();
457                    _setMomentOfInertia = null;
458                }
459            }
460        }
461
462        #endregion
463
464        /// <summary>
465        /// Luo uuden tyhjän rakenteen.
466        /// </summary>
467        public PhysicsStructure()
468        {
469            centerObject = new PhysicsObject( 1, 1 ) { IgnoresPhysicsLogics = true, IsVisible = false };
470            objects = new List<PhysicsObject>();
471            Joints = new List<AxleJoint>();
472            AssociatedListeners = new List<Listener>();
473            AddedToGame += AddJoints;
474            Removed += RemoveJoints;
475        }
476
477        private void AddJoints()
478        {
479            Joints.ForEach( ( (PhysicsGameBase)Game.Instance ).Add );
480        }
481
482        private void RemoveJoints()
483        {
484            Joints.ForEach( ( (PhysicsGameBase)Game.Instance ).Remove );
485        }
486
487        /// <summary>
488        /// Luo uuden rakenteen ja varustaa sen fysiikkaolioilla.
489        /// </summary>
490        /// <param name="objs">Fysiikkaoliot</param>
491        public PhysicsStructure( params PhysicsObject[] objs )
492            : this()
493        {
494            for ( int i = 0; i < objs.Length; i++ )
495            {
496                Add( objs[i] );
497            }
498        }
499
500        /// <summary>
501        /// Kutsutaan kun olio lisätään peliin.
502        /// </summary>
503        public void OnAddedToGame()
504        {
505            if ( AddedToGame != null )
506                AddedToGame();
507            //brain.AddToGameEvent();
508        }
509
510        /// <summary>
511        /// Kutsutaan kun törmätään.
512        /// </summary>
513        internal void OnCollided( IPhysicsObject part, IPhysicsObject target )
514        {
515            if ( Collided != null )
516                Collided( this, target );
517        }
518
519        public void Update( Time time )
520        {
521            foreach ( var obj in objects )
522            {
523                if ( obj.IsUpdated )
524                    obj.Update( time );
525            }
526        }
527
528        /// <summary>
529        /// Lisää olion rakenteeseen.
530        /// </summary>
531        /// <param name="obj">Lisättävä olio</param>
532        public void Add( GameObject obj )
533        {
534            if ( !( obj is PhysicsObject ) )
535                throw new NotImplementedException( "Currently only PhysicsObjects can be added to a structure." );
536
537            if ( !IsAddedToGame )
538            {
539                // Add to game and use relative coordinates
540                obj.Position += this.Position;
541                Game.Instance.Add( obj );
542            }
543
544            PhysicsObject physObj = (PhysicsObject)obj;
545            physObj.ParentStructure = this;
546            physObj.IsVisible = _isVisible;
547            physObj.IgnoresGravity = _ignoresGravity;
548            physObj.IgnoresCollisionResponse = _ignoresCollisionResponse;
549            physObj.IgnoresExplosions = _ignoresExplosions;
550            physObj.IgnoresPhysicsLogics = _ignoresPhysicsLogics;
551            physObj.CollisionIgnorer = _collisionIgnorer;
552            physObj.CollisionIgnoreGroup = _collisionIgnoreGroup;
553            physObj.Restitution = _coeffs.Restitution;
554            physObj.StaticFriction = _coeffs.StaticFriction;
555            physObj.KineticFriction = _coeffs.DynamicFriction;
556            physObj.LinearDamping = _linearDamping;
557            physObj.AngularDamping = _angularDamping;
558
559            physObj.Collided += this.OnCollided;
560
561            foreach ( var existing in objects )
562            {
563                AddJoint( physObj, existing );
564            }
565
566            objects.Add( physObj );
567            CalculateMomentOfInertia();
568        }
569
570        private void AddJoint( PhysicsObject obj1, PhysicsObject obj2 )
571        {
572            AxleJoint joint = new AxleJoint( obj1, obj2 );
573            joint.Softness = _softness;
574            Joints.Add( joint );
575            ( (PhysicsGameBase)Game.Instance ).Add( joint );
576        }
577
578        public void Remove( GameObject obj )
579        {
580            if ( !( obj is PhysicsObject ) )
581                throw new NotImplementedException( "Currently only PhysicsObjects can be added to a structure." );
582
583            PhysicsObject physObj = (PhysicsObject)obj;
584
585            if ( !objects.Contains( physObj ) )
586                return;
587
588            physObj.ParentStructure = null;
589            physObj.CollisionIgnorer = null;
590            physObj.CollisionIgnoreGroup = 0;
591            physObj.Collided -= this.OnCollided;
592
593            foreach ( var joint in Joints.FindAll( j => j.Object1 == physObj || j.Object2 == physObj ) )
594            {
595                ( (PhysicsGameBase)Game.Instance ).Remove( joint );
596            }
597
598            objects.Remove( physObj );
599            CalculateMomentOfInertia();
600        }
601
602        private void CalculateMomentOfInertia()
603        {
604            Vector center = this.Position;
605            _calcMomentOfInertia = 0;
606
607            foreach ( var part in objects )
608            {
609                double r = Vector.Distance( center, part.Position );
610                _calcMomentOfInertia += part.Mass * r * r;
611            }
612        }
613
614        public bool IsInside( Vector point )
615        {
616            foreach ( var obj in objects )
617            {
618                if ( obj.IsInside( point ) )
619                    return true;
620            }
621
622            return false;
623        }
624
625        #region IPhysicsObject
626
627        public void Hit( Vector impulse )
628        {
629            Vector velocity = impulse / Mass;
630
631            foreach ( var obj in objects )
632            {
633                obj.Hit( velocity * obj.Mass );
634            }
635        }
636
637        public void Push( Vector force )
638        {
639            Vector acceleration = force / Mass;
640
641            foreach ( var obj in objects )
642            {
643                obj.Push( acceleration * obj.Mass );
644            }
645        }
646
647        public void Push( Vector force, TimeSpan time )
648        {
649            Vector acceleration = force / Mass;
650
651            foreach ( var obj in objects )
652            {
653                obj.Push( acceleration * obj.Mass, time );
654            }
655        }
656
657        public void ApplyTorque( double torque )
658        {
659            if ( MomentOfInertia == 0 || double.IsInfinity( MomentOfInertia ) )
660                return;
661
662            double angularAcc = torque / MomentOfInertia;
663            Vector center = this.Position;
664
665            foreach ( var obj in objects )
666            {
667                Vector radius = obj.Position - center;
668                double linearAcc = radius.Magnitude * angularAcc;
669                obj.Push( linearAcc * obj.Mass * radius.LeftNormal );
670            }
671        }
672
673        public void Move( Vector movement )
674        {
675            foreach ( var obj in objects )
676            {
677                obj.Move( movement );
678            }
679        }
680
681        public override void MoveTo( Vector location, double speed, Action doWhenArrived )
682        {
683            centerObject.MoveTo( location, speed, doWhenArrived );
684
685            foreach ( var obj in objects )
686            {
687                Vector displacement = obj.AbsolutePosition - centerObject.AbsolutePosition;
688                obj.MoveTo( location + displacement, speed );
689            }
690        }
691
692        public void StopMoveTo()
693        {
694            foreach ( var obj in objects )
695                obj.StopMoveTo();
696        }
697
698        public void Stop()
699        {
700            foreach ( var obj in objects )
701                obj.Stop();
702        }
703
704        public void StopHorizontal()
705        {
706            foreach ( var obj in objects )
707                obj.StopHorizontal();
708        }
709
710        public void StopVertical()
711        {
712            foreach ( var obj in objects )
713                obj.StopVertical();
714        }
715
716        #endregion
717
718        #region DelayedDestroyable
719
720        #region DelayedDestroyable
721
722        /// <summary>
723        /// Onko olio tuhoutumassa.
724        /// </summary>
725        public bool IsDestroying { get; private set; }
726
727        /// <summary>
728        /// Tapahtuu, kun olion tuhoaminen alkaa.
729        /// </summary>
730        public event Action Destroying;
731
732        protected void OnDestroying()
733        {
734            if ( Destroying != null )
735                Destroying();
736        }
737
738        public override void Destroy()
739        {
740            IsDestroying = true;
741            OnDestroying();
742            Game.DoNextUpdate( ReallyDestroy );
743        }
744
745        protected virtual void ReallyDestroy()
746        {
747            foreach ( var joint in Joints ) joint.Destroy();
748            foreach ( var obj in objects ) obj.Destroy();
749            this.MaximumLifetime = new TimeSpan( 0 );
750            base.Destroy();
751        }
752
753        #endregion
754
755        #endregion
756
757        #region Unimplemented Members / IGameObject
758
759        public IGameObject Parent
760        {
761            get { throw new NotImplementedException(); }
762            set { throw new NotImplementedException(); }
763        }
764
765        #endregion
766    }
767}
Note: See TracBrowser for help on using the repository browser.