最近去看了看JavaScript,语法啥的比较简单,加上能页面显示,那写个小游戏就无可厚非了。
js新手,第一次写,主要还是学习吧。
首先写个简单的页面文件

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="game.js"></script>
    <link rel="stylesheet"  href="./css/game.css" />
    <meta charset="UTF-8">
    <title>game</title>
</head>
<body>
    <canvas id="canvas" >
    </canvas>
    <button onclick="begin()">begin</button><br>
</div>
</body>
</html>

写个css:

#canvas {
    width: 800px;
    height: 800px;
    position: relative;
    background: yellow;
}

开始主要的game.js
首先是获取画布,然后写个刷新画布的函数,包括一个分数和生命的显示函数
js中虽有数据类型,但变量一律用var来声明(不写也行),且均为全局(哪怕在函数中声明),想要单独的局部变量(比如for里的i),可以用let声明)
函数使用function声明

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var reflshflag=0;
function refresh(){
    //刷新屏幕
    if(reflshflag>4){
        canvas.height=canvas.height;
        reflshflag=0;
        paintText();
    }else{reflshflag++}
}
function paintText(){
    context.font = "bold 10px 微软雅黑";
    context.fillText("SCORE:" + score,20,20);
    context.fillText("LIFE:" + hero.life,20,130);
    context.fillText("BIGBONG:" + hero.bigbongtime,20,140);
}

js中存在一个叫“变量提升”的机制,在启动时会把所有声明提升到最前,所以哪怕在后面声明的函数与变量,也可以在前面被引用(与c、java等不同)

var speed=2;
var MaxEnemy=30;
var nowEnemy=0;
var state=1;//用于切换游戏状态
var EnemyWhite={EnemyLevel:5,speed:1,life:5,color:"White"};
var EnemyGreen={EnemyLevel:1,speed:2,life:1,color:"green"};
var EnemyBlue={EnemyLevel:3,speed:3,life:2,color:"blue"};
var EnemyRed={EnemyLevel:3,speed:6,life:1,color:"red"};
var score=0;

定义一些变量,
JS中的对象类型,十分类似py中的字典,以name:value的方式写,且通过EnemyBlue.life的方式获取

函数中也能有变量和函数,可以当作类来用
下面创建我方飞机类

// 我方飞机的构造函数
function Hero(){
     this.imgs = new Image(20,20);
     this.imgs.src ="you.jpg";//图片地址
     this.imgs.width=20;
     this.imgs.height=20;
     this.length = 15;
     this.width = 15;
     this.height = 15;
     this.bigbongtime=6;
     this.bulletflag=0;

     // 定义飞机的坐标
     this.x = 120;
     this.y = 130;
     this.life=3;

     // 绘制方法
     this.paint = function(){
         context.drawImage(this.imgs,this.x,this.y);
     }
     this.bigbongflag = 0;
     //内置射击cd计时器
     this.shoot = function(){
         this.bulletflag++;
         this.bigbongflag ++;
     }
     this.bang = function(){
         this.life --;
     }
 }

创建一个hero,同时获取页面中的body,为其加上按键捕捉事件keydown,为了能及时响应,所以还得加上一个监听器去监听事件
addEventListener(‘keydown’,function (event){
-------------------
}

var hero = new Hero();
var body = document.getElementsByTagName('body')[0];
body.addEventListener('keydown',function (event){
	switch(event.keyCode){
	case 65:
	case 37://左
	    hero.x-=5*speed;
	    break;
	case 87:
	case 38: //上
	    hero.y-=5*speed;
	    break;
	case 68:
	case 39:  //右
	    hero.x+=5*speed;
	    break;
	case 83:
	case 40:  //下
	    hero.y+=5*speed;
	    break;
	case 74:
	    if(bulletflag >=33){
	        bulletflag=0;
	    bullets.push(new Bullet())};
	    break;
	case 73:
	    if(hero.bigbongflag >=50){
	        hero.bigbongflag=0;
	        bigbong();}
	    break;
	}
	 //console.log("move "+i+" in "+speed );
},false)

以上用于检测按键,wasd控制移动,j发射子弹,i使用炸弹

接下来生成敌人
这里有两个参数,敌人的配置,创建的地址,配置就是上面写的那些

function Enemy(config,createaddress){
	this.EnemyLevel = config.EnemyLevel;
	this.speed = config.speed;
	this.life = config.life;
	this.img = new Image(20,20);
	this.img.src =config.color+".jpg";
	this.img.maxwidth=20;
	this.img.height=20;
	// 坐标
	this.x = createaddress;
	this.y = 0;
	// 绘制
	this.paint = function(){
	   context.drawImage(this.img,this.x,this.y);
	}
	// 运动
	this.step = function(){
	   this.y +=0.1*this.speed;
	}
	//碰撞检测,可能是子弹,可能是我方飞机
	this.checkHit = function(zd){
	   return zd.y + zd.height > this.y
	       && zd.x + zd.width > this.x
	       && zd.y < this.y + 20
	       && zd.x < this.x + 20
	}
	// 撞击的方法
	this.bang = function(){
	   this.life -- ;
	}
}

有了构造函数就可以写个创建函数了
使用数组来存储对象,这里面数组类似list,使用push向最后加入元素,使用.splice(i,n)删除从第i个位置开始的n个元素
随机数生成Math.floor(Math.random()*100);
随机生成不同等级的敌人

var enemies = [];
var enemyflag=0;//敌人生成的cd0.33秒一个
function createEnemy() {
    enemyflag++;
    if(enemyflag % 33 ==0){
        if(nowEnemy<=MaxEnemy){
            nowEnemy+=1;
            let createAddress = Math.floor(Math.random()*800);
            let enemytype = Math.floor(Math.random() * 100);
            if(enemytype < 10){
                enemies.push(new Enemy(EnemyWhite,createAddress));
            }else if(enemytype >= 10 && enemytype <35){
                enemies.push(new Enemy(EnemyGreen,createAddress));
            }else if(enemytype >= 35 && enemytype <70){
                enemies.push(new Enemy(EnemyBlue,createAddress));
            }else if(enemytype >= 70 && enemytype <100){
                enemies.push(new Enemy(EnemyRed,createAddress));
            }
        }
    }

}

由于敌人数量众多,我们为了让敌人移动,还得专门写一个对所有敌人操作的函数
通过数组的length获得数组长度

function Enemiesdo(){
   for(var i = 0;i < enemies.length;i++){
       enemies[i].paint();// 敌人绘制函数
       enemies[i].step();// 敌人运动
       // 敌人死亡,两种情况
       if(enemies[i].y > 140){
           enemies.splice(i,1);
           nowEnemy--;
       }
       if(enemies[i].life<=0){
           score=enemies[i].EnemyLevel+score;
           enemies.splice(i,1);
           nowEnemy--;
       }

	//碰撞检测
       if(enemies[i].checkHit(hero)){
           score+=enemies[i].EnemyLevel;
           enemies.splice(i,1);
           nowEnemy--;
           hero.bang();
           if(hero.life<=0) {state=2;paintText();}
       }
       // 子弹撞
       for(var j = 0;j < bullets.length;j++){
           if(enemies[i].checkHit(bullets[j])){
               enemies[i].bang();
               bullets[j].bang();
           }
       }
   }
}

接下来是子弹的类,基本原理相同
我这里只有一种子弹,所以没写更多东西,如果考虑拥有多种弹药,可以如同敌人函数一般使用config读取不同伤害、射速、图标的子弹,再在hero中加个当前子弹类型的flag,用于切换

function Bullet(){
//多种子弹function Bullet(config,typeflag)
    this.str = new Image(5,5);this.str.src="pong.jpg";
    this.str.width=5;
    this.str.height=5;
    this.width = 10;
    this.height = 10;
    // 坐标
    this.x = hero.x + hero.width/2 - this.width/2;
    this.y = hero.y - this.height;
    // 绘制
    this.paint = function(){
        context.drawImage(this.str,this.x,this.y);
    }
    // 运动
    this.step = function(){
        this.y -=0.2;
    }
    this.life=1;
    // 撞击的方法,用于修改子弹是否碰撞的属性
    this.bang = function(){
        this.life--;
    }
}

同样用一个数组来存储子弹,并用一个统一的函数来对子弹进行操作

//存储子弹
var bullets = [];
function bulletsdo(){
    for(var i = 0;i < bullets.length;i++){
        bullets[i].paint();// 绘制所有子弹
        bullets[i].step();// 子弹运动
        //子弹删除
        if(bullets[i].y < -bullets[i].height || bullets[i].life<=0){
            bullets.splice(i,1);
        }
    }
}

自此,飞机大战的要素,飞机-敌人-子弹都有了
开始游戏
通过setInterval来进行(该函数会定时循环运行)

//进程主循环
function begin(){
	setInterval(function(){
	      switch (state) {
	          case 1:
	              reflsh();
	              hero.paint();
	              hero.shoot();
	
	              bulletsdo();
	
	              createEnemy();
	              Enemiesdo();
	              break;
	          case 2:
	              break;
	      }
  	},10);
  }
//每10毫秒运行一次,相当于1秒100帧

运行页面,开始游戏吧!

(飞机图片自己找了放到目录里,我随便截到图,都没扣背景)

javascript飞机大战代码 js飞机大战编程_数组

大概就这个样子吧

有时间再写个贪吃蛇