Implementacja prostego silnika fizycznego w Javie

0

Cześć.

Próbuje napisać prosty silnik fizyczny w Javie. Kiedyś zrobiłem coś podobnego
w CPP, także szkielet miałem gotowy i teraz tylko przerabiam na Jave.
Jednak coś mi tu nie działa tak jak trzeba. Prędkość nie oblicza się poprawnie,
cały czas jest stała. Myślę, że kaszani się gdzieś przy rozwiązywaniu równania
Eulerem (metoda symuluj() w klasie Obiekt), ale pewności nie mam. Nie wiem
czy dobrze wywołuje metody na wektorach. Źle mi to wygląda, no ale operatorów
przeciążyć nie można, także nie ma wyboru. Nie za dobrze znam jeszcze Jave,
dlatego przydałoby się jakieś wprawne oko ;)

Oto kod:


import javax.vecmath.*;

import javax.vecmath.Vector3d.*;


class Obiekt
{
	double masa;								// Masa obiektu
	Vector3d pozycja = new Vector3d(0.0d, 0.0d, 0.0d);		// Pozycja w ukladzie
	Vector3d v = new Vector3d(0.0d, 0.0d, 0.0d);	       		// Predkosc
	Vector3d sila = new Vector3d(0.0d, 0.0d, 0.0d);		// Sila dzialajaca na obiekt

	Obiekt(double m)
	{
		masa = m;
	}

    /* Metoda void przyloz_sile(Vector3D force) jest uzywana do dodania sily dzialajacej na mase.
       W ciagu danego czasu, na mase(klasa Obiekt) moze działać kilka sił zewnetrznych. Metoda
       zwraca sile wypadkowa sil przylozonych do masy.
    */

	void przyloz_sile(Vector3d force)
	{
		sila.set(force);
	}

	void odbij(Vector3d v1)            // Zmienia wektor predkosci na wektor predkosci odbity
	{
		v = v1;
	}

	void zeruj_sile()                     // Zerowanie siły
	{
            sila = new Vector3d(0.0d, 0.0d, 0.0d);
	}

	/* metoda void symuluj() oblicza nowa predkosc i nowa pozycje
	   masy (obiektu) w stosunku do zmiany w czasie (dt). Używamy tutaj
	   "Metody Eulera". */

	void symuluj(double dt)
	{

                sila.scale(1/masa);                 // v += (sila / masa) * dt
                sila.scale(dt);
                v.add(sila);

                v.scale(dt);                          // pozycja += v * dt
                pozycja.add(v);    
	}
}


class Symulacja
{
	Obiekt pilka;
        Vector3d grawitacja = new Vector3d(0.0d, -8.0d, 0.0d);;

        void oblicz_sile_grawitacji()        // Oblicz sile grawitacji F = g*m
        {
            grawitacja.scale(pilka.masa);
        }

	Symulacja(double m)	           // Kontruktor tworzacy mase o wartosci m
	{
		pilka = new Obiekt(m);			        
	}

	void init()				// Metoda wywolujaca metode init() dla masy
	{
		pilka.zeruj_sile();
	}

	void solve()						
	{
            oblicz_sile_grawitacji();
	    pilka.przyloz_sile(grawitacja);				
	}

	void simulate(double dt)		// Iteruj masy pod wplywem czasu
	{
		pilka.symuluj(dt);		        // Iteruj masy i uzyskuj nowa pozycje i predkosc
	}

	void operate(double dt)			// Kompletna procedura symulacji
	{
		init();					// Krok 1: Resetuj sily
		solve();				// Krok 2: Przyloz sily
		simulate(dt);			// Krok 3: Iteruj masy pod wplywem czasu
	}
}

 
0

Tak na pirwszy rzut oka, nie podoba mi się ta linijka:

sila.scale(1/masa);                 // v += (sila / masa) * dt 

Ja zawsze się łapię, że przy dzieleniu zwykle coś mi się kopsa z ilością miejsc po przecinku.
Sprawdź w debugerze, ile wychodzi 1/masa.

0

Faktycznie zapomniałem o istnieniu debuggera! ;) Już wiem gdzie jest błąd,
natomiast nie wiem jak go naprawić. Brak mi pomysłów i doświadczenia.

         
void symuluj(double dt)
{
         sila.scale(1/masa);                
         sila.scale(dt);                       
         v.add(sila);                          // dotąd jest ok

         v.scale(dt);                          // tutaj wywala jakieś kosmiczne liczby
         pozycja.add(v);    
}

Jak widać wywołanie v.scale(dt) powoduje błędy. Dt to zmiana czasu
(delta t), która zazwyczaj mieści się w przedziale <0.001, 0.1>.
Jakieś pomysły co tu może być nie tak?

0

Napisz prozę ile ta dt ma w tym momencie?
Jeśli jest to doulbe, to może mieć np. 0.00198765658 coś tam.
Może jest za duża dokładność?
Jeśli tak, to sprawdź na sieci klasę BigInteger - obudowuje liczby rzeczywiste, możesz w niej ustawić dokładność np. do 3 miejsc po przecinku. Wtedy masz pewność, że liczba będzie od 0.1 do 0.001 a nie od 0.1234 do 0.001354354.

Pozdrawiam.

0

Dt ma za zadanie regulacje szybkości symulacji, powiedzmy żeby
sekunda w programie była równa sekundzie rzeczywistej. Jednak
teraz nie ma to większego znaczenia, bo wywołuje tę metodę ze
stałym parametrem:

    Symulacja symulacja = new Symulacja(1.0d);

    for (int i=0; i<1000; i++)
    {
      mot.operate(0.01);
      System.out.println("Pozycja: "symulacja.pilka.pozycja);
      System.out.println("Predkosc: "symulacja.pilka.v);
   }

Domyślam się, że chodziło Ci o BigDecimal?
Tylko nie do końca widzę tutaj zastosowanie.

A tak się mają wartości w poszczególnych krokach:

         sila.scale(1/masa);                
         sila.scale(dt);  

dt = 0.01;
sila.y = -0.0981;
v.y = 0.0;
pozycja.y = 0.0;

        v.add(sila);

dt = 0.01;
sila.y = -0.0981;
v.y = -0.0981;
pozycja.y = 0.0;

         v.scale(dt); 

dt = 0.01;
sila.y = -0.0981;
v.y = -9.81E-4; // kosmos
pozycja.y = 0.0;

         pozycja.add(v);

dt = 0.01;
sila.y = -0.0981;
v.y = -9.81E-4; // kosmos
pozycja.y = -9.81E-4; // pozycja przejmuje kosmos

0

Hej to nie jest kosmos, to po prostu zapis wykładniczy czyli masz -9.81do potęgi e-4 czy jakoś tak - nigdy nie lubiłem matmy.
Podejrzewam, że po skalowaniu liczby -0,0981 przez dt = 0.001 dostałeś 0,00981, tylko, że java tak wyświetla liczby w postaci wykładniczej.
Tak więc tym chyba nie musisz się przejmować.

0

@Black007, trochę się kompromitujesz. -9.81E-4=-9,81*10-4

0

Pisałem że nie lubiłem matmy :D.
Chodziło mi o to samo, co Tobie :D

0

Nadal nie działa. Prędkość zawraca stałą wartość. Jedynie kiedy
zmieniam masę (argument konstruktora klasy Symulacja()) coś
zaczyna działać. Jednak jak wiadomo, zmiana masy nie ma wpływu
na przyspieszenie i prędkość w swobodnym spadku.

Może znacie jakieś prosty i darmowy silnik fizyczny w Javie?

0

jbullet

0

Ok. Dzięki.

Znasz może jeszcze jakiś przystępny tutorial, traktujący
o łączeniu tego z Java3D? Ciężko coś konkretnego wygooglać.

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