虽然不跟电源扯不上边,出于对C语言的热爱,还是发出来了,如果不合适的话
请论坛管理员转到非技术区
开始游戏的编写,首先我要先声明,下面写的很多东西我会很无耻的使用陈坤大哥的原创作品中的内容,^_^毕竟我们只是需要了解如何编写一个游戏,通过这个游戏的编写过程让你更加了解Windows的机制,特别是GDI的应用。毕竟使用GDI来写游戏并非是明智的。在你还只会C语言的情况下,我们不懂得如何去使用面向对象的方法实现它,其实C语言也是可以干很多事情的,不要只看到现在的C#、Java等面向对象语言很流行,C语言可以说是它们的老祖宗,除非你想从事Windows下游戏或软件的编写以及手机游戏、平台的开发等需要用到类的地方,像单片机、嵌入式、LINUX等很多地方都是使用的C语言,把C语言学好你一样可以干大事,就像如鹏网杨中科老师说的那样,当你把一门语言学的很好的时候,其他的语言对你来说都不是问题,想学更多其他的,在这里只涉及到游戏的编写^_^。
好了,不多说废话了,首先,一般游戏开发之前,对自己的游戏进行前期分析,策划。将可预见问题都整理并分析可行性是很重要的。坦克的全套资源图片我们将使用陈坤大哥的(对独立程序员来说,最困难就是资源图片的获取了),坦克大战是典型的砖块贴图,这是大部分游戏所使用的方法,能够很好说明游戏的制作。
下面引用陈坤大哥的坦克大战介绍:
游戏名称:坦克大战
英文名称:Tank War
版本:1.0
游戏概要说明:
游戏为2D单人操作PC游戏,运行平台为Windows,使用VC++6.0开发,因为一般的游戏框架都没有使用MFC,所以我们还是直接用WIN32 API,运用GDI编程。
游戏过程:
游戏画面是一整张地图,开始玩家在地图底部有一辆坦克,和一个堡垒。堡垒里面是鹰标记。
从地图的顶部分左中右三个地方出地方坦克。胜利条件是击溃敌军所有坦克。
如果玩家的坦克被击爆或者堡垒里面的鹰标记被击中则失败。
玩家有三次复活机会。
游戏界面:
屏幕左上角标示己方分数,剩余复活次数,敌方剩余坦克
我们采用砖块贴图就需要规定砖块的大小,因为图片是32 Pixel*32 Pixel,所以就也采用32*32的砖块。
现在大部分机器都用1024*768的屏幕,我们游戏窗口就定大小为800*600吧,这样横行有25格(25*32=800),纵行是18格(18*32=600)
我们把游戏做简单一点,就直接把地图大小定为25*18吧,这样不需要卷轴,会很方便实现。
我们地图分为以下几种地形
陆地:正常状态
树林:子弹可穿过,坦克可通行,但会隐藏其中
土墙:子弹可击穿,坦克不可通过
钢墙:子弹不可穿过,坦克不可通过
水:子弹可穿过,坦克不可通过
雪地:子弹可穿过,坦克可通行,但减速
然后地图上会有如下道具:
心:奖励一次复活机会
时钟:敌方暂停移动10秒
工具:加强火力,同时发射双炮
炸弹:炸毁所有画面上的敌方坦克
激素:坦克加速
防护罩:保护基地15秒
好了,有了前期策划,我们需要先搭建一个游戏框架,如果你使用的是VC2003以上的版本的话,可以使用向导生成一个Win32的GUI框架程序。不懂的可以去陈坤大哥的博客那参考,VC++6.0的我们可以选择类型为Win32 Application创建工程。
第一步:点击新建后,选择工程对话框,设置好你的工程名称和路径后,单击确定。
第二步:单击完成就可以创建工程成功了。
此时工程里面什么都没有,别急~~我们先设置好窗口的大小先,引用陈坤大哥的公共头文件CommonHead.h设置(头文件会加吧,不会加的去百度搜索下方法吧 ),创建好CommonHead.h头文件后我们可以给它加入以下代码:
#ifndef _H_COMMONHEAD_H
#define _H_COMMONHEAD_H
#define C_TILE_W 32
#define C_TILE_H 32
#define C_MAP_W 25
#define C_MAP_H 18
#endif
这样就把窗口的大小设置成800 X 600了,接下来是框架
首先定义一个 #define WIN32_LEAN_AND_MEAN 这个宏主要是从 Windows 头中排除极少使用的资料,不使用MFC
窗口创建的代码如下:
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料,不使用MFC
#include "windows.h"
#include "CommonHead.h"
#define WINDOW_CLASS_NAME "TankWar"
HWND gamehwnd; //windows窗口句柄
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
//
// 函数: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
//
// 目的: 处理主窗口的消息。
//
// winclass - 注册窗口类
// CreateWindowEx - 保存实例句柄并创建主窗口
// GetMessage - 处理主事件循环
//
//
int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
{
WNDCLASSEX winclass; // this will hold the class we create
MSG msg; // generic message
/* first fill in the window class stucture 设置窗口风格 */
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC |
CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// register the window class
if (!RegisterClassEx(&winclass))
return(0);
/* create the window 创建一个windows窗口 */
if (!(gamehwnd = CreateWindowEx(NULL, // extended style
WINDOW_CLASS_NAME, // class
"坦克大战", // title
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,CW_USEDEFAULT, // initial x,y
C_TILE_W*C_MAP_W,C_TILE_H*C_MAP_H, // initial width, height
NULL, // handle to parent
NULL, // handle to menu
hinstance,// instance of this application
NULL))) // extra creation parms
return(0);
UpdateWindow(gamehwnd);
// save main window handle
/* instead of GetMessage() to retrieve messages 主事件循环 */
while(GetMessage(&msg,NULL,0,0))
{
// translate any accelerator keys
TranslateMessage(&msg);
// send the message to the window proc
DispatchMessage(&msg);
} // end while
// return to Windows like this
return(msg.wParam);
} // end WinMain
//
// 函数: WindowProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
// this is the main message handler of the system
PAINTSTRUCT ps;
HDC hdc;
// what is the message
switch(msg)
{
case WM_CREATE:
{
// do initialization stuff here
// return success
return(0);
} break;
case WM_PAINT: //绘制内存位图到窗口
{
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
// return success
return (0);
} break;
case WM_DESTROY: //窗口关闭处理
{
// kill the application, this sends a WM_QUIT message
PostQuitMessage(0);
// return success
return(0);
} break;
default:break;
} // end switch
// process any messages that we didn't take care of
return (DefWindowProc(hwnd, msg, wparam, lparam));
} // end WinProc
创建的窗口:
以上代码是什么意思可以翻看《Windows程序设计(北大版)》第五版 或 《Windows 游戏编程大师技巧(第二版)》两本书,
也可以去网上的《游戏开发新手入门之Windows编程
windows的框架构建都是这个模式的,你不需要去记住它,只要知道是什么意思,到时候直接使用就可以了。
但我们需要先编写一个地图编辑器,那样才容易构建我们的地图,供游戏主程序的读取。所以我们使用陈坤大哥的地图编辑器。
引用陈坤大哥的话:
我们分析地形,可分为地表层与障碍物。本来我们还有树木层的,但我们观察到其实树木层和地表层是一样的,只是显示时有所不同(树画在最上面)。
但为了简便处理,我们把他们通通归为地形。
那么地形有陆地、钢墙、土墙、河水、雪地、树林、鹰七种。可以用四位就够了。我们就给地图分配一个Byte(8位)。
所以地图所占字节为25*18=450 Bytes
这个地图很简单,只是反映地形而已,所以写起来不会很困难。
有惊无险,来到第二篇,前面已经有了一个框架了,而且也有了地图编辑器,可以绘制自己想要的地图了。在这一章我们还不需要用到地图,首先要实现一个游戏的开场动画和游戏失败动画。
下面将继续无耻的使用大哥的原创,特别是变量的命名,有现成的东西当然要使用了,想变量名也是很头疼的事^_^
每个游戏或软件都会有它自己的图标,我们先给游戏加上它的图标。
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|