我们要实现的效果是,按住并拖动一个物体,物体跟随手指(鼠标)移动,拖到指定位置放下,如果没有拖到指定位置 就放开则会返回到原始位置。
新建脚本DragItem.ts,挂到要拖动的预制体上
const { ccclass, property } = cc._decorator;
@ccclass
export default class DragItem extends cc.Component {
@property({type:cc.Node, tooltip:"拖动去的指定区域节点列表"})
targetOfDragList: cc.Node[] = [];
@property({tooltip:"是否吸附到中点心"})
isCenter:boolean = true;
_onDragComp:Function=null;
_oldPos = null; // 上一个位置
_target:cc.Node = null;//所在的槽位;
start() {
this._oldPos = this.node.position;
}
onEnable() {
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
}
onDisable() {
this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
}
public get target():cc.Node{
return this._target;
}
public set onDragComp(value:Function){
this._onDragComp = value;
}
_onTouchMove(touchEvent) {
let location = touchEvent.getLocation();
this.node.position = this.node.parent.convertToNodeSpaceAR(location); // 确定位置
}
_onTouchEnd(touchEvent) {
if (this.targetOfDragList.length === 0) {
return; // 没有目标位置
}
let inTarget = false;
let offsetX:number = 0;
let offsetY:number = 0;
for (const targetNode of this.targetOfDragList) {
let checkData:{isIn:boolean, offsetX?:number, offsetY?:number} = this._withinTarget(targetNode, touchEvent);
if (checkData.isIn) {
this._target = targetNode;
inTarget = true;
offsetX = checkData.offsetX;
offsetY = checkData.offsetY;
break;
}
}
if (!inTarget) {
this._target = null;
this.node.position = this._oldPos; //还回去
}else{
if(this.isCenter){
this.node.position = cc.v3(this.node.x-offsetX, this.node.y-offsetY);//吸咐到中心点上
}
}
if(this._onDragComp){
this._onDragComp(this.node, this._target);
}
}
/**
* 判断触摸事件是否在槽位里
* @param targetNode
* @param touchEvent
* @returns isIn是否在槽位里,offsetX与槽位中心点的偏移量X,offsetY与槽位中心点的偏移量Y
*/
_withinTarget(targetNode: cc.Node, touchEvent):{isIn:boolean, offsetX?:number, offsetY?:number} {
let rect = targetNode.getBoundingBox();
let location = touchEvent.getLocation();
let point = targetNode.parent.convertToNodeSpaceAR(location);
let checkData:any = {};
let isIn:boolean = rect.contains(point);
checkData.isIn = isIn;
if(isIn){
let centerX:number = rect.x + rect.width * 0.5;
let centerY:number = rect.y + rect.height * 0.5;
checkData.offsetX = point.x-centerX;
checkData.offsetY = point.y-centerY;
}
return checkData;
}
}
思路与之前的拖动类似。
在最后TOUCH_END的时候,判断自己是否在目标区域内。
如果不在则返回上一个坐标。
在场景中使用
import DragItem from "./DragItem";
const { ccclass, property } = cc._decorator;
@ccclass
export default class DragDemo extends cc.Component {
@property(cc.Prefab) dragitem: cc.Prefab = null;
@property([cc.Node]) dragTargets: cc.Node[] = [];
start() {
this.createItem();
}
createItem() {
let d = cc.instantiate(this.dragitem);
this.node.addChild(d);
let dragTo = d.getComponent(DragItem);
dragTo.targetOfDragList = this.dragTargets;// 设置目的地
}
}