• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Symulacja odbicia piłki od ścian o różnych nachyleniach, prośba o pomoc matematyczną. [ nie chodzi o Arkanoid ;) ]

+1 głos
192 wizyt
pytanie zadane 12 sierpnia w C i C++ przez Jakub 0 Stary wyjadacz (13,310 p.)
zamknięte 14 sierpnia przez Jakub 0

Witam, planuje zrobić program symulujący jakąś prostą formę fizyki, na początek nie przejmuje się jeszcze wektorem grawitacji a tworzę system odbijania się obiektu od krawędzi, wyglądać to może w ten sposób:

eksperymentując zauważyłem taką zasadę odbijania się piłki:

Jeśli kulka uderza o płaszczyznę L pod kątem alfa ( V to jej wektor ruchu ), to odbija się w "sposób lustrzany" jak to widać na obrazku. Zauważyłem że żeby uzyskać wektor V' musimy dokonać rotacji wektora V o kąt 180-alfa. Problem jest tylko ze sprawdzeniem ile wynosi kąt alfa. Jedyne co przecież znamy to wymiary wektorów V oraz L ( płaszczyzny ). Dużo eksperymentowałem ale nic z tego, co więcej rozwiązanie problemu być może jest znacznie prostsze niż ja to próbuję zrobić, wobec czego zadam pytanie:

Jak znając wektor V oraz L obliczyć wektor V'? ( oczywiście mowa tu o wektorach jednostkowych i zależy mi na znajomości składowych x i y wektora V', czyli nowy tor ruchu piłki ).

To jest mój kod gdzie eksperymentowałem ( użyłem sfml ), pewnie nie wiele się tu przyda ale to taki mój dowód że sam usiłowałem to rozwiązać ;(

#include <SFML/Graphics.hpp>
#include "Area.h"

#include <iostream>
#include <cmath>

int main() {

	sf::RenderWindow window(sf::VideoMode(500, 500), "SFML works!", sf::Style::Close); 

	sf::VertexArray vertex(sf::Lines, 4);
	vertex[0] = sf::Vertex(sf::Vector2f(0, 0), sf::Color(255, 255, 255));
	vertex[1] = sf::Vertex(sf::Vector2f(250.f, 250.f), sf::Color(255, 255, 255));
	vertex[2] = sf::Vertex(sf::Vector2f(250.f, 250.f), sf::Color(255, 255, 255));
	vertex[3] = sf::Vertex(sf::Vector2f(0, 0), sf::Color(255, 255, 255));

	sf::VertexArray surface(sf::Lines, 2);
	surface[0] = sf::Vertex(sf::Vector2f(-1000.f, 250.f), sf::Color(34, 177, 76));
	surface[1] = sf::Vertex(sf::Vector2f(1000.f, 250.f), sf::Color(34, 177, 76));
	sf::Transform surfaceTransform;
	
	sf::Event event; 
	while (window.isOpen()) {

		while (window.pollEvent(event)) {
			if (event.type == sf::Event::Closed) 
				window.close();	
		}

		//obracanie nachylenia ściany
		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) {
			surfaceTransform.rotate(-0.5f, sf::Vector2f(250.f, 250.f));
		}if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
			surfaceTransform.rotate(0.5f, sf::Vector2f(250.f, 250.f));
		}

		vertex[0].position = window.mapPixelToCoords(sf::Mouse::getPosition(window));

		float bside = std::hypotf(vertex[0].position.x - vertex[1].position.x,
								  vertex[0].position.y - vertex[1].position.y);

		float aside = std::abs(vertex[1].position.x - vertex[0].position.x);

		float angle = std::acos(aside / bside);
		float angleToMove = 180.f - angle;

		sf::Vector2f av = vertex[1].position;
		sf::Vector2f bv = vertex[0].position;

		sf::Vector2f nvec;
		nvec.x = ((bv.x - av.x) * std::cos(angleToMove)) - ((bv.y - av.y) * std::sin(angleToMove)) + av.x;
		nvec.y = ((bv.x - av.x) * std::sin(angleToMove)) + ((bv.y - av.y) * std::cos(angleToMove)) + av.y;

		vertex[3].position = nvec;
			
		window.clear(sf::Color(0,0,0)); 
		window.draw(surface, surfaceTransform); 
		window.draw(vertex); 
		window.display(); 
	}
}

Z góry dziękuje za pomoc.

komentarz zamknięcia: problem rozwiązany
komentarz 12 sierpnia przez Artek Dyskutant (7,540 p.)
przeniesione 13 sierpnia przez Patrycjerz
No a w jaki sposób opisana jest ta płaszczyzna L?

4 odpowiedzi

+2 głosów
odpowiedź 13 sierpnia przez Hipcio Szeryf (98,160 p.)
edycja 14 sierpnia przez Hipcio
 
Najlepsza

Oblicz kąt pomiędzy płaszczyzną a wektorem padającym ze wzoru na iloczyn skalarny. Teraz rzutuj wektor padający na wektor płaszczyzny (v * cos() - czyli nie trzeba liczyć arccos/cos) i przemnóż wynik razy wektor jednostkowy płaszczyzny (wersor). Teraz wystarczy dodać wektor wodzący pozycji myszki do dwukrotności rzutu.

W zasadzie można to w podobny sposób wyprowadzić w bardziej uogólnionej formie:

Przykładowy kawałek kodu:

sf::Vector2f surf = surface[1].position - surface[0].position;
sf::Vector2f incidence = vertex[1].position - vertex[0].position;

sf::Vector2f reflex = 2.f * surf * vector::dot_product(surf, incidence) / vector::dot_product(surf, surf) - incidence; // vector::dot_product(surf, surf) <==> std::pow(vector::length(surf), 2)
vertex[3].position = vertex[2].position + reflex;

Alternatywnie:

vertex[3].position = vertex[0].position + 2.f * surf * vector::dot_product(surf, incidence) / vector::dot_product(surf, surf);
komentarz 13 sierpnia przez Jakub 0 Stary wyjadacz (13,310 p.)
Ok, ale zastanawia mnie jedna rzecz, płaszczyzny nie da się przedstawić jako pary dwóch liczb ( x oraz y ) bo to jest wektor zaczepiony ( jest to forma odcinka składająca się z dwóch punktów ). Czy mam interpretować te wektory jako swobodne a potem przesunąć je o odpowiednie wartości?
komentarz 13 sierpnia przez Hipcio Szeryf (98,160 p.)
Tak traktuj je jako wektory swobodne.
komentarz 14 sierpnia przez Jakub 0 Stary wyjadacz (13,310 p.)

Dziękuje za wielką pomoc, problem rozwiązany:

#include <SFML/Graphics.hpp>
#include <cmath>

int main() {

	sf::RenderWindow window(sf::VideoMode(500, 500), "SFML works!", sf::Style::Close); 
	
	sf::VertexArray vertex(sf::Lines, 4);
	vertex[0] = sf::Vertex(sf::Vector2f(0, 0), sf::Color(255, 255, 255));
	vertex[1] = sf::Vertex(sf::Vector2f(250.f, 250.f), sf::Color(255, 255, 255));
	vertex[2] = sf::Vertex(sf::Vector2f(250.f, 250.f), sf::Color(0, 255, 255));
	vertex[3] = sf::Vertex(sf::Vector2f(0, 0), sf::Color(0, 255, 255));

	sf::Vector2f spoints[2]{
		sf::Vector2f(-1000.f, 250.f),
		sf::Vector2f(1000.f, 250.f)
	};
	sf::VertexArray surface(sf::Lines, 2);
	surface[0].color = sf::Color(34, 177, 76);
	surface[0].position = spoints[0];
	surface[1].color = sf::Color(34, 177, 76);
	surface[1].position = spoints[1];

	sf::Transform surfaceTransform;

	auto dotVec = [](const sf::Vector2f& a, const sf::Vector2f& b) { 
		return  a.x * b.x + a.y * b.y; 
	};
	
	sf::Event event; 
	while (window.isOpen()) {

		while (window.pollEvent(event)) {
			if (event.type == sf::Event::Closed) 
				window.close();	
		}

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) {
			surfaceTransform.rotate(-0.2f, sf::Vector2f(250.f, 250.f));
			surface[0].position = surfaceTransform.transformPoint(spoints[0]);
			surface[1].position = surfaceTransform.transformPoint(spoints[1]);

		}else if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
			surfaceTransform.rotate(0.2f, sf::Vector2f(250.f, 250.f));
			surface[0].position = surfaceTransform.transformPoint(spoints[0]);
			surface[1].position = surfaceTransform.transformPoint(spoints[1]);
		}

		vertex[0].position = window.mapPixelToCoords(sf::Mouse::getPosition(window));

		sf::Vector2f fsurface = surface[1].position - surface[0].position;
		sf::Vector2f ftrack = vertex[1].position - vertex[0].position;
		sf::Vector2f reflex = 2.f * fsurface * dotVec(fsurface, ftrack) / dotVec(fsurface, fsurface) - ftrack;
		vertex[3].position = vertex[2].position + reflex;
			
		window.clear(sf::Color(0,0,0)); 

		window.draw(surface); 
		window.draw(vertex); 

		window.display(); 
	}
}

Niby znam trygonometrie, znam wzory na iloczyn skalarny, na wektor jednostkowy... a jednak nie potrafię wykombinować z tego potrzebnego mi wzoru :/

Czułem że kombinowane z kątami to kiepski pomysł i dlatego nawet nie tłumaczyłem mojego domniemanego rozwiązania, by rozwiązać problem moją wcześniejszą metodą musiał bym najpierw zamienić wektory zaczepione na równanie funkcji liniowej ;) Dlatego poddałem się...

dzięki jeszcze raz i pozdrawiam

 

+1 głos
odpowiedź 13 sierpnia przez J0ker Mądrala (6,030 p.)
Idea Twojego rozumowania jest poprawna, ale nazewnictwo nie. Mówisz, że piłka pada na powierzchnię pod kątem alfa, ale źle ten kąt zaznaczyłeś.

Ten kąt alpha powinien być między torem ruchu piłki, a prostą prostopadłą do powierzchni w punkcie zetknięcia piłki z powierzchnią, a nie między torem ruchu piłki a tą powierzchnią

Ale ten błąd popełnia chyba 99% ludzi na pewnym etapie nauki fizyki, nie zawsze wszystko jest nazwane tak jak nakazuje intuicja. Z resztą każdy człowiek ma prawo do własnej intuicji.

Na tym etapie to nie ma dużego znaczenia, ale może warto to zapamiętać jak kiedyś będziesz robił bardziej zaawansowaną fizykę (gdzie np. powierzchnia będzie się uginać pod wpływem uderzenia piłki); wtedy już ważne żeby dobrze pamiętać czym jest kąt padania.
komentarz 14 sierpnia przez Jakub 0 Stary wyjadacz (13,310 p.)
Dziękuje za uwage.
0 głosów
odpowiedź 12 sierpnia przez pawi125 Stary wyjadacz (12,630 p.)

Widzałeś ten odcinek kursu? Ewentualnie poszukaj innych implementacji gry arkaniod tam masz to gotowe

komentarz 12 sierpnia przez Jakub 0 Stary wyjadacz (13,310 p.)
zupełnie nie o to chodzi...

grę arkanoid to ja potrafię napisać z zamkniętymi oczami ;) Nie jest sztuką napisać kod który odwróci wektor przy uderzeniu o pionową lub poziomą ścianę, ja piszę program który ma symulować zachowanie obiektu na ścianach pod różnymi kątami oraz dodać potem jakąś formę grawitacji. To co ja robię to bardziej forma systemu cząsteczek.
komentarz 12 sierpnia przez fisker Obywatel (1,030 p.)
edycja 12 sierpnia przez fisker

jakobianem się zainteresuj, zmieniasz układ współrzędnych z globalnych, i opisujesz wektor V współrzędnych L||x_localne i wtedy masz prawie przeciwny bo długości jednostkowe będę się zgadzać tylko znaki. Ale z palca ci tego nie zrobię, bo za dużo informacji było między czasie jak to rozkminiałem

edit ::(matematycznie) w cpp bez bibloteki to jakoś tak robiłem

 double dx = (end_point.x-begin_point.x);
    double dy = (end_point.y-begin_point.y);

    switch (ch) {
    case 'c' :
        return (dx)/sqrt(dx*dx+dy*dy);
        break;
    case 's' :
        return (dy)/sqrt(dx*dx+dy*dy);
        break;




double move_UCS_x= current.x- begin_point.x;
double move_UCS_y= current.y- begin_point.y;
double rotate_UCS_c_x=move_UCS_x * c+move_UCS_y*s; // c=cos
double rotate_UCS_c_y=move_UCS_x * (-s)+move_UCS_y*c; //s= sin
current.x=rotate_UCS_c_x;
current.y=rotate_UCS_c_y;

ale za nic nie mogę znaleźć linka 

to nie to ale zawsze  https://docs.microsoft.com/en-us/windows/win32/learnwin32/appendix--matrix-transforms

tu nawet na forum dodawałem ale nie mogę znaleźć było jakoś tak [xy] [move] [rotate] = [x'y'], a punkt A(1,5) to podobnie wygląda jak V[1,5] (bo zawsze może być przypięty w (0,0))

komentarz 12 sierpnia przez tkz Gaduła (3,820 p.)

@Jakub 0,  taka moja pierwsza myśl, biblioteka box2d, ona ma chyba zaimplementowaną fizykę, jest opensorcowa. 

0 głosów
odpowiedź 13 sierpnia przez spamator12 Stary wyjadacz (11,980 p.)

[nie jest to prosta odpowiedz - chodz ogladajac powinniennes bez problemu rozwiazac problem]

polecam - https://www.youtube.com/watch?v=P6UKhR0T6cs moze najda Cie jakies nowe ciekawe pomysly.

Podobne pytania

0 głosów
1 odpowiedź 97 wizyt
0 głosów
1 odpowiedź 294 wizyt
pytanie zadane 19 maja 2015 w C i C++ przez figorin Bywalec (2,100 p.)
0 głosów
1 odpowiedź 344 wizyt
pytanie zadane 2 października 2015 w C i C++ przez Куба Янчевски Początkujący (400 p.)
Porady nie od parady
Forum posiada swój własny chat IRC, dzięki któremu będziesz mógł po prostu pogadać z innymi Pasjonatami lub zapytać o jakiś problem. Podstrona z chatem znajduje się w menu pod ikoną człowieka w dymku.IRC

65,728 zapytań

112,370 odpowiedzi

237,231 komentarzy

46,688 pasjonatów

Przeglądających: 220
Pasjonatów: 6 Gości: 214

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...