Шаг 36 - Создаем анимацию, продолжение

В прошлом шаге мы создали интерфейс, теперь мы создадим наполнение класса. Для удобства всю инициализацию я провожу, создавая класс.

Visual Basic
Visual C++

Visual Basic

Описываем элементы класса и функции WinAPI

Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _
	ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight _
	As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
	ByVal dwRop As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, _
	ByVal hObject As Long) As Long

Private Const SRCCOPY = &HCC0020

Private srFon As DirectDrawSurface7
Private srChip As DirectDrawSurface7
Private srPrimarySurf As DirectDrawSurface7
Private srSecondarySurf As DirectDrawSurface7
Private objDirectDraw As DirectDraw7
Private objDirectX As DirectX7

В момент создания класса производим всю необходимую инициализацию – создание первичной, вторичной поверхности. Двух внеэкранных и переносим картинку на внеэкранные поверхности.

Private Sub Class_Initialize()
On Error GoTo errors:

Dim tempSurfdeck1 As DDSURFACEDESC2
Dim tempSurfdeck2 As DDSURFACEDESC2
Dim tempSurfdeck3 As DDSURFACEDESC2
Dim tempCaps As DDSCAPS2
Set objDirectX = New DirectX7
Set objDirectDraw = objDirectX.DirectDrawCreate("")
objDirectDraw.SetCooperativeLevel Form1.hWnd, DDSCL_FULLSCREEN Or DDSCL_EXCLUSIVE
objDirectDraw.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT
tempSurfdeck1.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
tempSurfdeck1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX
tempSurfdeck1.lBackBufferCount = 1
Set srPrimarySurf = objDirectDraw.CreateSurface(tempSurfdeck1)
tempCaps.lCaps = DDSCAPS_BACKBUFFER
Set srSecondarySurf = srPrimarySurf.GetAttachedSurface(tempCaps)

tempSurfdeck2.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH
tempSurfdeck2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
tempSurfdeck2.lWidth = 640
tempSurfdeck2.lHeight = 480

Set srFon = objDirectDraw.CreateSurface(tempSurfdeck2)

tempSurfdeck3.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH
tempSurfdeck3.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
tempSurfdeck3.lWidth = 233
tempSurfdeck3.lHeight = 66
Set srChip = objDirectDraw.CreateSurface(tempSurfdeck3)

Form1.Picture1.Picture = LoadResPicture(103, vbResBitmap)
a = srFon.GetDC
hCompt = CreateCompatibleDC(a)
SelectObject hCompt, Form1.Picture1.Picture
BitBlt a, 0, 0, 640, 480, hCompt, 0, 0, SRCCOPY
srFon.ReleaseDC (a)

Form1.Picture1.Picture = LoadResPicture(102, vbResBitmap)
a = srChip.GetDC
hCompt = CreateCompatibleDC(a)
SelectObject hCompt, Form1.Picture1.Picture
BitBlt a, 0, 0, 233, 66, hCompt, 0, 0, SRCCOPY
srChip.ReleaseDC (a)

FonToSecond
ChipToSecond 0, 0
Flip
FonToPrimary
ChipToPrimary 0, 0

Exit Sub
errors:
End
End Sub

Тут есть основные функции помещения фона и корабля на поверхность.

Public Sub ChipToPrimary(x, y As Integer)
	Dim r As RECT
	Dim r1 As RECT
	r.Top = y
	r.Left = x
	r.Right = x + 233
	r.Bottom = y + 66
	r1.Top = 0
	r1.Left = 0
	r1.Right = 233
	r1.Bottom = 66
	srPrimarySurf.Blt r, srChip, r1, DDBLT_WAIT
End Sub

Public Sub ChipToSecond(x, y As Integer)
	Dim r As RECT
	Dim r1 As RECT
	r.Top = y
	r.Left = x
	r.Right = x + 233
	r.Bottom = y + 66
	r1.Top = 0
	r1.Left = 0
	r1.Right = 233
	r1.Bottom = 66
	srSecondarySurf.Blt r, srChip, r1, DDBLT_WAIT
End Sub

Public Sub FonToSecond()
	Dim r As RECT
	r.Top = 0
	r.Left = 0
	r.Right = 640
	r.Bottom = 480
	srSecondarySurf.Blt r, srFon, r, DDBLT_WAIT
End Sub

Public Sub FonToPrimary()
	On Error GoTo errors:
	Dim r As RECT
	r.Top = 0
	r.Left = 0
	r.Right = 640
	r.Bottom = 480
   
	srPrimarySurf.Blt r, srFon, r, DDBLT_WAIT
	Exit Sub
errors:
End
End Sub

А Flip просто продублировано.

Public Sub Flip()
	srPrimarySurf.Flip Nothing, DDFLIP_WAIT
End Sub

При разрушении класса объекты удаляются.

Private Sub Class_Terminate()
Set srChip = Nothing
Set srFon = Nothing
Set srSecondarySurf = Nothing
Set srPrimarySurf = Nothing
objDirectDraw.RestoreDisplayMode
objDirectDraw.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL
Set objDirectDraw = Nothing
Set objDirectX = Nothing
End Sub

Вот и все. Запускайте приложение, на фоне моря будет корабль. Этот корабль можно будет двигать стрелками курсора. По идее никакого мигания заметно быть не должно, по крайней мере, у меня не заметно.

Visual C++

Описываем элементы класса

class CDirectDraw  
{
public:
	void ChipToSecond(int x,int y);
	void FonToSecond();
	void ChipToPrimary(int x,int y);
	void Flip();
	void FonToPrimary();
	CDirectDraw();
	virtual ~CDirectDraw();
private:
	LPDIRECTDRAWSURFACE srFon;
	LPDIRECTDRAWSURFACE srChip;
	LPDIRECTDRAWSURFACE srPrimarySurf;
	LPDIRECTDRAWSURFACE srSecondarySurf;
	LPDIRECTDRAW lpDD;
};

В момент создания класса производим всю необходимую инициализацию – создание первичной, вторичной поверхности. Двух внеэкранных и переносим картинку на внеэкранные поверхности.

CDirectDraw::CDirectDraw()
{
	HRESULT rezult;
	DDSURFACEDESC tempSurfdeck1;
	DDSURFACEDESC tempSurfdeck2;
	DDSURFACEDESC tempSurfdeck3;
	DDSCAPS tempCaps;
	rezult = DirectDrawCreate(NULL, &lpDD, NULL );
	lpDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(),
		DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
	lpDD->SetDisplayMode(640,480,16);

	memset(&tempSurfdeck1,0,sizeof(DDSURFACEDESC));
	tempSurfdeck1.dwSize = sizeof(DDSURFACEDESC);
	tempSurfdeck1.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; 
	tempSurfdeck1.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
		DDSCAPS_FLIP | DDSCAPS_COMPLEX; 
	tempSurfdeck1.dwBackBufferCount =1;
	lpDD->CreateSurface(&tempSurfdeck1,&srPrimarySurf,NULL);

	tempCaps.dwCaps = DDSCAPS_BACKBUFFER;
	srPrimarySurf->GetAttachedSurface(&tempCaps,&srSecondarySurf);

	memset(&tempSurfdeck2,0,sizeof(DDSURFACEDESC));
	tempSurfdeck2.dwSize = sizeof(DDSURFACEDESC);
	tempSurfdeck2.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	tempSurfdeck2.ddsCaps.dwCaps  = DDSCAPS_OFFSCREENPLAIN;
	tempSurfdeck2.dwHeight = 480;
	tempSurfdeck2.dwWidth = 640;
	lpDD->CreateSurface(&tempSurfdeck2,&srFon,NULL);
	memset(&tempSurfdeck3,0,sizeof(DDSURFACEDESC));
	tempSurfdeck3.dwSize = sizeof(DDSURFACEDESC);
	tempSurfdeck3.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	tempSurfdeck3.ddsCaps.dwCaps  = DDSCAPS_OFFSCREENPLAIN;
	tempSurfdeck3.dwHeight = 66;
	tempSurfdeck3.dwWidth = 233;
	lpDD->CreateSurface(&tempSurfdeck3,&srChip,NULL);

	HANDLE hBMP;
	HDC hdc;
	hBMP=LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP1),
		IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
	srFon->GetDC(&hdc);
	HDC hCompt = CreateCompatibleDC(hdc);
	SelectObject(hCompt,hBMP);
	BitBlt(hdc, 0, 0, 640, 480, hCompt, 0, 0, SRCCOPY);
	srFon->ReleaseDC(hdc);  

	hBMP=LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP2),
		IMAGE_BITMAP, 0, 0,  LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
	srChip->GetDC(&hdc);
	hCompt = CreateCompatibleDC(hdc);
	SelectObject(hCompt,hBMP);
	BitBlt(hdc, 0, 0, 233, 66, hCompt, 0, 0, SRCCOPY);
	srChip->ReleaseDC(hdc); 

	FonToSecond();
	ChipToSecond(0,0);
	Flip();
	FonToPrimary();
	ChipToPrimary(0,0);
}

Тут есть основные функции помещения фона и корабля на поверхность.

void CDirectDraw::FonToPrimary()
{
	DDBLTFX ddb;
	memset(&ddb,0, sizeof(DDBLTFX));
	ddb.dwSize = sizeof(DDBLTFX);
	ddb.dwDDFX = DDBLTFX_MIRRORLEFTRIGHT;

	CRect r;
	r.top = 0;
	r.left = 0;
	r.right = 640;
	r.bottom = 480;
	srPrimarySurf->Blt(r,srFon,r,DDBLT_WAIT,&ddb);
}


void CDirectDraw::FonToSecond()
{
	DDBLTFX ddb;
	memset(&ddb,0, sizeof(DDBLTFX));
	ddb.dwSize = sizeof(DDBLTFX);
	ddb.dwDDFX = DDBLTFX_MIRRORLEFTRIGHT;
 
	CRect r;
	r.top = 0;
	r.left = 0;
	r.right = 640;
	r.bottom = 480;
	srSecondarySurf->Blt(r,srFon,r,DDBLT_WAIT,&ddb);
}

void CDirectDraw::ChipToSecond(int x, int y)
{
	DDBLTFX ddb;
	memset(&ddb,0, sizeof(DDBLTFX));
	ddb.dwSize = sizeof(DDBLTFX);
	ddb.dwDDFX = DDBLTFX_MIRRORLEFTRIGHT;
	CRect r;
	CRect r1;
	r.top = y;
	r.left = x;
	r.right = x + 233;
	r.bottom = y + 66;
	r1.top = 0;
	r1.left = 0;
	r1.right = 233;
	r1.bottom = 66;
	srSecondarySurf->Blt(r,srChip,r1,DDBLT_WAIT,&ddb);
}

void CDirectDraw::ChipToPrimary(int x, int y)
{
	DDBLTFX ddb;
	memset(&ddb,0, sizeof(DDBLTFX));
	ddb.dwSize = sizeof(DDBLTFX);
	ddb.dwDDFX = DDBLTFX_MIRRORLEFTRIGHT;
	CRect r;
	CRect r1;
	r.top = y;
	r.left = x;
	r.right = x + 233;
	r.bottom = y + 66;
	r1.top = 0;
	r1.left = 0;
	r1.right = 233;
	r1.bottom = 66;
	srPrimarySurf->Blt(r,srChip,r1,DDBLT_WAIT,&ddb);
}

А Flip просто продублировано.

void CDirectDraw::Flip()
{
	srPrimarySurf->Flip(NULL,DDFLIP_WAIT); 
}

При разрушении класса объекты удаляются.

CDirectDraw::~CDirectDraw()
{
	srChip->Release(); 
	srFon->Release(); 
	srSecondarySurf->Release(); 
	srPrimarySurf->Release();
	lpDD->RestoreDisplayMode(); 
	lpDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(),DDSCL_NORMAL);
	lpDD->Release(); 
}

Вот и все. Запускайте приложение, на фоне моря будет корабль. Этот корабль можно будет двигать стрелками курсора. По идее никакого мигания заметно быть не должно, по крайней мере, у меня не заметно.


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Каев Артем - 08.05.2002