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

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

شكرا جزيلا 😄 لكن لم ينفع ذلك اخي فراس.😢
هل من مغيث ☺

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

طب جرب عملها في مصفوفة ثابتة و وضع قيمها بنفسك 


بس سؤال  هل جربت انك تحسب التصادم من دون تقسيم المساحات , فربما كل شيء سيعمل لديك جيدا من دون اي إضافات


+


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

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

بدون تقسيم المساحات فعدد العمليات اللازمة للكشف عن التصادم سيكون كبير و كبير جدا ، ب 1000 كائن : 1000*1000 = 1000000عملية كشف تصادمبتقسيم المساحات و التحسين الذي ذكرته من قبل سنحصل على : (1000*999)/2 = 499500 اي ما يعادل 49.95 بالمئة من الطريقة السابقة.
الغريب ان اظافة عنصر الى لائحة تعقيد الخوارزمية الخاصة به هو : (1)O.
ساحاول تحميل محركات فيزيائية مفتوحة المصدر عساني اجد حلا.
بالنسبة للمسابقة لا يشترط البرمجة على الاكس بوكس

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

هناك اشياء تزيد من السرعة و لكن لم تصل الى 1000 دبابة اول شيء الCollision Box في الdynamic sprite لو حولته من :



public Rectangle CollisionBox
{
get
{
return new Rectangle (m_Sprite.BoundingBox.X + m_CollisionBoxResizeX,
m_Sprite.BoundingBox.Y + m_CollisionBoxResizeY,
m_Sprite.BoundingBox.Width - ( m_CollisionBoxResizeX * 2 ),
m_Sprite.BoundingBox.Height - ( m_CollisionBoxResizeY * 2 )
);
}
}




الى


  public Rectangle CollisionBox;


و تعطيه قيمته في الupdate هكذا :


CollisionBox = new Rectangle(m_Sprite.BoundingBox.X + m_CollisionBoxResizeX,
m_Sprite.BoundingBox.Y + m_CollisionBoxResizeY,
m_Sprite.BoundingBox.Width - (m_CollisionBoxResizeX * 2),
m_Sprite.BoundingBox.Height - (m_CollisionBoxResizeY * 2)
);



فهذا يزيد من السرعة


و بجعل كود الاصطدام هكذا :




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 > i )
                        {
                            if ( EntityIntheArea[j].CollisionBox.Intersects (EntityIntheArea[i].CollisionBox) )
                                CollisionManager.AddCollisionUnite (EntityIntheArea[j], EntityIntheArea[i]);
                        }

                    }

                }
            }


فهذا لا يجعل اي كود يتحقق مرتين , هذا ما قدرت ان اصل اليه ^_^ و هو يحتمل 400 دبابة فقط


ربما يمكن ان يستعمل threading في موقف كهذا , الحقيقة انا لم اقع في موقف مثل هذا من قبل !! ان يكون لدي 1000 مجسم لأتحقق من الاصطدام بينهم

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

السلام عليكم.

بالنسبة للكود الذي اقترحته لتقليص الحسابات، لقد وضعته في مشاركة سابقة :


 /// 
        /// 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 ();
        }

مع ذلك مازال المشكل قائما ....بعض البرامج تصل حتى 2000 عنصر كحد اقصى، و تستعمل حسابات اعقد ...بصراحة لا افهم السبب

محترف مشرف عبد اللطيف حاجي علي مشاركة 16

هل بإمكانك تحميل الكود بشكله النهائي حتى نستطيع فحصه؟
أيضاً ماذا يحدث إذا ألغيت النداء للإجراء Update? وماذا يحدث إذا ألغيت النداء للإجراء AddCollisionUnite?

عبد اللطيف حاجي علي
مبرمج
In|Framez

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

تم ارفاق الملف مع المشاركة.


وفي 15 يناير 2011 08:35 م، أعرب عبد اللطيف حاجي علي عن رأيه بالموقف كالآتي:

أيضاً ماذا يحدث إذا ألغيت النداء للإجراء Update? وماذا يحدث إذا ألغيت النداء للإجراء AddCollisionUnite?
اجراء اي كلاس بالتحديد ؟
EntityManager : لا يتم تحديث الكائنات و تحديث مكانها في المساحات.
AreaManager : لا يتم تحديث المساحات

AddCollisionUnite  : تقوم بتسجيل حدث تصادم، اذا استغنينا عنها فلن يكون هناك ردة فعل للكائنين.

تعليق : اشتقنا اليك استاذ عبد اللطيف 😄

محترف مشرف عبد اللطيف حاجي علي مشاركة 18

عنيت ماذا يحدث من ناحية الأداء؟ أي كم عدد الدبابات التي يمكن محاكاتها؟
أيضاً كيف يصبح الأداء أذا أبقيت كشف التصادم لكن ألغيت الرد على التصادم (أي ألغيت النداء للإجراء ExecuteCollisionEvent)

عندما سألتك عن إلغاء AddCollisionUnite قصدت أن أكشف ما إذا كان تسجيل التصدام هو عنق الزجاجة في برنامجك (هذه طريقة بدائية لعمل profiling تستغني عن أجزاء برنامجك شيئاً فشيئاً لتكتشف أي الأجزاء هو المسؤول عن البطأ)

آسف على هذه الأسئلة لكنى لا أملك Visual Studio حالياً (أو Windows حتى) لذلك لا يمكنني أن أجرب
على فكرة AddCollisionUnit يفحص إذا ما كان الكائن موجوداً في القائمة قبل إضافتها لكن هذا الفحص ليس صحيحاً لأنك تفحص إذا ما كان المرجع reference موجوداً
 وليس إذا ما كان الكائن (بمعلوماته) موجوداً (أنظر object.Equals)

عبد اللطيف حاجي علي
مبرمج
In|Framez

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

اذا قمنا انا و الاخ علي بالاستنتاج ان المشكل هو في :


                            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);

                            }
و بالخصوص الدالة :


AddEntity (Entity);
عندما تحذف كل شيئ يسير على مايرام.
لقد قمنا بحذف محتوى كل الدوال، الى ان توصلنا الى ان المشكل هو هذا الاستدعاء بالتحديد

لم افهم ما تقصده من المرجع، فانا اريد ان احتفظ بكائن و استعمله في لوائح مختلف.

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

اتضح ان المشكل في الدالة GetArea


  /// 
        /// 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 the area in the list by referd index AreaHashIndex 
        ///  
        public static WorldArea GetArea( int NewArea )
        {
            return AreaInGameWorld[NewArea];
        }



 تحسن الاداء، اذا المشكل في :
          ( 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 )
        {
            //int i= (int)( ( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) * m_NumberOfAreaVerticaly 
             //+ ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor ) );
            
              return AreaInGameWorld[0];

               //(int)(
              //  1//( NewPosition.X * m_EntityPositionXToAreaIndexFactor ) * m_NumberOfAreaVerticaly 
             //    + ( NewPosition.Y * m_EntityPositionYToAreaIndexFactor )
            //)];
        }

------------------------------------------------------
        /// 
        /// retur the area in the list by referd index AreaHashIndex 
        ///  
        public static WorldArea GetArea( int NewArea )
        {
            return AreaInGameWorld[NewArea];
        }


لاحظة ان الدالتان تعملان بنفس الكيفية لكن الدالة التي تستقبل المستطيل ابطأ.
لان ندائها يطلب زاوية من زوايا الكائن.
بعد تعويض زاوية الكائن بقيمة معدومة تحسن الاداء اذن المشكلة الحقيقية في :


Entity.UpperRightCorne
Entity.UpperLeftCorner
Entity.BottomLeftCorner
Entity.BottomRightCorner
----------

        /// 
        ///  The Uper Left Coordinate
        ///  
        public Vector2 UpperLeftCorner
        {
            get
            {
                return new Vector2 (CollisionBox.X, CollisionBox.Y);
            }
        }

        /// 
        ///  The Uper Right Coordinate
        ///  
        public Vector2 UpperRightCorner
        {
            get
            {
                return new Vector2 (CollisionBox.X + CollisionBox.Width, m_Sprite.Y);
            }

        }

        /// 
        ///  The Bottom Left Coordinate
        ///  
        public Vector2 BottomLeftCorner
        {
            get
            {
                return new Vector2 (CollisionBox.X, CollisionBox.Y+CollisionBox.Height);
            }
        }

        /// 
        ///  The Bottom Right Coordinate
        ///  
        public Vector2 BottomRightCorner
        {
            get
            {
                return new Vector2 (CollisionBox.X + CollisionBox.Width, CollisionBox.Y + CollisionBox.Height);
            }

        }


ما قولكم
------------------------------
تعديل جديد ساهم في تحسين الاداء :
تم استبدال الدالة : AddEntity الخاصة بـ WorldArea من :


        public void AddEntity( DynamicSprite NewEntity )
        {
              if ( !( EntityIntheArea.Contains (NewEntity) ) )
                EntityIntheArea.Add (NewEntity);
        }

الى
        public void AddEntity( DynamicSprite NewEntity )
        {
            for ( int i = 0; i < NewEntity.GetAreaLocationIndex ().Count; i++ )
            {
                if ( NewEntity.GetAreaLocationIndex ().ElementAt (i) == m_Index )
                {
                    EntityIntheArea.Add (NewEntity);
                    break;
                }
            
            }
           
        }

فائدة هذه الدالة :
بما ان الكائن يضاف الى المساحة حسب زواياه، فلا نريد اضافة كائن اربع مرات في المساحة اذا كانت كل زواياه في المساحة، يكفي اضافته مرة واحدة.


سبب التعديل:
قد تبدو الدالة الاولى اقصر، لكن براي فانها تستهلك حسابات كبيرة جدا في حالة "عدد كائنات كبير" وليكن 50. فهنا من اجل كل كائن نود اضافته، يجب كاقصى حد 50عملية تحقق لمعرفة اذا كان الكائن في المساحة.

 اما الدالة المعدلة،يكفي التحقق من ان الكائن يملك واحد او اكثر من زاوية في هذه المساحة. بما ان المستطيل يملك 4زوايا : فاقصى حد سيكون : 4عمليات للتاكد من وجود الكائن في المساحة.

اذا كان الكائن موجود و في المرتبة 50 :
الدالة الاولى : 50عملية+عملية الاضافة
الدالة الثانية : 4عمليات كحد اقصى(اذ اذا كانت الزاوية الاولى محتواة في المساحة ، نتوقف عند هذه الزاوية و لا نقارن باقي الزوايا) + عملية اضافة.
تم توفير عدد لابئس به من الحسابات، ام انن حساباتي خاطئة ؟
------------------
تعديل :
الان انا متأكد ان المشكل في :


Entity.UpperRightCorne
Entity.UpperLeftCorner
Entity.BottomLeftCorner
Entity.BottomRightCorner
----------

        public Vector2 UpperLeftCorner
        {
            get { return new Vector2 (CollisionBox.X, CollisionBox.Y); }
        }

        public Vector2 UpperRightCorner
        {
            get { return new Vector2 (CollisionBox.X + CollisionBox.Width, m_Sprite.Y); }

        }

        public Vector2 BottomLeftCorner
        {
            get { return new Vector2 (CollisionBox.X, CollisionBox.Y+CollisionBox.Height); }
        }

        public Vector2 BottomRightCorner
        {
            get
            { 
               return new Vector2 
               (CollisionBox.X + CollisionBox.Width, CollisionBox.Y + CollisionBox.Height);
            }

        }

لانني قمت بوضع هذا الكود في دالة تحديث الكائنات، و حذفت كود التصادم و كود المساحات، تركت فقط كود تحديث الكائنات فتسبب بالبطئ الشديد عند 1000 كائن :


            m_UpperLeftCorner.X = CollisionBox.X;
            m_UpperLeftCorner.Y = CollisionBox.Y;

            m_UpperRightCorner.X = CollisionBox.X + CollisionBox.Width;
            m_UpperRightCorner.Y = CollisionBox.Y;

            m_BottomLeftCorner.X = CollisionBox.X;
            m_BottomLeftCorner.Y = CollisionBox.Y+CollisionBox.Height;

            m_BottomRightCorner.X= CollisionBox.X + CollisionBox.Width;
            m_BottomRightCorner.Y = CollisionBox.Y + CollisionBox.Height;

يعني لا اظنها معقدة الى هذا الحد...هل من تفسير من فضلكم ؟