• 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 ;) ]

VPS Starter Arubacloud
+2 głosów
694 wizyt
pytanie zadane 12 sierpnia 2019 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 14 sierpnia 2019 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 2019 przez Artek Stary wyjadacz (11,800 p.)
przeniesione 13 sierpnia 2019 przez Patrycjerz
No a w jaki sposób opisana jest ta płaszczyzna L?

4 odpowiedzi

+2 głosów
odpowiedź 13 sierpnia 2019 przez niezalogowany
edycja 14 sierpnia 2019
 
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 2019 przez Jakub 0 Pasjonat (23,120 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 2019 przez niezalogowany
Tak traktuj je jako wektory swobodne.
komentarz 14 sierpnia 2019 przez Jakub 0 Pasjonat (23,120 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 2019 przez J0ker Pasjonat (15,400 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 2019 przez Jakub 0 Pasjonat (23,120 p.)
Dziękuje za uwage.
0 głosów
odpowiedź 12 sierpnia 2019 przez Paweł Nąckiewicz Nałogowiec (48,990 p.)

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

komentarz 12 sierpnia 2019 przez Jakub 0 Pasjonat (23,120 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 2019 przez niezalogowany
edycja 12 sierpnia 2019

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 2019 przez tkz Nałogowiec (42,000 p.)

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

0 głosów
odpowiedź 13 sierpnia 2019 przez spamator12 Nałogowiec (28,230 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ź 161 wizyt
0 głosów
1 odpowiedź 378 wizyt
pytanie zadane 19 maja 2015 w C i C++ przez figorin Bywalec (2,040 p.)
0 głosów
1 odpowiedź 423 wizyt
pytanie zadane 9 czerwca 2020 w C i C++ przez kielek123 Nowicjusz (150 p.)

92,453 zapytań

141,262 odpowiedzi

319,086 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

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

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...