www.pudn.com > IntroductionTo3DGameEngineDesign.rar > App.cs
//-----------------------------------------------------------------------------
// File: App.cs
//
// Desc: Sample code for Introduction to 3D Game Engine Design.
//
// This sample shows the basic application software that sets up the
// base application and the process flow. The application uses a version of the
// CD3DApplication base class provided with the Microsoft DirectX 9 SDK to
// perform the standard initialization of DirectX.
//
// Note: This code uses the D3D Framework helper library.
//
// Copyright (c) 2002 Lynn T. Harrison All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using GameEngine;
using GameAI;
namespace SampleGame
{
///
/// Summary description for GameEngine.
///
class CGameApplication : GraphicsSample
{
#region // Game State enumeration
///
/// Each member of this enumeration is one possible state for the application
///
///
///
/// DevSplash - Display the Developer splash screen
///
///
/// GameSplash - Display the game splash screen
///
///
/// OptionsMain - Displays and process the primary options screen
///
///
/// GamePlay - state to actually play the game
///
///
/// AfterActionReview - Display the results of the game
///
public enum GameState
{
///
/// Display the Developer splash screen
///
DevSplash,
///
/// Display the game splash screen
///
GameSplash,
///
/// Displays and process the primary options screen
///
OptionsMain,
///
/// state to actually play the game
///
GamePlay,
///
/// Display the results of the game
///
AfterActionReview,
}
#endregion
#region // Application member variables
///
/// Current state of the application
///
private GameState m_State;
private static CGameEngine m_Engine = new CGameEngine(); // connection to the game engine
private GraphicsFont m_pFont = null; // font for screen text rendering
private GameEngine.Console m_Console;
private ArrayList m_opponents = null;
private OptionScreen m_OptionScreen = null;
private bool m_bShowStatistics = false;
private bool m_bScreenCapture = false;
private bool m_bUsingJoystick = true;
private bool m_bUsingKeyboard = false;
private bool m_bUsingMouse = false;
private Ownship m_ownship = null;
private Cloth m_flag = null;
private Jukebox music = null;
#endregion
public static CGameEngine Engine { get { return m_Engine; } }
///
/// Application constructor. Sets attributes for the app.
///
public CGameApplication()
{
// Initialize the Game state for the Developer Splash Screen
m_State = GameState.DevSplash;
// create a copy of the game engine
m_pFont = new GraphicsFont( "Aerial", System.Drawing.FontStyle.Bold );
windowed = false;
m_opponents = new ArrayList();
}
///
/// Called during initial app startup, this function performs all the
/// permanent initialization.
///
protected override void OneTimeSceneInitialization()
{
// Initialize the font's internal textures
m_pFont.InitializeDeviceObjects( device );
m_Engine.Initialize( this, device );
CGameEngine.Inputs.MapKeyboardAction(Key.Escape,new ButtonAction(Terminate), true);
CGameEngine.Inputs.MapKeyboardAction(Key.A,new ButtonAction(MoveCameraXM), false);
CGameEngine.Inputs.MapKeyboardAction(Key.W,new ButtonAction(MoveCameraZP), false);
CGameEngine.Inputs.MapKeyboardAction(Key.S,new ButtonAction(MoveCameraXP), false);
CGameEngine.Inputs.MapKeyboardAction(Key.Z,new ButtonAction(MoveCameraZM), false);
CGameEngine.Inputs.MapKeyboardAction(Key.P,new ButtonAction(ScreenCapture), true);
CGameEngine.Inputs.MapMouseAxisAction(0,new AxisAction(PointCamera));
CGameEngine.Inputs.MapMouseAxisAction(1,new AxisAction(PitchCamera));
m_Console = new GameEngine.Console( m_pFont, @"..\..\Resources\console.jpg" );
GameEngine.Console.AddCommand("QUIT", "Terminate the game", new CommandFunction(TerminateCommand));
GameEngine.Console.AddCommand("STATISTICS", "Toggle statistics display", new CommandFunction(ToggleStatistics));
m_OptionScreen = new OptionScreen( @"..\..\Resources\Options2.jpg" );
m_OptionScreen.AddButton( 328, 150, @"..\..\Resources\PlayOff.bmp", @"..\..\Resources\PlayOn.bmp", @"..\..\Resources\PlayHover.bmp", new ButtonFunction(Play) );
m_OptionScreen.AddButton( 328, 300, @"..\..\Resources\QuitOff.bmp", @"..\..\Resources\QuitOn.bmp", @"..\..\Resources\QuitHover.bmp", new ButtonFunction(Terminate) );
m_Engine.SetOptionScreen( m_OptionScreen );
music = new Jukebox();
music.AddSong("nadine.mp3");
music.AddSong("ComeOn.mp3");
music.AddSong("Rock.mp3");
music.Volume = 0.75f;
music.Play();
}
///
/// Called once per frame, the call is the entry point for all game processing.
/// This function calls the appropriate part of the game engine based on the
/// current state.
///
protected override void FrameMove()
{
try
{
SelectControls select_form = null;
// get any player inputs
m_Engine.GetPlayerInputs();
// Clear the viewport
device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, 0x00000000, 1.0f, 0 );
device.BeginScene();
// determine what needs to be rendered based on the current game state
switch ( m_State )
{
case GameState.DevSplash:
if ( m_Engine.ShowSplash(@"..\..\Resources\devsplash.jpg", 8, new BackgroundTask(LoadOptions)) )
{
m_State = GameState.GameSplash;
}
break;
case GameState.GameSplash:
if ( m_Engine.ShowSplash(@"..\..\Resources\gamesplash.jpg", 8, null) )
{
m_State = GameState.OptionsMain;
select_form = new SelectControls();
select_form.ShowDialog(this);
m_bUsingJoystick = select_form.UseJoystick.Checked;
m_bUsingKeyboard = select_form.UseKeyboard.Checked;
m_bUsingMouse = select_form.UseMouse.Checked;
if ( m_bUsingJoystick ) GameEngine.Console.AddLine("Using Joystick");
if ( m_bUsingKeyboard ) GameEngine.Console.AddLine("Using Keyboard");
if ( m_bUsingMouse ) GameEngine.Console.AddLine("Using Mouse");
m_ownship = (Ownship)Engine.GetObject("car1");
m_ownship.UseJoystick = m_bUsingJoystick;
m_ownship.UseKeyboard = m_bUsingKeyboard;
m_ownship.UseMouse = m_bUsingMouse;
}
break;
case GameState.OptionsMain:
m_Engine.DoOptions();
break;
case GameState.GamePlay:
m_Engine.GetPlayerInputs();
m_Engine.DoAI( elapsedTime );
m_Engine.DoDynamics( elapsedTime );
m_Engine.DoNetworking( elapsedTime );
m_Engine.Render();
break;
case GameState.AfterActionReview:
m_Engine.DoAfterActionReview();
break;
}
GameEngine.Console.Render();
if ( false && m_ownship != null && m_State == GameState.GamePlay )
{
m_pFont.DrawText( 200, 560, Color.FromArgb(255,0,0,0), m_ownship.MPH.ToString() );
m_pFont.DrawText( 280, 560, Color.FromArgb(255,0,0,0), m_ownship.RPM.ToString() );
m_pFont.DrawText( 200, 580, Color.FromArgb(255,0,0,0), m_ownship.ForwardVelocity.ToString() );
m_pFont.DrawText( 100, 560, Color.FromArgb(255,0,0,0), m_ownship.SidewaysVelocity.ToString() );
m_pFont.DrawText( 100, 580, Color.FromArgb(255,0,0,0), m_ownship.Steering.ToString() );
}
// Output statistics
if ( m_bShowStatistics )
{
m_pFont.DrawText( 2, 560, Color.FromArgb(255,255,255,0), frameStats );
m_pFont.DrawText( 2, 580, Color.FromArgb(255,255,255,0), deviceStats );
m_pFont.DrawText( 500, 580, Color.FromArgb(255,255,255,0),
m_Engine.Cam.Heading.ToString() + " " + m_Engine.Cam.Pitch.ToString() + " " +
m_Engine.Cam.X + " " +m_Engine.Cam.Y + " " +m_Engine.Cam.Z);
m_pFont.DrawText( 2, 600, Color.FromArgb(255,255,255,0),
"Steering " + (CGameEngine.Inputs.GetJoystickNormalX()-1.0f).ToString() + " " +
"throttle/Brake " + (1.0f-CGameEngine.Inputs.GetJoystickNormalY()).ToString());
}
if ( m_bScreenCapture )
{
SurfaceLoader.Save("capture.bmp",ImageFileFormat.Bmp,device.GetBackBuffer(0,0,BackBufferType.Mono));
m_bScreenCapture = false;
GameEngine.Console.AddLine("snapshot taken");
}
}
catch (DirectXException d3de)
{
System.Diagnostics.Debug.WriteLine("Error in Sample Game Application FrameMove" );
System.Diagnostics.Debug.WriteLine(d3de.ErrorString);
}
catch ( Exception e )
{
System.Diagnostics.Debug.WriteLine("Error in Sample Game Application FrameMove" );
System.Diagnostics.Debug.WriteLine(e.Message);
}
finally
{
device.EndScene();
}
}
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
try
{
CGameApplication d3dApp = new CGameApplication();
if (d3dApp.CreateGraphicsSample())
d3dApp.Run();
}
catch (DirectXException d3de)
{
System.Diagnostics.Debug.WriteLine("Error in Sample Game Application" );
System.Diagnostics.Debug.WriteLine(d3de.ErrorString);
}
catch ( Exception e )
{
System.Diagnostics.Debug.WriteLine("Error in Sample Game Application" );
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
// action functions
///
/// Action to start playing
///
public void Play()
{
m_State = GameState.GamePlay;
GameEngine.Console.Reset();
}
///
/// Action to terminate the application
///
public void Terminate()
{
m_bTerminate = true;
}
///
/// screen capture
///
public void ScreenCapture()
{
m_bScreenCapture = true;
}
///
/// version of terminate for use by the console
///
///
public void TerminateCommand( string sData )
{
Terminate();
}
///
/// Toggle the display of statistics information
///
///
public void ToggleStatistics( string sData )
{
m_bShowStatistics = !m_bShowStatistics;
}
///
/// Action to transition to the next game state based on a mapper action
///
public void NextState()
{
if ( m_State < GameState.AfterActionReview )
{
m_State++;
if ( m_State == GameState.GamePlay )
{
m_ownship = (Ownship)Engine.GetObject("car1");
m_ownship.Driving = true;
}
}
else
{
m_State = GameState.OptionsMain;
}
}
public void PointCamera( int count )
{
m_Engine.MoveCamera(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, count);
}
public void PitchCamera( int count )
{
m_Engine.MoveCamera(0.0f, 0.0f, 0.0f, count * 0.1f, 0.0f, 0.0f);
}
public void MoveCameraXP()
{
m_Engine.MoveCamera(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
}
public void MoveCameraXM()
{
m_Engine.MoveCamera(-0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
}
public void MoveCameraY()
{
m_Engine.MoveCamera(0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f);
}
public void MoveCameraZP()
{
m_Engine.MoveCamera(0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f);
}
public void MoveCameraZM()
{
m_Engine.MoveCamera(0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f);
}
///
///
///
protected override void RestoreDeviceObjects(System.Object sender, System.EventArgs e)
{
// Restore the device objects for the meshes and fonts
// Set the transform matrices (view and world are updated per frame)
Matrix matProj;
float fAspect = device.PresentationParameters.BackBufferWidth / (float)device.PresentationParameters.BackBufferHeight;
matProj = Matrix.PerspectiveFovLH( (float)Math.PI/4, fAspect, 1.0f, 100.0f );
device.Transform.Projection = matProj;
// Set up the default texture states
device.TextureState[0].ColorOperation = TextureOperation.Modulate;
device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
device.SamplerState[0].MinFilter = TextureFilter.Linear;
device.SamplerState[0].MagFilter = TextureFilter.Linear;
device.SamplerState[0].MipFilter = TextureFilter.Linear;
device.SamplerState[0].AddressU = TextureAddress.Clamp;
device.SamplerState[0].AddressV = TextureAddress.Clamp;
device.RenderState.DitherEnable = true;
}
///
/// Called when the app is exiting, or the device is being changed, this
/// function deletes any device-dependent objects.
///
protected override void DeleteDeviceObjects(System.Object sender, System.EventArgs e)
{
m_Engine.Dispose();
m_Console.Dispose();
}
public void LoadOptions()
{
try
{
System.Random rand = new System.Random();
// loading of options will happen here
m_Engine.SetTerrain(200,200,@"..\..\Resources\heightmap.jpg",@"..\..\Resources\sand1.jpg", 10.0f, 0.45f);
for ( int i=0; i<150; i++ )
{
float north = (float)(rand.NextDouble() * 1900.0);
float east = (float)(rand.NextDouble() * 1900.0);
BillBoard.Add( east, north, 0.0f, "cactus"+i, @"..\..\Resources\cactus.dds",1.0f, 1.0f);
}
for ( int i=0; i<150; i++ )
{
float north = (float)(rand.NextDouble() * 1900.0);
float east = (float)(rand.NextDouble() * 1900.0);
BillBoard.Add( east, north, 0.0f, "tree"+i, @"..\..\Resources\palmtree.dds",6.5f, 10.0f);
}
GameEngine.Console.AddLine("all trees loaded");
// m_Engine.AddObject( new ParticleGenerator("Spray1", 2000, 2000, Color.Yellow, "Particle.bmp", new ParticleUpdate(Gravity)));
double j = 0.0;
double center_x = 1000.0;
double center_z = 1000.0;
double radius = 700.0;
double width = 20.0;
m_flag = new Cloth("flag", @"..\..\Resources\flag.jpg", 2, 2, 0.1, 1.0f);
m_flag.Height = 0.6f;
m_flag.North = 2.0f;
m_flag.East = 0.1f;
Cloth.EastWind = -3.0f;
for ( double i=0.0; i<360.0; i += 1.5 )
{
float north = (float)(center_z + Math.Cos(i/180.0*Math.PI) * radius
);
float east = (float)(center_x + Math.Sin(i/180.0*Math.PI) * radius
);
BillBoard.Add( east, north, 0.0f, "redpost"+(int)(i*2), @"..\..\Resources\redpost.dds",0.25f, 1.0f);
j += 5.0;
if ( j > 360.0 ) j -= 360.0;
}
j = 0.0;
for ( double i=0.5; i<360.0; i += 1.5 )
{
float north = (float)(center_z + Math.Cos(i/180.0*Math.PI) * (radius+width)
);
float east = (float)(center_x + Math.Sin(i/180.0*Math.PI) * (radius+width)
);
BillBoard.Add( east, north, 0.0f, "bluepost"+(int)(i*2), @"..\..\Resources\bluepost.dds",0.25f, 1.0f);
j += 5.0;
if ( j >= 360.0 ) j -= 360.0;
}
m_ownship = new Ownship(this, "car1", @"..\..\Resources\SprintRacer.x", new Vector3(0.0f, 0.8f, 0.0f), new Attitude(0.0f, (float)Math.PI, 0.0f));
m_ownship.AddChild(m_flag);
SoundEffect.Volume = 0.25f;
m_Engine.AddObject( m_ownship );
/* Opponent opp1 = new Opponent("car2", @"..\..\Resources\SprintRacer.x", new Vector3(0.0f, 0.8f, 0.0f),
new Attitude(0.0f, (float)Math.PI, 0.0f), "knowledge.xml");
opp1.SetLOD( 10, 3000.0f );
m_opponents.Add( opp1 );
m_Engine.AddObject( opp1 );
*/
m_ownship.North = 298.0f;
m_ownship.East = 1000.0f;
m_Engine.Cam.Attach(m_ownship, new Vector3(0.0f, 0.85f,-4.5f));
m_Engine.Cam.LookAt(m_ownship);
m_ownship.Heading = (float)Math.PI * 1.5f;
m_ownship.SetLOD( 10, 3000.0f );
// Car car2 = (Car)m_Engine.GetObject("car2");
// car2.North = 295.0f;
// car2.East = 1000.0f;
// car2.Height = 0.0f;
// car2.Heading = (float)Math.PI * 1.5f;
// car2.SetLOD( 10, 300.0f );
// car2.SetUpdateMethod( new ObjectUpdate(OpponentUpdate));
GameEngine.GameLights.Ambient = Color.White;
// GameEngine.GameLights light1 = GameEngine.GameLights.AddPointLight( new Vector3(130.0f,35.0f,130.0f),Color.White,"light1");
// light1.Attenuation1 = 0.11f;
// GameEngine.GameLights light2 = GameEngine.GameLights.AddPointLight( new Vector3(40.0f,25.0f,40.0f),Color.White,"light2");
// light2.Attenuation1 = 0.11f;
// GameEngine.GameLights light3 = GameEngine.GameLights.AddPointLight( new Vector3(130.0f,35.0f,230.0f),Color.White,"light3");
// light3.Attenuation1 = 0.11f;
// GameEngine.GameLights light4 = GameEngine.GameLights.AddPointLight( new Vector3(230.0f,40.0f,230.0f),Color.White,"light4");
// light4.Attenuation1 = 0.11f;
// GameEngine.GameLights light5 = GameEngine.GameLights.AddPointLight( new Vector3(70.0f,25.0f,70.0f),Color.White,"light5");
// light5.Attenuation1 = 0.11f;
GameEngine.GameLights headlights = GameEngine.GameLights.AddSpotLight(new Vector3(0.0f,0.0f,0.0f),
new Vector3(1.0f,0.0f,1.0f), Color.White, "headlight");
headlights.EffectiveRange = 200.0f;
headlights.Attenuation0 = 1.0f;
headlights.Attenuation1 = 0.0f;
headlights.InnerConeAngle = 1.0f;
headlights.OuterConeAngle = 1.5f;
headlights.PositionOffset = new Vector3(0.0f, 2.0f, 1.0f);
headlights.DirectionOffset = new Vector3(0.0f, 0.00f, 1.0f);
m_ownship.AddChild(headlights);
headlights.Enabled = false;
CGameEngine.FogColor = Color.Beige;
CGameEngine.FogDensity = 0.5f;
CGameEngine.FogEnable = true;
CGameEngine.FogStart = 100.0f;
CGameEngine.FogEnd = 900.0f;
CGameEngine.FogTableMode = FogMode.Linear;
}
catch ( Exception e )
{
GameEngine.Console.AddLine("Exception");
GameEngine.Console.AddLine(e.Message);
}
}
public void Gravity( ref Particle Obj, float DeltaT )
{
Obj.m_Position += Obj.m_Velocity * DeltaT;
Obj.m_Velocity.Y += -32.0f * DeltaT;
if ( Obj.m_Position.Y < 0.0f ) Obj.m_bActive = false;
}
public void OwnshipUpdate( Object3D Obj, float DeltaT )
{
}
public void OpponentUpdate( Object3D Obj, float DeltaT )
{
Obj.Height = CGameEngine.Ground.HeightOfTerrain(Obj.Position) + ((Model)Obj).Offset.Y;
}
}
}