怎么怎么自己制作小游戏戏

《游戏编程》第一部 基础篇 -
《游戏编程》第一部 基础篇
文章内容:
  有了一个目标之后,往往人们比较有信心和动力。所以,我重新修改了一下教程的安排,在这儿插入了“零”篇。
  在基础篇里,我们将逐步学习关于游戏制作的基本知识,为后续的开发工作奠定基础。那么,在基础篇结束的时候,我们可以弄出个什么东西呢?我们看图:
  这是我写的一个演示程序的截图,暂时定为我们基础篇教程的目标。
  该演示程序包含了一些基本要素,如: Windows 程序的基本框架、DirectDraw 的基本使用方法、精灵的使用和 一些简单的关于
DirectInput
的东西。但是,这个程序没有对障碍和遮挡进行处理,也就是说,人物会走到任何地方去。因为一些关于地图方面的知识,我将会放到提高篇里。
  本范例在以下环境中通过:VC6.0、DirectX 7.0/8.1 SDK、Win2000/WinXP
  说明 []
  其实现在网上关于游戏编程的技术文章越来越多了,但是我发现关于最基本的了解游戏的文章还是比较少的。大多数文章是以 DirectX
作为开始教学起始的,因此,我觉得花点时间写下这篇文章还是值得的。今天,我就开始介绍一些关于游戏编程的基础东西,以便大家能够真正的开始了解游戏,从而能够很快的转入游戏开发。由于是针对新手的,如果您已经转入程序编写阶段,您完全可以抛开了。我将采用一种不同于网络上现有的教学方法,来讲一下游戏程序开发的奥秘:)
  大家可以看到游戏中主角连贯的出招动作、华丽的场景、震撼的战斗效果,这一切似乎很难让人想象程序是怎么实现的。也许您在上课无聊的时候尝试过在课本的角上画上几个人物动作的***图,然后一遍又一遍地翻着它,觉得很好玩。其实您已经在无形之中接触了游戏动画的基本原理。其实游戏动画的步骤可以想象成这样:
  手中拿着两张纸,把一张放在后面。其实这个就是 DirectDraw
的两个成员。我们先把一个***动作画在背后的那张纸上。那么,我们当前看到的就是一个“白屏”而已。然后,我们“快速地”将后面的那张纸拿到前面来。呵呵,你现在看到的是第一个***动作了吧!那么,怎么“快速地”呢?不要紧张,这些问题都被
DirectDraw
完美的解决了,别急,今后会详细的讲解的。现在,当前的两张纸已经交换了,而且也看到了动作(一个静态的而已),那么后面的“白纸”怎么办呢?我们先拿“橡皮”将纸擦一遍,然后,将第二个***图画上,接下来?呵呵,自己干吧,应该明白了吧。经过再次的交换,我们已经在屏幕上看到第二个动作了。我们继续把后面的纸擦干净,再画第三个动作,再交换,继续下去......由于我们的“快速地”动作相当快,所以感觉不到有任何问题。
  或许有人会问:为什么不直接在第一张纸上进行“擦-&画-&擦-&画”的动作呢?这个就是为了我们平常所说的“闪屏”问题而进行的解决方案。由于直接进行动作,速度相对较慢,有时用户会在屏幕上看到一闪一闪的现象。我们用“两张纸”的话,就完美的解决了这个问题。(啊?还闪屏?呵呵,你小子把显示器坏了的问题都怪我啊·#¥%……*)
  既然上面的游戏的“内幕”已经掌握,那么我们来看看在上一节中涉及的“武器”和基本知识。或许本篇所涉及的东西是基于理论的多数,但是,这将为理解在后面即将写的程序部分会打下很好的基础的。所以咬咬牙,看完吧!(啊?没有牙了啊?大家应该鼓掌吧!连牙都没有长齐的“3、4点种的太阳”都开始学习了,你们还有理由吗?恩?是大娘啊?那更应该值得学习了!跑题:)
  首先要介绍的第一位主角是 Windows 编程中的必要元素: RECT 。是英语 rectangle
的简写,意思是矩形。它有什么用呢?我们在上面不是讲到了动作的***动作吗?我们看右图:
  这个图就是一个简单的行走动作***图,复杂的可能有10帧左右哦:)那么怎么在程序中实现自动在纸上画出正确的图片呢?(其实我一直在考虑是否将这部分内容加上,因为实在太基本了。但是每个人都这么想的话,基础的谁来教呢?算了,让别人的口水淹死我吧!)假设您已经有点
C++ 语言的基础了。这个教我教的话,说不过去吧:)请看下面的代码:
#define m_Width&&
// 每个动作的 宽度
#define m_Height& 48&&
// 每个动作的 高度
void ShowThePic()
&&& static RECT&&&&&&&&&&&&&&
// 矩形对象,用于精确定位所要的当前动作
&&& static int CurrentFrame = 0;&&&
// 当前动作的编号
&&& static int Direction = 0;&&&&&&
// 当前的方向
&&& rect.top = D rect.bottom = (Direction+1)*m_H&
// 对当前矩形的大小定义,数学的问题哦
&&& rect.left = CurrentF rect.right =
(CurrentFrame+1)*m_W&
// 根据英文的意思也可以知道在给谁赋值
&&& BltPicToScreen();&&&&&&&&&&&&&&
// 一个伪函数,作用是将当前矩形内的图形复制到屏幕上。
&&& CurrentFrame++;
&&& if( CurrrentFrame==3 )
&&&&&&& CurrentFrame = 0;
// 这个步骤能够保证动作的循环
  不知道这么个函数你能否看懂。之所以要采用 static 静态变量,是因为我们这个函数程序要循环运行。如果直接写个 int
的话,每次执行都会被赋回原值 0,那么图片就不会变了。
  上面这段代码其实并不是那么理想。因为程序自己在那儿一个劲地运行,完全没有我们控制的份儿。别急!来看下面这份修改过的伪代码:
#define m_Width&& 32&&
// 每个动作的 宽度
#define m_Height& 48&&
// 每个动作的 高度
void ShowThePic()
&&& static RECT&&&&
// 矩形对象,用于精确定位所要的当前动作
&static int CurrentFrame = 0;
// 当前动作的编号
static int Direction = 0;&&&
// 当前的方向
rect.top = D rect.bottom = (Direction+1)*m_H
//对当前矩形的大小定义,数学的问题哦
& rect.left = CurrentF rect.right = (CurrentFrame+1)*m_W
//根据英文的意思也可以知道在给谁赋值
BltPicToScreen();&&&&
// 一个伪函数,作用是将当前矩形内的图形复制到屏幕上。
&&& if( LeftArrowDown() )
// 如果 左箭头 被按下
&&&&&&& Direction = 1;&&&
// 赋值方向为 1
&&&&&&& CurrentFrame++;
&&& if( RightArrowDown() )
&&&&&&& Direction = 3;
&&&&&&& CurrentFrame++;
&&& if( UpArrowDown() )
&&&&&&& Direction = 2;
&&&&&&& CurrentFrame++;
&&& if( DownArrowDown() )
&&&&&&& Direction = 0;
&&&&&&& CurrentFrame++;
&&& if(CurrrentFrame==3)
&&&&&&& CurrentFrame = 0;
// 这个步骤能够保证动作的循环
  经过这么一修改,问题再次得到解决。上面的代码就能够响应用户的操作了。当然,你这么直接在程序里输入这些代码是不行的:)因为是“伪代码”。你得根据实际情况,自己相应地做些修改,才能使程序运行!
  (题外话:不晓得这么进行教学,你是否能够一点一点的积累到知识?这种教程是不是合适?请到论坛内发表意见,我真的很想能够摸索出大家接受的方法,有利教学)
  欢迎回到教程中来!有人或许会问,为什么这么麻烦要把图形放在这么个图片里头,不一个动作一个图啊?呵呵,想想,那要多少图片啊,很难于管理的。况且,这样并不能避免使用这种常用手法,因为
RECT 已经是一个成员。游戏里不能不用他的!
  哇,口水干了。(其实是手累了:)我们下回再见吧。
  下回预告:
  少年侦探柯南为了查清楚事情的真相,他......(?还真的预告啊?)
  不好意思,习惯性用语了:)在下回,我会讲一下,如何将今天的代码整合到程序中去。
  Welcome back!很高兴再次与你相遇教程。废话不多说,继续。
  上次的代码片段,说实在,拿在手里没有用。为啥?因为不能运行的啊:)我们这次就按照上次的安排,讲如何将显示图片的代码片段整合到程序中,让它能够具体的体现出来。
  我将在这儿讨论 Windows 编程,而不是 MFC 。关于 MFC 和 Windows 的不同和各自的优点,我们不多涉及了。 MFC
就是微软的一个封装开发库,极大程度的降低了 Windows 开发的复杂。但是,我们还是继续 Windows 编程,呵呵。
  我们来看,一个基本的 Windows 程序是一个窗口对吧:)我们所玩的游戏,其实也是有窗口的,只不过是看不见的,而且被
DirectDraw 掩盖了而已。那么,如何创建一个窗口呢?我们来看:
BOOL Init(HINSTANCE hInst, int nCmdShow)
&&& HWND hW&&&&&&&&&&&&&&&&&&&&&&&&&&
// 窗口的句柄,就是一个储存窗口的对象
&&& WNDCLASS WndC&&&&&&&&&&&&&&&&&&
// 用于注册窗口的对象
&&& WndClass.style = CS_HREDRAW | CS_VREDRAW;
// 定义窗口的类型
&&& WndClass.lpfnWndProc = WinP&&&&&
// 指定了窗口消息的处理函数 ** 关键!
&&& WndClass.cbClsExtra = 0;&&&&&&&&&&&&
// 没有特定意义
&&& WndClass.cbWndExtra = 0;&&&&&&&&&&&&
// 没有特定意义
&&& WndClass.hInstance = hI&&&&&&&&&
// 窗口的实例
&&& WndClass.hIcon = LoadIcon(hInst, IDI_APPLICATION);
// 指定窗口的图标
&&& WndClass.hCursor = LoadCursor(hInst, IDC_ARROW);&&
// 指定程序的指针
&&& WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
// 指定背景色为黑色
&&& WndClass.lpszMenuName = NULL;&&&&&&&
// 指定菜单为无,游戏不需要
&&& WndClass.lpszClassName = &GDIM_GAME_ENGINE&;
//这个程序注册的名字
RegisterClass(&WndClass);&&&&&&&&&&&
// 注册程序
hWnd = CreateWindowEx(WS_EX_TOPMOST, &GDIM_GAME_ENGINE&, &GDIM_GAME&,
WS_POPUP, 112, 84, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInst,
// 这段代码就是实现了一个窗口的创建
// 我们可以通过来检测是否创建成功。如果失败将返回一个 FALSE 的值。
if(!hWnd) return FALSE;
ShowWindow(hWnd, nCmdShow);&
// 显示窗口
UpdateWindow(hWnd);&&&&&&&&&
// 更新窗口
  好了,到这儿呢,我们就成功的创建了一个窗口。我们回头看我注了“**”的地方,关于这个函数,我们得写个同名函数来处理 Windows
的消息。呵呵,不好意思,再看一个函数:
BOOL bActive = FALSE;&&&&&&&
// 用于判断程序是否运行的变量
long PASCAL WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
switch(message)
case WM_ACTIVATE:
bActive = TRUE;&&&&&
// 当程序被激活时,赋值 TRUE
case WM_SETCURSOR:
SetCursor(NULL);&&&&
// 设定鼠标为不显示
return TRUE;
case WM_KEYDOWN:
switch(wParam)
case VK_ESCAPE:&&&&
&// 处理按下 ESC 键的反应
&&&&&&&&&&&
PostMessage(hWnd, WM_CLOSE, 0, 0);&&
// 发送一个关闭窗口的命令
&&&&&&&&&&&
case WM_DESTROY:&&&&&&&&
// 在窗口即将销毁时的反应
PostQuitMessage(0);&
// 发送一个结束的消息,必须的!
return DefWindowProc(hWnd, message, wParam, lParam);&
// 一些没有像上面一样具体定义的消息的处理
  这个函数就是用来处理 Windows 的消息的,是一个标准程序必要的。
  再来最后一个重要的函数。不好意思哦,实在是不想这么写,但是想想,在这个函数结束后,你就可以实现一个具体的窗口了哦:)
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR
lpCmdLine, int nCmdShow)
// 定义一个消息的对象
if(!Init(hInst, nCmdShow)) return FALSE;&&&&&&&&&&
// 还记得上面的那个函数吗?
// 程序的循环
if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
// 不要特别注意的
&&&&&&&&&&&
if(!GetMessage(&msg, NULL, 0, 0 ))
&&&&&&&&&&&
return msg.wP
&&&&&&&&&&&
TranslateMessage(&msg);
&&&&&&&&&&&
DispatchMessage(&msg);
else if(bActive)&&&&
// 就是上面的“程序是否激活”的变量判断
&&&&&&&&&&&
ShowThePic();&&&
// 显示人物图片的函数,上节的内容,就是整合在这儿的!
else WaitMessage();&
// 没有消息时,就等消息:)
  其实到这儿,一个简单的程序已经可以出炉了:)编译,运行,你将看到一个黑色的窗口。这个窗口不同于一般的窗口,它没有平常的标题栏,这个才是适合我们游戏的。我在这儿给出完整的代码,但是,无法将上节的内容以程序的形式表现出来,因为涉及到了
DirectDraw 。我不想过多在教程中涉及未讲的知识,因为那样会影响对现有知识的理解。
  下章教程,我将开始介绍 DirectDraw 了,以便能尽快将显示的内容整合,同时我会保持教程和代码的详尽。
  本范例在以下环境中通过:VC6.0、DirectX 7.0/8.1 SDK、Win2000/WinXP
  说明 []
  真的很高兴能够继续我们的教程。大家也一定等了许久了,怪我太懒。
  上次,我们讲到了窗口的建立,并且附带了源代码,不知道大家有没有编译和运行。不是当老师的唠叨哦,大家一定要试试的,因为电脑这个东西,尤其是编程,要不断地实践才能掌握的。
  今天,我们来点轻松的,不涉及代码,我们来一次“纸上谈兵”。我今天是要大家选择适合自己的游戏引擎。曾经有很多网友问我:“引擎
”到底是什么东西?我也回答过许多遍了,但是,我从没有嫌烦过,因为我也是这么过来的。之所以取名叫“引擎”,他就像汽车之类的
Automobile
一样,得有一个家伙驱使他工作。而游戏引擎呢,他就负责接受用户输入,交付自己的内部工作机构,处理,并最终以声音、图像等形式表现出来。
  现在大家在网络上可以看到、并且下载到许多免费的游戏引擎,其中有2D的,也有时下流行的3D。国内有许多网站也在制作各自的引擎,有个别的的确有很高的效率,而且使用很方便,比如
云风 的 “风魂游戏开发库”。这些引擎都是将我们今后会碰到的 DirectDraw、DirectInput、DirectPlay 等等
部件整合,封装,使其便于使用。像我其实自己也在使用别人的引擎来开发自己的游戏制作库,那么,你该选择怎么样的引擎呢?我觉得这个完全取决于你对游戏开发的耐心及专研。
  现在,DirectX 已经发展到了 9.0 ,而且,在 8.1
的开发库中,我们很高兴的看到,微软也已经封装了以前繁琐的步骤,因此,DirectX 8.1b
的开发库,不失为一个比较好的基层函数库。为什么说他还只是一个基层的呢?因为他还没有像著名的 CDX 那样有比较高级的效果封装在里头。CDX
是我比较喜欢的封装库,他不仅使用简便,而且可以实现使用频率比较高的功能,比如 Alpha
混合,虽然他不像其他的引擎来得功能强大,但是,他用于自己的研究和扩充是很好的,通过使用 CDX ,你对 DirectX
可以有个比较理性的认识。
  到这儿,大家应该发现了,我们以前公布的教程目录和今天的对不上号,因为我发现现在其实有好多网站都有关于 DirectDraw
编程的辅导,而且,资源丰富。我相信,大家通过好好的分析这些代码,然后,大量的实践,就会打造你比较坚固的 DirectDraw 编程的基础了。
  我们今后的教程往哪个方向走,我正在考虑,我也很想看到大家的好建议,作为一个游戏编程入门者,你最想看到怎么样的文章?哪怕是一个不明白的地方,都可以提出来,我可以做专题来给大家讲解一下。DirectDraw
方面的,专题在近期是不会出现了,还请大家见谅!
  最后,告诉大家一个可能算是比较好的消息,我们的教程游戏,还在更新和完善之中哦...
本站中所有文章以及图形均为作者本人、公司所有,本站所有资讯仅供参考,若有任何损失本站概不负责,请自行斟酌。
All Rights reserved.
This site is optimized for at least
resolution (hi-color) viewing
with a browser that supports style sheets.快速上手:制作第一个游戏
快速上手:制作第一个游戏
您正在阅读的手册文档包括了系统化的介绍 Cocos Creator 的编辑器界面、功能和工作流程,但如果您想快速上手体验使用 Cocos Creator 开发游戏的大体流程和方法,这一章将满足您的好奇心。完成本章教程之后,您应该能获得足够上手制作游戏的信息,不过我们还是推荐您继续阅读本手册来了解各个功能模块的细节和完整的工作流程。
接下来就让我们开始吧,跟随教程我们将会制作一款名叫摘星星的坑爹小游戏。这款游戏的玩家要操作一个反应迟钝却蹦跳不停的小怪物来碰触不断出现的星星,难以驾驭的加速度将给玩家带来很大挑战,和您的小伙伴比比谁能拿到更多星星吧!
可以在这里感受一下这款游戏的完成形态:
准备项目和资源
我们已经为您准备好了制作这款游戏需要的全部资源,下载初始项目后,解压到您希望的位置,之后我们就可以开始了:
您也可以下载最终完成的项目,跟随教程制作过程中有任何不明白的地方都可以打开完成版的项目作为参考:
打开初始项目
如果您还不了解如何获取和启动 Cocos Creator,请阅读一节。
我们首先启动 Cocos Creator,然后选择打开其他项目
在弹出的文件夹选择对话框中,选中我们刚下载并解压完成的 start_project,点击打开按钮
Cocos Creator 编辑器主窗口会打开,我们将看到如下的项目状态
检查游戏资源
我们的初始项目中已经包含了所有需要的游戏资源,因此您不需要再导入任何其他资源。如果希望了解导入资源的方法,可以阅读的相关内容。
下面我们先来了解一下项目中都有哪些资源,请关注名为资源管理器的面板,这里显示的是项目中的所有资源树状结构。
可以看到,项目资源的根目录名叫assets,对应我们解压之后初始项目中的 assets 目录,只有这个目录下的资源才会被 Cocos Creator 导入项目并进行管理。
资源管理器可以显示任意层次的目录结构,我们可以看到这样的图标就代表一个文件夹,点击文件夹左边的三角图标可以展开文件夹的内容。将文件夹全部展开后,资源管理器中就会呈现如下图的状态。
每个资源都是一个文件,导入项目后根据扩展名的不同而被识别为不同的资源类型,其图标也会有所区别,下面我们来看看项目中的资源各自的类型和作用:
声音文件,一般为 mp3 文件,我们将在主角跳跃和得分时播放名为jump和score的声音文件。
位图字体,由 fnt 文件和同名的 png 图片文件共同组成。位图字体(Bitmap Font)是一种游戏开发中常用的字体资源,详情请阅读
各式各样的缩略图标,这些都是图像资源,一般是 png 或 jpg 文件。图片文件导入项目后会经过简单的处理成为texture类型的资源。之后就可以将这些资源拖拽到场景或组件属性中去使用了。
创建游戏场景
在 Cocos Creator 中,游戏场景(Scene)是开发时组织游戏内容的中心,也是呈现给玩家所有游戏内容的载体。游戏场景中一般会包括以下内容:
场景图像和文字(Sprite,Label)
以组件形式附加在场景节点上的游戏逻辑脚本
当玩家运行游戏时,就会载入游戏场景,游戏场景加载后就会自动运行所包含组件的游戏脚本,实现各种各样开发者设置的逻辑功能。所以除了资源以外,游戏场景是一切内容创作的基础,让我们现在就新建一个场景。
在资源管理器中点击选中assets目录,确保我们的场景会被创建在这个目录下
点击资源管理器左上角的加号按钮,在弹出的菜单中选择Scene
我们创建了一个名叫New Scene的场景文件,右键点击它并选择重命名,将它改名为game。
双击game,就会在场景编辑器和层级编辑器中打开这个场景。
了解Canvas
打开场景后,层级管理器中会显示当前场景中的所有节点和他们的层级关系。我们刚刚新建的场景中只有一个名叫Canvas的节点,Canvas可以被称为画布节点或渲染根节点,点击选中Canvas,可以在属性检查器中看到他的属性。
这里的Design Resolution属性规定了游戏的设计分辨率,Fit Height和Fit Width规定了在不同尺寸的屏幕上运行时,我们将如何缩放Canvas以适配不同的分辨率。
由于提供了多分辨率适配的功能,我们一般会将场景中的所有负责图像显示的节点都放在Canvas下面。这样当Canvas的scale(缩放)属性改变时,所有作为其子节点的图像也会跟着一起缩放以适应不同屏幕的大小。
更详细的信息请阅读。目前我们只要知道接下来添加的场景图像都会放在Canvas节点下面就可以了。
设置场景图像
首先在资源管理器里按照assets/textures/background的路径找到我们的背景图像资源,点击并拖拽这个资源到层级编辑器中的Canvas节点上,直到Canvas节点显示橙色高亮,表示将会添加一个以background为贴图资源的子节点。
这时就可以松开鼠标按键,可以看到Canvas下面添加了一个名叫background的节点。当我们使用拖拽资源的方式添加节点时,节点会自动以贴图资源的文件名来命名。
我们在对场景进行编辑修改时,可以通过主菜单文件-&保存场景来及时保存我们的修改。也可以使用快捷键Ctrl+S(Windows)或Cmd + S(Mac)来保存。
修改背景尺寸
在 场景编辑器 中,可以看到我们刚刚添加的背景图像,下面我们将修改背景图像的尺寸,来让他覆盖整个屏幕。
首先选中background节点,然后点击主窗口左上角工具栏第四个 矩形变换工具:
使用这个工具我们可以方便的修改图像节点的尺寸,将鼠标移动到 场景编辑器 中 background 的左边,按住并向左拖拽直到 background 的左边超出表示设计分辨率的蓝色线框。然后再用同样的方法将 background 的右边向右拖拽。
之后需要拖拽上下两边,使背景图的大小能够填满设计分辨率的线框。
在使用 矩形变换工具 修改背景图尺寸时,可以在 属性检查器 中看到 Node (节点)中的 Size 属性也在随之变化,完成后我们的背景图尺寸大概是 ()。您也可以直接在 Size 属性的输入框中输入数值,和使用 矩形变换工具 可以达到同样效果。这样大小的背景图在市面流行的手机上都可以覆盖整个屏幕,不会出现穿帮情况。
我们的主角需要一个可以在上面跳跃的地面,我们马上来添加一个。用和添加背景图相同的方式,拖拽 资源管理器 中 assets/textures/ground 资源到 层级管理器 的 Canvas 上。这次在拖拽时我们还可以选择新添加的节点和 background 节点的顺序关系。拖拽资源的状态下移动鼠标指针到 background 节点的下方,直到在 Canvas 上显示橙色高亮框,并同时在 background 下方显示表示插入位置的绿色线条,然后松开鼠标,这样 ground 在场景层级中就被放在了 background 下方,同时也是 Canvas 的一个子节点。
在层级管理器中,显示在下方的节点的渲染顺序会在上方节点的后面,我们可以看到位于最下的ground物体在场景编辑器中显示在了最前。另外子节点也会永远显示在父节点之前,我们可以随时调整节点的层级顺序和关系来控制他们的显示顺序。
按照修改背景的方法,我们也可以使用矩形变换工具来为地面节点设置一个合适的大小。在激活矩形变换工具的时候,如果拖拽节点顶点和四边之外的部分,就可以更改节点的位置。下图是我们设置好的地面节点状态:
除了矩形变换工具之外,我们还可以使用移动工具来改变节点的位置。尝试按住移动工具显示在节点上的箭头并拖拽,就可以一次改变节点在单个坐标轴上的位置。
我们在设置背景和地面的位置和尺寸时不需要很精确的数值,可以凭感觉拖拽。如果您偏好比较完整的数字,也可以按照截图直接输入position和size的数值。
接下来我们的主角小怪兽要登场了,从资源管理器拖拽assets/texture/PurpleMonster到层级管理器中Canvas的下面,并确保他的位置在ground下面,这样我们的主角会显示在最前面。
为了让主角的光环在场景节点中非常醒目,我们右键点击刚刚添加的PurpleMonster节点,选择重命名之后将其改名为Player。
接下来我们要对主角的属性进行一些设置,首先是改变锚点(Anchor)的位置。默认状态下,任何节点的锚点都会在节点的中心,也就是说该节点中心点所在的位置就是该节点的位置。我们希望控制主角的底部的位置来模拟在地面上跳跃的效果,所以现在我们需要把主角的锚点设置在脚下。在属性检查器里找到Anchor属性,把其中的y值设为0,可以看到场景编辑器中,表示主角位置的移动工具的箭头出现在了主角脚下。
接下来场景编辑器中拖拽Player,把他放在地面上,效果如下图:
这样我们基本的场景美术内容就配置好了。下面一节我们要编写代码让游戏里的内容生动起来。
编写主角脚本
Cocos Creator 开发游戏的一个核心理念就是让内容生产和功能开发可以流畅的并行协作,我们在上个部分着重于处理美术内容,而接下来就是通过编写脚本来开发功能的流程,之后我们还会看到写好的程序脚本可以很容易的被内容生产者使用。
如果您从没写过程序也不用担心,我们会在教程中提供所有需要的代码,只要复制粘贴到正确的位置就可以了,之后这部分工作可以找您的程序员小伙伴来解决。下面让我们开始创建驱动主角行动的脚本吧。
首先在资源管理器中右键点击assets文件夹,选择新建-&文件夹
右键点击New Folder,选择重命名,将其改名为scripts,之后我们所有的脚本都会存放在这里。
右键点击scripts文件夹,选择新建-&JavaScript,创建一个JavaScript脚本
将新建脚本的名字改为Player。双击这个脚本,打开代码编辑器。
注意: Cocos Creator 中脚本名称就是组件的名称,这个命名是大小写敏感的!如果组件名称的大小写不正确,将无法正确通过名称使用组件!
编写组件属性
打开的脚本里已经有了预先设置好的一些代码块,这些代码就是编写一个组件脚本所需的结构。具有这样结构的脚本就是 Cocos Creator 中的组件(Component),他们能够挂载到场景中的节点上,提供控制节点的各种功能。我们先来设置一些属性,然后看看怎样在场景中调整他们。
在代码编辑器中找到Player脚本里 properties部分,将其改为以下内容并按Ctrl + S(Windows)或Cmd + S(Mac)保存:
properties: {
jumpHeight: 0,
jumpDuration: 0,
maxMoveSpeed: 0,
这些新增的属性将规定主角的移动方式,在代码中我们不需要关心这些数值是多少,因为我们之后会直接在属性检查器中设置这些数值。
现在我们可以把 Player 组件添加到主角节点上。在 层级编辑器 中选中 Player 节点,然后在 属性检查器 中点击 添加组件 按钮,选择 添加用户脚本组件-&Player,为主角节点添加 Player 组件。
现在我们可以在 属性检查器 中(需要选中 Player 节点)看到刚添加的 Player 组件了,按照下图将主角跳跃和移动的相关属性设置好:
这些数值除了 jumpDuration 的单位是秒之外,其他的数值都是以像素为单位的,根据我们现在对 Player 组件的设置:我们的主角将能够跳跃 200 像素的高度,起跳到最高点所需的时间是 0.3 秒,最大水平方向移动速度是 400 像素每秒,水平加速度是 350 像素每秒。
这些数值都是建议,一会等游戏运行起来,您完全可以按照自己的喜好随时在属性检查器中修改这些数值,不需要改动任何代码,很方便吧!
编写跳跃和移动代码
下面我们添加一个方法,来让主角跳跃起来,在 properties: {...},代码块的下面,添加叫做setJumpAction的方法:
properties: {
setJumpAction: function () {
var jumpUp = cc.moveBy(this.jumpDuration, cc.p(0, this.jumpHeight)).easing(cc.easeCubicActionOut());
var jumpDown = cc.moveBy(this.jumpDuration, cc.p(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());
return cc.repeatForever(cc.sequence(jumpUp, jumpDown));
},这里用到了一些 Cocos2d-js 引擎中的 Action 来实现主角的跳跃动画,详情可以查询.
接下来在onLoad方法里调用刚添加的setJumpAction方法,然后执行runAction来开始动作:
onLoad: function () {
this.jumpAction = this.setJumpAction();
this.node.runAction(this.jumpAction);
},onLoad方法会在场景加载后立刻执行,所以我们会把初始化相关的操作和逻辑都放在这里面。
保存脚本,然后我们就可以开始第一次运行游戏了!
点击 Cocos Creator 编辑器上方正中的预览游戏按钮,Cocos Creator 会自动打开您的默认浏览器并开始在里面运行游戏,现在应该可以看到我们的主角----紫色小怪兽在场景中间活泼的蹦个不停了。
只能在原地傻蹦的主角可没前途,让我们为主角添加键盘输入,用A和D来控制他的跳跃方向。在setJumpAction方法的下面添加setInputControl方法:
setJumpAction: function () {
setInputControl: function () {
var self = this;
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed: function(keyCode, event) {
switch(keyCode) {
case cc.KEY.a:
self.accLeft = true;
self.accRight = false;
case cc.KEY.d:
self.accLeft = false;
self.accRight = true;
onKeyReleased: function(keyCode, event) {
switch(keyCode) {
case cc.KEY.a:
self.accLeft = false;
case cc.KEY.d:
self.accRight = false;
}, self.node);
},然后修改onLoad方法,在其中加入向左和向右加速的开关,以及主角当前在水平方向的速度,最后再调用我们刚添加的setInputControl方法,在场景加载后就开始***键盘输入:
onLoad: function () {
this.jumpAction = this.setJumpAction();
this.node.runAction(this.jumpAction);
this.accLeft = false;
this.accRight = false;
this.xSpeed = 0;
this.setInputControl();
},最后修改update方法的内容,添加加速度、速度和主角当前位置的设置:
update: function (dt) {
if (this.accLeft) {
this.xSpeed -= this.accel *
} else if (this.accRight) {
this.xSpeed += this.accel *
if ( Math.abs(this.xSpeed) & this.maxMoveSpeed ) {
this.xSpeed = this.maxMoveSpeed * this.xSpeed / Math.abs(this.xSpeed);
this.node.x += this.xSpeed *
},update在场景加载后就会每帧调用一次,我们一般把需要经常计算或及时更新的逻辑内容放在这里。在我们的游戏中,根据键盘输入获得加速度方向后,就需要每帧在update中计算主角的速度和位置。
保存脚本后,下面就可以去泡杯茶,点击预览游戏来看看我们最新的成果。在浏览器打开预览后,用鼠标点击一下游戏画面(这是浏览器的限制,要点击游戏画面才能接受键盘输入),然后就可以按A和D键来控制主角左右移动了!
感觉移动起来有点迟缓?主角跳的不够高?希望跳跃时间长一些?没问题,这些都可以随时调整。只要为Player组件设置不同的属性值,就可以按照您的想法调整游戏。这里有一组设置可供参考:
Jump Height: 150
Jump Duration: 0.3
Max Move Speed: 400
Accel: 1000这组属性设置会让主角变得灵活无比,至于如何选择,就看您想做一个什么风格的游戏了。
主角现在可以跳来跳去了,我们要给玩家一个目标,也就是会不断出现在场景中的星星,玩家需要引导小怪兽碰触星星来收集分数。被主角碰到的星星会消失,然后马上在随机位置重新生成一个。
制作Prefab
对于需要重复生成的节点,我们可以将他保存成Prefab(预制)资源,作为我们动态生成节点时使用的模板。关于Prefab的更多信息,请阅读。
首先从资源管理器中拖拽assets/textures/star资源到场景中,位置随意,我们只是需要借助场景作为我们制作 Prefab 的工作台,制作完成后会我们把这个节点从场景中删除。
我们不需要修改星星的位置或渲染属性,但要让星星能够被主角碰触后消失,我们需要为星星也添加一个专门的组件。按照和添加Player脚本相同的方法,添加名叫Star的JavaScript脚本到assets/scripts/中。
接下来双击这个脚本开始编辑,星星组件只需要一个属性用来规定主角距离星星多近时就可以完成收集,修改properties,加入以下内容:
properties: {
pickRadius: 0
},保存脚本后,将这个脚本添加到刚创建的star节点上。然后在属性检查器中把Pick Radius属性值设为60:
Star Prefab 需要的设置就完成了,现在从层级管理器中将star节点拖拽到资源管理器中的assets文件夹下,就生成了名叫star的 Prefab 资源。
现在可以从场景中删除star节点了,我们会在脚本中动态使用星星的 Prefab 资源生成星星。
添加游戏控制脚本
星星的生成是游戏主逻辑的一部分,所以我们要添加一个叫做Game的脚本作为游戏主逻辑脚本,这个脚本之后还会添加计分、游戏失败和重新开始的相关逻辑。
添加Game脚本到assets/scripts文件夹下,双击打开脚本。首先添加生成星星需要的属性:
properties: {
starPrefab: {
default: null,
type: cc.Prefab
maxStarDuration: 0,
minStarDuration: 0,
default: null,
type: cc.Node
default: null,
type: cc.Node
},保存脚本后将Game组件添加到层级编辑器中的Canvas节点上(选中Canvas节点后,拖拽脚本到 属性检查器 上,或点击 属性检查器 的 添加组件 按钮,并从 用户自定义脚本 中选择 Game,接下来从资源管理器中拖拽star Prefab 资源到Game组件的Star Prefab属性中。这是我们第一次为属性设置引用,只有在属性声明时规定type为引用类型时(比如我们这里写的cc.Prefab类型),才能够将资源或节点拖拽到该属性上。
接下来从层级编辑器中拖拽ground和Player 节点到组件中相同名字的属性上,完成节点引用。
然后设置Min Star Duration和Max Star Duration属性的值为3和5,之后我们生成星星时,会在这两个之间随机取值,就是星星消失前经过的时间。
在随机位置生成星星
接下来我们继续修改Game脚本,在onLoad方法后面添加生成星星的逻辑:
onLoad: function () {
this.groundY = this.ground.y + this.ground.height/2;
this.spawnNewStar();
spawnNewStar: function() {
var newStar = cc.instantiate(this.starPrefab);
this.node.addChild(newStar);
newStar.setPosition(this.getNewStarPosition());
getNewStarPosition: function () {
var randX = 0;
var randY = this.groundY + cc.random0To1() * this.player.getComponent('Player').jumpHeight + 50;
var maxX = this.node.width/2;
randX = cc.randomMinus1To1() * maxX;
return cc.p(randX, randY);
}保存脚本以后点击预览游戏按钮,在浏览器中可以看到,游戏开始后动态生成了一颗星星!用同样的方法,您可以在游戏中动态生成任何预先设置好的以 Prefab 为模板的节点。
添加主角碰触收集星星的行为
现在要添加主角收集星星的行为逻辑了,这里的重点在于,星星要随时可以获得主角节点的位置,才能判断他们之间的距离是否小于可收集距离,如何获得主角节点的引用呢?别忘了我们前面做过的两件事:
Game组件中有个名叫player的属性,保存了主角节点的引用。
每个星星都是在Game脚本中动态生成的。
所以我们只要在Game脚本生成Star节点实例时,将Game组件的实例传入星星并保存起来就好了,之后我们可以随时通过game.player来访问到主角节点。让我们打开Game脚本,在spawnNewStar方法最后面添加这样一句:
spawnNewStar: function() {
newStar.getComponent('Star').game = this;
},保存后打开Star脚本,现在我们可以利用Game组件中引用的player节点来判断距离了,在onLoad方法后面添加名为getPlayerDistance和onPicked的方法:
getPlayerDistance: function () {
var playerPos = this.game.player.getPosition();
var dist = cc.pDistance(this.node.position, playerPos);
onPicked: function() {
this.game.spawnNewStar();
this.node.destroy();
},然后在update方法中添加每帧判断距离,如果距离小于pickRadius属性规定的收集距离,就执行收集行为:
update: function (dt) {
if (this.getPlayerDistance() & this.pickRadius) {
this.onPicked();
},保存脚本,然后再次预览测试,可以看到控制主角靠近星星时,星星就会消失掉,然后在随机位置生成了新的星星!
小怪兽辛辛苦苦的收集星星,没有奖励怎么行,让我们现在就在收集星星时添加得分奖励的逻辑和显示。
添加分数文字(Label)
游戏开始时得分从0开始,每收集一个星星分数就会加1。要显示得分,首先要创建一个 Label 节点。在层级管理器中选中Canvas节点,右键点击并选择菜单中的创建新节点-&创建渲染节点-&Label(文字),一个新的 Label 节点会被创建在Canvas下面,而且顺序在最下面。接下来我们要用如下的步骤配置这个 Label 节点:
将该节点名字改为score
将score节点的位置(position属性)设为(0, 180)。
选中该节点,编辑Label组件的string属性,填入Score: 0的文字。
将Label组件的Font Size属性设为50。
从资源管理器中拖拽assets/mikado_outline_shadow位图字体资源(注意图标是)到Label组件的Font属性中,将文字的字体替换成我们项目资源中的位图字体。
完成后效果如下图所示:
在 Game 脚本中添加得分逻辑
我们将会把计分和更新分数显示的逻辑放在Game脚本里,打开Game脚本开始编辑,首先在properties区块的最后添加分数显示 Label 的引用属性:
properties: {
scoreDisplay: {
default: null,
type: cc.Label
},接下来在onLoad方法里添加计分用的变量的初始化:
onLoad: function () {
this.score = 0;
},然后在update方法后面添加名叫gainScore的新方法:
gainScore: function () {
this.score += 1;
this.scoreDisplay.string = 'Score: ' + this.score.toString();
},保存 Game 脚本后,回到 层级管理器,选中 Canvas 节点,然后把前面添加好的 score 节点拖拽到 属性检查器 里 Game 组件的 Score Display 属性中。
在 Star 脚本中调用 Game 中的得分逻辑
下面打开Star脚本,在onPicked方法中加入gainScore的调用:
onPicked: function() {
this.game.spawnNewStar();
this.game.gainScore();
this.node.destroy();
},保存后预览,可以看到现在收集星星时屏幕正上方显示的分数会增加了!
失败判定和重新开始
现在我们的游戏已经初具规模,但得分再多,不可能失败的游戏也不会给人成就感。现在让我们加入星星定时消失的行为,而且让星星消失时就判定为游戏失败。也就是说,玩家需要在每颗星星消失之前完成收集,并不断重复这个过程完成玩法的循环。
为星星加入计时消失的逻辑
打开Game脚本,在onLoad方法的spawnNewStar调用之前加入计时需要的变量声明:
onLoad: function () {
this.timer = 0;
this.starDuration = 0;
this.spawnNewStar();
this.score = 0;
},然后在spawnNewStar方法最后加入重置计时器的逻辑,其中this.minStarDuration和this.maxStarDuration是我们一开始声明的Game组件属性,用来规定星星消失时间的随机范围:
spawnNewStar: function() {
this.starDuration = this.minStarDuration + cc.random0To1() * (this.maxStarDuration - this.minStarDuration);
this.timer = 0;
},在update方法中加入计时器更新和判断超过时限的逻辑:
update: function (dt) {
if (this.timer & this.starDuration) {
this.gameOver();
this.timer +=
},最后加入gameOver方法,游戏失败时重新加载场景。
gameOver: function () {
this.player.stopAllActions();
cc.director.loadScene('game');
}对Game脚本的修改就完成了,保存脚本,然后打开Star脚本,我们需要为即将消失的星星加入简单的视觉提示效果,在update方法最后加入以下代码:
update: function() {
var opacityRatio = 1 - this.game.timer/this.game.starD
var minOpacity = 50;
this.node.opacity = minOpacity + Math.floor(opacityRatio * (255 - minOpacity));
}保存Star脚本,我们的游戏玩法逻辑就全部完成了!现在点击预览游戏按钮,我们在浏览器看到的就是一个有核心玩法、激励机制、失败机制的合格游戏了。
尽管很多人玩手游的时候会无视声音,我们为了教程展示的工作流程尽量完整,还是要补全加入音效的任务。
首先加入跳跃音效,打开Player脚本,添加引用声音文件资源的jumpAudio属性:
properties: {
jumpAudio: {
default: null,
url: cc.AudioClip
},然后改写setJumpAction方法,插入播放音效的回调,并通过添加playJumpSound方法来播放声音:
setJumpAction: function () {
var jumpUp = cc.moveBy(this.jumpDuration, cc.p(0, this.jumpHeight)).easing(cc.easeCubicActionOut());
var jumpDown = cc.moveBy(this.jumpDuration, cc.p(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());
var callback = cc.callFunc(this.playJumpSound, this);
return cc.repeatForever(cc.sequence(jumpUp, jumpDown, callback));
playJumpSound: function () {
cc.audioEngine.playEffect(this.jumpAudio, false);
},得分音效
保存Player脚本以后打开Game脚本,来添加得分音效,首先仍然是在properties中添加一个属性来引用声音文件资源:
properties: {
scoreAudio: {
default: null,
url: cc.AudioClip
},然后在gainScore方法里插入播放声音的代码:
gainScore: function () {
this.score += 1;
this.scoreDisplay.string = 'Score: ' + this.score.toString();
cc.audioEngine.playEffect(this.scoreAudio, false);
},保存脚本,回到层级编辑器,选中Player节点,然后从资源管理器里拖拽assets/audio/jump资源到Player组件的Jump Audio属性上。
然后选中Canvas节点,把assets/audio/score资源拖拽到Game组件的Score Audio属性上。
这样就大功告成了!完成形态的场景层级和各个关键组件的属性如下:
现在我们可以尽情享受刚制作完成的游戏了,您能打到多少分呢?别忘了您可以随时修改Player和Game组件里的移动控制和星星持续时间等游戏参数,来快速调节游戏的难度。修改组件属性之后需要保存场景,修改后的数值才会被记录下来。
恭喜您完成了用 Cocos Creator 制作的第一个游戏!希望这篇快速入门教程能帮助您了解 Cocos Creator 游戏开发流程中的基本概念和工作流程。如果您对编写和学习脚本编程不感兴趣,也可以直接从完成版的项目中把写好的脚本复制过来使用。
接下来您还可以继续完善游戏的各方各面,以下是一些推荐的改进方向:
加入简单的开始菜单界面,在游戏运行的一开始显示开始按钮,点击按钮后才会开始游戏
为游戏失败加入简单的菜单界面,游戏失败后点击按钮才会重新开始
限制主角的移动不能超过视窗边界
为主角的跳跃动作加入更细腻的动画表现
为星星消失的状态加入计时进度条
收集星星时加入更华丽的效果
为触屏设备加入输入控制
以上这些方向都得到改善的游戏版本可以下载 来参考和学习,这里就不再赘述了。
此外如果希望将完成的游戏发布到服务器上分享给好友玩耍,可以阅读一节的内容。
今天的教程就到这里了,您可以立刻开始制作您的第二款 Cocos Creator 游戏,或者继续阅读本手册。关于本快速开始教程的任何问题,都可以在提交反馈。
说明文档。
沪ICP备号-5

参考资料

 

随机推荐