Skakanie postaci, a kolizja z elementami na mapie

0

Cześć! Od wczoraj się męczę z zaimplementowaniem skoku po bloczkach ( coś a'la Icy Tower ), niestety, albo wychodzi tylko na to, że postać podskakuje na pierwszy bloczek, na drugi już nie; nie wskakuje na żaden bloczek; lub w ogóle nie skacze.
W source.cpp metoda updateJump wykonywana jest w timerze. Czy może mnie ktoś naprowadzić? Byłbym wdzięczny! Pozdrawiam

Na dobrą sprawę to powinno według mnie wyglądać tak ( Skocz ; Sprawdź, czy jest na ziemi, jeżeli tak, ustaw na fałsz ; zwiększaj atrybuty x,y, w między czasie sprawdzaj, czy nie zachodzi kolizja z żadnym z bloczków, jeżeli tak to ustaw na prawdę ;

Dla sytuacji przedstawionej poniżej, kolizję wykrywa mi tylko z podłogą, czyli pierwszym(zerowym bloczkiem). Jeżeli nawet na 'sztywno' ustawiłem postaci większą współrzędną y, by "latać", to przy kolizji z bloczkiem w konsoli nie wykrywało kolizji.

character.cpp

void character::startJump(map& Map, character& player) {
	if (Map.isCollidingBlock(player))
	{
		vel[1] = -11.0;
		onGround = false;
	}
}
void character::updateJump(map& Map, character& player) {
	vel[1] += 0.5;
	y += vel[1];
	x += vel[0];
	Map.isCollidingBlock(player);

	if (y > 460){
		y = 460;
		vel[1] = 0.0;
		onGround = true;
		vel[0] = 0.0;
	}

	if ((x + width >= START_WALL_X && x <= WALL_WIDTH + START_WALL_X) || (x + width >= END_WALL_X &&x <= END_WALL_X + WALL_WIDTH)){
	vel[0] *= -1;
	bound = true;
	if (direction == 1)
		direction = 2;
	else if (direction == 2)
		direction = 1;
	}
}

map.cpp

bool map::isCollidingBlock(character& player) { // kolizja gracza z bloczkami
	for (int i = 0; i < MAX_BLOCKS; i++) {
		if (player.x + player.width >= tab_axis[i][0] && player.x <= tab_axis[i][0] + tab_width[i] && player.y + player.height >= tab_axis[i][1] && player.y <= tab_axis[i][1] + block_height) {
			printf("KOLIZJA");
			return true;
		}
		else {
			printf("BRAK KOLIZJA");
			return false;
		}
	}
}
void map::FirstBlocks() { // tworzenie bloczków na mapie, 0 to podłoga
	int count = 0;
	tab_axis[0][0] = START_FLOOR_X;
	tab_axis[0][1] = START_FLOOR_Y;
	tab_width[0] = al_get_bitmap_width(floorbmp);
	for (int i = 1; i < MAX_BLOCKS; i++) {
		tab_width[i] = (rand() % MAX_RANDOM_X_SIZE) + MIN_RANDOM_X_SIZE;
		while (tab_width[i] > MAX_RANDOM_X_SIZE) {
			tab_width[i] = (rand() % MAX_RANDOM_X_SIZE) + MIN_RANDOM_X_SIZE;
		}
	}
	for (int x = 1; x < MAX_BLOCKS; x++) {
		for (int y = 0; y < 2; y++) {
			if (y == 0) {
				tab_axis[x][y] = rand() % END_WALL_X;
				while (tab_axis[x][y] < WALL_WIDTH || tab_axis[x][y] + tab_width[x] >= END_WALL_X) {
					tab_axis[x][y] = rand() % END_WALL_X;
				}
			}
			else if (y == 1)
				tab_axis[x][y] = 430 - count * 116;
		}

		count++;
	}
}
0

Zamiast boola zrobiłem voida, który po prostu w momencie kolizji z bloczkiem ustawia atrybut postaci na onGround = true;
**
Kolizja na ten moment nie jest dobra, bo gracz może mieć "onGround", jeżeli nawet dotknie bloczku od spodu, lecz na ten moment mam inny problem. Mianowicie, jeżeli ustawię sobie MAX_BLOCKS na 3, to będę mógł mieć tylko wartość "OnGround" na true na drugim bloczku, natomiast pierwszy bloczek jest jakby "ignorowany".
Jeżeli ustawię sobie
MAX_BLOCKS** na 2, to będę mógł wskoczyć na pierwszy bloczek.

static const int MAX_BLOCKS = 3;
float tab_axis[MAX_BLOCKS][2] = { 0 };
unsigned short tab_width[MAX_BLOCKS] = { 0 };
....
....
....
void map::isCollidingBlock(character& player) { // kolizja gracza z bloczkami
for (int i = 0; i < MAX_BLOCKS; i++){
		if (player.x + player.width >= tab_axis[i][0] && player.x <= tab_axis[i][0] + tab_width[i] && player.y + player.height >= tab_axis[i][1] && player.y <= tab_axis[i][1] + block_height) {
			player.onGround = true;
		}
		else {
			player.onGround = false;
		}
	}
	
}

updateJump

void character::updateJump(map& Map, character& player) {
	Map.isCollidingBlock(player);
	if (!onGround) {
		vel[1] += 0.5;
		y += vel[1];
		x += vel[0];
	}

	if (y > 460){
		y = 460;
		vel[1] = 0.0;
		onGround = true;
		vel[0] = 0.0;
	}
``
2

Skoro Ci nie działa to napisz testy dla tej metody isCollidingBlock(), a nie testuj tego manualnie. Jak nie wiesz jak pisać testy jednostkowe to powiedzmy napisz kod testujący i niech się wykonuje po wciśnięciu jakiegoś przycisku na klawiaturze. W testach ustawiasz na sztywno współrzędne playera i patrzysz co Ci wypluwa konsola. Dodatkowo możesz sobie wyświetlić współrzędne tych bloczków, współrzędne playera itd. Dzięki tym danym będzie Ci łatwiej ogarnąć co jest nie tak. Ogólnie to ten kod powinieneś poprawić bo idzie się w nim zatracić np. jak tworzysz bloczki to masz for z "x", "y" i to się myli ze współrzędnymi a współrzędne tak naprawdę przechowujesz w komórkach [y]. Tak mi się wydaje jak się temu przyglądałem. Przydałoby się tu wprowadzić klasy. Dla bloczka mógłbyś napisać klasę, która będzie przechowywała info o nim np. współrzędne, rodzaj materiału itp. Staraj się tak pisać kod żeby był przejrzysty to co się da wyodrębnić np. za pomocą klasy, metody to to rób. No i jeszcze nazwy powinny być bardziej opisowe, w kodzie masz tablicę vel, tab_axis, powiem to mało mówi o ich przeznaczeniu.

1

Owszem masz klasę mapy ale nie przechowujesz w niej bloczków tylko informacje dotyczące bloczków, a to błąd i radzę Ci żebyś to sobie wyodrębnił (utwórz sobie klasę np. Block) a w mapie wtedy tworzysz tablicę tego typu Block, nazywasz ją blocks i od razu jest większa przejrzystość. No bo jak będziesz dalej rozbudowywał tą grę i tak będziesz pisał ten kod, dojdą jakieś nowe obiekty np. jakieś bonusowe gwiazdki czy coś w ten deseń to będziesz miał dla jednej klasy tysiące linijek kodu i weź się później w tym połap. Co do metod to opłaca się bo dzięki temu tworzy Ci się taka jakby opisowa lista operacji jakie wykonujesz oczywiście jak dobrze nazwiesz te metody. Możesz mieć np. ChangePosition i w argumentach podajesz o ile ma się ta pozycja zmieniać, nie rób czegoś takiego jak teraz, że masz wpisane na sztywno, bo potem stwierdzisz, a chce żeby przesuwał się o 2 a nie o 0,5 i musisz zmieniać 2 linijki, potem gdzieś zapomnisz i będziesz się zastanawiał czemu źle działa. Wgl. nazwa updateJump jest trochę dziwna, bo co oznacza? Aktualizuj skok? Aktualizować możesz pozycję, jak coś to samo Jump. Co do wartości stałych to nie wiem jak jest w C++, w C# nie można użyć static const, a jeżeli w C++ można to nie mam zielonego pojęcia jaka jest różnica między static const, a const, musiałbyś o to zapytać kogoś innego.

0

Dzięki jeszcze raz, jeszcze jak mogę Cię prosić, to "jak bardzo" powinienem rozkładać kod na klasy, mam na myśli to, czy jak mam teraz klasę postać, która zawiera również metody od skoku, to czy powinienem rozdzielać powiedzmy właśnie klasę character oraz jump i potem powiedzmy to łączyć jakąś przyjaźnią? Gdzie jest granica tworzenia dodatkowych klas? Oczywiście w granicach rozsądku, by nie popadać w paranoję, bo jak dobrze zrozumiałem, jeżeli mam rozdzielić klasę mapę oraz klasę bloczek, to logicznym by było rozbicie na klasy również dla klas character oraz jump. Tak samo jak potem będę dodawał gwiazdki, to też pewnie będzie je trzeba stworzyć jako klasę.

1

Najlepiej jak sobie poczytasz jakieś tutoriale, albo obejrzysz na yt jak napisać grę.
Tu masz linki gdzie gość tworzył gre od początku do końca (skakanie ludzikiem po planszy) dawno temu to czytałem ale pamietam, ze było fajnie opisane, no i używał C++.

Link do strony z różnymi projektami gier:
http://informatyka.wroc.pl/gry?page=1

Link do pierwszej części opisu tej gry 2D:
http://informatyka.wroc.pl/node/387

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