学习HTML、JS、CSS一段时间了。
作为一个男人,还是练习了经典动作:打飞机。
没有使用HTML的<div>标签这些内容,使用了canvas。
目前状态仅完成了基础的动画、敌方子弹、本体操作移动。先做个记录分享。
代码里面有些是调试时的冗余内容,没有删。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>横向移动</title>
<style>
#x3{
background-color: yellow;
}
.container{
position: relative;
background-color: rgba(80,255,80,1);
}
.container canvas {
position: absolute;
left: 0;
top: 0;
border: 1px solid black;
}
</style>
</head>
<body>
<h1>Test for Horizon Scroll</h1>
<p><input type="button" id="startBtn" value="点击开始"></p>
<div class="container">
<canvas id="canvas1" width="600px" height="300px"></canvas>
<canvas id="canvas2" width="600px" height="300px" tabindex="1"></canvas>
</div>
<div id="x3">
<p id="test"></p>
</div>
</body>
<script>
//类定义区域
//定义障碍物类
class Obstercal{
name; x; y; vx; vy;sizex;sizey;out;
draw(){
ctx.fillStyle="rgba(255,0,0,1)";
ctx.fillRect(this.x,this.y,this.sizex,this.sizey);
};
move2Left(){
ctx.clearRect(this.x,this.y,this.sizex,this.sizey);
this.x=this.x-this.vx;
if(this.x>0){
this.draw();
}else{
this.out=true;
}
};
};
//定义控制的对象类。
class Me{
name; x; y; vx; vy;sizex;sizey;out;
draw(){
ctx2.fillStyle="rgba(0,0,255,1)";
ctx2.fillRect(this.x,this.y,this.sizex,this.sizey);
};
move2Left(){
ctx2.clearRect(this.x,this.y,this.sizex,this.sizey);
this.x=this.x-this.vx;
if(this.x>0){
this.draw();
}else{
this.x=0
this.draw();
}
};
move2Right(){
ctx2.clearRect(this.x,this.y,this.sizex,this.sizey);
this.x=this.x+this.vx;
if(this.x<=canvas2.width-this.sizex){
this.draw();
}else{
this.x=canvas2.width-this.sizex;
this.draw();
}
};
move2Up(){
ctx2.clearRect(this.x,this.y,this.sizex,this.sizey);
this.y=this.y-this.vy;
if(this.y>=0){
this.draw();
}else{
this.y=0;
this.draw();
}
};
move2Down(){
ctx2.clearRect(this.x,this.y,this.sizex,this.sizey);
this.y=this.y+this.vy;
if(this.y<=canvas2.height-this.sizey){
this.draw();
}else{
this.y=canvas2.height-this.sizey;
this.draw();
}
};
};
//脚本主体运行区域
//全局变量及初始化定义
//获取Canvas对象
let canvas=document.getElementById("canvas1");
let canvas2=document.getElementById("canvas2");
//获取Canvas的2D context
let ctx=canvas.getContext("2d");
let ctx2=canvas2.getContext("2d");
//获取开始按钮对象
let startbtn=document.getElementById("startBtn");
//设置运行状态标志
let running=false;
//设置时间变量,用于做随机间隔计算使用
let lastTime=performance.now();
let currentTime=lastTime;
//设置障碍对象生成的随机下限、上限时间
let laserTriggerLow=200;
let laserTriggerHigh=1000;
//生成随机的间隔时间
let delay=getRandomIntInclusive(laserTriggerLow,laserTriggerHigh);
//创建一个数组用来存放障碍物对象
let obs=[];
let me=getMe(); //创建操作对象
//给画布添加按键监听、给按钮添加点击动作的函数
canvas2.addEventListener("keydown",moveMe);
startbtn.addEventListener("click",startGame);
//函数定义区域
//启动按钮响应函数
function startGame(){
running=true; //运行状态标记为true。
run();
}
//生成操作对象me的函数
function getMe(){
let me=new Me();
me.name="me";
me.x=canvas2.width/2;
me.y=canvas2.height/2;
me.vx=4;
me.vy=4;
me.sizex=10;
me.sizey=10;
me.draw();
return me;
}
//响应键盘的移动函数
function moveMe(e){
switch (e.key){
case "ArrowUp":
me.move2Up();
break;
case "ArrowDown":
me.move2Down();
break;
case "ArrowLeft":
me.move2Left();
break;
case "ArrowRight":
me.move2Right();
break;
};
}
//动画运行的主体函数
function run(){
canvas2.focus(); //将页面焦点到canvas2,用于用户控制me。
//如果运行标志为true。
if (running){
let anid=requestAnimationFrame(run);
currentTime = performance.now(); //将当前函数运行时间记录为当前时间。
//按一个间隔时间,生成障碍物,将障碍物压到数组中
if (currentTime - lastTime >= delay) {
getObs();
}
//对数组中的内容进行移动
for (let i=0;i<obs.length;i++){
//对于已经跑出画面的对象进行删除
if(obs[i].out){
obs.splice(i,1);
}else{
//未出画面的,进行移动
obs[i].move2Left();
}
//判断与操控的对象的冲突
let crashMark=crash(obs[i],me);
if(crashMark){
running=false;
break;
}
}
}else{
alert("Over");
}
}
//检查两个方块碰撞的函数
function crash(rect1, rect2){
if (rect1.x>rect2.x+rect2.sizex || rect1.y>rect2.y+rect2.sizey || rect1.x+rect1.sizex<rect2.x || rect1.y+rect1.sizey<rect2.y){
return false; //未碰撞
}
return true; //碰撞
}
//创建生成障碍物的对象函数
function getObs(){
let newObs=new Obstercal();
newObs.name="laser";
newObs.x=canvas.width;
newObs.y=getRandomIntInclusive(0,canvas.height);
newObs.vx=getRandomIntInclusive(1,4);
newObs.vy=0;
newObs.sizex=getRandomIntInclusive(10,40);
newObs.sizey=getRandomIntInclusive(2,5);
newObs.out=false;
newObs.draw();
obs.push(newObs);
lastTime=performance.now();
delay=getRandomIntInclusive(laserTriggerLow,laserTriggerHigh);
setTimeout(getObs,delay);
test.textContent=Date();
}
//在某个区间的随机数生成函数
function getRandomIntInclusive(min, max){
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}
//canvas整个页面清除的函数
function clear(){
ctx.clearRect(0,0,canvas.width,canvas.height);
}
</script>
</html>
记录下过程中的几个自学到的知识点:
- 按照一定随机时间间隔,执行某个动作,需要使用performance.now()做函数运行的时间记录,用于和间隔时间的比对使用。
- canvas的多层,使用css格式,对canvas进行位置重叠设置。
- break命令,进行结束循环的跳出。
- 自定义class,可以帮助简单复用生成对象。
- 使用单独的函数声明,然后和keydown事件绑定。
剩余的问题、功能:
- 结束后的reset还没做。
- 分数还没记录。
- 键盘响应长按时,默认有延迟的效果,还没做处理。