【整理】HTML5游戏开发学习笔记(3)- 抛物线运动
2014-10-23 12:39 Benoly 阅读(606) 评论(0) 编辑 收藏 举报1.预备知识
(1)Canvas旋转的实现过程
1 2 3 4 5 6 7 8 9 10 11 12 | window.onload = function (){ var ctx = document.getElementById( 'canvas1' ).getContext( '2d' ) //旋转 ctx.save() ctx.translate(200,200) //把(200,200)点作为临时的(0,0)点 ctx.rotate(30*Math.PI/180) //顺时针旋转30度所对应的弧度 ctx.fillRect(0,0,100,150) ctx.restore() } |
(2)抛物线运动中的重力加速度的模拟实现模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /* 抛物线运动 这个版本做了修改,为了减少一次角度和弧度之间的转换计算(通过Math.atan2可以直接算出弧度), 构造参数中的角度改成了弧度 deleted: angle = angle, //初始角度 radians = angle*Math.PI/180, //初始弧度 object ParabolicMotion @velocity:初始速度 @radians:初始弧度 @gravity:初始加速度{x:0,y:2} */ function ParabolicMotion(velocity,radians,gravity){ var velocity = velocity, radians = radians, gravity = gravity var offsetX = velocity*Math.cos(radians), offsetY = -velocity*Math.sin(radians) function next(offset,gravity){ var offset1 = offset var offset2 = offset+gravity return {offset:offset2,dv:(offset1+offset2)*.5} } return { /* 获取运动轨迹到下一个时间点,x,y轴所偏移的距离 */ moveNext : function (){ var offsetXD = next(offsetX,gravity.x) var offsetYD = next(offsetY,gravity.y) offsetX = offsetXD.offset offsetY = offsetYD.offset //console.log(offsetX+','+offsetY) return {x:offsetXD.dv,y:offsetYD.dv} } } } |
2.实现思路
涉及的对象,包括球(Ball),弹弓(Slingshot),抛物线运动(ParabolicMotion)。
操作过程是,鼠标键按下拖拽小球,和弹弓的作用点成一定的角度,鼠标键按起后,小球做抛物线运动
3.主要代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /*弹弓*/ function Slingshot(){ var opts, ctx, crtBall, ballSelected = false function refresh(){ ctx.clearRect(0,0,opts.width,opts.height) drawSling() crtBall.draw() } function drawSling(){ var point = opts.actionPoint ctx.beginPath() ctx.moveTo(point.x,point.y) ctx.lineTo(point.x,opts.height) ctx.closePath() ctx.stroke() if (crtBall!= null &&ballSelected){ //绘制连接球和弹弓的"橡皮筋" ctx.beginPath() ctx.moveTo(point.x,point.y) ctx.lineTo(crtBall.x,crtBall.y) ctx.closePath() ctx.stroke() } } function isBallSelected(offsetX,offsetY){ var point = opts.actionPoint var a = Math.abs(point.x-offsetX) var b = Math.abs(point.y-offsetY) //var c = Math.sqrt(a*a+b*b) return (a*a+b*b)<=crtBall.radius*crtBall.radius } // 添加拉弹弓事件 function initEvents(){ var canvas = opts.canvas /* addEventListener函数的第3个参数, false表示内层元素事件先触发,ture则表示外层的事件先触发 alert(e.offsetX+','+e.offsetY) 必须使用offsetX,offsetX是相对于canvas画布的距离(但firefox不支持) 事件参数e没有考虑浏览器兼容问题 */ canvas.addEventListener( 'mousedown' , function (e){ // 判断球是否被选中 ballSelected = isBallSelected(e.offsetX,e.offsetY) if (ballSelected){ crtBall.locate(e.offsetX,e.offsetY) refresh() } }, false ) canvas.addEventListener( 'mousemove' , function (e){ if (ballSelected){ crtBall.locate(e.offsetX,e.offsetY) refresh() } }, false ) canvas.addEventListener( 'mouseup' , function (e){ if (ballSelected){ ballSelected = false crtBall.locate(e.offsetX,e.offsetY) refresh() //发射炮弹 fire( function (x,y){ //TODO 判断是否打中目标 }) } }, false ) } function fire(onCompleted){ // 获取当前的炮弹发射速度和弧度 var velocity = ($.square(opts.actionPoint.y-crtBall.y)+$.square(opts.actionPoint.x-crtBall.x))/100 var radians = -Math.atan2(opts.actionPoint.y-crtBall.y,opts.actionPoint.x-crtBall.x) //30*Math.PI/180 var gravity = {x:0,y:2} var parabolicMotion = new ParabolicMotion(velocity,radians,gravity) var completed = false var timer = setInterval( function (){ // 在当前抛物线轨迹下,获取炮弹下一次单位时间内x,y轴需要偏移的单位长度 var offset = parabolicMotion.moveNext() crtBall.move(offset.x,offset.y) refresh() // 检查是否超出画布边界 completed = (crtBall.x>=opts.width||crtBall.y>=opts.height) if (completed){ clearInterval(timer) if ( typeof onCompleted== 'function' ){ onCompleted(crtBall.x,crtBall.y) } } },100) } return { init : function (options){ opts = $.extend(options,{ canvas : null , //画布 width : 1000, //画布长 height : 300, //画布高 actionPoint : {x:150,y:200} /*作用力点坐标*/ }) ctx = opts.canvas.getContext( '2d' ) drawSling() // 添加拉弹弓事件 initEvents() return this }, loadBall : function (ball){ var point = opts.actionPoint crtBall = ball.init({ctx:ctx,x:point.x,y:point.y}) .draw() return this } } } |
1 2 3 4 5 6 7 8 9 10 | // app window.onload = function (){ var canvas = document.getElementById( 'canvas1' ) var ball = new Ball(10) var slingshot = new Slingshot().init({canvas:canvas}) // 装载一个炮弹 slingshot.loadBall(ball) } |
4.优化和完善
(1)需实现球打中目标物体后,目标物体进行旋转
(2)可以实现同时有多个小球发射,就像游戏里发射子弹的效果
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步