关闭

win32编程之贪吃蛇(有瑕疵)

标签: win32 C++ 贪吃蛇 UI分离
315人阅读 评论(0) 收藏 举报
分类:

今天花了大概8个小时做了个贪吃蛇,主要的时间还是花费在了如何做的更流畅上面,之前的做法是每次移动整数个单位,给自己的感觉是不太流畅,所以后来改成每次移动的部署为double类型的,  但是有潜在的问题,判断无法精准,只能有个大概的判断,可能是我水平不够暂时还无法做到,希望得到指点。


我是有个想法   把UI和实际数据分开来算, 可以将UI刷新的时间设置为实际跑动的时间的1/5,但是目前还有点问题

综上有

1)每次移动整数

2)每次移动double

3)UI分离


贴上暂时的源代码,这个版本是上面说的第二种,第一种因为流畅度还差点就不用了

#pragma once

#include "resource.h"

const int BORDER = 10;
const int SCREEN_WIDTH = 640;
const RECT rc_top = {BORDER,BORDER,SCREEN_WIDTH-BORDER,BORDER+20};
const RECT rc_bottom = {BORDER,BORDER+30,SCREEN_WIDTH-BORDER,SCREEN_WIDTH-BORDER};
const RECT rc_main = {0,0,SCREEN_WIDTH,SCREEN_WIDTH};

int BLOCK_SIZE = 15;
int curX=0,curY=0;
int curDir[4] = {1,0};
int g_blocked[100][100];
int NUM_X = 40;
int NUM_Y = 40;
typedef struct aaa{
	double curX;
	double curY;
	double curDir[2];
	struct aaa *pre;
	struct aaa  *next;
}body;
body *head;
int g_speed = 50;
int g_seed = 1995421;
int SNAKE_STATE = 0;
int SNAKE_SCORE = 0;
int SNAKE_DIFF = 1;


void MoveWindowToCenter(HWND hWnd);
void DrawBackground(HDC hdc);
void DrawBody(HDC hdc);
VOID outPutBoxInt(int num);
VOID outPutBoxString(TCHAR str[1024]);
int CalculatePosition();
void StartTimer(HWND hWnd);
void CALLBACK MoveSnake( HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime );
void CALLBACK ShowMove( HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime );
int CheckValidate();
void InitGameData();
void DrawBlocked(HDC hdc);
int GenerateFood();
int RandomInt(int _min,int _max);
int CheckForFood(int x,int y);
int GetSnakeLength();
body* GetLast();
void InsertAfterLast(body *newbody);
void SetChildMove();
int SelectDifficulty(int diff);
double GetAbs(double num);
void DrawScore(HDC hdc);


// Snake.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Snake.h"

#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;								// 当前实例
TCHAR szTitle[MAX_LOADSTRING];					// 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];			// 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	InitGameData();
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	
 	// TODO: 在此放置代码。
	MSG msg;
	HACCEL hAccelTable;

	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_SNAKE, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 执行应用程序初始化:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SNAKE));

	// 主消息循环:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SNAKE));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_SNAKE);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_CREATE:
		
		MoveWindowToCenter(hWnd);
		StartTimer(hWnd);
		break;
	case WM_KEYDOWN:
		switch(wParam)
		{
		case 'W':
			if (head->curDir[1]==0)
			{
				head->curDir[0] = 0;
				head->curDir[1] = -1;
			}
			break;
		case 'A':
			if (head->curDir[0]==0)
			{
				head->curDir[0] = -1;
				head->curDir[1] = 0;
			}
			
			break;
		case 'S':
			if (head->curDir[1]==0)
			{
				head->curDir[0] = 0;
				head->curDir[1] = 1;
			}
			
			break;
		case 'D':
			if (head->curDir[0]==0)
			{
				head->curDir[0] = 1;
				head->curDir[1] = 0;
			}
			
			break;
		}
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		case ID_dif1:
			SelectDifficulty(1);
			break;
		case ID_dif2:
			SelectDifficulty(2);
			break;
		case ID_dif3:
			SelectDifficulty(3);
			break;
		case ID_dif4:
			SelectDifficulty(4);
			break;
		case ID_PAUSE:
			SNAKE_STATE = !SNAKE_STATE;
			InvalidateRect(hWnd,&rc_top,false);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		DrawBackground(hdc);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}


void MoveWindowToCenter(HWND hWnd)
{
	RECT rect;
	GetWindowRect(hWnd,&rect);
	int posX = GetSystemMetrics(SM_CXSCREEN);
	int posY = GetSystemMetrics(SM_CYSCREEN);
	posX = (posX - SCREEN_WIDTH)>>1;
	posY = (posY - SCREEN_WIDTH-70)>>1;
	MoveWindow(hWnd,posX,posY,SCREEN_WIDTH,SCREEN_WIDTH+70,TRUE);
}

void DrawBackground(HDC hdc)
{
	HDC mdc = CreateCompatibleDC(hdc);
	HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
	HBRUSH hWhitebrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
	HPEN hPen = (HPEN)CreatePen(PS_DOT,3,RGB(0,255,0));
	HBITMAP hBitmap = (HBITMAP)CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_WIDTH);
	SelectObject(mdc,hBitmap);
	SelectObject(mdc,hBrush);
	//SelectObject(mdc,hPen);
	FillRect(mdc,&rc_main,hWhitebrush);
	
//	Rectangle(mdc,rc_bottom.left,rc_bottom.top,rc_bottom.right,rc_bottom.bottom);

	DrawBody(mdc);
	DrawBlocked(mdc);
	DrawScore(mdc);
	::BitBlt(hdc,0,0,SCREEN_WIDTH,SCREEN_WIDTH,mdc,0,0,SRCCOPY);
	DeleteDC(mdc);
	DeleteObject(hBitmap);
	DeleteObject(hPen);
	DeleteObject(hBrush);
}

void DrawBody(HDC hdc)
{
	HBRUSH hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
	SelectObject(hdc,hBrush);
	if (head==NULL)
	{
		head->curX = 0;
		head->curY = 0;
		head->curDir[0] = 1;
		head->curDir[1] = 0;
		head->next = NULL;
		head->pre = NULL;
	}
	body *temp = head;
	//outPutBoxInt(temp->curX);
	
	while(temp!=NULL)
	{
		Rectangle(hdc,
			(temp->curX*BLOCK_SIZE+rc_bottom.left),
			temp->curY*BLOCK_SIZE+rc_bottom.top,
			((temp->curX+1)*BLOCK_SIZE+rc_bottom.left),
			(temp->curY+1)*BLOCK_SIZE+rc_bottom.top);
		temp = temp->next;
	}
	DeleteObject(hBrush);
}

int CalculatePosition()
{
	curX += curDir[0];
	curY += curDir[1];
	if (g_blocked[curY][curX])
	{
		return -1;
	}
	return 1;
}

VOID outPutBoxInt(int num)
{
	TCHAR szBuf[1024];
	LPCTSTR str = TEXT("%d");
	wsprintf(szBuf,str,num);
	MessageBox(NULL,szBuf,L"Debug",MB_OK);
}

VOID outPutBoxString(TCHAR str[1024])
{
	TCHAR szBuf[1024];
	LPCTSTR cstr = TEXT("%s");
	wsprintf(szBuf,cstr,str);
	MessageBox(NULL,szBuf,L"Debug",MB_OK);
}

void DeleteLinkList(body *hl)
{
	body *temp = hl;
	body *last = GetLast();
	while (last!=head)
	{
		last = last->pre;
		delete(last->next);
	}
}

void StartTimer(HWND hWnd)
{
	SetTimer(hWnd,1001,20,MoveSnake);
	//SetTimer(hWnd,1002,20,ShowMove);
	GenerateFood();
}


void CALLBACK ShowMove(HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
	if (SNAKE_STATE)
	{
		body *temp = head;
		SetChildMove();
		head->curX += head->curDir[0]/(6-SNAKE_DIFF);
		head->curY += head->curDir[1]/(6-SNAKE_DIFF);
		
	}
}

void CALLBACK MoveSnake( HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
	if (SNAKE_STATE)
	{
		body *temp = head;
		SetChildMove();
		head->curX += head->curDir[0]/(5-SNAKE_DIFF);
		head->curY += head->curDir[1]/(5-SNAKE_DIFF);
		InvalidateRect(hWnd,&rc_bottom,false);
		int flag = CheckValidate();
		if (flag==-1)
		{
			KillTimer(hWnd,1002);
			KillTimer(hWnd,1001);
			if (MessageBox(hWnd,L"胜败乃兵家常事,菜鸡请重新来过",L":时光机",MB_YESNO)==IDYES)
			{
				DeleteLinkList(head->next);
				InitGameData();
				SNAKE_STATE = 1;
				StartTimer(hWnd);
				InvalidateRect(hWnd,&rc_top,false);
			}
			else
			{

				PostQuitMessage(0);
			}

		}
		else if(flag==2)
		{
			g_blocked[int(head->curY)][int(head->curX)] = 0;
			body *newbody = new body;
			InsertAfterLast(newbody);
			GenerateFood();
			SNAKE_SCORE++;
			InvalidateRect(hWnd,&rc_top,false);
		}
		else if(flag==3)
		{
			g_blocked[int(head->curY)+1][int(head->curX)+1] = 0;
			body *newbody = new body;
			InsertAfterLast(newbody);
			GenerateFood();
		}
	}
	
}

int CheckValidate()
{
	if (g_blocked[int(head->curY)][int(head->curX)]==1)
	{
		return -1;
	}
	else if (g_blocked[int(head->curY)][int(head->curX)]==2)
	{
		return 2;
	}
	else if(g_blocked[int(head->curY)+1][int(head->curX)+1]==2)
	{
		return 3;
	}
	body *temp = head->next;
	while (temp!=NULL)
	{
		if (GetAbs(temp->curX - head->curX)<0.03 && GetAbs(temp->curY - head->curY)<0.03)
		{
			return -1;
		}
		temp = temp->next;
	}
	return 1;
}

void InitGameData()
{
	int i,j;
	head = new body;
	head->curDir[0] = 1;
	head->curDir[1] = 0;
	head->curX = 10;
	head->curY = 10;
	head->next = head->pre =  NULL;

	memset(g_blocked,0,sizeof(g_blocked));
	for (j=0;j<40;j++)
	{
		g_blocked[0][j] = 1;
		g_blocked[1][j] = 1;
		g_blocked[38][j] = 1;
		g_blocked[39][j] = 1;
	}
	
	for (i=1;i<39;i++)
	{
		g_blocked[i][0] = 1;
		g_blocked[i][1] = 1;
		g_blocked[i][38] = 1;
		g_blocked[i][39] = 1;
	}

	SNAKE_STATE = 0;
	SNAKE_SCORE = 0;
	SNAKE_DIFF = 1;
}

void DrawBlocked(HDC hdc)
{
	int i,j;
	HBRUSH hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
	HBRUSH hYellowbrush = (HBRUSH)CreateSolidBrush(RGB(255,255,0));
	
	
	for (i=0;i<NUM_Y;i++)
	{
		for (j=0;j<NUM_X;j++)
		{
			if (g_blocked[i][j]==1)
			{
				SelectObject(hdc,hBrush);
				Rectangle(hdc,rc_bottom.left+j*BLOCK_SIZE,rc_bottom.top+i*BLOCK_SIZE,rc_bottom.left+(j+1)*BLOCK_SIZE,rc_bottom.top+(i+1)*BLOCK_SIZE);
			}
			else if (g_blocked[i][j]==2)
			{
				SelectObject(hdc,hYellowbrush);
				Rectangle(hdc,rc_bottom.left+j*BLOCK_SIZE,rc_bottom.top+i*BLOCK_SIZE,rc_bottom.left+(j+1)*BLOCK_SIZE,rc_bottom.top+(i+1)*BLOCK_SIZE);

			}
		}
	}
	DeleteObject(hYellowbrush);
	DeleteObject(hBrush);
}

int GenerateFood()
{
	int x = RandomInt(0,35*35-GetSnakeLength());
	int index = 0;
	int i=2,j=2;
	while(1)
	{
		if(j==37)
		{
			j=2;
			i++;
		}
		else
		{
			j++;
		}
		if (CheckForFood(i,j)==1)
		{
			
			index++;
			if(index>=x)
			{
				break;
			}
		}
		
	}
	g_blocked[i][j] = 2;
	return 1;
}

int RandomInt(int _min,int _max)
{
	srand((g_seed++)%65532+GetTickCount());
	return _min+rand()%(_max-_min);
}

int CheckForFood(int x,int y)
{
	if (g_blocked[y][x])
	{
		return -1;
	}
	body *temp = head;
	while(temp!=NULL)
	{
		if (temp->curX==x&&temp->curY==y)
		{
			return -1;
		}
		temp = temp->next;
	}
	return 1;
}

int GetSnakeLength()
{
	int count = 0;
	body *temp = head;
	while(temp!=NULL)
	{
		count++;
		temp = temp->next;
	}
	return count;
}

void InsertAfterLast(body *newbody)
{
	body *temp = head;
	temp = temp->next;
// 	body *last = GetLast();
// 	last->next = newbody;
// 	newbody->pre = last;
// 	newbody->next = NULL;
// 	newbody->curDir[0] = last->curDir[0];
// 	newbody->curDir[1] = last->curDir[1];
// 	newbody->curX = last->curX ;
// 	newbody->curY = last->curY ;
	newbody->pre = NULL;
	newbody->next = head;
	head->pre = newbody;
	newbody->curDir[0] = head->curDir[0];
	newbody->curDir[1] = head->curDir[1];
	newbody->curX = head->curX+head->curDir[0];
	newbody->curY = head->curY+head->curDir[1];
	head = newbody;
}

body* GetLast()
{
	body *ret;
	body *temp = head;
	while (temp!=NULL)
	{
		ret = temp;
		temp = temp->next;
	}
	return ret;
}

void SetChildMove()
{
	body *last = GetLast();
	while(last!=head)
	{
		last->curX = last->pre->curX;
		last->curY = last->pre->curY;
		last = last->pre;
	}
}

int SelectDifficulty(int diff)
{
	
	g_speed = 300-diff*60;
	InitGameData();
	SNAKE_DIFF = diff;
	SNAKE_STATE = 1;
	HWND hWnd = GetActiveWindow();
	StartTimer(hWnd);
	InvalidateRect(hWnd,&rc_top,false);
	return diff;
}

double GetAbs(double num)
{
	return num>0?num:-num;
}

void DrawScore(HDC hdc)
{	
	HFONT hFont = CreateFont(20,0,0,0,FW_THIN,0,0,0,UNICODE,0,0,0,0,L"微软雅黑");
	SelectObject(hdc,hFont);
	SetBkMode(hdc,TRANSPARENT);
	SetBkColor(hdc,RGB(255,255,0));
	RECT rect;
	rect.left = rc_top.left;
	rect.top = rc_top.top;
	rect.right = rc_top.right/2;
	rect.bottom = rc_top.bottom;
	TCHAR szBuf[30];
	LPCTSTR cstr = TEXT("当前难度:%d");
	wsprintf(szBuf,cstr,SNAKE_DIFF);
	DrawTextW(hdc,szBuf,_tcslen(szBuf),&rect,DT_CENTER | DT_VCENTER);

	RECT rect2;
	rect2.left = rc_top.left+100;
	rect2.top = rc_top.top;
	rect2.right = rc_top.right;
	rect2.bottom = rc_top.bottom;
	TCHAR szBuf2[30];
	LPCTSTR cstr2 = TEXT("得分:%d");
	wsprintf(szBuf2,cstr2,SNAKE_SCORE);
	DrawTextW(hdc,szBuf2,_tcslen(szBuf2),&rect2,DT_CENTER | DT_VCENTER);

	DeleteObject(hFont);
}


欢迎指点和交流

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7510次
    • 积分:228
    • 等级:
    • 排名:千里之外
    • 原创:15篇
    • 转载:6篇
    • 译文:0篇
    • 评论:4条
    最新评论