import ccclass = cc._decorator.ccclass; import property = cc._decorator.property; import requireComponent = cc._decorator.requireComponent; import menu = cc._decorator.menu; import Component = cc.Component; import Enum = cc.Enum; import Size = cc.Size; import Vec2 = cc.Vec2; import Graphics = cc.Graphics; import Node = cc.Node; import macro = cc.macro; import Color = cc.Color; import { LQCollideShape, LQCollideStatus } from "../lq_base/data/lq_const"; import { LQCollideConfig, LQCollideInfoList } from "./lq_collide_config"; import { LQCollideSystem } from "./lq_collide_system"; import { LQRect } from "../lq_base/data/lq_data"; import { LQCollideBase } from "./lq_collide_base"; import { LQGameUtil } from "../lq_base/util/lq_game_util"; import MapConroler from "../Map"; @ccclass @requireComponent(LQCollideBase) @menu("lq/collide") export class LQCollide extends Component { velocity: any; @property({ displayName: '绘制形状' }) get draw_collide(): boolean { return this._draw_collide; } set draw_collide(value: boolean) { this._draw_collide = value; this.draw_shape(); } @property protected _draw_collide: boolean = true; @property({ tooltip: '能否移动' }) protected can_move: boolean = true; @property({ tooltip: '碰撞形状,None就是无敌,不参与碰撞', type: Enum(LQCollideShape), displayName: '碰撞形状' }) get collide_shape(): LQCollideShape { return this._collide_shape; } set collide_shape(value: LQCollideShape) { this._collide_shape = value; this.draw_shape(); } @property() public _collide_shape: LQCollideShape = LQCollideShape.Rect; @property({ type: Enum(LQCollideInfoList), tooltip: '碰撞类别', displayName: '碰撞类别' }) get collide_group_index() { if (this._collide_group_index === -1) { this._collide_group_index = LQCollideSystem.get_info_by_id(this.collide_group_id).index; } return this._collide_group_index; } set collide_group_index(value) { if (this._collide_group_index === value) { return; } this._collide_group_index = value; this.collide_group_id = LQCollideSystem.get_group_by_index(value).id; } @property({ serializable: false }) private _collide_group_index = -1; @property({ visible: false }) protected collide_group_id: number = 0; @property({ visible: false }) protected collide_scle: number = 1; @property({ tooltip: 'collide半径', visible() { // @ts-ignore return this._collide_shape === LQCollideShape.Circle; }, displayName: '半径' }) get radius(): number { return this._radius; } set radius(value: number) { this._radius = value; this.draw_shape(); } @property() protected _radius: number = 50; // 物体速度 // public velocity: Vec2 = new Vec2(0, 0); @property({ tooltip: 'collide长宽', visible() { // @ts-ignore return this._collide_shape === LQCollideShape.Rect; }, displayName: '长宽' }) get size(): Size { return this._size; } set size(value: Size) { this._size = value; if (this.world_rect) { this.world_rect.width = value.width; this.world_rect.height = value.height; this.world_rect.half_width = value.width * 0.5; this.world_rect.half_height = value.height * 0.5; } this.draw_shape(); } @property() protected _size: Size = new Size(100, 100); @property({ displayName: '位置偏移' }) get offset(): Vec2 { return this._offset; } set offset(value: Vec2) { this._offset = value; this.draw_shape(); } @property({ type: Vec2, visible() { // @ts-ignore return this._collide_shape === LQCollideShape.Polygon; }, displayName: '多边形碰撞点' }) get polygon_points(): Vec2[] { return this._polygon_points; } set polygon_points(value: Vec2[]) { this._polygon_points = value; this.draw_shape(); } @property() public _polygon_points: Vec2[] = [new Vec2(-45, -45), new Vec2(45, -45), new Vec2(60, 40), new Vec2(0, 70), new Vec2(-60, 40)]; //collide碰撞位置偏移 @property() public _offset: Vec2 = new Vec2(0, 0); @property({ displayName: '自定义字符串' }) public data_string: string = ''; //每个collide的id唯一 public collide_id: number = 0; //状态 public collide_status: LQCollideStatus = LQCollideStatus.Idle; //是否可碰撞 public is_enable: boolean = true; //是否开启碰撞前后的函数 public is_open_func: boolean = true; //碰撞类别 public collide_category = 0; //碰撞筛选 public collide_mask = 0; //缓存多边形碰撞数据 public cache_polygon_points: number[]; //绘制collide形状组件 private _debugDrawer!: Graphics; public world_rect!: LQRect; public collide_map: { [key: number]: { collide: LQCollide, status: 1 | 2 } } = {}; public follow_target_category: number | undefined; private static id_maker: number = 1; //检测绘制组件是否添加 private checkDebugDrawValid() { if (!this._debugDrawer || !this._debugDrawer.isValid) { let node = this.node.getChildByName('Collide'); if (!node) { node = new Node('Collide'); node.zIndex = macro.MAX_ZINDEX; this.node.addChild(node); // @ts-ignore node._objFlags = 1096; this._debugDrawer = node.addComponent(Graphics); this._debugDrawer.lineWidth = 3; this._debugDrawer.strokeColor = new Color(255, 0, 0); this._debugDrawer.fillColor = new Color(255, 0, 0); } else { this._debugDrawer = node.getComponent(Graphics); } } } //绘制形状 protected draw_shape() { if (!this._draw_collide) { if (this._debugDrawer) { this._debugDrawer.clear(); } return; } this.checkDebugDrawValid(); this._debugDrawer.clear(); let o1 = { key: 'scaleX', value: this.node.scale }; let o2 = { key: 'scaleY', value: this.node.scale }; LQGameUtil.recursion_node_property(this.node, o1); LQGameUtil.recursion_node_property(this.node, o2); if (o1.value === 0 || o2.value === 0) { return; } this._debugDrawer.node.scaleX = 1 / o1.value; this._debugDrawer.node.scaleY = 1 / o2.value; switch (this._collide_shape) { case LQCollideShape.Circle: this._debugDrawer.circle(+this._offset.x, +this._offset.y, this._radius); this._debugDrawer.stroke(); break; case LQCollideShape.Rect: this._debugDrawer.moveTo(-this._size.width * 0.5 + this._offset.x, -this._size.height * 0.5 + this._offset.y); this._debugDrawer.lineTo(-this._size.width * 0.5 + this._offset.x, +this._size.height * 0.5 + this._offset.y); this._debugDrawer.lineTo(this._size.width * 0.5 + this._offset.x, +this._size.height * 0.5 + this._offset.y); this._debugDrawer.lineTo(this._size.width * 0.5 + this._offset.x, -this._size.height * 0.5 + this._offset.y); this._debugDrawer.lineTo(-this._size.width * 0.5 + this._offset.x, -this._size.height * 0.5 + this._offset.y); this._debugDrawer.stroke(); break; case LQCollideShape.Polygon: this._debugDrawer.moveTo(this._polygon_points[0].x + this._offset.x, this._polygon_points[0].y + this._offset.y); for (let i = 1; i < this._polygon_points.length; i++) { this._debugDrawer.lineTo(this._polygon_points[i].x + this._offset.x, this._polygon_points[i].y + this._offset.y); } this._debugDrawer.lineTo(this._polygon_points[0].x + this._offset.x, this._polygon_points[0].y + this._offset.y); this._debugDrawer.stroke(); break; } } //仅用于矩形 public update_size(width: number, height: number) { this._size.width = width; this.world_rect.width = width; this.world_rect.half_width = width * 0.5; this._size.height = height; this.world_rect.height = height; this.world_rect.half_height = height * 0.5; this.draw_shape(); } public init_lq_collide() { this.world_rect = new LQRect(0, 0, this._size.width, this._size.height); this.draw_shape(); const info = LQCollideSystem.get_info_by_id(this.collide_group_id); this.collide_mask = info.mask; this.collide_category = info.category; this.collide_id = LQCollide.id_maker++; this.updateCollisionArea(); } private updateCollisionArea() { if (this._size.width == 0 || this._size.height == 0 || MapConroler._instance == undefined) { return; } if (MapConroler._instance.node.scale) { let scaleX = MapConroler._instance.node.scale; let scaleY = MapConroler._instance.node.scale; if (scaleX === 0 || scaleX == undefined || scaleX == null || scaleX == 1) { return; } switch (this._collide_shape) { case LQCollideShape.Circle: // 圆形碰撞区域半径更新 this._radius = this._radius * Math.max(scaleX, scaleY); break; case LQCollideShape.Rect: // 矩形碰撞区域尺寸更新 // console.log(this.data_string); if (this._size.width !== 10 && this.data_string != "-1") { // if(this._size.width == 105 || this._size.height == 105){} this._size.width = this._size.width * scaleX; // console.log("放大倍数",scaleX); } if (this._size.height !== 10 && this.data_string != "-1") { // if(this._size.width == 105 || this._size.height == 105){} this._size.height = this._size.height * scaleY; // console.log("放大倍数",scaleY); } // this._size.width = this._size.width * scaleX; // this._size.height = this._size.height * scaleY; if (this.world_rect) { this.world_rect.width = this._size.width; this.world_rect.height = this._size.height; this.world_rect.half_width = this._size.width * 0.5; this.world_rect.half_height = this._size.height * 0.5; } break; case LQCollideShape.Polygon: // 多边形碰撞点坐标更新 this._polygon_points = this._polygon_points.map(point => { return new Vec2(point.x * scaleX, point.y * scaleY); }); break; } this.draw_shape(); } } public enable_lq_collide() { if (this.collide_status === LQCollideStatus.Live) { console.warn(this.node.name + '重复添加'); return; } this.is_enable = true; this.collide_status = LQCollideStatus.Live; LQCollideSystem.add_collide(this); } public disable_lq_collide() { if (this.collide_status !== LQCollideStatus.Live) { return; } this.is_enable = false; this.collide_status = LQCollideStatus.Idle; LQCollideSystem.remove_collide(this); } public update_lq_collide() { } // @ts-ignore // public on_collide(collide: LQCollide): void { // if(collide.node.parent.uuid == this.node.parent.uuid){ // return; // } // if (LQCollideConfig.switch_print_log) { // if(this.node.parent.getComponent("Block")){ // let block = this.node.parent.getComponent("Block"); // if(block.isTouch){ // block.checkCollision = true; // // console.log("碰撞",this.node.name); // if(this.node.name == "top" ){ // console.log("碰到上边缘"); // block.moveUp = false; // if(block.touchPointY > (this.node.parent.y+this.node.height)){ // block.moveY = 1; // } // } // if(this.node.name === "down"){ // block.moveDown = false; // console.log("碰到下边缘"); // if(block.touchPointY < (this.node.parent.y )){ // block.moveY = -1; // } // } // if(this.node.name === "left" ){ // block.moveLeft = false; // console.log("碰到左边缘"); // if(block.touchPointX < (this.node.parent.x - this.node.parent.width)){ // block.moveX = -1; // } // } // if(this.node.name === "right"){ // block.moveRight = false; // console.log("碰到右边缘"); // if(block.touchPointX > (this.node.parent.x)){ // block.moveX = 1; // } // } // } // } // } // } //@ts-ignore public on_enter(collide: LQCollide) { if (this.disableCollider(collide)) { return; } // if (LQCollideConfig.switch_print_log) { // console.log(this.node.name + ' on_enter'); // } } //@ts-ignore public on_exit(collide: LQCollide) { if (this.disableCollider(collide)) { return; } if (LQCollideConfig.switch_print_log) { if (this.node.parent.getComponent("Block")) { let block = this.node.parent.getComponent("Block"); // if(!block.isTouch){ // return; // } block.checkCollision = false; if (this.node.name == "top") { block.moveUp = true; } if (this.node.name === "down") { block.moveDown = true; } if (this.node.name === "left") { block.moveLeft = true; } if (this.node.name === "right") { block.moveRight = true; } } } } public on_collide(collide: LQCollide): void { if (this.disableCollider(collide)) { return; } if (LQCollideConfig.switch_print_log) { if (this.node.parent.getComponent("Block")) { let block = this.node.parent.getComponent("Block"); let jg = false; if (block.isTouch) { block.checkCollision = true; // console.log("碰撞",this.node.name); if (this.node.name == "top") { // console.log(collide.node.parent.name); block.moveUp = false; if (block.touchPointY > (this.node.parent.y + this.node.parent.height)) { block.moveY = 1; } // console.log("碰到上边缘"); } if (this.node.name === "down") { block.moveDown = false; if (block.touchPointY < (this.node.parent.y)) { block.moveY = -1; } // console.log("碰到下边缘"); } if (this.node.name === "left") { block.moveLeft = false; if (block.touchPointX < (this.node.parent.x - this.node.parent.width)) { block.moveX = -1; } } if (this.node.name === "right") { block.moveRight = false; if (block.touchPointX > (this.node.parent.x)) { block.moveX = 1; } } if (this.node.name.startsWith("tan") && collide.node.name.startsWith("tan")) { // console.log("_____________" + this.node.name); if (this.node.name == "tan_down_left" && collide.node.name == "tan_up_right") { block.Bounce(this.node.name); } else if (this.node.name == "tan_down_right" && collide.node.name == "tan_up_left") { block.Bounce(this.node.name); } else if (this.node.name == "tan_up_left" && collide.node.name == "tan_down_right") { block.Bounce(this.node.name); } else if (this.node.name == "tan_up_right" && collide.node.name == "tan_down_left") { block.Bounce(this.node.name); } } } } } } public disableCollider(collide: LQCollide) { let jg = false; if (collide.node && this.node) { if (collide.node.parent && this.node.parent) { if (collide.node.parent.uuid == this.node.parent.uuid) { jg = true; } if (this.node.parent.getComponent("Block")) { let block = this.node.parent.getComponent("Block"); if (block.type == 1 || block.type == 10 || block.type == 9) { if (collide.node.parent == block.block_Info.node) { jg = true; } } } } } return jg; } }