您的位置:首页 > 其它

寿司快卖:实现游戏主流程--制作寿司和客户显示动画特效

2018-10-29 17:09 183 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tyler_download/article/details/83509070

上一节我们搭建了游戏的基本框架。游戏界面被分为若干个板块,其中一个板块显示了各种制作寿司的材料,它的目的是用于玩家根据信息组装各种寿司,本节我们进入游戏的主流程设计阶段,这节我们要完成的是如何将让玩家将各种材料组合成相应的寿司。

首先我们先添加一些辅助函数,在gamescenecomponent.vue中添加代码如下:

resizeCanvas () {
// change 2
var customerView = document.getElementById('customer-view')
var w = this.getBorderView(customerView)
this.canvas = document.getElementById('canvas')
this.canvas.width = customerView.offsetWidth - w.left - w.right
this.canvas.height = customerView.offsetHeight - w.top - w.bottom
},

...

//change 1
initDomElement () {
....
this.others = document.getElementById('others')
this.rices = document.getElementById('rice')
this.seaweeds = document.getElementById('seaweed')

// 设置相应寿司的材料组合
this.recipes['sushiSalmonRoe'] = ['rice', 'seaweed', 'seaweed', 'salmon-roe'].sort()
this.recipes['sushiOctopus'] = ['rice', 'octopus'].sort()
this.recipes['sushiSalmon'] = ['rice', 'salmon'].sort()
this.recipes['sushiEgg'] = ['rice', 'egg', 'seaweed'].sort()
},
getBorderWidths (element) {
var style = document.getComputedStyled(element)
return {
top: parseInt(style.borderTopWidth),
right: parseInt(style.borderRightWidth),
bottom: parseInt(style.borderBottomWidth),
left: parseInt(style.borderLeftWidth)
}
},
// change 3
arrayIsEqual (array1, array2) {
if (array1.length !== array2.length) {
return false
}

for (var i = 0, len=array1.length; i < len; i++) {
if (array1[i] !== array2[i]) {
return false
}
}

return true
},
clearChild (node) {
while (node.lastChild) {
node.removeChild(node.lastChild)
}
},
clearAllIngredients () {
this.clearChild(others)
this.clearChild(rices)
this.clearChild(seaweeds)
}
}

上面代码用于计算可知Dom元素的大小位置,以及在Dom中添加或删除各种元素。在制作寿司时,玩家通过选取相应材料组合起来形成所需要的寿司,相应代码如下:

initDOMElements () {
// change 6
var ingredients = document.querySelectorAll('.ingredient')
for (var i = 0, len = ingredients.length; i < len; i++) {
var element = ingredients[i]
element.onclick = this.ingredentOnclick.bind(this)
}

var deleteButton = document.getElementById('delete-sushi-btn')
deleteButton.onclick = this.deleteButtonOnclick.bind(this)

this.ingredientsNode = document.getElementById('ingredient')
},
// change 7
deleteButtonOnclick () {
this.trashSushi()
},

...

// change 5
trashSushi () {
this.sushiOnHand.length = 0
this.clearAllIngredients()
}

当玩家选取若干种制作寿司的材料后,界面要做相应变化,对应代码如下:

// change 8
ingredentOnclick (ingredient) {
console.log('ingredient click:', ingredient)
var type = ingredient.toElement.dataset.type
this.sushiOnHand = this.sushiOnHand.sort()
this.addIngredientToScreen(type)
},
addIngredientToScreen (type) {
var isEqualToAnySushi = false
var sushiName = ''
for (var key in this.recipes) {
if (this.recipes.hasOwnProperty()) {
// 当前选中的材料是不是属于某个指定的寿司菜单里
isEqualToAnySushi = this.arrayIsEqual(this.sushiOnHand, this.recipes[key])
sushiName = key
if (isEqualToAnySushi) {
break
}
}
}

// 把所有选中的材料组合起来形成一个寿司
if (isEqualToAnySushi) {
this.clearAllIngredients()
var sushi = document.createElement('div')
sushi.classList.add(sushiName, 'sushi')
this.others.appendChild(sushi)
} else {
// 把选择材料拷贝到寿司板块
var node = this.ingredientsNode.querySelector('.ingredient[data-type=' + type + ']').cloneNode(true)
node.style.height = '80px'
if (type === 'rice') {
console.log('append to rice:', this.rices)
this.rices.appendChild(node)
} else if (type === 'seaweed') {
console.log('append to seaweeds:', this.seaweeds)
this.seaweeds.appendChild(node)
} else {
console.log('append to others:', this.others)
this.others.appendChild(node)
}
}

当上面代码完成后,玩家在寿司面板点击一个图片代表的元素时,如果它属于某个寿司组合菜单中的一部分,那么它就会显示在右边面板上,如下图所示:

当我们点击右上角的trash按钮时,下面选中的元素会被删除掉。接着我们继续添加顾客动画特效,客户将随机的出现在场景中央区域,根据一个随机值它会出现在左上方或右下方,一开始客户出现时它会显示出愉快的表情,如下图:

此时玩家应该根据客户的要求,点击左下方的材料图片组装出客户想要的寿司,如果时间过长没能及时将寿司制作出了,客户就会显示出愤怒的表情,如下图:

我们看看相应代码的实现:

data () {
return {
canvas: null,
// change 4
sushiOnHand: [],
recipes: [],
// change 10:
view: {},
queues: [],
queueIndex: 0,
leftPos: 0.40,
rightPos: 0.8
}
},
....
// change 9
initCustomerView () {
console.log('this.cjs: ', this.cjs)
this.stage = new this.cjs.Stage(this.canvas)
this.cjs.Ticker.setFPS(60)
this.cjs.Ticker.addEventListener('tick', this.stage)
this.cjs.Ticker.addEventListener('tick', this.tick)
// 实现客户队列
this.view.queueLeft = new this.cjs.Container()
this.stage.addChild(this.view.queueLeft)
this.view.queueRight = new this.cjs.Container()
this.stage.addChild(this.view.queueRight)
},

通过上面代码,为程序添加一个时钟,我们将根据时钟变化来设置游戏的动画效果,接着我们编写构造客户动画的代码:

// change 11 设置顾客对象
Customer (number, leftOrRight) {
var obj = new this.cjs.Container()
obj.number = number
// 随机构造客户想要吃的寿司
obj.wants = this.randomWants()
// 客户是否吃到指定寿司
obj.hasEaten = false
// 是否把客户放到队列前头
obj.hasShowUp = false
// 客户等待了多久
obj.hasWaitForTicks = 0
// 在左队列还是右队列
obj.queueIndex = 0
if (leftOrRight === 'right') {
obj.queueIndex = 1
}

return obj
},
randomWants () {
var options = ['sushiSalmonRoe', 'sushiOctopus', 'sushiSalmon', 'sushiEgg']
var index = Math.floor(Math.random() * options.length)
return options[index]
},
customerTick (customer) {
if (customer.hasShowUp === false) {
return
}
customer.hasWaitForTicks += 1
if (customer.hasShownUp === true && customer.hasWaitForTicks === 300) {
// 显示愤怒的顾客图片
console.log('customer angry')
customer.graphics.gotoAndStop('angry')
}
// 如果等待太久,将顾客从画面上删除
if (customer.hasWaitForTicks > 500) {
this.removeCustomer(customer)
}
// 如果成功吃到寿司,也将客户图片从页面删除
if (customer.hasEaten) {
this.removeCustomer(customer)
}
},
removeCustomer (customer) {
if (customer.parent === null) {
console.log('remove customer with null parent:', customer)
}
customer.parent.removeChild(customer)
this.removeFromQueue(customer.queueIndex)
},

上面代码构建客户对象,并且初始化它相关信息,customerTick用来根据时钟变化调整客户动画的显示,当经过一定时长,如果相关条件没有满足,那么我们就将客户的愉悦动画,通过调用gotoAndStop(‘angry’)来时实现将客户动画转变为愤怒表情,当时长超过500 tick后,我们将客户动画从页面上删除,客户在页面上的显示需要执行下面代码:

// 将客户图片显示到页面上
customerShowUp (customer) {
customer.graphics = new this.assetsLib['Customer' + customer.number]()
customer.graphics.gotoAndStop('normal')
customer.graphics.on('click', this.customerOnClick)
customer.addChild(customer.graphics)

var bubble = new this.assetsLib.Bubble()
bubble.x = -40
bubble.y = -120
customer.addChild(bubble)
bubble.sushiType.gotoAndStop(customer.wants)
customer.hasShowUp = true

this.customer = customer
},
customerOnClick () {
var isEqual = this.arrayIsEqual(this.sushiOnHand,
this.receipes[this.customer.wants])
if (isEqual) {
this.customer.hasEaten = true
}

this.trashSushi()
},
removeFromQueue (index) {
this.queues[index].shift()
},
tick () {
var durationForNewCustomer = 500
if (this.cjs.Ticker.getTicks() % durationForNewCustomer === 0) {
console.log('summon customer')
this.summonNewCustomer()
var customer = this.queues[0][0]
if (customer && !customer.hasShowUp) {
console.log('show up customer left')
this.customerShowUp(customer)
}
customer = this.queues[1][0]
if (customer && !customer.hasShowUp) {
console.log('show up customer right')
this.customerShowUp(customer)
}
}
if (this.queues[0][0] !== undefined) {
this.customerTick(this.queues[0][0])
}
if (this.queues[1][0] !== undefined) {
this.customerTick(this.queues[1][0])
}
},
summonNewCustomer () {
var leftOrRight = 'left'
var queueIndex = 0
if (Math.random() >= 0.5) {
leftOrRight = 'right'
queueIndex = 1
}

var customer = this.Customer(1, leftOrRight)
this.queues[queueIndex].push(customer)
this.queueIndex = queueIndex
if (leftOrRight === 'left') {
this.view.queueLeft.addChild(customer)
customer.parent = this.view.queueLeft
} else {
this.view.queueRight.addChild(customer)
customer.parent = this.view.queueRight
}
},

summonNewCustomer函数用来创建一个客户对象,并根据一个随机数决定客户是出现在页面的左上角还是右下角,时钟每次触发时,函数tick会被调用,在里面代码根据ticks来决定是否创建一个客户对象,每500个ticks就创建一个客户对象,当客户对象出现300个tick后显示愤怒表情,500个tick后自动从页面上删除,完成上面代码后,我们就可以看到前面所示的动画特效了。

更详细的讲解和代码调试演示过程,请点击链接

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐