2014-09-13 4 views
0

Я работаю над игрушкой для симулятора Direct3D9, в которой мне нужно создать камеру, которая удерживает позицию и точку зрения космического корабля игрока. На данный момент я ограничил свой код только для того, чтобы двигаться назад и вперед, вверх и вниз, а также обстреливать. Ниже мой код, и у него есть проблема. Все обернуто в класс, и все векторы инициализируются в D3DXVECTOR3 (0.0f, 0.0f, 0.0f) в конструкторе, за исключением LocalUp (D3DXVECTOR3 (0.0f, 1.0f, 0.0f)) и LocalAhead (D3DXVECTOR3 (0.0f , 0.0f, 1.0f)), а поплавки - 0.0f;Direct3D9 game: Космический аппарат

D3DXVECTOR3 Position, LookAt ,PosDelta, PosDeltaWorld, WorldAhead, WorldUp, LocalUp, 
LocalAhead, Velocity; 
D3DXMATRIX View, CameraRotation; 
float SpeedX, SpeedY, SpeedZ; 

void Update(float ElapsedTime) 
{ 
    SpeedX = 0.0f; 
    SpeedY = 0.0f; 

    if(IsKeyDown('A')) 
    { 
     SpeedX = -0.02f; 
     Velocity.x -= SpeedX; 
    } 
    if(IsKeyDown('D')) 
    { 
     SpeedX = 0.02f; 
     Velocity.x += SpeedX; 
    } 
    if(IsKeyDown('X')) 
    { 
     SpeedZ += 0.01f; 
     Velocity.z += SpeedZ; 
    } 
    if(IsKeyDown('Z')) 
    { 
     SpeedZ -= 0.01f; 
     Velocity.z -= SpeedZ; 
    } 
    if(IsKeyDown('W')) 
    { 
     SpeedY = 0.02f; 
     Velocity.y += SpeedY; 
    } 
    if(IsKeyDown('S')) 
    { 
     SpeedY = -0.02f; 
     Velocity.y -= SpeedY; 
    } 

    D3DXVec3Normalize(&Velocity, &Velocity); 

    PosDelta.x = Velocity.x * SpeedX; 
    PosDelta.y = Velocity.y * SpeedY; 
    PosDelta.z = Velocity.z * SpeedZ; 

    D3DXMatrixRotationYawPitchRoll(&CameraRotation, 0, 0, 0); 
    D3DXVec3TransformCoord(&WorldUp, &LocalUp, &CameraRotation); 
    D3DXVec3TransformCoord(&WorldAhead, &LocalAhead, &CameraRotation); 
    D3DXVec3TransformCoord(&PosDeltaWorld, &PosDelta, &CameraRotation); 

    Position += PosDeltaWorld; 
    LookAt = Position + WorldAhead; 

    D3DXMatrixLookAtLH(&View, &Position, &LookAt, &WorldUp); 
} 

и функция "D3DXMatrixPerspectiveFovLH" "IDirect3DDevice9 :: SetTransform" называются в другой части приложения. Поскольку они работают нормально, я больше не буду говорить о них.

Проблема в том, что всякий раз, когда скорость по оси Z довольно велика, и я стягиваюсь и двигаюсь в поперечном направлении, отдельно или в одно и то же время, скорость Z-оси камеры уменьшается. Более того, после того, как скорость почти равна 0, а затем я нажимаю клавишу, которая увеличивает скорость, смысл инвертирует вектор, а затем возвращается к норме. Это также происходит при изменении значения вектора на достаточно высоких скоростях (например, нажатие X, а затем немедленное нажатие «Z»). Может ли кто-нибудь объяснить мне, почему это происходит, и как я могу решить эту проблему?

Я также задам еще один вопрос: как я могу уменьшить скорость и скорость оси Y, если не нажата ни одна клавиша? Я хочу, чтобы эффект инерции реализовывался в игре.

Если есть кто-нибудь, кто может мне помочь, ответьте!

EDIT: НОВЫЙ КОД:

void NewFrontiers3DEntityPlayer::OnFrameUpdate(float ElapsedTime) 
{ 
State.SpeedX = 0.0f; 
State.SpeedY = 0.0f; 
if(IsKeyDown(State.Keys[CAM_STRAFE_LEFT])) 
    State.SpeedX = -0.02f; 
if(IsKeyDown(State.Keys[CAM_STRAFE_RIGHT])) 
    State.SpeedX = 0.02f; 
if(IsKeyDown(State.Keys[CAM_MOVE_FORWARD])) 
{ 
    State.SpeedZ += 0.01f; 
} 
if(IsKeyDown(State.Keys[CAM_MOVE_BACKWARD])) 
{ 
    State.SpeedZ -= 0.01f; 
} 
if(IsKeyDown(State.Keys[CAM_MOVE_UP])) 
    State.SpeedY = 0.02f; 
if(IsKeyDown(State.Keys[CAM_MOVE_DOWN])) 
    State.SpeedY = -0.02f; 

State.Velocity.x = State.SpeedX; 
State.Velocity.y = State.SpeedY; 
State.Velocity.z = State.SpeedZ; 

D3DXVec3Normalize(&State.Velocity, &State.Velocity); 

State.PosDelta.x = State.Velocity.x * ElapsedTime; 
State.PosDelta.y = State.Velocity.y * ElapsedTime; 
State.PosDelta.z = State.Velocity.z * ElapsedTime; 

D3DXMatrixRotationYawPitchRoll(&State.CameraRotation, 0, 0, 0); 
D3DXVec3TransformCoord(&State.WorldUp, &State.LocalUp, &State.CameraRotation); 
D3DXVec3TransformCoord(&State.WorldAhead, &State.LocalAhead, &State.CameraRotation); 
D3DXVec3TransformCoord(&State.PosDeltaWorld, &State.PosDelta, &State.CameraRotation); 

State.Position += State.PosDeltaWorld; 
State.LookAt = State.Position + State.WorldAhead; 

D3DXMatrixLookAtLH(&State.View, &State.Position, &State.LookAt, &State.WorldUp); 

return; 
} 

"государство" является структурой, которая содержит всю информацию о камере.

+0

Так как вы используете C++ я рекомендовал бы использовать классы вместо globals – Quest

+0

Я использую классы, я использовал глобальные переменные, потому что здесь намного проще размещать сообщения. –

ответ

1

Я бы предположил, что ваша скорость изменяется, когда вы двигаетесь в нескольких направлениях сразу, потому что вы нормализуете свою скорость.

Например, перемещение в Z:

Velocity = (0, 0, 0.01) 
Speed = (0,0, 0.01) 
Normalized Velocity = (0, 0, 1) 
PosDelta = (0, 0, 0.01) 

и перемещение в X + Z:

Velocity = (0.02, 0, 0.01) 
Speed = (0.02, 0, 0.01) 
Normalized Velocity = (0.897, 0, 0.435) 
PosDelta = (0.018, 0, 0.0044)  

Что касается вашей инверсии направления я предполагаю, что это может быть отчасти связано с вашей относительно странный метод использования скорости/скорости (см. ниже) и, возможно, из-за точности поплавков. Что касается последнего пункта, что вы думаете следующие выходы кода (игнорировать потенциальные оптимизации компилятора):

float test1 = 0f; 

test1 += 0.1f; 
test1 += 0.1f; 
test1 += 0.1f; 
test1 += 0.1f; 
test1 += 0.1f; 

test1 -= 0.1f; 
test1 -= 0.1f; 
test1 -= 0.1f; 
test1 -= 0.1f; 
test1 -= 0.1f; 

printf("%g\n", test1); 

It (? Вероятно) не будет выводить очевидный ответ 0 поскольку 0.1 не может быть точно представлены в базе-2 , Он печатает 1.49012e-008 в моей системе. Что может случиться, вы можете быть близки к 0, но не точно, что может вызвать появление инверсии координат. Вы можете избавиться от этого путем округления до определенной точности.

Ваш общий метод обработки скорости/скорости/положения немного странный и может быть источником ваших трудностей. Например, я ожидал бы, что Velocity будет вектором, представляющим скорость игрока, а не нормализованным вектором, как у вас.Я бы сделал что-то вроде:

SpeedX = 0.0f; 
SpeedY = 0.0f; 
SpeedZ = 0.0f 

if(IsKeyDown('A')) SpeedX += -0.02f; 
if(IsKeyDown('D')) SpeedX += 0.02f; 
... 

Velocity.x += SpeedX; 
Velocity.y += SpeedY; 
Velocity.z += SpeedZ; 

D3DXVECTOR3 NormVelocity; 
D3DXVec3Normalize(&NormVelocity, &Velocity); 

//Round velocity here if you need to 
Velocity.x = floor(Velocity.x * 10000)/10000.0f; 
... 

float FrameTime = 1; //Use last frame time here 

PosDelta.x = Velocity.x * FrameTime; 
PosDelta.y = Velocity.y * FrameTime; 
PosDelta.z = Velocity.z * FrameTime; 

Это избавляет вас от изменения скорости при движении в более чем одном направлении. Он также позволяет вам правильно компенсировать изменение частоты кадров, если вы установите FrameTime как время последнего кадра (или значение, полученное из него). Он также правильно останавливает игрока от перемещения, когда он пытается двигаться в двух противоположных направлениях одновременно.

Что касается вашего последнего вопроса относительно распада Y-скорости, то есть несколько способов сделать это. Вы можете просто сделать что-то вроде:

каждый кадр (отрегулируйте константу в соответствии с вашими потребностями). Более точная модель будет делать что-то вроде:

if (Velocity.y > 0) { 
    Velocity.y -= 0.001f; //Pick constant to suit 
    if (Velocity.y < 0) Velocity.y = 0; 
} 

еще лучший способ будет использовать последний раз рамки для учета изменения частоты кадров, как:

Velocity.y -= FrameTime * 0.2f; //Pick constant to suit 
+0

Спасибо за ответ и помощь, но у меня все еще есть проблема. У меня есть код, который я скоро опубликую по оригинальному вопросу с помощью редактирования. Проблема в том, что видимая скорость останется такой же, как я нажимаю (я говорю о скорости по оси X). Не могли бы вы помочь мне? –

+0

Ничего, я забыл добавить знак «+» при написании нового кода ... Спасибо, что решили мою проблему! –