الشبكة العربية لمطوري الألعاب

محترف  انس مشاركة 1

السلام عليكم 😄  .
واجهتني مشكلة في المشروع المقرر تقديمه لمسابقة  Xna challenge Algeria  و كما هو موضح في العنوان المشكلة مشكلة تصادم (التصادم في اللعبة و التصادم بين رأسي و شاشة الحاسوب ☺  ).

اللعبة ثنائية البعد، وهذا يبسط عمليا الحسابات اللازمة لكشف التصادم، رغم ذلك فاني تعرضت لحالات لا اعرف ايهما اسرع السلحفاة ام الحاسوب. هذه الحالات تكون عند وجود عدد كبير جدا من الكائنات التي من المحتمل ان تتصادم.في النهاية توصلت الى حل يوفر عدد كبير من الحسابات، سأشرح لكم خطوات هذا الحل ثم اخبركم عن المشكل الذي أواجهه.

الفكرة تكمن في عدم مقارنة الكائنات المتباعدة، و التي يستحيل أن تتصادم.
الخوارزمية :

1- نقسم عالم اللعبة الى مساحات (Areas) و المسؤول عن هذا هو منسق المساحات (AreaManager) و.

2- اضافة كل كائن جديد الى  منسق الكائنات(EntityManager)و.

3- يقوم منسق الكائنات من اجل كل كائن محتوى فيه :
     * التحقق من أن الكائن فعال(active) و ظاهر(Visible)، وإلا فيقوم بحذفه.
     * اذا كان الكائن فعال يقوم منسق الكائنات بتحديثه، ثم اذا كان ظاهرا أيضا يقوم بتحديد موقعه في العالم.
     * تحديد موقع كل كائن يتم كالتالي :
           + استخراج احداثيات الزوايا الاربعة للكائن(او النقاط الاربعة المشكلة لمستطيل الكائن)
           + انطلاقا من القيم السابقة، يتم بواسطة، معادلة بسيطة سيتم  التعرف عليها عند وضع الكود في الاسفل، تحويل هذه القيم الى اربع مؤشرات                   (بمعنى  Index) كل منها يشير الى مساحة معينة و التي يكون الكائن متواجدا بها.
           + اضافة الكائن الى المساحات التي يؤشر عليها.

4- يقوم منسق المساحات( AreaManager) بتحديث(و ممكن رسم) كامل المساحات

5- تقوم كل مساحة بمايلي : من اجل كل كائن موجود في المساحة :
     * نقارن الكائن مع الكائنات الاخرى (مع مراعات عدم مقارنة الكائن مع نفسه) وذلك لمعرفة الكائنات المحتمل تصادمها
     * إذا نحن بصدد مقارنة الكائن مع كائن اخر، و مستطيل كل من الكائنين في حالة تصادم، اذا هناك حالة تصادم.
     * إذا وجدة حالة تصادم، سننشئ وحدة تصادم(Collision Unit) و نرسلها الى منسق التصادم (CollisionManager). وحدة التصادم هي عبارة عن                كائن يخزن الكائنين المتصادمين. بعد انتهاء المقارنة نحذف الكائنات من المساحة.

6- يقوم منسق التصادم بتخزين وحدات التصادم في شكل طابور (Queue)، ثم يقوم بتنفيذ كل وحدات التصادم مستدعيا بذلك دالة التصادم لكلا الكائنين. بعد ان يتم تنفيذ كل وحدات التصادم، نمحي الوحدات المخزنة.
 
يا الله النص طويل جدا☺  ، لكن لا بئس ان اطمع في مساعدتكم حتى لا يكشف الحاسوب عن حالة تصادم راسي به.
الكود مكتوب بالسي شارب و Xna.

EntityManager.cs
static  class EntityManager
    {
        static private List WorldEntityList = new List ();

        static public void AddEntityToWorld( DynamicSprite NewEntity )
        {
            if(!(WorldEntityList.Contains(NewEntity)) )
                WorldEntityList.Add (NewEntity);
        }

        /// 
        /// Update all entity in the game
        /// 
        static public void Update( GameTime gameTime )
        {
            if ( WorldEntityList.Count > 0 )
            {
                foreach ( DynamicSprite Entity in WorldEntityList )
                {
                    // if the Entity is no more active no more visible delete it
                    if ( !(Entity.IsActive && Entity.IsVisible) )
                    {
                        WorldEntityList.Remove(Entity) ;
                    }
                    if ( Entity.IsActive )
                    {
                        Entity.Update (gameTime);
                        if ( Entity.IsVisible  )
                        {
                            // Get the index of area of each corner of the sprite
                            Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.UpperLeftCorner));
                            AreaManager.GetArea (Entity.UpperLeftCorner).AddEntity(Entity);

                            Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.UpperRightCorner));
                            AreaManager.GetArea (Entity.UpperRightCorner).AddEntity (Entity);

                            Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.BottomLeftCorner));
                            AreaManager.GetArea (Entity.BottomLeftCorner).AddEntity (Entity);

                            Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.BottomRightCorner));
                            AreaManager.GetArea (Entity.BottomRightCorner).AddEntity (Entity);
                        }
                    }
                }
            }
        }

        /// 
        /// Draw all entity in the game
        /// 
        static public void Draw( SpriteBatch spriteBatch, GraphicsDevice gpdevice )
        {
            if ( WorldEntityList.Count > 0 )

                foreach ( DynamicSprite Entity in WorldEntityList )

                    if ( Entity.IsVisible )
                        Entity.Draw (spriteBatch,gpdevice);
        }
    }

AreaManager.cs
 static class AreaManager
    {
        // The number of area in horiztontal and vertical side
        static private int m_NumberOfAreaHorizontaly;
        static private int m_NumberOfAreaVerticaly;

        static private float m_EntityPositionXToAreaIndexFactor;
        static private float m_EntityPositionYToAreaIndexFactor;

        // list of the area 
        static private List AreaInGameWorld = new List ();

        /// 
        /// Get the number of area in horizontal side  
        /// 
        static public int NumberOfAreaHorizontaly
        {
            get { return m_NumberOfAreaHorizontaly ; }
        }

        /// 
        /// Get the number of area in Vertival side  
        /// 
        static public int NumberOfAreaVerticaly
        {
            get { return m_NumberOfAreaVerticaly; }
        }


        #region Methods

        /// 
        /// Install the manager by putting the area in place  
        /// 
        static public void InstallAreaManager( GraphicsDevice graphicDevice, int NewAreaInHorizotal, 
                                               int NewAreaInVertical, Rectangle NewAreaSize )
        {
            m_NumberOfAreaHorizontaly = NewAreaInHorizotal;
            m_NumberOfAreaVerticaly = NewAreaInVertical;

            // because multiplication is faster than devision☺
            m_EntityPositionXToAreaIndexFactor = ( 1 / NewAreaSize.Width );
            m_EntityPositionYToAreaIndexFactor = ( 1 / NewAreaSize.Height );

            // put in place the Area
            for(int i = 0; i < NewAreaInVertical;i++)
                for ( int j = 0; j < NewAreaInHorizotal; j++ )
                {
                    Rectangle newrect = new Rectangle (( j * NewAreaSize.Width )+2,
                                     ( i * NewAreaSize.Height )+2, NewAreaSize.Width, NewAreaSize.Height);
                   
                   AreaInGameWorld.Add (new WorldArea (graphicDevice, newrect));
                }
        }

        /// 
        /// retur the Index of area in the list by referd index i,j  
        /// 
        static public int GetAreaIndexFromXY(int NewIndexJ,int NewIndexI)
        {
            return ( ( NewIndexI * AreaManager.NumberOfAreaHorizontaly ) + NewIndexJ );
        }

        /// 
        /// return the Index Of Area refered by X and Y entity position
        /// 
        public static int GetAreaIndex( int NewEntityPositionX, int NewEntityPositionY )
        {
          return (int)(
              ( NewEntityPositionX * m_EntityPositionXToAreaIndexFactor )*
                m_NumberOfAreaVerticaly+ (NewEntityPositionY * m_EntityPositionYToAreaIndexFactor)
              );
        }


        /// 
        /// return the Index Of Area refered by X and Y entity position
        /// 
        public static int GetAreaIndex( Vector2 NewPosition )
        {
            return (int)(
                ( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) *
                  m_NumberOfAreaVerticaly + ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor )
                );
        }

        /// 
        /// return the Index Of Area refered by X and Y entity position
        /// 
        public static int GetAreaIndex( Rectangle NewPosition )
        {
            return (int)(
                ( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) * 
                  m_NumberOfAreaVerticaly + ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor )
                );
        }

        /// 
        /// retur the area refered by X and Y entity position
        /// 
        public static WorldArea GetArea( Rectangle NewPosition )
        {
            return AreaInGameWorld[(int)(
                ( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) * 
                  m_NumberOfAreaVerticaly + ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor )
                )];
        }

        /// 
        /// retur the area refered by X and Y entity position
        /// 
        public static WorldArea GetArea( Vector2 NewPosition )
        {
            return AreaInGameWorld[(int)(
                ( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) *
                  m_NumberOfAreaVerticaly + ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor )
                )];
        }
        /// 
        /// retur the area in the list by referd index i,j  
        /// 
        public static WorldArea GetArea( int NewIndexI, int NewIndexJ )
        {
            return AreaInGameWorld[( NewIndexI * m_NumberOfAreaVerticaly ) + NewIndexJ];
        }

        /// 
        /// retur All the area in a List
        /// 
        public static List GetAreaList( )
        {
            return AreaInGameWorld;
        }

        /// 
        /// Update All The Area 
        /// 
        static public void Update( GameTime gametime )
        {
            foreach ( WorldArea area in AreaInGameWorld )
            {
                area.Update (gametime);
            }         
        }

        /// 
        /// Draw All Area 
        /// 
        static public void Draw( SpriteBatch spriteBatch )
        {
            foreach ( WorldArea area in AreaInGameWorld )
            {
                area.Draw (spriteBatch);
            }
        }

        #endregion
    }

WorldArea.cs

class WorldArea
    {

        //The limite of the area (x,y,width,Heigth)
        private Rectangle m_AreaBound;

        //The limite of the area (x,y,width,Heigth)
        private Rectangle m_ShowedArea;

        // This will be used when we draw the Area
        private Texture2D m_SurfaceToDraw;

        //The color of showen area
        private Color m_ColorOfTheArea = Color.Blue;

        // All entity in the area
        private List EntityIntheArea = new List ();

        #region Get/Set

        /// 
        /// The Area size and position
        /// 
        public Rectangle Area
        {
            get
            {
                return m_AreaBound;
            }
        }

        /// 
        /// the surface represeting the area when it will be drawen 
        /// 
        public Texture2D Surface
        {
            get
            {
                return m_SurfaceToDraw;
            }
        }

        /// 
        /// The color of the Area Surface
        /// 
        public Color AreaColor
        {
            get
            {
                return m_ColorOfTheArea;
            }
            set
            {
                m_ColorOfTheArea = value;
            }
        }

        #endregion

        #region Constructor

        /// 
        /// Creat new WorldArea
        /// 
        public WorldArea( GraphicsDevice NewGraphicDevice, int NewX, int NewY, int NewWidth, int NewHeight )
        {
            m_AreaBound = new Rectangle (NewX, NewY, NewWidth, NewHeight);
            m_ShowedArea = new Rectangle (m_AreaBound.X + 1, m_AreaBound.Y + 1,
                                          m_AreaBound.Width - 1, m_AreaBound.Height - 1);
            m_SurfaceToDraw = new Texture2D (NewGraphicDevice, 1, 1);
            m_SurfaceToDraw.SetData (new Color[] { m_ColorOfTheArea });
        }

        /// 
        /// Creat new WorldArea
        /// 
        public WorldArea( GraphicsDevice NewGraphicDevice, Rectangle NewRect )
        {
            m_AreaBound = NewRect;
            m_ShowedArea = new Rectangle (m_AreaBound.X + 1, m_AreaBound.Y + 1, 
                                          m_AreaBound.Width - 1, m_AreaBound.Height - 1);
            m_SurfaceToDraw = new Texture2D (NewGraphicDevice, 1, 1);
            m_SurfaceToDraw.SetData (new Color[] { m_ColorOfTheArea });
        }

        #endregion

        #region Methods

        /// 
        /// Add Entity to the Area Entity list
        /// 
        public void AddEntity( DynamicSprite NewEntity )
        {
            if ( !( EntityIntheArea.Contains (NewEntity) ) )
                EntityIntheArea.Add (NewEntity);
        }

        /// 
        /// Update the Area
        /// 
        public void Update( GameTime gameTime )
        {
            if ( EntityIntheArea.Count > 0 )
            {
                for ( int i = 0; i < EntityIntheArea.Count; i++ )
                {
                    //Do not check collision betwen the same object
                    int EntityItSelfIndex = i;

                    for ( int j = 0; j < EntityIntheArea.Count; j++ )
                    {
                        if ( j != EntityItSelfIndex  )
                        {
                            if ( EntityIntheArea[j].CollisionBox.Intersects (EntityIntheArea[i].CollisionBox) )
                                CollisionManager.AddCollisionUnite (EntityIntheArea[j], EntityIntheArea[i]);
                        }

                    }

                }
            }
            // the Entity list it will update evrey frame, 
            //we should clear it after checking all entity collision possibility
            EntityIntheArea.Clear ();
        }

        /// 
        /// Draw The Area
        /// 
        public void Draw( SpriteBatch spriteBatch )
        {
            spriteBatch.Draw (m_SurfaceToDraw, m_ShowedArea, m_ColorOfTheArea);
        }

        #endregion
    }

CollisionManager.cs
 class CollisionUnite
    {
        // the tow entity to collide, we name it "Collision Unite"
        private DynamicSprite m_EntityA = null;
        private DynamicSprite m_EntityB = null;

        #region Set/Get

        /// 
        ///  The First Entity in a collision event
        /// 
        public DynamicSprite EntityA
        {
            get
            {
                return m_EntityA;
            }
            set{
                m_EntityA = value;
            }
        }

        /// 
        ///  The Second Entity in a collision event
        /// 
        public DynamicSprite EntityB
        {
            get
            {
                return m_EntityB;
            }
            set
            {
                m_EntityB = value;
            }
        }   

        #endregion

        #region Constructor

        /// 
        ///  Creat a Empty Collision unite
        /// 
        public CollisionUnite( )
        {
            m_EntityA = null;
            m_EntityB = null;
        }

        /// 
        ///  Creat a defined Collision unite
        /// 
        public CollisionUnite(DynamicSprite NewEntityA, DynamicSprite NewEntityB )
        {
            m_EntityA = NewEntityA;
            m_EntityB = NewEntityB;
        }

        #endregion

    }


static class CollisionManager
    {
        // store all Collidable Sprite
        static private Queue CollisionEventList = new Queue ();

        /// 
        ///  Add Collision unite to the Queue event
        /// 
        static public void AddCollisionUnite( CollisionUnite NewCollsionUnite )
        {
            if ( !( CollisionEventList.Contains (NewCollsionUnite ) ) && NewCollsionUnite!=null )
                CollisionEventList.Enqueue (NewCollsionUnite);
        }

        /// 
        ///  Add Collision unite to the Queue event
        /// 
        static public void AddCollisionUnite( DynamicSprite NewEntityA, DynamicSprite NewEntityB )
        {
            if ( !(CollisionEventList.Contains (new CollisionUnite (NewEntityA, NewEntityB))) )
                CollisionEventList.Enqueue ( new CollisionUnite(NewEntityA, NewEntityB) );
        }

        /// 
        ///  execut all Collision in the que
        /// 
        static public void ExecuteCollisionEvent( )
        {
            foreach(CollisionUnite collisionUnite in CollisionEventList )
            {
                collisionUnite.EntityA.OnCollide (collisionUnite.EntityB);
                collisionUnite.EntityB.OnCollide (collisionUnite.EntityA);          
            }
            CollisionEventList.Clear ();
        }

    }

يتم استدعاء المنسقين كما يلي : 
 public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D TankSprite;
        DynamicSprite Tank;
        DynamicSprite Tank2;
        DynamicSprite Tank3;


        public Game1( )
        {
            graphics = new GraphicsDeviceManager (this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize( )
        {

            // TODO: Add your initialization logic here
            TankList = new List ();
            randomValue = new Random ();

            this.IsMouseVisible = true;
            base.Initialize ();
        }

        protected override void LoadContent( )
        {

            spriteBatch = new SpriteBatch (GraphicsDevice);
            TankSprite  = Content.Load (@"Textures\MulticolorTanks");

            Tank = new DynamicSprite (GraphicsDevice, TankSprite);
            Tank.Sprite.AddAnimation ("green", 0, 0, 32, 32, 8, 0.1f);
            Tank.Sprite.AutoRotate = true;
            Tank.Position = new Vector2 (100, 100);
            Tank.Traget = Tank.Position;
            Tank.AddPathNode (200, 200);
            Tank.AddPathNode (300, 300);
            Tank.AddPathNode (400, 200);
            Tank.AddPathNode (200, 100);
            Tank.Speed = 3.0f;
            Tank.IsLoopingPath = true;
            Tank.IsCollisionBoxVisible = true;
            Tank.ResizeCollisionBox (5, 5);
////////////////////////////////////////////////////
            EntityManager.AddEntityToWorld (Tank);
////////////////////////////////////////////////////

            Tank2 = new DynamicSprite (GraphicsDevice, TankSprite);
            Tank2.Sprite.AddAnimation ("yellow", 0, 64, 32, 32, 8, 0.1f);
            Tank2.Position = new Vector2 (400, 200);
            Tank2.Traget = Tank2.Position;
            Tank2.IsCollisionBoxVisible = true;
            Tank2.ResizeCollisionBox (5, 5);
////////////////////////////////////////////////////
            EntityManager.AddEntityToWorld (Tank2);
////////////////////////////////////////////////////


            Tank3 = new DynamicSprite (GraphicsDevice, TankSprite);
            Tank3.Sprite.AddAnimation ("yellow", 0, 64, 32, 32, 8, 0.1f);
            Tank3.Position = new Vector2 (200, 200);
            Tank3.Traget = Tank3.Position;
            Tank3.IsCollisionBoxVisible = true;
            Tank3.ResizeCollisionBox (5, 5);
////////////////////////////////////////////////////
            EntityManager.AddEntityToWorld (Tank3);
////////////////////////////////////////////////////




//********************************
            AreaManager.InstallAreaManager (GraphicsDevice, 8, 5, new Rectangle (0, 0, 100, 100));
//********************************  
        }

        protected override void Update( GameTime gameTime )
        {
////////////////////////////////////////////////////
            EntityManager.Update (gameTime);
            AreaManager.Update (gameTime);
            CollisionManager.ExecuteCollisionEvent();
////////////////////////////////////////////////////

            base.Update (gameTime);
        }

        protected override void Draw( GameTime gameTime )
        {
            GraphicsDevice.Clear (Color.CornflowerBlue);

            spriteBatch.Begin ();
            EntityManager.Draw (spriteBatch,GraphicsDevice);
            spriteBatch.End ();

            base.Draw (gameTime);

        }
    }

الأن وصلنا الى المشكل الذي أواجهه، كل هذا الكود يعمل بشكل جيد لكنه يعمل بشكل جيد لاخر كائن تم اضافته، اي يتحقق فقط للكائن الاخير، و لا يتحقق لباقي الكائنات الاخرى...ما السبب ؟
شكرا جزيلا على القراءة، و اتمنى ايجاد الحل.الملف المرفق يمثل الكود المستعمل و التطبيق الذي يظهر الخلل.
سلام

محترف  انس مشاركة 2

ملاحظة : محرر النصوص  لا يعمل بشكل صحيح مع غوغل كروم، اظطررت الى استعمال فاير فوكس لتنسيق النص، بكروم لم تحترم المسافاة و السطور كما انني لم اتمكن من اضافة مرفقات به.

مبتدئ  Ali Amin مشاركة 3

حسنا المشكلة حملت الكود و بعد التفحيص وجدت الآتي



المشكلة ليس في التحقق من التصادم او ما يحصل عند تحقق التصادم فكل شيء يعمل بخير و لكن المشكلة في النتيجة التي كانت تظهر


فكل كلاس للدبابة فيه هذه الجملة :


gpdevice.Clear (Test);//TODO DELETE THIS LINE
   
و يقوم هذا السطر بمسح الشاشة باللون المحدد و آخر أمر سيصل الى الكمبيوتر هو الذي سيطبق



بالتالي كان يتم مسح الشاشة بهذا اللون في كل فريم , و اللون الموجود في آخر دبابة هو الذي سيطبق و اي لون موجود في دبابة أخرى او  اي عملية مسح تمت في كلاس لدبابة في السابق لن تطبق


فلهذا كان يظهر وكأن التصادم لا يتحقق الا مع آخر دبابة


قمت برفع المثال مرة أخرى مع اصلاحه و هو بوضع لون المسح خارج كل كلاسات الدابة في كلاس عام (Static)


بالتوفيق لك ان شاء الله في المسابقة☺

محترف  انس مشاركة 4

بشرك الله بالخير ووفقك اليه اخي العزيز 😄 .بصراحة لم اتوقع ابدا ان يكون سطر اعادة اللون الاصلي هو الخطاء.لقد وفرت علي وقت ثمين حتى اتمكن من المواصلة في اساسيات المشروع. بارك الله فيك.
اذا كانت لديك اي اقتراحات او تعديلات على كيفية كشف التصادم لتحسينها فانا في الاستماع لان نوع اللعبة سيتطلب كشف التصادم بين عدد كبير جدا من الكائنات (من 500 الى 1000 كائن).
شكرا جزيلا مرة اخرى على هذا الرد الرائع و السريع 😄
سلام

محترف  انس مشاركة 5

السلام عليكم.
الطريقة التي اتبعتها، تبدو غير فعالة، اذ بوجود 403 كائن يصبح عداد الاطارات يشير الى ما بين 0-10
هل من مساعدة من فضلكم ؟
------تعديل : فكرت بتحسين يمكنه اختزال الحسابات الى النصف لكن مع ذلك البطء شديد جدا مع 203 كائن(العداد 4-8 اطار)
كود تحديث المساحة : 
        /// 
        /// Update the Area
        ///  
        public void Update( GameTime gameTime )
        {
            /**
             *  in this loop we check the collision of object with other objects  
             *  we check collision only betwen object with i index and object with i+1 index
             *  exemple to demonstrate the utility :
             *       check collision betwen Object[0] and Object[1]
             *       check collision betwen Object[0] and Object[2]
             *       check collision betwen Object[0] and Object[3]
             *       
             *  we dont need to check collision betwen Object[1] and Objetc[0] any more because its already checked when we 
             *  was in Object[0] check for collision routine
             *  if we have N object, we will have : 1+2+...+n-1 calcule
             *  exemple : we Have 4 Objects : Obj[0],Obj[1],Obj[2],Obj[3]
             *  Object   | Collision with
             *  --------------------------
             *  Obj[0]   | Obj[1],Obj[2],Obj[3]
             *  Obj[1]   | Obj[2],Obj[3]
             *  Obj[2]   | Obj[3]
             *  Obj[3]   | non need for check
             *  
             *  we have : 4 Objects thant we need : 1+2+3 = 6 collision check
             *  with simple collision check we will need : (4x4)-4 = 12 collision check 
             *  
             *  we save 6collision check with this solution !
             **/
            if ( EntityIntheArea.Count > 0 )
            {

                for ( int i = 0; i < EntityIntheArea.Count; i++ )
                {
                    //Do not check collision betwen the same object
                    int EntityItSelfIndex = i;

                    for ( int j = ( EntityItSelfIndex + 1 ); j < EntityIntheArea.Count; j++ )
                    {
                            if ( EntityIntheArea[i].CollisionBox.Intersects (EntityIntheArea[j].CollisionBox) )
                                CollisionManager.AddCollisionUnite (EntityIntheArea[i], EntityIntheArea[j]);
                    }
                
                }
            }
            // the Entity list it will update evrey frame, we should clear it after checking all entity collision possibility
            EntityIntheArea.Clear ();
        }
الشرح مع الدالة لكن ساعيده هنا :

الفكرة هي ان لا نقارن بين كائنين الا مرة واحدة فقط.
اذا كان الكائن{0} قد قارن نفسه مع الكائن{1} فلا داعي لمقارنة الكائن{1} مع الكائن{0} و بهذا اذا كان لدينا  9كائنات مرقمة من 0-9 فان الكائن 8 لن يقارن نفسه مع اي من الكائنات الاخرى لانه تم المقارنة بينهما سابقا.

سينتج لنا :

 1+2+...+ن-1 = (ن*(ن-1))/2  عملية حساب .

 بينما الطريقة الاخرى :

 (عدد الكائنات * عدد الكائنات)-عدد الكائنات

مع 9 كائنات : الطريقة التي قدمتها :
 1+2+3+4+5+6+7+8 = ((9*(9-1))/2 = 27/2 = 36 عملية كشف تصادم.
اما الطريقة الثانية : (9*9)-9 = 81-9 = 72.

ارى اننا اختزلنا عدد العمليات، لكن مازال البطئ شديد، هل من مساعدة ؟

مبتدئ  Ali Amin مشاركة 6

طب يا ريت ترفع الكود الي فيه ال403 كائن او أيا كان العدد لكي اجرب معك



بحب اسألك سؤال كمان


هل جربت ان تتحقق من التصادم قبل تقسيم المناطق ؟ و هل كان الاداء افضل ؟



سؤال كمان , امكانيات جهازك ايه؟

مبتدئ  Ali Amin مشاركة 7

شوف اعتقد ان فيه مشكلة فيه شيء في خوارزميات دباباتك ,  عندما جربت ان اقوم برسم 700 صورة و ان اتحقق من التصادم و ارسمهم لم يحصل اي مشكلة و كان الfps حوالي 50 , و لكن عند مجرد وضع 300 دبابة ينهار الجهاز



تعديل : جربت حتى ان اقوم بمسح كود التصادم و وضع 500 دبابة و لكنه لم يتعدى ال50 fps لهذا ما زلت اصر ان المشكلة في خوارزميات الدبابات

مبتدئ  Ali Amin مشاركة 8

حسنا التجربة الاخيرة وصلت بي الى هذا , لو قمت بمسح جميع الاكواد ما عدا السطر 



  EntityManager.Update(gameTime);




سيكون الfps حوالي 80 fps لو قمت بمسح هذه السطور من هذه الدالة :


Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.UpperLeftCorner));
AreaManager.GetArea (Entity.UpperLeftCorner).AddEntity(Entity);

Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.UpperRightCorner));
AreaManager.GetArea (Entity.UpperRightCorner).AddEntity (Entity);

Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.BottomLeftCorner));
AreaManager.GetArea (Entity.BottomLeftCorner).AddEntity (Entity);

Entity.AddNewAreaLocationIndex (AreaManager.GetAreaIndex (Entity.BottomRightCorner));
AreaManager.GetArea (Entity.BottomRightCorner).AddEntity (Entity);




فيصبح الfps حوالي 3800 بمعنى ان كود التقسيم هو الكود الذي يأخذ الكثير من الجهد , ارجو ان تتحقق منه و بانتظارك

محترف  انس مشاركة 9

معك حق، قمت بحذف السطور المذكورة، و قمت برسم 1303 دبابة، و النتيجة عددا الاطارات يشير الى : 124





بعد التجريب لاحظت ان الخلل يكمن في الدالة:
                                
.AddEntity (Entity);
مع ان هذه الدالة بسيطة : تتحقق من عدم وجود الكائن مسبقا، و تضيفه الى المساحة

مبتدئ  فراس أسعد مشاركة 10

حاول أن تحدد سعة كبيرة عند بناء اللائحة:



private List EntityIntheArea = new List ();


تصبح


private List EntityIntheArea = new List (1300);


اللائحة في .net عبارة عن مصفوفة ديناميكية لها سعة capacity معينة. عندما يزيد عدد العناصر فيها عن السعة يتم بناء مصفوفة جديدة ذات سعة أكبر، و من ثم نقل كل العناصر من المصفوفة الجديدة إلى القديمة. هذه العملية بطيئة و قد تحدث عدة مرات عند إضافة العناصر لذا من الأفضل أن تحدد السعة بنفسك في الباني  constructor بحيث يكون أكبر من أكبر عدد من العناصر التي ستخزنها في اللائحة. قد لا تكون هذه هي المشكلة بالذات و لكن الأمر يستحق التجربة.