ST7565 | Chuyển động trong lập trình Game và đồ họa | Phần 2

01/08/2019
st7565-chuyen-dong-trong-lap-trinh-game-va-do-hoa-phan-2

Trong bài viết trước, chúng ta đã cùng tìm hiểu một vài nguyên tắc của hiệu ứng chuyển động trong đồ họa. Bài viết này sẽ nối tiếp nội dung còn dở dang của bài trước, hãy cùng đi tiếp nào. Tất nhiên là trên arduino cùng lcd st7565 rồi.cheekyblush

1

Stop_Motion

Đây là bài viết số 2 thuộc chuỗi bài “Chuyển động trong lập trình Game và đồ họa”.

Nếu chưa đọc bài viết trước, thì hãy đọc nó tại đây bạn nhé:

P1:Chuyển động trong lập trình game và đồ họa

Hãy cùng bắt đầu nhélaughwink

Chúng ta đã biết, mỗi khung hình cho một đối tượng ở một thời điểm là khác nhau (nếu giống nhau thì ta coi vật đó là tĩnh hay đứng im , nên ta sẽ không xét), vì vậy để hành động của đối tượng được mền mại, không quá cứng nhắc thì việc duy trì hành động với quỹ đạo theo thời gian càng mượt mà càng tốt.

Để làm được điều này, người lập trình lại phải quan tâm đến những chi tiết nhỏ hơn.

Đây cũng là nguyên tắc Arcs -Bất cứ một chuyển động nào cũng cần tạo ra đường cong của chuyển động từ điểm bắt đầu tới kết thúc.

"Ngày nay, với sự hỗ trợ của máy tính và phần mềm, trong lập trình game có đòi hỏi chất lượng tốt, thì nguyên tắc trên sẽ được khai khác một cách hiệu quả nhất. Phương pháp tối ưu nhất hiện nay để quản lý và điều khiển hình ảnh của đối tượng ảo là việc sử dụng một bản đồ các điểm nút , mà ở đó tập hợp các điểm sẽ cho khung của đối tượng , và việc tô màu đối tượng ảo sẽ là việc tô trên các mạng lưới nhỏ hơn cấu thành từ các điểm..'".

Tuy nhiên nguyên tắc này vẫn có thể bị phá vỡ dần khi người ta muốn cải thiện tốc độ và các thay đổi của chuyển động sẽ ở một mức chấp nhận được, giống như các tựa game đơn giản trên nền Mobi cấu hình thấp. Và điều này cũng phù hợp khi ta mong muốn tạo game trên Arduino.

Dưới đây là các stop_motion khi các động tác của nhân vật được tổng quát với những bản phác ở các góc độ khác nhau,nó hướng tới sự đơn giản hóa, điều này sẽ làm tăng đáng kể hiệu xuất của máy tính .

2

Stop_Motion trên arduino .

Chúng ta sẽ cùng quay trở lại với nhân vật Penguin mập ú cùng với sự hỗ trợ của Arduino và lcd ST7565

Đầu tiên là bản phác họa các hành động

Chuyển sang dạng ảnh bmp và lấy mã hex lưu trữ của ảnh

Để lấy mã hex, mình sử dụng ứng dụng java lấy trong thư viện của OPEN GLCD

  • Trong file tải xuống tìm đến file glcdMakeBitmap.jad rồi mở nó
  • Mở song song thư mục chứa file BMP của bạn.
  • Nhấn giữ rồi kéo thả ảnh xuống cái cửa sổ chương trình glcdMakeBitmap.jad trên
  • File hex sẽ nằm ngay ở thư mục lớn có chứa glcdMakeBitmap
  • Mở file hex bằng NotePad , rồi copy đoạn nằm trong ngoặc { }, chú ý sửa lại ..
  • //ví dụ  

    25, // width   26, // height

    //viết thành

     // 25, width   //26,  height

  • Dán vào code mẫu của bạn là xong. Bạn cũng cần biết sử dụng hàm vẽ ảnh Bitmap trong thư viện tải về nhé.
  • Nếu có lỗi mở file .jad, thì bạn cần thiết lập máy tính có hỗ trợ môi trường JAVA, hãy lên google tham khảo hoặc sử dụng phần mềm khác thay thế.(Mình đã thử khá nhiều phần mềm, nhưng thấy ứng dụng java trên không ăn bớt mã hex của mình khi biên dịch yesheart, hãy cố gắng thiết lập môi trường java cho máy tính của bạn  nha)

Tải ứng dụng tại đây.

Quay lại với chủ đề nào wink

 walk1  walk2  walk3  walk4
 jump1  jump2  jump3  
 slide1  slide2  hurt  
 die1  die2 die3  

Mình đã chuyển ảnh bitmap sang dạng code lưu trữ trong một tệp có tên bmp1.h

Tải về tại đây

Tư liệu đã sẵn sàng, cùng mở IDE lên và tạo mới một chương trình thôi!!smiley

Chọn New Tab, và đặt tên file là “bmp1.h”, sau đó copy toàn bộ code trong file tải về dán vào, rồi nhớ ấn lưu.

 

Cuối cùng là thêm tệp  "bmp1.h"

Ta có code sau để test như sau

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #include "bmp1.h"//
  4. void setup() {
  5. lcd.ON();
  6. lcd.SET(23,0,0,0,4);
  7. }
  8. void loop() {
  9. lcd.bitmap(60,30,25,28,walk1,BLACK);
  10. lcd.display();
  11. }

Kết quả khi test bằng đoạn code trên

3

Mô phỏng hành động

Bước đi

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #include "bmp1.h"
  4. void setup() {
  5. lcd.ON();
  6. lcd.SET(23,0,0,0,4);
  7. }
  8.  
  9.  
  10. //Tạo một hàm có tên walk,với  3 tham số là x,y: tọa độ ; time_d: delay.
  11. void walk(int x, int y,unsigned int time_d){
  12. //p1
  13. lcd.Bitmap( x,y,25,28,walk1,BLACK);
  14. lcd.Display();
  15. delay(time_d);
  16. lcd.fillrect(x,y,25,28,DELETE);
  17. //p2
  18. lcd.Bitmap( x+3,y,25,28,walk2,BLACK);
  19. lcd.Display();
  20. delay(time_d);
  21. lcd.fillrect(x+3,y,25,28,DELETE);
  22. //p3
  23. lcd.Bitmap( x+6,y,25,28,walk3,BLACK);
  24. lcd.Display();
  25. delay(time_d);
  26. lcd.fillrect(x+6,y,25,28,DELETE);
  27. //p4
  28. lcd.Bitmap( x+9,y,25,28,walk4,BLACK);
  29. lcd.Display();
  30. delay(time_d);
  31. lcd.fillrect(x+9,20,25,28,DELETE);
  32. lcd.Display();
  33. }
  34.  
  35.  
  36. void loop(){
  37. for(int x=0; x<100; x+=9){
  38. walk(x,35,200);
  39. }
  40. }

Như bài trước, ta đã biết cách thức để vẽ một khung hình là một quy trình gồm các bước: tính toán->hiển thị->đợi->xóa.

Quy trình sẽ lặp lại với những khung hình tiếp theo. Một bước đi của nhân vật Penguin gồm 4 khung hình, do đó quy trình vẽ sẽ lặp lại  4 lần.  Tất nhiên ta cần dùng đến hàm for để nhân bản hành động khi tăng dần hoành độ , tạo ra hành động đi bộ. 

Tối ưu hóa code

Bất cứ dòng lệnh nào có tính lặp lại nhiều lần ta đều cần tối ưu nó.

Cụ thể là 4 khối code trên đã lặp lại, và mình sẽ cho vào hàm action để thực hiện nhiệm vụ chuyên biệt này.

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #include "bmp1.h"
  4. void setup() {
  5. lcd.ON();
  6. lcd.SET(23,0,0,0,4);
  7. }
  8. void action( int x, int y, int width, int high, const char* bitmap_name, unsigned int time_d){
  9.  
  10. lcd.Bitmap( x,y,width,high,bitmap_name,BLACK);
  11. lcd.Display();
  12. delay(time_d);
  13. lcd.fillrect(x,y,width,high,DELETE);
  14. lcd.Display();
  15. }
  16. void walk(int x, int y, unsigned int time_d){
  17.  
  18. action(x,y,25,28,walk1, time_d);
  19. action(x+3,y,25,28,walk2, time_d);
  20. action(x+6,y,25,28,walk3, time_d);
  21. action(x+9,y,25,28,walk4, time_d);
  22.  
  23. }
  24. void loop() {
  25. for(int x=0; x<100; x+=9)
  26. walk(x,35,250);
  27. }

Kết quả vẫn như trước

Giờ thì ta cần quay ảnh ngược lại ra phía sau nếu muốn Penguin đi từ phải sang trái

Ta cần đến Plus_Bitmap để xoay ảnh. Chúng ta cũng cần quy ước về hướng, hướng tổng quát sẽ được hiểu là góc hợp bởi vector chỉ hướng và trục hoành. 

Kể từ đây, khi nói  hướng   0’:Trái ,180’:Phải,90’: Lên,270’: Xuống Hoặc 45:  chếch phải. và hiểu theo nghĩa ngược lại .

Để quay hướng nhân vật ra phía sau, mình sẽ lật ảnh bằng gương

Cùng với đó là định nghĩa thêm 4 hướng.

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #include "bmp1.h"//
  4.  
  5.  
  6. #define Phai 0
  7. #define Len 90
  8. #define Trai 180
  9. #define Xuong 270
  10. void setup() {
  11. lcd.ON();
  12. lcd.SET(23,0,0,0,4);
  13. }
  14.  
  15.  
  16. void action( int x, int y, int width, int high, const char* bitmap_name, unsigned int time_delay,unsigned int huong){
  17. bool mirror=false;
  18. if(huong==Trai){
  19. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  20. }
  21. lcd.Plus_Bitmap( x,y,width,high,bitmap_name,0,mirror,BLACK);
  22. lcd.Display();
  23. delay(time_delay);
  24. lcd.fillrect(x,y,width,high,DELETE);
  25. lcd.Display();
  26. }
  27.  
  28. void walk(int x, int y, unsigned int time_delay,unsigned int huong){
  29. int denta=1;// sang phải thì x tăng
  30. if(huong==Trai){
  31. denta=-1;// sang trái thì x giảm, denta phải âm
  32. }
  33. action(x,y,25,28,walk1, time_delay,huong);
  34. action(x+3*denta,y,25,28,walk2, time_delay,huong);
  35. action(x+6*denta,y,25,28,walk3, time_delay,huong);
  36. action(x+9*denta,y,25,28,walk4, time_delay,huong);
  37. }
  38.  
  39. void loop(){
  40. byte y0=35;
  41.  
  42. for(int x=30; x<60; x+=9)
  43. walk(x,y0,220,Phai);
  44.  
  45. for(int x=60; x>30; x-=9)
  46. walk(x,y0,220,Trai);
  47. }

Kết quả, nhân vật đi qua đi lại như thế này.

4

Tương tác

Tiếp tục dùng nút bấm để điều khiển nhân vật Penguin nào

Để thuận tiện trong nạp code, mình sẽ không thay đổi thứ tự nút và chân kết nối, nên bạn hãy nối giống mình nhé.

Bây giờ để điều khiển, chỉ đơn giản mình khai báo thêm 4 dòng ở Setup và dùng hàm kiểm tra sự kiện nhấn nút Pullup_4.

Đầu tiên là điều khiển đối tượng đi qua đi lại

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #define de 100
  4. #define Phai 0
  5. #define Tren 90
  6. #define Trai 180
  7. #define Duoi 270
  8.  
  9.  
  10. #include "bmp1.h"// chú ý thêm
  11. void setup() {
  12. lcd.ON();
  13. lcd.SET(23,0,0,0,4);
  14.  
  15. pinMode(A3,INPUT_PULLUP);
  16. pinMode(A2,INPUT_PULLUP);
  17. pinMode(A1,INPUT_PULLUP);
  18. pinMode(A0,INPUT_PULLUP);
  19. }
  20.  
  21.  
  22.  
  23. void action( int x, int y, int width, int high, const char* bitmap_name, unsigned int time_delay,unsigned int huong){
  24. bool mirror=false;
  25. if(huong==Trai){
  26. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  27. }
  28. lcd.Display();
  29. lcd.Plus_Bitmap( x,y,width,high,bitmap_name,0,mirror,BLACK);
  30. lcd.Display();
  31. delay(time_delay);
  32. lcd.fillrect(x,y,width,high,DELETE);
  33. }
  34.  
  35. void walk(int x, int y, unsigned int time_delay,unsigned int huong){
  36. int denta=1;// sang phải thì x tăng
  37. if(huong==Trai){
  38. denta=-1;// sang trái thì x giảm, denta phải âm
  39. }
  40. action(x,y,25,28,walk1, time_delay,huong);
  41. action(x+3*denta,y,25,28,walk2, time_delay,huong);
  42. action(x+6*denta,y,25,28,walk3, time_delay,huong);
  43. action(x+9*denta,y,25,28,walk4, time_delay,huong);
  44.  
  45. }
  46.  
  47. void stand(int x, int y,unsigned int huong){
  48. bool mirror=false;
  49. if(huong==Trai){
  50. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  51. }
  52. lcd.Plus_Bitmap( x,y,25,28,walk2,0,mirror,BLACK);
  53. lcd.display();
  54. delay(10);
  55. lcd.fillrect(x,y,25,28,DELETE);
  56. }
  57.  
  58. int x=60;//hoành độ khảo sát
  59. int y=30;// tung độ khảo sát
  60. byte button;
  61. int huong;// góc xoay ảnh
  62.  
  63. void loop(){
  64. button= lcd.Pullup_4(A3, A2, A1, A0);
  65. switch(button){
  66. case 1: huong=Phai;walk(x,y,200,huong); x+=9; break;// right
  67. case 3: huong=Trai;walk(x,y,200,huong); x-=9; break;//left
  68. default : stand(x,y,huong); break;
  69. }
  70. }

Và cuối cùng thêm 6 động tác là Nằm-nút down, nhảy cao-nút up+(left/right),Trượt_nút down+(left/right), và Nhảy tại chỗ nút up

  1. #include "ST7565_homephone.h"
  2. ST7565 lcd(3,4,5,6);
  3. #define de 100
  4. #define Phai 0
  5. #define Tren 90
  6. #define Trai 180
  7. #define Duoi 270
  8.  
  9.  
  10. #include "bmp1.h"// chú ý thêm
  11. void setup() {
  12. lcd.ON();
  13. lcd.SET(23,0,0,0,4);
  14. //thêm hai dòng này khi cần dùng đến màn hình
  15.  
  16. pinMode(A3,INPUT_PULLUP);
  17. pinMode(A2,INPUT_PULLUP);
  18. pinMode(A1,INPUT_PULLUP);
  19. pinMode(A0,INPUT_PULLUP);
  20. }
  21.  
  22.  
  23. void action( int x, int y, int width, int high, const char* bitmap_name, unsigned int time_delay,unsigned int huong){
  24. bool mirror=false;
  25. if(huong==Trai){
  26. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  27.  
  28. }
  29. lcd.Display();
  30. lcd.Plus_Bitmap( x,y,width,high,bitmap_name,0,mirror,BLACK);
  31. lcd.Display();
  32. delay(time_delay);
  33. lcd.fillrect(x,y,width,high,DELETE);
  34. }
  35.  
  36. void walk(int x, int y, unsigned int time_delay,unsigned int huong){
  37. int denta=1;// sang phải thì x tăng
  38. if(huong==Trai){
  39. denta=-1;// sang trái thì x giảm, denta phải âm
  40. }
  41. action(x,y,25,28,walk1, time_delay,huong);
  42. action(x+3*denta,y,25,28,walk2, time_delay,huong);
  43. action(x+6*denta,y,25,28,walk3, time_delay,huong);
  44. action(x+9*denta,y,25,28,walk4, time_delay,huong);
  45.  
  46. }
  47.  
  48. void stand(int x, int y,unsigned int huong){
  49. bool mirror=false;
  50. if(huong==Trai){
  51. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  52. }
  53. lcd.Plus_Bitmap( x,y,25,28,walk2,0,mirror,BLACK);
  54. lcd.display();
  55. delay(10);
  56. lcd.fillrect(x,y,25,28,DELETE);
  57. }
  58.  
  59.  
  60. void lie(int x, int y, unsigned int time_delay,unsigned int huong){
  61. bool mirror=false;
  62. if(huong==Trai){
  63. mirror=true;// nếu đi sang trái thì xoay nhân vật về bên trái
  64. }
  65. //action(x,y+10,25,22,slide1,time_delay,huong);
  66. action(x,y+8,30,19,slide2,time_delay,huong);
  67.  
  68. }
  69.  
  70. void die( int x, int y, unsigned int time_delay,unsigned int huong){
  71. action(x,y,25,26,die1, time_delay,huong);
  72. action(x,y+3,25,27,die2, time_delay,huong);
  73. action(x,y+6,30,23,die3,time_delay,huong);
  74. delay(500);
  75. }
  76.  
  77. void jump(int x, int y, unsigned int time_delay,unsigned int huong){
  78. int denta=1;// sang phải thì x tăng
  79. if(huong==Trai){
  80. denta=-1;// sang trái thì x giảm, denta phải âm
  81. }
  82. action(x,y-8,25,27,jump1, time_delay,huong);
  83. action(x,y-5,24,24,jump2, time_delay,huong);
  84. action(x,y-3,24,24,jump3, time_delay,huong);
  85.  
  86. }
  87. void high_jump(int x0, int y, unsigned int time_delay,unsigned int huong){
  88. int denta=1;// sang phải thì x tăng
  89. if(huong==Trai){
  90. denta=-1;// sang trái thì x giảm, denta phải âm
  91. }
  92. for(int denta_x=0; denta_x<10; denta_x+=2){
  93. y-=2;
  94. action(x0+denta_x*denta,y,24,24,jump2, time_delay,huong);
  95. }
  96. x0+=10*denta;
  97. for(int denta_x=0; denta_x<10; denta_x+=2){
  98. y+=2;
  99. action(x0+denta_x*denta,y,24,24,jump3, time_delay,huong);
  100. }
  101.  
  102. }
  103.  
  104.  
  105.  
  106. int x=60;//hoành độ khảo sát
  107. int y=30;// tung độ khảo sát
  108. byte button;
  109. byte trangthai;
  110. int huong;// góc xoay ảnh
  111. void loop(){
  112. button= lcd.Pullup_4(A3, A2, A1, A0);
  113. switch(button){
  114. case 1: huong=Phai;walk(x,y,250,huong); x+=9; break;// right
  115. case 2: jump(x,y,150,huong); break;// up
  116. case 3: huong=Trai;walk(x,y,250,huong); x-=9; break;//left
  117. case 4: lie(x,y,300,huong); break; //down
  118. case 40: huong=Phai; x++; lie(x,y,5,huong); break;// slide right
  119. case 120: huong=Trai; x--; lie(x,y,5,huong); break;// slide left
  120. case 60: huong=Trai; high_jump(x,y,100,huong); x-=20;break;// jump higher
  121. case 20: huong=Phai; high_jump(x,y,100,huong);x+=20;break;// jump higher
  122.  
  123. default : stand(x,y,huong); break;
  124. }
  125. if(x<0){x=0;}
  126. if(y<0){y=0;}
  127. if(x>100){x=100;}
  128. if(y>53){y=53;}
  129.  
  130.  
  131. }
Bình luận
Nội dung này chưa có bình luận, hãy gửi bình luận đầu tiên của bạn.
VIẾT BÌNH LUẬN CỦA BẠN