您的位置:首页 > 编程语言 > C语言/C++

c++ 编写自己的小型游戏开发库

2010-10-05 22:49 519 查看
之前接触了SDL,的确是个很好的轻量级游戏引擎,其实自己一直也有个想法,自己来开发个游戏库,呵呵,有点大了,现在想想,在windows下也就是对图形操作和窗口消息的封装吧。试着写写看吧,花了两天的时间,搞出个雏形,发来给大家分享下:

#pragma warning(disable:4786)
#define ULONG_PTR ULONG
#include <windows.h>
#include <gdiplus.h>
#include <map>
#include <vector>
#include <iostream>
#include <string>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
using namespace std;
class surface{
public:
	surface();
	~surface();
	
	static void init();
	static void unit();
	static surface *loadimg(wchar_t*,int,int);
	void create(int,int);
	int getwidth();
	int getheight();
	void bitblt(surface *,int,int,int,int);
	Graphics *getgdi();
	Bitmap* getbitmap();
	void string(wchar_t *,int,int,int,Color,wchar_t *);
	void line(int,int,int,int,int,Color);
	void rect(int,int ,int ,int ,int ,Color);
	void dot(int ,int ,int ,Color );
	void fillrect(int,int,int,int,Color);
	void image(wchar_t *,int ,int ,int ,int );

private:
	Graphics *g;
	int width;
	int height;
	static ULONG_PTR m_gdiplusToken;
	Bitmap *b;
};
ULONG_PTR surface::m_gdiplusToken=0;
surface::surface(){
width=0;
height=0;
}
surface::~surface(){
	if(b)
delete b;
	if(g)
delete g;
}
void surface::init(){
	GdiplusStartupInput gdiplusStartupInput;
	GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

}
void surface::unit(){
	GdiplusShutdown(m_gdiplusToken);
}
Bitmap* surface::getbitmap(){
	return b;
}
void surface::create(int w,int h){
width=w;
height=h;
b=new Bitmap(w,h);
g=Graphics::FromImage(b);
}
surface* surface::loadimg(wchar_t *path,int w,int h){
	
	Image *i=Image::FromFile(path);
	surface *sur=new surface;
	sur->create(w,h);
	sur->getgdi()->DrawImage(i,0,0,w,h);
	return sur;
}
Graphics *surface::getgdi(){
	return g;
}
int surface::getheight(){
	return height;
}
int surface::getwidth(){
	return width;
}
void surface::bitblt(surface *src,int x,int y,int w,int h){
g->DrawImage(src->getbitmap(),x,y,w,h);
//	BitBlt(g->GetHDC(),x,y,w,h,src->getgdi()->GetHDC(),0,0,SRCCOPY);
}
void surface::string(wchar_t *str,int x,int y,int big=1,Color c=Color(255,0,0,0),wchar_t *style=L"Latha"){
	SolidBrush brush(c);
	
	FontFamily fontFamily(style); 
    Font font(&fontFamily,big,FontStyleRegular,UnitInch);
    PointF pointF(x,y);
	g->DrawString(str,-1,&font,pointF,&brush);
}
void surface::line(int x1,int y1,int x2,int y2,int big=1,Color c=Color(255,0,0,0)){
	Pen p(c);
	p.SetWidth(big);
	g->DrawLine(&p,x1,y1,x2,y2);
	/*
	HPEN b=CreatePen(PS_SOLID,3,RGB(255,255,255));
			HPEN	old=(HPEN)SelectObject(m_hdc,b);
	MoveToEx(m_hdc,x1,y1,0);
	LineTo(m_hdc,x2,y2);
	SelectObject(m_hdc,old);
	DeleteObject(b);*/
	
}
void surface::dot(int x,int y,int big=1,Color c=Color(255,0,0,0)){
	Pen p(c);
	p.SetWidth(big);
	g->DrawLine(&p,x,y,x,y);
}
void surface::rect(int x,int y,int w,int h,int big=1,Color c=Color(255,0,0,0)){
	Pen p(c);
	p.SetWidth(big);
	g->DrawRectangle(&p,x,y,w,h);
}
void surface::fillrect(int x,int y,int w,int h,Color c=Color(255,0,0,0)){
	SolidBrush brush(c);
	g->FillRectangle(&brush,x,y,w,h);
	/*
	HBRUSH b=CreateSolidBrush(RGB(111,111,111));
		RECT r={0,0,640,480};
		FillRect(m_hdc,&r,b);
		DeleteObject(b);*/
	
}
void surface::image(wchar_t *str,int x,int y,int w,int h){
	Image i(str);
	g->DrawImage(&i,x,y,w,h);
}
class wnd{
public:
	wnd();
	~wnd();
	void create(int ,int );
	HWND getwindow();
	LRESULT sendmessage(UINT,WPARAM,LPARAM);
	LRESULT postmessage(UINT,WPARAM,LPARAM);
	void addevent(UINT,LRESULT (*)(HWND,WPARAM,LPARAM));
	void removeevent(UINT,LRESULT (*)(HWND,WPARAM,LPARAM));
	void setrun(void (*)(wnd *,LPVOID),LPVOID);
	surface *draw();
	void setdelay(int);
	void exit();
private:
	int delay;
	void (*run)(wnd *,LPVOID);
	static map<UINT,LRESULT (*)(HWND,WPARAM,LPARAM)>e;
	int width;
	int height;
	HWND hwnd;
	static LRESULT CALLBACK wndproc(HWND,UINT,WPARAM,LPARAM);
	static DWORD WINAPI init(LPVOID);
	HANDLE thread;
	surface sur;
	LPVOID flag;
	static wnd *th;
	static vector<wnd*> wndmanage;
	int _exit;
};
wnd* wnd::th=0;
vector<wnd*> wnd::wndmanage;
map<UINT,LRESULT (*)(HWND,WPARAM,LPARAM)> wnd::e;
wnd::wnd(){
run=0;
delay=0;
_exit=0;
}
wnd::~wnd(){

}
void wnd::setdelay(int i){
	delay=i;
}
void wnd::create(int w,int h){
	width=w;
	height=h;
	thread=CreateThread(0,0,init,(LPVOID)this,0,0);

}
surface *wnd::draw(){
	return &sur;
}
void wnd::addevent(UINT m,LRESULT (*p)(HWND,WPARAM,LPARAM)){
e[m]=p;
}
void wnd::removeevent(UINT m,LRESULT (*p)(HWND,WPARAM,LPARAM)){
	map<UINT,LRESULT (*)(HWND,WPARAM,LPARAM)>::iterator it;
	it=e.find(m);
	if(it!=e.end()){
		e.erase(it);
	}
}
LRESULT CALLBACK wnd::wndproc(HWND h,UINT m ,WPARAM w,LPARAM l){
	map<UINT,LRESULT (*)(HWND,WPARAM,LPARAM)>::iterator it;
	it=e.find(m);
	if(it!=e.end()){
		return ((LRESULT (*)(HWND,WPARAM,LPARAM))it->second)(h,w,l);
	}
	if(m==WM_CREATE){
		
	}
	if(m==WM_ERASEBKGND){
		return 1;
	}
	if(m==WM_PAINT){
		//MessageBox(0,0,0,0);
		PAINTSTRUCT ps;
		HDC dc=BeginPaint(h,&ps);
		RECT r;
		GetClientRect(h,&r);
	Graphics g(dc);
//EnterCriticalSection(section);
	for(int i=0;i<wndmanage.size();i++){
		
	//	cout<<((wnd*)wndmanage[i])->getwindow()<<"   "<<h<<endl;
	
		if(((wnd*)wndmanage[i])->getwindow()==h){
			break;
		}
	}
//	if(i!=wndmanage.size()){
	//	cout<<i<<endl;
		if(((wnd*)wndmanage[i])->run!=0){
			((wnd*)wndmanage[i])->run((wnd*)wndmanage[i],((wnd*)wndmanage[i])->flag);
			g.DrawImage(((wnd*)wndmanage[i])->sur.getbitmap(),0,0,r.right-r.left,r.bottom-r.top);
		}
//	}
//	LeaveCriticalSection(section);
/*
g.FillRectangle(&SolidBrush(Color(255,100,100,100)),0,0,640,480);
for(int i=40;i<480;i+=40){
	g.DrawLine(&Pen(Color(255,200,200,200)),0,i,640,i);
	
		}
for(i=40;i<640;i+=40){
	g.DrawLine(&Pen(Color(255,200,200,200)),i,0,i,480);
	
		}*/

		
	
		EndPaint(h,&ps);
		return 0;

	}
	if(m==WM_DESTROY){
		for(int i=0;i<wndmanage.size();i++){
			
			cout<<((wnd*)wndmanage[i])->getwindow()<<"   "<<h<<endl;
			
			if(((wnd*)wndmanage[i])->getwindow()==h){
				break;
			}
		}
wndmanage.erase(&wndmanage[i]);
		PostQuitMessage(0);
	}
	return DefWindowProc(h,m,w,l);
}
DWORD WINAPI wnd::init(LPVOID l){
wnd *	w=(wnd *)l;

	WNDCLASS wndclass; 
	
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hbrBackground=(HBRUSH) GetStockObject(BLACK_BRUSH);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.hIcon=LoadIcon(NULL,IDC_ARROW);
	wndclass.hInstance=GetModuleHandle(0);
	wndclass.lpfnWndProc=wndproc;
	wndclass.lpszClassName="sx";
	wndclass.lpszMenuName="sx";
	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wndclass);
	RECT rect = {0,0,w->width,w->height}; 
		 AdjustWindowRect(&rect,((WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_SIZEBOX),false); 
th=w;
	w->hwnd=::CreateWindowEx(0,"sx","sx",((WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_SIZEBOX) ,CW_USEDEFAULT, CW_USEDEFAULT,rect.right-rect.left, rect.bottom-rect.top,NULL,NULL,GetModuleHandle(0),NULL);
wndmanage.push_back(w);
	w->sur.create(w->width,w->height);
	ShowWindow(w->hwnd,1);
	UpdateWindow(w->hwnd);
	HDC dc=GetDC(w->hwnd);
	RECT r;
	GetClientRect(w->hwnd,&r);
	Graphics g(dc);
/*
	char a[10];
	sprintf(a,"%d",r.right-r.left);
	MessageBox(0,a,0,0);*/
/*
HDC hdc=CreateCompatibleDC(dc);
HBITMAP bit=CreateCompatibleBitmap(dc,w->width,w->height);
SelectObject(hdc,bit);
HPEN b=CreatePen(PS_SOLID,3,RGB(255,255,255));
			SelectObject(hdc,b);
w->sur.attach(hdc);*/

	MSG msg;
	while(1)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
			if(msg.message==WM_QUIT){
				break;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}else{
		//	EnterCriticalSection(section);
			if(w->run!=0){
			w->run(w,w->flag);
g.DrawImage(w->sur.getbitmap(),0,0,r.right-r.left,r.bottom-r.top);
			}else{
				HBRUSH b=CreateSolidBrush(RGB(0,0,0));
				RECT r={0,0,w->width,w->height};
				FillRect(dc,&r,b);
		DeleteObject(b);
			}
			if(w->_exit==1){
				break;
			}
		/*
		for(int i=40;i<480;i+=40){
					MoveToEx(hdc,0,i,0);
					LineTo(hdc,640,i);
		
		}*/
		//w->draw()->bitblt(img,0,0,200,200);
		/*
		for(int i=40;i<640;i+=40){
					MoveToEx(hdc,i,0,0);
					LineTo(hdc,i,480);		}*/
		
		
		//::BitBlt(dc,0,0,w->width,w->height,hdc,0,0,SRCCOPY);
			Sleep(w->delay);
		//	LeaveCriticalSection(section);
		}
			Sleep(1);
	}
	return 0;
}

LRESULT wnd::sendmessage(UINT m,WPARAM w,LPARAM l){
	return ::SendMessage(hwnd,m,w,l);
}
LRESULT wnd::postmessage(UINT m,WPARAM w,LPARAM l){
	return ::PostMessage(hwnd,m,w,l);
}
HWND wnd::getwindow(){
	return hwnd;
}
void wnd::setrun(void (*p)(wnd *,LPVOID),LPVOID l){
	flag=l;
	run=p;
}
void wnd::exit(){
	_exit=1;
}




定义了两个类,surface和wnd,surface就是对图形的操作,这里封装的是GDI+,wnd就是对窗口的封装,包括它的创建和消息处理等。实际编写中发现gdi+对图形的操作蛮方便的,但是效率其实不如gdi,所以我的代码里有大量的gdi操作代码的注释,这里我想模拟双缓冲技术,写的要是有问题还望大家指正。wnd的窗口创建我用的是多线程,所以每个窗口对应自己的消息线程,但是窗口处理函数是共用的,所以消息处理代码要判断当前消息是对于哪个窗口的。下面看下实例代码:



LRESULT onbuttondown(HWND h,WPARAM w,LPARAM l){
	MessageBox(0,"sx","sx",0);
	return 0;
}
surface *img;
void run(wnd *w,LPVOID l){
w->draw()->fillrect(0,0,640,480,Color(255,255,255,255));
for(int i=40;i<480;i+=40)
w->draw()->line(0,i,640,i,1,Color(255,100,100,100));
	//w->draw()->bitblt(img,0,0,200,200);
for(i=40;i<640;i+=40)
w->draw()->line(i,0,i,480,1,Color(255,100,100,100));
w->draw()->fillrect(0,0,80,80);
}
void run1(wnd *w,LPVOID l){
w->draw()->fillrect(0,0,640,480,Color(255,0,0,0));
	for(int i=40;i<200;i+=40)
		w->draw()->line(0,i,200,i,1,Color(255,100,100,100));
//	w->draw()->fillrect(0,0,80,80);
}
wnd w;
wnd w1;
LRESULT ondb(HWND h,WPARAM w,LPARAM l){
	if(h==w1.getwindow())
	MessageBox(0,"sx1","sx1",0);
	else
MessageBox(0,"sx","sx",0);
	return 0;
}
main(){
	surface::init();
	atexit(surface::unit);
	img=surface::loadimg(L"c://1.jpg",1000,1000);
	

w.setrun(run,0);
//w.setdelay(100);
w.create(640,480);

//w.addevent(WM_LBUTTONUP,&onbuttondown);
w1.setrun(run1,0);
w1.setdelay(100);
w1.addevent(WM_LBUTTONUP,ondb);
w1.create(300,300);
system("pause");
}




在peekmessage上有个轮询的过程,所以我们要用setrun要添加自定义处理函数,来对窗口不停的刷新。addevent是添加事件处理的。setdelay是轮询的延迟函数,create便创建窗体了,创建后pause下,让主线程暂停。

本文有不足之处,还望大家多多指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: