这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
一、总结关键点和遇到的问题 1.javascript 中的继承,最好父类只提供方法共享,属性写到各自子类中,避免父类和子类的构造函数混杂。 2.prototype 模拟继承的代码,应写在所有方法定义之前,否则原型对象被改变,方法就变成了未定义,如:
这篇文章主要介绍了 javascript 模拟坦克大战游戏关键点和遇到的问题及实现代码, 需要的朋友可以参考下
- Hero.prototype = new Tank (0, 0, 0);
- Hero.prototype.constructor = Hero;
- Hero.prototype.addLife = function(){
- this.lifetimes++;
- document.querySelector("#life").innerHTML = hero.lifetimes;
- }
3.canvas 画图形时,除了画矩形,其他的都要加上 ctx.beginPath();、ctx.closePath();,否则会出现意想不到的错误。 4.concat 函数可以合并数组,或者是元素返回一个新的数组 5.Image 的 src 属性赋值后就会加载图片,但如果没有加载完毕就画图片,会导致失效,所以使用 onload 事件处理 6. 扩展 Array 功能,删除指定元素
- //扩展 删除指定元素
- Array.prototype.deleteElement = function (obj) {
- if (obj) {
- for (var i = 0; i < this.length; i++) {
- if (this[i] === obj) {
- this.splice (i, 1);
- }
- }
- }
- }
7. 定时器设置,setInterval("fun",1000)方法的第一个参数,可以是字符串,如 "hero.say()", 类似 eval 会去执行这串代码,所以它可以给函数带上参数,并且也指定了这个函数的运行上下文。但如果传入是函数的句柄,则不能带参数,并且不能指定上下文,除了第一种方式解决外,我用了闭包来解决这个问题
- //定时器,自行运动
- this.timer = setInterval ((function (context) {
- return function () {
- Bullet.prototype.move.call (context)
- }
- }) (this), 30);
我保存了当前的执行环境,并调用 call 方法手动执行。 8. 方法的功能设计,除了功能外,应该包括执行此功能的条件检测,如 move,就应该包括什么情况下可以移动,移动到什么地方就不能移动了。此检测不应该放在外部。 9. 写代码时不应该去想设计或者优化的问题,先实现功能,再谈优化,或者先设计再实现。思路要清晰,别混乱,着重于一点。 10.javascript 中没有 sleep 的功能,可以创建一个变量作为缓冲,来达到间隔执行的目的 二、代码实现 1. 本程序分为 Bomb.js,Bullet.js,Draw.js,Tank.js,index.html,img,music, 2. 最终效果
3. 代码 1.index.html
- <!DOCTYPE html>
- <html>
- <head>
- <title>
- </title>
- <meta charset="utf-8">
- <style type="text/css">
- body { font: 14px "sans-serif" } #Map { background-color: #000000; } .show
- { float: left } #guide { float: left; width: 200px; height: 390px; margin-left:
- 5px; background: #CCCCCC; padding: 5px; }
- </style>
- <script type="text/javascript" src="Tank.js">
- </script>
- <script type="text/javascript" src="Bullet.js">
- </script>
- <script type="text/javascript" src="Bomb.js">
- </script>
- <script type="text/javascript" src="Draw.js">
- </script>
- <script type="text/javascript">
- window.onload = function() {
- //画布信息
- width = document.getElementById('Map').width;
- height = document.getElementById('Map').height;
- ctx = document.getElementById('Map').getContext('2d');
- //初始页面
- var starImg = new Image();
- starImg.src = "img/star.jpg";
- starImg.onload = function() {
- ctx.drawImage(starImg, 0, 0, width, height);
- }
- //键盘监听 回车开始游戏
- document.body.onkeydown = function() {
- var keycode = event.keyCode;
- switch (keycode) {
- case 13:
- //初始化参数
- init()
- //刷新页面
- setInterval(draw, 30);
- document.body.onkeydown = gameControl;
- break;
- }
- }
- }
- function init() {
- //玩家和电脑
- hero = new Hero(100, 300, 0);
- enemys = [];
- for (var i = 0; i < 3; i++) {
- enemys.push(new Enemy(100 + i * 50, 0, 2));
- }
- //合并数组
- allTank = enemys.concat(hero);
- //炸弹
- Bombs = [];
- im = new Image();
- im2 = new Image();
- im3 = new Image();
- im.src = "img/bomb_3.gif";
- im2.src = "img/bomb_2.gif";
- im3.src = "img/bomb_1.gif";
- }
- function gameControl() {
- var keycode = event.keyCode;
- switch (keycode) {
- case 65:
- hero.moveLeft();
- break; //左
- case 83:
- hero.moveDown();
- break; //下
- case 87:
- hero.moveUp();
- break; //上
- case 68:
- hero.moveRight();
- break; //右
- case 74:
- hero.shot();
- break;
- case 49:
- hero.addLife() break;
- }
- }
- //扩展 删除指定元素
- Array.prototype.deleteElement = function(obj) {
- if (obj) {
- for (var i = 0; i < this.length; i++) {
- if (this[i] === obj) {
- this.splice(i, 1);
- }
- }
- }
- }
- </script>
- </head>
- <body>
- <div class="show">
- <canvas id="Map" width="500px" height="400px">
- </canvas>
- <audio id="music" autoplay="autoplay">
- <source src="music/111.wav">
- </audio>
- </div>
- <div id="guide">
- <p>
- 按下回车键开始游戏
- </p>
- <p>
- 按下1键增加生命,默认是1
- </p>
- <p>
- 剩余生命数 :
- <label id="life">
- 1
- </label>
- </p>
- <div id="data">
- </div>
- </div>
- </body>
- </html>
2.Draw.js
- /**
- * Created by Alane on 14-3-18.
- */
- function draw(){
- //检测子弹和坦克生死
- checkDead();
- //清空画布
- ctx.clearRect(0,0,500,400);
- //画玩家
- if(!hero.isdead){
- drawTank(hero);
- }else{
- hero.cutLife();
- }
- //画敌人坦克
- for (var i = 0; i < enemys.length; i++) {
- drawTank(enemys[i]);
- }
- //画敌人子弹
- for(var j=0;j<enemys.length;j++){
- var temp = enemys[j].bulletsList;
- for (var i = 0; i < temp.length; i++) {
- drawBullet(temp[i]);
- }
- }
- //画玩家子弹
- var temp = hero.bulletsList;
- for (var i = 0; i < temp.length; i++) {
- drawBullet(temp[i]);
- }
- //画炸弹
- for(var i=0;i<Bombs.length;i++){
- drawBown(Bombs[i]);
- }
- }
- function drawTank(tank){
- var x = tank.x;
- var y = tank.y;
- ctx.fillStyle = tank.color;
- if(tank.direct == 0 || tank.direct ==2){
- ctx.fillRect(x, y, 5,30);
- ctx.fillRect(x+15, y, 5,30);
- ctx.fillRect(x+6, y+8, 8,15);
- ctx.strokeStyle = tank.color;
- ctx.lineWidth = '1.5';
- if(tank.direct == 0){
- ctx.beginPath();
- ctx.moveTo(x+10,y-2);
- ctx.lineTo(x+10,y+8);
- ctx.closePath();
- }else{
- ctx.beginPath();
- ctx.moveTo(x+10,y+24);
- ctx.lineTo(x+10,y+32);
- ctx.closePath();
- }
- ctx.stroke();
- }else{
- ctx.fillRect(x, y, 30,5);
- ctx.fillRect(x, y+15, 30,5);
- ctx.fillRect(x+8, y+6, 15,8);
- ctx.strokeStyle = '#FF0000';
- ctx.lineWidth = '1.5';
- if(tank.direct == 3){
- ctx.beginPath();
- ctx.moveTo(x-2,y+10);
- ctx.lineTo(x+8,y+10);
- ctx.closePath();
- }else{
- ctx.beginPath();
- ctx.moveTo(x+24,y+10);
- ctx.lineTo(x+32,y+10);
- ctx.closePath();
- }
- ctx.stroke();
- }
- }
- function drawBullet(bullet){
- ctx.fillStyle = bullet.color;
- ctx.beginPath();
- ctx.arc(bullet.x,bullet.y,2,360,true);
- ctx.closePath();
- ctx.fill();
- }
- function drawBown (obj){
- if(obj.life>8){
- ctx.drawImage(im,obj.x,obj.y,50,50);
- }else if(obj.life>4){
- ctx.drawImage(im2,obj.x,obj.y,50,50);
- }else{
- ctx.drawImage(im3,obj.x,obj.y,50,50);
- }
- obj.lifeDown();
- if(obj.life<=0){
- Bombs.deleteElement(obj);
- }
- }
- function checkDead(){
- //检测敌人子弹生死
- for(var j=0;j<enemys.length;j++){
- var temp = enemys[j].bulletsList;
- for (var i = 0; i < temp.length; i++) {
- var o = temp[i];
- if(o.isdead){
- temp.deleteElement(o);
- }
- }
- }
- //检测玩家子弹生死
- var temp = hero.bulletsList;
- for (var i = 0; i < temp.length; i++) {
- var o = temp[i];
- if(o.isdead){
- temp.deleteElement(o);
- }
- }
- //检测敌人坦克生死
- for (var i = 0; i < enemys.length; i++) {
- var o = enemys[i];
- if(o.isdead){
- enemys.deleteElement(o);
- }
- }
- }
Bomb.js
- /**
- * Created by Alane on 14-3-18.
- */
- function Bomb(x,y){
- this.life = 12;
- this.x = x;
- this.y = y;
- }
- Bomb.prototype.lifeDown = function(){
- this.life--;
- }
Tank.js
- /**
- * Created by Alane on 14-3-7.
- */
- /**
- * direct 0 上
- * 1 右
- * 2 下
- * 3 左
- * @param x
- * @param y
- * @param direct
- * @constructor
- */
- //******************************************************************************************/
- //坦克父类
- function Tank (x, y, direct) {
- this.speed = 2;
- }
- Tank.prototype.moveUp = function () {
- //边界检测
- if (this.y < 0) {
- //换方向
- this.changeDirect ();
- return;
- }
- this.y -= this.speed;
- this.direct = 0;
- }
- Tank.prototype.moveDown = function () {
- if (this.y > height - 30) {
- this.changeDirect ();
- return;
- }
- this.y += this.speed;
- this.direct = 2;
- }
- Tank.prototype.moveLeft = function () {
- if (this.x < 0) {
- this.changeDirect ();
- return;
- }
- this.x -= this.speed;
- this.direct = 3;
- }
- Tank.prototype.moveRight = function () {
- if (this.x > width - 30) {
- this.changeDirect ();
- return;
- }
- this.x += this.speed;
- this.direct = 1;
- }
- //变换方向
- Tank.prototype.changeDirect = function () {
- while (true) {
- var temp = Math.round (Math.random () * 3);
- if (this.direct != temp) {
- this.direct = temp;
- break;
- }
- }
- //alert("x="+this.x+" y="+this.y+" direct="+this.direct)
- }
- //射击子弹
- Tank.prototype.shot = function () {
- if(this.isdead){
- return;
- }
- if (this.bulletsList.length < this.maxBulletSize) {
- //新建子弹
- var bullet = null;
- switch (this.direct) {
- case 0:
- bullet = new Bullet (this.x + 10, this.y - 2, 0, this.color);
- break;
- case 1:
- bullet = new Bullet (this.x + 32, this.y + 10, 1, this.color);
- break;
- case 2:
- bullet = new Bullet (this.x + 10, this.y + 32, 2, this.color);
- break;
- case 3:
- bullet = new Bullet (this.x - 2, this.y + 10, 3, this.color);
- break;
- }
- //放入弹夹
- this.bulletsList.push (bullet);
- }
- }
- //******************************************************************************************/
- //玩家
- function Hero (x, y, direct) {
- this.lifetimes = 5;
- this.isdead = false;
- this.color = '#FF0000';
- this.x = x;
- this.y = y;
- this.direct = direct;
- this.bulletsList = [];
- this.maxBulletSize = 10;
- this.newlife = null;
- }
- Hero.prototype = new Tank (0, 0, 0);
- Hero.prototype.constructor = Hero;
- Hero.prototype.addLife = function(){
- this.lifetimes++;
- document.querySelector("#life").innerHTML = hero.lifetimes;
- }
- Hero.prototype.cutLife = function(){
- if(this.lifetimes>=1 && !this.newlife){
- this.lifetimes--;
- this.newlife = setTimeout("hero.newLife()",2000);
- }
- }
- Hero.prototype.newLife = function(){
- this.isdead = false;
- clearTimeout(hero.newlife);
- hero.newlife = null;
- document.querySelector("#life").innerHTML = hero.lifetimes;
- }
- //******************************************************************************************/
- //敌人坦克
- function Enemy (x, y, direct) {
- this.isdead = false;
- this.color = 'blue';
- this.x = x;
- this.y = y;
- this.direct = direct;
- this.bulletsList = [];
- this.maxBulletSize = 1;
- //定时器,自动移动
- this.timer1 = setInterval ((function (context) {
- return function () {
- //移动
- Enemy.prototype.move.call (context);
- }
- }) (this), 30);
- //定时器,射击
- this.timer2 = setInterval ((function (context) {
- return function () {
- //射击
- Tank.prototype.shot.call (context);
- }
- }) (this), 2000);
- //定时器,变换方向
- this.timer3 = setInterval ((function (context) {
- return function () {
- //射击
- Tank.prototype.changeDirect.call (context);
- }
- }) (this), 3000);
- }
- Enemy.prototype = new Tank (0, 0, 0);
- Enemy.prototype.constructor = Enemy;
- Enemy.prototype.move = function () {
- switch (this.direct) {
- case 0:
- this.moveUp ();
- break;
- case 1:
- this.moveRight ();
- break;
- case 2:
- this.moveDown ();
- break;
- case 3:
- this.moveLeft ();
- break;
- }
- }
Bullet.js
- /**
- * Created by Alane on 14-3-11.
- */
- function Bullet(x, y, direct, color) {
- this.isdead = false;
- this.x = x;
- this.y = y;
- this.direct = direct;
- this.speed = 4;
- this.color = color;
- //定时器,自行运动
- this.timer = setInterval((function(context) {
- return function() {
- Bullet.prototype.move.call(context)
- }
- })(this), 30);
- }
- Bullet.prototype.move = function() {
- switch (this.direct) {
- case 0:
- this.y -= this.speed;
- break;
- case 1:
- this.x += this.speed;
- break;
- case 2:
- this.y += this.speed;
- break;
- case 3:
- this.x -= this.speed;
- break;
- }
- //边界检测
- if (this.y < 0 || this.x > width || this.y > height || this.x < 0) {
- clearInterval(this.timer);
- this.isdead = true;
- }
- //碰撞检测 检测敌人坦克
- for (var i = 0; i < allTank.length; i++) {
- var temp = allTank[i];
- if (temp.isdead) {
- continue;
- }
- switch (temp.direct) {
- case 0:
- case 2:
- if (this.x > temp.x && this.x < temp.x + 20 && this.y > temp.y && this.y < temp.y + 30) {
- if (this.color == temp.color) {
- break;
- }
- Bombs.push(new Bomb(temp.x - 10, temp.y - 10));
- clearInterval(this.timer);
- this.isdead = true;
- temp.isdead = true;
- }
- break
- case 1:
- case 3:
- if (this.x > temp.x && this.x < temp.x + 30 && this.y > temp.y && this.y < temp.y + 20) {
- if (this.color == temp.color) {
- break;
- }
- Bombs.push(new Bomb(temp.x - 10, temp.y - 10));
- clearInterval(this.timer);
- this.isdead = true;
- temp.isdead = true;
- }
- break;
- }
- }
- }
源码下载
来源: http://www.phperz.com/article/17/0424/276394.html