Monday, October 4, 2010

XNA Lesson 7: Circle Collision Detection and Game Input

Lesson 7: Circle Collision Detection and Game Input
الدرس السابع: اكتشاف التصادم الدائري و التعامل مع لوحة المفاتيح و الماوس للتحكم باللعبة


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

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

و بالتالي نتجه الي الملف clsSprite و نعرف الخصائص التالية ضمن ال properties:

public Vector2 size { get; set; }
public Vector2 center { get { return position + (size / 2); } }
public float radius { get { return size.X / 2; } }

public Vector2 size { get; set; }
يمثل مقاس الصورة ... طولها و عرضها ...

public Vector2 center { get { return position + (size / 2); } }
يمثل منتصف الصورة بالضبط و يحسب بمكان الصورة و طبعا هذا يكون في اقصي شمال اعلي الصورة ثم يضيف اليه المقاس مقسوم علي 2 مثلا
مكان الصورة = 0,0 ........ و مقاس الصورة = 40,40 ....... اذن منتصف الصورة يساوي ...
Center = (0, 0) + ((40, 40) /2) = (0, 0) + (20, 20) = (20, 20)

اذن بالفعل منتصف الصورة هو x=20 و y=20 .....



public float radius { get { return size.X / 2; } }
يمثل نصف قطر الصورة الدائرية و يحسب طبعا بعرض الصورة مقسوم علي 2 ... يعني لو عندنا صورة قطرها 40 بكسل اذن نصف قطرها هو 20 بكسل ...

ثم نذهب الي ال Consrtuctor و نعدله ليصبح كالاتي:
   public clsSprite(Texture2D newTexture, Vector2 newPosition, int screenWidth, int screenHeight)
        {
            texture = newTexture;
            position = newPosition;
            screenSize = new Vector2(screenWidth, screenHeight);
            size = new Vector2(texture.Width, texture.Height);
        }

و هنا قمنا بملء خاصية ال size بطول و عرض الصورة ليصبح التعامل معهم اسهل من خلال ال size....

و الان ننشا دالة جديدة تحت دالة ال collide بالضبط كالاتي:
public bool circleCollides(clsSprite otherSprite)
{
return (Vector2.Distance(this.center, otherSprite.center) <
                this.radius + otherSprite.radius);
}

و هنا قمنا بمقارنة المسافة بين نقطتين باستخدام Vector2.Distance و هي تحسب المسافة بين نقطتين ... فحسبنا المسافة بين منتصف هذه الصورة و منتصف الصورة الاخري بحيث اذا كانت المسافة بينهما اصغر من نصف قطر الصورة الاولي + نصف قطر الصورة التالية اذن يحدث التصادم ....

مش فاهمين ... طيب صلوا علي النبي (اللهم صلي علي سيدنا محمد و علي اله و صحبه و سلم) ....

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




اظن الصورة شرحت كل شئ ....

الان نذهب الي الملف Game1.cs و نعدل الحدث update بحيث نستخدم الدالة circleCollides بدلا من الدالة Collide ... و نشغل اللعبة بحيث تحتوي علي كائنين فقط و نلاحظ اكتشاف التصادم ....




الان دعونا ننتقل لموضوع درس اليوم و هو التعامل مع لوحة المفاتيح و الماوس او ما يسمي مدخلات اللعبة ...

مدخلات اللعبة قد تكون Game Pad او ذراع الالعاب ... او لوحة المفاتيح ... او الماوس ... و في مشروع ناتال الذي قامت به ميكروسوفت الان يمكنك اللعب بذاتك يعني تقف امام الشاشة و تلعب بجسمك و جهاز ال xbox يلقط حركاتك و ينفذها باللعبة ......

و الان تعالوا نحرك الكرات علي الشاشة بواسطة الاسهم بدلا من الحركة التلقائية لها ....

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

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

            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

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

            base.Update(gameTime);
        }

ما الذي قمنا بفعله هنا:
طبعا اللعبة في البداية تفحص ذراع الالعاب اذا كان اللاعب يضغط علي زر Back فانها تغلق اللعبة و بما اننا لسنا نلعب بذارع العاب فاننا نستخدم لوحة المفاتيح لنفحص اذا كان اللاعب يضغط علي زر Escape و دعونا نفصل قليلا هنا ...
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

Keyboard هنا هي تمثل نسخة من لوحة المفاتيح الان ...
GetState() هي دالة ترجع بحالة كل مفتاح من لوحة المفاتيح ...
IsKeyDown تفحص اذا كان زر معين مضغوط عليه ...
Keys.Escape ........ keys هي اسماء المفاتيح جميعا و طبعا هنا نحن نفحص زر escape....


نشغل اللعبة و نضغط علي زر Escape لنغلق اللعبة ....

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

            KeyboardState keyState = Keyboard.GetState();

            if (keyState.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            // TODO: Add your update logic here
            if (keyState.IsKeyDown(Keys.Up))
            {
                ball1.position += new Vector2(0, -5);
            }
            if (keyState.IsKeyDown(Keys.Down))
            {
                ball1.position += new Vector2(0, 5);
            }
            if (keyState.IsKeyDown(Keys.Left))
            {
                ball1.position += new Vector2(-5, 0);
            }
            if (keyState.IsKeyDown(Keys.Right))
            {
                ball1.position += new Vector2(5, 0);
            }

            base.Update(gameTime);
        }

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

دعونا نشغل اللعبة الان ... نري الكائن ثابت لا يتحرك ... نبدا نحركه بالاسهم و نري .............




الان قمنا بتحريك العنصر بواسطة لوحة المفاتيح ...

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

            KeyboardState keyState = Keyboard.GetState();

            if (keyState.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            // move the object with keyboard
            if (keyState.IsKeyDown(Keys.Up))
            {
                ball1.position += new Vector2(0, -5);
            }
            if (keyState.IsKeyDown(Keys.Down))
            {
                ball1.position += new Vector2(0, 5);
            }
            if (keyState.IsKeyDown(Keys.Left))
            {
                ball1.position += new Vector2(-5, 0);
            }
            if (keyState.IsKeyDown(Keys.Right))
            {
                ball1.position += new Vector2(5, 0);
            }


            // move the object with mouse
            if (Mouse.GetState().LeftButton == ButtonState.Pressed)
            {
                ball1.position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
            }

            base.Update(gameTime);
        }


ما الذي فعلناه في هذا الكود:
            if (Mouse.GetState().LeftButton == ButtonState.Pressed)
            {
                ball1.position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
            }

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


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

تطبيق الدرس:
زود سرعة الكرة عند التحرك بالاسهم ..................



No comments:

Post a Comment