A wygląda to tak:
Krótki opis działania
Jest to zabawka sterowana RCX 2.0 z podłączonymi doń dwoma silnikami, czujnikiem dotyku i czujnikiem światła. Zabawa polega na tym by napędzana dwoma silnikami łapka, trafiła gracza w dłoń. Na początku uruchamiamy program. Łapka wędruje do góry i w tej pozycji zostaje do momentu aż gracz umieści swoją dłoń obok fotokomórki, umieszczonej na prostopadłym wysięgniku. W pomieszczeniach z dość "zdradliwym" oświetleniem stosuje się też drugi wysięgnik z czarną płytką, tak by fotokomórka widziała wciąż ciemne tło, jeśli nie ma obok niej dłoni. Umieszczenie kończyny obok fotokomórki sygnalizowane jest dźwiękiem. Wykorzystałem tu fakt, że ręka jest sporo jaśniejsza niż tło i z bliskiej odległości daje duże odbicie, co jest wykrywane przez czujnik. Od tej pory czekamy od 0 do 5 sekund. Czas ten generowany jest losowo. Bez ostrzeżenie łapka spada. Gdy trafi nas w dłoń, umieszczony na niej czujnik dotyku zostaje zwolniony i wyczuwany jest kontakt z przeszkodą, co sygnalizuje dźwięk. Zabawka zyskuje punkt. Jeśli unikniemy zderzenia, to my ten punkt zdobędziemy, a na tę okazję przygotowałem inny sygnał dźwiękowy. Jeśli w czasie, od umieszczenie dłoni w pobliżu fotokomórki do opuszczenia ramienia, usuniemy rękę z pola widzenia czujnika, zabawka uznaje, że tę rundę wygrała, ponieważ gracz pozwolił sobie na falstart. Opuszcza wtedy powoli ramię po czym podnosi je znów gotowa do kolejnej rundy. Gra się do 5 punktów, a wynik wyświetlany jest na wyświetlaczu w postaci wartość z kropką, np: 3.2, co oznacza 3 do 2. Jak wiemy RCX umie wyświetlać tylko liczby naturalne i to był jedyny sposób na pokazanie punktacji obu rywali. Pierwsza wartość oznacza punkty gracza.
Gra, jak już wcześniej wspomniałem kończy się wraz ze zgromadzeniem, bądź to przez gracza, lub zabawkę, pięciu punktów. Rozgrywkę kończy smutna, w przypadku wygranej "bijki", lub wesoła melodia, jeśli wygra gracz.
Model budowałem jakieś 6 godzin. Dziwne że aż tak długo. Chciałem jednak by był bardzo mocny. Ramię napędzają dwa silniki z przełożeniem 1:1, czyli przez dwa średnie koła zębate co widać tutaj. Może niektórzy uznają, że przełożenie 1:3 byłoby jeszcze szybsze. Nic z tych rzeczy - wtedy mamy bardzo wolny start, a poza tym silniki nie mają siły podnieść ramię.
Łapka ma wbudowany czujnik dotyku, co widać tutaj. Guzik jest wciśnięty przez mały klocek dociskany gumką. Gdy łapka trafi w dłoń guzik jest zwalniany a dotknięcie to jest wyczuwane. Guzik nie pracuje w trybie 0,1. Podczas gwałtownego startu bardzo często wyczuwane byłoby jego zwolnienie, zatem zastosowałem tu tryb pracy "ciągłej", czyli w zakresie od 0 do 1024 (teoretycznie). A tak wygląda całe ramię.
Na wysięgniku jest fotokomórka. Podczas uruchamiania programu bada "siłę" światła w pomieszczeniu i traktuje ją jako wzorcową do tej potyczki. Gdy zbliżymy rękę porówna aktualny odczyt z wzorcowym i jeśli różnica będzie większa niż 35 jednostek wtedy zacznie rundę. Po cofnięciu ręki przez gracza, sprawdza czy przypadkiem odczyt nie jest większy niż wzorcowy i uznaje, że gracz zrobił falstart. Działa to w 95% przypadków. Czasami kanciarzom udaje się nie dostać kary. Podczas jednej gry nie wolno przestawiać zabawki, bo odczyty światła będą inne.
Po co dałem te zwinięte kable u góry? Po to, by ramię na nich hamowało i nie burzyło konstrukcji. Po spadku łapka łapana jest przez gumkę.
I to chyba tyle. Tu są pozostałe zdjęcia:
1, 2, 3, 4.
A TU JEST FILM. Grał mój kolega z pracy. Przegrał 3:5. Proszę wybaczyć to, że obraz jest obrócony. Plik ma ok. 9 mb.
Smacznego.
PS. Może komuś się przyda. Zamieszczam tu kod.
Kod: Zaznacz cały
///// Autor - Arkadiusz Kalecinski /////
////////////////////////////////////////
int czekanie, punkt_komp, punkt_gracz, wynik, naturalny_poziom_swiatla;
#define NOTETIME 10
#define WAITTIME 10
task podnies() // podnoszenie ramienia
{
PlaySound(SOUND_LOW_BEEP);
Wait(150);
ClearTimer(0);
while (Timer(0)<10) // podnosci powoli, tak by nie odbiło na końcu i z powrotem spadło
{
OnRev(OUT_A+OUT_C);
Wait(2);
Off(OUT_A+OUT_C);
Wait(1);
}
Off(OUT_A+OUT_C);
start opusc;
}
task opusc()
{
while (true)
{
if (SENSOR_2 <naturalny_poziom_swiatla-35) // zacznie działać dopiero gdy czujnik swiatła wyczuje rękę (czyli jasniejsze tło)
{
czekanie = Random(500); // czeka od 0 s do 5 s )
PlayTone(240, 5);
Wait(10);
PlayTone(340, 5);
start sprawdz; // sprawdza czy ręka nie została cofnięta przed czasem
Wait(czekanie);
start dotyk; // sprawdza czy nie dotnieto czujnika dotyku podczas opuszcza ramienia
stop sprawdz;
OnFwd(OUT_A+OUT_C);
Wait(30);
stop dotyk;
Off(OUT_A+OUT_C);
punkt_gracz = punkt_gracz+1;
PlayTone(175,NOTETIME); // jeśli gracz cofnał rękę w porę zagra mu melodyjkę
Wait(WAITTIME);
PlayTone(220,NOTETIME);
Wait(WAITTIME);
PlayTone(262,NOTETIME);
Wait(WAITTIME);
start punkty;
stop opusc;
}
}
}
task dotyk() // sprawdza czy podczas opadania ramienia ramię nie uderzyło w dłoń gracza
{
while (true)
{
if (SENSOR_1>700)
{
PlaySound(SOUND_DOUBLE_BEEP);
punkt_komp = punkt_komp+1;
Float(OUT_A+OUT_C);
stop opusc;
start punkty;
stop dotyk;
}
}
}
task sprawdz() // sprawdza czy reka wciaz jest trzymana przy sensorze
{
while (true)
{
if (SENSOR_2>=naturalny_poziom_swiatla)
{
stop opusc;
stop dotyk;
punkt_komp = punkt_komp+1;
PlaySound(SOUND_DOUBLE_BEEP);
PlaySound(SOUND_DOUBLE_BEEP);
Wait(200);
OnFwd(OUT_A+OUT_C); // opuszcza powoli ramię
Wait(5);
Off(OUT_A+OUT_C);
start punkty;
stop sprawdz;
}
}
}
task punkty() // sprawdza ile jest zdobytych punktow i przerywa gre jesli ktos zgromadzil 5
{
if ((punkt_gracz==5) || (punkt_komp==5))
{
wynik = punkt_gracz*10 + punkt_komp;
Wait(50);
if (punkt_gracz==5) // gracz wygrał
{
PlayTone(175,NOTETIME);
Wait(WAITTIME);
PlayTone(220,NOTETIME);
Wait(WAITTIME);
PlayTone(262,NOTETIME);
Wait(WAITTIME);
PlayTone(330,NOTETIME);
Wait(WAITTIME);
PlayTone(392,NOTETIME);
Wait(WAITTIME);
PlayTone(494,NOTETIME);
Wait(WAITTIME);
PlayTone(587,NOTETIME);
Wait(WAITTIME);
PlayTone(523,NOTETIME);
Wait(WAITTIME);
PlayTone(659,NOTETIME);
Wait(WAITTIME);
PlayTone(659,NOTETIME);
Wait(WAITTIME);
}
else // komputer wygrał
{
PlayTone(123,4*NOTETIME);
Wait(4*WAITTIME);
PlayTone(49,4*NOTETIME);
Wait(4*WAITTIME);
PlayTone(65,4*NOTETIME);
Wait(4*WAITTIME);
}
StopAllTasks();
}
else
{
wynik = punkt_gracz*10 + punkt_komp;
Wait(200);
start podnies;
stop punkty;
}
}
task wyswietl_punkty() // co 1/10 s wyswietla na wyswietlaczu aktualny wynik (liczba dwucyfrowa z przecinkiem)
{
while (true)
{
SetUserDisplay(wynik,1);
Wait(10);
}
}
task main()
{
punkt_komp = 0;
punkt_gracz = 0;
wynik=0;
naturalny_poziom_swiatla = SENSOR_2;
start wyswietl_punkty;
SetSensorType(SENSOR_1, SENSOR_TYPE_TOUCH);
SetSensorMode(SENSOR_1, SENSOR_MODE_RAW);
SetSensorType(SENSOR_2, SENSOR_TYPE_LIGHT);
SetSensorMode(SENSOR_2, SENSOR_MODE_RAW);
start podnies;
}