Вращающиеся кубики в XNA
До сих пор мне удалось создать Quaternion
для вращения. Единственная проблема сейчас, как я могу применить это только к определенным кубам? Как и в тот момент, когда я нажимаю правую клавишу на клавиатуре, каждый куб непрерывно вращается вокруг начала координат.
Для справки, у меня есть 8 кубов, расположенных в аналогичной настройке кубика Рубика (2x2x2). Поэтому, когда я нажимаю стрелку вправо / влево, правая / левая грань куба (большой куб, состоящий из 8 меньших кубов) поворачивается на 90 градусов по часовой стрелке / против часовой стрелки.
Пример объявления одного из кубов (всего из восьми):
GameObject subCube3 = new GameObject();
Vector3 subCube3Pos = new Vector3(-0.55f, -0.55f, 0.55f);
В моем методе обновления:
// declare rotation floats
float updownRotation = 0.0f;
float leftrightRot = 0.0f;
// get state of keyboard
KeyboardState keys = Keyboard.GetState();
// if key is pressed, change value of rotation
if (keys.IsKeyDown(Keys.Right))
{
leftrightRot = -0.10f;
}
// if key is pressed, change value of rotation
if (keys.IsKeyDown(Keys.Left))
{
leftrightRot = 0.1f;
}
// if key is pressed, change value of rotation
if (keys.IsKeyDown(Keys.Up))
{
updownRotation = 0.1f;
}
// rotation around axis
Quaternion addRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), leftrightRot);
//rotation of cubes
cubeRotation = cubeRotation * addRot;
Моя функция рисования:
void DrawGameObject(GameObject gameobject)
{
//graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
foreach (ModelMesh mesh in gameobject.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
effect.World =
Matrix.CreateScale(gameobject.scale) *
Matrix.CreateFromQuaternion(cubeRotation) *
Matrix.CreateTranslation(gameobject.position);
effect.Projection = cameraProjectionMatrix;
effect.View = cameraViewMatrix;
}
mesh.Draw();
}
}
Я думаю, что проблема в том, что Matrix.CreateTranslation(gameobject.position)
очевидно, влияет на все мои кубики. Я пытался создать новый Vector3
то есть: c_component1 = Vector3.Transform(cube1pos, cubeRotation);
но даже тогда я не уверен, куда это положить и на самом деле его использовать.
Любые идеи кто-нибудь? Любая помощь будет высоко ценится.
2 ответа
Для сценария с кубиком Rubix, в дополнение к квату, который у вас уже есть, вам потребуется кватернион для каждого меньшего куба. эти меньшие кваты представляют разницу ориентации между ними и кватом для всего пакета (тот, который у вас есть в настоящее время). Подумайте, иерархическая структура здесь ничем не отличается от костяка сис. Если вы хотите повернуть только несколько кубов (скажем, все с левой стороны), вы должны только умножить кват вращения на квоты этих конкретных меньших кубов, остальные не вращаются.
Затем для рисования вы создаете окончательный ориентационный кват, объединяя кват маленького куба с кватом большого куба. Сделайте это для каждого маленького кубика.
Вам понадобится такая же структура для vector3s, представляющих позиции всех меньших кубов тоже.
Итак, допустим, у вас есть класс с именем SmallCube, и он был создан 8 раз. Он содержит кват и Vector3 (для позиции).
Предположим, что кубы расположены по всему миру, и вам нужно вращать только верхние.
Foreach(smallCube sc in smallCubes)
{
if(sc.Position.Y > 0.1f)
{
Quaternion addRot = Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(90));
sc.quat *= addRot
sc.Position = Vector3.Transform(sc.Position, addRot);
}
}
Использование кватернионов для этого в отличие от матриц имеет дополнительное преимущество. Вы можете использовать встроенный метод Quaternion.Dot() для проверки решения. Если все маленькие ориентации куба одинаковы, все цвета должны быть выровнены. Когда это произойдет, все точечное произведение будет 1.0f. В матрицах нет равных возможностей.
Вам понадобится некоторая техника, чтобы выбрать конкретный куб, который вы хотите повернуть, например, щелкнув по нему (довольно сложно в XNA для новичка) или нажав какое-то число на клавиатуре, затем в каждом GameObject вы можете проверить, выбран ли он, и только примените вращение, если оно есть.
Надеюсь, это имеет смысл...