ATtiny85ミニアーケード:スネーク
コンポーネントと消耗品
> |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
必要なツールとマシン
> |
| |||
|
アプリとオンラインサービス
> |
| |||
|
このプロジェクトについて
インスピレーションと過去のプロジェクト
2017年12月に、ArduinoNanoとOLED画面と2つのボタンを使用したハンドヘルドArduinoPongコンソールを作成しました。
<図>当時はこれで問題ありませんでしたが、コンソールが少し大きすぎて面倒でした。しかし最近、私は過去のプロジェクトのいくつかを再現しようとしています。今回は、人々がヘビをプレイできる非常に小さなコンソールを作りたかったのです。
<図>
選択したコンポーネント
コンソールを小さくするために、Arduino開発ボードを使用できませんでした。そのため、ATtiny85を使用しました。
<図>2つのADCピンとI2Cポート、およびGPIOピンを含む、ゲームを実行するのに十分なI / Oを備えています。インターフェースが簡単で、シグナリングに必要なピンが3つしかないため、シンプルな2軸ジョイスティック/スイッチモジュールを使用することにしました。
<図>最後に、どのディスプレイが必要かを決定する時が来ました。 DFRobotの128x 64 OLED画面は小さいサイズですが、十分な解像度があるので、私はそれを使用しました。
<図>
システムのはんだ付け
まず、ATtiny85をSOP-8からDIP-8のブレークアウトPCBに取り付け、それを小さなパフォーマンスボードにはんだ付けしました。次に、プログラミング用と画面用の2つのヘッダーをはんだ付けしました。その後、アナログジョイスティックのピンをパフォーマンスボードに接続し、それに応じて配線しました。最後のステップとして、マイクロUSBブレークアウトボードをシステムの残りの部分に配線して電力を供給しました。
<図> <図>
エンクロージャーの設計
エンクロージャーはFusion360で設計されました。最初に、実際のビルドで使用したコンポーネントを作成してレイアウトし、次にそれらの周りにエンクロージャーを作成しました。
<図> <図>80年代のアーケードボックスを模倣したかったのですが、それでも非常に小さいサイズを維持しています。以下は、エンクロージャーのレンダリングです。
<図> <図>
ゲームのプログラミング
ヘビはプログラミングがかなり簡単なゲームです。 RAMを節約するために、ヘビの最大長を30に設定しました。つまり、ヘビが29ピクセルを食べると、プレーヤーが勝ちます。ヘビのセグメントを追跡するために、各セグメントの順序対を格納する2次元配列を作成しました。
<図>頭が新しい場所に移動するたびに、その前の位置は下にカスケードされます。セグメントが消費されるたびに、ランダムなポイントで新しいセグメントが生成されます。衝突チェックは、各セグメントの座標を反復処理し、頭の座標が同じであるかどうかを確認することによって行われます。さらに、壁のいずれかに沿ってヘビを打つと、プレーヤーも負けます。
<図>
ヘビを再生する
私はコンソールの電源を入れ、画面が食べ物とヘビの最初のセグメントにロードされるのを待つことから始めました。次に、食べ物を食べるのを見ながら、ジョイスティックを正しい方向に動かして、ヘビを操縦しました。このゲームはプレイするのが楽しく、小さなパッケージで退屈しのぎを殺すのに最適です。
<図> コード
- ATTiny85コード
ATTiny85コード C / C ++
必ず最初にU8g2libをインストールしてください//#include#include U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g(U8G2_R0、/ * clock =/ 2、/ data =/ 0、/ reset =* / U8X8_PIN_N; #define MAX_LENGTH 30 // 30セグメントmax#define X 0#define Y 1#define JOYSTICK_X 2#define JOYSTICK_Y 3#define DIR_THRESH 300 //値は0-300または723-1023のいずれかである必要があります。countuint8_tsegmentPositions[MAX_LENGTH] [ 2]; uint8_t headPosition [2] ={63、31}; //ヘビをstartuint8_tの最初に配置しますfoodPosition [2]; //食べ物が置かれている場所uint8_ttempPosition0 [2]; // nextuint8_tに渡す前のセグメントの位置を保存しますtempPosition1 [2]; // nextintに渡す前のセグメントの位置を格納しますsegmentLength =1; void gameUpdate(); enum DIRECTIONS {RIGHT、DOWN、LEFT、UP} currentDirection; void setup(){// TinyWireM.begin(); u8g.begin(); u8g.setPowerSave(0); pinMode(JOYSTICK_X、INPUT); pinMode(JOYSTICK_Y、INPUT); randomSeed(analogRead(0)); beginGame();} void loop(){u8g.firstPage(); {gameUpdate();を実行します。 u8g.setColorIndex(1); } while(u8g.nextPage());} void beginGame(){currentDirection =RIGHT; spawnFood(); delay(1000);} bool checkCollisions(){for(int i =1; i =128)return 1; else if(headPosition [Y] <=0 || headPosition [Y]> =64)return 1; falseを返します;} void spawnFood(){int randomX =random(5、123); int randomY =random(5、60); foodPosition [X] =randomX; foodPosition [Y] =randomY;} void checkFoodEaten(){if(headPosition [X] ==foodPosition [X] || headPosition [Y] ==foodPosition [Y]){segmentLength + =1; spawnFood(); }} void updateDirection(){int joy_x_val =analogRead(JOYSTICK_X); int joy_y_val =analogRead(JOYSTICK_Y); if(joy_x_val <=DIR_THRESH)currentDirection =LEFT; else if(joy_x_val> =1023-DIR_THRESH)currentDirection =RIGHT; else if(joy_y_val <=DIR_THRESH)currentDirection =UP; else if(joy_y_val> =1023-DIR_THRESH)currentDirection =DOWN;} void displaySegments(){for(int segment =0; segment =MAX_LENGTH)endGame(); delay(50);} void endGame(){segmentLength =1; headPosition [0] =63; headPosition [1] =31; beginGame();}
カスタムパーツとエンクロージャー
回路図
製造プロセス