博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【默默努力】ig-wxz-and-hotdog
阅读量:5319 次
发布时间:2019-06-14

本文共 14842 字,大约阅读时间需要 49 分钟。

这个是一个非常跟热点的小游戏,思聪吃热狗。这个游戏的话,我感觉思路还挺简单的,天上会掉热狗和障碍物,

思聪在下面张开嘴巴,进行左右移动,接热狗。如果吃到的是热狗就得一分,如果思聪吃到的不是热狗,是障碍物,就结束游戏。
如果要衍生的话,其实可以将热狗的下落方向不定的,就像俄罗斯方块那样,思聪的嘴巴也可以除了向上接热狗,还可以所有咬热狗那种。
感觉很简单很好玩的游戏哇,先放游戏的效果。
1037363-20190902114436572-1758738865.gif
我们看动图可以发现,其实这个里面除了热狗障碍物,还有一个是得5分的大能量。
先放作者的github地址:https://github.com/sl1673495/ig-wxz-and-hotdog
接下来我们一起分析代码
项目入口为

//index.js中会初始化游戏import Scheduler from './modules/scheduler'function initGame() {    new Scheduler()}initGame()

utils文件夹中是工具函数

//ig-wxz-and-hotdog\app\utils\index.jsexport const isUndef = (v) =>  v === null || v === undefinedexport const noop = () => {}export * from './constant'export * from './dom'export * from './device'export { default as eventEmitter } from './event'
//ig-wxz-and-hotdog\app\utils\constant.jsexport const PLYAYER_OPTIONS = {    img: require('@/assets/images/sicong.jpg'),    width: 70,    height: 70,}export const DIALOG_OPTIONS = {    width: 250,    height: 170,}// 坠落到底事件export const CHECK_FALL_EVENT = 'checkFall'
//定义的一些设备//ig-wxz-and-hotdog\app\utils\device.jsconst ua = window.navigator.userAgentconst dpr = window.devicePixelRatioconst w = window.screen.widthconst h = window.screen.height// iPhone X、iPhone XSconst isIPhoneX = /iphone/gi.test(ua) && dpr && dpr === 3 && w === 375 && h === 812// iPhone XS Maxconst isIPhoneXSMax = /iphone/gi.test(ua) && dpr && dpr === 3 && w === 414 && h === 896// iPhone XRconst isIPhoneXR = /iphone/gi.test(ua) && dpr && dpr === 2 && w === 414 && h === 896const needSafe = isIPhoneX || isIPhoneXSMax || isIPhoneXRexport const safeHeight = needSafe ? 45 : 0export const screenHeight = window.innerHeight - safeHeightexport const screenWidth = Math.max(window.innerWidth, 300)
//ig-wxz-and-hotdog\app\utils\dom.jsimport { isUndef } from './index'const supportsPassive = (function () {    let support = false    try {        const opts = Object.defineProperty({}, 'passive', {            get: function () {                support = true            }        })        window.addEventListener('test', null, opts)    } catch (e) { }    return support})()export const addEvent = (    node,    event,    fn,    options = {}) => {    let { capture, passive } = options    capture == isUndef(capture) ? false : capture    passive = isUndef(passive) ? true : passive    if (typeof node.addEventListener == 'function') {        if (supportsPassive) {            node.addEventListener(event, fn, {                capture,                passive,            })        } else {            node.addEventListener(event, fn, capture)        }    }    else if (typeof node.attachEvent == 'function') {        node.attachEvent('on' + event, fn);    }}export const removeEvent = function (node, event, fn) {    if (typeof node.removeEventListener == 'function') {        node.removeEventListener(event, fn);    }    else if (typeof node.detatchEvent == 'function') {        node.detatchEvent('on' + event, fn);    }}export const removeNode = (node) => node.parentNode.removeChild(node)

事件函数

//ig-wxz-and-hotdog\app\utils\event.jsclass EventEmitter {    constructor() {        this._event = {}        this._listeners = []    }    on(name, callback) {        (this._event[name] || (this._event[name] = [])).push(callback)    }    emit(name, payload) {        const cbs = this._event[name] || []        for (let i = 0, len = cbs.length; i < len; i++) {            cbs[i](payload)        }        if (this._listeners.length) {            for (let { trigger, callback } of this._listeners) {                if (trigger(name)) {                    callback()                }            }        }    }    remove(name) {        this._event[name] = null    }    clear() {        this._event = {}    }    // 监听某些事件时使用    listen(condition, callback) {        let trigger        if (condition instanceof RegExp) {            trigger = eventName => condition.test(eventName)        } else if (typeof condition === 'string') {            trigger = eventName => eventName.includes(condition)        }        this._listeners.push({            trigger,            callback        })    }}export default new EventEmitter()
//ig-wxz-and-hotdog\app\store\index.js//游戏中的状态管理/** * 全局状态管理 */class ReactiveStore {  constructor() {    this._store = {}    this._listeners = {}  }  // currying  createAction(key) {    const set = (val) => {      this.set(key, val)    }    const get = () => {      return this.get(key)    }    const subscribe = (fn) => {      return this.subscribe(key, fn)    }    return {      get,      set,      subscribe,    }  }  // set的时候触发subscribe的方法  set(key, val) {    this._store[key] = val    const listeners = this._listeners[key]    if (listeners) {      listeners.forEach(fn => fn())    }  }  get(key) {    return this._store[key]  }  // 订阅某个key的set执行fn回调  subscribe(key, cb) {    (this._listeners[key] || (this._listeners[key] = [])).push(cb)    // return unsubscribe    return () => {      const cbs = this._listeners[key]      const i = cbs.findIndex(f => cb === f)      cbs.splice(i, 1)    }  }}const store = new ReactiveStore()const { set: setScore, get: getScore, subscribe: subscribeScore } = store.createAction('score')const { set: setSeconds, get: getSeconds, subscribe: subscribeSeconds } = store.createAction('seconds')export {  setScore,  getScore,  subscribeScore,  setSeconds,  getSeconds,  subscribeSeconds,}
//ig-wxz-and-hotdog\app\modules\bounus-point.js/** * 得分提示 */import { PLYAYER_OPTIONS, safeHeight, addEvent, removeNode } from '@/utils'const { height: playerHeight } = PLYAYER_OPTIONSexport default class BounusPoint {  constructor(x, bounus) {    this.$el = null    this.left = x    this.bottom = safeHeight + playerHeight    this.bounus = bounus    this.init()    this.initEvent()  }  init() {    const el = document.createElement('div')    el.style.cssText = `       position: fixed;       z-index: 2;       width: auto;       height: 20px;       text-align: center;       left: ${this.left}px;       bottom: ${this.bottom}px;       font-weight: 700;       font-size: 18px;       animation:bounus 1s;    `    const text = document.createTextNode(`+${this.bounus}`)    el.appendChild(text)    document.body.appendChild(el)    this.$el = el  }  initEvent() {    addEvent(this.$el, 'animationend', () => {      removeNode(this.$el)    })  }}
//动态创建弹框//ig-wxz-and-hotdog\app\modules\dialog.js/** * 游戏结束对话框 */import { screenWidth, DIALOG_OPTIONS, addEvent, removeNode, noop } from '@/utils'import {    getScore,} from 'store'const { width, height } = DIALOG_OPTIONSexport default class Dialog {    constructor(onLeftClick, onRightclick) {        this.onLeftClick = onLeftClick ? () => {            this.destory()            onLeftClick()        } : noop        this.onRightClick = onRightclick || noop        this.initDialog()    }    initDialog() {        const dialog = document.createElement('div')        dialog.style.cssText = `            position: fixed;            z-index: 2;            width: ${width}px;            height: ${height}px;            padding-top: 20px;            border: 2px solid black;            text-align: center;            left: ${screenWidth / 2 - width / 2}px;            top: 200px;            font-weight: 700;        `        const endText = createText('游戏结束', 'font-size: 30px;')        const scoreText = createText(`${getScore()}分`, 'font-size: 30px;')        const restartBtn = createButton('replay', this.onLeftClick, 'left: 20px;')        const starBtn = createButton('❤star', this.onRightClick, 'right: 20px;')        dialog.appendChild(endText)        dialog.appendChild(scoreText)        dialog.appendChild(restartBtn)        dialog.appendChild(starBtn)        document.body.appendChild(dialog)        this.$el = dialog    }    destory() {        removeNode(this.$el)    }}const createText = (text, extraCss) => {    const p = document.createElement('p')    p.style.cssText = `        font-weight: 700;        text-align: center;        margin-bottom: 8px;        ${extraCss}    `     const textNode = document.createTextNode(text)    p.appendChild(textNode)    return p}const createButton = (text, fn, extraCss) => {    const button = document.createElement('div')    button.style.cssText = `        position: absolute;        width: 90px;        bottom: 20px;        border: 2px solid black;        font-weight: 700;        font-size: 20px;        ${extraCss}    `    const textNode = document.createTextNode(text)    button.appendChild(textNode)    addEvent(button,'click', fn)    return button}

这个是下落部分的

//ig-wxz-and-hotdog\app\modules\fall.js/** * 掉落物 */import {    screenWidth,    screenHeight,    PLYAYER_OPTIONS,    CHECK_FALL_EVENT,    removeNode,    eventEmitter,} from '@/utils'// 每次下落的距离const INTERVAL_DISTANCE = 15const CUP = {    width: 50,    height: 100,    img: require('@/assets/images/cup.jpg'),    bounus: 5,}const HOT_DOG = {    width: 20,    height: 50,    img: require('@/assets/images/hotdog.jpg'),    bounus: 1,}const {    height: playerHeight,} = PLYAYER_OPTIONSexport default class Fall {    constructor() {        this.img = null        this.bounus = 0        this.width = 0        this.height = 0        this.posY = 0        this.moveTimes = 0        this.randomFallItem()        this.calcTimePoint()        this.initFall()        this.startFall()    }    randomFallItem() {        const fallItem = Math.random() <= 0.08            ? CUP            : HOT_DOG        const { img, bounus, width, height } = fallItem        this.img = img        this.bounus = bounus        this.width = width        this.height = height    }    // 计算开始碰撞的时间点    calcTimePoint() {        const { width, height } = this        // 从生成到落到人物位置需要的总移动次数        this.timesToPlayer = Math.floor((screenHeight - playerHeight - height) / INTERVAL_DISTANCE)        // 从生成到落到屏幕底部需要的总移动次数        this.timesToEnd = Math.floor(screenHeight / INTERVAL_DISTANCE)    }    initFall() {        this.posX = getScreenRandomX(this.width)        const { width, height, posX } = this        const fall = document.createElement('img')        this.$el = fall        fall.src = this.img        fall.style.cssText = `            position: fixed;            width: ${width}px;            height: ${height}px;            left: ${posX}px;            transform: translateY(0px);            z-index: 0;        `        document.body.appendChild(fall)    }    updateY() {        this.moveTimes++        // 进入人物范围 生成高频率定时器通知外部计算是否碰撞        if (this.moveTimes === this.timesToPlayer) {            if (!this.emitTimer) {                this.emitTimer = setInterval(() => {                    eventEmitter.emit(CHECK_FALL_EVENT, this)                }, 4)            }        }        // 到底部了没有被外部通知销毁 就自行销毁        if (this.moveTimes === this.timesToEnd) {            this.destroy()            return        }        const nextY = this.posY + INTERVAL_DISTANCE        this.$el.style.transform = `translateY(${nextY}px)`        this.posY = nextY    }    destroy() {        this.emitTimer && clearInterval(this.emitTimer)        this.fallTimer && clearInterval(this.fallTimer)        removeNode(this.$el)    }    startFall() {        this.fallTimer = setInterval(() => {            this.updateY()        }, 16)    }}function getScreenRandomX(width) {    return Math.random() * (screenWidth - width)}
//ig-wxz-and-hotdog\app\modules\player.js/** * 人物 */import { screenWidth, safeHeight, addEvent, PLYAYER_OPTIONS, isUndef } from '@/utils'const { width: playerWidth, height: playerHeight, img } = PLYAYER_OPTIONSexport default class Player {    constructor() {        // 初始化位置 屏幕正中        this.posX = screenWidth / 2 - playerWidth / 2        this.initPlayer()        this.initMoveEvent()    }    //初始化图像    initPlayer() {        const el = this.$el = document.createElement('img')        el.src = img        el.style.cssText = `            position: fixed;            bottom: ${safeHeight}px;            width: ${playerWidth}px;            height: ${playerHeight}px;            transform: translateX(${ screenWidth / 2 - playerWidth / 2}px);            z-index: 1;        `        document.body.appendChild(el)    }    //移动事件    initMoveEvent() {        const body = document.body                addEvent(            body,            'touchstart',            e => {                setPositionX(this, e)            })        const moveEvent = 'ontouchmove' in window ? 'touchmove' : 'mousemove'        addEvent(            body,            moveEvent,            e => {                e.preventDefault()                setPositionX(this, e)            },            {                passive: false            }        )    }}//设置位置const setPositionX = (player, e) => {    let x = e.pageX    if (isUndef(x)) {        x = e.touches[0].clientX    }    const { $el } = player    $el.style.transform = `translateX(${checkScreenLimit(x - (playerWidth / 2))}px)`    player.posX = x}//设置位置限制const checkScreenLimit = (x) => {    const leftLimit = 0 - (playerWidth / 2)    const rightLimit = screenWidth - (playerWidth / 2)    return x < leftLimit        ? leftLimit        : x > rightLimit            ? rightLimit            : x}

分数

//ig-wxz-and-hotdog\app\modules\score-board.js/** * 计分板 */import {    setScore,    getScore,    subscribeScore,    getSeconds} from 'store'class Score {    constructor() {        this.$el = null        this.initScore()        subscribeScore(this.renderScore.bind(this))    }    initScore() {        const score = document.createElement('div')        score.style.cssText = `            position: fixed;            z-index: 2;            width: 100px;            height: 50px;            line-height: 50px;            text-align: center;            right: 0;            top: 0;            font-size: 30px;            font-weight: 700;        `        this.$el = score        document.body.appendChild(score)    }    addScore(bounus) {        const seconds = getSeconds()        if (seconds !== 0) {            setScore(getScore() + bounus)        }    }        renderScore() {        this.$el.innerText = getScore()    }}export default Score

计时板

//ig-wxz-and-hotdog\app\modules\time-board.js/** * 计时板 */import { subscribeSeconds, getSeconds } from 'store'export default class TimeBoard {  constructor() {    this.$el = null    this.initTimerBoard()    subscribeSeconds(this.renderTimerText.bind(this))  }  initTimerBoard() {    const board = document.createElement('div')    board.style.cssText = `            position: fixed;            z-index: 2;            width: 200px;            height: 50px;            line-height: 50px;            text-align: center;            left: 0;            top: 0;            font-size: 30px;            font-weight: 700;        `    document.body.appendChild(board)    this.$el = board  }  renderTimerText() {    this.$el.innerText = createTimerText(getSeconds())  }}const createTimerText = (seconds) => `剩余时间${seconds}秒`

后记,我没有看懂到底怎么写的

转载于:https://www.cnblogs.com/smart-girl/p/11446279.html

你可能感兴趣的文章
京华同学聚会
查看>>
@bzoj - 3750@ [POI2015] Pieczęć
查看>>
PHP定时任务
查看>>
浅谈性能测试
查看>>
Winform 菜单和工具栏控件
查看>>
jequery动态创建form
查看>>
CDH版本大数据集群下搭建的Hue详细启动步骤(图文详解)
查看>>
第六次java作业
查看>>
巧用Win+R
查看>>
浅析原生js模仿addclass和removeclass
查看>>
Python中的greenlet包实现并发编程的入门教程
查看>>
tweenlite使用说明
查看>>
ContentProvider数据访问详解
查看>>
java中遍历属性字段及值(常见方法)
查看>>
在iPhone应用中使用自定义字体
查看>>
在AD的环境下,更改计算机名导致TFS,无法连接解决办法
查看>>
Jenkins执行批处理文件失败
查看>>
linux下vi命令大全
查看>>
JAVA 基础坑
查看>>
oracle 创建自定义的流水号
查看>>