FrameListener,是Ogre最有用的部分,下面我们就先来看一下代码:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using MogreFramework;
using Mogre;
using System.Drawing;
namespace Tutorial04
{
static class Program
{
[STAThread]
static void Main()
{
try
{
MyOgreWindow win = new MyOgreWindow();
new SceneCreator(win);
win.Go();
}
catch (System.Runtime.InteropServices.SEHException)
{
if (OgreException.IsThrown)
MessageBox.Show(OgreException.LastException.FullDescription, "An Ogre exception has occurred!");
else
throw;
}
}
}
class MyOgreWindow : OgreWindow
{
const float TRANSLATE = 200;
const float ROTATE = 0.2f;
bool mRotating = false;
Vector3 mTranslation = Vector3.ZERO;
Point mLastPosition;
protected override void CreateInputHandler()
{
this.Root.FrameStarted += new FrameListener.FrameStartedHandler(FrameStarted);
this.KeyDown += new KeyEventHandler(KeyDownHandler);
this.KeyUp += new KeyEventHandler(KeyUpHandler);
this.MouseDown += new MouseEventHandler(MouseDownHandler);
this.MouseUp += new MouseEventHandler(MouseUpHandler);
this.MouseMove += new MouseEventHandler(MouseMoveHandler);
}
bool FrameStarted(FrameEvent evt)
{
Camera.Position += Camera.Orientation * mTranslation * evt.timeSinceLastFrame;
return true;
}
void KeyDownHandler(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
case Keys.W:
mTranslation.z = -TRANSLATE;
break;
case Keys.Down:
case Keys.S:
mTranslation.z = TRANSLATE;
break;
case Keys.Left:
case Keys.A:
mTranslation.x = -TRANSLATE;
break;
case Keys.Right:
case Keys.D:
mTranslation.x = TRANSLATE;
break;
case Keys.PageUp:
case Keys.Q:
mTranslation.y = TRANSLATE;
break;
case Keys.PageDown:
case Keys.E:
mTranslation.y = -TRANSLATE;
break;
}
}
void KeyUpHandler(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
case Keys.W:
case Keys.Down:
case Keys.S:
mTranslation.z = 0;
break;
case Keys.Left:
case Keys.A:
case Keys.Right:
case Keys.D:
mTranslation.x = 0;
break;
case Keys.PageUp:
case Keys.Q:
case Keys.PageDown:
case Keys.E:
mTranslation.y = 0;
break;
}
}
void MouseDownHandler(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Cursor.Hide();
mRotating = true;
mLastPosition = Cursor.Position;
}
}
void MouseUpHandler(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Cursor.Show();
mRotating = false;
}
}
void MouseMoveHandler(object sender, MouseEventArgs e)
{
if (mRotating)
{
float x = mLastPosition.X - Cursor.Position.X;
float y = mLastPosition.Y - Cursor.Position.Y;
Camera.Yaw(new Degree(x * ROTATE));
Camera.Pitch(new Degree(y * ROTATE));
mLastPosition = Cursor.Position;
}
}
}
class SceneCreator
{
public SceneCreator(OgreWindow win)
{
win.SceneCreating += new OgreWindow.SceneEventHandler(SceneCreating);
}
void SceneCreating(OgreWindow win)
{
win.SceneManager.AmbientLight = new ColourValue(0.25f, 0.25f, 0.25f);
Entity ent = win.SceneManager.CreateEntity("Ninja", "ninja.mesh");
win.SceneManager.RootSceneNode.CreateChildSceneNode().AttachObject(ent);
Light light = win.SceneManager.CreateLight("Light");
light.Type = Light.LightTypes.LT_POINT;
light.Position = new Vector3(250, 150, 250);
light.DiffuseColour = ColourValue.White;
light.SpecularColour = ColourValue.White;
win.Camera.Position = new Vector3(0, 200, 400);
win.Camera.LookAt(ent.BoundingBox.Center);
}
}
}
FrameListeners
在Ogre中,我们可以注册一个类在每个Frame呈现之前和之后接收通知,root提供了FrameStarted和FrameEnded事件来处理这些。Ogre的主要循环过程如下:
- Root对象发起FrameStarted事件;
- Root呈现一个frame;
- Root对象发起FrameEnded事件。
这个循环会一直执行,直到其中一个event handlers返回false。FrameEvent对象包括两个变量,但只有timeSinceLastFrame在一个FrameListener中有用。这个变量记录了到上一次FrameStarted或FrameEnded的时间间隔,注意到在frameStarted方法中, FrameEvent.TimeSinceLastFrame指的是到上一次FrameStarted事件的时间,而不是FrameEnded event。
我们写一个简单的FrameStarted函数:
bool FrameStarted(FrameEvent evt) { return true; }
把它添加到Root.FrameStarted事件中:
this.Root.FrameStarted += new FrameListener.FrameStartedHandler(FrameStarted);
要使程序响应键盘、鼠标事件,必须添加相应的事件响应代码,见开头的代码部分。需要强调的是,需要在FrameStarted方法中添加如下代码,使响应被呈现:
Camera.Position += Camera.Orientation * mTranslation * evt.timeSinceLastFrame;
按F5运行,就可以用左右上下前后移动摄像头。