الحركة والأصوات في ++C

الحركة والأصوات

c   

البرنامج التالي يستخدم المنهج المتبع في البرنامج السابقة لعمل نموذج لماكينة للعبء , تعمل بقذف قطع النقود بها فتظهر ثلاثة أشكال بصورة عشوائية ويكون المرء فائزا عندما يتصادف تماثل الصور الثلاث ] تسمي هذه الماكينة slot machine [ والأشكال الثلاثة تختار عشوائيا من بين أربعة أشكال دائرتين ومربع ذو خط وتري ومثلث , وكل شكل لونه الخاص .

وينشئ البرنامج فئات مشتقة من الفئة الأساسية shape لإنشاء الدائرة والمستطيل والمثلث لإنشاء شكل ما ولكن لإعطاء إمكانية مسح أي شكل من الأشكال برسم مربع فوقه يخفيه وتشتق فئات من كل من الفئة الخاصة بالشكل وفئة noshape حتي يحتوي كل كائن ينشأ علي إمكانية فنائه .

ثم يشتق فئتين من فئة الدائرة لإنشاء الدائرتين وهما الفئة cherry والفئة grape ويشتق فئة من فئة المستطيل تسمي squere لإنشاء المربع وفئة من فئة المثلث pyramide لإنشاء المثلث .

ثم ينشئ البرنامج فئة أساسية wheel تتولي إنشاء الكائنات التي تختار الأشكال عشوائيا لرسمهما ويستخدم في البرنامج إمكانية التأثير الصوتي لإعطاء شعور بالتشغيل الواقعي للماكينة وإليك صياغة البرنامج :

slot.cpp


 


// slot.cpp


// models a slot machine


// UCS Laboratories


 


#include <graphics.h>         // for graphics functions


#include <stdlib.h>           // for rand(), randomize()


#include <time.h>             // for randomize()


#include <conio.h>            // for getche()


#include <dos.h>              // for delay(), sound(), nosound()


 


const int W = 15;             // 1/2 width of images


const int MAR = 10;           // margin around images


 


class shape                   // base class


   {


   protected:


      int xCo, yCo;           // coordinates of center


      int linecolor;          // color of outline


      int fillcolor;          // color of interior


   public:


      shape()                 // no-arg constructor


     { xCo=0; yCo=0; linecolor=WHITE; fillcolor=WHITE; }


      void set(int x, int y, int lc, int fc)  


     { xCo=x; yCo=y; linecolor=lc; fillcolor=fc; }


      void draw()


     {


     setcolor(linecolor);                  // set line color


     setfillstyle(SOLID_FILL, fillcolor);  // set fill color


     }


   };


 


class ball : public shape


   {


   public:


      ball() : shape()        // no-arg constructor


     { }                  


      void set(int x, int y, int lc, int fc)    // set data


     { shape::set(x, y, lc, fc); }


      void draw()             // draw the ball


     {


     shape::draw();                         // set colors


     circle(xCo, yCo, W);                   // draw circle


     floodfill(xCo, yCo, linecolor);        // fill circle


     }


   };


 


class rect : public shape


   {


   public:


      rect() : shape()        // no-arg constructor


     { }


      void set(int x, int y, int lc, int fc)    // set data


     { shape::set(x, y, lc, fc); }


      void draw()             // draw the rectangle


     {


     shape::draw();                         // set colors


     rectangle(xCo-W, yCo-W, xCo+W, yCo+W); // draw rectangle


     floodfill(xCo, yCo, linecolor);        // fill rectangle


         line(xCo-W, yCo+W, xCo+W, yCo-W);      // draw diagonal


     }


   };


 


class tria : public shape


   {


   public:


      tria() : shape()        // no-arg constructor


     { }


      void set(int x, int y, int lc, int fc)    // set data


     { shape::set(x, y, lc, fc); }


      void draw();            // draw the triangle


   };


 


void tria::draw()             // draw the triangle


   {


   int triarray[] = { xCo,   yCo-W,      // top


              xCo+W, yCo+W,      // bottom right


              xCo-W, yCo+W };    // bottom left


   shape::draw();                        // set colors


   fillpoly(3, triarray);                // draw triangle


   }


 


class noshape : public shape


   {


   public:


      void erase();           // erase old shape


   };


 


void noshape::erase()         // erase old shape


   {


   int border[] =                        // rectangle to erase


     { xCo-W-MAR, yCo-W-MAR,         // upper-left


       xCo+W+MAR, yCo-W-MAR,         // upper-right


       xCo+W+MAR, yCo+W+MAR,         // bottom-right


       xCo-W-MAR, yCo+W+MAR };       // bottom-left


   setfillstyle(SOLID_FILL, DARKGRAY);   // background color


   fillpoly(4, border);                  // fill it


   }


 


class Cherry : public ball, public noshape


   {


   public:


      Cherry() : ball()                  // no-arg constructor


     { }


      void set(int x, int y)             // set data


     {


     ball::set(x, y, WHITE, RED);


     noshape::set(x, y, WHITE, RED);


     }


      void draw()                        // draw a cherry


     { erase(); ball::draw(); }      


   };


 


class Grape : public ball, public noshape


   {


   public:


      Grape() : ball()                   // no-arg constructor


     { }


      void set(int x, int y)             // set data


     {


     ball::set(x, y, WHITE, BLUE);


     noshape::set(x, y, WHITE, BLUE);


     }


      void draw()                        // draw a grape


     { erase(); ball::draw(); }      


   };


 


class Square : public rect, public noshape


   {


   public:


      Square() : rect()                  // no-arg constructor


     { }


      void set(int x, int y)             // set data


     {


     rect::set(x, y, WHITE, CYAN);


     noshape::set(x, y, WHITE, CYAN);


     }


      void draw()                        // draw a square


     { erase(); rect::draw(); }      


   };


 


class Pyramid : public tria, public noshape


   {


   public:


      Pyramid() : tria()                 // no-arg constructor


     { }


      void set(int x, int y)             // set data


     {


     tria::set(x, y, WHITE, GREEN);


     noshape::set(x, y, WHITE, GREEN);


     }


      void draw()                        // draw a pyramid


     { erase(); tria::draw(); }


   };


 


class Wheel        // contains four pips


   {


   private:


      Cherry ch;   // make one pip of each kind


      Grape gr;


      Square sq;


      Pyramid py;


      int xCo, yCo;             // wheel position   


   public:


      Wheel()                   // no-arg constructor


     { xCo=0; yCo=0; }


      void set(int x, int y)


     {


     xCo=x; yCo=y;          // set our position


     ch.set(xCo, yCo);      // set four pips to


     gr.set(xCo, yCo);      //    our position


     sq.set(xCo, yCo);


     py.set(xCo, yCo);


     }


      void draw();              // draw a random pip


   };


 


void Wheel::draw()              // draw a random pip


   {


   switch( random(4) )          // random number from 0 to 3


      {


      case 0 : ch.draw(); break;  // draw one of the pips


      case 1 : gr.draw(); break;  // selected randomly


      case 2 : sq.draw(); break;


      case 3 : py.draw(); break;


      }


   }


 


void main()


// UCS Laboratories


   {


   const int NUMBER = 60;      // number of times to cycle


   int driver, mode;


   driver = DETECT;            // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


   randomize();                // seed random number generator


 


   Wheel w1;                   // make three wheels


   Wheel w2;               


   Wheel w3;


 


   w1.set(100, 100);           // position in horizontal row


   w2.set(160, 100);


   w3.set(220, 100);


      


   for(int j=0; j<NUMBER; j++)  // spin the wheels


      {


      w1.draw();                // draw each wheel


      w2.draw();


      w3.draw();


      sound(100); delay(20); nosound();  // click


      delay( j*j/20 );          // delay gets longer and longer


      }


   sound(400); delay(400);      // two tones to signal done


   sound(500); delay(800); nosound();


   getche();                    // wait for keypress


   closegraph();                // close graphics system


   }




عمل البرنامج ينشئ البرنامج ثلاثة كائنات منتمية للفئة wheel , ينشئ كل كائن شكلا في موضع محدد بحسب عدد يتضمنه عشوائيا من 0 إلي 4 وتنشأ الأشكال خلال دوارة تتضمن الدالة المكتبية sound() المسئولة عن إصدار التأثير الصوتي .



إصدار الأصوات



يتطلب إصدار الأصوات في برامج السي ++ ثلاثة خطوات : 1 ) تشغيل الصوت , 2) تحديد المدة , 3) إغلاق الصوت . والدوال الثلاث المسئولة عن هذه الخطوات تتطلب ملف dos.h .



الدالة sound()



تقوم هذه الدالة بتشغيل مولد الصوت بالجهاز , ولها معامل واحد هو تردد الصوت بالهرتز ويتراوح الرقم المدخل من 15 إلي 3000 وتزيد حدة الصوت زيادة الرقم .



الدالة delay()



تتحكم هذه الدالة في مدة تشغيل مولد الصوت , ولها معامل واحد هو مدة التشغيل بالملي ثانية فالرقم 500 يشغل الصوت لنصف ثانية . الرقم 20 المخل من الصفر بحيث يعطي صوت تكة واحدة .



الدالة nosound()



تقوم هذه الدالة بإغلاق مولد الصوت وليس لهذه الدالة معاملات



نظرة تأملية



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



ويمثل هذا الأسلوب في البرمجة بالتالي أداة قوية في تمثيل الواقع كما نبين في المثال التالي :



تمثيل الحركة



كمثال بسيط لتمثيل الحركة نقدم مثلا يصور حركة الجزيئات داخل إناء , يمكن استخدامه في برامج أكثر تعقيدا للبرامج التي تتعامل مع الفيزياء أو الكيمياء ( من لديه رهبة من المواد العلمية يمكن اعتباره تمثيلا لحركة كرات البلياردو) . تتضمن الكائنات المنشأة للفئة molecule بيان الموضع (عن طريق الإحداثيات مقاسة بالبكسلات ) وسرعة الحركة (مقاسة ببكسلة لكل دورة من الجهاز ) وسوف نقصر البرنامج علي ثمانية جزيئات فقط .



تحدد الحركة بالاتجاه الرأسي , وله قيمتان up, down والاتجاه الأفقي وله قيمتان righ, left وتقوم الدوال المنتمية للبرنامج بمسح الأشكال المرسومة وتحسب موضعا للشكل التالي , ثم ترسمه بهذه الوسيلة يحدث تأثير الحركة , وإليك صياغة البرنامج .






molecule.cpp


 


// molecule.cpp


// moving balls reflect on edges of screen


// UCS Laboratories


 


#include <graphics.h>         // for graphics functions


#include <conio.h>            // for getch()


 


const int RAD = 5;            // radius of molecules


const int MAX = 6;            // maximum speed of molecules


const int DIST = (RAD+MAX);   // reflection distance


 


const int LEFT   =   0;       // screen coordinates


const int TOP    =   0;


const int RIGHT  = 639;       // standard VGA screen


const int BOTTOM = 479;


 


enum hdir {hSTOP=0, hRIGHT, hLEFT}; // horizontal direction


enum vdir {vSTOP=0, vDOWN, vUP};    // vertical direction


 


class molecule                // molecule class


   {


   private:


        int xCo, yCo;     // coordinates of center


        int oldx, oldy;   // previous coordinates


        int speed;        // speed: pixels per unit time


        hdir horz;        // horiz direction: stop, right, left


        vdir vert;        // vert direction: stop, down, up


        COLORS color;     // color


    public:


                                // constructor


        molecule(int x, int y, int s, hdir h, vdir v, COLORS c)


            { xCo=x; yCo=y; speed=s; horz=h; vert=v; color=c; }


        void erase();     // erase old position


        void calculate(); // calculate new position


        void draw();      // draw new position


   };


 


void molecule::erase()  // erase molecule in old position


   {


    setcolor(DARKGRAY);               // draw gray circle


    circle(oldx, oldy, RAD);


    setfillstyle(SOLID_FILL, BLACK);  // fill with black


    floodfill(oldx, oldy, DARKGRAY);


    setcolor(BLACK);                  // erase gray circle


    circle(oldx, oldy, RAD);


    }


                        // find molecule's new position


void molecule::calculate()


    {


   oldx = xCo;          // remember old location


   oldy = yCo;


    switch(horz)         // move left or right


        {


        case hSTOP:  /* no move */  break;


        case hRIGHT: xCo += speed;  break;


        case hLEFT:  xCo -= speed;  break;


        }


    if(xCo<=LEFT+DIST)        // if at left edge,


        horz = hRIGHT;         // go right


    else if(xCo>=RIGHT-DIST)  // if at right edge,


        horz = hLEFT;          // go left


 


    switch(vert)         // move up or down


        {


        case vSTOP: /* no move */  break;


        case vDOWN: yCo += speed;  break;


        case vUP:   yCo -= speed;  break;


        }


    if(yCo<=TOP+DIST)         // if at top edge,


        vert = vDOWN;          // go down


    else if(yCo>=BOTTOM-DIST) // if at bottom edge,


        vert = vUP;            // go up


   }


 


void molecule::draw()   // draw molecule in new position


   {


   setcolor(color);


   circle(xCo, yCo, RAD);


   setfillstyle(SOLID_FILL, color);


   floodfill(xCo, yCo, color);


    }


 


void main()


    {


   int driver, mode;


   driver = DETECT;           // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


 


                              // create some molecules


    molecule m1(100, 120, 2, hRIGHT, vUP,   BLUE);


    molecule m2(150, 220, 2, hLEFT,  vUP,   GREEN);


    molecule m3(200, 140, 3, hRIGHT, vDOWN, CYAN);


    molecule m4(250, 240, 3, hLEFT,  vDOWN, RED);


    molecule m5(300, 160, 3, hRIGHT, vUP,   MAGENTA);


    molecule m6(350, 260, 4, hLEFT,  vUP,   LIGHTGREEN);


    molecule m7(150, 350, 4, hLEFT,  vSTOP, LIGHTGRAY);


    molecule m8(150, 350, 4, hSTOP,  vUP,   BROWN);


 


                              // outline screen


   rectangle(LEFT, TOP, RIGHT, BOTTOM);


    while( !kbhit() )          // quit on keypress


        {                       // move molecules around


        m1.calculate(); m1.erase(); m1.draw();


        m2.calculate(); m2.erase(); m2.draw();


        m3.calculate(); m3.erase(); m3.draw();


        m4.calculate(); m4.erase(); m4.draw();


        m5.calculate(); m5.erase(); m5.draw();


        m6.calculate(); m6.erase(); m6.draw();


        m7.calculate(); m7.erase(); m7.draw();


        m8.calculate(); m8.erase(); m8.draw();


        }


   getche();


   closegraph();              // close graphics system


   }




ينشئ البرنامج ثمانية جزيئات , ويحركها ويبين الشكل الجزيئات ترتد علي جوانب الإناء وللأسف ليس بالإمكان تمثيل الحركة علي الصورة .



وكما في الرسوم المتحركة عادة , ينتج تأثير الحركة عن طريق تحريك الشكل في خطوات صغيرة تتكرر بسرعة . فإذا كان جهازك بطيئا فقد تجد الأشكال تتحرك ببطء , و بإمكانك إزالة بعضا من الأشكال للإسراع في الحركة . أما إذا كان الجهاز أسرع من اللازم فقد تحتاج لإدخال دالة تأخير delay() في الدوارة while .



وكما تلاحظ لكل جزئ اتجاهان للحركة أفقية ورأسية لحساب الموضع الجديد , نضيف أو نطرح لأحد الاتجاهين المتغير speed طبقا للاتجاه . وينعكس الاتجاه إذا ما وصل جزئ لحد من حدود الرسم مما يعطي انطباعا بالارتداد .



كما تلاحظ أن النوع COLOR معرف في ملف graphics.h كمرادف للنوع int ويفضل استخدام هذا النوع للمتغيرات المعبرة عن الألوان .

تعليقات

المشاركات الشائعة من هذه المدونة

المؤثرات الحسابية في C++

الرسم Graphics

دوال النمط الرسومي في ++C