Mục lục:

Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit: 10 bước (có Hình ảnh)
Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit: 10 bước (có Hình ảnh)

Video: Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit: 10 bước (có Hình ảnh)

Video: Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit: 10 bước (có Hình ảnh)
Video: Cách khiến người cãi cùn im lặng NGAY LẬP TỨC 2024, Tháng mười một
Anonim
Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit
Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit
Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit
Đối thủ mạng: Trò chơi có độ trễ thấp cho BBC Micro: bit

Trong hướng dẫn này, tôi sẽ giải thích cách triển khai trò chơi nhiều người chơi cơ bản trên BBC micro: bit với các tính năng sau:

  • Một giao diện đơn giản
  • Độ trễ thấp giữa các lần nhấn nút và cập nhật màn hình
  • Số lượng người tham gia linh hoạt
  • Dễ dàng điều khiển trò chơi bằng thiết bị điều khiển từ xa chính ("root")

Trò chơi thực chất là một mô phỏng chính trị. Tất cả người chơi bắt đầu không được chỉ định cho bất kỳ đội nào, ngoại trừ hai người chơi. Một trong những người chơi này được chỉ định cho Đội A và người còn lại được chỉ định cho Đội B.

Mục tiêu của trò chơi là mỗi người chơi phải ở trong đội với đa số người chơi tại thời điểm đó mà tất cả mọi người đều được chuyển đổi.

Sơ đồ trên minh họa một máy trạng thái hữu hạn, tức là đặc điểm kỹ thuật của các trạng thái mà thiết bị có thể ở và sự chuyển đổi giữa các trạng thái đó.

Trạng thái có thể được coi là tập dữ liệu hiện tại mô tả bộ nhớ của thiết bị kể từ khi nó được bật. Dựa trên dữ liệu đó, thiết bị có thể thực hiện các hành động nhất định hoặc phản ứng khác với thông tin nhập của người dùng.

Quá trình chuyển đổi là một điều kiện logic, khi đúng, làm cho thiết bị thay đổi trạng thái của nó. Quá trình chuyển đổi có thể từ trạng thái này sang bất kỳ trạng thái nào khác. Một trạng thái có thể có nhiều quá trình chuyển đổi.

Sơ đồ trên chỉ định các trạng thái sau:

  • Chưa giao
  • Lắng nghe A
  • Lắng nghe B
  • Đội A
  • Đội B

Một thiết bị chạy mã trò chơi có thể ở bất kỳ một trong năm trạng thái này, nhưng chỉ ở một thời điểm và chỉ năm trạng thái này.

Tôi sẽ giả sử trong suốt hướng dẫn rằng bạn đang sử dụng trình chỉnh sửa MakeCode của Microsoft, có thể tìm thấy tại:

Việc triển khai đầy đủ của trò chơi có thể được tìm thấy tại đây:

makecode.microbit.org/_CvRMtheLbRR3 ("microbit-demo-user" là tên dự án)

Và việc triển khai bộ điều khiển mạng chính ("gốc") có thể được tìm thấy tại đây:

makecode.microbit.org/_1kKE6TRc9TgE ("microbit-demo-root" là tên dự án)

Tôi sẽ tham khảo những ví dụ này trong suốt hướng dẫn của mình.

Bước 1: Cân nhắc Thiết kế Hình ảnh Lớn

Trước khi viết bất kỳ mã nào, chúng ta cần suy nghĩ về những gì chúng ta muốn sản phẩm cuối cùng của mình trông như thế nào. nói cách khác, các yêu cầu của ứng dụng là gì? Mã của chúng tôi sẽ cho thiết bị biết phải làm gì khi hoàn tất? Tôi đã chia chức năng của ứng dụng chính thành sáu loại, mỗi loại có thể được xem xét từ một quan điểm thiết kế khác nhau.

  1. Chúng tôi muốn kiểm soát các hành động của thiết bị dựa trên trạng thái hiện tại của nó
  2. Chúng tôi muốn thiết bị phản ứng với đầu vào của người dùng
  3. Chúng tôi có thể muốn hiển thị hình ảnh động và đồ họa bằng màn hình LED 5 x 5
  4. Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
  5. Chúng tôi muốn truyền dữ liệu không dây bằng radio của thiết bị
  6. Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu đó cho phù hợp

Cho phép tôi đi vào chi tiết hơn một chút về từng cái.

1. Chúng tôi muốn kiểm soát các hành động của thiết bị dựa trên trạng thái hiện tại của nó

Giống như hầu hết các chương trình khác, việc thực thi các hướng dẫn được chỉ định bởi mã diễn ra từng dòng một. Chúng tôi muốn thiết bị của mình thực thi các hướng dẫn nhất định dựa trên trạng thái bên trong của nó, như được minh họa bằng sơ đồ ở đầu hướng dẫn này. Chúng tôi có thể viết một loạt các điều kiện sau mỗi khối mã kiểm tra thiết bị nên thực hiện, nhưng cách tiếp cận này có thể rất lộn xộn rất nhanh, vì vậy chúng tôi sẽ sử dụng một vòng lặp vô hạn chỉ đơn giản là kiểm tra một biến và dựa trên biến đó, thực hiện một bộ hướng dẫn cụ thể hoặc không làm gì cả. Biến này sẽ được xác định bằng hậu tố "_state" trong cả ứng dụng người dùng và ứng dụng gốc của chúng tôi.

2. Chúng tôi muốn thiết bị phản ứng với đầu vào của người dùng

Mặc dù việc thực thi mã bình thường diễn ra tuần tự, tức là từng dòng một, chúng ta cần thiết bị của mình phản ứng với các lần nhấn nút trong khi vòng lặp trạng thái chính đang xác định thiết bị phải làm gì tại bất kỳ thời điểm nào. Với mục đích đó, thiết bị có khả năng gửi tín hiệu đến phần mềm cấp thấp hơn tương tác với phần cứng, kích hoạt cái gọi là sự kiện. Chúng ta có thể viết mã yêu cầu thiết bị làm điều gì đó khi nó phát hiện một loại sự kiện cụ thể.

3. Chúng tôi muốn hiển thị hình ảnh động và đồ họa bằng màn hình LED 5 x 5

Cơ chế để thực hiện việc này có vẻ đơn giản, nhưng khối hiển thị hình ảnh thêm độ trễ ẩn là 400 ms. Bởi vì chúng tôi muốn thiết bị của mình tiếp tục thực hiện vòng lặp trạng thái của nó với độ trễ ít nhất có thể, chúng tôi sẽ cần chỉnh sửa mã javascript để giảm thiểu độ trễ.

4. Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động

Trước khi thiết bị của chúng tôi thực hiện bất kỳ điều gì, ứng dụng cần tải dữ liệu của nó vào bộ nhớ. Điều này bao gồm các biến không đổi được đặt tên cho khả năng đọc mã, các biến có chứa hình ảnh, có thể là một phần của hoạt ảnh và các biến đếm cần bắt đầu từ 0 để hoạt động bình thường. Chúng ta sẽ kết thúc với một danh sách dài các tên biến và các giá trị mới được gán của chúng. Là một lựa chọn phong cách cá nhân, tôi sẽ biểu thị các giá trị không đổi, tức là các giá trị mà tôi sẽ không bao giờ cần thay đổi, bằng cách sử dụng ALL_CAPS. Tôi cũng sẽ đặt tiền tố cho số nhận dạng biến chính với tên danh mục đề cập đến một loại đối tượng hoặc loại mà mã định danh nằm trong đó. Điều này nhằm mục đích làm cho mã dễ theo dõi hơn. Tôi sẽ không bao giờ sử dụng một tên biến như "item" hoặc "x" vì sự mơ hồ nảy sinh khi cố gắng giải mã.

5. Chúng tôi muốn truyền dữ liệu không dây bằng radio của thiết bị

Đây thực sự là một nhiệm vụ khá đơn giản khi sử dụng ngôn ngữ khối MakeCode. Chúng tôi chỉ cần đặt tất cả các thiết bị vào cùng một nhóm radio tại thời điểm khởi động và sau đó khi chúng tôi muốn gửi tín hiệu, chúng tôi có thể chuyển một số duy nhất đến khối "Radio send number" được cung cấp cho chúng tôi. Điều quan trọng là người gửi và người nhận đang làm việc trên cùng một nhóm vô tuyến, bởi vì nếu không, họ sẽ gửi hoặc nhận trên các tần số khác nhau và liên lạc sẽ không thành công.

6. Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu đó cho phù hợp

Ghi nhớ những lưu ý tương tự như mục trước, chúng tôi sẽ lắng nghe các đường truyền đến giống như cách chúng tôi sẽ lắng nghe thông tin đầu vào của người dùng: với một trình xử lý sự kiện. Chúng tôi sẽ viết một khối mã sẽ kiểm tra bất kỳ tín hiệu nào đến và kiểm tra xem có hành động nào được thực hiện mà không làm ảnh hưởng đến vòng lặp trạng thái chính hay không.

Ngoài ra, chúng ta nên xem xét ngắn gọn về thiết kế của ứng dụng gốc đơn giản hơn nhiều, một chương trình sẽ cho phép một thiết bị kiểm soát toàn bộ mạng. Tôi sẽ không dành nhiều thời gian cho việc này vì nó đơn giản hơn nhiều so với thiết kế ở trên và phần lớn nó chỉ đơn giản là sự lặp lại. Tôi đã chia chức năng của root deice thành ba loại.

  1. Chúng tôi muốn có thể chọn một tín hiệu
  2. Chúng tôi muốn có thể truyền một tín hiệu

--

1. Chúng tôi muốn có thể chọn một tín hiệu

Điều này có thể được thực hiện bằng cách chỉ cần có một nút lặp qua các tín hiệu có thể. Vì chỉ có ba, cách tiếp cận này sẽ đủ. Đồng thời, chúng ta có thể có một vòng lặp liên tục hiển thị lại tín hiệu đã chọn, cho phép người dùng nhấn một nút và thấy tín hiệu đã chọn xuất hiện trên màn hình LED với độ trễ rất nhỏ.

2. Chúng tôi muốn có thể truyền một tín hiệu

Vì có hai nút, chúng tôi có thể chỉ định một nút để lựa chọn và nút kia để xác nhận. Giống như ứng dụng người dùng, chúng tôi chỉ cần gửi tín hiệu qua mạng dưới dạng một số. Không có thông tin khác được yêu cầu.

Tôi sẽ nói thêm về giao thức tín hiệu đơn giản trong phần tiếp theo.

Bước 2: Giao thức Tín hiệu: Một ngôn ngữ đơn giản cho giao tiếp mạng

Các tín hiệu sau đây có thể được coi là tập hợp của tất cả các từ có thể có mà các thiết bị có thể sử dụng để nói chuyện với nhau. Bởi vì mạng rất đơn giản, không có nhiều điều để nói, và vì vậy chúng ta có thể biểu diễn ba tín hiệu này bằng các giá trị số nguyên đơn giản.

0. Đặt lại

  • Định danh trong mã: SIG-R
  • Giá trị số nguyên: 0
  • Mục đích: Yêu cầu tất cả các thiết bị trong phạm vi ngừng hoạt động và hoạt động như thể chúng vừa được khởi động. Nếu tín hiệu này đến mọi thiết bị trên mạng, toàn bộ mạng sẽ được đặt lại và người dùng có thể bắt đầu trò chơi mới. Tín hiệu này chỉ có thể được phát bởi thiết bị gốc.

1. Chuyển đổi A

  • Định danh trong mã: SIG-A
  • Giá trị số nguyên: 1
  • Mục đích: Báo cho bất kỳ thiết bị nào ở trạng thái LISTEN_A, khi chúng nhận được tín hiệu chuyển đổi, chuyển sang trạng thái TEAM_A.

2. Chuyển đổi B

  1. Định danh trong mã: SIG-B
  2. Giá trị số nguyên: 2
  3. Mục đích: Báo cho bất kỳ thiết bị nào ở trạng thái LISTEN_B, khi chúng nhận được tín hiệu chuyển đổi, chuyển sang trạng thái TEAM_B.

Bước 3: Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó

Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó
Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó
Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó
Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó
Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó
Chúng tôi muốn kiểm soát các hoạt động của thiết bị dựa trên trạng thái hiện tại của nó

Cuối cùng, chúng ta có thể bắt đầu viết mã.

Đầu tiên, hãy mở một dự án mới trong Make Code

  • Tạo một chức năng mới. Tôi gọi là vòng lặp của tôi vì đây là vòng lặp cốt lõi của ứng dụng
  • Thêm một khối vòng lặp sẽ lặp lại vô thời hạn. Tôi đã sử dụng while (true) vì true theo nghĩa đen sẽ không bao giờ là false, do đó luồng điều khiển của ứng dụng sẽ không bao giờ thoát khỏi vòng lặp
  • Thêm đủ các khối if-else để kiểm tra xem thiết bị có ở bất kỳ trạng thái nào trong số năm trạng thái có thể có
  • Tạo một biến để giữ trạng thái thiết bị hiện tại
  • Tạo các biến để đại diện cho từng trạng thái trong số năm trạng thái có thể có

    Lưu ý: Có thể chấp nhận rằng các biến này chưa có bất kỳ giá trị nào được gán. Chúng tôi sẽ đạt được điều đó. Tại thời điểm này, điều quan trọng hơn là chúng ta phải viết mã rõ ràng, dễ đọc

  • Thay đổi từng điều kiện trong các khối if-else để so sánh trạng thái hiện tại với một trong các trạng thái có thể
  • Ở cuối khối if-else, hãy thêm khoảng dừng trong một số mili giây và tạo một biến để giữ số đó. Chúng tôi sẽ khởi tạo nó sau. Đảm bảo rằng biến có tên mô tả, chẳng hạn như đánh dấu hoặc nhịp tim. Bởi vì đây là vòng lặp cốt lõi của thiết bị, khoảng dừng này sẽ quyết định tốc độ thiết bị thực hiện vòng lặp chính, vì vậy nó là một giá trị rất quan trọng, và quá quan trọng là một số ma thuật không có tên.

Lưu ý: Đừng lo lắng về các khối màu xám trong hình ảnh thứ ba. Tôi sẽ đến với những thứ đó sau.

Bước 4: Chúng tôi muốn phản ứng với đầu vào của người dùng

Chúng tôi muốn phản ứng với đầu vào của người dùng
Chúng tôi muốn phản ứng với đầu vào của người dùng
Chúng tôi muốn phản ứng với đầu vào của người dùng
Chúng tôi muốn phản ứng với đầu vào của người dùng

Bây giờ, chúng tôi muốn cho thiết bị biết cách xử lý các lần nhấn nút. Suy nghĩ đầu tiên của người ta có thể chỉ đơn giản là sử dụng các khối "Khi nút được nhấn" trong danh mục đầu vào, nhưng chúng tôi muốn kiểm soát chi tiết hơn thế. Chúng tôi sẽ sử dụng khối "sự kiện trên từ (X) với giá trị (Y)" từ danh mục điều khiển trong phần nâng cao, vì chúng tôi đã nâng cao trong hướng dẫn này.

  • Tạo bốn khối "trên sự kiện từ…".

    • Hai trong số này nên kiểm tra nguồn sự kiện "MICROBIT_ID_BUTTON_A"
    • Hai trong số này nên kiểm tra nguồn sự kiện "MICROBIT_ID_BUTTON_B"
    • Trong số hai sự kiện nhắm mục tiêu mỗi nút:

      • Người ta nên kiểm tra sự kiện thuộc loại "MICROBIT_BUTTON_EVT_UP"
      • Người ta nên kiểm tra sự kiện thuộc loại "MICROBIT_BUTTON_EVT_DOWN"
    • Lưu ý: Các tùy chọn này bằng tất cả các chữ cái in hoa là các nhãn được sử dụng trong mã micro: bit cấp thấp hơn. Chúng chỉ đơn giản là các trình giữ chỗ sau này được thay thế bằng các số nguyên khi mã được biên dịch thành một tệp nhị phân thực thi. Con người sử dụng các nhãn này dễ dàng hơn là tra cứu số nguyên nào cần đưa vào, mặc dù cả hai đều hoạt động theo cùng một cách.
  • Tôi đã chọn, như một vấn đề của phong cách, để mỗi khối "on event from…" gọi một hàm mô tả sự kiện được nêu ra. Mặc dù không hoàn toàn cần thiết, theo tôi điều này cải thiện khả năng đọc. Nếu ai đó muốn làm như vậy, họ có thể đặt mã xử lý sự kiện bên trong chính khối "on event from…".

    Lưu ý: Khối mã xử lý phản hồi của thiết bị đối với một sự kiện được gọi trực quan là "trình xử lý sự kiện"

  • Thêm, trong mỗi trình xử lý sự kiện, cấu trúc if-else tương tự được sử dụng để phân chia luồng điều khiển dựa trên trạng thái thiết bị như cấu trúc trong vòng lặp trạng thái chính.
  • Thêm khối phân công sửa đổi trạng thái đó của thiết bị như được chỉ định bởi sơ đồ trạng thái của chúng tôi

    • Chúng tôi biết rằng khi thiết bị ở trạng thái KHÔNG ĐƯỢC ĐĂNG KÝ, thiết bị sẽ phản ứng với nút A được nhấn bằng cách chuyển sang trạng thái LISTEN_A và đến nút B được nhấn bằng cách chuyển sang trạng thái LISTEN_B
    • Chúng tôi cũng biết rằng khi thiết bị ở trạng thái LISTEN_A hoặc LISTEN_B, thiết bị sẽ phản ứng với nút A được thả ra và nút B được thả ra, tương ứng bằng cách chuyển trở lại trạng thái KHÔNG ĐƯỢC ĐĂNG KÝ.
    • Cuối cùng, chúng ta biết rằng khi thiết bị ở trạng thái TEAM_A hoặc TEAM_B, thiết bị sẽ phản ứng với nút A được nhấn và nút B được nhấn bằng cách phát sóng SIG_A và bằng cách phát sóng SIG_B tương ứng.

      Tại thời điểm này, không cần thiết phải điền vào các chi tiết của tín hiệu phát sóng. Chúng ta sẽ làm điều đó sau. Điều quan trọng là chúng tôi hướng dẫn các hàm này sử dụng mã mà chúng tôi sẽ viết bằng cách đặt tên cho khối hành động đó, như broadcastSignalSIG_A, mô tả những gì nên làm tại thời điểm đó

Bước 5: Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động

Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động
Chúng tôi muốn khởi tạo các giá trị dữ liệu trong bộ nhớ thiết bị khi thiết bị khởi động

Tại thời điểm này, chúng tôi đã sử dụng rất nhiều biến (tên cho dữ liệu), nhưng chúng tôi chưa thực sự gán giá trị cho những tên đó. Chúng tôi muốn thiết bị tải các giá trị của tất cả các biến này vào bộ nhớ khi nó khởi động, vì vậy chúng tôi đặt quá trình khởi tạo cho các biến này trong một khối "khi bắt đầu".

Đây là những giá trị chúng ta phải khởi tạo:

  • Hằng số tín hiệu, theo giao thức tín hiệu. Các giá trị PHẢI là:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Lưu ý: Tôi đã đặt trước các hằng số này bằng "EnumSignals" để biểu thị rằng các biến này sẽ hoạt động như thể chúng là một phần của kiểu liệt kê được gọi là Tín hiệu. Đây là cách các biến này có thể được triển khai trong các ngôn ngữ lập trình khác. Định nghĩa và giải thích về các kiểu liệt kê nằm ngoài phạm vi của hướng dẫn của tôi. Người ta có thể Google nó nếu họ muốn. Các tiền tố này chỉ đơn giản là các lựa chọn theo phong cách và hoàn toàn không cần thiết cho hoạt động bình thường của chương trình.
  • Hằng số trạng thái, có thể tùy ý miễn là chúng có giá trị. Tôi đã thực hiện một lựa chọn kiểu để chỉ sử dụng các số nguyên tăng dần từ 0, như sau:

    • UNASSIGNED = 0
    • LISTEN_A = 1
    • LISTEN_B = 2
    • TEAM_A = 3
    • TEAM_B = 4
    • Lưu ý: Tôi cũng đã đưa ra quyết định kiểu tương tự về tiền tố cho các biến này. Ngoài ra, tôi sẽ đề cập rằng mọi thứ về các phép gán này, các giá trị và thứ tự, là hoàn toàn tùy ý. Thậm chí không có vấn đề gì khi các giá trị này nhất quán từ thiết bị này sang thiết bị khác, bởi vì chúng chỉ được sử dụng nội bộ và không phải để giao tiếp qua mạng. Tất cả những gì quan trọng là các biến có một giá trị và chúng có thể được so sánh với nhau để xem liệu chúng có tương đương hay không.
  • Để dễ đọc, một hằng số được gọi là BOOT_STATE và đặt nó thành UNASSIGNED. Điều này làm cho thực tế là chúng tôi đặt lại về trạng thái khởi động, thay vì trạng thái tùy ý hơn, rõ ràng hơn khi thiết bị nhận được tín hiệu đặt lại, mà chúng tôi sẽ thực hiện sau.
  • Hằng số hoạt ảnh, được sử dụng trong bước sau để tạo hoạt ảnh cho phép gián đoạn độ trễ cực thấp thông qua đầu vào của người dùng. Chúng tôi đã không sử dụng chúng cho đến nay, nhưng chúng chắc chắn sẽ được giải thích và sử dụng trong phần sau. Ý nghĩa của một số trong số này phải trực quan do tên của chúng.

    • TICKS_PER_FRAME_LOADING_ANIMATION = 50
    • MS_PER_DEVICE_TICK = 10
    • MS_PER_FRAME_BROADCAST_ANIMATION = 500
    • MICROSECONDS_PER_MILLISECOND = 1000
    • NUMBER_OF_FRAMES_IN_LOADING_ANIMATION = 4
  • Một biến khác cho hoạt ảnh, lần này là một bộ đếm chắc chắn không phải là hằng số. Giống như hầu hết các bộ đếm, chúng tôi khởi tạo nó thành 0

    iTickLoadingAnimation = 0

  • Tạo hai chuỗi biến để giữ các khung hình ảnh động. Hình đầu tiên, mà tôi gọi là "hoạt ảnh đang tải", phải có bốn hình ảnh (mà bạn có thể đoán được bằng lần khởi tạo liên tục cuối cùng) và hình thứ hai, mà tôi gọi là "hoạt ảnh phát sóng", phải có ba hình ảnh. Tôi khuyên bạn nên đặt tên cho các biến tương ứng với khung của hoạt ảnh, ví dụ: ringAnimation0, ringAnimation1…

    Tạo các giá trị hình ảnh giống như tôi đã làm hoặc tạo nhiều hình ảnh độc đáo và mát mẻ hơn

  • Cuối cùng nhưng không kém phần quan trọng, chúng ta phải đặt nhóm radio của thiết bị thành 0 bằng cách sử dụng khối "radio set group (X)"
  • Theo tùy chọn, viết thông báo "Khởi tạo hoàn tất" vào đầu ra nối tiếp để cho người dùng biết rằng mọi thứ đã diễn ra bình thường.
  • Bây giờ chúng ta đã hoàn tất việc thiết lập thiết bị, chúng ta có thể gọi hàm vòng lặp trạng thái của chúng ta.

Bước 6: Chúng tôi muốn hiển thị hình ảnh động và đồ họa bằng màn hình LED 5 X 5

Chúng tôi muốn hiển thị ảnh động và đồ họa bằng màn hình LED 5 X 5
Chúng tôi muốn hiển thị ảnh động và đồ họa bằng màn hình LED 5 X 5
Chúng tôi muốn hiển thị ảnh động và đồ họa bằng màn hình LED 5 X 5
Chúng tôi muốn hiển thị ảnh động và đồ họa bằng màn hình LED 5 X 5
Chúng tôi muốn hiển thị hình ảnh động và đồ họa bằng màn hình LED 5 X 5
Chúng tôi muốn hiển thị hình ảnh động và đồ họa bằng màn hình LED 5 X 5

Và bây giờ cho một cái gì đó hoàn toàn khác nhau.

Chúng tôi muốn hiển thị một vài hoạt ảnh và một vài ký tự, nhưng chúng tôi không muốn làm gián đoạn vòng lặp trạng thái chính. Thật không may, các khối hiển thị hình ảnh và chuỗi văn bản có độ trễ là 400 ms theo mặc định. Không có cách nào để thay đổi điều này mà không cần chỉnh sửa biểu diễn javascript của mã. Vì vậy, đây là những gì chúng tôi sẽ làm.

  • Tạo một chức năng cho mỗi hình ảnh. Điều này sẽ cho phép người ta sử dụng một khối duy nhất để hiển thị hình ảnh thay vì chỉnh sửa javascript mọi lúc. Trong chương trình cụ thể này, không có hình ảnh nào được sử dụng nhiều hơn một lần, nhưng tôi vẫn nghĩ rằng phong cách này làm cho mã dễ đọc hơn.
  • Thêm, trong mỗi hàm mới, một khối "hiển thị hình ảnh (X) ở độ lệch 0" với tên biến hình ảnh tương ứng thay thế (X)
  • Thêm, trong vòng lặp trạng thái chính. "Hiển thị chuỗi (X)" khối cho mỗi khối bên cạnh khối xử lý trạng thái UNASSIGNED. Thêm một ký tự để thiết bị hiển thị để biểu thị các trạng thái khác nhau của thiết bị. Đây là những gì tôi đã làm:

    • LISTEN_A: 'a'
    • LISTEN_B: 'b'
    • TEAM_A: 'A'
    • TEAM_B: 'B'

      Đối với trạng thái UNASSIGNED, hãy thực hiện lệnh gọi đến một hàm sẽ cập nhật hoạt ảnh đang tải. Chúng tôi sẽ điền thông tin chi tiết của chức năng này vào bên dưới

  • Chuyển sang chế độ javascript.
  • Tìm mọi lệnh gọi tới X.showImage (0) và basic.showString (X)
  • Thay đổi từng cái một thành X.showImage (0, 0) hoặc basic.showString (X, 0)

    • Thêm đối số bổ sung này sẽ đặt độ trễ sau hành động thành 0. Theo mặc định, điều này bị bỏ qua và thiết bị sẽ tạm dừng trong 400 mili giây sau khi thực hiện từng khối này.
    • Bây giờ, chúng tôi có một cơ chế gần như không có độ trễ để hiển thị hình ảnh của chúng tôi trong các khối hoạt ảnh của chúng tôi, hiện chúng tôi có thể xây dựng

Đầu tiên, chúng ta sẽ xây dựng chức năng phát hình ảnh động tương đối đơn giản. Nó đơn giản hơn vì chúng tôi không muốn người dùng có thể làm bất cứ điều gì cho đến khi chức năng hoàn thành, để ngăn họ gửi spam chức năng phát. Để thực hiện điều này, chúng ta có thể chỉ cần giới hạn luồng điều khiển đối với khối cho đến khi chức năng hoàn tất, đó là hành vi tiêu chuẩn.

  • Tạo một chức năng sẽ hiển thị hoạt ảnh phát sóng.
  • Bên trong khối đó, hãy thêm ba lệnh gọi hàm, một vào mỗi khung của hoạt ảnh, theo thứ tự chúng sẽ được hiển thị
  • Thêm khối "đợi (chúng tôi) (X)" sau mỗi lần gọi vào chức năng hiển thị hình ảnh.

    Lưu ý: Khối này, từ phần điều khiển nâng cao, sẽ đi xa hơn "tạm dừng (mili giây)" ở chỗ nó sẽ đóng băng hoàn toàn bộ xử lý cho đến khi hết thời gian quy định. Khi khối tạm dừng được sử dụng, có thể thiết bị sẽ thực hiện các tác vụ khác ở hậu trường. Điều này là không thể với khối chờ

  • Thay thế (X) bằng (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • Hoạt ảnh bây giờ sẽ hoạt động bình thường

Thứ hai, chúng tôi sẽ xây dựng cơ chế hiển thị hoạt ảnh đang tải. Ý tưởng đằng sau việc này là cập nhật màn hình LED ở một khoảng thời gian cụ thể mà chúng tôi xác định trong biến MS_PER_DEVICE_TICK. Giá trị này, độ dài đánh dấu thiết bị, là số mili giây mà thiết bị tạm dừng sau khi hoàn thành mỗi lần lặp lại của vòng lặp trạng thái. Bởi vì giá trị này đủ nhỏ, chúng tôi có thể cập nhật hiển thị một lần trong mỗi lần lặp lại của vòng lặp hiển thị và nó sẽ hiển thị cho người dùng biết rằng hoạt ảnh đang tiến triển liền mạch và khi trạng thái thay đổi, sẽ có rất ít độ trễ giữa đầu vào của người dùng màn hình đang được cập nhật. Bằng cách đếm số tích tắc mà chúng tôi thực hiện với biến iTickLoadingAnimation, chúng tôi có thể hiển thị khung thích hợp của hoạt ảnh.

  • Tạo một hàm sẽ cập nhật hoạt ảnh đang tải
  • Thêm một điều kiện để kiểm tra xem bộ đếm đánh dấu đã đạt đến giá trị lớn nhất hay chưa. Điều kiện này sẽ đúng nếu giá trị của bộ đếm dấu tích lớn hơn số khung hình trong hoạt ảnh đang tải nhân với số dấu tích để hiển thị mỗi khung hình

    Nếu điều kiện là đúng, hãy đặt lại iTickLoadingAnimation về 0

  • Thêm một khối điều kiện if-else. Những điều này sẽ xác định khung nào của hoạt ảnh sẽ hiển thị.

    Đối với mỗi khung của hoạt ảnh, nếu bộ đếm dấu tích nhỏ hơn số dấu tích trong mỗi hoạt ảnh nhân với số khung của hoạt ảnh (bắt đầu từ 1), thì hãy hiển thị khung đó, nếu không, hãy kiểm tra xem khung tiếp theo có phải là khung để được hiển thị

  • Ở cuối khối, tăng iTickLoadingAnimation
  • Hoạt ảnh bây giờ sẽ hoạt động bình thường

Lưu ý: Tất cả các khối màu xám xuất hiện trong ví dụ của tôi được tạo ra khi một người chỉnh sửa biểu diễn javascript của một khối. Nó chỉ đơn giản có nghĩa là khối đại diện cho mã javascript không thể được biểu diễn bằng cách sử dụng bộ khối tiêu chuẩn và phải được chỉnh sửa ở dạng văn bản.

Bước 7: Chúng tôi muốn truyền dữ liệu không dây bằng radio của thiết bị

Chúng tôi muốn truyền dữ liệu không dây bằng radio của thiết bị
Chúng tôi muốn truyền dữ liệu không dây bằng radio của thiết bị

Bước này ngắn hơn nhiều so với bước trước. Trên thực tế, đây có lẽ là bước ngắn nhất trong toàn bộ hướng dẫn này.

Nhớ lại rằng khi chúng tôi lập trình phản ứng của thiết bị với đầu vào của người dùng, tôi có hai khối trong ảnh chụp màn hình không được giải thích trong phần đó. Đây là các cuộc gọi đến các chức năng gửi tín hiệu qua radio. Cụ thể hơn:

  • Trên nút A được nhấn:

    • Nếu thiết bị ở trạng thái TEAM_A:

      Phát tín hiệu SIG_A

  • Trên nút B được nhấn:

    • Nếu thiết bị ở trạng thái TEAM_B

      Phát tín hiệu SIG_B

Tạo các chức năng này nếu chúng chưa tồn tại.

Trong mỗi chức năng:

  • Gọi chức năng phát hình ảnh động. Điều này sẽ chặn mọi thứ khác xảy ra cho đến khi hoàn tất, sẽ trong MS_PER_FRAME_BROADCAST_ANIMATION * 3 = 1,5 giây. Hằng số được nhân với ba vì có ba khung hình trong hoạt ảnh. Điều này là tùy ý và nhiều hơn nữa có thể được thêm vào nếu nâng cấp thẩm mỹ đủ tuyệt vời. Mục đích thứ hai của hoạt ảnh này là ngăn người dùng gửi spam chức năng phát sóng.
  • Thêm khối "số gửi vô tuyến (X)", trong đó hằng số tín hiệu được đề cập trong tên hàm

Đó là tất cả những gì người ta cần để phát qua radio.

Bước 8: Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu theo đó

Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu theo đó
Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu theo đó
Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu theo đó
Chúng tôi muốn nghe và nhận dữ liệu qua radio của thiết bị và xử lý dữ liệu theo đó

Đây là bước cuối cùng để tạo ứng dụng chính.

Chúng tôi sẽ cho thiết bị biết cách xử lý tín hiệu vô tuyến đến. Đầu tiên, thiết bị của chúng tôi sẽ đặt tên cho tín hiệu nhận được. Sau đó, dựa trên giá trị của tín hiệu đó, nó sẽ quyết định hành động cần thực hiện, nếu có.

Ngày thứ nhất:

  1. Tạo một khối mã bắt đầu bằng một khối "trên sóng vô tuyến nhận (X)".
  2. Theo tùy chọn, chỉ định giá trị đã nhận đó cho một biến khác có tên mô tả hơn.
  3. Gọi một hàm sẽ xử lý tín hiệu

Thứ hai, trong chức năng xử lý tín hiệu:

  1. Tạo một khối câu lệnh if-else phân nhánh luồng điều khiển dựa trên giá trị của tín hiệu.
  2. Nếu tín hiệu là SIG_R

    Đặt trạng thái của thiết bị thành BOOT_STATE (đây là lý do tại sao chúng tôi tạo hằng số này trước đó)

  3. Nếu tín hiệu là SIG_A và nếu trạng thái hiện tại là LISTEN_A

    Đặt trạng thái của thiết bị thành TEAM_A

  4. Nếu tín hiệu là SIG_B và nếu trạng thái hiện tại là LISTEN_B

    Đặt trạng thái của thiết bị thành TEAM_B

Đó là nó. Ứng dụng đã hoàn thành.

Bước 9: Thiết bị gốc: Chúng tôi muốn có khả năng chọn tín hiệu

Thiết bị gốc: Chúng tôi muốn có khả năng chọn tín hiệu
Thiết bị gốc: Chúng tôi muốn có khả năng chọn tín hiệu

Bây giờ, chúng ta sẽ viết một ứng dụng đơn giản cho một thiết bị "root", tức là một thiết bị sẽ điều khiển mạng.

Thiết bị này sẽ cần thực hiện hai chức năng:

  • Chúng tôi muốn cho phép người dùng chọn một trong các tín hiệu của chúng tôi
  • Chúng tôi muốn cho phép người dùng phát tín hiệu

Bởi vì đặc điểm kỹ thuật của ứng dụng này là một tập hợp con của ứng dụng trước đó, tôi sẽ đưa ra một cái nhìn tổng quan nhưng tôi sẽ không đi sâu vào chi tiết như tôi đã có trước đây. Hình ảnh trên có chứa mã hoàn chỉnh cho ứng dụng này.

Để cho phép người dùng chọn một tín hiệu:

  1. Khởi tạo 5 biến trong một khối "khi bắt đầu":

    1. Ba tín hiệu (0, 1, 2)
    2. Số lượng tín hiệu (3)
    3. Một biến để giữ tín hiệu hiện được chọn (ban đầu được đặt thành tín hiệu đầu tiên, 0)
  2. Xử lý khi nhấn nút A:

    1. Tăng tín hiệu đã chọn
    2. Kiểm tra xem tín hiệu đã chọn lớn hơn hoặc bằng số lượng tín hiệu

      Nếu vậy, hãy đặt tín hiệu đã chọn thành 0

  3. Sau khối khởi động, chạy vòng lặp "mãi mãi" hiển thị giá trị tín hiệu đã chọn hiện tại mà không có độ trễ

Để cho phép người dùng phát tín hiệu

  1. Đặt nhóm radio thành 0 trong khối "khi bắt đầu"
  2. Xử lý khi nhấn nút B:

    Phát tín hiệu đã chọn bằng khối "số gửi radio (X)"

Đó là nó. Ứng dụng nút gốc cực kỳ đơn giản.

Bước 10: Chúng tôi đã hoàn thành

Chúng tôi đã hoàn thành
Chúng tôi đã hoàn thành

Trên đây là hình ảnh các thiết bị đang chạy ứng dụng. Hai ứng dụng bên phải đang chạy ứng dụng "người dùng" chính và ứng dụng bên trái đang chạy ứng dụng "gốc".

Tôi đã trình diễn trò chơi này tại CS Connections 2018, một hội nghị mùa hè kéo dài một tuần dành cho giáo viên trung học cơ sở và trung học phổ thông về giáo dục khoa học máy tính. Tôi đưa khoảng 40 thiết bị cho các giáo viên và giải thích các quy tắc. Hầu hết đều thấy trò chơi này mang tính giải trí và nhiều người cảm thấy khó hiểu cho đến khi họ tìm ra cách chơi. Cuộc biểu tình ngắn, nhưng chúng tôi thấy trò chơi rất thú vị giữa một đám đông khá đa dạng.

Thông tin thêm về CS Connections 2018 có thể được tìm thấy tại đây.

Đề xuất: