Animation workshop : นาฬิกาติดผนัง (ตอนที่ 1)

การออกแบบ


ตัวเรือนนาฬิกา


โครงสร้างหลักของนาฬิการมี 2 ส่วนคือ ตัวเรือนและเข็ม

1. ตัวเรือน คือวงกลมใหญ่แทนตัวเรือน และวงกลมเล็กอยู่ตรงกลางตัวเรือนแทนตำแหน่งของจุดหมุนของเข็มนาฬิกา

รูปที่ 1

2. เข็มนาฬิกา คือเส้นตรง 3 เส้นขนาดต่างกัน เส้นยาวสุดแทนเข็มวินาที เส้นสั้นสุดแทนเข็มชั่วโมง และเส้นที่มีความยาวระหว่างสองเส้นแรกแทนเข็มนาที

รูปที่ 2

นำองค์ประกอบมารวมเป็นตัวนาฬิกา

รูปที่ 3


การสร้างโปรแกรม


1. การวาดตัวเรือนนาฬิกา


1.1 กำหนดตำแหน่งที่ของนาฬิกา โดยให้อยู่ที่ตรงกลางของหน้าต่าง (window)


  // constants :
const int WIN_WIDTH=400;
const int WIN_HEIGHT=400;  
const float cx = (float)(WIN_WIDTH / 2);
const float cy = (float)(WIN_HEIGHt / 2);

  

1.2 การวาดตัวเรือนนาฬิกาใช้ function

  
  void DrawRing(Vector2 center, 
                float innerRadius, 
                float outerRadius, 
                float startAngle, 
                float endAngle, 
                int segments, 
                Color color);
  

function นี้ต้องใช้ 7 parameters :

   ♦ center : ตำแหน่งจุดศูนย์กลาง ในการทำงานครั้งนี้คือค่าของ cx,cy แต่ต้องนำมาแปลงให้เป็นตัวแปรแบบ Vector2 ก่อน

   ♦ innerRadius : ความยาวของรัศมีของวงกลมด้านใน

   ♦ outerRadius : ความยาวของรัศมีของวงกลมด้านนอก

   ♦ startAngle : มุมของจุดเริ่มต้นใช้หน่วยเป็น degree โดยมุมจะเริ่มวัดจากแนวของ X+ axis (แนวตั้งฉากกับพื้น) แล้ววัดไปในทิศทวนเข็มนาฬิกา

   ♦ endAngle : มุมของจุดสุดท้าย

   ♦ segMents : จำนวนเหลี่ยมที่ต้องการ เริ่มต้นจาก 0 (ไม่มีการวาด) จำนวนเหลี่ยมยิ่งมากขึ้น รูปทรงจะออกมาใกล้กับเส้นโค้งของวงกลมมากขึ้น

   ♦ color : สีที่ต้องการเติ่ม


ข้อดีของการกำหนด startAngle , endAngle ทำให้สามารถวาดรูป arc ได้ และการที่สามารถกำหนดจำนวนเหลี่ยมก็ทำให้สามารถวาดรูปอื่นที่ไม่มีส่วนโค้งได้ เช่น รูป 6 เหลี่ยม ได้


รูปที่ 4

การวาดวงกลมตรงกลางของนาฬิกาจะใช้

  
 void DrawCircle(int centerX, 
                 int centerY, 
                 float radius, 
                 Color color);
  

1.3 สร้าง function ของการวาดตัวเรือน

  
void draw_clock(){
    float thickness = 5.0f; // thickness of the ring
    float inrad = 100.0f; // inner radius
    float ourad = inrad + thickness; // outter radius
    float stang = 0.0f; // start angle 
    float enang = 360.0f; // end angle
    float seg = 360.0f; // segments
    
    Vector2 cnt = {cx,cy}; // cast cx,cy to Vector2 
    DrawRing(cnt,inrad,ourad,stang,enang,seg,BLUE); // draw blue clock
    DrawCircle((int)cx,(int)cy,10,BLACK); // draw black circle with radius 10 pixels on the middle of the clock
}

2. การวาดเข็มนาฬิกา

การวาดเข็มคือการวาดเส้นตรง 3 เส้นที่มีความยาวต่างกันด้วย function


  void DrawLineEx(Vector2 startPos,
                  Vector2 endPos,
                  float thick, 
                  Color color);
  

function นี้ต้องการ 4 parameters:

   ♦ startPos : coordinate ของตำแหน่งเริ่มต้น

   ♦ endPos : coordinate ของตำแหน่งสิ้นสุด

   ♦ thick : ขนาดความหนาของเส้น

   ♦ color : สีของเส้น


ควรกำหนดขนาดความยาวไว้เป็นค่าคงที่


// constants :

//clock  
const int WIN_WIDTH=400;
const int WIN_HEIGHT=400;  
const float cx = (float)(WIN_WIDTH / 2);
const float cy = (float)(WIN_HEIGHt / 2);

// arms
const int SEC_ARM_LEN = 70;
const int MIN_ARM_LEN = 60;
const int HRS_ARM_LEN = 50;
  

เพื่อให้ง่ายในการแก้ไข ควรแยก function ของการวาดเข็มแยกกันระหว่าง เข็มวินาที, เข็มนาทีและเข็มชั่วโมง แม้วิธีการทำงานจะเหมือนกันก็ตาม ถ้าหากเข้าใจการทำงานดีแล้วก็สามารถปรับแต่งได้ตามความต้องการภายหลัง


void draw_sec_arm(){
	float thickness = 3.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_ARM_LEN),(float)(cy+SEC_ARM_LEN)};
    DrawLineEx(start,end,thickness,RED);
}

void draw_min_arm(){
	float thickness = 7.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_MIN_LEN),(float)(cy+SEC_MIN_LEN)};
    DrawLineEx(start,end,thickness,BLUE);
}

void draw_hrs_arm(){
	float thickness = 11.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_HRS_LEN),(float)(cy+SEC_HRS_LEN)};
    DrawLineEx(start,end,thickness,DARKPURPLE);
}
  

3. Complete Code



#include "raylib.h"

/ constants :

//clock  
const int WIN_WIDTH=400;
const int WIN_HEIGHT=400;  
const float cx = (float)(WIN_WIDTH / 2);
const float cy = (float)(WIN_HEIGHT / 2);

// arms
const int SEC_ARM_LEN = 70;
const int MIN_ARM_LEN = 60;
const int HRS_ARM_LEN = 50;

const int FPS = 20;

// functions
void draw_clock();
void draw_sec_arm();
void draw_min_arm();
void draw_hrs_arm();

int main(void){	
	InitWindow(SCR_WIDTH,SCR_HEIGHT,"Clock");	
	SetTargetFPS(FPS);	
	while(!WindowShouldClose()){
         ClearBackground(WHITE);
           draw_hrs_arm();				
		   draw_min_arm();	
		   draw_sec_arm();		
		   draw_clock();	
		EndDrawing();
    }
    CloseWindow();
    return 0;
}    

void draw_clock(){
    float thickness = 5.0f; // thickness of the ring
    float inrad = 100.0f; // inner radius
    float ourad = inrad + thickness; // outter radius
    float stang = 0.0f; // start angle 
    float enang = 360.0f; // end angle
    float seg = 360.0f; // segments
    
    Vector2 cnt = {cx,cy}; // cast cx,cy to Vector2 
    DrawRing(cnt,inrad,ourad,stang,enang,seg,BLUE); // draw blue clock
    DrawCircle((int)cx,(int)cy,10,BLACK); // draw black circle with radius 10 pixels on the middle of the clock
}

void draw_sec_arm(){
	float thickness = 3.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_ARM_LEN),(float)(cy+SEC_ARM_LEN)};
    DrawLineEx(start,end,thickness,RED);
}

void draw_min_arm(){
	float thickness = 7.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_MIN_LEN),(float)(cy+SEC_MIN_LEN)};
    DrawLineEx(start,end,thickness,BLUE);
}

void draw_hrs_arm(){
	float thickness = 11.0f;
    Vector2 start = {cx,cy};
    Vector2 end = {(float)(cx+SEC_HRS_LEN),(float)(cy+SEC_HRS_LEN)};
    DrawLineEx(start,end,thickness,DARKPURPLE);
}

  

ผลลัพธ์ที่ได้จะเป็นดังรูปที่ 5


รูปที่ 5

การบ้าน


   ♦ ทดลองเปลี่ยนรูปทรงของนาฬิกาจากวงกลมไปเป็นรูปหลายเหลี่ยม

   ♦ ทดลองเปลี่ยนค่า parameters ต่างๆ


Vector2 เป็น datatype แบบโครงสร้าง (structure) มี 2 components คือ x และ y ในโปรแกรมนี้จะใช้เพื่อเก็บตำแหน่งของวัตถุ


  typedef struct Vector2 {
    float x;                // Vector x component
    float y;                // Vector y component
} Vector2;

Color เป็น datatype แบบโครงสร้าง (structure) มี 4 components คือ r,g,b และ a ใช้เก็บค่าสีของ pixel


  typedef struct Color {
    unsigned char r;        // Color red value
    unsigned char g;        // Color green value
    unsigned char b;        // Color blue value
    unsigned char a;        // Color alpha value
} Color;

Raylib มีการสร้างตัวแปรสำหรับแทนค่าสีไว้แล้วบางค่า สามารถนำไปใช้ได้


ความคิดเห็น