cocos creator 3.8 合成大西瓜Demo 11
界面上的Node节点: 背景 警戒线 三面墙 初始位置节点 水果容器
先分组吧,墙 地板 水果
创建预制体 先挂一个脚本 刚体碰撞器先弄上再说
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('FruitData')
export class FruitData extends Component {
//水果的Id 区分哪一种水果的
fruitId: number = 0;
//水果的碰撞次数 主要记录水果的状态用的
contactNum: number = 0;
//是否合成
isSynthesis: boolean = false;
}
再建一个脚本,开始折腾走起
@property({ type: Node, displayName: "水果生成的位置" })
fruitStart: Node = null;//大小随便,位置合理就行,不行就大小[0,0]
@property({ type: Node, displayName: "水果的父节点" })
fruitRoot: Node = null;//水果容器
@property({ type: [Prefab], displayName: "水果的预制体" })
fruitPrefabs: Prefab[] = [];//一堆水果的预制体
//存储临时节点,方便计算用
currentFruit: Node = null;
@property({ type: Node, displayName: "警告" })
WarnningLine: Node = null;
开始游戏了
start() {
//创建一个随机水果,前两前三的
this.createRadomFruit();
//加上触摸监听 看api好像input比node监听使用范围广
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
}
创建水果了
createRadomFruit() {
const fruitId: number = Math.floor(Math.random() * 3);
const fruitNode: Node = instantiate(this.fruitPrefabs[fruitId]);
fruitNode.setPosition(this.fruitStart.position);
//禁用刚体,用来监听移动事件后再开启
fruitNode.getComponent(RigidBody2D).enabled = false;
fruitNode.getComponent(RigidBody2D).gravityScale = 2;
//赋值
fruitNode.getComponent(FruitData).fruitId = fruitId;
fruitNode.getComponent(FruitData).contactNum = 0;
//监听碰撞
const collider2D: Collider2D = fruitNode.getComponent(Collider2D);
collider2D.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
fruitNode.setParent(this.fruitRoot);
//用一个临时的Node来存储这个节点,方便操作
this.currentFruit = fruitNode;
}
两个监听
//收到点击事件后,水果位置平移
onTouchStart(event: EventTouch) {
//放置连续点击
if (!this.currentFruit) return;
//可以看看这个https://blog.csdn.net/weixin_44053279/article/details/129568612
//获取 UI 坐标系下的触点位置
const touchPos = event.getUILocation();
//记住 是父节点 可以搜一下坐标空间转换
const parentPos = this.fruitRoot.getComponent(UITransform).convertToNodeSpaceAR(v3(touchPos.x, touchPos.y, 0));
//这是个节点位置 position现在是个静态的 拿不到.x
const fruitPos = this.currentFruit.getPosition();
fruitPos.x = parentPos.x;
// 防止穿透,还是用tween动画吧
// this.currentFruit.setPosition(fruitPos);
tween(this.currentFruit)
.to(.3, { position: fruitPos })
.start();
}
onTouchEnd(event: EventTouch) {
//放置连续点击
if (!this.currentFruit) return;
this.currentFruit.getComponent(RigidBody2D).enabled = true;
this.currentFruit = null;
//延时一下 生成下一个
this.scheduleOnce(this.createRadomFruit, 2);
//用来检测是否超过预期位置没
this.scheduleOnce(this.checkGameOver, 2);
}
碰撞检测
//3.8 .d.ts中没给监听的参数
//https://forum.cocos.org/t/topic/158425
onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
const selfFruitData = selfCollider.getComponent(FruitData);
const otherFruitData = otherCollider.getComponent(FruitData);
if (otherCollider.group === Math.pow(2, 1)) {
selfCollider.getComponent(FruitData).contactNum += 1;
otherCollider.getComponent(FruitData).contactNum += 1;
}
if (otherCollider.group === Math.pow(2, 3)) {
selfCollider.getComponent(FruitData).contactNum += 1;
}
if (otherCollider.group !== Math.pow(2, 1)) return;
//Id相同 未合成 否则也返回
if (selfFruitData.fruitId !== otherFruitData.fruitId) return;
if (selfFruitData.isSynthesis || otherFruitData.isSynthesis) return;
selfFruitData.isSynthesis = true;
otherFruitData.isSynthesis = true;
//合成后的新水果
const synthesisFruitId = selfFruitData.fruitId + 1;
const synthesisFruitPos = selfCollider.node.position;
//https://blog.csdn.net/loveyoulouyou/article/details/127583198
this.scheduleOnce(() => {
otherCollider.getComponent(RigidBody2D).enabled = false;
selfCollider.getComponent(RigidBody2D).enabled = false;
tween(otherCollider.node)
.to(.2, { position: synthesisFruitPos })
.to(.2, { scale: new Vec3(1.2, 1.2, 1) })
.parallel()
.call(() => {
//碰撞后立即实例化会报错,给一个延时器,tween动画都可以
this.createSynthesisFruit(synthesisFruitId, synthesisFruitPos);
})
.call(() => {
selfCollider.node.destroy();
otherCollider.node.destroy();
})
.start();
}, 0.1);
};
合成的逻辑
createSynthesisFruit(synthesisFruitId: number, synthesisFruitPos: Vec3) {
const SynthesisNode: Node = instantiate(this.fruitPrefabs[synthesisFruitId]);
//刚体碰撞 回弹可能造成穿透效果
synthesisFruitPos.y += 10;
SynthesisNode.setPosition(synthesisFruitPos);
SynthesisNode.getComponent(RigidBody2D).enabled = false;
SynthesisNode.getComponent(FruitData).contactNum = 0;
SynthesisNode.getComponent(RigidBody2D).gravityScale = 2;
//赋值
SynthesisNode.getComponent(FruitData).fruitId = synthesisFruitId;
//监听碰撞
SynthesisNode.getComponent(Collider2D).on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
SynthesisNode.setParent(this.fruitRoot);
this.scheduleOnce(() => {
//立即改变刚体状态也会报错,给一个延时
SynthesisNode.getComponent(RigidBody2D).enabled = true;
SynthesisNode.getComponent(FruitData).contactNum += 1;
if (synthesisFruitId === this.fruitPrefabs.length - 1) {
// if (synthesisFruitId === 3) {
console.log("=====================胜利了=====================");
this.reStartGame();
}
}, .1);
}
检测是否要结束游戏
//遍历所有水果,比较高度
checkGameOver() {
const warnningLinePos = this.WarnningLine.getPosition();
for (let i = 0; i < this.fruitRoot.children.length; i++) {
const element = this.fruitRoot.children[i];
//水果没下落呢
if (element.getComponent(FruitData).contactNum === 0) continue;
if (element.getPosition().y >= warnningLinePos.y - 300) {
console.log("=====================游戏警告=====================");
}
if (element.getPosition().y >= warnningLinePos.y) {
console.log("=====================游戏结束=====================");
break;
}
}
}
重新开始
//重新开始
reStartGame() {
this.fruitRoot.removeAllChildren();
this.createRadomFruit();
}
就这样了,没写其它的逻辑,刚体有点乱,不要立即改变一些东西,总之就是要么用计时器,要么tween一下。