这个游戏的原理我分为11个步骤,依次如下:

1、布局,

2、画曲线(曲线由两个半径不同的圆构成)

3、画曲线起点起始圆和曲线终点终止圆

4、起始的圆动起来,

5、起始的圆沿曲线走起来

6、起始的圆沿曲线走起来,并在曲线初始位置处产生新圆

7、添加图片,这个图片是为了发射子弹

8、让图片跟随鼠标动起来

9、让动起来的图片跟随鼠标的位置发送子弹,并让子弹的颜色变红

10、图片发射的子弹和轨迹上的小圆碰撞检测

11、碰撞检测后让发射的子弹和轨迹上的小圆消失

这就是该程序步骤的的分解。

第一点:布局

<div id="div1">
<canvas id="canvas1" width="800px" height="800px"></canvas>
</div>
 *{margin:;padding:;}
#canvas1{background-color: #ccc;}
#div1{
width: 800px; margin: 20px auto;}

布局很简单。

第二点:画曲线

//外大圆
oCG.beginPath();
oCG.arc(400,400,250,-90*Math.PI/180,180*Math.PI/180,false);
oCG.stroke();
//内小圆
oCG.beginPath();
oCG.arc(350,400,200,180*Math.PI/180,0,false);
oCG.stroke();
//末尾圆
oCG.beginPath();
oCG.arc(550,400,30,0,360*Math.PI/180,false);
oCG.stroke();

外面的大圆圆心坐标为400,400,半径为250,从-90度到180度,顺时针。,内小圆的圆心坐标为350,400,半径为200,从180度到0度,瞬时针。曲线终点有一个小圆,圆心坐标为550,400,半径为30。三个圆都为空心圆。

第三点:画曲线起点起始圆和曲线终点末尾圆

曲线终点的末尾圆,在上面已经绘制了,下来就是曲线的起始点的圆如何绘制

                    oCG.beginPath();
oCG.moveTo(400,150);
oCG.arc(400,150,30,0,360*Math.PI/180,false);
oCG.fill();

第四点:起始的圆动起来

起始点的坐标为400,150,半径为30,但是要考虑到一点,小圆圆心坐标是变化的,为了方便数据的改变,使用json去存放数据

            var ball=[];
ball[0]={
x:400, //小圆起始点横坐标
y:150, //小圆起始点纵坐标
r:250, //大圆的半径
num:0, //小圆转过的角度
//必须新建一个小圆的横纵坐标,否则小圆会飞出去。
X:400, //小圆起始点横坐标
Y:150 //小圆起始点纵坐标
}

计算运动后下一个圆心的坐标

 setInterval(function(){
for(var i=0;i<ball.length;i++){
ball[i].num++; // 圆角度由0-360
ball[i].x=Math.sin(ball[i].num*Math.PI/180)*ball[i].r+ball[i].X; //小圆横坐标
ball[i].y=ball[i].r-Math.cos(ball[i].num*Math.PI/180)*ball[i].r+ball[i].Y;//小圆的纵坐标
}
{,1000/60)

第五点:起始的圆沿曲线走起来

然后 ball[i].x ball[i].y 附给新画的圆,因为在定时器内,所以就能形成1000/60ms变化一次圆心的效果,进而让圆运动,但是这个运动仅仅是围绕大圆运动的。要想再围绕内小圆运动,就应该再加一个if判断

  setInterval(function(){
for(var i=0;i<ball.length;i++){
ball[i].num++; // 圆角度由0-360
if(ball[i].num==270){// 如果角度变为270度,改变ball的起始点坐标,就是改变它的轨迹。
ball[i].r=200;
ball[i].X=350;
ball[i].Y=200;
}
else if(ball[i].num==360+45+45
){
confirm('你失败了!点击确定重来!');
window.location.reload()
}
ball[i].x=Math.sin(ball[i].num*Math.PI/180)*ball[i].r+ball[i].X; //小圆横坐标
ball[i].y=ball[i].r-Math.cos(ball[i].num*Math.PI/180)*ball[i].r+ball[i].Y;//小圆的纵坐标
}
},1000/60)

当小圆走到270度时,把ball的起始点坐标改变,就能改变ball 的轨迹。当ball[i].num=450度时,也就是走到末尾圆,代表游戏结束。

第六点:起始的圆沿曲线走起来,并在曲线初始位置处产生新圆。

为了产生新的圆,只是开一个定时器,让每隔一段时间产生一个新的json

            var ball=[];
setInterval(function(){
ball.push({
x:400, //小圆起始点横坐标
y:150, //小圆起始点纵坐标
r:250, //大圆的半径
num:0, //小圆转过的角度
//必须新建一个小圆的横纵坐标,否则小圆会飞出去。
X:400, //小圆起始点横坐标
Y:150 //小圆起始点纵坐标
})
},400);

第七点:添加图片,这个图片是为了发射子弹

var oimg= new Image();
oimg.src='1.jpg' ;
oimg.onload=function(){
//让图片顺在中心转起来
var picX=(oC.width-oimg.offsetWidth)/2;
var picY=(oC.height-oimg.offsetHeight)/2;
oCG.save(); //为了不受定时器影响,sava起来
oCG.translate(picX,picY);
oCG.rotate(-iRotate);//里面的参数是为了控制让图片跟着鼠标旋转
oCG.translate(-30,-30); //为了让图片沿着图片中心转动
oCG.drawImage(oimg,0,0);
// oCG.drawImage(oimg,(oC.width-oimg.offsetWidth)/2,(oC.height-oimg.offsetHeight)/2)
oCG.restore();
},1000/60);

8、让图片跟随鼠标动起来

//让图片跟着鼠标转,原理就是求图片纵坐标与鼠标与图片中心的距离的夹角。把这个夹角附给
//图片旋转的角度
var iRotate=0;
oC.onmousemove=function(ev){
oEvent=ev||event;
var a=oEvent.clientX-oC.offsetLeft-(oC.width-oimg.offsetWidth)/2;
var b=oEvent.clientY-oC.offsetTop-(oC.height-oimg.offsetHeight)/2;
iRotate=Math.atan(a/b);
};

四角星代表鼠标,角度为a与b的夹角,红色方块代表图片,把获取到角度赋给  ”oCG.rotate(-iRotate);//里面的参数是为了控制让图片跟着鼠标旋转”

第九点:让动起来的图片跟随鼠标的位置发送子弹,并让子弹的颜色变红

 

            //让图片吐子弹
var Buttle=[];
oC.onmousedown=function(ev){
oEvent=ev||event;
var a=oEvent.clientX-oC.offsetLeft-(oC.width-oimg.offsetWidth)/2;
var b=oEvent.clientY-oC.offsetTop-(oC.height-oimg.offsetHeight)/2;
var iSpeed=5;
var c=Math.sqrt(a*a+b*b); //鼠标距离图片中心的距离
var iSpeedX=iSpeed*a/c; //横轴分得到的速度
var iSpeedY=iSpeed*b/c; //纵轴分得到的速度
Buttle.push({
x:(oC.width-oimg.offsetWidth)/2,
y:(oC.height-oimg.offsetHeight)/2,
iSpeedX:iSpeedX,
iSpeedY:iSpeedY
})
}
 //图片吐子弹的路径,获得吐到子弹终点的坐标
for(var i=0;i<Buttle.length;i++){
Buttle[i].x=Buttle[i].x+Buttle[i].iSpeedX; //子弹终点横坐标
Buttle[i].y=Buttle[i].y+Buttle[i].iSpeedY; //子弹终点纵坐标
}
  for(var i=0;i<Buttle.length;i++){
oCG.save();
oCG.beginPath();
oCG.fillStyle='red';
oCG.moveTo(Buttle[i].x,Buttle[i].y);
oCG.arc(Buttle[i].x,Buttle[i].y,30,0,360*Math.PI/180,false);
oCG.fill();
oCG.restore();
}

利用新的坐标Buttle[i].x和Buttle[i].y绘制一个圆。

第10点:图片发射的子弹和轨迹上的小圆碰撞检测

 //构建碰撞检测函数
function pz(x1,y1,x2,y2){
var a=x1-x2;
var b=y1-y2;
var c=Math.sqrt(a*a+b*b);
if(c<60){ //如果两圆心的距离小于60
return true
}
else{
return false
} }

第11点:碰撞检测后让发射的子弹和轨迹上的小圆消失

 for(var i=0;i<Buttle.length;i++){
for(var j=0;j<ball.length;j++){
if(pz(Buttle[i].x,Buttle[i].y,ball[j].x,ball[j].y)){
Buttle.splice(i,1);
ball.splice(j,1);
break;
}
}
}

让子弹和轨迹上的小圆消失,让构建的两个json splice即可。

注意,每次绘画的时候,要clearRect,设置在一个1000/60ms定时器内,静态的图形clear后再绘制依旧是静态的,但是动态生成的图形,在经过定时器后,绘制的是1000/60ms后的图形。图片的dragImage必须是在 onload事件下的,为了不影响图片加载,程序也是在onload事件下的。

以上就是我对这道题的理解。因为时间仓促,里面难免有些语句有错误,恳请大家斧正。

下面是程序的源代码。

    window.onload=function(){
var oC=document.getElementById('canvas1');
var oCG=oC.getContext('2d');
//设置图形
var oimg= new Image();
oimg.src='1.jpg' ;
oimg.onload=function(){
//重新绘制实现动画效果,每次先清空上次一次绘画的,过一段时间,然后再画下一次绘画的,静态不变,东西改变,实现了动的效果
setInterval(function(){
oCG.clearRect(0,0,oC.width,oC.height);
//外大圆
oCG.beginPath();
oCG.arc(400,400,250,-90*Math.PI/180,180*Math.PI/180,false);
oCG.stroke();
//内小圆
oCG.beginPath();
oCG.arc(350,400,200,180*Math.PI/180,0,false);
oCG.stroke();
//末尾圆
oCG.beginPath();
oCG.arc(550,400,30,0,360*Math.PI/180,false);
oCG.stroke();
//起始圆围绕曲线做圆周运动,把每一个已经动态变过的小圆的横纵坐标赋给新圆坐标,
// 达到到新位置1000/60ms,每350ms从原起点生成一个新的ball的效果
for(var i=0;i<ball.length;i++){
oCG.beginPath();
oCG.moveTo(400,150);
oCG.arc(ball[i].x,ball[i].y,30,0,360*Math.PI/180,false);
oCG.fill();
}
//设置字体
oCG.font="100px impact";
oCG.textBaseline='top';
oCG.fillText("hello",280,700);
//让图片顺在中心转起来
var picX=(oC.width-oimg.offsetWidth)/2;
var picY=(oC.height-oimg.offsetHeight)/2;
oCG.save(); //为了不受定时器影响,sava起来
oCG.translate(picX,picY);
oCG.rotate(-iRotate);
oCG.translate(-30,-30); //为了让图片沿着图片中心转动
oCG.drawImage(oimg,0,0);
// oCG.drawImage(oimg,(oC.width-oimg.offsetWidth)/2,(oC.height-oimg.offsetHeight)/2)
oCG.restore();
//子弹
for(var i=0;i<Buttle.length;i++){
oCG.save();
oCG.beginPath();
oCG.fillStyle='red';
oCG.moveTo(Buttle[i].x,Buttle[i].y);
oCG.arc(Buttle[i].x,Buttle[i].y,30,0,360*Math.PI/180,false);
oCG.fill();
oCG.restore();
}
},1000/60);
//循环每一个ball,动态去改变每一个原心的坐标,
setInterval(function(){
for(var i=0;i<ball.length;i++){
ball[i].num++; // 圆角度由0-360
if(ball[i].num==270){// 如果角度变为270度,改变ball的起始点坐标,就是改变它的轨迹。
ball[i].r=200;
ball[i].X=350;
ball[i].Y=200;
}
else if(ball[i].num==360+45+45
){
confirm('你失败了!点击确定重来!');
window.location.reload()
}
ball[i].x=Math.sin(ball[i].num*Math.PI/180)*ball[i].r+ball[i].X; //小圆横坐标
ball[i].y=ball[i].r-Math.cos(ball[i].num*Math.PI/180)*ball[i].r+ball[i].Y;//小圆的纵坐标
}
//图片吐子弹的路径,获得吐到子弹终点的坐标
for(var i=0;i<Buttle.length;i++){
Buttle[i].x=Buttle[i].x+Buttle[i].iSpeedX; //子弹终点横坐标
Buttle[i].y=Buttle[i].y+Buttle[i].iSpeedY; //子弹终点纵坐标
}
//碰撞检测
for(var i=0;i<Buttle.length;i++){
for(var j=0;j<ball.length;j++){
if(pz(Buttle[i].x,Buttle[i].y,ball[j].x,ball[j].y)){
Buttle.splice(i,1);
ball.splice(j,1);
break;
}
}
}
},1000/60);
//开定时器,每350ms添加一个ball
var ball=[];
setInterval(function(){
ball.push({
x:400, //小圆起始点横坐标
y:150, //小圆起始点纵坐标
r:250, //大圆的半径
num:0, //小圆转过的角度
//必须新建一个小圆的横纵坐标,否则小圆会飞出去。
X:400, //小圆起始点横坐标
Y:150 //小圆起始点纵坐标
})
},400);
//让图片跟着鼠标转,原理就是求图片纵坐标与鼠标与图片中心的距离的夹角。把这个夹角附给
//图片旋转的角度
var iRotate=0;
oC.onmousemove=function(ev){
oEvent=ev||event;
var a=oEvent.clientX-oC.offsetLeft-(oC.width-oimg.offsetWidth)/2;
var b=oEvent.clientY-oC.offsetTop-(oC.height-oimg.offsetHeight)/2;
iRotate=Math.atan(a/b);
};
//让图片吐子弹
var Buttle=[];
oC.onmousedown=function(ev){
oEvent=ev||event;
var a=oEvent.clientX-oC.offsetLeft-(oC.width-oimg.offsetWidth)/2;
var b=oEvent.clientY-oC.offsetTop-(oC.height-oimg.offsetHeight)/2;
var iSpeed=5;
var c=Math.sqrt(a*a+b*b); //鼠标距离图片中心的距离
var iSpeedX=iSpeed*a/c; //横轴分得到的速度
var iSpeedY=iSpeed*b/c; //纵轴分得到的速度
Buttle.push({
x:(oC.width-oimg.offsetWidth)/2,
y:(oC.height-oimg.offsetHeight)/2,
iSpeedX:iSpeedX,
iSpeedY:iSpeedY
})
}
};
//构建碰撞检测函数
function pz(x1,y1,x2,y2){
var a=x1-x2;
var b=y1-y2;
var c=Math.sqrt(a*a+b*b);
if(c<60){ //如果两圆心的距离小于60
return true
}
else{
return false
} }
}

canvas学习作业,模仿做一个祖玛的小游戏的更多相关文章

  1. html5面向对象做一个贪吃蛇小游戏

    canvas加面向对象方式的贪吃蛇 2016-08-25 这个小游戏可以增加对面向对象的理解,可以加强js逻辑能力,总之认真自己敲一两遍收获还是不少啊!!适合刚学canvas的同学练习!! 废话不多说 ...

  2. 用Python做一个简单的小游戏

    学习总是枯燥的,对于Python小白的我来讲,更是乏味的.为了提高学习的兴趣,今天我就来写一个小程序练练手. 数字猜谜游戏相信大家都不陌生,A给出最小值最大值,B写一个该范围内的数,A猜测写下的是多少 ...

  3. 用原生javascript做的一个打地鼠的小游戏

    学习javascript也有一段时间了,一直以来分享的都是一些概念型的知识,今天有空做了一个打地鼠的小游戏,来跟大家分享一下,大家也可以下载来增加一些生活的乐趣,下面P出代码:首先是HTML部分代码: ...

  4. 今天来做一个PHP电影小爬虫。

    今天来做一个PHP电影小爬虫.我们来利用simple_html_dom的采集数据实例,这是一个PHP的库,上手很容易.simple_html_dom 可以很好的帮助我们利用php解析html文档.通过 ...

  5. 跟我一起做一个vue的小项目(二)

    这个vue项目是紧跟着之前的项目跟我一起做一个vue的小项目(一)来的. 我继续后面的开发(写的比较粗糙,边学边记录) 下图是header头部的样式 header组件内容如下 //header.vue ...

  6. 【C语言探索之旅】 第一部分第八课:第一个C语言小游戏

    ​ 内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写 ...

  7. python小练习:使用循环和函数实现一个摇骰子小游戏。游戏规则如下:游戏开始,首先玩家选择Big or Small(押大小),选择完成后开始摇三个骰子,计算总值,11<=总值<=18为“大”,3<=总值<=10为“小”。然后告诉玩家猜对或者是猜错的结果。

    python小练习:使用循环和函数实现一个摇骰子小游戏.游戏规则如下:游戏开始,首先玩家选择Big or Small(押大小),选择完成后开始摇三个骰子,计算总值,11<=总值<=18为“ ...

  8. 用Nodejs做一个简单的小爬虫

    Nodejs将JavaScript语言带到了服务器端,作为js主力用户的前端们,因此获得了服务器端的开发能力,但除了用express搭建一个博客外,还有什么好玩的项目可以做呢?不如就做一个网络爬虫吧. ...

  9. Canvas学习实践:一款简单的动画游戏

    最近学习了下Canvas绘图...突发奇想就有了下面这款简单的小游戏,纯属娱乐~ 废话不多说,直接上代码: <!DOCTYPE html> <html lang="zh&q ...

随机推荐

  1. 【POJ3071】Football - 状态压缩+期望 DP

    Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, …, 2 ...

  2. 【Spring注解驱动开发】如何实现方法、构造器位置的自动装配?我这样回答让面试官很满意!

    在 冰河技术 微信公众号前面的文章中,我们介绍了如何使用注解来自动装配Spring组件.之前将的都是在来的字段上添加注解,那有没有什么方法可以实现方法.构造器位置的自动装配吗?今天我们就一起来探讨下如 ...

  3. 用python进行实际地址经纬度提取

    实际地址经纬度提取 请求接口: https://apis.map.qq.com/ws/place/v1/suggestion/ 所需参数: 参数名称 是否必须 参数类型 说明 keyword 是 St ...

  4. puppeteer去掉同源策略及请求拦截

    puppeteer是一个功能强大的工具,在自动化测试和爬虫方面应用广泛,这里谈一下如何在puppeteer中关掉同源策略和进行请求拦截. 同源策略 同源策略为web 安全提供了有力的保障,但是有时候我 ...

  5. 7. oracle表的管理*

    一.表名和列名的命名规则: 1.必须以字母开头 2.长度不能超过30个字符 3.不能使用oracle的保留字 4.只能使用如下字符 A-Z,a-z,0-9,$,#等 二.Oracle数据类型1.字符类 ...

  6. 牛客网PAT练兵场-锤子剪刀布

    题目地址:https://www.nowcoder.com/questionTerminal/79db907555c24b15a9c73f7f7d0e2471 题解:无 /** * *作者:Ycute ...

  7. Docker 最常用的镜像命令和容器命令

    本文列出了 Docker 使用过程中最常用的镜像命令和容器命令,以及教大家如何操作容器数据卷,实现容器数据的备份.熟练练习这些命令以后,再来一些简单的应用部署练习,大家就可以学习 Docker 的镜像 ...

  8. Cassandra社区是怎么测试4.0的

    点击查看活动录像,获取更多技术细节. Cassandra社区是怎么测试4.0的 Cassandra 4.0的目标就是成为史上最稳定的版本.为了达到这个目的,我们需要用很多方法和工具进行测试.我今天主要 ...

  9. 技术揭秘:华为云DLI背后的核心计算引擎

    摘要:介绍隐藏在华为云数据湖探索服务背后的核心计算引擎Spark,玩转DLI,,轻松完成大数据的分析处理. 本文主要给大家介绍隐藏在华为云数据湖探索服务(后文简称DLI)背后的核心计算引擎——Spar ...

  10. 企业站如何做长尾关键词seo优化

    http://www.wocaoseo.com/thread-315-1-1.html     很多企业站,优化到一定程度后网站的流量很快就上去了,但是之后网站就无法更进一步.那么对于普通中小型企业站 ...