//----------------------------------------------------------------------------- // 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.Directlnput; using GameEngine; using GameAI;
namespace SampleGame { /// <summary> /// Summary description for GameEngine. /// </summary> class CGameApplication : GraphicsSample { #region //
Game
State
enumeration /// <summary> /// Each member of this enumeration is one possible state for the /// application /// </summary> /// /// <remarks> /// DevSplash -Display the developer splash screen /// </remarks> /// <remarks> /// GameSplash -Display the game splash screen /// </remarks> /// <remarks> /// OptionsMain -Display and process the primary options screen /// </remarks> /// <remarks> /// GamePlay -State to actually play the game /// </remarks> /// <remarks> /// AfterActionReview - Display the results of the game /// </remarks> public enum GameState { /// <summary> /// Display the developer splash screen /// </summary> DevSplash, /// <summary> /// Display the game splash screen /// </summary> GameSplash, /// <summary> /// Display and process the primary options screen /// </summary> OptionsMain, /// <summary>
///
State
to actually play the game /// </summary> GamePlay, /// <summary> /// Display the results of the game /// </summary> AfterActionReview, } #endregion
#region // Application member variables /// <summary> /// Current state of the application /// </summary> private GameState m_State; private static CGameEngine m_Engine = new CGameEngine(); private GraphicsFont m_pFont = null; 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; } }
/// <summary> /// Application constructor. Sets attributes for the app. /// </summary> public CGameApplication() { // Initialize the game state for the developer splash screen. m_State = GameState.DevSplash; m_pFont = new GraphicsFont( "Aerial", System.Drawing.FontStyle.Bold ); windowed = false;
m_opponents = new ArrayList(); }
/// <summary> /// Called during initial app startup, this function performs all the /// permanent initialization. /// </summary> protected override void OneTimeSceneInitialization() { // Initialize the font's internal textures. m_pFont.InitializeDeviceObjects( device );
// Nothing much to do yet - will be used in later chapters. 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, "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( "Options1.jpg"); m_OptionScreen.AddButton( 328, 150, "PlayOff.jpg", "PlayOn.jpg", "PlayHover.jpg", new ButtonFunction(Play) ); m_OptionScreen.AddButton(328, 300, "QuitOff.jpg", "QuitOn.jpg", "QuitHover.jpg", 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(); }
/// <summary> /// 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 /// engine based on the current state. /// </summary> 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, 0×00000000,
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("devsplash.jpg", 8, new BackgroundTask(LoadOptions)) ) { m_State = GameState.GameSplash; } break; case GameState.GameSplash: if ( m_Engine.ShowSplash("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 ( 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( 200, 580, Color. FromArgb(255, 0,0,0), m_ownship.ForwardVelocity.ToString() ); m_pFont.DrawText( 200, 600, Color.FromArgb(255,0,0,0), m_ownship.SidewaysVelocity.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 ); }
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(); } }
/// <summary> /// The main entry point for the application /// </summary> [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
/// <summary> /// Action to start playing /// </summary> public void Play() { m_State = GameState.GamePlay; GameEngine.Console.Reset(); }
/// <summary> /// Action to terminate the application /// </summary> public void Terminate() { m_bTerminate = true; }
/// <summary> /// Screen capture /// </summary> public void ScreenCapture() { m_bScreenCapture = true; }
/// <summary> /// Version of terminate for use by the console /// </summary> /// <param name="sData"></param> public void TerminateCommand( string sData ) { Terminate(); }
/// <summary> /// Toggle the display of statistics information. /// </summary> /// <param name="sData"></param> public void ToggleStatistics( string sData ) { m_bShowStatistics = !m_bShowStatistics; }
/// <summary> /// Action to transition to the next game state based on a mapper action /// </summary> public void NextState() { if ( m_State < GameState.AfterActionReview ) { m_State++; } 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
); }
/// <summary> /// /// </summary> protected override void RestoreDeviceObjects(System.Object sender, System.EventArgs e) { // 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; }
/// <summary> /// Called when the app is exiting, or the device is being changed, this /// function deletes any device-dependent objects. /// </summary> protected override void DeleteDeviceObjects(System.Object sender, System.EventArgs e) { m_Engine.Dispose(); }
public void LoadOptions() { try { System.Random rand = new System.Random(); // Loading of options will happen here. m_Engine.SetTerrain(200, 200, "heightmap.jpg", "sand1.jpg",
10.0f
,
0.45f
);
for ( int i=0; i<300; i++ ) { float north = (float) (rand.NextDouble() * 1900.0); float east = (float) (rand.NextDouble() * 1900.0); BillBoard.Add( east, north,
0.0f
, "cactus"+i, "cactus.dds",
1.0f
,
1.0f
); } for ( int i=0; i<300; i++ ) { float north = (float) (rand.NextDouble() * 1900.0); float east = (float) (rand.NextDouble() * 1900.0); BillBoard.Add( east, north,
0.0f
, "tree"+i, "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", "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), "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), "bluepost.dds",
0.25f
,
1.0f
); j += 5.0; if ( j >= 360.0 ) j −= 360.0; }
m_ownship = new Ownship(this, "car1", "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 );
m_own ship.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
);
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.PositionOff set = 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 += −
9.8f
* 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; } } }
|