Files
MatchMaster/assets/Script/lq_collide_system/lq_collide.ts

548 lines
21 KiB
TypeScript

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;
public is_music: boolean = false;
//检测绘制组件是否添加
private checkDebugDrawValid() {
if (!this._debugDrawer || !this._debugDrawer.isValid) {
let node = this.node.getChildByName('Collide');
if (!node && this.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" && this.data_string != "-2") {
// 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" && this.data_string != "-2") {
// 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_enter(collide: LQCollide) {
if (this.disableCollider(collide)) {
return;
}
// if (LQCollideConfig.switch_print_log) {
// console.log(this.node.name + ' on_enter');
// }
let block = this.node.parent.getComponent("Block");
if (collide.node.name == "rise" && block.type == 9) {
let otherColor = collide.node.parent.getChildByName("risefall").getChildByName("color").getComponent(cc.Label).string;
if (block.color == otherColor && this.data_string != "-1" && this.data_string != "-2") {
return;
}
if (block) {
if (block.block_Info) {
if (block.block_Info.node.getComponent("Block").color == otherColor && this.data_string != "-1" && this.data_string != "-2") {
return;
}
}
}
// if (this.is_music == false) {
// this.is_music = true;
cc.fx.AudioManager._instance.playEffect("simpleColor", null);
// }
}
else if (collide.node.name == "rise" && block.type != 9) {
let otherColor = collide.node.parent.getChildByName("risefall").getChildByName("color").getComponent(cc.Label).string;
if (block.color == otherColor) {
return;
}
// if (this.is_music == false) {
// this.is_music = true;
cc.fx.AudioManager._instance.playEffect("simpleColor", null);
// }
}
}
//@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;
}
// if (collide.node.name == "rise") {
// this.is_music = false;
// }
}
}
}
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) {
if (collide.node.name == "rise" && block.type == 9) {
let otherColor = collide.node.parent.getChildByName("risefall").getChildByName("color").getComponent(cc.Label).string;
// console.log("我的顔色", block.color, "粘合顔色", block.block_Info.node.getComponent("Block").color, "單色通過地块颜色:", otherColor, this.data_string);
if (block.color == otherColor && this.data_string != "-1" && this.data_string != "-2") {
return;
}
if (block.block_Info.node.getComponent("Block").color == otherColor && (this.data_string == "-1" || this.data_string == "-2")) {
return;
}
}
else if (collide.node.name == "rise" && block.type != 9) {
let otherColor = collide.node.parent.getChildByName("risefall").getChildByName("color").getComponent(cc.Label).string;
if (block.color == otherColor) {
return;
}
}
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");
// 固定单色通道与藤蔓、伸缩杆共用 rise,只放行地图登记的单色通道。
if ((block.oldRainbow || block.color === 100) && collide.node.name === "rise"
&& MapConroler._instance?.riseFallBlock?.indexOf(collide.node.parent) >= 0) {
jg = true;
}
if (block.type == 1 || block.type == 10 || block.type == 9) {
if (collide.node.parent == block.block_Info.node) {
jg = true;
}
}
if (collide.node.parent.getComponent("Block")) {
let collideBlock = collide.node.parent.getComponent("Block");
let blockType22 = block.type == 22;
let collideType22 = collideBlock.type == 22;
if (blockType22 != collideType22) {
// 同色或彩虹可穿过单色地块,保留原有的组合移动限制。判断实际的
// 非单色方块,避免碰撞双方顺序不同时出现一边能过、一边不能过。
let colorBlock = blockType22 ? collideBlock : block;
if ((colorBlock.oldRainbow || colorBlock.color === 100 || block.color == collideBlock.color) && colorBlock.canPassSameColorSimpleBlock()) {
jg = true;
}
}
}
}
}
}
return jg;
}
}