วันอาทิตย์ที่ 15 ธันวาคม พ.ศ. 2556

ขั้นตอนการเขียนโปรแกรมเพื่อควบคุมการทำงานของเกมส์งู ด้วย Arduino

           ในส่วนของ Software ที่ใช้เขียนโปรแกรมในการควบคุม Dot Metrix LED ด้วย microcontroller ซึ่งเราเลือกใช้ Arduino เป็นตัวควบคุม ก่อนอื่นเราก็ควรออกแบบการทำงานของโปรแกรมของเรากันก่อน ซึ่งขั้นตอนของเราก็ได้แสดงไว้ใน Flowchart ด้านล่าง ดังนี้


การออกแบบโปรแกรมควบคุมบน Arduino



                                           
   Flowchart โปรแกรมทั้งหมด


             หลังจากที่เราออกแบบโปรแกรมเรียบร้อยแล้ว เราก็มาเริ่มลงมือเขียนโปรแกรมตามขั้นตอนด้านบน โดยใช้ความรู้ เรื่องการเขียนโปรแกรม arduino ที่มีลักษณะการเขียนและตรรกะคล้ายๆกับการเขียนภาษาซี แต่อาจจะมีบางฟังก์ชันที่แตกต่างกัน เช่น การใช้ digitalWrite , digitalRead , ramdomSeed เป็นต้น หากใครที่ยังไม่มีความรู้พื้นฐาน และมีความสนใจ ก็ลองไปศึกษาเพิ่มเติมกันดูนะคะ  ^^



ตัวอย่างโปรแกรมเกมงู  สามารถนำไปลองเล่นกันได้นะคะ 

// Shift Register Pin

const int latchPin = 8;  // STCP
const int clockPin = 12; // SHCP
const int dataPin = 11;  // DS

// Button Pin

const int leftButton = 6;
const int rightButton = 7;
const int upButton = 9;
const int downButton = 10;

const int delayTime = 1;  // in uS
const int shiftTime = 1;  // in uS

unsigned long displayUpdateTime;
unsigned long foodTime;
unsigned long foodDelay;

const unsigned long displayRefreshPeriod = 60;
const unsigned long minimumFoodDelay = 900;
const unsigned long maximumFoodDelay = 4000;

typedef struct
{
  int x;
  int y;
} POINT_T;

POINT_T p[256];

int headPos=2;
int tailPos=0;

// Current Direction N, S, E, W
char headDirection = 'E';

unsigned short data[16] = {
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111};
    
unsigned short food[16] = {
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111};

     
unsigned short three[16] = {
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111100000011111,
    0b1111101111111111,
    0b1111101111111111,
    0b1111101111111111,
    0b1111100000011111,
    0b1111101111111111,
    0b1111101111111111,
    0b1111101111111111,
    0b1111100000011111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111};
   
unsigned short two[16] = {
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111110000011111,
    0b1111111111011111,
    0b1111111111011111,
    0b1111111111011111,
    0b1111110000011111,
    0b1111110111111111,
    0b1111110111111111,
    0b1111110111111111,
    0b1111110000011111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111};
       
       
unsigned short one[16] = {
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111000000011111,
    0b1111111011111111,
    0b1111111011111111,
    0b1111111011111111,
    0b1111111011111111,
    0b1111111011111111,
    0b1111111011011111,
    0b1111111010111111,
    0b1111111001111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111,
    0b1111111111111111};
       
         
unsigned short gameover[16]={          
    0b0110100011011000,
    0b0110111011011010,
    0b0110111010101010,
    0b00001000010101010,
    0b1110111010101010,
    0b00001111001110010,
    0b0110111001110010,
    0b0000100001110000,
    
    0b0000111001100000,
    0b1100111001100110,
    0b1100111001100110,
    0b0000101000000010,
    0b1100101001101110,
    0b1100010001101110,
    0b1100010001100110,
    0b0000111000000000};
    
    
void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  pinMode(2, OUTPUT);  // A0
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);  // A3
  
  pinMode(leftButton, INPUT);
  pinMode(rightButton, INPUT);
  pinMode(upButton, INPUT);
  pinMode(downButton, INPUT);
  
  digitalWrite(leftButton, HIGH);
  digitalWrite(rightButton, HIGH);
  digitalWrite(upButton, HIGH);
  digitalWrite(downButton, HIGH);
  
  p[2].x=9;
  p[2].y=10;
  p[1].x=8;
  p[1].y=10;
  p[0].x=7;
  p[0].y=10;
  
  randomSeed(analogRead(0));
  foodDelay = random(minimumFoodDelay, maximumFoodDelay);
  
  displayUpdateTime = millis();
  foodTime = millis();

    unsigned long tmp = millis();
    while(millis() - tmp < 1000)
    {
        showDisplay(three);
    }

    tmp = millis();
    while(millis() - tmp < 1000)
     {
        showDisplay(two);
     }

    tmp = millis();
    while(millis() - tmp < 1000)
     {
        showDisplay(one);
     }

  Serial.begin(9600);
}


void loop()
{
  
  unsigned long newTime = millis();
  
  // Update direction
  if (headDirection == 'N' || headDirection == 'S')
  {
    if (digitalRead(leftButton) == LOW)
      headDirection = 'W';
    if (digitalRead(rightButton) == LOW)
      headDirection = 'E';
  }

  else if (headDirection == 'E' || headDirection == 'W')
  {
    if (digitalRead(upButton) == LOW)
      headDirection = 'N';
    if (digitalRead(downButton) == LOW)
      headDirection = 'S';
  }
  
   // Clear display buffer
   for (int i=0; i<16; i++)
   {
     data[i] = 0xFFFF;
   }
   
   // Update snake position
   int prevHead = headPos;
   if (newTime - displayUpdateTime > displayRefreshPeriod)
   {
     headPos++;
     if (headPos == 256)
       headPos = 0;
     tailPos++;
     if (tailPos == 256)
       tailPos = 0;
   
     if (headDirection == 'N')
     {
       p[headPos].x = p[prevHead].x;
       p[headPos].y = p[prevHead].y + 1;
       if (p[headPos].y == 16)
         p[headPos].y = 0;
     }
   
     else if (headDirection == 'S')
     {
       p[headPos].x = p[prevHead].x;
       p[headPos].y = p[prevHead].y - 1;
       if (p[headPos].y == -1)
         p[headPos].y = 15;
     }
   
     else if (headDirection == 'E')
     {
       p[headPos].x = p[prevHead].x + 1;
       p[headPos].y = p[prevHead].y;
       if (p[headPos].x == 16)
         p[headPos].x = 0;
     }
   
     else if (headDirection == 'W')
     {
       p[headPos].x = p[prevHead].x - 1;
       p[headPos].y = p[prevHead].y;
       if (p[headPos].x == -1)
         p[headPos].x = 15;
     }
     displayUpdateTime = newTime;
   }
   
   for (int i=headPos-1; i>=tailPos; i--)
  {
      if (i < 0)
        i = 255;
      if (p[i].x == p[headPos].x && p[i].y == p[headPos].y)
      while (1)
      {
        showDisplay(gameover);
      }
  } 
   
   // Check if snake hit food
   //Serial.print(~food[p[headPos].y]);
   //Serial.print(" ");
   //Serial.print((1 << p[headPos].x));
   //Serial.print(" ");
   //Serial.println(~food[p[headPos].y] & (0x0001 << p[headPos].x));
   
   if ((~food[p[headPos].y] & (0x0001 << p[headPos].x)) != 0)
   {
     tailPos--;
     if (tailPos < 0)
       tailPos = 15;
     food[p[headPos].y] |= (1 << p[headPos].x);
   }
   

   // Gen food
   if (newTime - foodTime > foodDelay)
   {
     int foodX;
     int foodY;
     do
     {
       foodX = random(0, 16);
       foodY = random(0, 16);
     }
     while (isInSnake(foodX, foodY));
     food[foodY] &= ~(1 << foodX);
     foodTime = newTime;
     foodDelay = random(minimumFoodDelay, maximumFoodDelay);
   }
   
   // Create display buffer
   for(int i=headPos; i>=tailPos; i--)
   { 
      if (i < 0)
         i = 255;
      data[p[i].y] &= ~(1 << p[i].x);
   }
  
   // Display
  for (int i=0; i<16; i++)
   { 
       for (int j=0; j<16; j++)
      {
        digitalWrite(dataPin, ((data[i] & food[i] & (1 << j)) >> j));
        delayMicroseconds(shiftTime);
        digitalWrite(clockPin, HIGH);
        delayMicroseconds(shiftTime);
        digitalWrite(clockPin, LOW);
        delayMicroseconds(shiftTime);
      }
      
      digitalWrite(2, (i&0x01));
      digitalWrite(3, (i&0x02) >> 1);
      digitalWrite(4, (i&0x04) >> 2);
      digitalWrite(5, (i&0x08) >> 3);
      
      digitalWrite(latchPin, HIGH);
      delayMicroseconds(shiftTime);
      digitalWrite(latchPin, LOW);
      delayMicroseconds(shiftTime);
      
      delayMicroseconds(delayTime);
    }
  
  //dead 
    
}


void showDisplay(unsigned short data[])
{
  for (int i=0; i<16; i++)
   { 
       for (int j=0; j<16; j++)
      {
        digitalWrite(dataPin, ((data[i] & (1 << j)) >> j));
        delayMicroseconds(shiftTime);
        digitalWrite(clockPin, HIGH);
        delayMicroseconds(shiftTime);
        digitalWrite(clockPin, LOW);
        delayMicroseconds(shiftTime);
      }
      
      digitalWrite(2, (i&0x01));
      digitalWrite(3, (i&0x02) >> 1);
      digitalWrite(4, (i&0x04) >> 2);
      digitalWrite(5, (i&0x08) >> 3);
      
      digitalWrite(latchPin, HIGH);
      delayMicroseconds(shiftTime);
      digitalWrite(latchPin, LOW);
      delayMicroseconds(shiftTime);
      
      delayMicroseconds(delayTime);
    }
}

boolean isInSnake(int foodX, int foodY)
{
  for (int i=headPos; i>=tailPos; i--)
  {
      if (i < 0)
        i = 255;
      if (p[i].x == foodX && p[i].y == foodY)
        return true;
  } 
  return false;
}











ไม่มีความคิดเห็น:

แสดงความคิดเห็น