本文主要是使用Cocos2.x版本完成一个左右跳跃的小游戏demo。游戏的核心玩法比较简单即是通过点击左右方向控制人物左右向上的跳跃。这里实现主要逻辑
- 玩法如下
1:场景/节点制作
- 在demo中主要是一个背景节点以及一个放置所有地板节点的父节点,当人物往上跳跃的时候就让所有地板节点的父节点往下方移动并且朝着点击方向的反方向移动地板宽度的一半,即可在场景中表现出是人物在往上跳跃的现象。
- 人物是通过不同的部位进行拼接得到的一个预制体。其中有jump和walk动画。
2:事件注册
- 由于游戏的玩法需要使用到触摸事件以及判断是点击在设备的左侧还是右侧,那么我们需要在代码中先添加触摸事件。
let isTouchEnabled = true
cc.Class({
extends: cc.Component,
properties: {
},
onLoad () {
this.initTouchEnabled();
},
initTouchEnabled() {
this.node.on("touchstart", this.touchStart, this, false);
this.node.on("touchend", this.touchEnd, this, false);
},
touchStart(event) {
if (!isTouchEnabled) return
let touchPos = event.getLocation()
if (touchPos.x < cc.winSize.width / 2) {
this.player.scaleX = -1 * Math.abs(this.player.scaleX)
this.blockMoveDown(false);
} else {
this.player.scaleX = Math.abs(this.player.scaleX)
this.blockMoveDown(true);
}
isTouchEnabled = false
this.player.getComponent(cc.Animation).play("jump")
},
touchEnd() {
cc.log("touchEnd--");
},
start () {
},
});
3:地块的生成与放置
- 地块的生成是每次会生成一些地块的位置数据放到一个数组里面,当场上的地块少于某个数量时,就会将数组内的地块位置赋值给对象池(对象池[cocos文档])中拿出来的地块。然后清空数组,再次生成一些地块的位置数据放到该数组内,重复下去。
const ladderNum = [2, 6];
let wallArr = [];
let totalWallArr = []
let position = [];
let totalPosition = []
let objectCount = 10;
let checkTime = 120
let isTouchEnabled = true
let playerPos = cc.v2(0, -400);
cc.Class({
extends: cc.Component,
properties: {
},
onLoad () {
this.getWallPosition()
this.createItem(position)
},
getWallPosition(isFirst = true) {
let x = playerPos.x
let y = playerPos.y
let width = 0
let height = 0
for (let i = 0; i < objectCount; i) {
let num = getRandom(ladderNum[0], ladderNum[1])
i + num < objectCount ? i += num : i = objectCount
if (!isFirst) {
let lasted = null
if (position.length > 0) {
lasted = position[position.length - 1];
} else {
lasted = totalPosition[totalPosition.length - 1]
}
x = lasted.x
y = lasted.y
width = lasted.width
height = lasted.height
}
let dstNum = getRandom(0, 3, false);
for (let j = 0; j < num; j++) {
let obj = {}
if (isFirst) {
let node = this.getWall()
width = node.getContentSize().width
height = node.getContentSize().height
node.setPosition(x, y)
this.wallNode.addChild(node)
isFirst = false
totalPosition.push({ "x": x, "y": y, "width": width, "height": height })
totalWallArr.push(node)
} else {
if (dstNum <= 2.5) {
dstNum <= 1.25 ? x += width / 2 : x -= width / 2;
y += height / 2
obj = { "x": x, "y": y, "width": width, "height": height }
position.push(obj)
} else {
this.getBoxPosition(x, y, width, height);
break
}
}
}
}
},
getBoxPosition(x, y, w, h) {
let r = getRandom(3, 6)
let l = getRandom(3, 6)
for (let i = 0; i <= r; i++) {
for (let j = 0; j <= l; j++) {
if (i == 0 && j == 0) continue
if (j == 0 || j == l || i == 0 || i == r) {
let dx = x + (i - j) * w / 2
let dy = y + (i + j) * h / 2
let pos = { "x": dx, "y": dy, "width": w, "height": h }
position.push(pos);
}
}
}
},
createItem(posArr) {
let index = true;
for (let pos of posArr) {
let node = this.getWall();
node.setPosition(pos.x, pos.y + 500)
this.wallNode.addChild(node)
if (index) {
index = false;
node.zIndex = totalWallArr[totalWallArr.length - 1].zIndex - 1
} else {
node.zIndex = wallArr[wallArr.length - 1].zIndex - 1
}
cc.tween(node)
.by(0.1, { scale: 0.1, angle: 10 })
.by(0.1, { scale: -0.1, angle: -10 })
.by(0.3, { position: cc.v2(0, -500) })
.start();
wallArr.push(node)
}
totalPosition = totalPosition.concat(posArr);
posArr = []
totalWallArr = totalWallArr.concat(wallArr);
wallArr = []
return posArr
},
start () {
},
});
4:人物下方的地块检测与下移重新放入对象池
- 在本示例中人物下方的地块是通过一个简单的相对的节点的y坐标来判断的。小于人物的y坐标-某个值时,将该地块节点下移且移动到屏幕外时将该节点重新放入对象池。
cc.Class({
extends: cc.Component,
properties: {
},
onLoad () {
},
blockMoveDown(isRight = false) {
let node = totalWallArr[totalWallArr.length - 1];
let delX = 0;
isRight ? delX = - node.width / 2 : delX = node.width / 2
cc.tween(this.wallNode)
.by(0.2, { position: cc.v2(delX, -node.height / 2 - 20) })
.by(0.15, { position: cc.v2(0, 20) })
.call(() => {
if(!this.checkPlayerPos(isRight, node)){
this.playerFall()
return
}
isTouchEnabled = true
this.checkBlock();
})
.start()
},
playerFall(){
cc.tween(this.player)
.by(0.2, { position: cc.v2(0, 50) })
.by(0,2)
.by(2, { position: cc.v2(0, -cc.winSize.height) })
.call(() => {
this.gameOver()
})
.start()
},
checkPlayerPos(isRight, wall) {
isRight ? playerPos.x += wall.width / 2 : playerPos.x += -wall.width / 2
playerPos.y += wall.height / 2
for (let pos of totalPosition) {
if(Math.abs(pos.x-playerPos.x)<1&&Math.abs(pos.y-playerPos.y)<1){
return true
}
}
return false
},
checkBlock() {
let count = 0
for (let node of totalWallArr) {
let worldPos = localConvertWorldPointAR(node)
let dstPos = worldConvertLocalPoint(this.player, worldPos)
if (count >= 2) return
if (dstPos.y < -120) {
count++
totalPosition = removeObjFromArray(node, totalPosition)
totalWallArr = removeObjFromArray(node, totalWallArr)
cc.tween(node)
.by(0.1, { scale: 0.1, angle: -10 })
.by(0.1, { scale: -0.1, angle: 20 })
.by(0.1, { scale: 0.1, angle: -20 })
.by(0.1, { scale: -0.1, angle: 10 })
.by(1, { position: cc.v2(0, -cc.winSize.height / 2) })
.call(() => {
if (totalWallArr.length < 8) {
this.getWallPosition(false)
setTimeout(() => {
position = this.createItem(position);
}, 0.5);
}
this.putWall(node);
})
.start();
} else {
}
}
},
start () {
},
});
完结完结,overover!
|