Let the Music Play

Started by
6 comments, last by Gamesmaster3 18 years, 10 months ago
I've been trying to add midi music campability to my Memory project.I've played the game without music so I know that the game portion is good but I can't seem to get the sound portion to work at all.I get four errors but when I check the code I don't see anything wrong with it.So more than likely there must have been something that I missed.I've included the GameEngine.cpp file text and the GameEngine.h file text.All the errors are said to be the .cpp file but you never know.If anyone can help me out I would appreciate it. UPDATE:I've added the text in the file SexyMemory.cpp and SexyMemory.h as well as putting in the includes.The only files I have added are the Bitmap.cpp,Bitmap.h,Sprite.h and Sprite.cpp files.None of those have music components to them which is why I left them off GameEngine.cpp

//-----------------------------------------------------------------
// Game Engine Object
// C++ Source - GameEngine.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "GameEngine.h"

//-----------------------------------------------------------------
// Static Variable Initialization
//-----------------------------------------------------------------
GameEngine *GameEngine::m_pGameEngine = NULL;

//-----------------------------------------------------------------
// Windows Functions
//-----------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR szCmdLine, int iCmdShow)
{
  MSG         msg;
  static int  iTickTrigger = 0;
  int         iTickCount;

  if (GameInitialize(hInstance))
  {
    // Initialize the game engine
    if (!GameEngine::GetEngine()->Initialize(iCmdShow))
      return FALSE;

    // Enter the main message loop
    while (TRUE)
    {
      if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
      {
        // Process the message
        if (msg.message == WM_QUIT)
          break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      else
      {
        // Make sure the game engine isn't sleeping
        if (!GameEngine::GetEngine()->GetSleep())
        {
          // Check the tick count to see if a game cycle has elapsed
          iTickCount = GetTickCount();
          if (iTickCount > iTickTrigger)
          {
            iTickTrigger = iTickCount +
              GameEngine::GetEngine()->GetFrameDelay();
            HandleKeys();
            GameCycle();
          }
        }
      }
    }
    return (int)msg.wParam;
  }

  // End the game
  GameEnd();

  return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Route all Windows messages to the game engine
  return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
}

//-----------------------------------------------------------------
// GameEngine Constructor(s)/Destructor
//-----------------------------------------------------------------
GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass,
  LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth, int iHeight)
{
  // Set the member variables for the game engine
  m_pGameEngine = this;
  m_hInstance = hInstance;
  m_hWindow = NULL;
  if (lstrlen(szWindowClass) > 0)
    lstrcpy(m_szWindowClass, szWindowClass);
  if (lstrlen(szTitle) > 0)
    lstrcpy(m_szTitle, szTitle);
  m_wIcon = wIcon;
  m_wSmallIcon = wSmallIcon;
  m_iWidth = iWidth;
  m_iHeight = iHeight;
  m_iFrameDelay = 50;   // 20 FPS default
  m_bSleep = TRUE;
  m_uiMIDIPlayerID = 0;
}

GameEngine::~GameEngine()
{
}

//-----------------------------------------------------------------
// Game Engine General Methods
//-----------------------------------------------------------------
BOOL GameEngine::Initialize(int iCmdShow)
{
  WNDCLASSEX    wndclass;

  // Create the window class for the main window
  wndclass.cbSize         = sizeof(wndclass);
  wndclass.style          = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc    = WndProc;
  wndclass.cbClsExtra     = 0;
  wndclass.cbWndExtra     = 0;
  wndclass.hInstance      = m_hInstance;
  wndclass.hIcon          = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetIcon()));
  wndclass.hIconSm        = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetSmallIcon()));
  wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  wndclass.lpszMenuName   = NULL;
  wndclass.lpszClassName  = m_szWindowClass;

  // Register the window class
  if (!RegisterClassEx(&wndclass))
    return FALSE;

  // Calculate the window size and position based upon the game size
  int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
      iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
        GetSystemMetrics(SM_CYCAPTION);
  if (wndclass.lpszMenuName != NULL)
    iWindowHeight += GetSystemMetrics(SM_CYMENU);
  int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
      iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;

  // Create the window
  m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
    WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
    iWindowHeight, NULL, NULL, m_hInstance, NULL);
  if (!m_hWindow)
    return FALSE;

  // Show and update the window
  ShowWindow(m_hWindow, iCmdShow);
  UpdateWindow(m_hWindow);

  return TRUE;
}

LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Route Windows messages to game engine member functions
  switch (msg)
  {
    case WM_CREATE:
      // Set the game window and start the game
      SetWindow(hWindow);
      GameStart(hWindow);
      return 0;

    case WM_ACTIVATE:
      // Activate/deactivate the game and update the Sleep status
      if (wParam != WA_INACTIVE)
      {
        GameActivate(hWindow);
        SetSleep(FALSE);
      }
      else
      {
        GameDeactivate(hWindow);
        SetSleep(TRUE);
      }
      return 0;

    case WM_PAINT:
      HDC         hDC;
      PAINTSTRUCT ps;
      hDC = BeginPaint(hWindow, &ps);

      // Paint the game
      GamePaint(hDC);

      EndPaint(hWindow, &ps);
      return 0;

    case WM_LBUTTONDOWN:
      // Handle left mouse button press
      MouseButtonDown(LOWORD(lParam), HIWORD(lParam), TRUE);
      return 0;

    case WM_LBUTTONUP:
      // Handle left mouse button release
      MouseButtonUp(LOWORD(lParam), HIWORD(lParam), TRUE);
      return 0;

    case WM_RBUTTONDOWN:
      // Handle right mouse button press
      MouseButtonDown(LOWORD(lParam), HIWORD(lParam), FALSE);
      return 0;

    case WM_RBUTTONUP:
      // Handle right mouse button release
      MouseButtonUp(LOWORD(lParam), HIWORD(lParam), FALSE);
      return 0;

    case WM_MOUSEMOVE:
      // Handle mouse movement
      MouseMove(LOWORD(lParam), HIWORD(lParam));
      return 0;

    case WM_DESTROY:
      // End the game and exit the application
      GameEnd();
      PostQuitMessage(0);
      return 0;
  }
  return DefWindowProc(hWindow, msg, wParam, lParam);
}

void GameEngine::ErrorQuit(LPTSTR szErrorMsg)
{
  MessageBox(GetWindow(), szErrorMsg, TEXT("Critical Error"), MB_OK | MB_ICONERROR);
  PostQuitMessage(0);
}

void GameEngine::PlayMIDISong(LPTSTR szMIDIFileName, BOOL bRestart)
{
  // See if the MIDI player needs to be opened
  if (m_uiMIDIPlayerID == 0)
  {
    // Open the MIDI player by specifying the device and filename
    MCI_OPEN_PARMS mciOpenParms;
    mciOpenParms.lpstrDeviceType = "sequencer";
    mciOpenParms.lpstrElementName = szMIDIFileName;
    if (mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
      (DWORD_PTR)&mciOpenParms) == 0)
      // Get the ID for the MIDI player
      m_uiMIDIPlayerID = mciOpenParms.wDeviceID;
    else
      // There was a problem, so just return
      return;
  }

  // Restart the MIDI song, if necessary
  if (bRestart)
  {
    MCI_SEEK_PARMS mciSeekParms;
    if (mciSendCommand(m_uiMIDIPlayerID, MCI_SEEK, MCI_SEEK_TO_START,
      (DWORD_PTR)&mciSeekParms) != 0)
      // There was a problem, so close the MIDI player
      CloseMIDIPlayer();
  }

  // Play the MIDI song
  MCI_PLAY_PARMS mciPlayParms;
  if (mciSendCommand(m_uiMIDIPlayerID, MCI_PLAY, 0,
    (DWORD_PTR)&mciPlayParms) != 0)
    // There was a problem, so close the MIDI player
    CloseMIDIPlayer();
}

void GameEngine::PauseMIDISong()
{
  // Pause the currently playing song, if possible
  if (m_uiMIDIPlayerID != 0)
    mciSendCommand(m_uiMIDIPlayerID, MCI_PAUSE, 0, NULL);
}

void GameEngine::CloseMIDIPlayer()
{
  // Close the MIDI player, if possible
  if (m_uiMIDIPlayerID != 0)
  {
    mciSendCommand(m_uiMIDIPlayerID, MCI_CLOSE, 0, NULL);
    m_uiMIDIPlayerID = 0;
  }
}



GameEngine.h

//-----------------------------------------------------------------
// Game Engine Object
// C++ Header - GameEngine.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include <windows.h>
#include <mmsystem.h>



//-----------------------------------------------------------------
// Windows Function Declarations
//-----------------------------------------------------------------
int WINAPI        WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow);
LRESULT CALLBACK  WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

//-----------------------------------------------------------------
// Game Engine Function Declarations
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance);
void GameStart(HWND hWindow);
void GameEnd();
void GameActivate(HWND hWindow);
void GameDeactivate(HWND hWindow);
void GamePaint(HDC hDC);
void GameCycle();
void HandleKeys();
void MouseButtonDown(int x, int y, BOOL bLeft);
void MouseButtonUp(int x, int y, BOOL bLeft);
void MouseMove(int x, int y);

//-----------------------------------------------------------------
// GameEngine Class
//-----------------------------------------------------------------
class GameEngine
{
protected:
  // Member Variables
  static GameEngine*  m_pGameEngine;
  HINSTANCE           m_hInstance;
  HWND                m_hWindow;
  TCHAR               m_szWindowClass[32];
  TCHAR               m_szTitle[32];
  WORD                m_wIcon, m_wSmallIcon;
  int                 m_iWidth, m_iHeight;
  int                 m_iFrameDelay;
  BOOL                m_bSleep;
  UINT                m_uiMIDIPlayerID;
public:
  // Constructor(s)/Destructor
          GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
            WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
  virtual ~GameEngine();

  // General Methods
  static GameEngine*  GetEngine() { return m_pGameEngine; };
  BOOL                Initialize(int iCmdShow);
  LRESULT             HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,
                        LPARAM lParam);
  void                ErrorQuit(LPTSTR szErrorMsg);
void                PlayMIDISong(LPTSTR szMIDIFileName = TEXT(""),
                        BOOL bRestart = TRUE);
  void                PauseMIDISong();
  void                CloseMIDIPlayer();


  // Accessor Methods
  HINSTANCE GetInstance() { return m_hInstance; };
  HWND      GetWindow() { return m_hWindow; };
  void      SetWindow(HWND hWindow) { m_hWindow = hWindow; };
  LPTSTR    GetTitle() { return m_szTitle; };
  WORD      GetIcon() { return m_wIcon; };
  WORD      GetSmallIcon() { return m_wSmallIcon; };
  int       GetWidth() { return m_iWidth; };
  int       GetHeight() { return m_iHeight; };
  int       GetFrameDelay() { return m_iFrameDelay; };
  void      SetFrameRate(int iFrameRate) { m_iFrameDelay = 1000 /
              iFrameRate; };
  BOOL      GetSleep() { return m_bSleep; };
  void      SetSleep(BOOL bSleep) { m_bSleep = bSleep; };
};




SexyMemory.cpp

//-----------------------------------------------------------------
// SexyMemory Application
// C++ Source - SexyMemory.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "SexyMemory.h"

//-----------------------------------------------------------------
// Game Engine Functions
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance)
{
  // Create the game engine
  _pGame = new GameEngine(hInstance, TEXT("SexyMemory"),
    TEXT("Sexy Memory"), IDI_SEXYMEMORY, IDI_SEXYMEMORY_SM, 500, 500);
  if (_pGame == NULL)
    return FALSE;
  
  // Set the frame rate
  _pGame->SetFrameRate(20);

  // Store the instance handle
  _hInstance = hInstance;

  return TRUE;
}

void GameStart(HWND hWindow)
{
	//Seed the Random Number Generator
	srand(GetTickCount());


  // Create and load the background and saucer bitmaps
  HDC hDC = GetDC(hWindow);
  _pTiles[0] = new Bitmap(hDC,IDB_SMBLANK,_hInstance);
  _pTiles[1] = new Bitmap(hDC,IDB_SM1,_hInstance);
  _pTiles[2] = new Bitmap(hDC,IDB_SM2,_hInstance);
  _pTiles[3] = new Bitmap(hDC,IDB_SM3,_hInstance);
  _pTiles[4] = new Bitmap(hDC,IDB_SM4,_hInstance);
  _pTiles[5] = new Bitmap(hDC,IDB_SM5,_hInstance);
  _pTiles[6] = new Bitmap(hDC,IDB_SM6,_hInstance);
  _pTiles[7] = new Bitmap(hDC,IDB_SM7,_hInstance);
  _pTiles[8] = new Bitmap(hDC,IDB_SM8,_hInstance);

//Clear the tile States and images
  for(int i= 0;i < 4;i++)
	  for(int j = 0;j < 4;j++)
	  {
		  _bTileStates[j] = FALSE;
		  _iTiles[j] = 0;
	  }

	  //Initialize the tile images randomly
	  for( i = 0;i < 2;i++)
		  for(int j = 1;j < 9; j++)
		  {
			  int x = rand() % 4;
			  int y = rand() % 4;
			  while (_iTiles[x][y] != 0)
			  {
				  x = rand() % 4;
				  y = rand() % 4;
			  }
			  _iTiles[x][y] = j;
		  }
		  //Initialize the tiles selections and match/ try count
		  _ptTile1.x = _ptTile1.y = -1;
		  _ptTile2.x = _ptTile2.y = -1;
		  _iMatches = _iTries = 0;
		  //Play some nice music
		  _pGame->PlayMIDISong(TEXT("fft-Save_Olan.mid"));
}


 

void GameEnd()
{
	_pGame->CloseMIDIPlayer();
  // Cleanup the Tile Bitmaps
  for(int i = 0; i < 9; i++)
	  delete _pTiles;


  

  // Cleanup the game engine
  delete _pGame;
}

void GameActivate(HWND hWindow)
{
	//Resume Playing the Midi
	_pGame->PlayMIDISong(TEXT(""),FALSE);
}

void GameDeactivate(HWND hWindow)
{
	//Pause the Midi Music
	_pGame->PauseMIDISong();

}

void GamePaint(HDC hDC)
{
  // Draw the Tiles
  int iTileWidth = _pTiles[0] ->GetWidth();
  int iTileHeight = _pTiles[0] ->GetHeight();
  for(int i = 0;i < 4;i++)
	  for(int j = 0; j < 4; j++)
		  if( _bTileStates[j] ||((i == _ptTile1.x) && (j == _ptTile1.y)) ||
			  ((i == _ptTile2.x) &&(j == _ptTile2.y)))
			  _pTiles[_iTiles[j]] ->Draw(hDC,i * iTileWidth, j * iTileHeight,TRUE);
		  else
			  _pTiles[0] ->Draw(hDC,i * iTileWidth, j * iTileHeight,TRUE);
}


void GameCycle()
{

}

void HandleKeys()
{
  
}

void MouseButtonDown(int x, int y, BOOL bLeft)
{
	//Determine which tile was clicked
	int iTileX  = x / _pTiles[0] ->GetWidth();
	int iTileY = y/_pTiles[0] ->GetHeight();
	//Make sure the tile hasn't already been matched
	if(!_bTileStates[iTileX][iTileY])
	{
		//See if this is  the first tile selected
		if(_ptTile1.x == -1)
		{
			//Play a sound for the tile Selection
			PlaySound((LPCSTR)IDW_SELECT,_hInstance,SND_ASYNC |SND_RESOURCE);

			//Set the first tile selection
			_ptTile1.x = iTileX;
			_ptTile1.y = iTileY;
		}
		else if((iTileX != _ptTile1.x) || (iTileY != _ptTile1.y))
		{
			if(_ptTile2.x == -1)
			{
				//Play a sound for the tile selection
				PlaySound((LPCSTR)IDW_SELECT,_hInstance,SND_ASYNC |SND_RESOURCE);

				//Increase the number of tries
				_iTries++;
				//Set the Tile selection
				_ptTile2.x = iTileX;
				_ptTile2.y = iTileY;

				//see if there's a match
				if(_iTiles[_ptTile1.x][_ptTile1.y] ==
					_iTiles[_ptTile2.x][_ptTile2.y])
				{
					//Play a Sound for the tile match
					PlaySound((LPCSTR)IDW_MATCH,_hInstance,SND_ASYNC |SND_RESOURCE);

					//Set the tile state to indicate the match
					_bTileStates[_ptTile1.x][_ptTile1.y] = TRUE;
					_bTileStates[_ptTile2.x][_ptTile2.y] = TRUE;

					//Clear the Tile Selections
					_ptTile1.x = _ptTile1.y = _ptTile2.x = _ptTile2.y = -1;

					//Update the match count and check for a winner
					if(++_iMatches == 8)
					{
						//Play Sound that says you win
						PlaySound((LPCSTR)IDW_YOUWIN,_hInstance,SND_ASYNC |SND_RESOURCE);

						TCHAR szText[64];
						wsprintf(szText,"You won in %d tries.", _iTries);
						MessageBox(_pGame ->GetWindow(), szText,TEXT("Sexy Memory"),MB_OK);
					}
				}
				else
					//Play a sound that says you didn't get a matvh
					PlaySound((LPCSTR)IDW_MISMATCH,_hInstance,SND_ASYNC |SND_RESOURCE);

			}
			else
			{
				//Clear the tile selections
				_ptTile1.x = _ptTile1.y = _ptTile2.x = _ptTile2.y = -1;
			}
		}
		

	  
  // Force a repaint to update the tile
  InvalidateRect(_pGame->GetWindow(), NULL, FALSE);
	}
  
}

void MouseButtonUp(int x, int y, BOOL bLeft)
{
}

void MouseMove(int x, int y)
{
}
[\source]

SexyMemory.h
[source lang ="cpp"]
//SexyMemory.h
#pragma once

//....................................................
//Include Files
//...................................................
#include <windows.h>
#include "Resource.h"
#include "gameengine.h"
#include "Bitmap.h"

//....................................................
//Global Variables
//....................................................

HINSTANCE _hInstance;
GameEngine* _pGame;
Bitmap*  _pTiles[9]; //Stores away the tile images
BOOL  _bTileStates[4][4]; //This storeswhether a tile is matched or not
int  _iTiles[4][4]; // Stores the bitmap associated with each tile
POINT  _ptTile1, _ptTile2; //Keeps track of the 2 tile selections the player makes
int  _iMatches,_iTries; //Keeps track of the number of matches and the number of tries respectively
[\source]

SexyMemory.h

//SexyMemory.h
#pragma once

//....................................................
//Include Files
//...................................................
#include <windows.h>
#include "Resource.h"
#include "gameengine.h"
#include "Bitmap.h"

//....................................................
//Global Variables
//....................................................

HINSTANCE _hInstance;
GameEngine* _pGame;
Bitmap*  _pTiles[9]; //Stores away the tile images
BOOL  _bTileStates[4][4]; //This storeswhether a tile is matched or not
int  _iTiles[4][4]; // Stores the bitmap associated with each tile
POINT  _ptTile1, _ptTile2; //Keeps track of the 2 tile selections the player makes
int  _iMatches,_iTries; //Keeps track of the number of matches and the number of tries respectively
[\source]


And these are the 4 errors that I get


GameEngine.cpp
c:\program files\microsoft visual studio\myprojects\sexy memory\gameengine.cpp(238) : error C2065: 'DWORD_PTR' : undeclared identifier
c:\program files\microsoft visual studio\myprojects\sexy memory\gameengine.cpp(238) : error C2677: binary '&' : no global operator defined which takes type 'struct tagMCI_OPEN_PARMSA' (or there is no acceptable conversion)
c:\program files\microsoft visual studio\myprojects\sexy memory\gameengine.cpp(251) : error C2677: binary '&' : no global operator defined which takes type 'struct tagMCI_SEEK_PARMS' (or there is no acceptable conversion)
c:\program files\microsoft visual studio\myprojects\sexy memory\gameengine.cpp(259) : error C2677: binary '&' : no global operator defined which takes type 'struct tagMCI_PLAY_PARMS' (or there is no acceptable conversion)
Error executing cl.exe.

Sexy Memory.exe - 4 error(s), 0 warning(s)

[Edited by - Gamesmaster3 on June 9, 2005 6:37:18 PM]
Advertisement
It would appear that you are a few #includes shy of a compiling program. ;)

Based on what you've posted, you should be getting a lot more than 4 errors. So, I can only assume that what you've posted doesn't show all of your includes. DWORD_PTR is defined in basetsd.h, which should get included through some other include (not sure which one, though). You can include it manually, as I don't think it's dependent on any other includes.
I didn't include every file because I didn't think there would be anyone that would look through that much code just to find an answer for someone they didn't know.So I included the code for the file that the compiler said the error occured in and then the header file because I assumed that's where most of the definitions and declarations would be.

I tryed out your suggestion but still get the same 4 errors.The guy at Gametutorials.com said that the code was basically correct and thought there might be something wrong with my settings.Because he got it to work.

I've included the winmm'lib and the msimg32.lib into my project.I chose a empty WIN32 application for this project.I just don't know what I've done wrong.If it helps to put the whole code on I will.I just need some help with this
If the only file that GameEngine.cpp includes is GameEngine.h, then perhaps a look at what files GameEngine.h includes might help resolve the issue.

The libs that you are linking to won't have any impact on this situation, as it is a compile-time error, not a link-time error.
I've gone ahead and included some of the other code I have for this project.Pretty much any file that had anything to do with the music portion was added.So please check it out.
I finally figured it out.The problem has been a change in the Visual c++ format since Michael Morrison's book was first published.I had to change (DWORD_PTR) to just (DWORD)

Once I did that everything went through fine.Thats everyone that tried to help me out.
You might want to look into FMOD as its just so amazingly powerful and easy to use. I like your SexyMemory.cpp .
Rob Loach [Website] [Projects] [Contact]
Thanks Rob!!Besides a few modifications though I can't take credit for the Memory Game code.Michael Morrison's book Teach Yourself Game Programming in 24 hours is chiefly responsible for that.Putting music to the program was my idea.And since then I cadded a continue function to it.I'm hoping that sooner or later I will know enough to do one totally on my own.But I am learning which is the important thing.

I will look into FMOD but I probally won't take you up on it anythime soon.I want to learn one thing at a time and once I have it down then I can think about moving on.

This topic is closed to new replies.

Advertisement