1.Introduction.

The first version of this tutorial has been made by Regress, I have just rewritten the original code to make it more understandable. I'm not a Yake or C++ specialist so don't hesitate to correct me if something is wrong. In fact I written this tutorial as an exercise to discover Yake, then I thought that it could be a good idea to share it.

2.Basic application.

Before making the RAF application we need some usefull hearders file.

#include "yake\base\yake.h"
#include "yake\audio\yakeAudio.h"
#include "yake\input\yakeInput.h"
#include "yapp\base\yapp.h"
#include "yapp\raf\yakeRaf.h"
 
#if YAKE_PLATFORM == PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

Ok so the first thing we want to do in our RAF application is … the application itself. With RAF it's pretty easy and we will just derivate the ExampleApplication class from the RAF frame work. As it will be a very simple application we will use only one state.

//Very basic application with only one state.
class TheApp : public raf::ExampleApplication<TheConfiguration>
{
public:
	TheApp(void);
 
protected:
	virtual raf::MainState* createMainState()
	{
		return new YapMainState(*this);
	}
};

ExampleApplication use a template in order to wrap a configuration to the raf base application. This configuration is class which can be used to tell Yake which modules we are using and which plug ins they are based on:

//Configuration struct, storing the module used for our application.
struct TheConfiguration : public raf::ApplicationConfiguration
{
	virtual StringVector getLibraries()
	{ return MakeStringVector() << "graphicsOgre" << "inputOgre"; }
 
	virtual StringVector getInputSystems()
	{ return MakeStringVector() << "ogre"; }
 
	virtual StringVector getGraphicsSystems()
	{ return MakeStringVector() << "ogre3d"; }
};

In this tutorial we will be only using Ogre 3d for rendering and Ogreinput for keyboard and mouse input. In next tutorials we will just add the new module we want to use.

Last thing to do is to just write a main function which launch our application:

#if YAKE_PLATFORM == PLATFORM_WIN32
   INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
   int main(int argc, char *argv[])
#endif
{
	// Use default executor for convenience.
	// It's always possible to manually execute TheApp::initialise() etc.
	return (raf::runApplication( TheApp() )) ? 0 : 1;
}

That's all we need for our application !

3.Main state.

In this tutorial we are using only one state so everything will be done here. Our main state will be based on the RTMainState in the raf framework. A lot of things, like worlds creation, camera and view port etc , are already handled in the base class so we don't need to worry about them. If you feel curious you can check the base class to see how it is done. All the rest of the interesting stuff will be done here.

This class looks as follow:

//Main (and only for the moment) state of our application. 
class YapMainState :
	public raf::RtMainState
{
public:
	// YapMainState(raf::Application& owner); <-- this constructor has linking problems
        YapMainState(raf::Application& owner) : raf::RtMainState(owner) {} // <- use this instead
 
protected:
 
virtual void onCreateScene(); //-> called at startup to build the scene.
virtual void onFrame(const real timeElapsed); //->called every time a new frame is drawn.
 
 
private:
 
	//graphical world 
	yake::graphics::IWorld*			mGWorld;
 
	//Well, a few lights might not be so bad...
	graphics::ISceneNode*			mLightOneNode;
	graphics::ILight*			mLightOne;
 
	//Light, from yonder sky, tis the sun! And an associated SceneNode, apparently.
	graphics::ILight*			mSunLight;
	graphics::ISceneNode*			mSunLightNode;
 
	//Shadows
	graphics::StringVector			mShadowTechniques;
	size_t					mCurrentShadowTechnique;
 
	//utils
	yake::math::RandomNumberGeneratorMT 	mRandgen;
	yake::math::Math 			mMath; 
 
	struct Bounds {
		real					leftBound;
		real					rightBound;
		real					lowerBound;
		real					upperBound;
	};
 
	//Let's define a simple class for easy access to a SceneNode and the associated
	//Entity.
	class SimpleObj {
		public:
		graphics::ISceneNode*			pSN;
		graphics::IEntity*			pE;
		real					x,y,mSize,mHeight;
		real					verticalDirection, horizontalDirection;
		Bounds					bounds;
		void setPosition (real _x, real _y) 
		{
			x = _x;
			y = _y;
 
			if (x > bounds.rightBound) x = bounds.rightBound;
			else if (x < bounds.leftBound) x = bounds.leftBound;
 
			if (y > bounds.upperBound) y = bounds.upperBound;
			else if (y < bounds.lowerBound) y = bounds.lowerBound;
 
 
			if (pSN)
				pSN->setPosition( Vector3(x,mHeight,y));
		}
		void translate (real tx, real ty)
 
		{
			x += tx;
			y += ty;
 
			if (x > bounds.rightBound) x = bounds.rightBound;
			else if (x < bounds.leftBound) x = bounds.leftBound;
 
			if (y > bounds.upperBound) y = bounds.upperBound;
			else if (y < bounds.lowerBound) y = bounds.lowerBound;
 
			if (pSN)
				pSN->setPosition( Vector3(x,mHeight,y));
 
 
		}
	};
 
 
 
	SimpleObj				mPaddle1;
	SimpleObj				mPaddle2;
	SimpleObj				mBall;
	SimpleObj				mGroundPlane;
	Bounds					mArena;
 
 
 
	real mBallSpeed;
	real mPaddleSpeed;
 
 
 
 
 
private:
 
//Setup function used to create the scene.
 
	void SetupGround(void);
	void SetupVariables(void);
	void SetupBall(void);
	void SetupPaddle1(void);
	void SetupPaddle2(void);
	void SetupLights(void);
	void SetupInput(void);
	void SetupShadowTechnique(void);
 
 
//Input listeners
 
	void onKey(const yake::input::KeyboardEvent & e);
	void onMB(uint8 btn);
	void onMMove(Vector3 mVector);
 
};

There is 2 important functions: onCreateScene and onFrame. The first one is called at startup so we will use it to build our scene and the second one is called every frame before the rendering. We also define a SimpleObj class that we can use to handle all our game objects properties and perform some basic operation (moving or translating).

4.Creating the scene.

Let's have a look at the scene creation:

	YAKE_LOG_INFORMATION("OnCreateScene ...");
 
	SetupVariables();
	SetupInput();
 
	YAKE_LOG_INFORMATION("Creating world");
	mGWorld = getGraphicalWorld();
	YAKE_ASSERT( mGWorld );
 
	YAKE_LOG_INFORMATION("Creating viewport & camera");
	//Camera and viewport creation is done by base class.
	// position camera
	getDefaultCamera()->setFixedYawAxis(Vector3::kUnitY);
	getDefaultCamera()->setPosition(Vector3( 0, 1500, 10));
	getDefaultCamera()->lookAt(Vector3(0,0,0));
 
 
	YAKE_LOG_INFORMATION("Creating ball");
	SetupBall();
 
	YAKE_LOG_INFORMATION("Creating ground");
	SetupGround();
 
	YAKE_LOG_INFORMATION("Creating Paddle1");
	SetupPaddle1();
 
	YAKE_LOG_INFORMATION("Creating Paddle2");
	SetupPaddle2();
 
	YAKE_LOG_INFORMATION("Initializing lights");
	SetupLights();
 
	YAKE_LOG_INFORMATION("Initializing shadow");
	mShadowTechniques = mGWorld->getShadowTechniques ();
	SetupShadowTechnique();
	mGWorld->setShadowsEnabled(true);
 
 
	YAKE_LOG_INFORMATION("Scene creation done.");

We create the graphical world, a view port a camera, some lights and shadows and finally our objects.

For the lights, we will use one as static to illuminate everything and one moving attached on the paddle1 node to create some nice shadows on our playground:

void YapMainState::SetupLights(void)
{
	// fixed light (sun)
	mSunLight = mGWorld->createLight();
	mSunLightNode = mGWorld->createSceneNode();
	mSunLightNode->attachLight(mSunLight);
 
	mSunLight->setType(yake::graphics::ILight::LT_SPOT);
	mSunLightNode->setPosition(Vector3(1000,1250,500));
	mSunLight->setSpotlightRange(30,50,1);
	Vector3 dir = -mSunLightNode->getPosition();
	mSunLight->setDirection(dir.normalisedCopy());
	mSunLight->setDiffuseColour(Color(0.35, 0.35, 0.38));
	mSunLight->setSpecularColour(Color(0.9, 0.9, 1));
 
	// movable light 1.
	// This light will be attached to the paddle 1 node to create some shadows.
	mLightOneNode = mPaddle1.pSN->createChildNode();
	YAKE_ASSERT( mLightOneNode );
	mLightOne = mGWorld->createLight();
	YAKE_ASSERT( mLightOne );
	mLightOneNode->attachLight( mLightOne );
	mLightOne->setType( graphics::ILight::LT_POINT );
	mLightOne->setDiffuseColour( Color(0.6,0.7,0.8) );
	mLightOne->setSpecularColour( Color(1,1,1) );
	mLightOne->setAttenuation( 8000, 1, 0.0005, 0 );
 
	mLightOneNode->translate(Vector3( 0, 20, 0 ));
}

As a demonstration, we will let the user swap between shadows technique so we retrieve from the graphical world all the shadow technique possible and the scroll through them in the SetupShadowTechnique method:

void YapMainState::SetupShadowTechnique(void)
{
 
	if (mShadowTechniques.empty())
		return;
 
	mCurrentShadowTechnique = ++mCurrentShadowTechnique % mShadowTechniques.size();
	const String& name = mShadowTechniques[mCurrentShadowTechnique];
	graphics::StringMap params;
 
	params["tex_size"] = "1024";
	params["tex_count"] = "3";
	params["far_distance"] = "3000";
	params["directional_light_extrusion_distance"] = "3000";
 
	mGWorld->selectShadowTechnique( mShadowTechniques[mCurrentShadowTechnique], params );
	if (name == "stencil_additive")
	{
		mSunLight->setCastsShadows( true );
 
		mLightOne->setType(yake::graphics::ILight::LT_POINT);
		mLightOne->setCastsShadows(true);
		mLightOne->setDiffuseColour( Color(0.9,0.7,0.7) );
		mLightOne->setSpecularColour( Color(1,1,1) );
		mLightOne->setAttenuation(8000,1,0.0005,0);
	}
	else if (name == "stencil_modulative")
	{
 
		mSunLight->setCastsShadows( false );
 
		mLightOne->setType(yake::graphics::ILight::LT_POINT);
		mLightOne->setCastsShadows( true );
		mLightOne->setDiffuseColour( Color(0.9,0.7,0.7) );
		mLightOne->setSpecularColour( Color(1,1,1) );
		mLightOne->setAttenuation(8000,1,0.0005,0);
	}
	else if (name == "texture_modulative")
	{
		mSunLight->setCastsShadows( true );
 
		// Change fixed point light to spotlight
		mLightOne->setType(yake::graphics::ILight::LT_SPOT);
		mLightOne->setDirection(-Vector3::kUnitZ);
		mLightOne->setCastsShadows(true);
		mLightOne->setDiffuseColour( Color(0.9,0.7,0.7) );
		mLightOne->setSpecularColour( Color(1,1,1) );
		mLightOne->setAttenuation(8000,1,0.0005,0);
		mLightOne->setSpotlightRange(80,90,1);
	}
	std::cout << "SHADOW TECHNIQUE: " << name.c_str() << "\n";
}

Now let's create the ground, scale it and position it:

void YapMainState::SetupGround(void)
{
	// create entity
	mGroundPlane.pE = mGWorld->createEntity("plane_1x1.mesh");
	YAKE_ASSERT( mGroundPlane.pE );
	mGroundPlane.pE->setCastsShadow( false  );
 
	// create scene node and attach entity to node
	mGroundPlane.pSN = mGWorld->createSceneNode("root");
	YAKE_ASSERT( mGroundPlane.pSN );
	mGroundPlane.pSN->attachEntity( mGroundPlane.pE );
	//Set size and position.
	mGroundPlane.pSN->setScale( Vector3(1200,1,1200) );
	mGroundPlane.pSN->setPosition (Vector3(0,0,0));
	//Set material.
	mGroundPlane.pE->setMaterial("Examples/GrassFloor");		
}

Finally we can create the others object based on the same procedure. The ball will have a random direction at startup.

void YapMainState::SetupBall(void)
{
	mBall.pSN = mGWorld->createSceneNode();
	YAKE_ASSERT( mBall.pSN );
 
	mBall.pE = mGWorld->createEntity("Sphere_d1.mesh");
	YAKE_ASSERT( mBall.pE );
 
	mBall.pSN->setScale(Vector3(mBall.mSize,mBall.mSize,mBall.mSize)); 
 
 
	mBall.pE->setCastsShadow( true );
	mBall.pE->setMaterial("Examples/BumpMapping/MultiLightSpecular");
 
	mBall.pSN->attachEntity( mBall.pE );
 
	mBall.setPosition(mBall.x,mBall.y);
 
	//Apply a random direction to the ball.
	real dir = mRandgen () * 2 * mMath.PI;
	mBall.horizontalDirection =  mMath.Cos (dir);
	mBall.verticalDirection =  mMath.Sin (dir);
 
}
 
void YapMainState::SetupPaddle1(void)
{
	// setup Paddle1
	mPaddle1.pSN = mGWorld->createSceneNode();
	YAKE_ASSERT( mPaddle1.pSN );
 
	mPaddle1.pE = mGWorld->createEntity("cube.mesh");
	YAKE_ASSERT( mPaddle1.pE );
	mPaddle1.pE->setMaterial("2 - Default");
	mPaddle1.pE->setCastsShadow( true );
 
	mPaddle1.pSN->attachEntity( mPaddle1.pE );
	mPaddle1.pSN->setScale( Vector3( 30./100., 100./100., mPaddle1.mSize/100.)); //original cube size is 100.
	mPaddle1.setPosition( mPaddle1.x,mPaddle1.y);
 
}
 
void YapMainState::SetupPaddle2(void)
{
	// setup Paddle2
	mPaddle2.pSN = mGWorld->createSceneNode();
	YAKE_ASSERT( mPaddle2.pSN );
 
	mPaddle2.pE = mGWorld->createEntity("cube.mesh");
	YAKE_ASSERT( mPaddle2.pE );
	mPaddle2.pE->setMaterial("2 - Default");
	mPaddle2.pE->setCastsShadow( true );
 
 
	mPaddle2.pSN->attachEntity( mPaddle2.pE );
	mPaddle2.pSN->setScale(  Vector3( 30./100., 100./100., mPaddle1.mSize/100.)); //original cube size is 100.
	mPaddle2.setPosition( mPaddle1.x,mPaddle1.y);
 
}

Now we need to initialize all the parameters of our game so we just add a method to do it.

void YapMainState::SetupVariables(void)
{
	//One function to cleanly define all of the variables
	//CHALLENGE: Load all of the variables out of an XML config file.
 
	mBallSpeed = 600;
	mPaddleSpeed = 500.0;
 
	mPaddle1.x = -500;
	mPaddle1.y = 0;
	mPaddle1.mSize = 200;
	mPaddle1.mHeight = 50;
 
	mPaddle1.bounds.lowerBound = -600+(mPaddle1.mSize/2);
	mPaddle1.bounds.upperBound = 600-(mPaddle1.mSize/2);
	mPaddle1.bounds.leftBound = mPaddle1.x;
	mPaddle1.bounds.rightBound = mPaddle1.x;
 
	mPaddle2.x = 500;
	mPaddle2.y = 0;
	mPaddle2.mSize = 200;
	mPaddle2.mHeight = 50;
 
	mPaddle2.bounds.lowerBound = -600+(mPaddle2.mSize/2);
	mPaddle2.bounds.upperBound = 600-(mPaddle2.mSize/2);
	mPaddle2.bounds.leftBound = mPaddle2.x;
	mPaddle2.bounds.rightBound = mPaddle2.x;
 
 
	mBall.x = 0;
	mBall.y = 0;
	mBall.mSize = 40;
	mBall.mHeight = mBall.mSize / 2.;
 
	mBall.bounds.lowerBound = -600+(mBall.mSize/2);
	mBall.bounds.upperBound = 600-(mBall.mSize/2);
	mBall.bounds.leftBound = -600+(mBall.mSize/2);
	mBall.bounds.rightBound = 600-(mBall.mSize/2);
 
	mArena.leftBound = -600;
	mArena.rightBound = 600;
	mArena.upperBound = 600;
	mArena.lowerBound = -600;	
}

5.Adding Keyboard and Mouse listener.

We will allow the user to change the camera orientation and by pressing the ā€œSā€ key, to change the shadow technique. Pressing the ESC key will exit the application.

First we need to register our listeners to the keyboard and mouse event generator:

void YapMainState::SetupInput(void)
{
	// setup event input generators and bind them to the correct function.
	getApp().getKeyboardEventGenerator()->subscribeToKeyDown( Bind1( &YapMainState::onKey, this ) );
	getApp().getMouseEventGenerator()->subscribeToMouseButtonDown( Bind1( &YapMainState::onMB, this ) );
	getApp().getMouseEventGenerator()->subscribeToMouseMoved( Bind1( &YapMainState::onMMove, this ) );
}

Moving the mouse will change the camera orientation. This is easly done with the following method:

void YapMainState::onMMove(Vector3 mVector)
{
 
	std::cout << "MouseMove.x: " << static_cast<int>( mVector.x ) << std::endl;
	std::cout << "MouseMove.y: " << static_cast<int>( mVector.y ) << std::endl;	
	getDefaultCamera()->yaw(-( mVector.x ) * 0.13);
	getDefaultCamera()->pitch(-( mVector.y ) * 0.13);
}

Hitting a mouse button will just log the pressed button to the log window:

void YapMainState::onMB(uint8 btn)
{
	std::cout << "MB: " << static_cast<int>(btn) << std::endl;
}

And finally the keyboard listener:

void YapMainState::onKey(const yake::input::KeyboardEvent & e)
{
	std::cout << "Key pressed: " << e.keyCode << "\n";
 
	if (e.keyCode == input::KC_ESCAPE)
		this->requestQuit();
	else if (e.keyCode == input::KC_S)
		this->SetupShadowTechnique();
}

The paddles movments will be handled synchronously with the rendering in the onFrame method.

6.Making everything move.

Now we want to have everything move so we will get a closer look at the onFrame method:

void YapMainState::onFrame (const real timeElapsed)
{
	real distance;
 
	if ( getApp().getKeyboard() )
	{
		//Camera stuff.
		distance = -200. * timeElapsed;
		if ( getApp().getKeyboard()->isKeyDown(input::KC_LEFT))
		  getDefaultCamera()->moveRelative( distance*Vector3::kUnitX ); //Strafe Left (TS_LOCAL)
		if ( getApp().getKeyboard()->isKeyDown(input::KC_RIGHT))
		  getDefaultCamera()->moveRelative( -distance*Vector3::kUnitX );  //Strafe Right (TS_LOCAL)
		if ( getApp().getKeyboard()->isKeyDown(input::KC_UP))
		  getDefaultCamera()->moveRelative( distance*Vector3::kUnitZ );//Move Forward in TS_LOCAL
		if ( getApp().getKeyboard()->isKeyDown(input::KC_DOWN))
		  getDefaultCamera()->moveRelative( -distance*Vector3::kUnitZ );//Move Backwards in TS_LOCAL
 
 
		//Paddle movement.
		distance = mPaddleSpeed * timeElapsed;
		if ( getApp().getKeyboard()->isKeyDown(input::KC_A)) //paddle1 down
		  mPaddle1.translate (0,distance);
		if ( getApp().getKeyboard()->isKeyDown(input::KC_Q)) //paddle 1up
		  mPaddle1.translate (0,-distance);
		if ( getApp().getKeyboard()->isKeyDown(input::KC_L)) //paddle 2 down
		  mPaddle2.translate (0,distance);
		if ( getApp().getKeyboard()->isKeyDown(input::KC_P)) //paddle 2 up
		  mPaddle2.translate (0,-distance);
	}
 
	//move ball !
	distance = mBallSpeed * timeElapsed;
	mBall.translate (mBall.horizontalDirection * distance,mBall.verticalDirection * distance);
 
	//rotate the ball.
	yake::math::Matrix3 RotMatrix;
	yake::math::Quaternion RotQuat;
 
	//Calculate rotation matrix depending of the ball speed and direction.
	RotMatrix.FromEulerAnglesXYZ  (mBall.verticalDirection * distance * 2 / mBall.mSize,0,-mBall.horizontalDirection * distance * 2 / mBall.mSize);
	//Calculate quaternion from this matrix.
	RotQuat.FromRotationMatrix (RotMatrix);
	//apply rotation.
	mBall.pSN->rotate (RotQuat);
 
 
	//Check ball collision with arena.
 
	if  (((mBall.x + mBall.mSize / 2) >= mArena.rightBound) || ((mBall.x - mBall.mSize / 2) <= mArena.leftBound))
	  mBall.horizontalDirection = -mBall.horizontalDirection + mRandgen()*0.01; //invert horizontal direction and add some random stuff for fun.
	if  (((mBall.y + mBall.mSize / 2) >= mArena.upperBound) || ((mBall.y - mBall.mSize / 2) <= mArena.lowerBound))
	  mBall.verticalDirection = -mBall.verticalDirection + mRandgen()*0.01; //invert vertical direction and add some random stuff for fun.
 
 
	//Check ball collision with paddle1. (works ok but not so realistic.)
 
	real dx, dy;
 
	dx = mMath.Abs (mBall.x-mPaddle1.x);
	dy = mMath.Abs (mBall.y-mPaddle1.y);
 
	//First, check if there is a collision
	if ((dx <= (mBall.mSize / 2 +15)) && (dy <= (mBall.mSize / 2 + mPaddle1.mSize / 2)))
	{
	  //calculate collision angle and compare with paddle diagonal.
	  real angle = mMath.ATan2 ((dy),(dx));
	  real diag = mMath.ATan2 (mPaddle1.mSize/2,15.);
	  std::cout << "ball collision with paddle 1, angle =  " << angle << std::endl;
	  if ( (angle >= -diag) && 	(angle <=  diag))
	  {
	    mBall.horizontalDirection = -mBall.horizontalDirection + (mRandgen()-0.5)*0.05; //invert horizontal direction and add some random stuff for fun.
	    //Move the ball outside the paddle.
	    if ((mBall.x-mPaddle1.x) > 0) 
	      mBall.setPosition (mPaddle1.x + mBall.mSize / 2. + 15.,mBall.y); 
	    else
	      mBall.setPosition (mPaddle1.x - mBall.mSize / 2. - 15.,mBall.y); 
	  }
	  else 
	  {	
	    mBall.verticalDirection = -mBall.verticalDirection + (mRandgen()-0.5)*0.05; //invert vertical direction and add some random stuff for fun.
	    //Move the ball outside the paddle.
	    if ((mBall.y-mPaddle1.y) > 0) 
	      mBall.setPosition (mBall.x,mPaddle1.y + mBall.mSize /2. + mPaddle1.mSize/2.);
	    else
	      mBall.setPosition (mBall.x,mPaddle1.y - mBall.mSize /2. - mPaddle1.mSize/2.);
	  }
	}
 
	//Check ball collision with paddle2. (works ok but not so realistic.)
 
	dx = mMath.Abs (mBall.x-mPaddle2.x);
	dy = mMath.Abs (mBall.y-mPaddle2.y);
 
	//First, check if there is a collision
	if ((dx <= (mBall.mSize / 2 +15)) && (dy <= (mBall.mSize / 2 + mPaddle2.mSize / 2)))
	{
	  //calculate collision angle and compare with paddle diagonal.
	  real angle = mMath.ATan2 ((dy),(dx));
	  real diag = mMath.ATan2 (mPaddle2.mSize/2,15.);
	  std::cout << "ball collision with paddle 2, angle =  " << angle << std::endl;
	  if ( (angle >= -diag) && 	(angle <=  diag))
	  {
	    mBall.horizontalDirection = -mBall.horizontalDirection + (mRandgen()-0.5)*0.05; //invert horizontal direction and add some random stuff for fun.
	    //Move the ball outside the paddle.
	    if ((mBall.x-mPaddle2.x) > 0) 
	      mBall.setPosition (mPaddle2.x + mBall.mSize / 2. + 15.,mBall.y); 
	    else
	      mBall.setPosition (mPaddle2.x - mBall.mSize / 2. - 15.,mBall.y); 
	  }
	  else 
	  {	
	    mBall.verticalDirection = -mBall.verticalDirection + (mRandgen()-0.5)*0.05; //invert vertical direction and add some random stuff for fun.
	    //Move the ball outside the paddle.
	    if ((mBall.y-mPaddle1.y) > 0) 
	      mBall.setPosition (mBall.x,mPaddle2.y + mBall.mSize /2. + mPaddle2.mSize/2.);
	    else
	      mBall.setPosition (mBall.x,mPaddle2.y - mBall.mSize /2. - mPaddle2.mSize/2.);
	  }
	}
}

The first things to do is to get the user input and move either the camera or the paddles. The movment is scaled as a function of the time elapsed so the movment speed doesn't depend on the frame rate.

Then the ball is updated for rotation and position.

And finally a check for collision with walls or paddles is done and the ball position and direction is updated accordingly.

7.Conclusion

This example is very basic and doesn't show really the interest of yake. In fact, it could have been done with Ogre alone nearly as easy. Its purpose however is to serve as support for the next tutorials where the interest of yake will be clearer.

Lythaniel

8.Comments

I would like to say thanks for this tutorial and all the great effort that went into creating it. This will definitely help not only me, but many others getting started with yake. Very much appreciated. ~Justin~

Very usefull tutorial. I have made some presentation changements.

~Flyers~

 
tutorials/beginners/yap_1._the_basics.txt · Last modified: 2008/02/21 21:59 (external edit)
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki