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


Posted in PHP onNovember 02, 2009

网页游戏开发入门教程二(游戏模式+系统)
https://3water.com/article/20724.htm

一、选择开发语言
后台:java .net php
前台:flex javascript ajax
数据库:mysql mssql
用哪种组合,真的不重要。重要的是时间和成本。复杂的地方在数据的交互和完善,而不在技术或效果的实现。往往遇到一些问题。比如地图如何编?人物移动如何实现?其实这些问题从技术上实现都比较容易。难在实现后,数据如何交互。没有解决数据交互的问题,实现这些技术点的意义不大。我用的是php+javascript+mysql。
原因:简单,上手快。可以比较快速的出产品。
二、程序简单应用。
、模板
为了方便UI的修改。所以用模板。smart template还算方便。很简单。代码也可以嵌套在模板里。唯一的问题是如果美术不会程序,修改模板还得程序来。不科学啊。
smart template的教程网上有。只说一点。可以在模板(.html的文件)里用<?php ?>嵌套任何代码。获得传值。用$_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)就放在下面两个层的里面。
一个层处理地图大小:
<div style=\"position:relative;width:".$mapwidth."px;height:".$mapheight."px;overflow:hidden\" >
一个层处理拖动:

<div style=\"position:absolute;z-index:10;left:2px;top:2px;width:".$mapwidth."px;height:".$mapheight."px;\" onmousedown=\"fDragging(this, event,false);\"> 
//处理拖动的js代码。(网上抄的。。感谢这位大大。) 
<script> 
function fDragging(obj, e, limit){ 
if(!e) e=window.event; 
var x=parseInt(obj.style.left); 
var y=parseInt(obj.style.top); 
var x_=e.clientX-x; 
var y_=e.clientY-y; 
if(document.addEventListener){ 
document.addEventListener('mousemove', inFmove, true); 
document.addEventListener('mouseup', inFup, true); 
document.body.style.cursor="move"; 
} else if(document.attachEvent){ 
document.attachEvent('onmousemove', inFmove); 
document.attachEvent('onmouseup', inFup); 
document.body.style.cursor="move"; 
} 
inFstop(e); 
inFabort(e) 
function inFmove(e){ 
var evt; 
if(!e)e=window.event; 
if(limit){ 
var op=obj.parentNode; 
var opX=parseInt(op.style.left); 
var opY=parseInt(op.style.top); 
if((e.clientX-x_)<0) return false; 
else if((e.clientX-x_+obj.offsetWidth+opX)>(opX+op.offsetWidth)) return false; 
if(e.clientY-y_<0) return false; 
else if((e.clientY-y_+obj.offsetHeight+opY)>(opY+op.offsetHeight)) return false; 
//status=e.clientY-y_; 
} 
obj.style.left=e.clientX-x_+'px'; 
obj.style.top=e.clientY-y_+'px'; 
inFstop(e); 
} // shawl.qiu script 
function inFup(e){ 
var evt; 
if(!e)e=window.event; 
if(document.removeEventListener){ 
document.removeEventListener('mousemove', inFmove, true); 
document.removeEventListener('mouseup', inFup, true); 
} else if(document.detachEvent){ 
document.detachEvent('onmousemove', inFmove); 
document.detachEvent('onmouseup', inFup); 
} 
inFstop(e); 
document.body.style.cursor="auto"; 
//实现类似google地图的拖动效果。 
ajaxRead('map.php?mapx='+(e.clientX-x_)+'&mapy='+(e.clientY-y_)+'','2'); 
} // shawl.qiu script 
function inFstop(e){ 
if(e.stopPropagation) return e.stopPropagation(); 
else return e.cancelBubble=true; 
} // shawl.qiu script 
function inFabort(e){ 
if(e.preventDefault) return e.preventDefault(); 
else return e.returnValue=false; 
} // shawl.qiu script 
} 
//]]> 
</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。上面的地图代码都需要放到这个层里。如<div id=display name=display></div>写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<count($uptype);$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()
{
从记时器里取数据。
生成回合,生成战报。
}
注:由于本人工作原因,此系列可能要暂停一段时间才更新,望大家见谅。。。
PHP 相关文章推荐
将RTF格式的文件转成HTML并在网页中显示的代码
Oct 09 PHP
配置Apache2.2+PHP5+CakePHP1.2+MySQL5运行环境
Apr 25 PHP
PHP XML备份Mysql数据库
May 27 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(九)
Jun 24 PHP
在win系统安装配置 Memcached for PHP 5.3 图文教程
Mar 03 PHP
PHP中实现crontab代码分享
Mar 26 PHP
PHP中生成UUID自定义函数分享
Jun 10 PHP
24条货真价实的PHP代码优化技巧
Jul 28 PHP
js基于qrcode.js生成二维码的方法【附demo插件源码下载】
Dec 28 PHP
PHP实现UTF8二进制及明文字符串的转化功能示例
Nov 20 PHP
PHP实现QQ登录的开原理和实现过程
Feb 04 PHP
PHP面向对象程序设计继承用法简单示例
Dec 28 PHP
网页游戏开发入门教程二(游戏模式+系统)
Nov 02 #PHP
初学CAKEPHP 基础教程
Nov 02 #PHP
PHP+MySQL 制作简单的留言本
Nov 02 #PHP
PHP+XML 制作简单的留言本 图文教程
Nov 02 #PHP
php 调用远程url的六种方法小结
Nov 02 #PHP
PHP 程序员应该使用的10个组件
Oct 31 #PHP
基于HTTP长连接的&quot;服务器推&quot;技术的php 简易聊天室
Oct 31 #PHP
You might like
隐性调用php程序的方法
2009/03/09 PHP
PHP实现对数组分页处理实例详解
2017/02/07 PHP
PHP中mysqli_get_server_version()的实例用法
2020/02/03 PHP
PHP Web表单生成器案例分析
2020/06/02 PHP
驱动事件的addEvent.js代码
2007/03/27 Javascript
js 蒙版进度条(结合图片)
2010/03/10 Javascript
基于jquery的cookie的用法
2011/01/10 Javascript
javascript 快速排序函数代码
2012/05/30 Javascript
Javascript根据指定下标或对象删除数组元素
2012/12/21 Javascript
js判断是否按下了Shift键的方法
2015/01/27 Javascript
使用jQuery实现更改默认alert框体
2015/04/13 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
Ext JS动态加载JavaScript创建窗体的方法
2016/06/23 Javascript
AngularJS基础 ng-keyup 指令简单示例
2016/08/02 Javascript
微信JSAPI Ticket接口签名详解
2020/06/28 Javascript
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
JavaScript学习笔记之惰性函数示例详解
2017/08/27 Javascript
分析JS单线程异步io回调的特性
2017/12/01 Javascript
详解vue-router 初始化时做了什么
2018/06/11 Javascript
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
2018/10/09 Javascript
JS/HTML5游戏常用算法之追踪算法实例详解
2018/12/12 Javascript
Vue 开发必须知道的36个技巧(小结)
2019/10/09 Javascript
jquery实现商品sku多属性选择功能(商品详情页)
2019/12/20 jQuery
基于javascript canvas实现五子棋游戏
2020/07/08 Javascript
Python常用随机数与随机字符串方法实例
2015/04/09 Python
Python编程之变量赋值操作实例分析
2017/07/24 Python
Python中常用信号signal类型实例
2018/01/25 Python
python中kmeans聚类实现代码
2018/02/23 Python
python使用Matplotlib画条形图
2020/03/25 Python
详解python读取image
2019/04/03 Python
python使用HTMLTestRunner导出饼图分析报告的方法
2019/12/30 Python
MADE荷兰:提供原创设计师家具
2018/04/03 全球购物
2019史上最全Database工程师题库
2015/12/06 面试题
歌颂祖国的演讲稿
2014/05/04 职场文书
董事长助理岗位职责
2015/02/11 职场文书
增值税发票丢失证明
2015/06/19 职场文书