Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

KillTux

0.00/5 (No votes)
3 Sep 2001 1  
The Space Donuts 3D for MFC.
  • Download source files - 496 Kb
  • Download demo project - 583 Kb
  • Sample Image - KillTux1.gif

    Description

    Most of the samples that come with DirectX 8 SDK don't use MFC. What if we want to take a sample and add some code that requires MFC?
    This article describes the steps to convert the 'Space Donuts 3D' into an MFC application.

    Create the Framework

    figure 1

    Start VC, Select File/New from the menu and select MFC�Appwizard(exe). Give a name (ex.'BattleMachine') and press OK to start the wizard. Select Single�document as the type of application and uncheck the Document/View�architecture�support (Fig.1).
    Click Finish.

    Adding Donuts

    The Sample from the SDK have a lot of global functions & variables. I created a new class named C3DEngine and copy most of the global functions/variables as members of C3DEngine. Then i added a global instance of C3DEngine after the decleration of theApp.

    CBattleMachineApp theApp;
    C3DEngine g_3DEngine;
    

    I also added the following two lines in BattleMachine.h after the definition of CBattleMachineApp

    extern CBattleMachineApp theApp;
    extern C3DEngine g_3DEngine;
    

    You can use the Space Donuts 3D engine in you application by adding the files 3DEngine.cpp and 3DEngine.h. Those files contain any other classes, structs and definitions used by space donuts.

    There are 2 functions from space donuts 3D that we can't make them members of C3DEngine. One is ConfigureInputDevicesCB which is a Callback function. We have to change it's code a little, to reference g_3DEngine member functions.

    BOOL CALLBACK ConfigureInputDevicesCB( IUnknown* pUnknown, VOID* pUserData )
    {
    	//if( g_dwAppState != APPSTATE_ACTIVE )
    
    	if( g_3DEngine.g_dwAppState != APPSTATE_ACTIVE )
    		return TRUE;
    ...
    

    The other function is WindowProc. I moved all of it's code to the CMainFrame::WindowProc. Once again, references to previously globals has to change into references to members of g_3DEngine.

    Initialisation and Changes to the framework

    To initialise the 3D Engine you have to set g_hWndMain to a valid HWND and then call CreateGameObjects by passing that same HWND.
    Also a good idea is to set the window size to 640x480 as the space donuts 3D. We do that in CMainFrame::OnCreate by using the WHND of the MainFrame.

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	lpCreateStruct->cx=640;
    	lpCreateStruct->cy=480;
    
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	// create a view to occupy the client area of the frame
    
    	if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
    		CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
    	{
    		TRACE0("Failed to create view window\n");
    		return -1;
    	}
    
    	SetWindowPos( NULL , 50,50, 640,480, SWP_NOOWNERZORDER   | SWP_NOREPOSITION   |SWP_NOZORDER    );
    
    	g_3DEngine.g_hWndMain = GetSafeHwnd();
        // Create the game objects (display objects, sounds, input devices,
    
        // menus, etc.)
    
        if( FAILED( g_3DEngine.CreateGameObjects( g_3DEngine.g_hWndMain ) ) )
        {        
            return FALSE;
        }
    	
    	return 0;
    }
    

    Then we have to change the function CMainFrame::OnSetFocus. The function generated by appwizard gives focus to the CChildView window. The CMainFrame should keep the focus, because we need to handle keypress from the CMainFrame::WindowProc.

    /////////////////////////////////////////////////////////////////////////////
    
    // CMainFrame message handlers
    
    void CMainFrame::OnSetFocus(CWnd* pOldWnd)
    {
    	CFrameWnd::OnSetFocus(pOldWnd);
    	// forward focus to the view window
    
    	//m_wndView.SetFocus();
    
    }
    

    Finally we add the virtual function OnIdle to the CBattleMachineApp class. The following code will render the next frame.

    BOOL CBattleMachineApp::OnIdle(LONG lCount) 
    {
    	// Render a frame during idle time (no messages are waiting)
    
    	if( g_3DEngine.g_bDisplayReady )
    	{
    		g_3DEngine.FrameMove();
    		g_3DEngine.RenderFrame();
    	}	
    	return true;
    }
    

    Other changes

    I made some changes to the original space donuts engine.

    First, i replaced the sprites of donuts, pyramid, cube and sphere with Tux. There's no fun killing donuts after all!

    Second, I made the landscape more flat by changing the function C3DEngine::HeightField. The height of every object (ship,bullets,donuts ) depence on that function.

    // Simple function to define "hilliness" for terrain
    
    inline FLOAT C3DEngine::HeightField( FLOAT x, FLOAT z )
    {
    	return (cosf(x/2.0f+0.2f)*cosf(z/1.5f-0.2f)+1.0f)*0.1f - 2.0f;
    }
    

    Third, i added the ability to the ship to change altitude. By using the mouse wheel, instead of changing ships, you can lift or drop the ship's nose. Try to fly above all those Tuxs and kill them with no fear of dropping on them.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here