• 用原生Canvas写贪吃蛇及问题解决


    为了学习Canvas,写了这个小游戏贪吃蛇供自己和大家学习

    Github: https://github.com/zhiyishou/Gsnake

    Play On: http://zhiyishou.github.io/Gsnake

    游戏截图:

    前言:

    为了方便加载转移,我把整个js都写在了html里,为了方便阅读,将函数结构在html里清晰地分开,

    并在代码里有足够注释。

    函数结构如下:

    |----script   
        |----Definations
            |----Global Snake variables
            |----Global Canvas variables
            |----Global Panel variables
            |----Global Stage variables
            |----Global Game status variables
        |----Init Functions
            |----initPanel
            |----initButtons
            |----initStage
            |----initCanvas
            |----initMaps
            |----SnakeNode
            |----initSnake
            |----produceSingle
            |----init
        |----Draw Funcitons
            |----drawScore
            |----drawButton
            |----drawButtons
            |----drawSnake
            |----drawSingle
            |----drawStage
            |----draw
        |----Action Functions
            |----moveSnake
            |----main
        |----Event Functions
            |----KeyDown
            |----getOffsetPosition
            |----determineButton
            |----MouseMove
            |----ClickButton
            |----debounce
            |----bind
            |----Pause
            |----Start
            |----ReStart
            |----Died
        |----ROCK and ROLL
            |----init()
            |----main()

    其中碰到的问题与解决:

    一、鼠标事件问题

    Canvas 中无法实现内部事件的添加和删除,准确的来说,在Canvas就是一张单纯的画布,整个Canvas才能做Dom中的事件操作

    如果想在Canvas中实现内部click或mousemove等事件,有两种方案来实现:

    1、用四周边界来确定:

    • 基于:
      1. 对Canvas绑定事件后,每当有事件发生,则计算当前鼠标相对于Canvas的坐标值;
      2. 在每个要绑定事件的对象中设定其四边边距坐标,并将其放在一个数组;
    • 触发:事件发生时则遍历整个数组,来根据坐标来判断是否在哪一个对象的边界范围内,来确定鼠标现在所在的对象。
    • 缺点:这个做的话要求对象只能是形状规整的直角四边形,对复杂图形的处理没有可实施性。

    2、使用CanvasAPI中的isPointInPath方法:

    • 基于:
      1. (同上)对Canvas绑定事件后,每当有事件发生,则计算当前鼠标相对于Canvas的坐标值;
      2. 将要绑定事件的对象储存在数组里;
      3. isPonitInPath或isPointInStroke方法针对context上下文来判断一个坐标值是否在其Path中或上;
    • 触发:事件发生时则遍历整个数组,并重绘数组里的对象,即改变context,每绘制一个对象则context改变一次,当前的context来使用isPointInPath或isPointInStroke方法,将Offset坐标传入,来判断鼠标是否在其路径上,确定现在focus或click的对象。(canvas中的context会在closePath方法后重新设置)
    • 优点:可实现复杂的图形事件。

     

    二、绘制问题

    在我原先的版本中我是将整个对象操作和对象绘制设置成一个Interval来实现在,在后来的编写中就发现这样做会很死板,如果想添加或改动一些功能,则要对整个代码进行修改甚至在这种模型下无法实现。

    最后还是将绘制和操作分离开来

    • 对绘制设置Interval,如:
    setInterval(function(){
         draw();
    },1000/60)    //每秒重绘60次
    • 而将绘制对象属性的改变绑定在事件上,如:

      该游戏中的Event Functions

    原理:对象事件来改变对象的属性,而绘制则是用对象属性来绘制,两个逻辑各司其职,互不干预。

    优点:整体程序逻辑会更清晰,更方便后续功能的新增和修改。

    The End

  • 相关阅读:
    Java8部分新特性的学习
    SurfaceView的基本使用
    Android Apk的反编译和加密
    Notification的基本用法以及使用RemoteView实现自定义布局
    Anroid事件分发
    Xmpp学习之Asmack取经-asmack入门(一)
    android通过DialogFragment实现时间选择
    使用官方Android-support-v7在低版本上使用ActionBarActivity
    五一后总结
    Android在有存储卡和无存储卡情况下拍照后固定尺寸和压缩大小
  • 原文地址:https://www.cnblogs.com/zhiyishou/p/4315025.html
Copyright © 2020-2023  润新知