上手微信小游戏——官方实例学习,第一天学习游戏结构与逻辑

这篇博客介绍了微信小游戏的开发结构,包括基础类、对象池、精灵类、敌机、子弹、背景、游戏信息、音效管理和游戏状态管控等关键组件。通过官方实例学习,了解小游戏的开发逻辑。
摘要由CSDN通过智能技术生成

上手微信小游戏——官方实例学习

文件结构

├── base // 定义游戏开发基础类
│ ├── animatoin.js // 帧动画的简易实现
│ ├── pool.js // 对象池的简易实现
│ └── sprite.js // 游戏基本元素精灵类
├── libs
│ ├── symbol.js // ES6 Symbol简易兼容
│ └── weapp-adapter.js // 小游戏适配器
├── npc
│ └── enemy.js // 敌机类
├── player
│ ├── bullet.js // 子弹类
│ └── index.js // 玩家类
├── runtime
│ ├── background.js // 背景类
│ ├── gameinfo.js // 用于展示分数和结算界面
│ └── music.js // 全局音效管理器
├── databus.js // 管控游戏状态
└── main.js // 游戏入口主函数

├── base // 定义游戏开发基础类
│ ├── animatoin.js // 帧动画的简易实现

代码内容

import Sprite  from './sprite'
import DataBus from '../databus'

let databus = new DataBus()

const __ = {
   
  timer: Symbol('timer'),
}

/**
 * 简易的帧动画类实现
 */
export default class Animation extends Sprite {
   
  constructor(imgSrc, width, height) {
   
    super(imgSrc, width, height)

    // 当前动画是否播放中
    this.isPlaying = false

    // 动画是否需要循环播放
    this.loop = false

    // 每一帧的时间间隔
    this.interval = 1000 / 60

    // 帧定时器
    this[__.timer] = null

    // 当前播放的帧
    this.index = -1

    // 总帧数
    this.count = 0

    // 帧图片集合
    this.imgList = []

    /**
     * 推入到全局动画池里面
     * 便于全局绘图的时候遍历和绘制当前动画帧
     */
    databus.animations.push(this)
  }

  /**
   * 初始化帧动画的所有帧
   * 为了简单,只支持一个帧动画
   */
  initFrames(imgList) {
   
    imgList.forEach((imgSrc) => {
   
      let img = new Image()
      img.src = imgSrc

      this.imgList.push(img)
    })

    this.count = imgList.length
  }

  // 将播放中的帧绘制到canvas上
  aniRender(ctx) {
   
    ctx.drawImage(
      this.imgList[this.index],
      this.x,
      this.y,
      this.width  * 1.2,
      this.height * 1.2
    )
  }

  // 播放预定的帧动画
  playAnimation(index = 0, loop = false) {
   
    // 动画播放的时候精灵图不再展示,播放帧动画的具体帧
    this.visible   = false

    this.isPlaying = true
    this.loop      = loop

    this.index     = index

    if ( this.interval > 0 && this.count ) {
   
      this[__.timer] = setInterval(
        this.frameLoop.bind(this),
        this.interval
      )
    }
  }

  // 停止帧动画播放
  stop() {
   
    this.isPlaying = false

    if ( this[__.timer] )
      clearInterval(this[__.timer])
  }

  // 帧遍历
  frameLoop() {
   
    this.index++

    if ( this.index > this.count - 1 ) {
   
      if ( this.loop ) {
   
        this.index = 0
      }

      else {
   
        this.index--
        this.stop()
      }
    }
  }
}

│ ├── pool.js // 对象池的简易实现

const __ = {
   
  poolDic: Symbol('poolDic')
}

/**
 * 简易的对象池实现
 * 用于对象的存贮和重复使用
 * 可以有效减少对象创建开销和避免频繁的垃圾回收
 * 提高游戏性能
 */
export default class Pool {
   
  constructor() {
   
    this[__.poolDic] = {
   }
  }

  /**
   * 根据对象标识符
   * 获取对应的对象池
   */
  getPoolBySign(name) {
   
    return this[__.poolDic][name] || ( this[__.poolDic][name] = [] )
  }

  /**
   * 根据传入的对象标识符,查询对象池
   * 对象池为空创建新的类,否则从对象池中取
   */
  getItemByClass(name, className) {
   
    let pool = this.getPoolBySign(name)

    let result = (  pool.length
                  ? pool.shift()
                  : new className()  )

    return result
  }

  /**
   * 将对象回收到对象池
   * 方便后续继续使用
   */
  recover(name, instance) {
   
    this.getPoolBySign(name).push(instance)
  }
}

│ └── sprite.js // 游戏基本元素精灵类

/**
 * 游戏基础的精灵类
 */
export default class Sprite {
   
  constructor(imgSrc = '', width=  0, height = 0, x = 0, y = 0) {
   
    this.img     = new Image()
    this.img.src = imgSrc

    this.width  = width
    this.height = height

    this.x = x
    this.y = y

    this.visible = true
  }

  /**
   * 将精灵图绘制在canvas上
   */
  drawToCanvas(ctx) {
   
    if ( !this.visible )
      return

    ctx.drawImage(
      this.img,
      this.x,
      this.y,
      this.width,
      this.height
    )
  }

  /**
   * 简单的碰撞检测定义:
   * 另一个精灵的中心点处于本精灵所在的矩形内即可
   * @param{Sprite} sp: Sptite的实例
   */
  isCollideWith(sp) {
   
    let spX = sp.x + sp.width / 2
    let spY = sp.y + sp.height / 2

    if ( !this.visible || !sp.visible )
      return false

    return !!(   spX >= this.x
              && spX <= this.x + this.width
              && spY >= this.y
              && spY <= this.y + this.height  )
  }
}

├── libs
│ ├── symbol.js

/**
 * 对于ES6中Symbol的极简兼容
 * 方便模拟私有变量
 */

let Symbol  = window.Symbol
let idCounter = 0

if (!Symbol) {
   
  Symbol = function Symbol(key) {
   
    return `__${
   key}_${
   Math.floor(Math.random() * 1e9)}_${
   ++idCounter}__`
  }

  Symbol.iterator = Symbol('Symbol.iterator')
}

window.Symbol = Symbol

// ES6 Symbol简易兼容
│ └── weapp-adapter.js // 小游戏适配器

/******/ (function(modules) {
    // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {
   }

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
   

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
   
/******/ 			exports: {
   },
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		}

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true

/******/ 		// Return the exports of the module
/******/ 		return module.exports
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = ""

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0)
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
   

	'use strict'

	var _window2 = __webpack_require__(1)

	var _window = _interopRequireWildcard(_window2)

	function _interopRequireWildcard(obj) {
    if (obj && obj.__esModule) {
    return obj } else {
    var newObj = {
   }; if (obj != null) {
    for (var key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key] } } newObj.default = obj; return newObj } }

	var global = GameGlobal

	function inject() {
   
	  _window.addEventListener = _window.canvas.addEventListener = function (type, listener) {
   
	    _window.document.addEventListener(type, listener)
	  }
	  _window.removeEventListener = _window.canvas.removeEventListener = function (type, listener) {
   
	    _window.document.removeEventListener(type, listener)
	  }

	  var _wx$getSystemInfoSync = wx.getSystemInfoSync(),
	      platform = _wx$getSystemInfoSync.platform

	  // 开发者工具无法重定义 window


	  if (typeof __devtoolssubcontext === 'undefined' && platform === 'devtools') {
   
	    for (var key in _window) {
   
	      var descriptor = Object.getOwnPropertyDescriptor(global, key)

	      if (!descriptor || descriptor.configurable === true) {
   
	        Object.defineProperty(window, key, {
   
	          value: _window[key]
	        })
	      }
	    }

	    for (var _key in _window.document) {
   
	      var _descriptor = Object.getOwnPropertyDescriptor(global.document, _key)

	      if (!_descriptor || _descriptor.configurable === true) {
   
	        Object.defineProperty(global.document, _key, {
   
	          value: _window.document[_key]
	        })
	      }
	    }
	    window.parent = window
	  } else {
   
	    for (var _key2 in _window) {
   
	      global[_key2] = _window[_key2]
	    }
	    global.window = _window
	    window = global
	    window.top = window.parent = window
	  }
	}

	if (!GameGlobal.__isAdapterInjected) {
   
	  GameGlobal.__isAdapterInjected = true
	  inject()
	}

/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
   

	'use strict'

	Object.defineProperty(exports, "__esModule", {
   
	  value: true
	})
	exports.cancelAnimationFrame = exports.requestAnimationFrame = exports.clearInterval = exports.clearTimeout = exports.setInterval = exports.setTimeout = exports.canvas = exports.location = exports.localStorage = exports.HTMLElement = exports.FileReader = exports.Audio = exports.Image = exports.WebSocket = exports.XMLHttpRequest = exports.navigator = exports.document = undefined

	var _WindowProperties = __webpack_require__(2)

	Object.keys(_WindowProperties).forEach(function (key) {
   
	  if (key === "default" || key === "__esModule") return
	  Object.defineProperty(exports, key, {
   
	    enumerable: true,
	    get: function get() {
   
	      return _WindowProperties[key]
	    }
	  })
	})

	var _constructor = __webpack_require__(3)

	Object.keys(_constructor).forEach(function (key) {
   
	  if (key === "default" || key === "__esModule") return
	  Object.defineProperty(exports, key, {
   
	    enumerable: true,
	    get: function get() {
   
	      return _constructor[key]
	    }
	  })
	})

	var _Canvas = __webpack_require__(9)

	var _Canvas2 = _interopRequireDefault(_Canvas)

	var _document2 = __webpack_require__(10)

	var _document3 = _interopRequireDefault(_document2)

	var _navigator2 = __webpack_require__(17)

	var _navigator3 = _interopRequireDefault(_navigator2)

	var _XMLHttpRequest2 = __webpack_require__(18)

	var _XMLHttpRequest3 = _interopRequireDefault(_XMLHttpRequest2)

	var _WebSocket2 = __webpack_require__(19)

	var _WebSocket3 = _interopRequireDefault(_WebSocket2)

	var _Image2 = __webpack_require__(11)

	var _Image3 = _interopRequireDefault(_Image2)

	var _Audio2 = __webpack_require__(12)

	var _Audio3 = _interopRequireDefault(_Audio2)

	var _FileReader2 = __webpack_require__(20)

	var _FileReader3 = _interopRequireDefault(_FileReader2)

	var _HTMLElement2 = __webpack_require__(4)

	var _HTMLElement3 = _interopRequireDefault(_HTMLElement2)

	var _localStorage2 = __webpack_require__(21)

	var _localStorage3 = _interopRequireDefault(_localStorage2)

	var _location2 = __webpack_require__(22)

	var _location3 = _interopRequireDefault(_location2)

	function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
    default: obj } }

	exports.document = _document3.default
	exports.navigator = _navigator3.default
	exports.XMLHttpRequest = _XMLHttpRequest3.default
	exports.WebSocket = _WebSocket3.default
	exports.Image = _Image3.default
	exports.Audio = _Audio3.default
	exports.FileReader = _FileReader3.default
	exports.HTMLElement = _HTMLElement3.default
	exports.localStorage = _localStorage3.default
	exports.location = _location3.default


	// 暴露全局的 canvas
	var canvas = new _Canvas2.default()

	exports.canvas = canvas
	exports.setTimeout = setTimeout
	exports.setInterval = setInterval
	exports.clearTimeout = clearTimeout
	exports.clearInterval = clearInterval
	exports.requestAnimationFrame = requestAnimationFrame
	exports.cancelAnimationFrame = cancelAnimationFrame

/***/ }),
/* 2 */
/***/ (function(module, exports) {
   

	"use strict"

	Object.defineProperty(exports, "__esModule", {
   
	  value: true
	})

	var _wx$getSystemInfoSync = wx.getSystemInfoSync(),
	    screenWidth = _wx$getSystemInfoSync.screenWidth,
	    screenHeight = _wx$getSystemInfoSync.screenHeight,
	    devicePixelRatio = _wx$getSystemInfoSync.devicePixelRatio

	var innerWidth = exports.innerWidth = screenWidth
	var innerHeight = exports.innerHeight = screenHeight
	exports.devicePixelRatio = devicePixelRatio
	var screen = exports.screen = {
   
	  availWidth: innerWidth,
	  availHeight: innerHeight
	}
	var performance = exports.performance = {
   
	  now: function now() {
   
	    return Date.now() / 1000
	  }
	}
	var ontouchstart = exports.ontouchstart = null
	var ontouchmove = exports.ontouchmove = null
	var ontouchend = exports.ontouchend = null

/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
   

	'use strict'

	Object.defineProperty(exports, "__esModule", {
   
	  value: true
	})
	exports.HTMLCanvasElement = exports.HTMLImageElement = undefined

	var _HTMLElement3 = __webpack_require__(4)

	var _HTMLElement4 = _interopRequireDefault(_HTMLElement3)

	function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
    default: obj } }

	function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function") } }

	function _possibleConstructorReturn(self, call) {
    if (!self) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called") } return call && (typeof call === "object" || typeof call === "function") ? call : self }

	function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass) } subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
    value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass }

	var HTMLImageElement = exports.HTMLImageElement = function (_HTMLElement) {
   
	  _inherits(HTMLImageElement, _HTMLElement)

	  function HTMLImageElement() {
   
	    _classCallCheck(this, HTMLImageElement)

	    return _possibleConstructorReturn(this, (HTMLImageElement.__proto__ || Object.getPrototypeOf(HTMLImageElement)).call(this, 'img'))
	  }

	  return HTMLImageElement
	}(_HTMLElement4.default)

	var HTMLCanvasElement = exports.HTMLCanvasElement = function (_HTMLElement2) {
   
	  _inherits(HTMLCanvasElement, _HTMLElement2)

	  function HTMLCanvasElement() {
   
	    _classCallCheck(this, HTMLCanvasElement)

	    return _possibleConstructorReturn(this, (HTMLCanvasElement.__proto__ || Object.getPrototypeOf(HTMLCanvasElement)).call(this, 'canvas'))
	  }

	  return HTMLCanvasElement
	}(_HTMLElement4.default)

/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
   

	'use strict'

	Object.defineProperty(exports, "__esModule", {
   
	  value: true
	})

	var _createClass = function () {
    function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
    var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor) } } return function (Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor } }()

	var _Element2 = __webpack_require__(5)

	var _Element3 = _interopRequireDefault(_Element2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值