请点此下载代码并用浏览器打开试玩。

图例:

代码:

<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>地图加载 英雄可以射箭了 怪物爆炸 19.3.7 7:59 by:逆火狂飙 horn19782016@163.com</title>

     <style>
     #canvas{
        background:#ffffff;
        cursor:pointer;
        margin-left:10px;
        margin-top:10px;
        -webkit-box-shadow:3px 3px 6px rgba(0,0,0,0.5);
        -moz-box-shadow:3px 3px 6px rgba(0,0,0,0.5);
        box-shadow:3px 3px 6px rgba(0,0,0,0.5);
     }

     #controls{
        margin-top:10px;
        margin-left:15px;
     }
     </style>

    </head>

     <body onload="init()">
        <div id="controls">
            <input id='animateBtn' type='button' value='开始'/>
        </div>

        <canvas id="canvas" width="160px" height="160px" >
            出现文字表示你的浏览器不支持HTML5
        </canvas>
     </body>
</html>
<script type="text/javascript">
<!--
var paused=true;
animateBtn.onclick=function(e){
    paused=! paused;

    if(paused){
        animateBtn.value="开始";    

    }else{
        animateBtn.value="停止";

        window.requestAnimationFrame(animate);
    }
}

var ctx;// 绘图环境
var r;// 表盘半径
var terrain;
var hero;
var arrows;
var monsterMng;
function init(){
    // init Canvas
    var canvas=document.getElementById('canvas');
    r=160;
    canvas.width =2*r;
    canvas.height=2*r;
    ctx=canvas.getContext('2d');

    terrain=new Terrain();
    hero=new Hero();

    arrows=new Array();
    monsterMng=new MonsterMng();

    // 响应键盘事件
    canvas.addEventListener('keydown', doKeyDown, true);
    canvas.focus();
    window.addEventListener('keydown', doKeyDown, true);
};

function draw(){
    // Clear Canvas
    ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
    ctx.fillStyle="#ECF5FF";
    ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);

    terrain.paint(ctx);
    monsterMng.paint(ctx);
    hero.paint(ctx);

    for(var i=arrows.length-1;i>-1;i--){
        var arrow=arrows[i];
        var x=parseInt(arrow.x / 32,10);
        var y=parseInt(arrow.y / 32,10);

        // 箭矢射中怪物所在
        if(monsterMng.getValue(x,y)==1){
            monsterMng.setValue(x,y,2);
            arrows.splice(i,1);
            break;
        }

        // 箭矢射中树木房屋等障碍物
        if(terrain.getValue(x,y)!=0){
            arrows.splice(i,1);
        }
    }

    // 画箭矢
    for(var i=0;i<arrows.length;i++){
        var arrow=arrows[i];

        arrow.paint(ctx);
    }

    // 胜利条件
    if(monsterMng.hasMonster()==false){
        alert("You win!");
        init();
    }
}

function animate(){
    if(!paused){
        draw();
        window.requestAnimationFrame(animate); /// 让浏览器自行决定帧速率
    }
}

function doKeyDown(e) {
    var keyID = e.keyCode ? e.keyCode :e.which;
    if(keyID === 38 || keyID === 87)  { // up arrow and W
        hero.move('up');
        e.preventDefault();
    }
    if(keyID === 39 || keyID === 68)  { // right arrow and D
        hero.move('right');
        e.preventDefault();
    }
    if(keyID === 40 || keyID === 83)  { // down arrow and S
        hero.move('down');
        e.preventDefault();
    }
    if(keyID === 37 || keyID === 65)  { // left arrow and A
        hero.move('left');
        e.preventDefault();
    }

    if(keyID === 32 )  { // SpaceBar
        var a=new Arrow(hero.x+16,hero.y+16,hero.direction);
        arrows.push(a);
        console.log('arrows.length='+arrows.length);
        e.preventDefault();
    }
}

//---------------------------------------------------地形类定义开始------------------------------------------------------------------->>
Terrain=function(){
    this.files=["road.png","tree.png","home.png"];

    this.maps=new Array(
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,1,1,1,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,2,2,2,2,2,2,2,0],
        [0,0,0,0,0,0,2,0,0,0],
        [0,0,0,2,0,0,2,0,0,0],
        [0,0,0,2,0,0,0,0,0,0],
        [0,2,2,2,2,2,2,2,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,1,1,1,1,1,1,1,1,0],
    );
}
Terrain.prototype={
    files:[],
    // Property
    maps:0,

    // method
    paint:function(ctx){
        for(var i=0;i<this.maps.length;i++){
            var arr=this.maps[i];

            for(var j=0;j<arr.length;j++){
                var value=arr[j];

                var img=new Image();
                img.src=this.files[value];

                ctx.drawImage(img,i*32,j*32);
            }
        }
    },

    getValue:function(i,j){
        if(i<0 || i>=this.maps.length){
            return undefined;
        }
        var arr=this.maps[i];
        if(j<0 || j>=arr.length){
            return undefined;
        }
        var value=arr[j];
        return value;
    },

    setValue:function(i,j,value){
        if(i<0 || i>=this.maps.length){
            return undefined;
        }
        var arr=this.maps[i];
        if(j<0 || j>=arr.length){
            return undefined;
        }
        arr[j]=value;
    },
}
//---------------------------------------------------地形类定义结束-------------------------------------------------------------------<<

//---------------------------------------------------英雄类定义开始------------------------------------------------------------------->>
Hero=function(){
    this.pngs=[
        {left:0,top:10,width:40,height:40},
        {left:0,top:66,width:40,height:40},
        {left:0,top:120,width:40,height:40},
        {left:0,top:180,width:40,height:40},
    ];
}
Hero.prototype={
    pngs:[],
    x:160,
    y:160,
    xTo:160,
    yTo:160,
    step:32,
    direction:'up',

    paint:function(ctx){
        var img=new Image();
        img.src='bowman.png';

        var index=0;
        if(this.direction=='up'){
            index=3;
        }
        if(this.direction=='down'){
            index=0;
        }
        if(this.direction=='left'){
            index=1;
        }
        if(this.direction=='right'){
            index=2;
        }
        var pos=this.pngs[index];
        ctx.drawImage(img,pos.left,pos.top,pos.width,pos.height,this.x,this.y,pos.width,pos.height);
    },

    move:function(direction){
        this.direction=direction;

        if(this.direction=='up'){
            this.yTo-=this.step;
        }
        if(this.direction=='down'){
            this.yTo+=this.step;
        }
        if(this.direction=='left'){
            this.xTo-=this.step;
        }
        if(this.direction=='right'){
            this.xTo+=this.step;
        }

        if(terrain.getValue(this.xTo/this.step,this.yTo/this.step)==0){
            this.x=this.xTo;
            this.y=this.yTo;
        }else{
            this.xTo=this.x;
            this.yTo=this.y;
        }
    }
}
//---------------------------------------------------英雄类定义结束-------------------------------------------------------------------<<

//---------------------------------------------------箭矢类定义开始------------------------------------------------------------------->>
Arrow=function(x,y,direction){
    this.x=x;
    this.y=y;
    this.direction=direction;
}
Arrow.prototype={
    x:0,
    y:0,
    velocity:1,// 飞行速度
    len:16,// 箭杆长
    direction:'',

    // method
    paint:function(ctx){
        var x1=this.x,y1=this.y;
        var leaf=4;//箭头箭羽长
        var x2,y2,x3,y3;
        var angle=getRad(15);

        if(this.direction=='up'){
            this.y-=this.velocity;
            y1=this.y-this.len;
            x1=this.x;

            y2=y1+leaf*Math.cos(angle);
            x2=x1-leaf*Math.sin(angle);
            y3=y2;
            x3=x1+leaf*Math.sin(angle);
        }
        if(this.direction=='down'){
            this.y+=this.velocity;
            y1=this.y+this.len;
            x1=this.x;
            y2=y1-leaf*Math.cos(angle);
            x2=x1-leaf*Math.sin(angle);
            y3=y2;
            x3=x1+leaf*Math.sin(angle);
        }
        if(this.direction=='left'){
            this.x-=this.velocity;
            x1=this.x-this.len;
            y1=this.y;

            x2=x1+leaf*Math.cos(angle);
            y2=y1-leaf*Math.sin(angle);
            x3=x2;
            y3=y1+leaf*Math.sin(angle);
        }
        if(this.direction=='right'){
            this.x+=this.velocity;
            x1=this.x+this.len;
            y1=this.y;

            x2=x1-leaf*Math.cos(angle);
            y2=y1-leaf*Math.sin(angle);
            x3=x2;
            y3=y1+leaf*Math.sin(angle);
        }

        ctx.beginPath();
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#ff0000";
        ctx.lineTo(this.x,this.y);
        ctx.lineTo(x1,y1);
        ctx.lineTo(x2,y2);
        ctx.lineTo(x3,y3);
        ctx.lineTo(x1,y1);

        ctx.stroke();
        ctx.closePath();
    },
}
//---------------------------------------------------箭矢类定义结束-------------------------------------------------------------------<<

//---------------------------------------------------怪物管理类定义开始------------------------------------------------------------------->>
MonsterMng=function(){
    this.files=["","skull.png","bomb.png",];

    this.maps=new Array(
        [0,0,0,0,0,0,0,0,0,0],
        [0,1,0,0,0,0,0,0,1,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,1,0,0,0,0,0,0,1,0],
        [0,0,0,0,0,0,0,0,0,0],
    );
}
MonsterMng.prototype={
    files:[],
    // Property
    maps:[],

    // method
    paint:function(ctx){
        for(var i=0;i<this.maps.length;i++){
            var arr=this.maps[i];

            for(var j=0;j<arr.length;j++){
                var value=arr[j];

                if(value!=0){
                    var img=new Image();
                    img.src=this.files[value];

                    ctx.drawImage(img,i*32,j*32);
                }
            }
        }
    },

    // 判断怪物还是否存在
    hasMonster:function(){
        var count=0;
        for(var i=0;i<this.maps.length;i++){
            var arr=this.maps[i];

            for(var j=0;j<arr.length;j++){
                var value=arr[j];

                if(value==1){
                    count++;// 累计怪物数
                }
            }
        }

        // 怪物数大于零就是还有怪物
        return count>0;
    },

    getValue:function(i,j){
        if(i<0 || i>=this.maps.length){
            return undefined;
        }
        var arr=this.maps[i];
        if(j<0 || j>=arr.length){
            return undefined;
        }
        var value=arr[j];
        return value;
    },

    setValue:function(i,j,value){
        if(i<0 || i>=this.maps.length){
            return undefined;
        }
        var arr=this.maps[i];
        if(j<0 || j>=arr.length){
            return undefined;
        }
        arr[j]=value;
    },
}
//---------------------------------------------------怪物管理类定义结束-------------------------------------------------------------------<<
//  常规函数:角度得到弧度
function getRad(degree){
    return degree/180*Math.PI;
}
//-->
</script>

2019年3月7日08点50分

[Canvas]游戏增加怪物爆炸效果,改善箭头形状的更多相关文章

  1. Atitit 游戏引擎---物理系统(1)------爆炸效果

    Atitit 游戏引擎---物理系统(1)------爆炸效果 1.1. 动画框架的来源flex,jqueryuijs,anim , cocos2d 1 1.2. Jqueryui的特效库 1 1.3 ...

  2. jQuery 打气球小游戏 点击气球爆炸效果

    最近在学习前端,看到偶尔看到前端小游戏,就想自己写一个小游戏,奈何水平有限,只能写打气球这种简单的,所有的气球都是动态生成的,气球的颜色也是随机的 html部分 <div class=" ...

  3. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  4. Java坦克大战 (五) 之产生敌方坦克和爆炸效果

    本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...

  5. canvas游戏小试:画一个按方向键移动的圆点

    canvas游戏小试:画一个按方向键移动的圆点   自己对canvas,但又有一颗做游戏的心TT.然后记录一下对canvas的学习吧,用一个按方向键控制的小圆点来做练习.(编程时用了一些es6的语法) ...

  6. [一位菜鸟的COCOS-2D编程之路]打飞机中机种敌机和战机损毁时的爆炸效果

    1.第一步,添加爆炸动画 //添加玩家飞机飞行动画 id _playerFlyAction; id _playerBlowupAnimation; //战机爆炸动画 id _enemyBlowupAn ...

  7. WPF编游戏系列 之七 动画效果(2)

    原文:WPF编游戏系列 之七 动画效果(2)        上一篇已经对关闭窗口图标进行了动画效果处理,本篇将对窗口界面的显示和关闭效果进行处理.由于所有的动画效果都是针对窗口界面的Canvas,所以 ...

  8. WPF编游戏系列 之六 动画效果(1)

    原文:WPF编游戏系列 之六 动画效果(1)        本篇主要针对界面进行动画效果处理.首先在打开或关闭界面时,使其产生动态效果而不是生硬的显示或消失(如下图).其次在鼠标放到关闭窗口图标上时, ...

  9. 【CSS】398- 原生JS实现DOM爆炸效果

    爆炸动效分享 前言 此次分享是一次自我组件开发的总结,还是有很多不足之处,望各位大大多提宝贵意见,互相学习交流. 分享内容介绍 通过原生js代码,实现粒子爆炸效果组件 组件开发过程中,使用到了公司内部 ...

随机推荐

  1. RabbitMQ高级指南:从配置、使用到高可用集群搭建

    本文大纲: 1. RabbitMQ简介 2. RabbitMQ安装与配置 3. C# 如何使用RabbitMQ 4. 几种Exchange模式 5. RPC 远程过程调用 6. RabbitMQ高可用 ...

  2. jstat命令 -- Java虚拟机监控统计工具

    http://blog.sina.com.cn/s/blog_5f5716580100u76r.html 语法:jstat [generalOption | outputOptions vmid [i ...

  3. Reactor与Proactor比较

    from http://www.cnblogs.com/dawen/archive/2011/05/18/2050358.html 1.标准定义 两种I/O多路复用模式:Reactor和Proacto ...

  4. stm32 优先级说明

    抢占优先级和响应优先级.事实上是一个中断所包括的两个优先级,当中前者是对抢占优先级的级别划分,后者是同样抢占优先级的优先级别的划分. 比方: 中断A抢占优先级比B高,那么A的中断能够在B里面触发,忽略 ...

  5. C#面向服务编程技术WCF从入门到实战演练

    一.WCF课程介绍 1.1.Web Service会被WCF取代吗? 对于这个问题阿笨的回答是:两者在功能特性上却是有新旧之分,但是对于特定的系统,适合自己的就是最好的.不能哪一个技术框架和行业标准作 ...

  6. WebLogic使用总结(五)——Web项目使用Sigar在WebLogic服务器部署遇到的问题

    今天在WebLogic 12c服务器上部署Web项目时,碰到了一个问题.项目中使用到了"Sigar.jar"监控Window平台下的cpu使用率.内存使用率和硬盘信息,sigar. ...

  7. 解决ubuntu上在androidstudio中启动emulator闪退的问题(2)

    平台 Ubuntu14.04 64 现象 在AndrodStudio中点击模拟器的启动按钮后,模拟器界面弹出后,又立刻闪退. 解决 一.查看模拟器的信息 从上面可以看到模拟器的存放路径以及名称: 路径 ...

  8. 【工具类】根据IP获取IP归属地,国家,城市信息

    使用淘宝的IP归属地查询接口: http://ip.taobao.com/service/getIpInfo.php?ip=192.168.92.130 通过新浪的IP归属地查询接口: http:// ...

  9. React中的的JSX

    什么是JSX? JSX是JavaScript XML的缩写,其本质是js,表现形式类似于XML,与js区别在于可直接在里面编写html标签. 怎么使用JSX? 语法规则: JSX 的基本语法规则:HT ...

  10. SharePoint Online 创建列表库

    前言 本文介绍如何在Office 365中创建列表库,以及列表库的一些基本设置. 正文 通过登录地址登录到Office 365的SharePoint Online站点中,我们可以在右上角的设置菜单中, ...