![]() |
|
![]() www.icons8.com |
This script shows how to rotate a plane of character blocks. This a quit advanced topic, some knowledge about vector operation and an understanding how rotating coordinates in 3D space are needed.
This is the "Tutorial21" included in the Tutorial-Download..
Main work is done in OnChar() - for other functions see other tutorials.
The script rotates three lines of the C64 screen around the Y and X axis. The
rotation animation is done in the OnFrameEnd() function, where only the rotation
angles are set.
The OnUser() function reacts to user input to one of the five script defined
buttons. OnLoad() just setups our emulator and 3D scene as already seen in prior
tutorials.
To understand how rotation works in context of YACE, you should know, that
each character (and sprite) has ist own rotation coordinate, which is the
left/bottom.
So setting one or more rotations to the character (or sprite) (see
BlockManipulation)
will only rotate it around its left/bottom coordinate. To set the position in 3D
you need to set translation (xTranslation, yTranslation, zTranslation) values in
BlockManipulation; if you want to rotate multiple character around an arbitrary
point in 3D space you have first to set the position of all the characters (e.g.
into a plane) around the rotation center (0.0, 0.0, 0.0) then rotate the
coordinates and after that move everything to its desired position in 3D space.
See comments of the source code detailed informations.
const int MapEmptyId = 1;
grid<float> mapEmpty = { {0.0, 0.0},
{0.0, 0.0} }; // Depthmaps will be explained later
const int MapFlatId = 2;
grid<float> mapFlat = { {1.0, 1.0},
{1.0, 1.0} }; // Depthmaps will be explained later
float animatedRotationY = 0.0;
float animatedRotationX = 0.0;
const float pixelSize = 0.005f; // This is the default size of a 3D pixel
bool rotateX = false;
bool rotateY = false;
// Setup our scene
void OnLoad(bool reloaded)
{
APP.ClearDepthMaps(); // Clear all loaded depth maps
// Set the view mode to the new 3D
APP.ViewMode = ViewMode::Ext3D;
// Set the ambient light color and brigtness
APP.SetAmbientLight(0.3, 0.3, 0.3);
// Set the direction of the light (from the middle off the
scene (x), from top to bottom (y) and back to forth (z))
APP.SetLightDir(0.0, -1.0, +1.0);
// Position the scene, so we have the top rows in the middle
of the screen
E3D.SetScenePosition(0.1, -0.35, +1.4);
// Rotate the scene a little bit, so we can see the effect
better
E3D.SetSceneOrientation(-25.0, -15.0, 0.0, 0.0);
// Name our script buttons
GUI.SetButtonTitle(1, "Rotate X");
GUI.SetButtonTitle(2, "Rotate Y");
GUI.SetButtonTitle(3, "Rotate X and Y");
GUI.SetButtonTitle(4, "Stop");
GUI.SetButtonTitle(5, "-");
}
// This is called for every char on the screen (8x8 pixel block)
int
OnChar(int mode,
CharInfo&
charInfo, BlockManipulation& charManipulationBack,
BlockManipulation& charManipulationFore)
{
// set some default transformations for all 40*25 chars of
the C64 screen
charManipulationFore.voxelMode = Voxel::HardEdge;
charManipulationFore.depthMapIndex = MapFlatId;
if (charInfo.row >= 1 && charInfo.row <= 3 && charInfo.col >
0 && charInfo.col < 39)
{
charManipulationFore.reflective =
1.0;
charManipulationFore.zScale = 2.0;
// rotate the char itself
around his own axis (left/bottom is rotation center)
if (rotateX)
{
charManipulationFore.rotationAxis1 = Rotation::X;
charManipulationFore.rotation1 = animatedRotationX;
}
if (rotateY)
{
charManipulationFore.rotationAxis2 = Rotation::Y;
charManipulationFore.rotation2 = animatedRotationY;
}
// Now rotate the char
coordinate using a rotation Center...
float rotationCenterY = pixelSize *
63.5;
float rotationCenterX = -pixelSize *
285.0;
// ...next create a vector
with the position of each char in a x/y plane.
// The rotationCenterX and
rotationCenterY is the rotation center, in this case the middle of the three
text rows.
// Calculate the position of each
char within the plane using the original x and y coordinate.
Vector v = Vector(charInfo.x
* pixelSize + rotationCenterX, -charInfo.y * pixelSize + rotationCenterY, 0.0);
if (rotateX)
{
//
rotate the position around the x axis
v = v.RotateX(animatedRotationX);
}
if (rotateY)
{
//
rotate the position around the y axis
v = v.RotateY(animatedRotationY);
}
// move the rotated plane in
place
v += Vector(0.0, pixelSize * 71.5,
-pixelSize * 2.0);
charManipulationFore.xTranslation =
v.x;
charManipulationFore.yTranslation =
v.y;
charManipulationFore.zTranslation =
v.z;
}
return Draw::DrawCombined;
}
void OnFrameEnd()
{
// just some animation for the rotation angle (always in
degree)
animatedRotationY += 1.0;
animatedRotationX += 0.5;
}
grid<float>& OnGetDepthMap(int mode, int index, bool front)
{
switch (index)
{
case MapFlatId: return(mapFlat);
default: break;
}
return(mapEmpty);
}
void OnUser(int buttonIndex)
{
if (buttonIndex == 1)
{
rotateX = true;
rotateY = false;
animatedRotationX = 0.0;
animatedRotationY = 0.0;
GUI.ShowInfoMessage("Rotate around X
axis");
}
else if (buttonIndex == 2)
{
rotateX = false;
rotateY = true;
animatedRotationX = 0.0;
animatedRotationY = 0.0;
GUI.ShowInfoMessage("Rotate around Y
axis");
}
else if (buttonIndex == 3)
{
rotateX = true;
rotateY = true;
animatedRotationX = 0.0;
animatedRotationY = 0.0;
GUI.ShowInfoMessage("Rotate around X
and Y axis");
}
else if (buttonIndex == 4)
{
rotateX = false;
rotateY = false;
animatedRotationX = 0.0;
animatedRotationY = 0.0;
GUI.ShowInfoMessage("Stop
rotations");
}
}