Pomoc z projektem Snake - Poruszanie Wężem (praca na ncurses.h)

0

Witam,

Potrzebuję zrobić grę Snake. Dostałem 8 plików od profesora z uczelni, do których mam dodać własne funkcje / klasy itd w celu stworzenia Snake'a.
W plikach są stworzone już klasy, porobione dziedziczenia itd. Musiałem zrozumieć podany kod i dodać do niego tworzenie węża, a następnie zrobić poruszanie wężem itd.

Niestety na początku mam problem.

Zrobiłem "proste" wypisanie węża. Wąż jest jako string (później planuję zrobić wszystko na kontenerach oczywiście ale najpierw potrzebuję poruszania wężem).
Następnie funkcja handleEvent() musi posłużyć za poruszanie wężem.
Niestety gdy próbuję cokolwiek zrobić z wypisywaniem to nic się nie dzieje. Sama funkcja działa, bo porusza całym polem gry - ale to dlatego, że używam funkcji Move, która jest własnie od tego chyba żeby całymi obiektami poruszać, a sam mój string nie jest obiektem.

Wiem, że to już "większy" projekt i wymaga jakiejś znajomości biblioteki ncurses.h ale może ktoś miałby trochę czasu na pomoc? Jest to naprawdę ważne, bo goni mnie termin, a nie mogę przejść przez ten etap :/
Nagradzam lajkami każdą pomoc!

Główne dwa pliki w których mam pracować: snake.cpp i snake.h
paczka plików z projektem: (Dosłownie 5kb)
https://mega.nz/#!jdFDSSZY!dMvtmHqGqIwQOJnqcWec1rx0h_LgWhRDsjYfiwgm9io

Virustotal żeby nie było:
https://www.virustotal.com/#/file/d6b824d8ee31713ddc3dcde01fc0927a90e732a11f4ce3a54fc9f9590284323e/detection

Dodam tutaj kod snake.cpp i snake.h, bo może tylko w nich leży mój błąd?

Snake.h:

#ifndef __SNAKE_H__
#define __SNAKE_H__

#include "winsys.h"

class Snake:public FramedWindow
{
private:
   string snek;
   string snek2;
public:
  Snake(Rect r, char _c = ' ');

  void paint();
  bool handleEvent(int key);
  //bool test(int key);

};

#endif

Snake.cpp:

#include "snake.h"
#include "screen.h"
#include "point.h"
#include <time.h>
#include <unistd.h>
//Snake w wyznaczonym polu gry
Snake::Snake(Rect r, char _c /*=' '*/):
  FramedWindow(r, _c)
{
}

void Snake::paint()
{
    snek="Dupa Dupa";
    FramedWindow::paint();
    int x = geom.size.y+geom.topleft.x;
    int y = geom.size.y;
    unsigned int xx=0;

//wypisanie snek w centrum pola gry
    gotoyx(y, x);
    for(xx=0;xx<snek.size() ; xx++)
    printl("%c", xx < snek.size() ? snek[xx] : c);

 //  for(xx=0;xx<snek.size() ; xx++)
 //  mvprintw(y+5,x+xx,"%c",xx < snek.size() ?snek[xx]: c);

}

bool Snake::handleEvent(int key)  //handleEvent na w,s,a,d
{
//to nie działa dla 'w'. Żadnej reakcji w programie, a miało wypisać snek2 w centrum pola gry.
    int x = geom.size.y+geom.topleft.x;
    int y = geom.size.y;
    unsigned int xx=0;
    snek2="TEST TEST";
  switch (key)
    {
    case 'w':
      gotoyx(y, x);
      for(xx=0;xx<snek2.size() ; xx++)
      printl("%c", xx < snek2.size() ? snek2[xx] : c);
      return true;

    case 's':
      move (Point (0, 10));  //to jest funkcja przesuwająca obiekty zadeklarowana w pliku winsys.h z deklaracją w winsys.cpp linia 11

      return true;
    case 'd':
      move (Point (10, 0));

      return true;
    case 'a':
      move (Point (-10, 0));

      return true;
    };
  return false;
}

1

Na początek:

  • w Snake zdefiniuj współrzędne głowy węża.
  • w paint() narysuj węża zaczynając od podanych współrzędnych.
  • w handleEvent() zmieniaj te współrzędne.
0

Współrzędne głowy węża powinny być najpierw na środku pola gry. A to są współrzędne środka:

    int x = geom.size.y+geom.topleft.x;
    int y = geom.size.y;

W paint() za wypisanie stringa w tych współrzędnych użyłem:

    gotoyx(y, x);  //przejscie do wspolrzednych
    for(xx=0;xx<snek.size() ; xx++)
    printl("%c", xx < snek.size() ? snek[xx] : c);

I to jeszcze działa poprawnie.

Jedynie handleEvent() nie działa poprawnie, a probowałem już wielu kombinacji ;/

W pliku point.h jest struktura Point. Może jej w tym użyć? Tylko nie wiem jak ;/

1

W paint() i w handleEvent() definiujesz zmienne lokalne tych metod. One nawzajem się nie widzą, pojawiają się w momencie zadeklarowania i znikają na końcu tych metod.
Zrób je właściwościami Snake, wspólnymi dla całego obiektu.

    int x = geom.size.y+geom.topleft.x;
    int y = geom.size.y;

To nie są współrzędne środka.

0

Snake.h:

#ifndef __SNAKE_H__
#define __SNAKE_H__

#include "winsys.h"

class Snake:public FramedWindow
{
private:

public:
  Snake(Rect r, char _c = ' ');
  void paint();
  bool handleEvent(int key);
  //bool test(int key);
  string snek = "O";
  string snek2 = "TEST";
  unsigned int xx=0;
  int x = geom.size.y+geom.topleft.x;
  int y = geom.size.y;
};



#endif

Snake.cpp

#include "snake.h"
#include "screen.h"
#include "point.h"
#include <time.h>
#include <unistd.h>
//Snake w wyznaczonym polu gry
Snake::Snake(Rect r, char _c /*=' '*/):
  FramedWindow(r, _c)
{
}

void Snake::paint()
{
    FramedWindow::paint();
    
    gotoyx(y, x-15);
    for(xx=0;xx<snek.size() ; xx++)
    printl("%c", xx < snek.size() ? snek[xx] : c);

    for(xx=0;xx<snek.size() ; xx++)
    {
       gotoyx(y+xx, x);
       printl("%c", xx < snek.size() ? snek[xx] : c);
    }
    
   //for(xx=0;xx<snek.size() ; xx++)
   //mvprintw(y+5,x+xx,"%c",xx < snek.size() ?snek[xx]: c);

}

bool Snake::handleEvent(int key)  //handleEvent na w,s,a,d
{

  switch (key)
    {
    case 'w':
      
      gotoyx(y+5, x+5);
      for(xx=0;xx<snek.size() ; xx++)
      printl("%c", xx < snek.size() ? snek[xx] : c);
      return true;

    case 's':
      move (Point (0, 10));

      return true;
    case 'd':
      move (Point (10, 0));

      return true;
    case 'a':
      move (Point (-10, 0));

      return true;
    };
  return false;
}


Dałem zmienne do klasy. Ale handleEvent niestety dalej nie działa poprawnie :/
W innych plikach nic nie zmieniałem.

1
wiezaawieza napisał(a):

... Musiałem zrozumieć podany kod i dodać do niego tworzenie węża, a następnie zrobić poruszanie wężem itd.

Niestety na początku mam problem.

Zrobiłem "proste" wypisanie węża. ...

Możesz wrócić na początek i nie opuszczać poszczególnych kroków?

0

Każdą funkcję w plikach starałem się zrozumieć i dodałem po bokach komentarze żeby łatwiej było mi się poruszać. Nie są one napisane przeze mnie więc jest mi dosyć ciężko.
Pierwszym krokiem, który musiałem zauważyć i zrozumieć było dziedziczenie - pierwszy raz tego używam w programie. Następnie doszły do tego funkcje wirtualne, które też pierwszy raz używam.
No więc teraz wiem, że dla mojej klasy Snake mam zrobić funkcje paint i handleEvent.

Tworzenie węża będzie trzeba rozbudować mocno ale najpierw chciałbym wiedzieć jak poruszać stringiem po polu gry. Później to poruszanie łatwiej by mi było zrobić dla całego ciała węża.

Mógłbys powiedzieć na co mam zwrócić uwagę, co wykorzystać, a ja będę próbował przez kolejne 8 godzin i jutrzejszy dzień. Małymi kroczkami ale do przodu :/ Jestem jednym z użytkowników którzy zakładają tematy na kilka stron

//Jeej po 3 godzinach na coś wpadłem.

#include "snake.h"
#include "screen.h"
#include "point.h"
#include <time.h>
#include <unistd.h>
//Snake w wyznaczonym polu gry
Snake::Snake(Rect r, char _c /*=' '*/):
  FramedWindow(r, _c)
{
}

void Snake::paint()
{
    FramedWindow::paint();

    gotoyx(y, x-15);
    for(xx=0;xx<snek.size() ; xx++)
    printl("%c", xx < snek.size() ? snek[xx] : c);

    for(xx=0;xx<snek.size() ; xx++)
    {
       gotoyx(y+xx, x);
       printl("%c", xx < snek.size() ? snek[xx] : c);
    }

   //for(xx=0;xx<snek.size() ; xx++)
   //mvprintw(y+5,x+xx,"%c",xx < snek.size() ?snek[xx]: c);

}

bool Snake::handleEvent(int key)  //handleEvent na w,s,a,d
{

  switch (key)
    {
    case 'w':
       y--;
      gotoyx(y, x);
      for(xx=0;xx<snek.size() ; xx++)
      printl("%c", xx < snek.size() ? snek[xx] : c);
      return true;

    case 's':
      y++;
     gotoyx(y, x);
     for(xx=0;xx<snek.size() ; xx++)
     printl("%c", xx < snek.size() ? snek[xx] : c);

      return true;
    case 'd':
      x++;
     gotoyx(y, x);
     for(xx=0;xx<snek.size() ; xx++)
     printl("%c", xx < snek.size() ? snek[xx] : c);

      return true;
    case 'a':
      x--;
     gotoyx(y, x);
     for(xx=0;xx<snek.size() ; xx++)
     printl("%c", xx < snek.size() ? snek[xx] : c);

      return true;
    };
  return false;
}


Środek pola gry:

  int x = geom.topleft.x + geom.size.x/2;
  int y = geom.topleft.y+geom.size.y/2;


Już tekst się porusza wciskajac w, s, a , d w poprawne strony :)

0
  for(xx=0;xx<snek.size() ; xx++)
    printl("%c", xx < snek.size() ? snek[xx] : c);

W pętli xx zawsze będzie mniejsze niż snek.size() bo sama pętla to sprawdza.
Nie wyświetlaj węża w samym handleEvent() tylko zmień współrzędne i wywołaj paint().

W paint() rysujesz go dwukrotnie?

Zmień układ klas:
Po klasie FrameWindow niech dziedziczy klasa np: GameWindow i tak klasa niech ma w sobie obiekt klasy Snake. W ten sposób rozdzielisz trochę logikę aplikacji. GameWindow będzie zarządzała wyświetlaniem i reagowaniem na klawisze a Snake będzie wiedział o swoim wyglądzie i położeniu.

0

Ooo racja z tą pętlą. - Już poprawiłem :)

Co do "W paint() rysujesz go dwukrotnie?" - testowo było to drugie. Już wyrzuciłem.

Nie wiem czy powinienem zmieniać dziedziczenia itd. Średnio się w tym czuję, a potem będę musiał profesorowi tłumaczyć co i jak. Bezpieczniej chyba nie ruszać dziedziczeń :D

Tutaj kod obecny:

#include "snake.h"
#include "screen.h"
#include "point.h"
#include <time.h>
#include <unistd.h>
//Snake w wyznaczonym polu gry
Snake::Snake(Rect r, char _c /*=' '*/):
  FramedWindow(r, _c)
{
}

void Snake::paint()
{
    FramedWindow::paint();
    if(helped==0)
    starthelp();

    gotoyx(y, x);
    for(xx=0;xx<snek.size() ; xx++)
    printl("%c", snek[xx]);

}

bool Snake::handleEvent(int key)  //handleEvent na w,s,a,d
{

  switch (key)
    {
    case 'w':
    if(dir!=1)
    goUp();

      return true;

    case 's':
    if(dir!=0)
    goDown();

      return true;

    case 'd':
    if(dir!=2)
    goRight();

      return true;
    case 'a':
    if(dir!=3)
    goLeft();

      return true;
    };
  return false;
}

void Snake::goUp()
{
    dir=0;
    y--;
    if(y==geom.topleft.y)
        y=geom.topleft.y + geom.size.y -2;
    paint();
}

void Snake::goDown()
{
    dir =1;
    y++;
    if(y==geom.topleft.y + geom.size.y -1)
        y=geom.topleft.y+1;
    paint();
}

void Snake::goLeft()
{
    dir=2;
    x--;
    if(x==geom.topleft.x)
        x=geom.topleft.x + geom.size.x -2;
    paint();
}

void Snake::goRight()
{
    dir =3;
    x++;
    if(x==geom.topleft.x + geom.size.x -1)
        x=geom.topleft.x+1;
    paint();
}
void Snake::starthelp()
{
    helped =1;
    x = geom.topleft.x + 4;
    y = geom.topleft.y + 4;
    gotoyx(y, x);
    for(xx=0;xx<helpstr.size() ; xx++)
    printl("%c", helpstr[xx]);
    y++;
    y++;
    gotoyx(y, x);
    for(xx=0;xx<helpstr4.size() ; xx++)
    printl("%c",helpstr4[xx] );
    y++;
    y++;
    gotoyx(y, x);
    for(xx=0;xx<helpstr2.size() ; xx++)
    printl("%c",helpstr2[xx]);
    y++;
    y++;
    gotoyx(y, x);
    for(xx=0;xx<helpstr3.size() ; xx++)
    printl("%c", helpstr3[xx]);
    y++;
    y++;
    gotoyx(y, x);
    for(xx=0;xx<helpstr5.size() ; xx++)
    printl("%c",helpstr5[xx]);

    x = geom.topleft.x + geom.size.x/2;
    y = geom.topleft.y+geom.size.y/2;
}

Zrobiłem tak jak mówiłeś. W eventHandle zmieniam tylko współrzędne, sprawdzam czy nie stykam się z granicą pola gry, wywołuję paint().
Nie wiem co dodać żeby nadać automatyzację. Żeby póki nie wcisnę innego klawisza kierunku to wąż dalej podążał w danym kierunku. Pętle while próbowałem ale zwieszał się Snake, w internecie patrzyłem ale dosyć inaczej to wszystko robią więc nic nie udalo mi się poprawnie zastosować.

Teraz spróbuję dodać strukturę i vector dla ogona węża

0

Nie tak.
Snake::paint() to ma wywoływać główna pętla programu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1