Pulse 图形界面框架 pulse图形界面框架提供了常用的图形界面和控件,如:登陆界面,房间管理界面,聊天界面,朋友关系界面,角色信息界面等等这个教程教您如何开始制作 自己的多人在线flash游戏! 本教程是基于一款经典的回合制游戏Tic-Tac-Toe 开发环境需求 ? Windows 操作系统 ? JRE ? Flash / Flex3 development environment / FlashDevelop (http://www.flashdevelop.org) ? 免费 Pulse 开发,可以从这下载(注册可见下载板块) [url=http://pulse.gamatra.com/]http://pulse.gamatr a.com[/url] 或者 [url=http://72.167.250.161/]http://72.167.250.161 [/url] ? 在这个开发包中,有一个完整的清单,包含了SDK,代码和资源等 编程基础 如果您已经进行过flash开发和AS3编程,那就足够啦!当然如果您熟悉面向对象方式的编程那就更好了! 开始 首先请您下载免费的Pulse 开发包并且安装它开发包中包括了… ? Pulse 服务器 ? 诸多范例程序 (含完整源代码和资源) ? Pulse Game 图像界面框架 (含代码和美术资源) 来吧,先启动Pulse服务器! 首先从安装目录或者开始菜单运行Pulse服务器 图A01:从开始菜单开始运行Pulse Server 图A02:从安装目录开始运行 Pulse Server 导入SWC组件 首先您需要在您的开发环境(Flash / Flex3 development environment / FlashDevelop)中导入开发包中的SWC组件 在安装目录下的“lib”目录中,我们提供了四个SWC文件: pulse.swc ,pulseUI.swc是针对FLEX Builder 的组件您可以新建自己的项目,并在项目属性的“Library Path”中导入我们的SWC文件 pulse_cs3.swc,pulseUI_cs3.swc是供Flash CS 使用的组件您可以将 SWC 文件复制到 Configuration/Components 目录中,然后重启Flash CS ,从组件面板中便可以看到pulse和pulseUI组件,便能使用了 运行游戏范例 范例目录(samples目录)有三个范例:HelloWorld, jigsaw, tictactoe 在此选择tictactoe做为本教程的游戏 从范例目录(samples 目录)开始运行游戏范例请注意在免费服务器版本中,您暂时只能在同一时间内运行一个游戏如果您想切换不同的游戏范例,需要关闭前面一个游戏的所有客户端程序它的出现让您花更多的时间在游戏编码和设计上,不用浪费时间在这些美术资源的上对于开发新的多人在线游戏这是不错的方式 在下载包中有所有这些图形资源;当然,如果你想更换风格或者美术资源,可以随时更换,非常方便 开始开发游戏 首先您需要考虑的是:如何设计游戏状态(game states),因为它将被一个游戏房间中的所有玩家共用 为游戏建模 对于tic tac toe游戏,你需要向其他玩家发送玩家动作(player action)信息,这意味着,客户端需要发送x和y 位置信息. 知道哪些信息是我们必需的之后,接下来我们来建造一个简单的xml文件,这个文件就是负责定义游戏中所需的游戏状态(game state) 它分为两个小步骤: 1. 建造xml文件 2. 按照你建造的xml文件,使用安装目录下的PulseCodeGen.bat(图A02中第一个文件),自动生成AS3代码 您可以在安装目录中找到,而且您可以参考整个目录,如图:图A03 图A03:tictactoe完成目录结构,请参考 以下是xml文件内容,文件名我们命名为:tictactoeSchema.xml <ObjectSchema> <import> <client import="pulse.gsrc.client.*" /> </import> <class name="Put" parent="GameState" classId="601" > <public> <property index="0" name="PutRow" count="1" type="int"/> <property index="1" name="PutColumn" count="1" type="int"/> <property index="2" name="PutValue" count="1" type="int"/> </public> </class> </ObjectSchema> 在这个schema 文件中,我们所需要的东西很简单――想要和其他玩家的动作进行通讯玩家选择一个位置点(行,列来表示)和值,在tic tac toe中就是画一个“X”或者画一个“O”,它的值由游戏开始时谁先创建了这个房间(游戏房间)的那个人(房间主)所决定 在完成了游戏状态(game states)设计之后,我们需要通过PulseCodeGen.bat工具运行以上xml文件以下是我们需要的一个批处理文件(名为:init.bat,您可以在图A03中找到),它用以将PulseCodeGen和tictactoeSchema.xml关联,并运行 IF EXIST .\src\tictactoe\gsrc\client del .\src\tictactoe\gsrc\client\*.as CALL "%GAMANTRA%"\bin\PulseCodeGen.bat .\tictactoeSchema.xml tictactoe.gsrc .\src\tictactoe\gsrc IF NOT %ERRORLEVEL% == 0 GOTO ERROR ECHO Success! GOTO END :ERROR ECHO oops! :END Pause 运行: init.bat 就可以了 如果您想改变schema文件,那么只需重新运行以上批处理文件(init.bat),就可以迅速生成最新的AS3代码 开始写代码 一旦您有了生成的AS3代码,你需要从以下四个类继承,也就是说生成以下四个类的子类: 先让我们预览下子类 TictactoeGame 这是游戏的主类,你的游戏代码从这个类开始在这个类中,你也可以告诉PulseUI包中哪些类被重写(over-ridden)了例如,以下三个类就重写(over-ridden)了PulseUI 中的三个类(pulseui.Skinner, pulseui. NewGameScreen, pulseui. GameScreen) 您可以在范例目录中找到它们,以便参考 TictactoeSkinner 你需要生成Skinner类的子类,这样就能读取图像文件(skin),这些图像文件通常被用于画所有的屏幕图形界面 TictactoeNewGameScreen 是否生成这个类的子类是可选的对于tic tac toe游戏来说,我们需要告诉pulse 服务器一些关于游戏房间的特定属性,比如:这个游戏是回合制的,每个房间允许最多或者最少有几个玩家等等信息 TictactoeGameScreen 最后,本类定义了游戏进行时,游戏房间中的所有行为 子类细节 TictactoeGame 这是游戏的主类,游戏代码由此开始 重写构造函数: public function TictactoeGame() { new TictactoeSkinner(); } 构造函数是初始游戏特定的skinner类(它基本功能就是显示外壳,有点像Winamp的Skins,可以随便换外观模板)的好地方关于skinner类我们将在稍后讨论 重写 PulseGame的getGameId方法: public override function getGameId():String { return "Tictactoe"; } 由于Pulse服务器程序可以同时运行多个游戏,所以每个游戏需要一个唯一的游戏id(game id),比如:正在玩Tictactoe的玩家不能同时去玩另一个Jigsaw游戏 重写start方法: import tictactoe.gsrc.client.GNetClientObjectFactory; … protected override function start():void { var factory:GNetClientObjectFactory; factory = new GNetClientObjectFactory(); m_netClient = new GameClient(factory, this); s_instance = this; super.start(); } Start 方法是是程序开始点正如代码中所示,一个工厂对象(factory object)必需首先创建这个工厂类(GNetClientObjectFactory)是由前面的PulseCodeGen 生成的所以不用担心怎么写它的代码 : p 接着,创建一个Game Client对象,它的第一个参数就是前面创建的工厂对象(facetory)m_netClient 是在 PulseGame中定义的在这里,你只需要将值赋给m_netClient,不用担心其他的变化 整个游戏中只需要一个GameClinet实例最后,通过调用super.start() ,在一个闪屏特效之后,玩家就进入了登陆屏幕 程序到达这里,玩家面前就呈现出登陆屏幕玩家可以选择注册新帐号或者以匿名身份登陆进入游戏大厅 创建自定义类: protected override function initGameScreen():void { m_gameScreen = new TictactoeGameScreen(this); m_gameScreen.init(); } protected override function initNewGameScreen():void { m_newGameScreen = new TictactoeNewGameScreen(); m_newGameScreen.init(); } 以上两个重写的方法用来创建游戏特点的屏幕,前者用来创建新的游戏房间界面,后者是在游戏玩(game play)的期间 回合制: 由于tictacoe是一个典型的回合制游戏(它的设置请查看:TictactoeNewGameScreen类),Pulse 服务器 会发出一个回调(callback)到客户端,以让客户端知道现在轮到它的回合了,而与此同时,一个显著的标记会出现在客户端上,给玩家一个明显的告知 public override function onPlayerTurn():void { (m_gameScreen as TictactoeGameScreen).onPlayerTurn(); } 让游戏屏幕(game screen)显示这个告知也是一个非常简单的范例,供参考 与服务器通讯: public override function onGameStateAction(gameState:GameStateClient):void{ (m_gameScreen as TictactoeGameScreen).onPlayerMoved(gameState); } public function sendGameState(xPos:int,yPos:int,value:int):void { var putMsg:PutClient = new PutClient(); putMsg.setStateType(GameConstants.GS_IS_UNIQUE); putMsg.setPutRow(xPos); putMsg.setPutColumn(yPos); putMsg.setPutValue(value); m_netClient.sendGameStateAction(putMsg); m_netClient.nextTurn(); } 以上两个方法需要被实现,前者用来接受别的玩家发送的动作信息(action);而后者则用来通知其他玩家自己做了哪些动作 TictactoeSkinner 你需要子类化skinner(就是指:自己定义Skinner的子类),这样就可以读取图像文件(skin),这些将用于画屏幕的图形界面 public class TictactoeSkinner extends Skinner { [Embed(source="tictactoe\\rsrc\\Outline.png")] private static var OutlineClass:Class; [Embed(source="tictactoe\\rsrc\\ui.png")] private static var UIClass:Class; [Embed(source="tictactoe\\rsrc\\frame.png")] private static var FrameClass:Class; public function TictactoeSkinner() { } protected override function load():void { m_outline = (new OutlineClass() as BitmapAsset).bitmapData; m_ui = (new UIClass() as BitmapAsset).bitmapData; m_frame = (new FrameClass() as BitmapAsset).bitmapData; } } 定制Skinner非常简单,以上便是一个完整的代码清单Load 方法被重写以创建outline, ui和frame 的BtimapAsset这些protected属性的变量在Skinner类中定义Skinner对象将负责除了图片等资源的裁剪,生成工件等操作(开发者不用了解它细节,这样可以省些时间,多喝些咖啡,多打打WAR III) TictactoeNewGameScreen 这个子类化是可选的,然后对于tic tac toe 游戏来说,我们需要告诉服务器一些房间的特定属性,比如:采用回合制,每房间容纳多少玩家等等 public override function createNewRoom():void { PulseGame.getInstance().setCreatingRoom(); var room:GameRoomClient = new GameRoomClient(); room.setRoomName(m_ti.text); room.setMaxPlayerCount(2); room.setRoomType(GameConstants.ROOM_TURN_BASED); PulseGame.getInstance().getGameClient().createGame Room(room); } 这里的tictactoe new game screen 仅用来定义房间类型以上是 tic tac toe游戏所特有的,其他游戏不一定要弄这个类代码设置了房间名称(由玩家健入),每房间仅2个人,并且告诉服务器是回合制类型 Pulse的行为方式是基于这些参数的,您可以查阅《Pulse 开发者手册》和《API 指南》或者直接给我们发Email, Email:FAQ@gamantra.com ,以获取更详细的使用方法和更多设置 TictactoeGameScreen 最后,一旦游戏开始,所有的房间内的操作将由这个类决定 游戏代码由另外两个类实现,在这我们没有列出,完全是游戏逻辑的设定,不复杂,您可以直接下载Pulse开发包,浏览范例(samples)目录中的tic tac toe 代码这两个类是: TictactoeHotspot, 是Sprite的子类,主要用于跟踪游戏面板上的9个区域,以及根据玩家操作确定是否增child (”O” 或者”X”) TictactoeGameStatus TictactoeGameStatus, 一个简单的类,主要用于定义一些常量 重写的Init 方法中用来初始 hotspot 区域等操作,游戏客户端仅执行一次这些代码不详细说明了 初始化游戏屏幕(Game Screen): 以上init 方法仅仅被调用一次,然而,玩家进出房间(game screen)许多此 每一次玩家进入房间,show 方法被调用;玩家离开房间的时候,hide 方法被调用 public override function show():void { super.show(); } 对于tictactoe游戏,在 游戏开始前,show 方法里,我们选择不在屏幕中画所有的东西,而是等待super. show() 调用GameScreen类中的show方法GameScreen 类显示“go”或者“wait”sprite房主创建房间的时候自动生成了room creator ,PulseUI 将按照时候有其他玩家进入房间来显示“开始”或者“等待” 如果没有特殊的操作,你可以忽略这个重写(override) 当房间主点击“开始(go)”图标时,startGame被调用m_putValue被初始化以确定“O”或者“X”哪一个被显示 public override function startGame():void { super.startGame(); if ( PulseGame.getInstance().getGameClient().isGameHost () ) { m_putValue = 1; } else { m_putValue = -1; } addChild(m_borderSprite); for each (var hotspotArray:Array in m_hotspotArray) { for each (var hotspot:TictactoeHotspot in hotspotArray) { m_borderSprite.addChild(hotspot); } } m_isGaming = true; } 父类的实现移除了“go”或者“wait”标识游戏面板开始初始化 在以下hide 方法中,我们确定是否移除了所有与游戏屏幕(game screen)有关的所有sprite public override function hide():void { if (m_showingTurn) { removeChild(m_turnSprite); } if(m_borderSprite.numChildren > 0) { for each (var hotspotArray:Array in m_hotspotArray) { for each (var hotspot:TictactoeHotspot in hotspotArray) { if(hotspot.numChildren > 0) hotspot.removeChildAt(0); m_borderSprite.removeChild(hotspot); } } } if ( m_isGaming ) { finishRound(); removeChild(m_borderSprite); } m_isGaming = false; super.hide(); } 当玩家选择退出游戏游戏屏幕(game screen)时,lobbyHit 方法被调用通常游戏就结束了对于一些情况,一个玩家退出后另一个玩家仍然在这个房间中,应此只要一个玩家退出了,我们就把玩家带回游戏大厅你可以选择任何实现方式 protected override function lobbyHit():void { //Host send finish game and non-host sent enterlobby if ( m_isGaming == true ) m_tictactoeGame.getGameClient().finishGame(); super.lobbyHit(); } 因为我们已经看到屏幕管理,所以现在开始看怎样玩游戏的部分… 显示玩家回合: public function onPlayerTurn():void { // show the turn indicator m_showingTurn = true; addChild(m_turnSprite); } PulseGame对象调用这个方法当服务器声明轮到某个玩家的回合时,我们显示“Your Trun”给那个玩家 让玩家产生移动: private function playAction(event:MouseEvent):void { var gc:GameClient = PulseGame.getInstance().getGameClient(); if (gc.isMyTurn() == true) { var selectedSprite:TictactoeHotspot; selectedSprite = event.target as TictactoeHotspot; if ( selectedSprite == null ) return; var xPos:int = selectedSprite.col; var yPos:int = selectedSprite.row; if(m_hotspotArray[xPos][yPos].value == 0) { m_tictactoeGame.sendGameState(xPos, yPos, m_putValue); m_showingTurn = false; removeChild(m_turnSprite); } } } 我们处理鼠标点击,并进行一些检查首先检查是否轮到该玩家,然后我们检查点击是否有效,如果检查都没问题,我们发送玩家动作信息到服务器,服务器将在下一合中把游戏状态(game state)发送给玩家自己和其他玩家 当客户端收到玩家动作信息后,TictactoeGame(前面介绍过)对象调用以下方法,这里这个方法简单地更新了屏幕以及检查游戏是否有输赢 public function onPlayerMoved(gameState:GameStateClient):void { var putMsg:PutClient = gameState as PutClient; showSprite(putMsg.getPutRow(), putMsg.getPutColumn(), putMsg.getPutValue()); checkGameEnd(); } 这是一个典型的回合制多人游戏范例,希望大家好运!开发更多精彩的多人在线flash游戏 为了接收另一个玩家的动作,在这里,我们就简单地重写了(override)onGameStateAc tion方法,并且将它传递给游戏屏幕(game screen) 为了发送玩家动作信息,我们写了一个方便的方法sendGameState,它由游戏屏幕对象(game screen object)调用在这个时候,我们也告诉服务器:这个回合已经结束了这样服务器好通知下一个玩家:轮到他的回合了注意:PutClient是在前面的xml schema文件中定义的,并且在code gen期间自动生成 如果想了解关于游戏状态(game states)类型的更多信息,可以直接下载参看《Pulse 开发者手册》 转自:http://bbs.mhhf.net/showtopic-379064.html 很抱歉,因为您在网易相册发布了违规信息,账号被屏蔽被屏蔽期间他人无法访问您的相册 去帮助中心,了解如何重新恢复服务 (责任编辑:admin) |