效果图:
1:index.html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>**</title>
<style type="text/css">
#controller {
position: fixed;
top: 94%;
width: 100%;
}
#up{
position: absolute;
margin-top: -34px;
}
#down{
position: absolute;
margin-top: 34px;
}
#right{
margin-left: 34px;
}
#openfire{
float: right;
}
</style>
<script src="pj_game.js?v=2" type="text/javascript" charset="UTF-8"></script>
</head>
<body style="height: 100%; width: 100%; background-color:;">
<div id="controller">
键盘控制:A键开火,上下左右键移动
<button id="left">左</button>
<button id="up">上</button>
<button id="down">下</button>
<button id="right">右</button>
<button id="openfire">开火</button>
</div>
<div class="pj_tanks_myself" pj_tank_name="自己人" pj_color="green"
pj_tank_HP="100000000" pj_tank_radius="50" style="display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
pj_tank_radius="100" style="width: 300px; height: 70px; display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
pj_tank_radius="100" style="width: 300px; height: 70px; display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
style="width: 300px; height: 70px; display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
pj_tank_radius="100" style="width: 300px; height: 70px; display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
pj_tank_radius="100" style="width: 300px; height: 70px; display: none"></div>
<div class="pj_tanks_employee" pj_tank_name="敌人" pj_color="black"
style="width: 300px; height: 70px; display: none"></div>
</body>
<script type="text/javascript">
</script>
</html>
2.pj_game.js文件
var PJ = (function(document) {
var pjCanvas;
var pjTankCanvas;
var $ = function() {
}
$.init = function() {
};
$.htmlobj = function(classselector) {
return document.getElementsByClassName(classselector);
}
$.each = function(list, callback) {
for (var i = 0; i < list.length; i++) {
callback(list[i], i);
}
}
$.pj_tank_canvas = function() {
if (pjTankCanvas == undefined || pjTankCanvas == null)
pjTankCanvas = new CANVAS("pj_tank");
return pjTankCanvas;
}
return $;
})(document);
var util;
var tankCanvas;
var MY_TANK_FIRE_LAZY_TIME = 100;
var PJ_Util = function() {
};
PJ_Util.prototype = {
getStrLength : function($) {
var len = $.replace(/[\u0391-\uFFE5]/g, "aa").length;// 先把中文替换成两个字节的英文
return len;
},
isEmpty : function($) {
if ($ == undefined || $ == null) {
return true;
}
return false;
},
getRandomChar : function($) {
var index = (Math.floor((Math.random() * 10))) % $.length
return $.charAt(index)
},
getRandom : function($) {
return (Math.floor((Math.random() * $)));
},
isRectIntersection:function(r1,r2){// 连个矩形相交
if(r1.x+r1.w < r2.x || r1.x>r2.x+r2.w || r1.y+r1.h<r2.y||r1.y>r2.y+r2.h){
return false;
}else{
return true;// 相交
}
},
getWindomWidth:function(){
var b = document.getElementsByTagName("html")[0];
return b.clientWidth;
},
getWindomHeight:function(){
var b = document.getElementsByTagName("html")[0];
return b.clientHeight;
},
getElementById:function(id){
var b = document.getElementById(id);
return b;
}
}
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
Array.prototype.remove = function (obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
this.splice(i,1);
}
}
}
util = new PJ_Util();
var Position = function(x, y, direction, radius) {
this.x = x;
this.y = y;
this.direction = direction;// 0右1左2下3上
this.radius = radius;// 半径
};
Position.prototype = {
setDirection : function($) {
this.direction = $;
}
};
/**
* 矩形
*/
var PJ_RECT = function(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
var CANVAS = function(name) {
this.name = name;
this.canvas = this.create();
this.ctx = this.canvas.getContext("2d");// 画笔
};
CANVAS.prototype.create = function() {
var id = "pj_canvas_" + this.name;
var canvasdiv = document.createElement("canvas");
canvasdiv.setAttribute("style", "position: absolute;z-index:-1;left:0;top:0;background-color:transparent;");
canvasdiv.setAttribute("id",id)
canvasdiv.setAttribute("width",util.getWindomWidth())
canvasdiv.setAttribute("height",util.getWindomHeight())
document.body.appendChild(canvasdiv);
return canvasdiv;
};
var PJ_TANK = function($) {
this.canvas = tankCanvas.canvas;
this.ctx = tankCanvas.ctx;// 画笔
var radius = util.isEmpty($.getAttribute("pj_tank_radius"))?10:Number($.getAttribute("pj_tank_radius"));
this.position = new Position(util.getWindomWidth()*Math.random(), util.getWindomHeight()*Math.random(),
util.getRandomChar("0123"), radius);
this.initRadius = this.position.radius;
this.bigCls = 1;
this.color = util.isEmpty($.getAttribute("pj_color")) ? "gray" : $
.getAttribute("pj_color");
this.name = util.isEmpty($.getAttribute("pj_tank_name")) ? "PJ_TANK" : $
.getAttribute("pj_tank_name");
this.bodyRect;
this.turretRect;
this.speed = util.isEmpty($.getAttribute("pj_speed")) ? 1 : Number($
.getAttribute("pj_scroll_text"));// 速度
this.autoPositionSpeed = 1000;// 自动换方向时间
this.autoAutoFireSpeed = 10000;// 自动换方向时间
this.activeRect = new PJ_RECT(this.canvas.offsetLeft,
this.canvas.offsetTop, this.canvas.offsetWidth,
this.canvas.offsetHeight);// 活动矩形范围
this.namesize = this.position.radius / 4;
this.bullet;
this.firedbullets = [];// 已经发射的子弹
this.HP =util.isEmpty($.getAttribute("pj_tank_HP"))?1000:Number($.getAttribute("pj_tank_HP"));// 生命值
this.OLDHP = this.HP;// 初始生命值
this.ATK =200;// 攻击力
this.DEF = 200;// 防御力
this.score;
this.fireLazyTime = 0;// 开火延迟时间
};
PJ_TANK.prototype = {
setSpeed : function($) {
this.speed = $;
},
drow : function() {
if(this.HP){
this.setPaopao();
this.drowBody();
this.drowTurret();
this.drowName();
this.drowHP();
this.drowBullets();
}
},
setPaopao:function(){
if(this.bigCls){
if(this.position.radius-this.initRadius<this.initRadius/4){
this.position.radius = this.position.radius+0.2;
}else{
this.bigCls = 0;
}
}else{
if(this.position.radius-this.initRadius>0){
this.position.radius = this.position.radius-0.2;
}else{
this.bigCls = 1;
}
}
},
fire : function() {
if(this.HP && this.fireLazyTime == 0){
this.firedbullets.push(this.bullet);
}
},
drowHP:function(){
this.ctx.font = this.namesize + "px Georgia";
this.ctx.fillStyle = "BLUE";//
this.ctx.strokeRect(this.position.x - this.position.radius,this.position.y - this.position.radius-this.namesize-10,this.position.radius*2,10);
this.ctx.fillRect(this.position.x - this.position.radius,this.position.y - this.position.radius-this.namesize-10,this.position.radius*2*this.HP/this.OLDHP,10);
},
drowBullets : function() {
for (var i = 0; i < this.firedbullets.length; i++) {
var b = this.firedbullets[i];
if (!b.alive) {
this.firedbullets.splice(i, 1);
}
}
for (var i = 0; i < this.firedbullets.length; i++) {
var b = this.firedbullets[i];
b.move();
}
},
drowBody : function() {
// 画一个实心圆
this.ctx.beginPath();
this.ctx.arc(this.position.x, this.position.y, this.position.radius, 0,
360, false);
this.ctx.closePath();
this.ctx.fillStyle = this.color;// 填充颜色,默认是黑色
this.ctx.fill();// 画实心圆
this.bodyRect = new PJ_RECT(this.position.x - this.position.radius,
this.position.y - this.position.radius,
this.position.radius * 2, this.position.radius * 2);
},
drowName : function() {
this.ctx.font = this.namesize + "px Georgia";
this.ctx.fillText(this.name, this.position.x - this.position.radius,
this.position.y - this.position.radius);
},
drowTurret : function() {
this.ctx.fillStyle = "red";// 填充颜色,默认是黑色
var w = this.position.radius / 4;
var l = this.position.radius + this.position.radius / 2;
var bp;
switch (Number(this.position.direction)) {
case 0:// 向右
this.turretRect = new PJ_RECT(this.position.x, this.position.y - w
/ 2, l, w);
bp = new Position(this.turretRect.x + this.turretRect.w,
this.turretRect.y + this.turretRect.h / 2, 0,
this.turretRect.h / 2);
break;
case 1:// 向左
this.turretRect = new PJ_RECT(this.position.x - l, this.position.y
- w / 2, l, w);
bp = new Position(this.turretRect.x, this.turretRect.y
+ this.turretRect.h / 2, 1, this.turretRect.h / 2);
break;
case 2:// 向下
this.turretRect = new PJ_RECT(this.position.x - w / 2,
this.position.y, w, l);
bp = new Position(this.turretRect.x + this.turretRect.w / 2,
this.turretRect.y + this.turretRect.h, 2,
this.turretRect.w / 2);
break;
case 3:// 向上
this.turretRect = new PJ_RECT(this.position.x - w / 2,
this.position.y - l, w, l);
bp = new Position(this.turretRect.x + this.turretRect.w / 2,
this.turretRect.y, 3, this.turretRect.w / 2);
break;
default:
this.turretRect = new PJ_RECT(this.position.x, this.position.y - w
/ 2, l, w);
break;
}
this.ctx.beginPath();
this.ctx.arc(this.position.x, this.position.y, w, 0,
360, false);
this.ctx.closePath();
this.ctx.fill();// 画实心圆
this.ctx.fillRect(this.turretRect.x, this.turretRect.y,
this.turretRect.w, this.turretRect.h);
this.bullet = new PJ_BULLET(bp);
this.bullet.ATK = this.ATK;// 初始化子弹攻击力
},
move : function() {
switch (Number(this.position.direction)) {
case 0:// 向右
this.position = new Position(this.speed + this.position.x,
this.position.y, 0, this.position.radius);
break;
case 1:// 向左
this.position = new Position(this.position.x - this.speed,
this.position.y, 1, this.position.radius);
break;
case 2:// 向下
this.position = new Position(this.position.x, this.position.y
+ this.speed, 2, this.position.radius);
break;
case 3:// 向上
this.position = new Position(this.position.x, this.position.y
- this.speed, 3, this.position.radius);
break;
default:
this.position = new Position(this.position.x + this.speed,
this.position.y, 0, this.position.radius);
break;
}
this.drow();
},
autoMove : function() {
var self = this;
self.move();
self.autoBorderPosition();
},
autoBorderPosition : function() {// 边界自动方向
if (this.bodyRect) {
if ("0" == this.position.direction
&& this.bodyRect.x + this.bodyRect.w >= this.activeRect.x
+ this.activeRect.w) {
this.position.setDirection(util.getRandomChar("123"));
} else if ("1" == this.position.direction
&& this.bodyRect.x <= this.activeRect.x) {
this.position.setDirection(util.getRandomChar("023"));
} else if ("2" == this.position.direction
&& this.bodyRect.y + this.bodyRect.h >= this.activeRect.y
+ this.activeRect.h) {
this.position.setDirection(util.getRandomChar("013"));
} else if ("3" == this.position.direction
&& this.bodyRect.y <= this.activeRect.y) {
this.position.setDirection(util.getRandomChar("012"));
}
}
},
autoPosition : function() {
var self = this;
PJ_requestAnimFrame(function() {
self.position.setDirection(util.getRandomChar("0123"));
self.autoPosition();
self.autoPositionSpeed = Math
.floor((Math.random() * self.canvas.width));
}, self.autoPositionSpeed);
},
setReward:function(){
this.HP += 100;// 生命值
this.OLDHP += 100;// 初始生命值
this.ATK +=20;// 攻击力
this.position.radius+=5;
this.initRadius+=5;
}
}
var PJ_BULLET = function($) {
this.canvas = tankCanvas.canvas;
this.ctx = tankCanvas.ctx;// 画笔
this.position = $;
this.speed = 3;
this.color = "blue";
this.ATK;// 攻击力
this.rect = new PJ_RECT(this.position.x - this.position.radius,
this.position.y - this.position.radius,
this.position.radius * 2, this.position.radius * 2);
this.alive = 1;
}
PJ_BULLET.prototype = {
drow : function() {
this.outborder();
this.initStyle();
},
initStyle : function() {
this.ctx.beginPath();
this.ctx.arc(this.position.x, this.position.y, this.position.radius, 0,
360, false);
this.ctx.closePath();
this.ctx.fillStyle = this.color;// 填充颜色,默认是黑色
this.ctx.fill();// 画实心圆
this.rect = new PJ_RECT(this.position.x - this.position.radius,
this.position.y - this.position.radius,
this.position.radius * 2, this.position.radius * 2);
},
move : function() {
switch (Number(this.position.direction)) {
case 0:// 向右
this.position = new Position(this.speed + this.position.x,
this.position.y, 0, this.position.radius);
break;
case 1:// 向左
this.position = new Position(this.position.x - this.speed,
this.position.y, 1, this.position.radius);
break;
case 2:// 向下
this.position = new Position(this.position.x, this.position.y
+ this.speed, 2, this.position.radius);
break;
case 3:// 向上
this.position = new Position(this.position.x, this.position.y
- this.speed, 3, this.position.radius);
break;
default:
this.position = new Position(this.position.x + this.speed,
this.position.y, 0, this.position.radius);
break;
}
this.drow();
},
outborder : function() {
if (this.position.x >= this.canvas.width || this.position.x <= 0
|| this.position.y >= this.canvas.height
|| this.position.y <= 0) {
this.alive = 0;
}
}
}
// 爆炸对象
var PJ_BLAST = function(x,y){
this.canvas = tankCanvas.canvas;
this.ctx = tankCanvas.ctx;// 画笔
this.position = new Position(x,y);
this.cellList = [];
this.borderRange = y+100;
this.alive=1;
this.gravity=0.5;
var cellNum=3*Math.floor(Math.random()*10+10);
for(var i=0;i<cellNum;i++)
{
this.cellList.push(this.createCell(x,y));
}
}
PJ_BLAST.prototype = {
createCell:function(x,y) {
var myCell={
die:false,
posx:x,
posy:y,
vx:(Math.random()-0.5)*8*2,
vy:(Math.random()*(-6)-3)*2,
radius:Math.random()*2+1,
color:255
};
return myCell;
},
drowCell:function()
{
this.ctx.lineWidth=2;
var self = this;
this.cellList.forEach(function (e) {
self.ctx.strokeStyle = "rgb("+ 0+","+0+","+e.color+")";
self.ctx.beginPath();
self.ctx.arc(e.posx,e.posy,e.radius,Math.random()*2*Math.PI,2*Math.PI);
self.ctx.stroke();
});
},
action:function(){
if(this.cellList.length>0)
{
var self = this;
this.cellList.forEach(function (e) {
e.posx=e.posx+e.vx;
e.vy=e.vy+self.gravity;
e.posy=e.posy+e.vy;
e.color=e.color-6;
if(e.posy>self.borderRange)
{
e.die=true;
}
});
}else{
this.alive=0;
}
for(var i=this.cellList.length-1;i>=0;i--)
{
if(this.cellList[i].die){
this.cellList.splice(i,1);
}
}
this.drowCell();
}
}
var PJ_ENEMY = function() {
this.tanks = [];
this.autoAddPJTank();
}
PJ_ENEMY.prototype = {
addTank : function($) {
this.tanks.push($);
},
autoAddPJTank : function() {
var list = PJ.htmlobj("pj_tanks_employee");
var self = this;
PJ.each(list, function(t) {
self.addTank(new PJ_TANK(t));
});
}
}
var PJ_CONTROLLER = function() {// 遥控器
this.keys = new Array();
this.keys = [37,38,39,40,65];
this.currentKeys = new Array();
}
PJ_CONTROLLER.prototype = {
conttrol : function($) {
var self = this;
window.onkeydown = function(e) {
if(self.keys.contains(e.keyCode)){
if(self.currentKeys.contains(65) && e.keyCode != 65){
if($.fireLazyTime == 0 ){
$.fire();
$.fireLazyTime=MY_TANK_FIRE_LAZY_TIME;
}
}
if(self.currentKeys.contains(38) ||self.currentKeys.contains(37)
|| self.currentKeys.contains(39) ||self.currentKeys.contains(40)
&& e.keyCode == 65){
$.move();
}
if (38 == e.keyCode) {// 上键
$.position.direction = 3;
$.move();
} else if (40 == e.keyCode) {// 下键
$.position.direction = 2;
$.move();
} else if (37 == e.keyCode) {// 左键
$.position.direction = 1;
$.move();
} else if (39 == e.keyCode) {// 右键
$.position.direction = 0;
$.move();
}else if (65 == e.keyCode ) {//
if($.fireLazyTime == 0 ){
$.fire();
$.fireLazyTime=MY_TANK_FIRE_LAZY_TIME;
}
}
self.currentKeys.push(e.keyCode);
}
};
window.onkeyup = function(e) {
if(self.keys.contains(e.keyCode)){
self.currentKeys.remove(e.keyCode);
}
};
util.getElementById("up").onclick = function(){
$.position.direction = 3;
$.move();
}
util.getElementById("down").onclick = function(){
$.position.direction = 2;
$.move();
}
util.getElementById("left").onclick = function(){
$.position.direction = 1;
$.move();
}
util.getElementById("right").onclick = function(){
$.position.direction = 0;
$.move();
}
util.getElementById("openfire").onclick = function(){
if($.fireLazyTime == 0 ){
$.fire();
$.fireLazyTime=MY_TANK_FIRE_LAZY_TIME;
}
}
}
}
var PJ_MYSELF = function() {
var list = PJ.htmlobj("pj_tanks_myself");
this.tank = new PJ_TANK(list[0]);
}
PJ_MYSELF.prototype = {
}
var PJ_GAME = function() {
this.tanks = [];
this.enemyTanks = new PJ_ENEMY().tanks;
this.myTank = new PJ_MYSELF().tank;
this.myTank.speed = 5;
this.canvas = tankCanvas.canvas;
this.ctx = tankCanvas.ctx;// 画笔
this.autoAutoFireSpeed = 2000;
this.blasts = [];
this.controller = new PJ_CONTROLLER();
}
PJ_GAME.prototype = {
start : function() {
this.autoAddPJTank();
this.autoMove();
this.autoFire();
this.controller.conttrol(this.myTank);
},
autoMove : function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
for (var i = 0; i < this.enemyTanks.length; i++) {
this.enemyTanks[i].autoMove();
}
this.myTank.drow();
if(this.myTank.fireLazyTime > 0 ){
--this.myTank.fireLazyTime;
}
this.allBlast();
var self = this;
PJ_requestAnimFrame(function() {
self.checkAlive();
self.autoMove();
}, 2);
},
allBlast:function(){
if(this.blasts.length>0){
for (var i = 0; i < this.blasts.length; i++) {
this.blasts[i].action();
}
for(var i=this.blasts.length-1;i>=0;i--)
{
if(!this.blasts[i].alive){
this.blasts.splice(i,1);
}
}
}
},
autoFire : function() {
for (var i = 0; i < this.enemyTanks.length; i++) {
this.enemyTanks[i].fire();
}
var self = this;
PJ_requestAnimFrame(function() {
self.autoFire();
}, self.autoAutoFireSpeed);
},
addTank : function($) {
$.autoPosition();// 自动转换方向
this.tanks.push($);
},
autoAddPJTank : function() {
var list = PJ.htmlobj("pj_tanks");
var self = this;
PJ.each(list, function(t) {
self.addTank(new PJ_TANK(t));
});
},
checkAlive:function(){
for(var i=0;i<this.myTank.firedbullets.length && this.myTank.HP;i++){
var mtfb = this.myTank.firedbullets[i];
var mr = mtfb.rect;
for(var em = 0;em<this.enemyTanks.length;em++){
var emtank = this.enemyTanks[em];
var ebr = emtank.bodyRect;
if(emtank.HP && util.isRectIntersection(mr,ebr)){
var hp = emtank.HP-this.myTank.firedbullets[i].ATK
emtank.HP= hp<0?0:hp;
if(hp<=0){
this.myTank.setReward();
}
this.myTank.firedbullets[i].alive = 0;
this.blasts.push(new PJ_BLAST(mtfb.position.x,mtfb.position.y));
}
for(var eb=0;eb<emtank.firedbullets.length;eb++){
var efr = emtank.firedbullets[eb].rect;
if(util.isRectIntersection(mr,efr)){
emtank.firedbullets[eb].alive = 0;
this.myTank.firedbullets[i].alive = 0;
this.blasts.push(new PJ_BLAST(mtfb.position.x,mtfb.position.y));
}
if(util.isRectIntersection(efr,this.myTank.bodyRect)){
var hp = this.myTank.HP-emtank.firedbullets[eb].ATK
this.myTank.HP= hp<0?0:hp;
if(hp<=0){
emtank.setReward();
}
emtank.firedbullets[eb].alive = 0;
this.blasts.push(new PJ_BLAST(emtank.firedbullets[eb].position.x,emtank.firedbullets[eb].position.y));
}
}
}
}
for(var em = 0;em<this.enemyTanks.length;em++){
var emtank = this.enemyTanks[em];
for(var eb=0;eb<emtank.firedbullets.length;eb++){
var efr = emtank.firedbullets[eb].rect;
if(this.myTank.HP && util.isRectIntersection(efr,this.myTank.bodyRect)){
var hp = this.myTank.HP-emtank.firedbullets[eb].ATK
this.myTank.HP= hp<0?0:hp;
if(hp<=0){
emtank.setReward();
}
emtank.firedbullets[eb].alive = 0;
this.blasts.push(new PJ_BLAST(emtank.firedbullets[eb].position.x,emtank.firedbullets[eb].position.y));
}
}
}
}
}
/**
* 自定义requestAnimFrame
*/
window.PJ_requestAnimFrame = (function() {
return function(callback, speed) {
window.setTimeout(callback, speed);// 自定义时间间隔动画
};
})();
window.onload = function() {
tankCanvas = PJ.pj_tank_canvas();
var game = new PJ_GAME();
game.start();
}