轻轻松松学习JavaScript


Posted in Javascript onFebruary 25, 2007

JavaScript 的历史虽短,但却发展迅速。最初NetScape开发了LiveScript语言,使得它的Navigator和Web 服务器产品有了基本的脚本编写功能。当 Navigator 2.0中加入了Java小程序后,NetScape才把LiveScript变成了JavaScript,至此JavaScript诞生。  

本文将以一个有趣的小程序为开端,介绍JavaScript的基本语法与功能。此趣味程序为小球碰撞仿真程序,它可仿真弹性碰撞和动能有损的不完全恢复碰撞。你若想了解此例程中的球间碰撞处理程序,需熟悉矢量的坐标旋转和一些基本的物理学知识。如果你对此一窍不通,也没什么关系,因为对于小球之间的碰撞程序仅为几个函数,你只管调用就是了,这并不影响我们对JavaScript 的学习。之所以要写这样一个带点旁门左道的趣味例程,只是希望你对JavaScript多增加一分兴趣。  

废话就不多说,现在开始吧。  

第一步:材料的准备  

制作两张小球图片,红球 、蓝球 各一张。图片格式为 GIF。你可先用3D软件制作出立体球图片,然后再将其转为GIF格式,这样程序动画会显得更加逼真。需注意的是图片背景一定要透明,不然就会让人看出破绽。最后还需一张背景图,图片格式同上。  

第二步:编写主页骨架  

1. 在NetObject ScriptBuilder 中用New 命令生成一个HTML文件的骨架。顺便在新生成的HTML文件中,将TITLE标志之间的文字改为"小球碰撞仿真演示程序"。  

2. 加入背景图案和小球图片资源。  
将BODY标志改为,此语句中的background 属性指定window.gif 为背景图案。  

为加载小球图片资源,在标志与间添加以下两句  

 

这两句HTML脚本的含义完全相同,标志IMG用于加入图片资源,其中SRC属性指明加入的图片文件名。ID属性指出图片的对象名称,这是个重要属性,因为以后在JavaScript 编程中要使用它。如第一句中,指明BallBlue为图片资源的对象名称(你可以把它想象成变量名)。STYLE属性指明图片在浏览器中的风格,其中"position" 开关设为"absolute",这样图片在窗口中的定位就可使用绝对坐标模式,而非文本行模式。  

HTML 部分的编写到此完成。接下来该用JavaScript 让图片动起来了。  

第三步:编写JavaScript 程序  

1.仿真程序使用窗口对象的SetTimeout()方法循环调用Move_Step()函数,达到移动图片的目的,而Move_Step()根据速度矢量来计算移动一步的长度和方向。碰撞处理分为两部分,第一是球对墙壁的碰撞处理,其处理函数为Ball_Crash_Wall(),第二是球体之间的碰撞处理,其处理函数为Ball_Crash_Ball()。还需设置一些碰撞标志变量,记录当前碰撞状态,以避免仿真误差带来的错误,也许现在你还不明白为什么误差会导致错误,不要紧,后面会慢慢告诉你。  

2.图片对象使用属性 style.pixelLeft、style.pixelTop 指定图片在窗口上的位  
置,这两个属性是图片运动的关键。不过在计算图片移动位置时并不用它,而是用数组变量BallCoord 记录图片当前坐标位置,因为属性 style.pixelLeft、style.pixelTop 是整型变量,而在计算碰撞中有小数生成,这样如果直接用 style.pixelLeft、style.pixelTop 记录位置,除了有误差,最重要的是在窗口边缘发生某些类型的球间碰撞时,会产生小球被撞出屏幕的错误。而数组变量可为浮点型,用于存放小数,从而避免了错误的发生。  

(一)变量定义与程序的初始化  

JavaScript 语句可放在HTML文件的主体(BODY区)中或文件头(HEAD区)中,区别是HEAD 区一般摆放预制好的函数和全局变量,以供BODY区的语句调用,而BODY区一般放入程序初始语句。JavsScript 的变量定义比较自由,但仍需满足先定义后使用的基本规则。  

1.在HEAD区中定义全局变量:  
Window_Top = 22 //窗口顶端位置。  
Window_Left = 22 //窗口左端位置。  
Window_Bottom = 294 //窗口底端位置。  
Window_Right = 590 //窗口右端位置。  
Setp_Proportion = 3.00 //速度放大比率。  

BallCoord = new Array(new Array(2),new Array(2)) //定义一个二维数组,用于记录两球的当前坐标。  

BallDiametre = new Array(66,92) //定义一维数组,存放两球的直径,其值分别为66和92。  

BallMoveVector = new Array(new Array(2,1),new Array(1,-2))//定义一个二维数组,用于记录两球的速度向量,第二维分别存放X与Y轴的速度。  

CrashingWall = new Array(new Array(false,false,false,false),new Array(false,false,false,false))//数组 CrashingWall 用于避免墙壁碰撞的二次计算,值为 true ,表明当前处于碰撞状态。初值为 false。  

2.在BODY区中完成程序的初始工作。其内容如下:  

这里你已经看见了一个JavaScript 程序的框架。标志SCRIPT 告诉浏览器,下面的内容为脚本程序,用LANGUAGE="JavaScript" 指明程序语言为JavaScript。不管是在BODY区,还是HEAD区中,任何JavaScript程序必须放在 标志之间。程序中用 new Array() 定义了一个数组Balls,以便以后存放图片对象。接下来的语句Balls[0] = BallBlue 将图片对象BallBlue 赋给Balls[0],如果你细心,你会发现BallBlue正是加载图片资源语句中指定的对象名。语句Balls[0].style.pixelTop = BallCoord[0][0] = 100,同时将值100赋给数组变量BallCoord[0][0]和图片对象的style.pixelTop属性。从而坐标数组变量BallCoord[0][0]得到了初值并且指定了球1的初始顶端位置。其余语句的含义雷同。最后一句调用函数Move_Step()将小球移动一步。  

(二) 单步移动函数Move_Step()讲解  

在HTML文件的HEAD区中编写Move_Step() 函数其内容如下:  
function Move_Step() {  
Ball_Crash_Ball() //调用球间碰状处理函数  

Balls_Crash_Wall(0) //调用蓝球碰墙处理函数  
Balls_Crash_Wall(1) //调用红球碰墙处理函数  

//计算移动步长  
BallCoord[0][0] += BallMoveVector[0][0] * Setp_Proportion  
BallCoord[0][1] += BallMoveVector[0][1] * Setp_Proportion  
BallCoord[1][0] += BallMoveVector[1][0] * Setp_Proportion  
BallCoord[1][1] += BallMoveVector[1][1] * Setp_Proportion  
//移动一步  
Balls[0].style.pixelTop = BallCoord[0][0]  
Balls[0].style.pixelLeft = BallCoord[0][1]  
Balls[1].style.pixelTop = BallCoord[1][0]  
Balls[1].style.pixelLeft = BallCoord[1][1]  
window.setTimeout("Move_Step()",100) //100毫秒后再次调用Move_Step()函数  
}  
该函数的大部分含义,你可看其中的注释,这里只对几点加以说明。  

1在语句BallCoord[0][0] += BallMoveVector[0][0] * Setp_Proportion中, BallMoveVector数组存放着速度向量。Setp_Proportion 变量存放步长放大比率,BallMoveVector[0][0] 乘以Setp_Proportion 得到移动一步的长度。最后该语句加上BallCoord[0][0]原值后再赋给BallCoord[0][0]本身,得到移动位置。  

2.语句window.setTimeout("Move_Step()",100) 表示100毫秒后再次调用Move_Step()函数。现在有了setTimeout()方法,程序就不断的循环起来了。  

Ball_Crash_Ball()是小球之间的碰撞处理函数, 你只管调用就是了,如果你不使用它,程序一样能运行,只是少了处理球间碰撞的功能。(在Ball_Crash_Ball()函数中调用了函数CrashEnd_Speed() 与atan360(x,y),以及使用了全局变量CrashingBalls,因而要正确使用它,必须将以上所说的函数与变量都拷入你的程序中)  

(三) 在HEAD区中编写墙壁碰撞处理函数Balls_Crash_Wall()  

一个简化的函数如下:  

function Balls_Crash_Wall(i) {  

if( BallCoord[i][0] <= Window_Top)  
BallMoveVector[i][0] = - BallMoveVector[i][0]  

if ( BallCoord[i][1] <= Window_Left)  
BallMoveVector[i][1] = - BallMoveVector[i][1]  

if ( BallCoord[i][0] + BallDiametre[i] >= Window_Bottom)  
BallMoveVector[i][0] = - BallMoveVector[i][0]  

if ( BallCoord[i][1] + BallDiametre[i] >= Window_Right)  
BallMoveVector[i][1] = - BallMoveVector[i][1]  

}  

函数首先判断是否球已经碰到了墙壁,如是就将相应方向上的速度方向反向,而大小不变。但这个函数有可能发生错误(错误发生的原因有些复杂,这里只梢作提示。由于小球移动的步长往往大于1个点,而仿真又是离散进行的,从而在有些情况下会发生错误)。需用数组变量CrashingWall 来标识碰撞状态,使得小球与墙壁处于碰撞状态时不能再发生第二次小球与墙壁的碰撞,相应的语句也要更改,如第一句改为  

if( BallCoord[i][0] <= Window_Top)  
{ if (!CrashingWall[i][0]) { BallMoveVector[i][0] = - BallMoveVector[i][0] }  
CrashingWall[i][0] = true  
} else CrashingWall[i][0] = false  

语句中CrahingWall数组的类型为逻辑型,记录球与墙壁是否正在发生碰撞。当为碰撞状态时,就不必再将球的运动方向反向。  

到此程序的编写基本完成,其它详细内容见光盘的原程序及说明。现在在NetObject ScriptBuilder 中选择菜单Preview 项,运行程序。  

附注:  
1. 运行本例程需先安装IE4.0以上浏览器 或Netscape Navigator 4.0以上浏览器  

2. 球间碰撞处理提示:当两球发生碰撞时,计算两球圆心连线与X轴的夹角。在依据此夹角对坐标进行旋转。将原速度矢量映射到旋转后的坐标中。从而将球间的任意碰撞转变为正对心碰撞。用冲量定理可推出碰后的速度计算公式。然后再将坐标旋转成原始坐标。可得碰撞后的速度矢量。看了上面的文字是不是有些烦人,其实并非如此,程序中只用了11行语句就完成了全部计算。

Javascript 相关文章推荐
jQuery对象和DOM对象的相互转化实现代码
Mar 02 Javascript
js调用后台、后台调用前台等方法总结
Apr 17 Javascript
jquery获取radio值实例
Oct 16 Javascript
JQuery.get提交页面不跳转的解决方法
Jan 13 Javascript
jQuery实现鼠标滑向当前图片高亮显示并且其它图片变灰的方法
Jul 27 Javascript
如何解决谷歌浏览器下jquery无法获取图片的尺寸
Sep 10 Javascript
AngularJS指令详解及示例代码
Aug 16 Javascript
详解JS异步加载的三种方式
Mar 07 Javascript
js实现颜色阶梯渐变效果(Gradient算法)
Mar 21 Javascript
webpack常用配置总览(小结)
Nov 18 Javascript
JQuery复选框全选效果如何实现
May 08 jQuery
解决Vue中的生命周期beforeDestory不触发的问题
Jul 21 Javascript
用javascript编写的第一人称射击游戏
Feb 25 #Javascript
极酷的javascirpt,让你随意编辑任何网页
Feb 25 #Javascript
你真的了解JavaScript吗?
Feb 24 #Javascript
SUN的《AJAX与J2EE》全文译了
Feb 23 #Javascript
js玩一玩WSH吧
Feb 23 #Javascript
用Javascript做flash做的事..才完成的一个类.Auntion Action var 0.1
Feb 23 #Javascript
javascript知识点收藏
Feb 22 #Javascript
You might like
一个php Mysql类 可以参考学习熟悉下
2009/06/21 PHP
C#使用PHP服务端的Web Service通信实例
2014/04/08 PHP
PHP+shell实现多线程的方法
2015/07/01 PHP
执行iframe中的javascript方法
2008/10/07 Javascript
实现点击列表弹出列表索引的两种方式
2013/03/08 Javascript
原生JavaScript实现合并多个数组示例
2014/09/21 Javascript
JavaScript中的style.cssText使用教程
2014/11/06 Javascript
JavaScript定义类和对象的方法
2014/11/26 Javascript
再分享70+免费的jquery 图片滑块效果插件和教程
2014/12/15 Javascript
AngularJS基础知识笔记之表格
2015/05/10 Javascript
jQuery实现简单下拉导航效果
2015/09/07 Javascript
JavaScript转换与解析JSON方法实例详解
2015/11/24 Javascript
js时间戳转为日期格式的方法
2015/12/28 Javascript
Bootstrap3制作自己的导航栏
2016/05/12 Javascript
详解如何使用webpack+es6开发angular1.x
2017/08/16 Javascript
vue中的scope使用详解
2017/10/29 Javascript
关于react中组件通信的几种方式详解
2017/12/10 Javascript
jQuery实现表格的增、删、改操作示例
2019/01/27 jQuery
[01:32]TI珍贵瞬间系列(一)
2020/08/26 DOTA
Python实现计算文件夹下.h和.cpp文件的总行数
2015/04/23 Python
使用Python读写及压缩和解压缩文件的示例
2016/07/08 Python
win10 64bit下python NLTK安装教程
2018/09/19 Python
Python+threading模块对单个接口进行并发测试
2019/06/25 Python
Python如何实现转换URL详解
2019/07/02 Python
Python使用turtle库绘制小猪佩奇(实例代码)
2020/01/16 Python
Python通过len函数返回对象长度
2020/10/22 Python
Python 中如何使用 virtualenv 管理虚拟环境
2021/01/21 Python
css3实现针线缝合效果(图解步骤)
2013/02/04 HTML / CSS
KIKO MILANO荷兰网上商店:意大利专业化妆品品牌
2017/05/12 全球购物
求高于平均分的学生学号及成绩
2016/09/01 面试题
大学生农村教师实习自我鉴定
2013/09/21 职场文书
《池塘边的叫声》教学反思
2014/04/12 职场文书
生物技术专业求职信
2014/06/10 职场文书
2014年房产经纪人工作总结
2014/12/08 职场文书
国产动画《万圣街》日语配音版制作决定!
2022/03/20 国漫
吉利入股戴姆勒后smart“长大了”
2022/04/21 数码科技