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

时间: 2024-10-19 11:47:44

【整理】HTML5游戏开发学习笔记(3)- 抛物线运动的相关文章

【整理】HTML5游戏开发学习笔记(1)-骰子游戏

<HTML5游戏开发>,该书出版于2011年,似乎有些老,可对于我这样没有开发过游戏的人来说,却比较有吸引力,选择自己感兴趣的方向来学习html5,css3,相信会事半功倍.不过值得注意的是,该书的游戏是些小的游戏,内容相对比较基础,而且html5标准已经正式发布,可能会和书中所描述有少许出处.当然了,书中的小游戏还是比较不错的,适合我这样的前端开发不咋地的来练手,学习方式是在以自己的思路实现之后,再来看书中的实现思路,因为每个人有自己的开发习惯. 1.预备知识在做第一个骰子游戏开发前,必须知

【整理】HTML5游戏开发学习笔记(2)- 弹跳球

1.预备知识(1)在画布上绘制外部图片资源(2)梯度(gradient):HTML5中的对象类型,包括线性梯度和径向梯度.如createLinearGradient,绘制梯度需要颜色组http://www.w3school.com.cn/tags/canvas_createlineargradient.asp function test1(){ //在画布上绘制外部图片资源 var ctx = document.getElementById('ballCanvas').getContext('2

cocos2dx游戏开发学习笔记3-lua面向对象分析

在lua中,可以通过元表来实现类.对象.继承等.与元表相关的方法有setmetatable().__index.getmetatable().__newindex. 具体什么是元表在这里就不细说了,网上很多介绍,这里主要讲与cocos2dx相关联的部分. 在lua-binding库中extern.lua里,有如下方法: --Create an class. function class(classname, super) local superType = type(super) local c

cocos2dx游戏开发学习笔记1-基本概念

这里主要讲构建整个游戏需要的基本元素,很大部分都摘自cocos2dx官网. 1.Director 导演 导演,顾名思义,就是对整个游戏进行整体控制的. "Director"是一个共享的(单元素集)对象,负责不同场景之间的控制.导演知道当前哪个场景处于活动状态,允许你改变场景,或替换当前的场景,或推出一个新场景.当你往场景堆中推出一个新场景时,"Director"会暂停当前场景,但会记住这个场景.之后场景堆中最顶层的场景跳离时,该场景又会继续活跃.此外"Di

cocos2dx游戏开发学习笔记2-从helloworld开始

一.新建工程 具体安装和新建工程的方法在cocos2dx目录下的README.md文件中已经有详细说明,这里只做简单介绍. 1.上官网下载cocos2dx-3.0的源码,http://www.cocos2d-x.org/ 2.安装python2.7 3.运行setup.py安装 4.执行cocos new helloworld -p helloworld -l cpp,生成新工程 二.新建工程中包含的东西 -Classes AppDelegate.cpp      -----游戏真正开始执行的地

[Android游戏开发学习笔记]View和SurfaceView

本文为阅读http://blog.csdn.net/xiaominghimi/article/details/6089594的笔记. 在Android游戏中充当主要角色的,除了控制类就是显示类.而在Android中涉及到显示的是View类,及继承自它的SurfaceView类和SurfaceView的其他子类等. 这里先只说View和SurfaceView.SurfaceView的直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及CAmera摄像头一般均使用Su

[游戏开发-学习笔记]菜鸟慢慢飞(一)

"菜鸟"就是我自己. 分享一下我从零开始学习游戏开发的过程,心得什么的.本篇先扯个开头,说说个人一些乱七八糟的想法. 从0开始 其实,只要有心,不管干哪一行,都不能算从零开始.总会有办法了解到行业的信息.我之前是干船舶电气的,一路过来,最大的感觉是:不怕你找不到资料,就怕你没时间.我要做的是分清楚自己想学什么,怎么样去提高自己,然后沿着自己路线"慢慢"朝前飞.比如:知乎就是个很好的地方,我最早接触游戏开发,是在这里.决定学这个,也是在知乎喝了鸡汤. 游戏开发 对我来

[游戏开发-学习笔记]菜鸟慢慢飞(二)-迷宫

简介:练手Demo,<走出迷宫>,文章主要说说如何创建迷宫. 学习Unity3D有一段时间了,自己想了一个项目来练手手.然后就有了这篇. 一.固定的格数,开局后随机生成. 说明:这个迷宫10*10,开始后随机生成,四周留下一个空做出口. 先说如何实现: 主要准备了三个Prefab:横墙,竖墙,柱子,墙高度是10,宽度是10,厚度是1,柱子高度是10.宽度和厚度都是10. 手动按照10*10排列(参考下图) 脚本 #region //初始化游戏 #endregion using System.C

[游戏开发-学习笔记]菜鸟慢慢飞(四)-Camera

游戏开发中,主相机应该是最重要的GameObject之一,毕竟游戏呈现给玩家,就是通过它. 相机的使用,在不同的游戏中,有很大的不同.这里总结一下自己学到的一些相关知识. 固定位置-游戏过程中相机的Transform属性不改变. 调整好位置后就不要动了,一般使用正交相机,即Camera-Projection选择Orthographic.Unity Manual-Camera 适用:2D游戏.比如飞机大战,消消乐. 游戏开始后,相机追踪某一物体,然后固定不动. 游戏开始后,我们才能确定追踪物体的位