A Simple Turret
From C4 Engine Wiki
This tutorial is the third in a series of tutorials on how to make a simple game with C4. The first two tutorials are A Simple Projectile and A Simple Tank. This time we will add a turret gun which will track and fire at the player.
Here are the steps:
1. Open your C4 solution file, which is in the directory ..\C4\VisualStudio2010\C4, in Visual Studio and then open SimpleChar.cpp and SimpleChar.h.
2. Create a new file called SimpleTurret.cpp in the directory ..\C4\GameCode and copy the following code into it:
#include "SimpleTurret.h"
using namespace C4;
TurretController::TurretController() : Controller(kControllerTurret)
{
}
TurretController::~TurretController()
{
}
bool TurretController::ValidNode(const Node *node)
{
return (node->GetNodeType() == kNodeModel || node->GetNodeType() == kNodeGeometry);
}
void TurretController::Preprocess(void)
{
Controller::Preprocess();
myCount = 0;
const Node *target = GetTargetNode();
originalTransform = target->GetWorldTransform();//GetNodeTransform();
Point3D originalDirection = Point3D(originalTransform[0].x,originalTransform[0].y, originalTransform[0].z);
originalView = (originalDirection).Normalize();
//Find the marker on the Turret. It is the point from which to fire.
Node *root = GetTargetNode();
Node *thisnode = root;
String<30> nodeName = "NoName";
bool found = false;
do
{
nodeName = "NoName";
if (thisnode->GetNodeName() != NULL)
nodeName = thisnode->GetNodeName();
if ((Text::CompareText(nodeName, "TurretBarrel")) ) {
turretBarrel = thisnode;
found = true;
}
thisnode = root->GetNextNode(thisnode);
} while (thisnode && !found);
}
void TurretController::Move(void)
{
World *world = TheWorldMgr->GetWorld();
Node *target = GetTargetNode();
/* To fire at camera */
World *myWorld = TheWorldMgr->GetWorld();
const FrustumCamera *myCamera = myWorld->GetCamera();
Point3D targetPoint = myCamera->GetWorldPosition();
Point3D startPos = turretBarrel->GetWorldPosition();
Vector3D view = (targetPoint - startPos);
float x = view.x, y = view.y, z = view.z;
float distance = Sqrt(x * x + y * y + z * z);
view = view.Normalize();
if (distance < 1000.0f) {
//interpolate between the current viewing direction and the target viewing direction.
//If you use say 40.0 instead of 20.0 then it will move twice as slowly.
Vector3D updatedView = Vector3D(originalView.x+(view.x-originalView.x)/20.0f, originalView.y+(view.y-originalView.y)/20.0f, originalView.z+(view.z-originalView.z)/20.0f);
originalView = updatedView;
x = updatedView.x;
y = updatedView.y;
float f = InverseSqrt(x * x + y * y);
Vector3D right(y * f, -x * f, 0.0F);
Vector3D down = updatedView % right;
target->SetNodeMatrix3D(updatedView, -right, -down);
updatedView = updatedView.Normalize();
Vector3D objectVelocity = 5.0F * (Vector3D(distance * updatedView.x, distance * updatedView.y, distance * updatedView.z));
//Firing
if (world)
{
Controller *controller;
Model *model = nullptr;
//Fire on some condition - here is just an example
//So this is true about once every few seconds - increase (or decrease) "300"
//for longer (or shorter) pauses between shots
if ((myCount++ % (300 + Math::Random(50))) == 0)
{
//create projectile!!
controller = new BallController(objectVelocity);
model = Model::Get(kModelBall);
if (model)
{
model->SetController(controller);
Zone *zone = world->FindZone(startPos);
Point3D zonePosition = zone->GetInverseWorldTransform() * startPos;
model->SetNodePosition(zonePosition);
zone->AddNewSubnode(model);
model->Update();
}
}
}
// Invalidate the target node so that it gets updated properly
target->Invalidate();
}//if distance
}
3. Create a new file called SimpleTurret.h in the directory ..\C4\GameCode and copy the following code into it:
#ifndef SimpleTurret_h
#define SimpleTurret_h
#include "SimpleProjectile.h"
namespace C4
{
// Controller types
enum
{
kControllerTurret = 'Turr'
};
enum
{
kModelTurret = 'Turt'
};
class TurretController : public Controller
{
private:
int myCount;
Transform4D originalTransform; // The target's original transform
Vector3D originalView; // The direction turret is facing before updating each frame
Node *turretBarrel; //Marker on Turret Model from which missiles are fired
public:
TurretController();
~TurretController();
static bool ValidNode(const Node *node);
void Preprocess(void);
void Move(void);
};
}
#endif
4. Right click on SimpleChar project in the solution explorer and chose Add and then select Existing Item. Now mark the SimpleTurret.h and SimpleTurret.cpp files and add them to the SimpleChar project. Open these files.
5. In SimpleChar.h, include the new SimpleTurret code by adding an include directive just after the line where you included the SimpleProjectile.h file
#include "SimpleTurret.h"
6. Register the new Turret Controller code in SimpleChar.cpp as follows:
// Register the new Turret Controller and Model with the World Editor turretControllerReg(kControllerTurret, "Turret"), turretModelReg(kModelTurret, "Turret", "model/Turret", kModelPrecache, kControllerTurret),
7. And declre that in SimpleChar.h just after the line ParticleSystemReg<SparkSystem> sparkSystemReg; as follows:
//new for turret ControllerReg<TurretController> turretControllerReg; ModelRegistration turretModelReg;
8. Create a Turret model and save it under the Tutorials/model folder. Don't forget to add a location marker to your model at the tip of the barrel. Call that node "TurretBarrel".
9. Start C4 and press Ctrl-O to open the Water world under Tutorial/world. From the World editor pages menu, open the models page. In the models page on the left of the World editor, click on your Turret model and then click in the top viewport to place your turret it in the Water world. Use the move tool to raise it slightly above the ground.
10. Press Ctrl-P to try out your new game. You should find that the turrets rotate to track and fire at your tank.
