Home >php教程 >php手册 >网页游戏开发入门教程三(简单程序应用)

网页游戏开发入门教程三(简单程序应用)

WBOY
WBOYOriginal
2016-06-13 12:20:281162browse

网页游戏开发入门教程二(游戏模式+系统)
http://www.jb51.net/article/20724.htm

一、选择开发语言
后台:java .net php
前台:flex javascript ajax
数据库:mysql mssql
用哪种组合,真的不重要。重要的是时间和成本。复杂的地方在数据的交互和完善,而不在技术或效果的实现。往往遇到一些问题。比如地图如何编?人物移动如何实现?其实这些问题从技术上实现都比较容易。难在实现后,数据如何交互。没有解决数据交互的问题,实现这些技术点的意义不大。我用的是php+javascript+mysql。
原因:简单,上手快。可以比较快速的出产品。
二、程序简单应用。
、模板
为了方便UI的修改。所以用模板。smart template还算方便。很简单。代码也可以嵌套在模板里。唯一的问题是如果美术不会程序,修改模板还得程序来。不科学啊。
smart template的教程网上有。只说一点。可以在模板(.html的文件)里用嵌套任何代码。获得传值。用$_obj[‘xxx']或者用$_stack[0][‘']可以和{xxx}写法的代码嵌套。跟.php的文件一样,没任何区别。
、地图
因为游戏类型不是ogame模式的,所以地图并不是自动生成。而是全从数据库里调用。思路很简单。地图是一整张大图。切成多个小图块。数据库里记录下每个小图块对应大图的绝对坐标。显示的时候,调用相应坐标区域的小图块。
代码类似:
$sql="select * from map where mapx between $xxx and $xxx and mapy between $ yyy and $yyy ";
意思就是从地图表里,获得横坐标xx到xx。纵坐标xx到xx的所有小图块。比如20个。假设我们写个函数showMap(x,y),把获得的数据全显示出来。地图可以有很多层。
每个小图块都是一个div。具体的控制就用css就行了。小图块可以当作div的背景。也可以用作div里的图片。控制好div的left和top就行了。(left和top就是小图块相对于大图块的绝对坐标)showMap(x,y)就放在下面两个层的里面。
一个层处理地图大小:


一个层处理拖动:

复制代码 代码如下:



//处理拖动的js代码。(网上抄的。。感谢这位大大。)
<script> <BR>function fDragging(obj, e, limit){ <BR>if(!e) e=window.event; <BR>var x=parseInt(obj.style.left); <BR>var y=parseInt(obj.style.top); <BR>var x_=e.clientX-x; <BR>var y_=e.clientY-y; <BR>if(document.addEventListener){ <BR>document.addEventListener('mousemove', inFmove, true); <BR>document.addEventListener('mouseup', inFup, true); <BR>document.body.style.cursor="move"; <BR>} else if(document.attachEvent){ <BR>document.attachEvent('onmousemove', inFmove); <BR>document.attachEvent('onmouseup', inFup); <BR>document.body.style.cursor="move"; <BR>} <BR>inFstop(e); <BR>inFabort(e) <BR>function inFmove(e){ <BR>var evt; <BR>if(!e)e=window.event; <BR>if(limit){ <BR>var op=obj.parentNode; <BR>var opX=parseInt(op.style.left); <BR>var opY=parseInt(op.style.top); <BR>if((e.clientX-x_)<0) return false; <BR>else if((e.clientX-x_+obj.offsetWidth+opX)>(opX+op.offsetWidth)) return false; <BR>if(e.clientY-y_<0) return false; <BR>else if((e.clientY-y_+obj.offsetHeight+opY)>(opY+op.offsetHeight)) return false; <BR>//status=e.clientY-y_; <BR>} <BR>obj.style.left=e.clientX-x_+'px'; <BR>obj.style.top=e.clientY-y_+'px'; <BR>inFstop(e); <BR>} // shawl.qiu script <BR>function inFup(e){ <BR>var evt; <BR>if(!e)e=window.event; <BR>if(document.removeEventListener){ <BR>document.removeEventListener('mousemove', inFmove, true); <BR>document.removeEventListener('mouseup', inFup, true); <BR>} else if(document.detachEvent){ <BR>document.detachEvent('onmousemove', inFmove); <BR>document.detachEvent('onmouseup', inFup); <BR>} <BR>inFstop(e); <BR>document.body.style.cursor="auto"; <BR>//实现类似google地图的拖动效果。 <BR>ajaxRead('map.php?mapx='+(e.clientX-x_)+'&mapy='+(e.clientY-y_)+'','2'); <BR>} // shawl.qiu script <BR>function inFstop(e){ <BR>if(e.stopPropagation) return e.stopPropagation(); <BR>else return e.cancelBubble=true; <BR>} // shawl.qiu script <BR>function inFabort(e){ <BR>if(e.preventDefault) return e.preventDefault(); <BR>else return e.returnValue=false; <BR>} // shawl.qiu script <BR>} <BR>//]]> <BR></script>

注意下面这段代码:
ajaxRead('map.php?mapx='+(e.clientX-x_)+'&mapy='+(e.clientY-y_)+'','2');
这句代码的位置,是在拖动层后,释放鼠标的时候触发的。你可以用alert(“地图拖动到了这里”); 替换。测试下效果。这句代码的意思是,根据当前地图被拖动的坐标。调用一个ajax。也就是重新从数据库里获得地图信息。AjaxRead()是一个ajax的调用函数。你可以全部自己写。也可以用如prototype.js之类的框架写。
//处理ajax的代码。(还是网上抄的,有轻微的改动。。。唉,怎么老抄呢。。主要是为了节约开发时间。。还有一点就是我的JavaScript很垃圾的(*^__^*) 嘻嘻)

复制代码 代码如下:


function ajaxRead(file,action)
{
var xmlObj = null;
if(window.XMLHttpRequest)
{
xmlObj = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
return;
}
function ajaxDo(action)
{
switch(action)
{
case "2":
document.getElementById('display').innerHTML = xmlObj.responseText;//这里的display是你在页面上层的id。上面的地图代码都需要放到这个层里。如

写id和name,是为了方便firefox和ie的兼容。
break;
}
}
xmlObj.onreadystatechange = function()
{
/*
if(xmlObj.readyState == 1 )//loading状态。
{
document.getElementById('xianshi2').innerHTML = "正在载入";
}
*/
if(xmlObj.readyState == 4)//完成状态时。
{
ajaxDo(action);
}
}
xmlObj.open ('GET', file, true);
//xmlObj.reload('GET', file, true);
xmlObj.send (null);
//xmlObj.abort ('');
}

整个代码的意思就是:
当拖动地图释放鼠标后,显示层重新获得数据。并无刷新的显示出来。地图里的图片都用的png32的透明图。Ie7和ff3都没问题。遇到ie6的话。。用gif的替代吧。map.php的功能。根据获得的x,y显示相应的一谢谢小图块。这个功能其实就是上面说的showMap(x,y),这个很像google地图的拖动。不过简单了很多。简单,效果还不错。2、角2、角色属性
因为设定的要求。角色需要有装备加成,有状态加成(buff,debuff)。这时候,把所有需要的加成,都放到角色类里。是一个很好的方法。
大概像这样:

复制代码 代码如下:


class role
{
//获得角色数据。
getRloe()
{
从数据库里获得角色信息。
}
//获得装备加成。
getEquip()
{
获得装备加成信息。
}
//获得状态加成
getState()
{
获得状态加成信息。
}
//把上面获得的信息相加或者相减,或者调整。
//返回角色数据。
Return xxx
}


专门把这条提出来说。是因为没把加成放到角色对象里时。每次要战斗或者要干点什么的时候。获得角色数据后,还要加一大堆代码处理加成。重复太多。一让代码前置,世界就清静了。。。
、道具
道具比较特殊。因为种类繁多,使用方式多,可能有多个存放地点,可能有唯一道具。有天看了web魔兽的代码。发现他的道具只有一个表。有一个字段,来处理道具位置,如(1,拍卖行,2,背包,3,仓库,4,商店)这个办法挺好的。不过,如果道具的复杂度上去了。比如不同的仓库,不同的拍卖行,需要合成等等。还是只有分表。
基础道具表:
id
itemname 名称
itemprice 价格
itemimage 图片
itemtype 类型
uptype 增加类型
uppoint 增加点数
addtype 增加类型(永久)
addpoint 增加点数(永久)
cleardebuff 清除debuff
addbuff 增加buff
从uptype开始。都可以写成xx|yy|zz的形式。最好一一对应。分割符号可以自己选。
调用和处理数据的时候,可以用类似下面的方式:

复制代码 代码如下:


$uptype = explode("|", $iteminfo['uptype']);
$uppoint = explode("|", $iteminfo['uppoint']);
for ($j=0;$j{
echo $uptype[$j];
echo $uppoint[$j];
}


仓库,拍卖行,商店,背包等等。承载道具的地方。只要有个id字段来存道具id就可以。至于是横表或者是纵表,根据实际需要选择。目前为止,道具看上去处理得还不错。这时候,策划说。道具需要有唯一的,需要能附魔。ok,那么你把所有组合都填到道具表里吧。合成也就是a+b=c而已。。一计算。比如40个可能附魔的东西。200个可以附魔的道具。40*200=8000。显然,策划不会同意的。那么头痛的就是程序了。怎么处理呢。加表吧。
唯一道具表:
id 唯一道具id(与普通道具id不能重复。方便背包等等调用)
temp_id 临时id(默认0。合成道具的时候可能会用到。)
itemid 原始道具id(获得道具的初始值)
fumo_id 附魔id。(默认0,即无附魔)
附魔表:(即增加的属性)
id
uptype 增加类型
uppoint 增加点数
cleardebuff 清除debuff
addbuff 增加buff
现在看功能修改
首先是道具类:
class Item
{
getItem()
{
//以前是直接根据id获得道具信息就ok了。
//现在增加了附魔
//首先判断道具id是否属于唯一道具。(比如普通道具1-10000。唯一道具id的从10001开始。如果觉得这样不好,那么基础道具表里,加个字段。判断道具是否唯一)
if (道具唯一)
{
//从唯一道具表获得原始道具id和附魔id
//根据原始道具id,或者道具基础信息。
//根据附魔id,获得附魔加成信息。
//两边值相加。
Return 道具信息。
}
else
{
直接获得道具信息。
}
}
}
附魔功能:
道具A。(基础道具)+道具B。(基础道具) =道具C。(唯一道具)
也就是唯一道具是在附魔功能执行的时候生成。以背包举例。没附魔前。
背包内道具A。id为1。
背包内道具B。id为2。
当执行附魔功能后。道具A,道具B的id都置0(横表),或者删除了(纵表)。生成一个唯一数。temp_id。(md5生成就行了。)生成一个唯一道具。这时候,根据temp_id,让A的背包再次获得唯一道具的id。道具,比较完善的解决了。
以下部分均涉及到一些商业问题,所以只能给思路,及很少的代码。
--------------------------------------------------------------------------------
、记时器
处理等待xx时间后,执行xx的问题。php自带一个sleep()函数。等待时间也可以控制。
但是显然,不管从运用还是效率上讲。都不足以支持游戏计时的。思路很简单。将需要倒计时的事件的所有参数,以及开始时间、结束时间。都存储到一个表里。前台用javascript倒计时,时间到后,通过ajax调用时间到后的处理程序。后台每隔一定时间,自动执行一次调用时间到后的处理程序。
至少需要三个php页面。
一个用来写存取定时的内容。
一个处理前台时间到时,结束操作。
一个处理后台定时刷新,判断时间到了就执行结束,时间未到不作处理。
miracle:计时器是不同的计时器对应不同的事件,还是可以多个事件都调用同一个计时器,如果一个玩家他调用了一个计时器计时一个建筑建设多长时间,在之中又调用了这个计时器用来计时另一个建筑建设多长时间,这样行不行的?会不会有冲突?
键盘上的烟灰:
多个事件对应1个计时器。
你可以在timer里增加一个字段。比如叫做actiontype(事件类型)
每个用户可以同时处理多件事。只是每个事情都有固定编号。
比如你的用户允许同时做5件事情。那么actiontype里直接编号为1-5。调用计时器的时候,根据不同的编号,你就知道这是用户的第某个“线程”。
miracle
如果是不同的用户,调用同一个计时器是不会发生冲突的吧
键盘上的烟灰:
当然不会。你看。userid可以用来确定某一个用户。actiontype可以用来确定是第几个线程。
、事件控制
结合记时器,处理开始(),过程(),结束()

复制代码 代码如下:


interface Action
{
function doAction();
function beginAction();
function processAction();
function endAction();
}
//简单事件工厂
class ActionFactory
{
public function getAction($what)
{
$ActionName = $what;
return new $ActionName;
}
}
//比如移动
class Move implements Action
{
function doAction()
{
具体执行函数
什么时候该这行哪一个过程。都在这里判断。
}
function beginAction()
{
事件开始时候执行。
这里可以把数据存到记时器里。以后就从记时器里取数据了。
}
function processAction()
{
从记时器里取数据。
事件执行的过程。比如用户刷新页面的时候。如果仍然在倒计时。那么就是调用这里了。
}
function endAction()
{
从记时器里取数据。
事件结束的过程。
记时到后,完成事件。
}
}
//第一次调用的时候。
$Action = new ActionFactory();
$InstanceAction = $Action->getAction("Move");
$InstanceAction->set ($parameter);
$InstanceAction->doAction();
//以后调用的时候。
$Action = new ActionFactory();
$InstanceAction = $Action->getAction("Move");
//这时候,事件的参数或数据都从记时器里取得。
$InstanceAction->doAction();


、战斗
即时和半即时的回合战斗(两人或多人即时回合制战斗)比较繁琐。
至少包含:
前台:
自动接收邀请信息。Ajax
显示战斗过程。Ajax
回合倒计时间。javascript
后台:
发送邀请,接受,拒绝,超时。一个表。战斗数据。一个表。保存双方或多方的数据,包括回合时间,第几回合等。
战斗控制。一系列函数。处理玩家的操作,将操作存到战斗数据表里。时间到后执行操作。
出兵后,直接返回战报。
写在事件里就行了。
function endAction()
{
从记时器里取数据。
生成回合,生成战报。
}
注:由于本人工作原因,此系列可能要暂停一段时间才更新,望大家见谅。。。
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:php遍历目录viewDir函数Next article:PHP 基本语法格式