【Cocos Creator游戏开发教程】仿微信趣味画赛车小游戏(一)前言,界面UI
【Cocos Creator游戏开发教程】仿微信趣味画赛车小游戏(二)物理刚体关节
项目地址已放到 github 上,需要的小伙伴可自行下载。
这节我们讲一下游戏代码实现
1.开启物理世界
// GameMain.tsprotected onLoad(): void {cc.director.getPhysicsManager().enabled = true; // 开启物理引擎需要写在 onLoad 中}protected start(): void {cc.debug.setDisplayStats(false);this.openPhysics();this.node.on(DrawArea.DRAW_VEHICLE, this.onDrawVehicle, this);}private openPhysics(): void {let manager: cc.PhysicsManager = cc.director.getPhysicsManager();manager.enabledAccumulator = true;manager.debugDrawFlags = 1;// 设置调试绘制标志cc.PhysicsManager.FIXED_TIME_STEP = 1 / 30;cc.PhysicsManager.VELOCITY_ITERATIONS = 8;cc.PhysicsManager.POSITION_ITERATIONS = 8;}
2.画车
监听触摸DrawArea开始事件,将绘画节点移到触摸点,记录存储当前触摸点
// DrawArea.tsprivate onTouchStart(event: cc.Event.EventTouch): void {// 转换到局部坐标let pos = this.node.convertToNodeSpaceAR(event.getLocation());this.drawLine.moveTo(pos.x, pos.y);this.recordPos = cc.v2(pos.x, pos.y);this.drawPoints.push(cc.v2(pos.x, pos.y));}
监听触摸DrawArea移动事件
// DrawArea.tsprivate onTouchMove(event: cc.Event.EventTouch): void {let pos: cc.Vec2 = this.node.convertToNodeSpaceAR(event.getLocation());let widthLimit: number = (this.node.width + DrawArea.DRAW_CIRCLE_R) / 2;let heightLimit: number = (this.node.height + DrawArea.DRAW_CIRCLE_R) / 2;// 检查当前触摸点是否超出绘画区域if (pos.x < -widthLimit || pos.x > widthLimit) {return;}if (pos.y < -heightLimit || pos.y > heightLimit) {return;}// 绘画this.drawLine.lineTo(pos.x, pos.y);this.drawLine.stroke();this.drawLine.moveTo(pos.x, pos.y);// 记录当前手移动到的点this.currentPos = cc.v2(pos.x, pos.y);//求两点之间的距离let subVec: cc.Vec2 = this.currentPos.sub(this.recordPos);let distance: number = subVec.mag() + 5; // 防止线段间出现空隙,所以+5长度// 为了减少触摸点数量,如果距离大于等于预制体的width,记录存储该触摸点if (distance >= 25) {// 将此时的触摸点设为记录点this.recordPos = cc.v2(pos.x, pos.y);this.drawPoints.push(cc.v2(pos.x, pos.y));}}
监听触摸DrawArea结束事件,发送自定义画车事件,将触摸点数组发送出去
// DrawArea.tsprivate onTouchEnd(event: cc.Event.EventTouch): void {// 判断触摸点数量是否小于2,不是才发送画车事件if (this.drawPoints.length <= 1) {this.drawPoints = [];return;}// 发送自定义画车事件 DrawArea.DRAW_VEHICLElet customEvent: cc.Event.EventCustom = new cc.Event.EventCustom(DrawArea.DRAW_VEHICLE, true);customEvent.setUserData(this.drawPoints);this.node.dispatchEvent(customEvent);// 清空绘画区域,存储的触摸点this.drawLine.clear();this.drawPoints = [];}
3.创建小车
监听自定义画车事件,获取绘画节点数组,调用Vehicle.ts脚本刷新小车
// GameMain.tsprivate onDrawVehicle(event: cc.Event.EventCustom): void {event.stopPropagation();(this.vehicle.getComponent('Vehicle') as Vehicle).updateVehicle(event.getUserData());}
收到监听,调用刷新车方法
// Vehicle.tspublic updateVehicle(drawPoints: Array<cc.Vec2>): void {if (drawPoints.length <= 0) {return;}let _self = this;// 重置车位置_self.node.x = 0;_self.node.y = 200;// 重置车_self.resetVehicle();// 画车身_self.drawVehicleBody(drawPoints);// 画轮子_self.drawWheel(drawPoints);// 激活车节点if (!_self.node.active) {_self.node.active = true;}}
重置车,清空子节点
// Vehicle.tsprivate resetVehicle(): void {let _self = this;let vehicleNode: cc.Node = _self.vehicle.node; // 获取车节点vehicleNode.removeAllChildren();_self.vehicleBodys = [];_self.wheelRear = null;_self.wheelFront = null;}
画车身
// Vehicle.tsprivate drawVehicleBody(drawPoints: Array<cc.Vec2>): void {let _self = this;let vehicleNode: cc.Node = _self.vehicle.node; // 获取车节点let beforePos: cc.Vec2 = drawPoints[0];for (let i = 1; i < drawPoints.length; i++) {let curPos: cc.Vec2 = drawPoints[i];let subVec: cc.Vec2 = curPos.sub(beforePos);let distance: number = subVec.mag() + 5; // 防止线段间出现空隙,所以+5长度// 给定方向向量let tempVec: cc.Vec2 = cc.v2(0, 10);// 求两点的方向角度let rotateVec: number = subVec.signAngle(tempVec) / Math.PI * 180 - 90;// 创建车刚体小部件let lineItem: cc.Node = cc.instantiate(_self.linePrefab);lineItem.angle = -rotateVec;lineItem.setPosition(beforePos);lineItem.setParent(vehicleNode);// 这一步是为了防止两个线段之间出现空隙,动态改变预制体的长度lineItem.width = distance;// 设置刚体属性lineItem.getComponent(cc.PhysicsBoxCollider).offset.x = lineItem.width / 2;lineItem.getComponent(cc.PhysicsBoxCollider).size.width = lineItem.width;lineItem.getComponent(cc.PhysicsBoxCollider).sensor = true;lineItem.getComponent(cc.PhysicsBoxCollider).restitution = 100;lineItem.getComponent(cc.PhysicsBoxCollider).apply();// 首刚体不需要创建刚体焊接组件if (_self.vehicleBodys.length > 0) {let beforeLine: cc.Node = _self.vehicleBodys[_self.vehicleBodys.length - 1];// 焊接车刚体小部件let weldJoint: cc.WeldJoint = lineItem.addComponent(cc.WeldJoint);weldJoint.referenceAngle = -rotateVec - beforeLine.angle;weldJoint.connectedBody = beforeLine.getComponent(cc.RigidBody);weldJoint.connectedAnchor = cc.v2(beforeLine.width - 5, 0);}_self.vehicleBodys.push(lineItem);beforePos = cc.v2(curPos.x, curPos.y);}}
画轮子
// Vehicle.tsprivate drawWheel(drawPoints: Array<cc.Vec2>): void {let _self = this;let vehicleNode: cc.Node = _self.vehicle.node;// 首尾车身刚体let lineRear: cc.Node = _self.vehicleBodys[0];let lineFront: cc.Node = _self.vehicleBodys[_self.vehicleBodys.length - 1];let wheelSF: cc.SpriteFrame = new cc.SpriteFrame("HelloWorld");// 轮胎精灵帧// 首尾触摸点let rearPos: cc.Vec2 = drawPoints[0];let frontPos: cc.Vec2 = drawPoints[drawPoints.length - 1];// 通过预制节点,创建后轮let wheelRear: cc.Node = cc.instantiate(_self.wheelPrefab);wheelRear.getComponent(cc.Sprite).spriteFrame = wheelSF;wheelRear.setPosition(rearPos);vehicleNode.addChild(wheelRear);// 通过预制节点,创建前轮let wheelFront: cc.Node = cc.instantiate(_self.wheelPrefab);wheelRear.getComponent(cc.Sprite).spriteFrame = wheelSF;wheelFront.setPosition(frontPos);vehicleNode.addChild(wheelFront);// 添加轮子刚体标识wheelRear.getComponent(cc.PhysicsCircleCollider).tag = VehicleEnum.COLLIDER_TAG.REAR_TAG; // 后轮wheelFront.getComponent(cc.PhysicsCircleCollider).tag = VehicleEnum.COLLIDER_TAG.FRONT_TAG;// 前轮wheelRear.getComponent(cc.PhysicsCircleCollider).apply();wheelFront.getComponent(cc.PhysicsCircleCollider).apply();// 加入轮子关节// 后轮let wheelJointRear: cc.WheelJoint = ComponentUtil.addWheelJointToObj(lineRear, {connectedNode: wheelRear,anchor: cc.v2(0, 0)});// 前轮let wheelJointFront: cc.WheelJoint = ComponentUtil.addWheelJointToObj(lineFront, {connectedNode: wheelFront,anchor: cc.v2(lineFront.width - 5, 0)});// 添加距离关节,约束两个轮子let distanceJoint: cc.DistanceJoint = wheelRear.addComponent(cc.DistanceJoint);distanceJoint.connectedBody = wheelFront.getComponent(cc.RigidBody);distanceJoint.distance = frontPos.sub(rearPos).mag();_self.wheelRear = wheelRear;_self.wheelFront = wheelFront;}