218 lines
6.8 KiB
TypeScript
218 lines
6.8 KiB
TypeScript
/*
|
||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||
|
||
https://www.cocos.com/
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
of this software and associated documentation files (the "Software"), to deal
|
||
in the Software without restriction, including without limitation the rights to
|
||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||
subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
THE SOFTWARE.
|
||
*/
|
||
|
||
import { _decorator, Component, Node, game, Vec3, PhysicsRayResult, randomRange, v3 } from 'cc';
|
||
import { ActionActorEquip, key_type_boolean } from '../../core/action/action';
|
||
import { Actor } from './actor';
|
||
import { BagItem } from './actor-bag';
|
||
import { UtilNode, UtilVec3 } from '../../core/util/util';
|
||
import { Msg } from '../../core/msg/msg';
|
||
import { ActorAnimationGraph } from './actor-animation-graph';
|
||
import { FxBase } from '../../core/effect/fx-base';
|
||
import { fx } from '../../core/effect/fx';
|
||
import { Local } from '../../core/localization/local';
|
||
const { ccclass, property } = _decorator;
|
||
|
||
let tracerEndPosition = v3(0, 0, 0);
|
||
|
||
@ccclass('ActorEquipBase')
|
||
export class ActorEquipBase extends Component {
|
||
|
||
point_shoot: Node | undefined;
|
||
|
||
_animationGraph: ActorAnimationGraph | undefined;
|
||
|
||
_view: Node | undefined;
|
||
|
||
_bagData: BagItem | undefined;
|
||
|
||
_data: { [key: string]: any } = {};
|
||
|
||
_action: ActionActorEquip | undefined;
|
||
|
||
_actor: Actor | undefined;
|
||
|
||
isPlayer = false;
|
||
|
||
fxMuzzle: FxBase | undefined;
|
||
|
||
isBulletEmpty = false;
|
||
|
||
mask = 1 << 2 | 1 << 3 | 1 << 4;
|
||
|
||
__preload () {
|
||
this.point_shoot = this.node.getChildByName('point_shoot')!;
|
||
this.fxMuzzle = UtilNode.find(this.node, 'fx_muzzle').getComponent(FxBase)!;
|
||
this._view = this.node.getChildByName('view')!;
|
||
this.node.on('do', this.do, this);
|
||
this.node.on('init', this.init, this);
|
||
}
|
||
|
||
|
||
init (bagData: BagItem) {
|
||
this._actor = bagData.actor;
|
||
this._bagData = bagData;
|
||
this._data = this._bagData.data;
|
||
this._action = new ActionActorEquip(this._data.action, this);
|
||
this._bagData.lastUseTime = game.totalTime / 1000;
|
||
this.isPlayer = this._actor.isPlayer;
|
||
this._animationGraph = this._actor._animationGraph;
|
||
}
|
||
|
||
onDestroy () {
|
||
this.node.off('do', this.do, this);
|
||
this.node.off('init', this.init, this);
|
||
}
|
||
|
||
do (name: string) {
|
||
if (this._action) {
|
||
if (name === 'fire' && !this.checkUse()) return;
|
||
this._action.on(name);
|
||
}
|
||
}
|
||
|
||
checkAutoFire () {
|
||
if (this._actor?._data.is_auto_fire) {
|
||
this.do("fire");
|
||
}
|
||
}
|
||
|
||
update (deltaTime: number) {
|
||
this._action?.update(deltaTime);
|
||
}
|
||
|
||
setActive (data: key_type_boolean) {
|
||
const activeNode = this.node.getChildByName(data.key);
|
||
if (activeNode) activeNode.active = data.value;
|
||
else console.warn(` You want set undefined node active. ${this.node?.name}/${data.key}`);
|
||
}
|
||
|
||
hiddenNode () {
|
||
this.node.active = false;
|
||
}
|
||
|
||
setFx (data: key_type_boolean) {
|
||
fx.playLoop(this.node, data.key, data.value);
|
||
}
|
||
|
||
showMuzzle () { this.fxMuzzle?.play(); }
|
||
|
||
onFx (name: string) {
|
||
fx.play(this.node, name);
|
||
}
|
||
|
||
/**
|
||
* Weapon recoil method
|
||
*/
|
||
onRecoil () {
|
||
|
||
// Get the recoil ratio.
|
||
// Aim state gets a specific value based on the gun's data, non-Aim state defaults to one.
|
||
const recoil_rate = this._actor!._data.is_aim ? this._data.recoil_aim_rate : 1;
|
||
|
||
// Random recoil offset is performed.
|
||
const recoilX = randomRange(this._data.recoil_x[0], this._data.recoil_x[1]) * recoil_rate;
|
||
const recoilY = randomRange(this._data.recoil_y[0], this._data.recoil_y[1]) * recoil_rate;
|
||
|
||
// Set the offset of the recoil.
|
||
this._actor?.onRotation(recoilX, recoilY);
|
||
}
|
||
|
||
|
||
/**
|
||
* Display the current infrared tracking path.
|
||
* @param hit The location of the detection point.
|
||
* @param dir The direction of the target point.
|
||
*/
|
||
showTracer (hit: PhysicsRayResult | undefined, dir: Vec3) {
|
||
|
||
// Get the world coordinates of the firing point.
|
||
const origin = this.fxMuzzle!.node.worldPosition;
|
||
|
||
// The physical hit point exists set as the end coordinate.
|
||
if (hit?.hitPoint) {
|
||
UtilVec3.copy(tracerEndPosition, hit.hitPoint);
|
||
} else { // If the physical hit point does not exist, the end point is extended by 100 units in the direction of fire.
|
||
UtilVec3.copy(tracerEndPosition, origin);
|
||
tracerEndPosition.add3f(dir.x * 100, dir.y * 100, dir.z * 100);
|
||
}
|
||
//console.log(origin, dir, tracerEndPosition);
|
||
Msg.emit('msg_set_tracer', { start: origin, end: tracerEndPosition });
|
||
}
|
||
|
||
actionEnd () { }
|
||
|
||
checkUse (): boolean {
|
||
// Check bullet count.
|
||
this.isBulletEmpty = this._bagData!.bulletCount <= 0 && this._bagData!.data.bullet_count !== -1;
|
||
if (this.isBulletEmpty) {
|
||
this.do('fire_empty');
|
||
return false;
|
||
}
|
||
const lastUseTime = this._bagData!.lastUseTime;
|
||
const timeSpace = (game.totalTime - lastUseTime) / 1000;
|
||
return timeSpace >= this._data.damage.cooling;
|
||
|
||
}
|
||
|
||
updateCooling () {
|
||
this._bagData!.lastUseTime = game.totalTime;
|
||
}
|
||
|
||
checkFullBullet (): boolean {
|
||
|
||
if (this._bagData!.bulletCount == this._bagData?.data.bullet_count) {
|
||
Msg.emit(
|
||
'msg_tips',
|
||
`${Local.Instance.get('bullet_is_full')}`
|
||
);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
onReload () {
|
||
|
||
if (!this._actor) return;
|
||
|
||
if (this._actor.bulletBox > 0) {
|
||
//this._bagData!.bulletClipCount--;
|
||
this._actor.bulletBox--;
|
||
if (this._actor.bulletBox < 0) this._actor.bulletBox = 0;
|
||
this._bagData!.bulletCount = this._bagData?.data.bullet_count;
|
||
this.isBulletEmpty = false;
|
||
} else {
|
||
Msg.emit(
|
||
'msg_tips',
|
||
`${Local.Instance.get('clip_is_null')}`
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
onUse () { }
|
||
|
||
}
|
||
|