Applying Special Effects in 3D Game Development with Microsoft Silverlight 3: Part 2

Exclusive offer: get 50% off this eBook here
3D Game Development with Microsoft Silverlight 3: Beginner's Guide

3D Game Development with Microsoft Silverlight 3: Beginner's Guide — Save 50%

A practical guide to creating real-time responsive online 3D games in Silverlight 3 using C#, XBAP WPF, XAML, Balder, and Farseer Physics Engine

$29.99    $15.00
by Gastón C. Hillar | September 2009 | Beginner's Guides Web Development Web Graphics & Video

Read Applying Special Effects in 3D Game Development with Microsoft Silverlight 3: Part 1 here.

Time for action – simulating fluids with movement

Your project manager is amazed with the shower of dozens of meteors in the background. However, he wants to add a more realistic background.

He shows you a water simulation sample using Farseer Physics Engine. He wants you to use the wave simulation capabilities offered by this powerful physics simulator to create an asteroids belt.

First, we are going to create a new class to define a fluid model capable of setting the initial parameters and updating a wave controller provided by the physics simulator.

We will use Farseer Physics Engine's wave controller to add real-time fluids with movement for our games. The following code is based on the Silverlight water sample offered with the physics simulator. However, in this case, we are not interested in collision detection capabilities because we are going to create an asteroid belt in the background.

  1. Stay in the 3DInvadersSilverlight project.
  2. Create a new class—FluidModel.
  3. Replace the default using declarations with the following lines of code (we are going to use many classes and interfaces from Farseer Physics Engine):
    using System;
    using FarseerGames.FarseerPhysics;
    using FarseerGames.FarseerPhysics.Controllers;
    using FarseerGames.FarseerPhysics.Mathematics;
  4. Add the following public property to hold the WaveController instance:
    public WaveController WaveController { get; private set; }
  5. Add the following public properties to define the wave generator parameters:
    public float WaveGeneratorMax { get; set; }
    public float WaveGeneratorMin { get; set; }
    public float WaveGeneratorStep { get; set; }
  6. Add the following constructor without parameters:
    public FluidModel()
    {
    // Assign the initial values for the wave generator parameters
    WaveGeneratorMax = 0.20f;
    WaveGeneratorMin = -0.15f;
    WaveGeneratorStep = 0.025f;
    }
  7. Add the Initialize method to create and configure the WaveController instance using the PhysicsSimulator instance received as a parameter:
    public void Initialize(PhysicsSimulator physicsSimulator)
    {
    // The wave controller controls how the waves move
    // It defines how big and how fast is the wave
    // It is represented as set of points equally spaced
    horizontally along the width of the wave.
    WaveController = new WaveController();
    WaveController.Position = ConvertUnits.ToSimUnits(-20, 5);
    WaveController.Width = ConvertUnits.ToSimUnits(30);
    WaveController.Height = ConvertUnits.ToSimUnits(3);
    // The number of vertices that make up the surface of the wave
    WaveController.NodeCount = 40;
    // Determines how quickly the wave will dissipate
    WaveController.DampingCoefficient = .95f;
    // Establishes how fast the wave algorithm runs (in seconds)
    WaveController.Frequency = .16f;
    //The wave generator parameters simply move an end-point of the
    WaveController.WaveGeneratorMax = WaveGeneratorMax;
    WaveController.WaveGeneratorMin = WaveGeneratorMin;
    WaveController.WaveGeneratorStep = WaveGeneratorStep;
    WaveController.Initialize();
    }
  8. Add the Update method to update the wave controller and update the points that draw the waves shapes:
    public void Update(TimeSpan elapsedTime)
    {
    WaveController.Update((float) elapsedTime.TotalSeconds);
    }

What just happened?

We now have a FluidModel class that creates, configures, and updates a WaveController instance according to an associated physics simulator. As we are going to work with different gravitational forces, we are going to use another independent physics simulator to work with the FluidModel instance in our game.

Simulating waves

The wave controller offers many parameters to represent a set of points equally spaced horizontally along the width of one or many waves. The waves can be:

  • Big or small
  • Fast or slow
  • Tall or short

The wave controller's parameters allow us to determine the number of vertices that make up the surface of the wave assigning a value to its NodeCount property. In this case, we are going to create waves with 40 nodes and each point is going to be represented by an asteroid:

WaveController.NodeCount = 40;

The Initialize method defines the position, width, height and other parameters for the wave controller. We have to convert our position values to the simulator values. Thus, we use the ConvertUnits.ToSimUnits method. For example, this line defines the 2D Vector for the wave's upper left corner (X = -20 and Y = 5):

WaveController.Position = ConvertUnits.ToSimUnits(-20, 5);

The best way to understand each parameter is changing its values and running the example using these new values. Using a wave controller we can create amazing fluids with movement.

 

Time for action – creating a subclass for a complex asteroid belt

Now, we are going to create a specialized subclass of Actor (Balder.Core.Runtime. Actor) to load, create an update a fluid with waves. This class will enable us to encapsulate an independent asteroid belt and add it to the game. In this case, it is a 3D character composed of many models (many instances of Mesh).

  1. Stay in the 3DInvadersSilverlight project.
  2. Create a new class, FluidWithWaves (a subclass of Actor) using the following declaration:
    public class FluidWithWaves : Actor
  3. Replace the default using declarations with the following lines of code (we are going to use many classes and interfaces from Balder, Farseer Physics Engine and lists):
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    // BALDER
    using Balder.Core;
    using Balder.Core.Geometries;
    using Balder.Core.Math;
    using Balder.Core.Runtime;
    // FARSEER PHYSICS
    using FarseerGames.FarseerPhysics;
    using FarseerGames.FarseerPhysics.Collisions;
    using FarseerGames.FarseerPhysics.Dynamics;
    using FarseerGames.FarseerPhysics.Factories;
    using FarseerGames.FarseerPhysics.Mathematics;
    // LISTS
    using System.Collections.Generic;
  4. Add the following protected variables to hold references for the RealTimeGame and the Scene instances:
    protected RealTimeGame _game;
    protected Scene _scene;
  5. Add the following private variables to hold the associated FluidModel instance, the collection of points that define the wave and the list of meshes (asteroids):
    private FluidModel _fluidModel;
    private PointCollection _points;
    private List<Mesh> _meshList;
  6. Add the following constructor with three parameters—the RealTimeGame, the Scene, and the PhysicsSimulator instances:
    public FluidWithWaves(RealTimeGame game, Scene scene,
    PhysicsSimulator physicsSimulator)
    {
    _game = game;
    _scene = scene;
    _fluidModel = new FluidModel();
    _fluidModel.Initialize(physicsSimulator);
    int count = _fluidModel.WaveController.NodeCount;
    _points = new PointCollection();
    for (int i = 0; i < count; i++)
    {
    _points.Add(new Point(ConvertUnits.ToDisplayUnits
    (_fluidModel.WaveController.XPosition[i]),
    ConvertUnits.ToDisplayUnits
    (_fluidModel.WaveController.CurrentWave[i])));
    }
    }
  7. Override the LoadContent method to load the meteors' meshes and set their initial positions according to the points that define the wave:
    public override void LoadContent()
    {
    base.LoadContent();
    _meshList = new List<Mesh>(_points.Count);
    for (int i = 0; i < _points.Count; i++)
    {
    Mesh mesh = _game.ContentManager.Load<Mesh>("meteor.ase");
    _meshList.Add(mesh);
    _scene.AddNode(mesh);
    mesh.Position.X = (float) _points[i].X;
    mesh.Position.Y = (float) _points[i].Y;
    mesh.Position.Z = 0;
    }
    }
  8. Override the Update method to update the fluid model and then change the meteors' positions taking into account the points that define the wave according to the elapsed time:
    public override void Update()
    {
    base.Update();
    // Update the fluid model with the real-time game elapsed time
    _fluidModel.Update(_game.ElapsedTime);
    _points.Clear();
    for (int i = 0; i < _fluidModel.WaveController.NodeCount; i++)
    {
    Point p = new Point(ConvertUnits.ToDisplayUnits
    (_fluidModel.WaveController.XPosition[i]),
    ConvertUnits.ToDisplayUnits
    (_fluidModel.WaveController.CurrentWave[i])
    +ConvertUnits.ToDisplayUnits
    (_fluidModel.WaveController.Position.Y));
    _points.Add(p);
    }
    // Update the positions for the meshes that define the wave's points
    for (int i = 0; i < _points.Count; i++)
    {
    _meshList[i].Position.X = (float)_points[i].X;
    _meshList[i].Position.Y = (float)_points[i].Y;
    }
    }
3D Game Development with Microsoft Silverlight 3: Beginner's Guide A practical guide to creating real-time responsive online 3D games in Silverlight 3 using C#, XBAP WPF, XAML, Balder, and Farseer Physics Engine
Published: September 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

What just happened?

Now, we have a subclass of Actor that loads the models of the meteors and updates their position according to the fluids with movement simulation. It will load as many meteors as points used to draw the waves.

Creating subclasses of Actor and overriding its methods, we can encapsulate the complexities of the physics involved in complex backgrounds like our asteroid belt.

Using an Actor to represent a wave in the background

The most appropriate way to represent a 3D background component in Balder is by creating a new subclass of the Actor class. By doing this, we can keep the main game's code easy to understand and maintain. The constructor creates a FluidModel instance and initializes it. It creates PointCollection (_points) that will hold the 2D position for each point that composes the wave:

  for (int i = 0; i < count; i++)
{
_points.Add(new Point(ConvertUnits.ToDisplayUnits
(_fluidModel.WaveController.XPosition[i]),
ConvertUnits.ToDisplayUnits
(_fluidModel.WaveController.CurrentWave[i])));
}
}

Then, the Update method calls the Update method for the fluid model in order to renew the positions for the points that define the wave:

_fluidModel.Update(_game.ElapsedTime);

Once the fluid model updates the points, it creates the new collection of points taking into account the new positions. Then, it is time to update the meshes' locations according to these points that define the wave:

for (int i = 0; i < _points.Count; i++)
{
_meshList[i].Position.X = (float)_points[i].X;
_meshList[i].Position.Y = (float)_points[i].Y;
}

This technique does not offer the best performance. However, in this case, we are interested in a clear code. We can improve the game's performance later.

Time for action – adding an asteroid belt background to the game

Now, we are going to add another physics simulator with a different gravitational force to control the fluid model as an actor, with a predefined behavior.

  1. Stay in the 3DInvadersSilverlight project.
  2. Open InvadersGame.cs.
  3. Add the following private variable in the public class InvadersGame : RealTimeGame, to hold another PhysicsSimulator (FarseerGames.FarseerPhysics.PhysicsSimulator) instance:
    private PhysicsSimulator _fluidPhysicsSimulator;
  4. Add the following private variable to hold the new FluidWithWaves instance:
    private FluidWithWaves _fluidWithWaves;
  5. Add the following private method to initialize the fluids physics simulator, specifying a specific desired gravitational force as a 2D vector parameter:
    private void InitializeFluidPhysicsSimulator()
    {
    fluidPhysicsSimulator = new PhysicsSimulator(new Vector2(0,4f));
    //50 pixels = 1 meter
    ConvertUnits.SetDisplayUnitToSimUnitRatio(50);
    }
  6. Add the following lines of code before the end of the Initialize method:
    InitializeFluidPhysicsSimulator();
    _fluidWithWaves = new FluidWithWaves(this, Scene,_fluidPhysicsSimulator);
    AddActor(_fluidWithWaves);
  7. Add the following line of code before the end of the UpdateWithTime method:
    _fluidPhysicsSimulator.Update((float)_elapsedTime.
    TotalSeconds);
  8. Build and run the solution. Click on the Start the game! button. The UFOs will begin their chase game while 30 meteors rain. An asteroid belt will create waves in the background, as shown in the following screenshot:

    Applying Special Effects in 3D Game Development with Microsoft Silverlight 3: Part 2

  9. Click on the web browser's viewport to activate its focus. Move the mouse left and right. You will see the entire scene, including the asteroid belt, rotating as the mouse is moved. Use the cursor movement keys to control the camera. The 3D background will go on moving, as shown in the following screenshot:

    Applying Special Effects in 3D Game Development with Microsoft Silverlight 3: Part 2

What just happened?

You can add an even more exciting background to the game. Now, there is an asteroid belt creating waves in the 3D scene. You can create any moving fluid model by changing just a few parameters to define a different behavior for the wave controller.

Using a third instance of the 2D physics engine, you could simulate moving fluid models for 40 asteroids (actually represented by meteors). Now, the game has 3D waves as a background offering a realistic effect.

Working with encapsulated physics controllers

We added a new physics simulator instance to manage the wave controller. This way, we could use a gravitational force that was different to the ones applied to the UFOs and the raining meteors.

Also, we used an Actor subclass to encapsulate the complexities behind the wave effect. We just added the new actor to the game associated to the new physics simulator and we followed the necessary steps to update it.

We can change parameters and we can use different backgrounds according to the game's level or stage.

The FluidWithWaves class creates, loads, and updates the asteroids to follow the wave that is created and updated by the FluidModel instance.

The FluidModel class creates, configures, and updates a WaveController instance.

The WaveController class works with the associated PhysicsSimulator instance to define the points that draw a wave according to many parameters, physics properties, and the elapsed time.

Summary

We learned a lot in this article about adding special effects to our games. Specifically, we were able to add characters raining in the background with an independent behavior. We used physics controller to emulate fluids with movement and we were able to work with different gravitational forces. We created 3D backgrounds with many layers. We also understood the importance of encapsulating complex physics using many classes.

[ 1 | 2 ]

3D Game Development with Microsoft Silverlight 3: Beginner's Guide A practical guide to creating real-time responsive online 3D games in Silverlight 3 using C#, XBAP WPF, XAML, Balder, and Farseer Physics Engine
Published: September 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Gastón C. Hillar

Gastón C. Hillar has been working with computers since he was eight. He began programming with the legendary Texas TI-99/4A and Commodore 64 home computers in the early 80s.
He has a Bachelor degree in Computer Science from which he graduated with honors, and an MBA from which he graduated with an outstanding thesis. Now, he is an independent IT consultant and a freelance author always looking for new adventures around the world.

To date he’s written more than 40 books in Spanish, and for Packt Publishing has written “C# 2008 and 2005 Threaded Programming: Beginner's Guide”. He usually writes articles for Spanish magazines Mundo Linux, Solo Programadores and Resistor.
He contributes to Dr. Dobb's Go Parallel programming portal http://www.ddj.com/go-parallel/ and he is a guest blogger at Intel Software Network http://software.intel.com

Gastón C. Hillar is the author of "Microsoft Silverlight 4 and SharePoint 2010 Integration".

Books From Packt

Blender 3D 2.49 Incredible Machines
Blender 3D 2.49 Incredible Machines

jQuery 1.3 with PHP
jQuery 1.3 with PHP

Symfony 1.3 Web Application Development
Symfony 1.3 Web Application Development

Zend Framework 1.8 Web Application Development
Zend Framework 1.8 Web Application Development

JBoss Tools 3 Developers Guide
JBoss Tools 3 Developers Guide

Seam 2.x Web Development
Seam 2.x Web Development

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

Scratch 1.4: Beginner’s Guide
Scratch 1.4: Beginner’s Guide

 

 

 

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
V
v
C
C
6
U
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software