一个字。累并快乐,兴趣索然。。。。追回梦想
学习WINDOWS编程2个月。下一步:DIrectX9...
自己加载资源:素材在下面自行下载(修改成BMP格式)
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 Tanker.rc 使用
//
#define IDB_ENEMY 101
#define IDB_HERO 103
#define IDI_ICON 105
#define IDB_ARMS 107
#define IDB_BOOMENM 108
#define IDB_HEROBOOM 109
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 110
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
main.cpp:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "resource.h"
#include <math.h>
#include <process.h>
#pragma comment (lib,"msimg32.lib") //处理BMP背景色函数
//常量。
#define MAX_STR 32
#define HERO_SPEED 3
#define ARM_NUM 50
#define ARM_SPEED 5
#define ENM_NUM 8
#define ENM_SPEED 1
#define ENM_CHANGDIR 4 //enemy changdir probability 。
//全局变量。
TCHAR wndclassname[MAX_STR] = TEXT("TankerWar");
TCHAR wndtitlename[MAX_STR] = TEXT("小坦克大战");
HINSTANCE hInst;
HWND hwnd;
HDC hdc, memdc, bufdc;
RECT wndrect;
HBITMAP hHeroBMP, hEnemyBMP, hNullBMP, hArmBMP, hEnemyboomBMP, hHeroBoombmp;
//游戏各类SPRITE参数。
enum MOVEDIR { left, up, down, right };
enum ISDIE { die, nodie };
enum ARMTYPE { heroarm, enemyarm };
struct TKPOINT
{
INT x; INT y;
};
struct HERO
{
ISDIE isdie;
MOVEDIR movedir;
TKPOINT pstn;
};
struct ENEMY
{
ISDIE isdie;
MOVEDIR movedir;
TKPOINT pstn;
};
struct ARMS
{
ISDIE isdie;
MOVEDIR movedir;
TKPOINT pstn;
ARMTYPE armtp;
};
//创建对象。(可惜了还不会用抽象成对象)
ARMS arms[ARM_NUM];
HERO hero;
ENEMY enemy[ENM_NUM];
//函数声明
LRESULT WINAPI WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); //消息主函数
void GameInit(); //游戏初始化
void DispalyScreen(); //显示SPRITE
void Fire(ENEMY &enemy, ARMTYPE armstype);//敌人开火
void HeroFire(ARMTYPE);//主角开火
void EnemyAutoMove(LPVOID param);
void DispalyScreen() {
hdc = GetDC(hwnd);
memdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
hNullBMP = CreateCompatibleBitmap(hdc, wndrect.right, wndrect.bottom);
SelectObject(memdc, hNullBMP); //设定CreateCompatibleBitmap的大小,否则不会显示在HDC上。
//Display arms(没有死亡的子弹)
hArmBMP = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_ARMS));
SelectObject(bufdc, hArmBMP);
for (int i = 0; i < ARM_NUM; i++)
{
if (arms[i].isdie == nodie)
{
TransparentBlt(memdc, arms[i].pstn.x, arms[i].pstn.y, 7, 7, bufdc, 0, 0, 7, 7, RGB(255, 255, 255));
switch (arms[i].movedir)
{
case left:
arms[i].pstn.x > 0 ?
arms[i].pstn.x -= ARM_SPEED : arms[i].isdie = die;
break;
case up:
arms[i].pstn.y > 0 ?
arms[i].pstn.y -= ARM_SPEED : arms[i].isdie = die;
break;
case right:
arms[i].pstn.x < wndrect.right ?
arms[i].pstn.x += ARM_SPEED : arms[i].isdie = die;
break;
case down:
arms[i].pstn.y < wndrect.bottom ?
arms[i].pstn.y += ARM_SPEED : arms[i].isdie = die;
break;
}
}
}
//enemy display and move
hEnemyBMP = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_ENEMY));
SelectObject(bufdc, hEnemyBMP);
for (int j = 0; j < ENM_NUM; j++)
{
if (enemy[j].isdie == nodie)
{
switch (enemy[j].movedir)
{
case left:
enemy[j].pstn.x > 0 ?
enemy[j].pstn.x -= ENM_SPEED : enemy[j].pstn.x = 0;
TransparentBlt(memdc, enemy[j].pstn.x, enemy[j].pstn.y, 33, 33, bufdc, 0, 0, 33, 33, RGB(0, 0, 0));
break;
case up:
enemy[j].pstn.y > 0 ?
enemy[j].pstn.y -= ENM_SPEED : enemy[j].pstn.y = 0;
TransparentBlt(memdc, enemy[j].pstn.x, enemy[j].pstn.y, 33, 33, bufdc, 33, 0, 33, 33, RGB(0, 0, 0));
break;
case right:
enemy[j].pstn.x < wndrect.right - 33 ?
enemy[j].pstn.x += ENM_SPEED : enemy[j].pstn.x = wndrect.right - 33;
TransparentBlt(memdc, enemy[j].pstn.x, enemy[j].pstn.y, 33, 33, bufdc, 66, 0, 33, 33, RGB(0, 0, 0));
break;
case down:
enemy[j].pstn.y < wndrect.bottom - 33 ?
enemy[j].pstn.y += ENM_SPEED : enemy[j].pstn.y = wndrect.bottom - 33;
TransparentBlt(memdc, enemy[j].pstn.x, enemy[j].pstn.y, 33, 33, bufdc, 99, 0, 33, 33, RGB(0, 0, 0));
break;
}
}
}
// display hero(这里可以将主角调整成自动移动)
hHeroBMP = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_HERO));
SelectObject(bufdc, hHeroBMP);
if (hero.isdie == nodie)
{
switch (hero.movedir)
{
case left:
TransparentBlt(memdc, hero.pstn.x, hero.pstn.y, 33, 33, bufdc, 0, 0, 33, 33, RGB(0, 0, 0));
break;
case up:
TransparentBlt(memdc, hero.pstn.x, hero.pstn.y, 33, 33, bufdc, 33, 0, 33, 33, RGB(0, 0, 0));
break;
case right:
TransparentBlt(memdc, hero.pstn.x, hero.pstn.y, 33, 33, bufdc, 66, 0, 33, 33, RGB(0, 0, 0));
break;
case down:
TransparentBlt(memdc, hero.pstn.x, hero.pstn.y, 33, 33, bufdc, 99, 0, 33, 33, RGB(0, 0, 0));
break;
}
}
//碰撞检测
hEnemyboomBMP = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BOOMENM));
hHeroBoombmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_HEROBOOM));
for (int i = 0; i < ARM_NUM; i++)
{
if (arms[i].isdie == nodie)
{ //检测敌人中弹
for (int j = 0; j < ENM_NUM; j++)
{
if (arms[i].armtp == heroarm && enemy[j].isdie == nodie && abs(enemy[j].pstn.x + 13 - arms[i].pstn.x) < 18 && abs(enemy[j].pstn.y + 13 - arms[i].pstn.y) < 18)
{
SelectObject(bufdc, hEnemyboomBMP);
TransparentBlt(memdc, enemy[j].pstn.x - 3, enemy[j].pstn.y - 3, 40, 40, bufdc, 120, 0, 40, 40, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, enemy[j].pstn.x - 3, enemy[j].pstn.y - 3, 40, 40, bufdc, 80, 0, 40, 40, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, enemy[j].pstn.x - 3, enemy[j].pstn.y - 3, 40, 40, bufdc, 40, 0, 40, 40, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, enemy[j].pstn.x - 3, enemy[j].pstn.y - 3, 40, 40, bufdc, 0, 0, 40, 40, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
arms[i] = { };
enemy[j] = { };
}
}
//检测主角中弹
if (arms[i].armtp == enemyarm && hero.isdie == nodie
&& abs(hero.pstn.x + 13 - arms[i].pstn.x) < 18 && abs(hero.pstn.y + 13 - arms[i].pstn.y) < 18)
{
SelectObject(bufdc, hHeroBoombmp);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 300, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 250, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 200, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 150, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 100, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 50, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
TransparentBlt(memdc, hero.pstn.x - 8, hero.pstn.y - 8, 50, 50, bufdc, 0, 0, 50, 50, RGB(0, 0, 0));
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
hero.isdie = die;
MessageBox(NULL, TEXT("you falt"), TEXT("loser"), MB_OK);
}
}
}
BitBlt(hdc, 0, 0, wndrect.right, wndrect.bottom, memdc, 0, 0, SRCCOPY);
DeleteObject(hHeroBoombmp);
DeleteObject(hEnemyboomBMP);
DeleteObject(hEnemyBMP);
DeleteObject(hHeroBMP);
DeleteObject(hNullBMP);
DeleteObject(hArmBMP);
DeleteDC(bufdc);
DeleteDC(memdc);
ReleaseDC(hwnd, hdc);
}
void GameInit() {
//hero init
hero.isdie = nodie;
hero.pstn.x = (int)wndrect.right / 2 - 17;
hero.pstn.y = (int)wndrect.bottom - 33;
hero.movedir = up;
for (int i = 0; i < ENM_NUM; i++)
{
srand((UINT)GetTickCount()*i);
int trand = rand();
if (enemy[i].isdie != nodie)
{
enemy[i].isdie = nodie;
enemy[i].movedir = (MOVEDIR)(trand % 4);
enemy[i].pstn = { trand % (wndrect.right - 33),trand % (wndrect.bottom - 33) };
}
}
}
void Fire(ENEMY &enemy, ARMTYPE armstype) {
for (int i = 0; i < ARM_NUM; i++)
{
if (arms[i].isdie != nodie)
{
arms[i].isdie = nodie;
arms[i].movedir = enemy.movedir;
arms[i].armtp = armstype;
if (arms[i].armtp == enemyarm)
{
switch (enemy.movedir)
{
case left:
arms[i].pstn.x = enemy.pstn.x + 3;
arms[i].pstn.y = enemy.pstn.y + 13;
break;
case up:
arms[i].pstn.x = enemy.pstn.x + 13;
arms[i].pstn.y = enemy.pstn.y + 3;
break;
case right:
arms[i].pstn.x = enemy.pstn.x + 29;
arms[i].pstn.y = enemy.pstn.y + 13;
break;
case down:
arms[i].pstn.x = enemy.pstn.x + 13;
arms[i].pstn.y = enemy.pstn.y + 29;
break;
}
break;
}
}
}
}
void HeroFire(ARMTYPE armstype) {
for (int i = 0; i < ARM_NUM; i++)
{
if (hero.isdie == die)
{
break;
}
if (arms[i].isdie != nodie)
{
arms[i].isdie = nodie;
arms[i].movedir = hero.movedir;
//arms[i].pstn.x = hero.pstn.x;
arms[i].armtp = armstype;
if (arms[i].armtp == heroarm)
{
switch (hero.movedir)
{
case left:
arms[i].pstn.x = hero.pstn.x + 3;
arms[i].pstn.y = hero.pstn.y + 13;
break;
case up:
arms[i].pstn.x = hero.pstn.x + 13;
arms[i].pstn.y = hero.pstn.y + 3;
break;
case right:
arms[i].pstn.x = hero.pstn.x + 29;
arms[i].pstn.y = hero.pstn.y + 13;
break;
case down:
arms[i].pstn.x = hero.pstn.x + 13;
arms[i].pstn.y = hero.pstn.y + 29;
break;
}
}
break;
}
}
}
void EnemyAutoMove(LPVOID param) {
while (TRUE)
{
Sleep(800);//否则CPU会飙
srand(UINT(GetTickCount() * 1101));
MOVEDIR dir;
dir = (MOVEDIR)(rand() % 4);
for (int p = 0; p < ENM_NUM; p++)
{
if (enemy[p].pstn.x<ENM_SPEED || enemy[p].pstn.y<ENM_SPEED ||
enemy[p].pstn.x>wndrect.right - 40 || enemy[p].pstn.y>wndrect.bottom - 40)
{
enemy[p].movedir = dir;
}
}
if (enemy[rand() % ENM_NUM].isdie == nodie)
enemy[rand() % ENM_NUM].movedir = dir;
int f = rand() % ENM_NUM;
if (enemy[f].isdie == nodie)
Fire(enemy[f], enemyarm);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prehInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wcs = { CS_HREDRAW | CS_VREDRAW,WndProc,0,0,hInstance,LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON)),LoadCursor(NULL,IDC_UPARROW),HBRUSH(BLACK_BRUSH),NULL,wndclassname };
hInst = hInstance;
if (!RegisterClass(&wcs))
{
return 0;
}
hwnd = CreateWindow(wndclassname, wndtitlename, WS_OVERLAPPEDWINDOW&~WS_THICKFRAME, CW_USEDEFAULT, 0, 500, 500, NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
GameInit(); //角色类初始化
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Sleep(30);//否则CPU会飙
DispalyScreen();
}
}
UnregisterClass(wndclassname, hInstance);
return 0;
}
LRESULT WINAPI WndProc(HWND hwnd, UINT mesage, WPARAM wparam, LPARAM lparam) {
switch (mesage)
{
case WM_LBUTTONUP:
HeroFire(heroarm);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC whdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &wndrect);
EndPaint(hwnd, &ps);
break;
}
case WM_CREATE:
{
_beginthread(EnemyAutoMove, 0, NULL);//创建线程(敌人自动随机变向和开火)
break;
}
case WM_RBUTTONDOWN:
GameInit();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if (hero.isdie == die)
{
break;
}
switch (wparam)
{
case VK_UP:
if (hero.pstn.y > 0)
{
hero.pstn.y -= HERO_SPEED;
hero.movedir = up;
}
else
{
hero.pstn.y = 0;
}
break;
case VK_DOWN:
if (hero.pstn.y < wndrect.bottom - 33)
{
hero.pstn.y += HERO_SPEED;
hero.movedir = down;
}
else
{
hero.pstn.y = wndrect.bottom - 33;
}
break;
case VK_LEFT:
if (hero.pstn.x > 0)
{
hero.pstn.x -= HERO_SPEED;
hero.movedir = left;
}
else
{
hero.pstn.x = 0;
}
break;
case VK_RIGHT:
if (hero.pstn.x < wndrect.right - 33)
{
hero.pstn.x += HERO_SPEED;
hero.movedir = right;
}
else
{
hero.pstn.x = wndrect.right - 33;
}
break;
}
default:
return DefWindowProc(hwnd, mesage, wparam, lparam);
break;
}
return 0;
}
终于搞定。