在之前的二节中,我做出一个基本的游戏精灵--一条红色的飞行的小飞龙,但是在进行下一步开发前,我觉得有必要对现有的代码进行封装!在这一节中,我将封装一些基本的方法,并演示如何在JS中实现继承!

首先了解下什么叫立即调用的函数:

(function(){//你的代码})();

  顾名思义,即函数定义完后会立即调用或执行自己,在这里,它相当于

function 函数名(){//你的代码;}

函数名();

  封装在里面的代码,外部是无法访问的,这样能确保不会因为外面的同名变量而产生不可预料的异常!然后可以通过一个全局变量来访问相关内容!网上一些JS库都是这种方式封装的,包括jQuery!在这里我们建一个立即调用函数并将上一节用到的几个方法,封装进去,然后通过一个全局变量window.j2d来访问里面的方法!

(function(window){var j2d={//canves context对象    Context:undefined,//坐标    Point:function(x,y){if(isNaN(x)){            x=0;        }if(isNaN(y)){            y=0;        }return {"X":x,"Y":y};    },//每秒帧数    FPS:10,//精灵容器    Containet:new Array(),//八个方向    Directions:{        North:0,        NorthEast:1,        East:2,        SouthEast:3,        South:4,        SouthWest:5,        West:6,        NorthWest:7    },//获取两点之间距离    GetDistance:function(x,y) {return Math.sqrt(Math.pow((x.X - y.X), 2) + Math.pow((x.Y - y.Y), 2));    },

//计算当前坐标与目标点之间的正切值以获取朝向    GetDirection:function(current,target){//...略    },

//是否到达指定坐标

    RatherPoint:function(direction,p1,p2){//...略    }//};window.j2d=j2d;})(window);

封装好后,我们可以直接通用j2d来调用相关方法了!不过在这里要先改进一下计算移动步长GetMovePoint这个方法,上一节中没有细致考虑导致方法过于冗余!在这里改进调整下!

如果精灵是横向或者纵向移动,每次移动步长直接是当前移动速度即可,如果是斜向移动,则需要计算目标点的长度,并根据对应的比例获取x坐标长度与y坐标长度!

根据勾股定理:两条直角边的长度的平方之和等于斜边的平方,则得出获取两个坐标点的距离为Math.sqrt(Math.pow((point2.X - point1.X), 2) + Math.pow((point2.Y - point1.Y), 2));

因为同号两数相乘得正数,异号两数相乘得负数,所以这里得出的结果永远是正数!再根据 斜边/长(高) = 速度/x步长(y步长) (两者比例一致的,斜边上的移动步长即为当前速度)就能得出对应的x轴移动步长或者y轴移动步长了!优化后方法如下(方法名调整为GetMoveStep):

GetMoveStep:function(point1,point2,speed){var length = j2d.GetDistance(point1,point2);var p = j2d.Point(0,0);if(length==0){return p;    }    p.X= (point2.X - point1.X) * speed / length;    p.Y= (point2.Y - point1.Y) * speed / length;return p;}

  下面我将实现精灵对象的基类封装,每个精灵都有一个Draw方法,用来绘制精灵对象,一个Update方法,用来实现相关逻辑处理

    ObjectEntity:function(){this.DrawObject=undefined;//绘制对象        this.ID=undefined;//编号        this.Name=undefined;//名字        this.Offset={"X":0,"Y":0};//偏移量        this.Containet=new Array();//子对象集合        this.Width=0;//宽        this.Height=0;//高        this.Direction=0;//朝向        this.DrawPoint={"X":0,"Y":0};//绘制起始坐标        this.Coordinate={"X":0,"Y":0};//当前所在坐标        this.Draw=function(){if(j2d.Context&&this.DrawObject){var point = this.Coordinate;var w = this.Width;var h = this.Height;                j2d.Context.drawImage(this.DrawObject,//绘制对象                                      parseInt(this.DrawPoint.X),//                                      parseInt(this.DrawPoint.Y),//                                      parseInt(w),//裁剪尺寸                                      parseInt(h),//裁剪的尺寸                                      parseInt(point.X-this.Offset.X),//                                      parseInt(point.Y-this.Offset.Y),                                      parseInt(w),//绘制大小。                                      parseInt(h) //绘制大小。                                 );for(var n=0;n<this.Containet.length;n++){//执行子集合里面的Draw方法                    if(this.Containet[n]&&this.Containet[n].Draw){this.Containet[n].Draw(gameTime);                    }                }            }        }    }

  然后,我们再定义一个地图对象,继承自ObjectEntity,其实javascript中并不存在类,继承等东西,但是我们可以通过一些方法来实现继承等功能,实现继承有多种方法,这里使用call来实现(其它还有原型继承等,更多请自行搜索了解)!

Map:function(){        j2d.ObjectEntity.call(this);this.Update=function(gameTime){for(var n=0;n<this.Containet.length;n++){if(this.Containet[n]){if(this.Containet[n].Update){this.Containet[n].Update(gameTime);                    }                }            }        };    }

  Map里面只新增一个Update方法,遍历子集合里面的所有对象并运行其Update方法(注:随着后面更多的功能增加,会有更多的方法增减,但是目前为了方便理解与突出重点,用不到的方法暂时不放出来)

  OK,地图定义完了,再定义一个Sprite类,在之前的演示中,我们的精灵只有一个动行,即飞行,但是这远远不够的,可能我还要有站立,行走,攻击,死亡,打坐,受伤,施法...等很多动作,在这里我不想把这些动作写死,我打算在实际开发中动态添加,在这里我定义一个AddAnimation方法,来用添加动作动画,再定义一个SetAnimation,来设置当前动作。但是精灵的基本图片要求不变,即每个方向为一行!其实在一般的游戏中,精灵图片一般都是单张单张分开的,但是为了减少HTTP请求,我将所有图片都拼合到一张图片里面了,加载的时候慢点,但是不需要频繁的去请求,智者见智,仁者见仁,如果不想一次加载的,可以自己更改相关方法,但是原理还是一致的!

 

    Sprite:function(){        j2d.ObjectEntity.call(this);this.Speed=100;//速度        var action="",//当前动作        list,//动作列表        index=0,//当前动作的帧索引        timeStep=0;//距上次更新时的时间步长        this.AddAnimation=function(key,value){if(!list){                list=new Object();            }            list[key]=value;return true;        };

this.SetAnimation=function(key){if(action!=key){                index=0;                action=key;                timeStep=3600000;//这里将时间设为一个较大的数值是为了切换动作后能马上更换图片            }        };

this.Update=function(gameTime){if(action&&action!=""&&list[action]){                timeStep+=gameTime;if(timeStep>=list[action].Interval){//是否达到每帧的切换时间                    timeStep=0;this.DrawPoint=j2d.Point(list[action].Frames[index]*this.Width,this.Direction*this.Height);if(list[action].Callback){                        list[action].Callback(index,action);                    }if(index>=list[action].Frames.length-1){                        index=0;                    }else{                        index++;                    }                }            }

for(var n=0;n<this.Containet.length;n++){if(this.Containet[n]){if(this.Containet[n].Update){this.Containet[n].Update(gameTime);                    }                }            }        };    }

  实现了封装后,下面的开发中我们将大大简化相关代码,在下面,我将再次实现一个会行走的精灵,这次我不再打算用上次的小龙了,必竟这是老外们的龙,咱们中国人,当然要用中国元素,所以我决定用一个小美女,嗯,现在美女大家都喜欢,不是吗,特别对于代码老是报“找不到对象”的错误的同学们来说!

  先展示一下我们要用到的精灵素材(这里只有部分,全图放在下载文件中,站立10帧,行走10帧,8个方向,计160张图片拼合而成,说实话,处理图片真是一个很麻烦的过程!原图可都是一张一张零散的图片)

  同时,这里我也将加入地图元素,不再像上一节中精灵只能在无尽的白色背景中行走了!实现代码:

j2d.Context=document.getElementById("scene").getContext("2d");

//为Sprite添加一个RunTo方法,用来控制行走j2d.Sprite.prototype.RunTo=function(point,Callback){    clearInterval(this.runTimer);var speed=parseFloat(this.Speed/1000)*(1000/j2d.FPS);//point = arguments[0];    var me = this;

var moveStep = j2d.GetMoveStep(this.Coordinate,point,this.Speed);

    me.runTimer=setInterval(function(){var x = parseInt(me.Coordinate.X+moveStep.X),        y=parseInt(me.Coordinate.Y+moveStep.Y);if(x<0||x>(j2d.Context.canvas.width-me.Offset.X)||y<0||y>(j2d.Context.canvas.height - me.Offset.Y)||j2d.RatherPoint(me.Direction,me.Coordinate,point)){//碰撞检测与判断是否到达目标点            clearInterval(me.runTimer);if(Callback){                Callback(me);            };        }else{            me.Coordinate.X=x;            me.Coordinate.Y=y;        }    },1000/j2d.FPS)};

var map,hero;var mapImg = new Image();mapImg.οnlοad=function(){    map = new j2d.Map();//地图    map.DrawObject=mapImg;    map.Width = mapImg.width;    map.Height=mapImg.height;var heroImg = new Image();    heroImg.οnlοad=function(){        hero = new j2d.Sprite();//美女        hero.DrawObject=heroImg;        hero.Width = 70;        hero.Height=200;        hero.Speed=5;//移动速度        hero.Offset = j2d.Point(35,160);        hero.Coordinate = j2d.Point(400,350);//所处位置        hero.AddAnimation("Stand",{//添加动作-站立            Interval:10,            Frames:[0,1,2,3,4,5,6,7,8,9]        });        hero.AddAnimation("Walk",{//添加动作 - 行走            Interval:10,            Frames:[10,11,12,13,14,15,16,17,18,19]        });        hero.SetAnimation("Stand");//设置当前动作为-站立        map.Containet.push(hero);        j2d.Containet.push(map);

        j2d.Context.canvas.οnclick=function(){//点击事件            var point = j2d.GetMousePoint();//获取点击坐标            hero.Direction=j2d.GetDirection(hero.Coordinate,point);//设置朝向            hero.SetAnimation("Walk");//设置行走动画            hero.RunTo(point,function(){//开始行走                hero.SetAnimation("Stand");//到达目标点的回调方法:此处为改变动作为站立            });        };

        j2d.Run();//开始执行

    };    heroImg.src="Data/Sprite/1.png";};mapImg.src = "Data/Map/1.gif";

  好,我们来运行一下结果吧:

  冰山上一个漂亮的美女正在孤独的行走,慢慢前行...,冰山上的美女,简称冰女,要是石头上的美女,简称...咳咳,我什么都没有说啊...

  今天本节到此为止,开发已经渐入佳境了,不过,还有很多功能没有出来,比如地图没有障碍,人物没有阴影,2.5D效果处理,地图切换,怪物,技能等,不过别急,请关注本人的Html5 Game开始系列文章,让我们一起走近html5,感受html5的魅力,享受html5之神奇之旅...

作者:翅膀的初衷
    QQ:4585839
    总目录:点击进入
    本章代码下载:点击下载
    本系列效果演示:http://www.iis0.com/html5

  这篇文章是旧历2011年的最后一篇文章了,过两天要回家过年了,下面的更新将在节后回来继续。如果代码与文章中存在不足之处,欢迎大家指点(本代码在IE9,火狐(中国版)9.01中测试通过)!

  本文(包括本系列其它文章)为原创作品,如有转载请保留作者信息与出处,其中涉及到的图片,来源于网络,仅供学习研究目的使用,请勿用于其它用途,否则由此产生的任何后果均与本人无关!

转载于:https://www.cnblogs.com/hnvvv/archive/2012/01/18/2326025.html

html5 Game开发系列文章之 三 搭建基本游戏框架(代码封装)相关推荐

  1. html5 Game开发系列文章之 二 精灵(下)

    昨天在家装了IE9,感觉不错,界面终于清爽了,跑HTML5也还不错!期待IE10正式版! 上一节我简单了介绍了HTML5 canvas 中的 drawImage方法,并绘制了一条扇动翅膀的小红龙,那么 ...

  2. 音视频开发系列(12):音频录制的代码封装

    这节课分享一下如何对基于qt的音频推流的代码进行封装,首先先说明一下封装的目的,主要是为了以后如何有多种方案可以进行使用时,只需要在该封装的类上提供新的接口即可.本次封装的类的基类为XAudioRec ...

  3. Windows Mobile 开发系列文章收藏 - Windows Mobile 6.x

    收集整理一些Windows Mobile 6.x开发相关文章, 文章及相关代码大部分搜集自网络,版权属于原作者! 智能手机      手机词汇      研发手机基本流程 WAP协议分析(1)     ...

  4. Jerry Wang的微信公众号开发系列文章

    微信程序开发系列教程(一)开发环境搭建 微信程序开发系列教程(二)使用JavaScript给微信用户发送消息 微信程序开发系列教程(二)微信订阅号+人工智能问答服务 微信程序开发系列教程(三)使用微信 ...

  5. [转载]C# WinForm开发系列 - 文章索引

    该系列主要整理收集在使用C#开发WinForm应用文章及相关代码, 平时看到大家主要使用C#来开发Asp.Net应用,这方面的文章也特别多,而关于WinForm的文章相对少很多,而自己对WinForm ...

  6. Android蓝牙开发系列文章-蓝牙设备类型知多少?

    在写<Android蓝牙开发系列文章-蓝牙音箱连接>时,计划细化出一篇讲解蓝牙设备类型的文章,现在它来了~ 阅读其他内容,可以点击<Android蓝牙开发系列文章-策划篇>,或 ...

  7. ZYNQ开发系列——ZYNQ系统的搭建

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 ZYNQ开发系列--ZYNQ系统的搭建 DDR设置 FLASH设置 UART设置 网口设置 当我们有一个要用ZYNQ做的项目时,首先当 ...

  8. AARCH64 开发系列1: AARCH64 环境搭建

    首发极术社区 作者:Zhiyuan zhu 如对Arm相关技术感兴趣,欢迎私信aijishu20加入技术微信群. 概述 近年来 Arm 服务器的发展势头很猛,但大部分人的个人电脑还是 x86 环境,开 ...

  9. STM32 cubemx 开发系列文章(一)认识cubemx

    STM32 cubemx 开发系列文章 新建一个cubemx工程 1.下载stm32 cubemx软件 2.安装软件 3.配置软件 4.开始第一个Hello World工程配置 写在最后 新建一个cu ...

最新文章

  1. Windows Phone开发(41):漫谈关键帧动画之下篇
  2. constraint的一些用法总结
  3. 互联网1分钟 | 1015
  4. java 引用队列_Java中管理资源的引用队列相关原理解析
  5. 优秀!史学博士在Science杂志发表一篇学术评论
  6. SpringCloud 从菜鸟到大牛之五 统一配置中心 Spring Cloud Config
  7. (组合数学笔记)格点路径问题分析求解
  8. 大数据可视化的方法和价值
  9. 网络工程设计教程--系统集成方法
  10. 现代操作系统 第三章 内存管理 习题答案
  11. 阮一峰ES6入门读书笔记(九):Set 和 Map
  12. 全自动共享软件破解器4.8
  13. 关于计算机方面英语ppt模板,经典ppt模板--计算机软件.ppt
  14. scum服务器里找不到车,人渣SCUM车辆机制介绍 人渣SCUM车辆为什么消失
  15. 2毫秒c51汇编语言延时函数,单片机精确毫秒延时函数
  16. web前端高级必备面试资料
  17. 关于SQLの大题练习
  18. 【Navicat】连接Oracle报错 ORA-12505
  19. iphone的shsh备份实用方法
  20. oracle 数据类型的变更无效 clob,ORA-22858:数据类型的变更无效varchar2类型转换为clob类型...

热门文章

  1. web攻击有哪些方式?小白需要知道的几种攻击方式
  2. 免费开源漏洞扫描工具+商业级
  3. ZZULIOJ:1051: 平方根的和
  4. c++第八周【任务2】实现Time类中的运算符重载
  5. 数据库的应用(一):建库、建表、录数据最基础操作
  6. mysql 5.7 tokudb_percona 5.7 + tokudb
  7. oledb mysql_oledb方式连接mysql5 ado连接MySQL[未验证]
  8. idea远程连接工具使用
  9. 华硕笔记本,wifi图标不见,连不上网的解决方法
  10. java iterable 使用_Iterable(迭代器)的用法