• 【整理】HTML5游戏开发学习笔记(3)- 抛物线运动


    1.预备知识
    (1)Canvas旋转的实现过程

    			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)抛物线运动中的重力加速度的模拟实现模型

    			/*
    				抛物线运动
    				这个版本做了修改,为了减少一次角度和弧度之间的转换计算(通过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.主要代码

    			/*弹弓*/
    			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
    					}
    
    				}
    			}
    
    			// 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)可以实现同时有多个小球发射,就像游戏里发射子弹的效果

  • 相关阅读:
    语言及其文法
    编译原理绪论
    数据库系统绪论
    Flask系列-模板
    进程调度
    Flask系列-程序基本结构
    针对博客园上传md文件有点麻烦的解决方案
    博客样式存档二 (目前样式)
    [省选联考 2020 A 卷] 组合数问题
    退役划水(2)
  • 原文地址:https://www.cnblogs.com/Benoly/p/4045487.html
Copyright © 2020-2023  润新知