Landolt-C Game
Description
This is an mBed implementation of the Landolt-C vision test. The main purpose of this game is to achieve the best score possible. This is done by successfully completing each level. In each level, the player is shown a Landolt-C for a short amount of time, oriented randomly upwards, downwards, leftwards or rightwards. The player is then prompted to input the orientation of the Landolt-C using the pushbuttons. If the user does this correctly, he or she is awarded one point. The game repeats this process at a higher difficulty each time by reducing the size of the Landolt-C and the time it is displayed. If the player cannot guess the orientation of the Landolt-C correctly, the game ends and the player’s score is recorded on a high-score table.
The game features a main menu from which the player can select three different options. First, the player can choose to play the game. Second, the player can choose to view the list of high scores. Lastly, the player can view details about the creators of the game.
The approach taken to implement the game is the following: we used phase variables inside the infinite while loop to display each stage of the game. Images and audio were loaded onto two different micro SD cards, and are used in the different phases. The images were used to display the Landolt-Cs, the watermark, the main menu, the instructions, and the correct/incorrect indicators. The high-scores table was implemented using a bubble-sort algorithm, which is efficient for sorted data.
Pin-out Connections
SD Card Connections
mBed | SD |
---|---|
p5 | d0 |
p6 | SCK |
p7 | DI |
p8 | CS |
GND | GND |
Vout | Vcc |
uLCD Connections
mBed | uLCD |
---|---|
Vu | 5V |
Gnd | Gnd |
Tx=p9 | RX |
Rx=p10 | TX |
P11 | Reset |
Up Pushbutton Connections
mBed | Up Pushbutton |
---|---|
P19 | P1 |
Gnd | P2 |
Down Pushbutton Connections
mBed | Up Pushbutton |
---|---|
P12 | P1 |
Gnd | P2 |
Left Pushbutton Connections
mBed | Up Pushbutton |
---|---|
P15 | P1 |
Gnd | P2 |
Right Pushbutton Connections
mBed | Up Pushbutton |
---|---|
P9 | P1 |
Gnd | P2 |
Audio Amplifier and Speaker Connections
mBed | Audio Amplifier | Speaker |
---|---|---|
p18 | in+ | |
Gnd | in- | |
out+ | + | |
out- | - | |
Gnd | Pwr- | |
Vcc | Pwr+ |
Demo
Program
main.cpp
#include "mbed.h" #include "SDFileSystem.h" #include "uLCD_4DGL.h" #include <algorithm> #include "wave_player.h" void bubbleSort(int arr[], int n) { bool swapped = true; int j = 0; int tmp; while (swapped) { swapped = false; j++; for (int i = 0; i < n - j; i++) { if (arr[i] > arr[i + 1]) { tmp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = tmp; swapped = true; } } } } uLCD_4DGL uLCD(p13, p14, p11); // serial tx, serial rx, reset pin; SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card DigitalIn pbUp(p19); DigitalIn pbLeft(p15); DigitalIn pbDown(p12); DigitalIn pbRight(p9); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); AnalogOut DACout(p18); //Global Variables wave_player waver(&DACout); int phase = 0; int level = 1; int score = 0; int correctAns = -1; int ans = -1; bool isCorrect = false; bool lost = false; float waitTime = 1.0; int homepage = 0; int instruction = 0; int highScores [10]; int flag = 0; int main() { //Initialize Sound Variables FILE *sound_start; for (int i = 0; i < 10; i++){ highScores[i] = 0; } pbUp.mode(PullUp); pbLeft.mode(PullUp); pbRight.mode(PullUp); pbDown.mode(PullUp); while(1) { sound_start=fopen("/sd/mydir/start.wav","r"); if (phase == 0) { //Display Watermark uLCD.cls(); uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x86DB); uLCD.display_image(0,0); waver.play(sound_start); wait(1.0); uLCD.cls(); phase = 1; } else if (phase == 1) { //Homepage if(homepage == 0){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8618); uLCD.display_image(0,0); if (pbUp < 0.5) { homepage = 2; } else if (pbDown < 0.5) { homepage = 1; } else if (pbRight < 0.5) { phase = 2; uLCD.cls(); } } if(homepage == 1){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8659); uLCD.display_image(0,0); if (pbUp < 0.5) { homepage = 0; } else if (pbDown < 0.5) { homepage = 2; } else if (pbRight < 0.5) { phase = 7; uLCD.cls(); } } if(homepage == 2){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x869A); uLCD.display_image(0,0); if (pbUp < 0.5) { homepage = 1; } else if (pbDown < 0.5) { homepage = 0; } else if (pbRight < 0.5) { phase = 8; } } } else if (phase == 2) { if(instruction == 0){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8596); uLCD.display_image(0,0); } else if(instruction == 1){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x85D7); uLCD.display_image(0,0); } else if (instruction == 2){ uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n Get Ready "); wait(1.0); uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n 3"); wait(1.0); uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n 2"); wait(1.0); uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n 1"); wait(1.0); uLCD.cls(); phase = 3; } if (pbRight < 0.5){ instruction++; } if(instruction > 0){ if (pbLeft < 0.5){ instruction--; } } } else if (phase == 3) { waitTime = waitTime / level; correctAns = rand() % 4 + 1; if(level < 5){ switch(correctAns) { case 1 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x83CF); uLCD.display_image(0,0); break; case 2 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8145); uLCD.display_image(0,0); break; case 3 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8000); uLCD.display_image(0,0); break; case 4 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x828A); uLCD.display_image(0,0); break; } } else if(level > 4 && level < 9){ switch(correctAns) { case 1 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8410); uLCD.display_image(0,0); break; case 2 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8186); uLCD.display_image(0,0); break; case 3 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8041); uLCD.display_image(0,0); break; case 4 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x82CB); uLCD.display_image(0,0); break; } } else if(level > 8 && level < 13){ switch(correctAns) { case 1 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8451); uLCD.display_image(0,0); break; case 2 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x81C7); uLCD.display_image(0,0); break; case 3 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8082); uLCD.display_image(0,0); break; case 4 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x830C); uLCD.display_image(0,0); break; } } else if(level > 12 && level < 17){ switch(correctAns) { case 1 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8492); uLCD.display_image(0,0); break; case 2 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8208); uLCD.display_image(0,0); break; case 3 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x80C3); uLCD.display_image(0,0); break; case 4 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x834D); uLCD.display_image(0,0); break; } } else if(level > 16){ switch(correctAns) { case 1 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x84D3); uLCD.display_image(0,0); break; case 2 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8249); uLCD.display_image(0,0); break; case 3 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8104); uLCD.display_image(0,0); break; case 4 : uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x838E); uLCD.display_image(0,0); break; } } wait(waitTime); uLCD.cls(); phase = 4; } else if (phase == 4) { //Display guess uLCD.printf("\n\n\n\n\n\n\n Take your guess. \n\n\n\n\n\n\n\n"); if (pbUp < 0.5) { ans = 1; } else if (pbLeft < 0.5) { ans = 2; } else if (pbDown < 0.5) { ans = 3; } else if (pbRight < 0.5) { ans = 4; } if (ans > 0) { if (ans == correctAns) { isCorrect = true; } else { isCorrect = false; } phase = 5; } } else if (phase == 5) { uLCD.cls(); ans = -1; if (isCorrect) { //Display correct check mark uLCD.cls(); uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8514); uLCD.display_image(0,0); waver.play(sound_start); wait(1.0); uLCD.cls(); } else { //Display incorrect x uLCD.cls(); uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x8555); uLCD.display_image(0,0); wait(2.0); uLCD.cls(); lost = true; } score = level - 1; level++; ans = -1; correctAns = -1; if (lost) { phase = 6; } else { phase = 2; } } else if (phase == 6) { if(score > highScores[0]){ highScores[0] = score; bubbleSort(highScores,10); } if(score >= highScores[9]){ uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n New record of %D! ", score); } else{ uLCD.cls(); uLCD.printf("\n\n\n\n\n\n\n Score: %D ", score); } wait(5.0); level = 1; phase = 1; score = 0; lost = false; waitTime = 1.0; instruction = 0; homepage = 0; } else if (phase == 7){ if(flag == 0){ uLCD.printf("\n High Scores \n"); for(int i = 9; i > -1; i--){ uLCD.printf("%2d. %2d\n",(10-i),highScores[i]); } flag = 1; } if((pbUp < 0.5) || (pbDown < 0.5) || (pbLeft < 0.5) || (pbRight < 0.5)){ phase = 1; homepage = 0; flag = 0; } } else if (phase == 8){ uLCD.media_init(); uLCD.set_sector_address(0x003B, 0x871C); uLCD.display_image(0,0); if((pbUp < 0.5) || (pbDown < 0.5) || (pbLeft < 0.5) || (pbRight < 0.5)){ phase = 1; homepage = 0; } } fclose(sound_start); } }
Import programlandolt
mBed implementation of the Landolt-C vision test. The main purpose of this game is to achieve the best score possible. This is done by successfully completing each level. In each level, the player is shown a Landolt-C for a short amount of time, oriented randomly upwards, downwards, leftwards or rightwards. The player is then prompted to input the orientation of the Landolt-C using the pushbuttons. If the user does this correctly, he or she is awarded one point. The game repeats this process at a higher difficulty each time by reducing the size of the Landolt-C and the time it is displayed.
Please log in to post comments.