html鼠标点击出现小球

html鼠标点击出现小球,第1张

html绘制小球并跟随鼠标移动,Canvas跟随鼠标炫彩小球的实现

黄利好

转载

关注

0点赞·318人阅读

跟随鼠标炫彩小球

canvas没有让我失望,真的很有意思

实现效果

超级炫酷

实现原理

创建小球

给小球添加随机颜色,随机半径

鼠标移动通过实例化,新增小球

通过调用给原型新增的方法,来实现小球的动画效果

通过定时器不断地更新画布

实现过程

创建小球

通过创建函数收纳小球所有的样式,再通过实例化函数,将鼠标当前的位置传递给Ball函数,让通过实例化创建出来的小球,最后将创建出来的小球存入数组中,数组中以对象形式存放着每个小球的属性和属性值

function Ball(x, y, r) {

this.x = x

this.y = y

this.r = r

this.color = getRandom()//随机生成颜色

this.dx = parseInt(Math.random() * 10) - 5//生成随机移动的位置

this.dy = parseInt(Math.random() * 10) - 5//`-5`是让小球能向四周随机移动

ballArr.push(this)//添加小球

}

//监听鼠标移动事件

canvas.addEventListener('mousemove', function (e) {

new Ball(e.offsetX, e.offsetY, parseInt(Math.random() * 20))

/*实例化Ball为Ball对象通过__proto__来调用原型的方法*/

})

生成随机颜色

对于color这个属性,可以通过6位16进制的值来表示一种颜色

因此,可以通过随机产生一个6位的16进制数来做为随机颜色

将0到f这16个数存入数组中,通过随机生成6个0到16的索引值,这样就能通过数组的索引号随机的获取6个到0到f中的数了

split的作用是:以括号内的参数为标志符来分割字符串,返回数组

//设置随机颜色

function getRandom() {

var allType = '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f'//16进制颜色

var allTypeArr = allType.split(',')//通过','分割为数组

var color = '#'

for (var i = 0i <6i++) {

//随机生成一个0-16的数

var random = parseInt(Math.random() * allTypeArr.length)

color += allTypeArr[random]

}

return color//返回随机生成的颜色

}

渲染小球

给函数的原型链中添加render方法,让每一个通过Ball函数实例化出来的对象,带有这些方法

这个函数的作用是,通过Ball的参数生成一个圆形,在实例化的时候,会生成一个对象,这个对象里就存放的x,y,r这些值

Ball.prototype.render = function () {

ctx.beginPath()//路径开始

ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false)//画圆,位置,半径

ctx.fillStyle = this.color//颜色

ctx.fill()//填充

}

更新小球信息

因为生成的小球x,y,r是固定的,所以小球的位置也是固定的,不会改变

因此需要通过改变每个小球的位置和半径让小球动起来,当小球的半径小于0时,调用remove方法将小球从数组中删除

/* 更新小球位置和半径 小于0时清除 */

Ball.prototype.update = function () {

this.x += this.dx//x改变

this.y += this.dy//y改变

this.r -= 0.1//半径减小

if (this.r <0) {

this.remove()//调用添加的remove方法

}

}

删除小球

这是上面调用的remove方法,当this也就是当前小球半径小于0时i,遍历整个数组,找到这个this,也就是”这个小球“,通过调用数组中的方法,删除掉数组的这个元素

splice(index,num) 方法可删除从 index 处开始删除num个元素

Ball.prototype.remove = function () {

for (var i = 0i <ballArr.lengthi++) {

if (ballArr[i] == this) {

ballArr.splice(i, 1)//找到这个小于0 的元素,删除

<html>

<head>

<title>

大球吃小球by大奔

</title>

<script type="text/javascript" src="src/jscex.js"></script>

<script type="text/javascript" src="src/jscex-parser.js"></script>

<script type="text/javascript" src="src/jscex-jit.js"></script>

<script type="text/javascript" src="src/jscex-builderbase.js"></script>

<script type="text/javascript" src="src/jscex-async.js"></script>

<script type="text/javascript" src="src/jscex-async-powerpack.js"></script>

</head>

<body>

<canvas id="myCanvas" width="480" height="300" style="border:1px solid #c3c3c3">

你的浏览器改换了

</canvas>

<script type="text/javascript">

var d=document.getElementByIdx_x("myCanvas")

var cxt=d.getContext("2d")

var balls=[]

//这里为了获得随机数的向量

function getRandom(a,b){

return (a+Math.floor(Math.random()*(b-a+1)))

}

//这里对向量进行赋值

var Vector2=function(a,b){

this.x=a||0

this.y=b||0

}

//这里需要注意,对象的默认方法在这里写不会管用。例如sub

Vector2.prototype={//写对象的构造函数

constructor:Vector2,

multiplyScalar:function(s){

this.x*=s

this.y*=s

return this

},

divideScalar:function(s){

if(s){

this.x/=s

this.y/=s

}else{

this.set(0,0)

}

return this

},

dot:function(v){

return this.x*v.x+this.y*v.y//即两个向量相乘

},

lengthSq:function(){

return this.x*this.x+this.y*this.y

},

length:function(){

return Math.sqrt(this.lengthSq())

},

normalize:function(){

//这里得到的是单位向量,按照google的定义,单位的向量是,//(a,b)则a*a+b*b=1

return this.divideScalar(this.length())

},

reflectionSelf:function(v){

//这里得到的是反射向量。公式参考这个网址。

//blog.physwf.com/?p=42

var nv=v.normalize()

this.sub(nv.multiplyScalar(2*this.dot(nv)))

},

distanceToSquared:function(v){//求出两点之间的距离

var dx=this.x-v.x,

dy=this.y-v.y

return dx*dx+dy*dy

}

}

Vector2.sub=function(v1,v2){//这里重写sub方法

return new Vector2(v1.x-v2.x,v1.y-v2.y)

}

for(var i=0i<40i++){//初始化40个小球

var ball={

position:new Vector2(getRandom(20,600),getRandom(20,600)),

r:getRandom(6,20),

speed:new Vector2(getRandom(-200,200),getRandom(-200,200)),

mass:1,//这是小球的质量

restitution:1//这是d性系数

}

balls.push(ball)

}

var filterBalls=[]

for(var i=0i<balls.lengthi++){

var overlapCount=0

for(var j=i+1j<balls.lengthj++){//两个两个比较防止重复,而且初始化的位置不能重 //叠,否则符合碰撞的条件。去掉这个判断以后,效果不太显著,可以多放些球试试。

var distance=balls[i].position.distanceToSquared(balls[j].position)

var l=balls[i].r+balls[j].r

if(distance<=(l*l)){

overlapCount++

}

}

if(overlapCount===0){

filterBalls.push(balls[i])

}

}

balls=filterBalls//这里可以去掉试试。

cxt.fillStyle="#030303"

cxt.fillRect(0,0,d.width,d.height)

function init(){

cxt.fillStyle="#fff"

for(i in balls){

cxt.beginPath()

cxt.arc(balls[i].position.x,balls[i].position.y,balls[i].r,0,Math.PI*2,true)

cxt.closePath()

cxt.fill()

}

}

init()

var cyc=20

var moveAsync2=eval_r(Jscex.compile("async",function(){

var tag=0

while(true){

try{

cxt.fillStyle="rgba(0,0,0,3)"

cxt.fillRect(0,0,d.width,d.height)

cxt.fillStyle="#fff"

for(var i=0i<balls.lengthi++){

//这里是为了两个小球比较会重复所以,每次比较都是i与i+1//开始相比较

for(var j=i+1j<balls.lengthj++){

collisionSolver(balls[i],balls[j])

}

}

for(i in balls){

cxt.beginPath()

cxt.arc(balls[i].position.x,balls[i].position.y,balls[i].r,0,Math.PI*2,true)

cxt.closePath()

cxt.fill()

if(balls[i].r+balls[i].position.x>d.width){

//如果小球x轴跑出了画布的范围

balls[i].position.x=d.width-balls[i].r

//小球的位置返回到画布的边缘位置

balls[i].speed.x*=-1

//同时x轴的方向变为反方向

}if(balls[i].position.x<balls[i].r){

//如果小球的x坐标小于小球的半径。肯定画不成完整的圆了,所以要归位

balls[i].position.x=balls[i].r

balls[i].speed.x*=-1 }if(balls[i].r+balls[i].position.y>d.height){//同理y轴

balls[i].position.y=d.height-balls[i].r

balls[i].speed.y*=-1

}

if(balls[i].position.y<balls[i].r){

balls[i].position.y=balls[i].r

balls[i].speed.y*=-1

} balls[i].position.x+=balls[i].speed.x*cyc/1000

//小球的x轴不断按照速度增大

balls[i].position.y+=balls[i].speed.y*cyc/1000

}

}catch(e){

alert(e)

}

$await(Jscex.Async.sleep(cyc))

}

}))

function collisionSolver(bodyA,bodyB){//判断小球发生碰撞的时候的变化。

var vB=bodyB.speed

var vA=bodyA.speed

var l=bodyA.r+bodyB.r

var distSqr=bodyA.position.distanceToSquared(bodyB.position)

var isTouching=distSqr<=l*l? true:false

//判断两圆心之间的距离如果小于两半径之和的平方。则为true

var normal=Vector2.sub(bodyB.position,bodyA.position).normalize()

//请看上面的解释,所以得到的是B相对于A的单位向量。

var ratio=bodyA.r/l//这是一个比例

var contactPoint=new Vector2()

//根据平行线切割的三角形,两边的边的比例相等,

contactPoint.x=bodyA.position.x+(bodyB.position.x-bodyA.position.x)*ratio

contactPoint.y=bodyA.position.y+(bodyB.position.y-bodyA.position.y)*ratio

var rA=Vector2.sub(contactPoint,bodyA.position)

//这两个地方没有找到是哪里用到的?????

var rB=Vector2.sub(contactPoint,bodyB.position)

var vrn=Vector2.sub(vA,vB).dot(normal)

//这里得到的是Va相对于vB的速度向量与两球的圆心的单位向量相乘。

///a*b=|a|*|b|*cos@.所以如果vrn大于零,则夹角小于90度。

if(isTouching&&vrn>0){

//这里是冲量公式的一个部分

var normalMass=1/(1/bodyA.mass+1/bodyB.mass)

var restitution=(bodyA.restitution+bodyB.restitution)/2

var normalImpulse=-normalMass*vrn*(1+restitution)

bodyA.speed.x+=normalImpulse*normal.x/bodyA.mass

//这里总之是一个大球一个小球,所以速度一个增大一个减小

bodyA.speed.y+=normalImpulse*normal.y/bodyA.mass

bodyB.speed.x-=normalImpulse*normal.x/bodyB.mass

bodyB.speed.y-=normalImpulse*normal.y/bodyB.mass

}

}

moveAsync2().start()

</script>

</body>

</html>

装,但那个还是比较耗钱的,而且小改没有作用,凑合着用用吧

2:每辆车的刹车性能都是和车的构造性能有密切关系的,在生产的时候经过实验论证,如果随意更换的话,全车的一个平衡就容易被打破,刹车换个同型号的质量好点的,大碟对小车未必好

3:FF是'Front Engine,Front Drive'的简写,意思是'前置引擎, 前轮驱动',即所谓'前偈前驱'.引擎放在车头,波箱紧贴引擎,动力由前轮送到地面.前轮兼负动力转送和转向的功 能.优点就是省却通往后轮的传动轴,车箱有更大的空间, 车身也自然轻.虽然一般而言它不及FR 般灵活,但胜在爱生活,爱飚车控容易,高速失控时也较易救车,所以在飞车圈子也普遍受落.本来FF另有缺点,就是前轮传动轴的万 向接头(俗称'和尚头' 容易耗损,不宜大动力传送,但随著汽 车工艺与科技的进步,这问题得以渐渐减少.所以,FF成为今天轿车的主流,更愈来愈多大型车采用

FC、 马自达RX-7 FC3S

FD、 马自达RX-7 FD3S

FR、 前置引擎 后轮驱动

FF、 前置引擎 前轮驱动

32、 尼桑 SKYLINE GTR-R32

S13 尼桑 Silvia 13代

都是车的专业缩写 一般是底盘型号 或者业内人士的习惯称呼

FF FR MR 4WD 是驱动形式

4:这个要询问汽配改装的专业人士,一般家用车的可以不用过分计较

5:扭力为引擎在运转速时所输出的扭矩。扭矩或扭力是针对旋转运动的物体说的,因为引擎的驱动力,从飞轮经过变速箱传导到车轮,都是在旋转状态下。对于驾驶者,能感受到的就是车辆加速的力量,所以说一部车很够力,是因为感受到引擎强大扭力所产生的加速力。汽车驱动力的计算方式:

将扭矩除以车轮半径即可由引擎马力-扭力输出曲线图可发现,在每一个转速下都有一个相对的 扭矩数值,这些数值要如何转换成实际推动汽车的力量呢?答案很简单,就是「除以一个长度」,便可获得「力」的数据。举例而言,一 部1.6升的引擎大约可发挥15.0kg-m的最大扭力,此时若直接连上185/ 60R14尺寸的轮胎,半径约为41公分,则经由车轮所发挥的推进力量为15/0.41=36.6公斤的力量(事实上公斤并不是力量的单位,而是重量的单位,须乘以重力加速度9.8m/sec2才是力的标准单位「牛顿」)。

36公斤的力量怎么推动一公吨的车重呢?而且动辄数千转的引擎转速更不可能恰好成为轮胎转速,否则车子不就飞起来了?幸好聪明的人类发明了「齿轮」,利用不同大小的齿轮相连搭配,可以将旋转的速度降低,同时将扭矩放大。由于齿轮的圆周比就是半径比,因此从小齿轮传递动力至大齿轮时,转动的速度降低的比率以及扭矩放大的倍数,都恰好等于两齿轮的齿数比例,这个比例就是所谓的「齿轮比」。

举例说明,以小齿轮带动大齿轮,假设小齿轮的齿数为15齿,大齿轮的齿数为45齿。

当小齿轮以3000rpm的转速旋转,而扭矩为20kg-m时,传递至大齿轮的转速便降低了1/3,变成1000rpm;但是扭矩反而放大三倍,成为60kg-m。这就是引擎扭矩经由变速箱可降低转速并放大扭矩的基本原理。

在汽车上,引擎输出至轮胎为止共经过两次扭矩的放大,第一次由变 速箱的档位作用而产生,第二次则导因于最终齿轮比(或称最终传动 比)。扭矩的总放大倍率就是变速箱齿比与最终齿轮比的相乘倍数。举例来说,手排六代喜美的一档齿轮比为3.250,最终齿轮比为4.058,而引擎的最大扭矩为14.6kgm/5500rpm,于是我们可以算出第一档的最 大扭矩经过放大后为14.6×3.250×4.058=192.55kgm,比原引擎放大了13倍。此时再除以轮胎半径约0.41m,即可获得推力约为470公斤。然而上述的数值并不是实际的推力,毕竟机械传输的过程中必定有磨 耗损失,因此必须将机械效率的因素考虑在内。

论及机械效率,每经过一个齿轮传输,都会产生一次动力损耗,手排变速箱的机械效率约在95%左右,自排变速箱较惨,约剩88%左右,而传动轴的万向接头 效率约为98%,各位自己乘乘看就知道实际的推力还剩多少。整体而 言,汽车的驱动力可由下列公式计算:

扭矩×变速箱齿比×最终齿轮比×机械效率

驱动力= ————————————————————

轮胎半径(单位为公尺)

马力亦非「力」乃「功率」的一种

了解如何将扭矩经由变速箱的齿比放大成为实际推力之后,接着可以研究什么叫做「马力」。马力其实也不是一种「力」,而是一种功率 (Power)的单位,定义为单位时间内所能做「功」的大小。尽管如此,我们不得不继续使用「马力」这个名字,毕竟已经用太久了,讲「功率」恐怕没几个消费者听得懂?

功率是由扭矩计算出来的,而计算的公式相当简单:功率(W)=2π× 扭矩(N-m)×转速(rpm)/60,简化计算后成为:功率(kW)=扭矩(N-m) ×转速(rpm)/9549,详细的推导请参看方块文章。然而功率kW要如何 转换成大家常见的「马力」呢,这又有一段故事得讲。

英制或公制?

1PS=735W;1hp=746W

马力定义竟然不一样!

谈到引擎的马力,相信不少人会直觉地想到什么DIN、SAE、EEC、JIS等等不同测试标准,到底这些标准的差异在哪儿,以后有空再研究;有点夸张的是由于英制与公制的不同,对「马力」的定义基本上就不一样。英制的马力(hp)定义为:一匹马于一分钟内将200磅(lb)重的物体拉动165英呎(ft),相乘之后等于33,000ft-lb/min;而公制的马力(PS)定义则为一匹马于一分钟内将75公斤的物体拉动60公尺,相乘之后等于4500kg-m/min。经过单位换算,(1lb=0.454kg1ft=30.48cm)竟然发现1hp=4566kg-m/min,与公制的1PS=4500kg-m有些许差异,而如果以功率W(1W=1Nm/sec= 9.8kgm/sec)来换算的话,可得1hp=746W1PS=735W两项不一样的结果。

同样是「马力」,英制马 力与公制马力的定义竟然不一样!难道英国马比较「有力」吗?

到底世界上为什么会有英制与公制的分别,就好像为什么有的汽车是右驾,有的却是左驾一样,是人类永远难以协调的差异点。若以大家 比较熟悉的几个测试标准来看,德国的DIN与欧洲共同体的新标准 EEC还有日本的JIS是以公制的PS为马力单位,而SAE使用的是英制的 hp为单位,但为了避免复杂,本刊一率将马力的单位标示为hp。近来,越来越多的原厂数据已改提供绝对无争议的KW作为引擎输出的功率数值。

不过话说回来,1PS与1hp之间的差异仅1.5%,每一百匹马力差1.5匹,差异并不大。一般房车的马力多半仅在200匹马力以下,两者由于定义的差异也仅3匹马力左右,因此如果您真要「马马计较」,就把SAE 标准的数据多个1.5%吧!不过SAE、JIS、DIN、EEC各种测试标准之 间亦有些许差异,这个老问题已经争论过很多次了,单位之间不能真正划上等号,然而在差别不怎么多的情况之下,就当作相同吧!因此 管他是PS或hp,都差不多可以视为相等。

终于可以做结论了!将上述获得的马力与功率换算方式代入功率与扭矩的换算公式,并且将扭矩的单位换算为大家熟悉的kg-m之后,可得下列结果:

英制马力hp=扭力(kg-m)×引擎转速(rpm)/727

公制马力PS =扭力(kg-m)×引擎转速(rpm)/716

知道这些公式之后有什么用呢?从「马力hp=扭力×转速/727」看来, 如果能增加引擎转速,扭力不变的情况下,便能增加马力。例如若能 将转速从6000rpm增加到8000rpm,等于增加了33%,但因为凸轮轴的 限制使得8000rpm时的扭力下降了10%,则仍能使马力增加19.7%,这 说明了时下改装计算机的为何能在解除断油后大幅增加马力。

所以不要被「增加??匹马力」的广告所著魔。

让我们从另外一个角度来想:如果在同样的转速下,增加20匹马力,代表能增加多少推力呢?以最大扭力点发挥于5000rpm的情况下,将公式稍微变换一下,可发现增加的扭力=20hp×727/ 5000rpm=2.9kgm。再将这个结果代入汽车驱动力的公式,同样以喜美 的一档计算,2.9×3.250×4.058/0.41=93公斤。对于一吨重的车身而言,影响似乎也不怎么大;再者如果相差5匹马力的话,推力更仅增加23公斤,可见相差5匹马力,根本也没差多少,所以能「增加5匹马力」的产品,到底应该花多少钱去改装,您自个儿会拿捏了吧?

大马力决定真性能!

到底大马力的车子跑得快,还是大扭力的车子跑得快?从公式可以知 道大马力的原因是「高转速的时候仍保有高扭力数值」,也就是说要 有大马力,不只是低转速的扭力要好,连高转速的扭力都得继续维持 ,这表示扭力与马力的争论根本是多余的,只要能做到高马力,除了表示各转速区域的扭力都很大之外,更代表材料技术的优越性,将活塞、进排气阀门的材质与重量予以强化与轻量化,才能将引擎转速提高。

扭矩与功率的换算公式推导

假设一圆的半径为r(单位为m),扭矩为T(单位为N-m),则圆周上切线 方向的力F=T/r,由于功率的定义为「每秒钟所作的功」,对于圆周?动而言,每旋转一圈所作的功为:F×圆周总长2πr 将F=T/r代入计算,每一圈所作的功Work=F×2πr=(T/r)×2πr=2πT

再乘上引擎转速rpm就是每分钟所作的功,但功率P的单位是N-m/sec ,所以需除以60,转换成每秒所作的功。代入公式:P=T2πrpm/60,将常数整理后,则可得P(kW)=Trpm/9545。

由上文可见,一台车的动力由发动机传输到车轮,需要经过多组齿轮因此有所损耗,如果德制马力测的是传递到车轮上的动力,那么同样发动机用在不同车型上的动力输出应该不同,试拿bmw330和bmw530做比较,其功率均是225hp/5900rpm;结论,要么bmw在数据上造假,要么它测的是发动机输出净值


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/6094929.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-14
下一篇 2023-03-14

发表评论

登录后才能评论

评论列表(0条)

保存