251 lines
6.3 KiB
TypeScript
251 lines
6.3 KiB
TypeScript
import { CCFloat, Component, Enum, error, EventTouch, macro, Node, UIOpacity, UITransform, Vec2, Vec3, _decorator } from "cc";
|
|
import { Vec3Util } from "../../../../../extensions/oops-plugin-framework/assets/core/utils/Vec3Util";
|
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
/**
|
|
* 方向类型
|
|
*/
|
|
export enum DirectionType {
|
|
FOUR,
|
|
EIGHT,
|
|
ALL,
|
|
}
|
|
|
|
/**
|
|
* 速度类型
|
|
*/
|
|
export enum SpeedType {
|
|
Start,
|
|
STOP,
|
|
NORMAL,
|
|
FAST,
|
|
}
|
|
|
|
/**
|
|
* 摇杆类型
|
|
*/
|
|
export enum JoystickType {
|
|
FIXED,
|
|
FOLLOW,
|
|
}
|
|
|
|
export interface JoystickDataType {
|
|
/** 速度类型 */
|
|
type: SpeedType;
|
|
|
|
/** 移动向量 */
|
|
vector: Vec3;
|
|
|
|
/** 角度 */
|
|
angle: number;
|
|
}
|
|
|
|
|
|
export type ControllerFunc = (event: EventTouch, data: JoystickDataType) => void;
|
|
|
|
/** 摇杆 */
|
|
@ccclass("RoleViewUIJoystick")
|
|
export class RoleViewUIJoystick extends Component {
|
|
@property({
|
|
type: Node,
|
|
tooltip: "摇杆操纵点",
|
|
})
|
|
dot: Node | null = null;
|
|
|
|
@property({
|
|
type: Node,
|
|
tooltip: "摇杆背景节点",
|
|
})
|
|
ring: Node | null = null;
|
|
|
|
@property({
|
|
type: Enum(JoystickType),
|
|
tooltip: "触摸类型",
|
|
})
|
|
joystickType = JoystickType.FIXED;
|
|
|
|
@property({
|
|
type: Enum(DirectionType),
|
|
tooltip: "方向类型",
|
|
})
|
|
directionType = DirectionType.ALL;
|
|
|
|
@property({
|
|
tooltip: "摇杆所在位置"
|
|
})
|
|
_stickPos = new Vec3();
|
|
|
|
@property({
|
|
tooltip: "触摸位置"
|
|
})
|
|
_touchLocation = new Vec2();
|
|
|
|
@property({
|
|
type: CCFloat,
|
|
tooltip: "摇杆背景半径"
|
|
})
|
|
radius = -1;
|
|
|
|
onController: ControllerFunc | null = null;
|
|
|
|
onLoad() {
|
|
if (!this.dot) {
|
|
error("Joystick Dot is null!");
|
|
return;
|
|
}
|
|
|
|
if (!this.ring) {
|
|
error("Joystick Ring is null!");
|
|
return;
|
|
}
|
|
|
|
// 摇杆背景半径
|
|
if (this.radius == -1)
|
|
this.radius = this.ring.getComponent(UITransform)!.width / 2;
|
|
|
|
// 摇杆跟随跟随时默认隐藏界面
|
|
const uiOpacity = this.node.getComponent(UIOpacity);
|
|
if (this.joystickType === JoystickType.FOLLOW && uiOpacity) {
|
|
uiOpacity.opacity = 0;
|
|
}
|
|
|
|
this._initTouchEvent();
|
|
}
|
|
|
|
/**
|
|
* 改变摇杆类型
|
|
* @param type
|
|
*/
|
|
setJoystickType(type: JoystickType) {
|
|
this.joystickType = type;
|
|
const uiOpacity = this.node.getComponent(UIOpacity);
|
|
if (uiOpacity) {
|
|
uiOpacity.opacity = type === JoystickType.FIXED ? 255 : 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 初始化触摸事件
|
|
*/
|
|
private _initTouchEvent() {
|
|
this.node.on(Node.EventType.TOUCH_START, this._touchStartEvent, this);
|
|
this.node.on(Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this);
|
|
this.node.on(Node.EventType.TOUCH_END, this._touchEndEvent, this);
|
|
this.node.on(Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this);
|
|
}
|
|
|
|
/**
|
|
* 触摸开始回调函数
|
|
* @param event
|
|
*/
|
|
private _touchStartEvent(event: EventTouch) {
|
|
if (!this.ring || !this.dot) return;
|
|
|
|
if (this.onController) {
|
|
this.onController(event, {
|
|
type: SpeedType.Start,
|
|
vector: Vec3Util.zero,
|
|
angle: 0
|
|
});
|
|
}
|
|
|
|
const location = event.getUILocation();
|
|
const touchPos = new Vec3(location.x, location.y);
|
|
|
|
if (this.joystickType === JoystickType.FIXED) {
|
|
this._stickPos = this.ring.getWorldPosition();
|
|
|
|
// 相对中心的向量
|
|
const moveVec = touchPos.subtract(this.ring.getWorldPosition());
|
|
// 触摸点与圆圈中心的距离
|
|
const distance = moveVec.length();
|
|
|
|
// 手指在圆圈内触摸,控杆跟随触摸点
|
|
if (this.radius > distance) {
|
|
this.dot.setPosition(moveVec);
|
|
}
|
|
}
|
|
else if (this.joystickType === JoystickType.FOLLOW) {
|
|
// 记录摇杆位置,给 touch move 使用
|
|
this.node.getComponent(UIOpacity)!.opacity = 255;
|
|
this._stickPos = touchPos;
|
|
this._touchLocation = event.getUILocation();
|
|
// 更改摇杆的位置
|
|
|
|
this.ring.setWorldPosition(touchPos);
|
|
this.dot.setPosition(Vec3.ZERO);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 触摸移动回调函数
|
|
* @param event
|
|
*/
|
|
private _touchMoveEvent(event: EventTouch) {
|
|
if (!this.dot || !this.ring) return;
|
|
|
|
// 如果 touch start 位置和 touch move 相同,禁止移动
|
|
if (this.joystickType === JoystickType.FOLLOW && this._touchLocation === event.getUILocation()) {
|
|
return false;
|
|
}
|
|
|
|
// 以圆圈为锚点获取触摸坐标
|
|
const location = event.getUILocation();
|
|
const touchPos = new Vec3(location.x, location.y);
|
|
|
|
// 移动向量
|
|
const moveVec = touchPos.subtract(this.ring.getWorldPosition());
|
|
const distance = moveVec.length();
|
|
|
|
let speedType = SpeedType.NORMAL;
|
|
if (this.radius > distance) {
|
|
this.dot.setPosition(moveVec);
|
|
speedType = SpeedType.NORMAL;
|
|
}
|
|
else {
|
|
// 控杆永远保持在圈内,并在圈内跟随触摸更新角度
|
|
this.dot.setPosition(moveVec.normalize().multiplyScalar(this.radius));
|
|
speedType = SpeedType.FAST;
|
|
}
|
|
|
|
// 算出与(1,0)的夹角
|
|
let angle = this.covertToAngle(moveVec);
|
|
|
|
if (this.onController) {
|
|
this.onController(event, {
|
|
type: speedType,
|
|
vector: moveVec.normalize(),
|
|
angle
|
|
});
|
|
}
|
|
}
|
|
|
|
/** 根据位置转化角度 */
|
|
private covertToAngle(pos: Vec3) {
|
|
let angle = Math.atan2(pos.y, pos.x);
|
|
return angle * macro.DEG;
|
|
}
|
|
|
|
/**
|
|
* 触摸结束回调函数
|
|
* @param event
|
|
*/
|
|
private _touchEndEvent(event: EventTouch) {
|
|
if (!this.dot || !this.ring) return;
|
|
|
|
this.dot.setPosition(new Vec3());
|
|
if (this.joystickType === JoystickType.FOLLOW) {
|
|
this.node.getComponent(UIOpacity)!.opacity = 0;
|
|
}
|
|
|
|
if (this.onController) {
|
|
this.onController(event, {
|
|
type: SpeedType.STOP,
|
|
vector: Vec3Util.zero,
|
|
angle: 0
|
|
});
|
|
}
|
|
}
|
|
}
|