Autor Wątek: [XNA i JigLib] Obrót kamery i podążanie za samochodem  (Przeczytany 759 razy)

Offline jackeneczek

  • Użytkownik

# Czerwiec 17, 2011, 23:51:23
Mam taki problem: stworzyłem samochód (carobject = new CarObject(... )etc.) i w sekcji Update wstawilem:
camera.Position = new Vector3(carObject.PhysicsBody.Position.X, carObject.PhysicsBody.Position.Y, carObject.PhysicsBody.Position.Z);Wszystko git, tylko dlaczego samochód się 'zacina'? Jedzie kawałek w przód i w tył odrobinę, tak parę razy na sekundę. Jak to naprawić?No i nie wiem jak zrobić, żeby kamera była tak z góry ustawiona zawsze na przód samochodu (na razie podąża za samochodem, ale muszę ją obracać, bo przy manewrowaniu 'gubi' auto - patrzy się zawsze w jednym kierunku.
Kierunek w którym zwrócony jest samochód jest opisany macierzą. Znalazłem tam dla ciekawe pola: M13 i M33. są one z sobą w zależności sinus-cosinus. Oznacza to, że jeśli obliczymy, dla jakiego kąta sinusem jest M13, to będzie to ta sama wartość kąta, dla której M33 jest cosinusem. Nie myślałem długo - naskrobałem:

                  double asinek = Math.Asin(carObject.PhysicsBody.Orientation.M13);
                 if(asinek < 0) asinek += (-(asinek)) + 180 + (-(asinek));
                Matrix cameraRotation = Matrix.CreateRotationX(0) * Matrix.CreateRotationY((float)asinek);
                Vector3 targetPos = camera.Position + Vector3.Transform(Vector3.Forward, cameraRotation);
        camera.Target =  targetPos;
 


Z merytorycznego punktu widzenia - wszystko powinno być o.k. W drugiej linii dbam o to, by obliczać sinus zawsze dodatniej strony paraboli, żeby nie było problemów z parametrami kamery. Potem wpisuje w macierz i powinno grać. Tylko dlaczego kamera ładnie zbliża się do jednego boku, a nagle przeskakuje gdzieś do tyłu???

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline komorra

  • Użytkownik
    • Blog naszego teamu (o grze Voxelfield)

# Czerwiec 18, 2011, 08:24:13
Ja bym tutaj nie kombinował bezpośrednio z wartościami macierzy. W XNA macierz ma 6 wektorów, które można ładnie wykorzystać. Są to Forward, Backward, Up, Down, Left, Right. Wystarczy że "obrócimy" sobie macierz: matrix = Matrix.CreateRotationY(kąt) a matrix będzie trzymał odpowiednie wektory, które już będą zgodne z tym obrotem. Dodatkowo możesz spróbować użyć mojej klasy Camera:

public class Camera
    {
        public BasicEffect Effect;
        public Matrix orientation;
        public Vector3 Position;
        float hangle;
        float vangle;
        public Vector3 newPosition;
        float newHAngle;
        float newVAngle;
        float moveSpeed = 0.5f;
        float angleSpeed = 0.006f;
        float soft = 0.08f;
        float lasthangle;
        float lastvangle;
        int lastmx;
        int lastmy;
        bool mdown = false;
        public static Camera Active;

        public Camera(BasicEffect effect)
        {
            this.Effect = effect;
            newPosition = Position = new Vector3(0, 0, 0);
            newVAngle = vangle = 0.7f;
            Active = this;
        }

        public void Update(GameTime gameTime)
        {
            KeyboardState ks = Keyboard.GetState();
            if (ks.IsKeyDown(Keys.W)) newPosition += orientation.Forward * moveSpeed;
            if (ks.IsKeyDown(Keys.S)) newPosition += orientation.Backward * moveSpeed;
            if (ks.IsKeyDown(Keys.A)) newPosition += orientation.Left * moveSpeed;
            if (ks.IsKeyDown(Keys.D)) newPosition += orientation.Right * moveSpeed;

            MouseState ms = Mouse.GetState();
            if ((!mdown) && (ms.MiddleButton == ButtonState.Pressed))
            {
                lastmx = ms.X;
                lastmy = ms.Y;
                lasthangle = hangle;
                lastvangle = vangle;
                mdown = true;
            }
            if (ms.MiddleButton != ButtonState.Pressed) mdown = false;
            if (mdown)
            {
                newHAngle -= (ms.X - lastmx) * angleSpeed;
                newVAngle += (ms.Y - lastmy) * angleSpeed;
                lastmx = ms.X;
                lastmy = ms.Y;
            }

            Position = Vector3.Lerp(Position, newPosition, soft);
            hangle = MathHelper.Lerp(hangle, newHAngle, soft);
            vangle = MathHelper.Lerp(vangle, newVAngle, soft);
            orientation = Matrix.CreateRotationY(hangle);
            orientation *= Matrix.CreateFromAxisAngle(orientation.Left, vangle);
            Effect.View = Matrix.CreateLookAt(Position, Position + orientation.Forward, orientation.Up);
        }
    }

Aby używać powyższej klasy musisz sobie stworzyć BasicEffect który będzie odpowiadał za trzymanie macierzy widoku i projekcji. Generalnie w Initialize:

basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.Projection = new Matrix.CreatePerspectiveFieldOfView(1,1.33f,1,1000);
camera = new Camera(basicEffect);

w Update:

camera.Update(gameTime)
a potem z dowolnego miejsca w kodzie używasz Camera.Active.Effect.View i Camera.Active.Effect.Projection przy rysowaniu swojego modelu. Sterowanie jak widać: przeciąganie środkowym myszy + WSAD.

Offline jackeneczek

  • Użytkownik

# Czerwiec 18, 2011, 21:31:53
0. Wogóle dzięki za pomoc & fatygę :)
1. Do utworzenia instancji klasy BasicEffect potrzeba jakiegoś Effect Pool - ale chyba mogę wpisać po prostu BasicEffect basicEffect = new BasicEffect(GraphicsDevice, new EffectPool());, konstruktor EffectPool z tego co podpowiada mi Visual Studio jest bezargumentowy.
2. Troszkę przyśpieszyłeś zapis :) o ile ja też uwielbiam nawalić ile się da do jednej linijki, bo jest to dla mnie bardziej logiczne i prostsze, o tyle kompilator zaprotestował, musiałem rozbic: Matrix matriks = new Matrix;
matriks = Matrix.CreatePerspectiveFieldOfView(1,1.33f,1,1000);
    basicEffect.Projection = matriks;
3. Niestety w JigLib jestem baaardzo zielony, bo zacząłem od wczoraj :) Przy Twojej klasie Camera nie za bardzo się orientuje co i jak przypisać samochodowi, żeby jechał tak, jak skierowana jest kamera :) Przy samochodzie dołączone są właściwości: carObject.PhysicsBody.Orientation, carObject.PhysicsBody.Position (z tych które mogą nas w tym momencie ew. interesować).
4. Rozumiem, że może być ciężko pomóc na odległość, jakby co mogę podesłać plik z projektem.

Offline komorra

  • Użytkownik
    • Blog naszego teamu (o grze Voxelfield)

# Czerwiec 18, 2011, 21:36:31
Błędy które u Ciebie wystąpiły są spowodowane po części tym że ja użyłem XNA 4 a Ty XNA 3 :) BasicEffect możesz utworzyć przekazując null jako EffectPool. Co do samej kamery to nie samochód powinien podążać za kamerą tylko na odwrót. Pokombinuj z kodem i pewnie się uda.