zoukankan      html  css  js  c++  java
  • canvas入门级小游戏《开关灯》思路讲解

    游戏很简单,10行10列布局,每行每列各10盏灯,游戏初始化时随机点亮其中一些灯,点击某盏灯,其上下左右的灯及本身状态反转,如果点击前是灭着的,点击后即点亮,将所有灯全部点亮才算过关。游戏试玩:

     下面说说大概思路:

    生成画布

    创建canvas画布,先是生成10*10阵列的100盏灯,每盏灯之间的间隔为margin = 5px,第一盏灯圆心坐标为它的半径"R, R",第一行第二盏灯坐标为3R+margin,以此类推得出灯坐标计算公式:第一行第i盏灯横坐标(2*i + 1)*R + i*margin,同理第一列第j行纵坐标为(2*j + 1)*R + j*margin 

    为其中灯开关的状态是随机的,很自然的想到利用随机数Math.random()去和0.5比较大小,随机数大于0.5则灯熄灭,否则点亮。为了便于游戏扩展和维护,游戏中灯的半径、所有灯的坐标、颜色、数量、是否点亮等数据用变量存起来。 

    <canvas id="canvas" width="445" height="445"> 
        您的浏览器不支持canvas!
    </canvas>
    <script>
    var lightOff = {
            gameData : [], // 灯开关状态
            r : 20, // 灯半径
            margin: 5, // 灯间距
            padding: 20, // canvas内边距
            onColor: "#0077AA", // 灯亮的颜色
            offColor: "#E0E0E0", // 灯灭的颜色
            row : 10, // 10行
            col : 10, // 10列
            canvas : document.getElementById("canvas"),
            ctx : this.canvas.getContext("2d"),
            reDraw: function(p){
                for (var i = 0; i < this.row; i++) {
                    for (var j = 0; j < this.col; j++) {
                        this.ctx.beginPath();                    
                        this.ctx.fillStyle = this.gameData[i][j] ? this.onColor : this.offColor;
                        this.ctx.arc( i*this.margin+(2*i+1)*this.r, j*this.margin+(2*j+1)*this.r, this.r, 0, 2*Math.PI );                    
                        this.ctx.fill();
                    }
                }            
                return this;
            },
            // 随机生成100盏灯的状态
            createMap: function(){
                for (var i = 0; i < this.row; i++) {
                    this.gameData[i] = [];
                    for (var j = 0; j < this.col; j++) {
                        this.gameData[i].push( Math.random() > 0.5 ? false : true );
                    }
                }
                return this;
            }
        }
    </script>

    添加点击事件

     众所周知,canvas是一个整体,如何给其中某一盏灯添加点击事件?事实上,可以给整个canvas对象添加点击事件,将event对象下的event.layerX, event.layerY传入isPointInPath(x, y)方法判断点击的坐标event.layerX, event.layerY是否在灯上从而触发回调函数。

    示例:

    需要注意的是:isPointInPath(x, y)方法只能判断坐标x, y是否在最近的上下文所绘制的图形内,如果canvas一次性绘制了100盏灯,isPointInPath(x, y)只能判断x, y是否在第100盏灯内,要想判断x, y是否在所点击的某盏灯内,就应该在每次点击的时候重绘这100盏灯(调用reDraw方法),每绘制一盏灯触发一次isPointInPath(x, y)方法,如果在灯上,将gameData对应灯的数据状态反转。如当前绘制第i行第j盏灯,调用isPointInPath(x, y)返回true,则反转该灯状态game[i][j] = !game[i][j]之后再次调用reDraw方法重绘。每次点击需要重绘两次。

    综上所述,代码修改为:

    var lightOff = {
            gameData : [],
            r : 20,
            margin: 5,
            padding: 20,
            onColor: "#0077AA",
            offColor: "#E0E0E0",
            row : 10,
            col : 10,
            canvas : document.getElementById("canvas"),
            ctx : this.canvas.getContext("2d"),
            init: function(){
                var This = this;
                // 判断是否点击了该圆点
                this.canvas.addEventListener("click", function(ev){
                    This.reDraw(ev);
                    This.reDraw();
                })
                this.createMap().reDraw();
                return this;
            },
            reDraw: function(p){
                this.count = 0;
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                for (var i = 0; i < this.row; i++) {
                    for (var j = 0; j < this.col; j++) {
                        this.ctx.beginPath();
                        
                        this.ctx.fillStyle = this.gameData[i][j] ? this.onColor : this.offColor;
                        this.ctx.arc( i*this.margin+(2*i+1)*this.r, j*this.margin+(2*j+1)*this.r, this.r, 0, 2*Math.PI );                    
                        this.ctx.fill();
                        if( p && this.ctx.isPointInPath(p.layerX-this.padding, p.layerY-this.padding) ){
                            this.gameData[i][j] = !this.gameData[i][j];
                            i > 0 && (this.gameData[i-1][j] = !this.gameData[i-1][j]);
                            i < 9 && (this.gameData[i+1][j] = !this.gameData[i+1][j]);
                            j > 0 && (this.gameData[i][j-1] = !this.gameData[i][j-1]);
                            j < 9 && (this.gameData[i][j+1] = !this.gameData[i][j+1]);
                        }
                        this.gameData[i][j] && this.count++;
                    }
                }
    
                if(this.count === 100 ){
                    alert("成功了")
                }
                
                return this;
            },
            createMap: function(){
                for (var i = 0; i < this.row; i++) {
                    this.gameData[i] = [];
                    for (var j = 0; j < this.col; j++) {
                        this.gameData[i].push( Math.random() > 0.5 ? false : true );
                    }
                }
                return this;
            }
        }
    
        lightOff.init();

     

    作者:古德God
    出处:http://www.cnblogs.com/wangmeijian
    本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
    如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!

  • 相关阅读:
    WampServer Mysql配置
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 陶陶摘苹果2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 质因数2
    Java实现 蓝桥杯VIP 算法提高 前10名
  • 原文地址:https://www.cnblogs.com/wangmeijian/p/4738184.html
Copyright © 2011-2022 走看看