Sunday, October 3, 2010

XNA: Lesson6: اكتشاف التصادم بين كائنات اللعبة

الدرس السادس: اكتشاف التصادم بين كائنين
Coding for collision detection between two objects


بسم الله و الصلاة و السلام علي رسول الله ... اللهم لا سهل الا ما جعلته سهلا و انت تجعل الحزن اذا شئت سهلا ...


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

في هذا الدرس ان شاء الله سوف نتعلم كيف نكتشف تصادم كائنين في اللعبة ببعضها البعض ... طيب و ما فائدة هذا ؟؟؟

استطيع ان اقول لكم ان هذا يمثل لب اللعبة نفسها يعني بها نعرف مثلا كيف تصطدم طائرة بالجبل مثلا داخل اللعبة او نعرف اذا اصاب الرمح العدو فاماته ام لا ... و نعرف بها مثلا اذا كانت الكرة دخلت المرمي ام لا تخيلوا لعبة كرة بلا اهداف J ...

هناك خوارزميات كثيرة لاكتشاف التصادم منها المعقد و منها البسيط ...

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

و منها البسيط الذي سنستخدمه هنا و هو خوارزم او اسلوب الصندوق او "Bounding Boxes" و هو مطابقة اطار الصورة الاولي باطار الصورة الثانية فاذا تداخلوا فهذا يعني تصادم مثلا الصورة التالية:


ماذا نلاحظ ؟؟؟
قسمنا الصور الي مربعان كبيران ليغطوا كل الصورة ... و بالتالي معنا الان طائرتان نريد ان نكتشف التصادم الخاص بهم ... بمنتهي البساطة اذا تلاقت حدود الطائرة الاولي مع حدود الطائرة الثانية فهذا يعني تصادم ...






-          الان دعونا نطبق مثال علي التصادم:
o       اولا سنقوم بتحميل الصورة التالية و التي ستكون صورة الكائن الذي سنحركه من الرابط التالي:
o       http://lh3.ggpht.com/_60yQUD53BPE/TKfftPYXVgI/AAAAAAAAA0k/KZoc6ed01BE/ball.pngافتح تطبيق الدرس الخامس (الأخير).
o       اضف الصورة التي قمت بتحميلها الي الفولدر Content كما تعلمنا مسبقا ...
o       افتح الكلاس clsSprite.
o       و سنضيف دالة اكتشاف التصادم بين كائنين و هي ستكون كالتالي:


        public bool Collide(clsSprite otherSprite)
        {
            Rectangle thisRec = new Rectangle((int)this.position.X, (int)this.position.Y,
                this.texture.Width, this.texture.Height);

            Rectangle otherSpriteRec = new Rectangle((int)otherSprite.position.X, (int)otherSprite.position.Y,
                otherSprite.texture.Width, otherSprite.texture.Height);

            if (otherSpriteRec.Intersects(thisRec))
            {
                return true;
            }

            return false;
        }



الدالة اسمها Collide يعني تصادم  و ترجع بنعم او لا يعني اذا حدث تصادم ترجع ب true و اذا لم يحدث تصادم ترجع ب false ...

الدالة تستقبل parameter من نوع clsSprite و هو الكائن الاخر الذي سنفحص تصادمه مع هذا الكائن ...

كما ذكرنا مسبقا نحن سنستخدم الجوريزم اكتشاف التصادم بين الكائنين باستخدام اسلوب الصندوق المحيط بالصورة و بالتالي يجب ان نحدد الصندوق او المربع حول كل صورة كالتالي:

Rectangle thisRec = new Rectangle((int)this.position.X, (int)this.position.Y,
                this.texture.Width, this.texture.Height);
قمنا بتعريف مربع يحتوي علي ابعاد الصورة الاولي ...

Rectangle otherSpriteRec = new Rectangle((int)otherSprite.position.X, (int)otherSprite.position.Y,
                otherSprite.texture.Width, otherSprite.texture.Height);
قمنا بتعريف مربع يحتوي علي ابعاد الصورة الثانية...

if (otherSpriteRec.Intersects(thisRec))
{
            return true;
}

return false;
قمنا باستخدام دالة Intersects و الموجودة ضمن العنصر Rectangle و هي تقوم باكتشاف اذا كان هناك تداخل بين مربعين و قمنا باعطاء الدالة مربع الصورة الاخري لكي تطابق بينه و بين مربع الصورة الاولي .... فاذا كانت ابعادهم متداخلة ستعطي true و اذا كانت ابعادهم غير متداخلة ستعطي false...

و بهذا انتهت دالة اكتشاف التصادم و هذه الدالة باسلوب تطابق المربعات او ال Bounding Boxes .... و هذا الاسلوب ليس دقيق مائة في المائة لان هناك ابعاد دائرية مثل حالة الكرة هنا لكنها حتي الان تفي بالغرض و سنتعلم طرق اكثر تعقيدا فيما بعد ...




  • دعونا الان ننتقل الي الملف Game1.CS:
    • نعرف كائنين clsSprite كما بالاتي:
clsSprite sprite1;
clsSprite sprite2;


    • نعدل ابعاد الشاشة في ال Constructor Game1 كالاتي:
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferWidth = 900;
            graphics.PreferredBackBufferHeight = 600;
        }


    • ثم نذهب الي حدث ال LoadContent و نحمل الكائنات:
            sprite1 = new clsSprite(Content.Load<Texture2D>("ball"),
                    Vector2.Zero,
                    graphics.PreferredBackBufferWidth,
                    graphics.PreferredBackBufferHeight);

            sprite1.velocity = new Vector2(2, 2);

            sprite2 = new clsSprite(Content.Load<Texture2D>("ball"),
                new Vector2(300, 300),
                graphics.PreferredBackBufferWidth,
                graphics.PreferredBackBufferHeight);

            sprite2.velocity = new Vector2(3, 3);

و ذلك كما تعلمنا مسبقا طبعا .... قمنا بتعريف كائنين في موضعين مختلفين ... و بسرعات مختلفة ...



ثم نذهب الان الي الحدث Update و نعدله ليصبح كالاتي:
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            sprite1.Move();
            sprite2.Move();

            if (sprite1.Collide(sprite2))
            {
                Vector2 tempVelocity = sprite1.velocity;
                sprite1.velocity = sprite2.velocity;
                sprite2.velocity = tempVelocity;
            }

            base.Update(gameTime);
        }


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





  • تطبيق الدرس:
قم بانشاء كائن ثالث في اللعبة و اكتب كود التصادم بحيث لا يصطدم الثلاث كائنات ببعضهم البعض ...
رابط حل التطبيق:
http://www.mediafire.com/?l8hg68gl4dpnzzq

  • ملاحظة:
نلاحظ ان الصورة التي نستخدمها هي صورة كرة و لكن اكتشاف التصادم لا يتم بالدقة الكافية بحيث يتعامل مع الصورة علي انها مربع و بالتالي في بعض الاحيان يكتشف التصادم في اماكن تكون بعيدة عن الكرة و لهذا حل ان شاء الله و هو اكتشاف التصادم بين الكائنات المدورة مثل الكرة مثلا و ان شاء الله في الدرس القادم سنتعلم كيف نطبقه ...............


Friday, October 1, 2010

XNA: Lesson5: Collision detection 1

الدرس الخامس: Collision Detection
اساسيات اكتشاف التصادمات


بسم الله و الصلاة و السلام علي رسول الله ...

  • درسنا اليوم هو اكتشاف التصادمات ... طيب ما معني التصادمات؟
التصادم هو شئ فيزيائي يحدث عندما يصطدم كائن في اللعبة بكائن اخر ... هنا نريد ان نحدد كيف سيصطدم الكائنان ببعض و كيف نكتشف بالكود هذا التصادم ...

بداية سنقوم باكتشاف التصادم مع اطار اللعبة نلاحظ في الدرس السابق ان عناصر اللعبة تمشي بسرعة معينة و لكنها تبقي تتحرك الي خارج اطار اللعبة لذلك مهمتنا الان هي اكتشاف التصادم مع اطار اللعبة و اذا اصطدم الكائن باطار اللعبة فنعيده مرة اخري الي داخل اطار اللعبة ... دعونا نبدا:

  • نفتح الملف clsSprite.CS:
اولا لكي نعرف احداثيات الشاشة يجب ان خاصية جديدة ستحمل طول و عرض شاشة اللعبة:
public Vector2 screenSize { get; set; }

ثم نعدل ال Constructor كالاتي:
        public clsSprite(Texture2D newTexture, Vector2 newPosition, int screenWidth, int screenHeight)
        {
            texture = newTexture;
            position = newPosition;
            screenSize = new Vector2(screenWidth, screenHeight);
        }

و هنا قمنا بملء ال screenSize بطول الشاشة و عرض الشاشة...

ثم نتجه الان الي الدالة Move() لكي نكتب الكود الذي سيكتشف التصادم:

        public void Move()
        {
            // سنفخص اذا كان الكائن يتحرك لليمين
            if (position.X + texture.Width + velocity.X > screenSize.X)
            {
                velocity = new Vector2(-velocity.X, velocity.Y);
            }
            // سنفخص اذا كان الكائن يتحرك للأسفل
            if (position.Y + texture.Height + velocity.Y > screenSize.Y)
            {
                velocity = new Vector2(velocity.X, -velocity.Y);
            }
            // سنفخص اذا كان الكائن يتحرك لليسار
            if (position.X + velocity.X < 0)
            {
                velocity = new Vector2(-velocity.X, velocity.Y);
            }
            // سنفخص اذا كان الكائن يتحرك للأعلي
            if (position.Y + velocity.Y < 0)
            {
                velocity = new Vector2(velocity.X, -velocity.Y);
            }

            //نعطي السرعة الجديدة للكائن
            position += velocity;
        }



شرح الكود:
            // سنفخص اذا كان الكائن يتحرك لليمين
            if (position.X + texture.Width + velocity.X > screenSize.X)
            {
                velocity = new Vector2(-velocity.X, velocity.Y);
            }

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


            // سنفخص اذا كان الكائن يتحرك للأسفل
            if (position.Y + texture.Height + velocity.Y > screenSize.Y)
            {
                velocity = new Vector2(velocity.X, -velocity.Y);
            }

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



            // سنفخص اذا كان الكائن يتحرك لليسار
            if (position.X + velocity.X < 0)
            {
                velocity = new Vector2(-velocity.X, velocity.Y);
            }

هنا سنفحص اذا كان الكائن يتجه لليسار  ... يتجه لليسار يعني تناقص  ال x  و بالتالي اذا وصل لاقصي نقطة في يسار الشاشة  ستكون الاحداثيات الخاصة به هي نقطة 0  Zero   زائد سرعته و بالتالي اذا كان الناتج اقل من الصفر فنقوم بعكس قيمة ال x للسرعة التي يتحرك بها حتي يتجه لليمين مرة ثانية ...


            // سنفخص اذا كان الكائن يتحرك للأعلي
            if (position.Y + velocity.Y < 0)
            {
                velocity = new Vector2(velocity.X, -velocity.Y);
            }
هنا سنفحص اذا كان الكائن يتجه للأعلي... يتجه للأعلي يعني تناقص  ال y   و بالتالي اذا وصل لاقصي نقطة في اعلي  الشاشة  ستكون الاحداثيات الخاصة به هي نقطة 0  Zero   زائد سرعته و بالتالي اذا كان الناتج اقل من الصفر فنقوم بعكس قيمة ال y  للسرعة التي يتحرك بها حتي يتجه للأسفل مرة ثانية ...


            //نعطي السرعة الجديدة للكائن بعد ان حسبناها
            position += velocity;
        }


تطبيق: اكمل علي التطبيق السابق و جرب هذا الكود بنفسك و اجعله يعمل .... و شاهد بنفسك ما يحدث ...


Wednesday, September 29, 2010

XNA: Lesson4: 2D Graphics 2

الدرس الرابع
2D Graphics 2

بسم الله و الصلاة و السلام علي رسول الله صلي الله عليه و سلم ...

نكمل في هذا الدرس باذن الله مفاهيم و اساسيات التعامل مع كائنات ال 2D...

  • تغيير مقاس الشاشة: Changing Windows Size:
لتغيير ابعاد الشاشة الي 500 * 300 مثلا نكتب الكود التالي في ملف Game1.CS في ال Constructor:
public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 500;
            graphics.PreferredBackBufferHeight = 300;

            Content.RootDirectory = "Content";
        }


  • تطبيق:
    • غير ابعاد الشاشة لاي مقاس جديد تريده ...


  • Moving the sprite on the screen:
  • تحريك العنصر علي الشاشة:
اتفقنا ان في نظام الاحداثيات يوجد x و يوجد y ....
طبعا نستخدم x لتحريك العنصر بشكل افقي ... و نستخدم ال y  للتحريك بشكل عمودي ...
و اتفقنا ايضا ان ال x تبدا من الشمال يعني اول نقطة علي الشاشة في الشمال تساوي صفر ... و بالتالي اذا اردنا تحريك العنصر لليمين ماذا سنفعل ؟؟؟ سنزيد ال x بالقيمة التي نريد التحريك بها ... و كذلك في ال y نقطة الصفر تبدا من اول نقطة علي الشاشة بالاعلي و بالتالي اذا اردنا تحريك العنصر لتحت سنزيد ال y .

نفترض اننا نريد تحريك العنصر لليمين مثلا سنكتب الكود التالي:
mySprite1.position.X += 1;
ماذا فعنا هنا؟ قمنا بزيادة ال x بمقدار 1 ... و بالتالي سيتحرك العنصر لليمين بمقدار 1 في التكرار الواحد ...

  • دعونا نطبق ... افتحوا المشروع الخاص بالدرس الثالث ...
نفتح الكلاس clsSprite.CS و نعرف خاصية جديدة به:
public Vector2 velocity { get; set; }
ما هي ال velocity : هي تمثل سرعة الكائن علي الشاشة ... و عرفناها ب vector2 حيث ال x هي قيمة السرعة للتحريك الافقي و ال y هي قيمة السرعة للتحريك الراسي ...



  • ثم نبدا وظيفة جديدة في الكلاس و هي Move اي تحرك و التي ننفذها في كل تكرار في اللعبة بحيث يتحرك الكائن بالسرعة التي حددناها و هذه ال Method ستكون كالتالي:
        public void Move()
        {
            position += velocity;
  }

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

  • الان نفتح ملف ال Game1.CS:
ثم نذهب الي الحدث LoadContent و نعدل الكود ليصبح كالتالي:
        protected override void LoadContent()
        {
// Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here

            spriteBall = new clsSprite(Content.Load<Texture2D>("ball"),
                Vector2.Zero);

            spriteBall.velocity = new Vector2(1, 1);
        }

كما ترون يوجد سطر اضافي بعد تعريف object   من كلاس ال clsSprite و هو:
            spriteBall.velocity = new Vector2(1, 1);
و هنا تم تعريف السرعة بمقدار 1,1 يعني في كل تكرار في اللعبة ستزيد قيمة ال x بمقدار 1 و ستزيد قيمة ال y بقيمة 1.



ثم نذهب الي حدث ال Update() و نعدل الكود ليصبح كالتالي:
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            spriteBall.Move();

            base.Update(gameTime);
        }
نلاحظ السطر التالي:
spriteBall.Move();
و لا ننسي ان حدث ال update يتم تنفيذه في كل تكرار في اللعبة ... و بالتالي ننفذ كود التحرك Move فيه ليتحرك الكائن ...


  • خلاصة الدرس:
تم التدريب علي تحريك كائنات ال 2D في اللعبة ... و في الدرس القادم سنتعلم كيف نتحكم في الحركة بحيث لا يخرج الكائن خارج حدود اللعبة ...

التطبيق:
قم بانشاء 3 كائنات من نوع clsSprite و قم بتحريكهم في اتجاهات مختلفة ...
التطبيق بالانجليزي لمن يفهم اكثر بها:
Create 3 objects of the clsSprite class, and move them towards different ways …

و صلي الله و سلم علي سيدنا محمد و السلام عليكم ...