A Simple Projectile

From C4 Engine Wiki

Jump to: navigation, search

You can make a basic projectile, which you can fire with the Space Bar, by starting with the SimpleBall tutorial code as follows:

1. Open the C4 solution file, which is in the directory ..\C4\VisualStudio2010\C4, in Visual Studio and then open SimpleBall.cpp

2. Replace the void MovementAction::Begin(void) function as follows:

void MovementAction::Begin(void)
{
	// This function is called when the input control associated with this
	// particular action is activated (e.g., a key was pressed).
	GameWorld *world = static_cast<GameWorld *>(TheWorldMgr->GetWorld());
	if (world)
	{
		// If there's currently a world loaded, apply the movement to
		// the spectator camera.
		SpectatorCamera *camera = world->GetSpectatorCamera();
		if (movementFlag & 16) {//Space Bar (Up) pressed, so fire rockets!
			GameWorld *world = static_cast<GameWorld *>(TheWorldMgr->GetWorld());
			Controller *controller1;
			Model *model1 = nullptr;
			Point3D zonePosition;
			float speed = 20.0F;// increase or decrease to change the speed
			Vector3D direction = camera->GetWorldTransform()[2];// WorldTransform[2] for front
			Point3D startPos = camera->GetWorldPosition() + Point3D(0.0F,0.0F,0.0F);
			Zone *zone = world->FindZone(startPos);
			controller1 = new BallController((speed * direction));
			model1 = Model::Get(kModelBall);
			if (model1)
			{
				model1->SetController(controller1);
				zonePosition = zone->GetInverseWorldTransform() * (startPos);
				model1->SetNodePosition(zonePosition);
				zone->AddNewSubnode(model1);
				model1->Update();
			}

		} else 
			camera->SetSpectatorFlags(camera->GetSpectatorFlags() | movementFlag);
	}
}

3. Now add a new constructor for the BallController, so that it takes an initial velocity as a parameter:

BallController::BallController(Vector3D& velocity) : RigidBodyController(kControllerBall)
{
	ballVelocity = velocity;
	// This constructor is  called when a new ball model is created with an initial velocity
}

4. Add the following globals at the top of the SimpleBall.cpp file, just before the line starting with C4::Application *ConstructApplication(void)

Vector3D ballVelocity = Vector3D(0.0f,0.0f,0.0f);//projectile velocity
float speed = 20.0F;//projectile initial speed

5. Add this line at the end of the Preprocess() function for the BallController, just after the line SetRestitutionCoefficient(0.95F);

SetLinearVelocity(ballVelocity);

6. In the SimpleBall.h header file, you need to declare the new constructor, just after the line BallController();

BallController::BallController(Vector3D& velocity);//new constructor

7. Now back in SimpleBall.cpp, comment out the line which creates the "Start Window" Widget:

//new TheInterfaceMgr->AddWidget(new StartWindow);

8. OK, compile that and then try out your new projectiles as follows:

9. Set $gameModuleName = "SimpleBall"; in the file game.cfg under ..\C4\Data\Game

10. Start C4.exe

11. Click Ctrl-O to open a world and then browse to Data/Tutorial/world and open Water.world

12. Press Ctrl-P to play that world

13. Once inside the world editor, press the Space Bar on your keyboard to fire your projectiles!

14. If your projectiles are not spherical, you will need to rotate them before to point in the direction you want them to travel. To do that, put this next code into your Preprocess function, replacing the line SetLinearVelocity(ballVelocity);

Note that to make sure you can actually see that your bullet moves the way you expect it to, you probably want to slow down the bullet for tests and to reduce gravity for it with SetGravityMultiplier(0.1F);

SetGravityMultiplier(0.1F);
GameWorld *world = static_cast<GameWorld *>(TheWorldMgr->GetWorld());
Matrix3D cameraMatrix3D = world->GetCamera()->GetNodeTransform().GetMatrix3D();
Model *model = static_cast<Model *>(Controller::GetTargetNode());
SetRigidBodyTransform(Transform4D(cameraMatrix3D, model->GetNodePosition()));
model->Invalidate();
SetLinearVelocity(ballVelocity/10.0F);

15. To shoot in an arbitrary direction Vector3D bulletVelocity and not just the camera's direction, you can use this:

Model *model = static_cast<Model *>(Controller::GetTargetNode());
Vector3D bulletFrontDirection = bulletDirection.Normalize();
float magnitude = InverseSqrt(bulletFrontDirection.x * bulletFrontDirection.x + bulletFrontDirection.y * bulletFrontDirection.y);
Vector3D bulletRightDirection(bulletFrontDirection.y * magnitude, -bulletFrontDirection.x * magnitude, 0.0F);
SetRigidBodyTransform(Transform4D(bulletRightDirection, bulletFrontDirection % bulletRightDirection, bulletFrontDirection, model->GetNodePosition()));
model->Invalidate();
SetLinearVelocity(bulletVelocity);

Hope that helps a bit.

Your turn:

1. See if you can bind the firing to a different key, or to a mouse click.

2. Try to create a Spark effect when the Ball hits the Walls or the ground.

3. Can you change the spark effect to be more like an explosion?

OK, let's move on to the next tutorial. Let's make A Simple Tank, which will fire our new projectiles.

--Jimbobjames

Personal tools