<四>3D角色的移动和转向
这里只记录一般角色移动控制。比如摇杆输入。
移动控制
1.在触摸屏幕时,把摇杆移动到触摸位置。
2.在触摸移动时移动标点,标点要限制在摇杆范围内
把标点和摇杆范围(半径)的比值作为摇杆输入系数,通过这个移动系数来控制角色的移动,比值大就移动的快一些,比值小就移动的慢一些。
import { _decorator, CCFloat, Component, EventTouch, Input, input, Node, v3, Vec3 } from 'cc';
import { _gameData } from './GameMgr';
const { ccclass, property } = _decorator;
@ccclass('JoyStick')
export class JoyStick extends Component {
@property(Node)
stick_bg: Node = null;
@property(Node)
nail: Node = null;
@property({ type: CCFloat })
radius: number = 0;
start() {
this.stick_bg.active = false;
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
onTouchStart(event: EventTouch) {
//移动摇杆到触摸位置
let touch_point = event.getUILocation();
this.stick_bg.active = true;
this.stick_bg.setWorldPosition(touch_point.x, touch_point.y, 0);
}
onTouchMove(event: EventTouch) {
let touch_point = event.getUILocation();
//把世界坐标转换为stick_bg下的本地坐标
let local_point: Vec3 = v3();
this.stick_bg.inverseTransformPoint(local_point, v3(touch_point.x, touch_point.y, 0));
//计算local_point的长度
let length = local_point.length();
//如果长度大于半径,则限制长度为半径
if (length >= this.radius) {
local_point.normalize().multiplyScalar(this.radius);
};
//设置nail的位置
this.nail.setPosition(local_point.x, local_point.y, 0);
//存储(移动)摇杆系数
_gameData.stick_input_v = local_point.y / this.radius;
_gameData.stick_input_h = local_point.x / this.radius;
}
onTouchEnd(event: EventTouch) {
this.stick_bg.active = false;
this.nail.setPosition(0, 0, 0);
_gameData.stick_input_v = 0;
_gameData.stick_input_h = 0;
}
update(deltaTime: number) {
}
}
转向控制
import { v3, Vec3 } from "cc";
export class MathUtil {
/**
* 求带符号的夹角
* @param from 起点
* @param to 终点
* @param axis 朝向参照(轴)
*/
static signAngle(from: Vec3, to: Vec3, axis: Vec3): number {
//通过Vec3.angle方法计算两个向量之间的夹角
const angle = Vec3.angle(from, to);
//始末向量进行一个叉乘,两个向量的叉乘的结果就是两个向量所形成的平面的法向量
let cross = v3();
Vec3.cross(cross, from, to);
//判断这个向量和参照轴的向量的x,y,z轴的乘积,如果大于0,则说明这两个向量所形成的平面与axis向量所形成的平面是同侧的
//Math.sign() 函数返回一个数字的符号, 指示数字是正数,负数还是零。
const sign = Math.sign(cross.x * axis.x + cross.y * axis.y + cross.z * axis.z);
//得到的符号乘以夹角,如果大于0,则返回夹角,否则返回负的夹角
return sign * angle;
}
}
import { _decorator, CCFloat, CCInteger, Collider, Component, EventTouch, Input, input, Node, RigidBody, SkeletalAnimation, v3, Vec3 } from 'cc';
import { MathUtil } from './MathUtil';
import { _gameData } from './GameMgr';
const { ccclass, property } = _decorator;
enum PlayerState {
Idle1 = 'idle01',
Run = 'run',
Move = 'move',
}
@ccclass('PlayerCtrl')
export class PlayerCtrl extends Component {
@property(SkeletalAnimation)
player_ani: SkeletalAnimation = null;
@property(CCFloat)
move_speed: number = 1.0;
@property(CCFloat)
angleSpeed: number = 10;//角色旋转的线性移动速度
rigidBody: RigidBody = null;
collider: Collider = null;
_isTouch: boolean = false;
_temp_vec: Vec3 = v3();
_cur_state: PlayerState = null
start() {
this.rigidBody = this.node.getComponent(RigidBody);
this.collider = this.node.getComponent(Collider);
this.changePlayerState(PlayerState.Idle1);
}
changePlayerState(state: PlayerState) {
if (state == this._cur_state) return;
if (state == PlayerState.Idle1) {
this.stopMove();
}
this._cur_state = state;
this.player_ani.play(state);
}
doMove() {
//速度 = 方向(node.forward)*基础速度*速度因子(摇杆输入/加速减速)
const speed = this.move_speed * v3(_gameData.stick_input_h, 0, -_gameData.stick_input_v).length();//在编辑器中看到人物显示的朝向是负z的方向,这里取一个负值
this._temp_vec.x = this.node.forward.x * speed;
this._temp_vec.z = this.node.forward.z * speed;
this._temp_vec.y = 0;
this.node.getComponent(RigidBody).setLinearVelocity(this._temp_vec);
}
doRotate() {
//角色只会沿着Y轴旋转
this._temp_vec.x = 0;
//输入朝向和当前朝向的夹角(带符号)
const angle = MathUtil.signAngle(this.node.forward, v3(-_gameData.stick_input_h, 0, _gameData.stick_input_v), Vec3.UP)
this._temp_vec.y = angle * this.angleSpeed;
this._temp_vec.z = 0;
//设置角速度
this.rigidBody.setAngularVelocity(this._temp_vec);
}
stopMove() {
console.log('stopMove');
this.node.getComponent(RigidBody).setLinearVelocity(Vec3.ZERO);
this.node.getComponent(RigidBody).setAngularVelocity(Vec3.ZERO);
}
update(deltaTime: number) {
if (_gameData.stick_input_h != 0 || _gameData.stick_input_v != 0) {
this.changePlayerState(PlayerState.Run);
this.doRotate();
this.doMove();
} else {
this.changePlayerState(PlayerState.Idle1);
}
}
}
浙公网安备 33010602011771号