Gra sterowana kamerą - pomaluj płot

19.05.2013 - Filip Mróz
TrudnośćTrudność

Drugi gracz

Pora wprowadzić do gry drugą osobę. Okaże się to dość proste, ponieważ nie zakładamy między graczami dużej interakcji. Z grubsza wystarczy zdublować wszystkie wykonane wcześniej czynności.

Gotowy kod z tej części można znaleźć w paczce ze źródłami w katalogu: Wersja_7_Gracz

Zaczniemy od przystosowania StanGry. Zmieńmy pole gracz na tablicę gracze oraz dodajmy prywatne pole _liczbaGraczy, które będzie się ustawiać przy rozpoczęciu gry:

protected:    
    ($ \dots $)
    int _liczbaGraczy;
public:
    StanGracza gracze[2];
Stany.h

Ustalmy liczbę graczy w metodzie rozpocznijGre, zależnie od tego czy drugi gracz ma ustawioną nazwę:

    $ \dots $
    _graTrwa = true;
    _liczbaGraczy = gracze[1].nazwa.size() != 0 ? 2 : 1;
}
StanGry.cpp

Chcemy pionowo podzielić ekran na dwie części i kazać obydwu graczom pracować tylko nad jego kawałkiem. Ponieważ metody klasy StanGracza korzystają tylko z podanego im Mat, możemy to łatwo zaimplementować. Będziemy przekazywać poszczególnym graczom tylko okno z ich częścią ekranu. Dodajmy do StanGry metody zwracające aktualne okna graczy:

protected:
    Mat oknoGracza1(Mat obraz);
    Mat oknoGracza2(Mat obraz);
Stany.h

Okno gracza pierwszego będzie, w zależności od liczby graczy, całym ekranem lub lewą połówką, drugi gracz to zawsze prawa połowa:

Mat StanGry::oknoGracza1(Mat obraz) {
    if(_liczbaGraczy == 1) return obraz;
    else return Mat(obraz,Range(0,obraz.rows),Range(0,obraz.cols/2));
}
 
Mat StanGry::oknoGracza2(Mat obraz) {
    return Mat(obraz,Range(0,obraz.rows),Range(obraz.cols/2,obraz.cols));
}
StanGry.cpp

Musimy teraz poprawić większość metod klasy StanGry w taki sposób, aby dotyczyły obydwu graczy, jednak z wyliczonymi wcześniej oknami graczy będzie to proste:

$ \dots $
gracze[0].uaktualnijStanGracza(_pozostalyCzasGry - nowyPozostalyCzasGry,oknoGracza1(obraz));
if(_liczbaGraczy==2) gracze[1].uaktualnijStanGracza(_pozostalyCzasGry - nowyPozostalyCzasGry,oknoGracza2(obraz));
$ \dots $
StanGry::uaktualnijStanGry
$ \dots $
gracze[0].wyswietlStanGracza(oknoGracza1(gdzie));
if(_liczbaGraczy==2) gracze[1].wyswietlStanGracza(oknoGracza2(gdzie));
$ \dots $
StanGry::wyswietlStanGry
$ \dots $
Uzytki::dodajWpisDoWynikow(gracze[0].nazwa,gracze[0].stanMalowania.wyznaczPomalowanaCzesc());
if(_liczbaGraczy==2) Uzytki::dodajWpisDoWynikow(gracze[1].nazwa,gracze[1].stanMalowania.wyznaczPomalowanaCzesc());
StanGry::zakonczGre

Kilkanaście linii i już udało nam się dostosować mechanikę gry do istnienia dwóch graczy. Pozostaje nam dopisać wczytywanie obu imion oraz wybór pędzla drugiego gracza.

Na początku programu zapytamy o liczbę graczy i wczytamy ich imiona:

int liczbaGraczy;
printf("Podaj liczbe graczy (1 lub 2): ");
scanf("%d",&liczbaGraczy);
if(liczbaGraczy!=1 && liczbaGraczy !=2) {
    printf("Podano nieprawidlowa liczbe graczy (tylko 1 albo 2).");
    getchar();
    return -1;
}
 
char imionaGraczy[2][100];
for(int i=0;i<liczbaGraczy;i++) {
    printf("Podaj imie gracza %d: ",i+1);
    scanf("%s", imionaGraczy[i]);
    stanGry.gracze[i].nazwa = imionaGraczy[i];
}        
 
#ifdef _WIN32 
$ \dots $
main.cpp

Teraz musimy dodać kalibrację pędzla drugiego gracza. Aby uniknąć kopiowania dużego kawałka kodu, przeniesiemy istniejącą pętlę kalibracyjną do funkcji kalibrujPedzelGracza pobierającą StanGracza jako parametr. Musimy oczywiście zamienić w niej stanGry.gracz na gracz. Wyświetlimy też informacje o tym, który gracz ma się przygotować do kalibracji. Metoda ostatecznie przybierze postać:

void kalibrujPedzelGracza(StanGracza &gracz) {
    kamera >> aktualnyObraz;
    flip(aktualnyObraz,aktualnyObraz,1);
    aktualnyObraz.copyTo(wyswietlanyObraz);
    Uzytki::wypiszTekst(wyswietlanyObraz, gracz.nazwa + "! Wybierz pedzel!",Point(0,25));
    wyswietlZachowujacProporcje(wyswietlanyObraz);
    waitKey(3000);
 
    while(waitKey(100)!=' ') {
        kamera >> aktualnyObraz;
        aktualnyObraz.copyTo(wyswietlanyObraz);
 
        Rect polozenieOkna = Rect(aktualnyObraz.cols/2-ROZMIAR_OKNA_KALIBRACJI,aktualnyObraz.rows/2-ROZMIAR_OKNA_KALIBRACJI,ROZMIAR_OKNA_KALIBRACJI,ROZMIAR_OKNA_KALIBRACJI);
        Mat okno = Mat(aktualnyObraz,polozenieOkna);
        gracz.ustawParametryPedzla(okno);
 
        Mat pikselePedzla = gracz.stanMalowania.przetwarzanieObrazow.wybierzPiksele(aktualnyObraz);
        wyswietlanyObraz.setTo(Scalar(255,0,0),pikselePedzla);
        rectangle(wyswietlanyObraz,polozenieOkna,Scalar(0,255,0),3);
        wyswietlZachowujacProporcje(wyswietlanyObraz);
 
        int liczbaPikseliPedzlaOkno = countNonZero(Mat(pikselePedzla,polozenieOkna));
        int liczbaPikseliPedzla = countNonZero(pikselePedzla);
        if(2*liczbaPikseliPedzlaOkno > liczbaPikseliPedzla) {
            break;
        }
    }
}
main.cpp

Wybór pędzli obydwu graczy za pomocą tej metody jest prosty:

$ \dots $
cvResizeWindow("Maluj plot!", screenX, screenY);
 
kalibrujPedzelGracza(stanGry.gracze[0]);
if(liczbaGraczy==2) kalibrujPedzelGracza(stanGry.gracze[1]);
 
kamera >> aktualnyObraz;
$ \dots $
main.cpp

Jeśli podczas wyznaczania koloru pędzla drugiego gracza automatycznie ustawiany jest kolor pierwszego gracza, to należy w pętli kalibrującej dwukrotnie wczytać obraz z kamery do aktualnyObraz. Pierwsze wywołanie z nieznanego mi powodu potrafi zwrócić obraz poprzedniej kalibracji. Gdyby komuś udałoby się ładnie rozwiązać ten problem, proszę o kontakt.

5
Twoja ocena: Brak Ocena: 5 (2 ocen)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com