[add] first

This commit is contained in:
2023-02-22 09:50:51 +08:00
commit 6260e95bc8
9053 changed files with 4492644 additions and 0 deletions
@@ -0,0 +1,26 @@
import { _decorator, Component, Node, animation, Vec3, v3 } from 'cc';
import { Actor } from './actor';
import { ActorAnimationGraph } from './actor-animation-graph';
const { ccclass, property } = _decorator;
@ccclass('ActorAnimationGraphGroup')
export class ActorAnimationGraphGroup extends Component {
_groups:ActorAnimationGraph[] | undefined;
__preload () {
this._groups = this.getComponentsInChildren(ActorAnimationGraph);
if (this._groups === undefined || this._groups === null) {
throw new Error(`${this.node.name} node not find ActorAnimationGraph`);
}
}
play (key: string, value: boolean | number) {
console.log('ActorAnimationGraphGroup', key, value);
for(let i = 0; i < this._groups!.length; i++) {
this._groups![i].play(key, value);
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a16cf102-2aea-4701-8203-95e21b2ee88b",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,35 @@
import { _decorator, Component, Node, animation, Vec3, v3 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActorAnimationGraph')
export class ActorAnimationGraph extends Component {
_graph: animation.AnimationController | undefined | null;
//_actor: Actor = Object.create(null);
start () {
// [3]
this._graph = this.getComponent(animation.AnimationController);
//this._actor = this.node.parent.parent.getComponent(Actor);
if (this._graph === undefined || this._graph === null) {
throw new Error(`${this.node.name} can not find AnimationController`);
}
}
play (key: string, value: boolean | number) {
this._graph?.setValue(key, value);
}
setValue(key:string, value:number) {
this._graph?.setValue(key, value);
}
update (deltaTime: number) {
// // [4]
//this.play('speed', this._actor._data.cur_speed);
//this.play('move_speed', this._actor._data.cur_speed + 0.5);
//this.play('is_ground', this._actor._data.is_ground);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fbeac263-42e6-4401-bb66-b6568aca650a",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,21 @@
import { _decorator, Component, Node, SkeletalAnimation } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActorAnimatorController')
export class ActorAnimatorController extends Component {
_anim:SkeletalAnimation = Object.create(null);
_data = Object.create(null);
init(_data) {
this._data = _data;
this._anim = this.getComponent(SkeletalAnimation);
}
play(name: string) {
var anims = this._data[name];
this._anim.play(anims[0]);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "7acb1d68-3df4-4c3d-8bc4-372796cd91eb",
"files": [],
"subMetas": {},
"userData": {}
}
+25
View File
@@ -0,0 +1,25 @@
import { _decorator, Component, Node, geometry, PhysicsSystem, PhysicsRayResult } from 'cc';
import { fx } from '../../core/effect/fx';
import { ActorEquipBase } from './actor-equip-base';
import { ActorPart } from './actor-part';
import { calculateDamage } from './damage-core';
const { ccclass, property } = _decorator;
@ccclass('ActorAxe')
export class ActorAxe extends ActorEquipBase {
onFire() {
this._bagData!.bulletCount--;
const forwardNode = this._actor!._forwardNode;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
let ray = new geometry.Ray(origin.x, origin.y, origin.z, dir.x, dir.y , dir.z);
const mask = 1 << 3 | 1 << 4;
const distance = this._data.damage.distance;
let hit:PhysicsRayResult | undefined = undefined;
if (PhysicsSystem.instance.raycastClosest(ray, mask, distance)) {
hit = PhysicsSystem.instance.raycastClosestResult;
}
calculateDamage(this._data, hit);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "87a465c0-0b33-4476-9294-4e6acc215b38",
"files": [],
"subMetas": {},
"userData": {}
}
+238
View File
@@ -0,0 +1,238 @@
/*
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 { game, _decorator } from 'cc';
import { DataEquipInst } from '../data/data-core';
import { Level } from '../level/level';
import { Actor } from './actor';
export class ActorBag {
// The character object to which the current bag belongs.
_actor: Actor;
// Bag capacity.
_capacity = 0;
// Bag usage count statistics.
_usageCount = 0;
constructor (actor: Actor) {
// The character object to which the current equipment belongs.
this._actor = actor;
// Set Bag capacity.
this._capacity = this._actor._data.bag_capacity;
// Initialize the bag space and set the default value.
this._actor._data.equipment_name_list = new Array<string>(this._capacity);
for (let i = 0; i < this._capacity; i++) {
this._actor._data.equipment_name_list[i] = '';
}
// Set the default value of the bag.
const bags = actor._data.bags;
for (let i = 0; i < bags.length; i++) {
this.pickedItem(bags[i]);
}
}
/**
* Get the index of the empty slot in the bag
* @returns Returns the index of the corresponding empty slot, -1 means it cannot exist.
*/
public getEmptySlot (): number {
for (let i = 0; i < this._actor._data.equipment_name_list.length; i++) {
const name = this._actor._data.equipment_name_list[i];
if (name.length <= 0) return i;
}
return -1;
}
/**
* The method is check picked same weapon then increase clip.
* @param name Weapon name
* @returns TRUE is same weapon increase clip, FALSE is not same weapon.
*/
public pickedSameWeaponIncreaseClips (name: string) {
const bagItems = this._actor._data.items[name] as BagItem;
if (bagItems) {
//bagItems.bulletClipCount++;
this._actor.bulletBox++;
return true;
}
return false;
}
/**
* The method picked bullet box.
* @returns
*/
public pickedBulletBox () {
const bagItems = this._actor._actorEquipment?.currentEquipItem;
if (bagItems) {
//bagItems.bulletClipCount++;
this._actor.bulletBox += 2;
return true;
}
return false;
}
/**
* This method is used to pick up item.
* @param name Pick item name.
* @returns Picked state, true is picked, false is not picked.
*/
public pickedItem (name: string): boolean {
// Get the current backpack item by name, may be empty.
let bagItems = this._actor._data.items[name];
// Get information about equipment props.
const equipData = DataEquipInst.get(name);
// If the item already exists in the backpack and is stackable, run the stacking logic.
if (bagItems && equipData.stackable) {
this.stackItem(equipData.bullet_count);
} else {
// Get the current empty slot index and determine if it exists.
const index = this.getEmptySlot();
if (index === -1) return false;
// Create a backpack item.
this.createItem(equipData, name);
// Update the value corresponding to the array index of the item slot
this._actor._data.equipment_name_list[index] = name;
// Accumulation of the number of uses.
this._usageCount++;
}
return true;
}
/**
* This method is used to discard the equipment currently held in your hand.
* @returns Dropped status: true is success false is failure
*/
public dropItem (): boolean {
// Get the bag index of the currently held equipment.
const curIndex = this._actor._data.current_equipment_index;
// Determine if the current index is in the valid range.
// Default 0 equipment is not drop.
if (curIndex >= this._capacity || curIndex <= 0) return false;
// Get it from the bag equipment list.
const data = this._actor._data.equipment_name_list;
//Get the name of the equipment in the current slot and determine if the equipment exists based on the name value.
const name = data[curIndex];
if (!name || name.length <= 0) return false;
// Take off the prop that is being equipped.
this._actor._actorEquipment?.unEquip();
// Clear specific items data.
this._actor._data.items[name] = undefined;
// Discard the current prop near the character.
const pos = this._actor.node.worldPosition;
Level.Instance.addDrop(name, pos);
// Clears the value of the equipment list for the current index mapping.
data[curIndex] = '';
// Replace the default equipment.
this._actor._data.current_equipment_index = 0;
this._actor._actorEquipment?.equip(0);
// The total number of bags used decreases.
this._usageCount--;
return true;
}
/**
* This method is used to create bag items.
* @param equipData Current equip data.
* @param name The name of the bag prop that needs to be created.
*/
public createItem (equipData: any, name: string) {
let newItems = {
'name': name,
'actor': this._actor,
'stackable': equipData.stackable === undefined ? false : true,
'count': 1,
'data': equipData,
'bulletClipCount': equipData.bullet_clip_count,
'bulletCount': equipData.bullet_count,
'lastUseTime': game.totalTime,
}
this._actor._data.items[name] = newItems;
}
/**
* This method is used to update the number of stackable props.
* @param bagItems Current backpack information.
*/
public stackItem (bagItems: BagItem) {
bagItems.count++;
bagItems.bulletCount += bagItems.data.bullet_count;
}
}
// The bag item data interface.
export interface BagItem {
fov: number;
name: string,
actor: Actor,
stackable: boolean,
count: number,
bulletClipCount: number
bulletCount: number,
data: any,
lastUseTime: number,
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "31aaecab-d831-4c7e-b31f-cc0c0d40b35e",
"files": [],
"subMetas": {},
"userData": {}
}
+420
View File
@@ -0,0 +1,420 @@
/*
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, Vec3, v3, random, randomRangeInt, Node, math, game, randomRange, Game } from 'cc';
import { SensorRaysAngle } from '../../core/sensor/sensor-rays-angle';
import { UtilVec3 } from '../../core/util/util';
import { NavSystem } from '../navigation/navigation-system';
import { ActorInputBrain } from './actor-input-brain';
import { Level } from '../level/level';
import { Actor } from './actor';
const { ccclass } = _decorator;
let tempRotationSideVector = v3(0, 0, 0);
@ccclass('ActorBrain')
export class ActorBrain extends Component {
// The character object to which the current equipment belongs.
_actor: Actor | undefined;
// The currently planned waypoint.
_wayPoints = new Array<NavSystem.NavPointType>();
// The direction the character moves.
_moveDir: Vec3 = v3(0, 0, 0);
// Target distance from my direction.
targetDirection: Vec3 = v3(0, 0, 0);
// Unified input management object for character.
input: ActorInputBrain | undefined;
// Sector sensor, used to detect the status in front of the character.
sensorRays: SensorRaysAngle | undefined;
// Whether it is waypoint navigation.
isFollowWayPointsMove = false;
// current waypoint index.
currentWaypointsIndex = 1;
// The closest Navigation point marker to the character.
closestNavigationPon = -1;
// The target object node.
_targetNode: Node | undefined;
// The position of the target node.
targetPosition: Vec3 = v3(0, 0, 0);
// Path node index of the current fire.
waypointsFireIndex = -1;
// Open fire planning waypoints.
waypointsFire = new Array<NavSystem.NavPointType>();
// The direction of the open fire.
fireDirection = v3(0, 0, 0);
// The time it takes to replace ammunition.
reloadTime = 0;
// Path following direction, 1 means move forward, -1 means move backwards.
followPathsDirection = 1;
// Fire wait time.
fireWaitTime = 5;
start () {
this._actor = this.getComponent(Actor)!;
this.input = this.getComponent(ActorInputBrain)!;
const sensorNode = this.node.getChildByName('sensor_target')!;
this.sensorRays = sensorNode.getComponent(SensorRaysAngle)!;
this.closestNavigationPon = this._actor._data.nearest;
if (this._actor === undefined || this.input === undefined || this.sensorRays === undefined) {
throw new Error(`${this.node.name} node lose components : ActorBase or ActorInputBrain.`);
}
}
onMove () {
this.input!.onMove(this._moveDir);
this.input!.onRotation(this.targetDirection.x, this.targetDirection.z);
this.input!.onRun(random() < 0.05);
}
onJump () {
this.input?.onJump();
}
onCrouch () {
this.input?.onCrouch();
}
onProne () {
this.input?.onProne();
}
onFire () {
this.input?.onFire();
}
update (deltaTime: Number) {
if (Level.Instance.stop) return;
// Not ready returns do not execute the following logic.
if (!this._actor!.isReady) return;
// If you die, you will return without executing the logic of your brain.
if (this._actor?._data.is_dead) return;
// Returns without executing brain logic if the player dies.
const player = Level.Instance._player;
if (!player || Level.Instance._player?._data.is_dead) return;
// Check near has player.
this.checkNearPlayer();
// Test to open and close enemy fire.
//this._targetNode = undefined;
//console.log('target node:', this._targetNode);
// Go target position.
// Find target look at target and shoot.
if (this._targetNode !== undefined) {
this.shootFire();
} else { // Random move and find target.
this.randomMove();
this.input?.onAim(false);
}
}
shootFire () {
const angle = this.checkPlayerAngle();
// Fire move.
this.moveFire(angle);
// Wait reload weapon.
if (this.reloadTime > 0) {
this.reloadTime -= game.deltaTime;
return;
}
// Check bullet empty.
if (this._actor?._actorEquipment?.currentEquip?.isBulletEmpty) {
// Reload Bullet.
this.input?.onReload();
this.reloadTime = 3;
return;
}
this.input?.onAim(true);
// Check fire.
this.checkFire(angle);
}
randomMove () {
this.waypointsFireIndex = -1;
if (this.isFollowWayPointsMove) {
this.PathsFollowing();
} else {
this.calculateNextPosition();
}
}
PathsFollowing () {
if (this.isFollowWayPointsMove) {
this._actor!._actorMove!.faceMove = true;
const worldPosition = this._actor!.node.worldPosition;
const target = this._wayPoints[this.currentWaypointsIndex];
UtilVec3.copy(this.targetPosition, target);
// Detect distance to target point.
if (Vec3.distance(worldPosition, target) <= 1) {
// Arrive current node.
this.currentWaypointsIndex += this.followPathsDirection;
if (this.currentWaypointsIndex >= this._wayPoints.length || this.currentWaypointsIndex < 0) this.isFollowWayPointsMove = false;
else this.closestNavigationPon = this._wayPoints[this.currentWaypointsIndex].id;
} else {
// Detects if there is a character ahead.
if (this.sensorRays?.checkedNode) {
//this.followPathsDirection = -1;
//Calculate checked node direction.
UtilVec3.copy(this.targetDirection, this.sensorRays.checkedNode.worldPosition);
this.targetDirection.y = this.node.worldPosition.y;
let checkDirection = this.targetDirection.clone();
checkDirection.subtract(this.node.worldPosition);
//Calculate checked node side.
const side = -this.targetDirection.clone().cross(this.node.forward).y
//Calculate normal vector.
let normal = checkDirection.clone();
normal.cross(side > 0 ? v3(0, -1, 0) : v3(0, 1, 0));
//Calculate new target direction.
this.targetDirection.add(normal);
} else {
// Calculate move direction.
UtilVec3.copy(this.targetDirection, this.targetPosition);
//this.followPathsDirection = 1;
}
this.targetDirection.y = worldPosition.y;
this.targetDirection.subtract(worldPosition).normalize();
// Set target move.
this._moveDir.x = -this.targetDirection.x;
this._moveDir.y = 0;
this._moveDir.z = -this.targetDirection.z;
// Calculates the rotation angle of the target.
this.lookAtTarget(this._moveDir);
this._moveDir.x = 0;
this._moveDir.y = 0;
this._moveDir.z = 1;
//
this.onMove();
// Random Jump.
//if (random() < 0.05) this.onJump();
}
}
}
followTargetPaths () {
}
lookAtTarget (lookAtDirection: Vec3) {
UtilVec3.copy(tempRotationSideVector, lookAtDirection);
const angle = Math.abs(Vec3.angle(lookAtDirection, this.node.forward));
if (angle > 0.001) {
const side = Math.sign(-tempRotationSideVector.cross(this.node.forward).y);
this.targetDirection.x = side * angle;// game.deltaTime;
this.targetDirection.z = 0;
}
}
moveFire (angle: number) {
this._actor!._actorMove!.faceMove = false;
if (this.waypointsFireIndex === -1) {
this.closestNavigationPon = NavSystem.findNearest(this._actor!.node.worldPosition);
NavSystem.randomFirePath(this.waypointsFire, this.closestNavigationPon);
this.waypointsFireIndex = 0;
}
const worldPosition = this._actor!.node.worldPosition;
let target = this.waypointsFire![this.waypointsFireIndex];
UtilVec3.copy(this.targetPosition, target);
const targetDistance = Vec3.distance(worldPosition, target);
//console.log('target distance:', targetDistance);
if (targetDistance <= 1) {
// Next way
this.waypointsFireIndex++;
if (this.waypointsFireIndex >= this.waypointsFire!.length) {
this.closestNavigationPon = NavSystem.findNearest(this._actor!.node.worldPosition);
NavSystem.randomFirePath(this.waypointsFire, this.closestNavigationPon);
this.waypointsFireIndex = 0;
target = this.waypointsFire![this.waypointsFireIndex];
}
}
// Calculate move direction.
UtilVec3.copy(this.targetDirection, this.targetPosition);
this.targetDirection.y = worldPosition.y;
// Calculate angle speed.
const angleSpeed = angle < 5 ? 0.5 : 1.5;
this.targetDirection.subtract(worldPosition).normalize().multiplyScalar(angleSpeed);
this._moveDir.x = -this.targetDirection.x;
this._moveDir.y = 0;
this._moveDir.z = -this.targetDirection.z;
// Look at direction.
const player = Level.Instance._player;
UtilVec3.copy(this.targetDirection, worldPosition);
this.targetDirection.y += player._data.is_crouch ? 0.3 : 1;
this.targetDirection.subtract(player.node.worldPosition).normalize();
this.lookAtTarget(this.targetDirection);
this.onMove();
//if (random() < 0.1) this.onJump();
}
checkPlayerAngle (): number {
// Check shoot angle.
const player = Level.Instance._player;
const forward = this._actor?.node.forward!;//this._actor?._forwardNode!.forward!;
UtilVec3.copy(this.fireDirection, player.node!.worldPosition);
this.fireDirection.subtract(this._actor!.node.worldPosition);
const angle = math.toDegree(Vec3.angle(forward, this.fireDirection));
return angle;
}
checkFire (angle: number) {
// Brain wait fire logic.
this.fireWaitTime -= game.deltaTime;
if (this.fireWaitTime > 0) return;
this.fireWaitTime = randomRange(0.3, 1.3);
if (angle < 10) this.onFire();
}
freePathMove () {
NavSystem.randomPaths(this._wayPoints, this._actor!.node.worldPosition, randomRangeInt(5, 10), this.closestNavigationPon);
//Navigation.calculateRandomPoint(this._actor!.node.worldPosition);
console.log('this._wayPoints:', this._wayPoints);
this.isFollowWayPointsMove = true;
this.currentWaypointsIndex = 0;
}
fleeTarget () {
// calculate flee.
}
followTarget () {
// calculate target.
NavSystem.findPaths(this._wayPoints, this._actor!.node.worldPosition, this.closestNavigationPon, Level.Instance._player!.node.worldPosition);
}
checkNearPlayer () {
const player = Level.Instance._player;
if (!player) return undefined;
const data = this._actor!._data;
const distance = Vec3.distance(player.node.worldPosition, this._actor!.node.worldPosition);
//console.log('target distance:', distance, ' nearby distance:', data._ai_nearby_distance);
if (distance < data.ai_nearby_distance) {
this._targetNode = player.node;
} else {
this._targetNode = undefined;
}
}
calculateNextPosition () {
NavSystem.randomPaths(this._wayPoints, this._actor!.node.worldPosition, randomRangeInt(5, 10),);
if (this._wayPoints.length === 0) {
console.warn(`${this.node.name} can not find path`);
return;
}
//console.log('this._wayPoints:', this._wayPoints);
this.isFollowWayPointsMove = true;
this.currentWaypointsIndex = 0;
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2fdf616d-2091-4a60-9880-0cc718e65277",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,23 @@
import { _decorator, Component, Node } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { IActorEquip } from './actor-interface';
const { ccclass, property } = _decorator;
@ccclass('ActorCrossbow')
export class ActorCrossbow extends ActorEquipBase {
_pointShoot:Node | null | undefined;
start() {
this._pointShoot = this.node.getChildByName('point_shoot');
}
onDestroy() {
}
update(deltaTime: number) {
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "5e88b1bb-ad7a-4f42-9417-33d45cb61159",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,76 @@
/*
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 } from 'cc';
import { geometry, PhysicsSystem, PhysicsRayResult } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { calculateDamage } from './damage-core';
import { UtilVec3 } from '../../core/util/util';
const { ccclass, property } = _decorator;
let ray = new geometry.Ray();
@ccclass('ActorEnemyGun')
export class ActorEnemyGun extends ActorEquipBase {
/**
* Execute fire.
*/
onFire() {
if(!this._actor?._forwardNode) return;
// The number of bullets is reduced by one.
this._bagData!.bulletCount--;
// Get the weapon shooting direction node.
const forwardNode = this._actor!._forwardNode!;
// Get Weapon Shooting Points
const origin = forwardNode.worldPosition;
// Get the weapon shooting direction.
const shootDirection = forwardNode.forward;
// Set physical ray detection parameters.
UtilVec3.copy(ray.o, origin);
UtilVec3.copy(ray.d, shootDirection);
// Get weapon range.
const distance = this._data.damage.distance;
// Start physical shot detection.
let hit:PhysicsRayResult | undefined;
if (PhysicsSystem.instance.raycastClosest(ray, this.mask, distance)) {
hit = PhysicsSystem.instance.raycastClosestResult;
}
// Show Tracer line.
this.showTracer(hit, shootDirection);
// Calculates shot damage.
calculateDamage(this._data, hit);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e36354c3-abb6-4a73-b240-9b6229d711e4",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,217 @@
/*
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 () { }
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e03a7900-64f1-4336-a4db-b663c4a6628b",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,227 @@
/*
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, Node, game, math } from 'cc';
import { Msg } from "../../core/msg/msg";
import { Res } from '../../core/res/res';
import { ResCache } from '../../core/res/res-cache';
import { UtilNode } from '../../core/util/util';
import { Actor } from "./actor";
import { BagItem } from './actor-bag';
import { fun } from '../../core/util/fun';
import { ActorEquipBase } from './actor-equip-base';
export class ActorEquipment {
// The character object to which the current equipment belongs.
_actor:Actor;
// A pool of cached equipment objects.
//The purpose is to avoid the creation and destruction of objects at runtime.
equipPool:{ [key:string]:Node } = {};
// Dictionary of weapon skeleton nodes for mounted equipment.
equipBoneNode: { [key:string]:Node } = {};
// Current equipment node.
currentEquipNode:Node | undefined;
// bag information of current equipment.
currentEquipItem:BagItem | undefined;
// The component object of the current weapon.
currentEquip:ActorEquipBase | undefined;
// The stability value of the equipment.
// The purpose is to describe the stability value of the shot.
// This value affects the size of the aiming area of the shot.
stableValue = 1;
constructor(actor:Actor) {
// Initialize the Actor object corresponding to the equipment manager passed in.
this._actor = actor;
// Get all node maps with the name 'weapon_root'.
this.equipBoneNode = UtilNode.getChildrenByNameBlur(this._actor.node, 'weapon_root');
// Initialize the cache pool for the equipment list.
const equipmentList = this._actor._data.cache_equipment_list;
// Get the length of the equipment list.
const length = equipmentList.length;
for(let i = 0; i < length; i++) {
// Get the equipment name from the current index.
const weaponName = equipmentList[i];
// Get the prefab of the equipment from the resource buffer pool.
const prefab = ResCache.Instance.getPrefab(weaponName + '_tps');
// Get the bone node of the equipment.
const bindNode = this.equipBoneNode[this._actor._data.weapon_bone];
// Instantiate the game object and set the parent node to the bone node.
const nodePrefab = Res.inst(prefab, bindNode);
// Set the object pool key to map to this instantiated weapon object.
this.equipPool[weaponName] = nodePrefab;
// Set the activity of this cache object to false.
nodePrefab.active = false;
}
// Equip the default weapon.
this.equip(actor._data.default_equip_index);
}
public equip(replaceEquipmentIndex:number):boolean {
// Get the current bag equipment index.
const currentEquipmentIndex = this._actor._data.current_equipment_index;
// If the current bag index is the same as the updated bag index,
// true is no need to switch weapons, false is need to switch weapons.
if (currentEquipmentIndex !== replaceEquipmentIndex) {
// Get bag equipment name list from player data.
const equipment_name_list = this._actor._data.equipment_name_list;
// Get the name of the equipment name to be switched from the equipment list.
const changeEquipmentName = equipment_name_list[replaceEquipmentIndex];
// Return false if the equipment does not exist or is not empty to cancel switching equipment.
if(!changeEquipmentName || changeEquipmentName.length <= 0) return false;
// Uninstall current equipment.
this.unEquip();
// Replace new equipment data and models.
// Here you need to do a time delay with the animation.
const self = this;
fun.delay(()=>{
const items = self._actor._data.items;
self.currentEquipNode = self.equipPool[changeEquipmentName];
self.currentEquipItem = items[changeEquipmentName];
self.currentEquipNode!.active = true;
self.currentEquipNode!.emit('init',this.currentEquipItem);
self.currentEquipNode!.emit('do', 'take_out');
self._actor._data.current_equipment_index = replaceEquipmentIndex;
self.currentEquip = self.currentEquipNode?.getComponent(ActorEquipBase)!;
if(this._actor.isPlayer) {
//const mainCamera = CameraSetting.main?.camera;
//if(mainCamera) mainCamera.fov = this.currentEquipItem!.fov;
Msg.emit('msg_change_equip');
Msg.emit('msg_update_equip_info');
}
}, 0.3)
return true;
}else{
return false;
}
}
/**
* Uninstall current equipment.
*/
public unEquip() {
//Get the index of the current equipment.s
const currentEquipmentIndex = this._actor._data.current_equipment_index;
// Compare whether the current equipment index value is -1.
// An index of -1 means no current equipment, skip setting.
if (currentEquipmentIndex !== -1) {
// Get a list of equipment names.
const equipment_name_list = this._actor._data.equipment_name_list;
// Get the current equipment name.
const currentEquipmentName = equipment_name_list[currentEquipmentIndex];
// Whether the current equipment name exists.
// false means it does not exist, the return function does not uninstall the equipment
if(!currentEquipmentName) {
console.warn(`The equipment index that does not exist, the index id is ${currentEquipmentIndex}, the object is ${this._actor?.node.name}`)
return;
}
// Get the current equipment object node from the equipment object pool.
const currentEquipmentNode = this.equipPool[currentEquipmentName];
//Whether the object pool contains equipment objects.
if (currentEquipmentNode) {
// Notify the equipment node to perform recovery behavior.
currentEquipmentNode.emit('do', 'take_back');
}else{
console.warn(``);
}
}
}
/**
* Execution equipment action.
* @param action Name of the execution action.
*/
public do(action:string) {
// Execute the current equipment action.
this.currentEquipNode?.emit('do', action);
}
/**
* Update to set the range of Aim.
* @param normalizeCharacterMoveSpeed Normalized character movement speed.
* @param toMax The aim range is set to the maximum value: true is set, false is not set.
*/
public updateAim(normalizeCharacterMoveSpeed:number, toMax = false) {
if (this.currentEquipItem === undefined) {
if (this.stableValue !== 0){
this.stableValue = 0;
if(this._actor.isPlayer) Msg.emit('msg_update_aim', this.stableValue);
}
}else{
const equipData = this.currentEquipItem.data;
const equipStable = equipData.stable_max_value;
let currentStable = 0;
if(toMax) {
this.stableValue = equipData.stable_max_value;
currentStable = equipData.stable_max_value;
}else{
if (equipStable !== 0) {
currentStable = Math.abs(normalizeCharacterMoveSpeed) <= 0.001 ? equipData.stable_min_value : equipData.stable_max_value * normalizeCharacterMoveSpeed;
currentStable = Math.max(equipData.stable_min_value, currentStable);
}
this.stableValue = math.lerp(this.stableValue, currentStable, game.deltaTime * equipData.stable_smooth);
}
if(this._actor.isPlayer) Msg.emit('msg_update_aim', this.stableValue);
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "74f9852c-4476-42f6-9993-3d25969fbcbf",
"files": [],
"subMetas": {},
"userData": {}
}
+59
View File
@@ -0,0 +1,59 @@
import { _decorator, Component, math, Node, v3, CCFloat } from 'cc';
import { UtilVec3 } from '../../core/util/util';
import { ActorMove } from '../actor/actor-move';
import { Msg } from '../../core/msg/msg';
const { ccclass, property } = _decorator;
@ccclass('ActorFace')
export class ActorFace extends Component {
@property(Node)
rotationNode: Node | undefined;
@property({ type: ActorMove, tooltip: 'Test actor move.' })
actorMove: ActorMove | undefined;
@property(CCFloat)
smoothAngle = 20;
@property(CCFloat)
smoothHeight = 1;
targetAngle = v3(0, 0, 0);
currentAngle = v3(0, 0, 0);
targetPosition = v3(0, 0, 0);
currentPosition = v3(0, 0, 0);
start () {
UtilVec3.copy(this.targetAngle, this.rotationNode!.eulerAngles);
UtilVec3.copy(this.currentAngle, this.targetAngle);
UtilVec3.copy(this.targetPosition, this.rotationNode!.position);
UtilVec3.copy(this.currentAngle, this.targetPosition);
}
update (deltaTime: number) {
this.rotationX(this.actorMove!.angleVertical);
this.currentAngle.x = math.lerp(this.currentAngle.x, this.targetAngle.x, this.smoothAngle * deltaTime);
this.rotationNode?.setRotationFromEuler(this.currentAngle);
this.currentPosition.y = math.lerp(this.currentPosition.y, this.targetPosition.y, this.smoothHeight * deltaTime);
this.rotationNode?.setPosition(this.currentPosition);
}
rotationX (angleX: number) {
this.targetAngle.x = angleX;
}
setRootY (height: number) {
this.targetPosition.y = height;
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d7147c1b-98b1-4c7b-bba6-347728d2cc39",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,10 @@
import { _decorator, Component } from 'cc';
const { ccclass } = _decorator;
@ccclass('ActorFollowPathMove')
export class ActorFollowPathMove extends Component {
//public setMove()
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "11a177b8-e3f6-4cf2-99a1-efe4cf8f86e3",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,26 @@
import { _decorator, v3 } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { Res } from '../../core/res/res';
import { ResCache } from '../../core/res/res-cache';
import { ProjectileGrenade } from './projectile-grenade';
import { Level } from '../level/level';
const { ccclass, property } = _decorator;
@ccclass('ActorGrenade')
export class ActorGrenade extends ActorEquipBase {
onFire() {
const forwardNode = this._actor!._forwardNode!;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
const prefab = ResCache.Instance.getPrefab(this._data.projectile_res);
let position = v3(origin.x, origin.y, origin.z);
position.add(dir);
const projectile = Res.instNode(prefab, Level.Instance._objectNode, position);
const projectileGrenade = projectile.getComponent(ProjectileGrenade);
const throwDir = dir.multiplyScalar(10);
projectileGrenade?.onThrow(this._data, throwDir, this._actor);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "aeef2555-a4d2-4b63-9ca5-9e5eb71b4a34",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,28 @@
import { _decorator, Component, Node, geometry, PhysicsSystem, game, PhysicsRayResult, Vec3, director } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { calculateDamage } from './damage-core';
import { UtilVec3 } from '../../core/util/util';
const { ccclass, property } = _decorator;
let ray = new geometry.Ray();
@ccclass('ActorHandgun')
export class ActorHandgun extends ActorEquipBase {
onFire() {
this._bagData!.bulletCount--;
const forwardNode = this._actor!._forwardNode!;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
UtilVec3.copy(ray.o, origin);
UtilVec3.copy(ray.d, dir);
const distance = this._data.damage.distance;
let hit:PhysicsRayResult | undefined;
if (PhysicsSystem.instance.raycastClosest(ray, this.mask, distance)) {
hit = PhysicsSystem.instance.raycastClosestResult;
}
this.showTracer(hit, dir);
calculateDamage(this._data, hit, this._actor);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "84405be6-9660-4ef3-8904-d5500e1dbbfa",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,82 @@
import { _decorator, Component, find, Vec2, PhysicsSystem, input, Input, EventMouse, geometry, Camera, game, EventTouch, director, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
import { IActorInput } from '../../core/input/IActorInput';
import { Msg } from '../../core/msg/msg';
import { Actor } from './actor';
@ccclass('ActorInputBrain')
export class ActorInputBrain extends Component implements IActorInput {
_actor:IActorInput | undefined | null;
_isPause = false;
start () {
this._actor = this.getComponent(Actor);
if (this._actor === null) {
throw new Error(`${this.node.name} node can not find ActorEnemy`);
}
}
onMove(move:Vec3) {
this._actor?.onMove(move);
}
onRotation(x:number, y:number){
this._actor?.onRotation(x, y);
}
onDir(x:number, y:number) {
this._actor?.onDir(x, y);
}
onJump() {
this._actor?.onJump();
}
onRun(isRun:boolean) {
this._actor?.onRun(isRun);
}
onCrouch() {
this._actor?.onCrouch();
}
onProne(){
//this._actor?.onProne();
}
onAim(isAim:boolean | undefined): void {
this._actor?.onAim(isAim);
}
onChangeEquips(): boolean {
throw new Error('Method not implemented.');
}
onFire() {
this._actor?.onFire();
}
onEquip(index:number) {
this._actor?.onEquip(index);
}
onPick() {
this._actor?.onPick();
}
onReload() {
this._actor?.onReload();
}
onDrop() {
this._actor?.onDrop();
}
onPause() {}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "9a779e15-18f0-460e-97f8-ee362f501aa8",
"files": [],
"subMetas": {},
"userData": {}
}
+155
View File
@@ -0,0 +1,155 @@
/*
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, Vec3, sys } from 'cc';
const { ccclass } = _decorator;
import { IActorInput } from '../../core/input/IActorInput';
import { Level } from '../level/level';
import { Msg } from '../../core/msg/msg';
import { UI } from '../../core/ui/ui';
@ccclass('ActorInput')
export class ActorInput extends Component implements IActorInput {
_actor:IActorInput | undefined | null;
_isPause = false;
_isOpenEquips = false;
public static inst:ActorInput | undefined;
start () {
Msg.on('msg_set_input_active', this.setActive.bind(this));
ActorInput.inst = this;
Msg.on('msg_exit_pointer',this.exitPointer.bind(this));
}
exitPointer() {
document.exitPointerLock();
}
onDestroy() {
Msg.off('msg_set_input_active', this.setActive.bind(this));
Msg.off('msg_exit_pointer', this.exitPointer.bind(this));
if(sys.platform === sys.Platform.MOBILE_BROWSER ||
sys.platform === sys.Platform.ANDROID ||
sys.platform === sys.Platform.IOS ) {
UI.Instance.off('ui_joystick');
}
}
setActive(isShow:boolean) {
if(isShow) {
this.initInput();
}else{
for(let i = 0; i < this.node.children.length; i++) this.node.children[i].active = false;
UI.Instance.off('ui_joystick');
}
}
initInput() {
this._actor = Level.Instance._player;
// Select the type of input device enabled based on the platform.
if(sys.platform === sys.Platform.MOBILE_BROWSER ||
sys.platform === sys.Platform.ANDROID ||
sys.platform === sys.Platform.IOS ) {
UI.Instance.on('ui_joystick');
}else {
this.node.children[1].active = true;
this.node.children[0].active = true;
//UI.Instance.on('ui_joystick');
}
}
onMove(move:Vec3) {
this._actor?.onMove(move);
}
onRotation(x:number, y:number){
this._actor?.onRotation(x, y);
}
onJump() {
this._actor?.onJump();
}
onRun(isRun:boolean) {
this._actor?.onRun(isRun);
}
onCrouch() {
this._actor?.onCrouch();
}
onAim(){
this._actor?.onAim(undefined);
}
onFire() {
this._actor?.onFire();
}
onAutoFire(isAutoFire:boolean) {
this._actor?.onAutoFire(isAutoFire);
}
onEquip(index:number) {
this._actor?.onEquip(index);
}
onPick() {
this._actor?.onPick();
}
onReload() {
this._actor?.onReload();
}
onDrop() {
this._actor?.onDrop();
}
onDir(x: number, y: number) {
}
onPause() {
this._isPause = !this._isPause;
Msg.emit('push', 'level_pause');
}
onChangeEquips() {
Msg.emit('push', 'select_equips');
return true;
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "01c0931b-1410-4e31-a555-3d1093b99c13",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,13 @@
export interface IActorEquip {
onUse();
onDrop();
onPick();
}
export class DamageData {
hitPart:string | undefined;
hitDistance:number | undefined;
fireData:any;
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "92104162-688d-4e2e-bb59-9b4be96a170b",
"files": [],
"subMetas": {},
"userData": {}
}
+17
View File
@@ -0,0 +1,17 @@
import { Component, _decorator } from "cc";
import { BagItem } from "./actor-bag";
import { IActorEquip } from "./actor-interface";
const { ccclass } = _decorator;
@ccclass('ActorItem')
export class ActorItem extends Component {
data:BagItem | undefined;
item:IActorEquip | undefined;
start() {
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "bccb4286-0a47-4ba7-83f0-724984017f11",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,27 @@
import { _decorator, Component, Node, find } from 'cc';
import { UtilNode } from '../../core/util/util';
const { ccclass, property } = _decorator;
@ccclass('ActorLookAt')
export class ActorLookAt extends Component {
@property
bone_name = 'bone_root';
@property(Node)
bone_head: Node = Object.create(null);
_angle = 0;
_dir = 1;
start () {
this.bone_head = UtilNode.find(this.node, this.bone_name);
}
lateUpdate (deltaTime: number) {
this.bone_head?.setRotationFromEuler(this._angle, 0, 0);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "9a855bfe-32b2-4644-99e0-73aef065a33d",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,29 @@
import { _decorator, geometry, PhysicsSystem, PhysicsRayResult } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { calculateDamage } from './damage-core';
import { UtilVec3 } from '../../core/util/util';
const { ccclass, property } = _decorator;
let ray = new geometry.Ray();
@ccclass('ActorMachineGun')
export class ActorMachineGun extends ActorEquipBase {
onFire() {
this._bagData!.bulletCount--;
const forwardNode = this._actor!._forwardNode!;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
UtilVec3.copy(ray.o, origin);
UtilVec3.copy(ray.d, dir);
const distance = this._data.damage.distance;
let hit:PhysicsRayResult | undefined;
if (PhysicsSystem.instance.raycastClosest(ray, this.mask, distance)) {
hit = PhysicsSystem.instance.raycastClosestResult;
}
this.showTracer(hit, dir);
calculateDamage(this._data, hit, this._actor);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d1de3d77-deed-4506-a59b-69a8b0abf0f2",
"files": [],
"subMetas": {},
"userData": {}
}
+18
View File
@@ -0,0 +1,18 @@
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActorMain')
export class ActorMain extends Component {
public static target = Object.create(null);
start () {
ActorMain.target = this.node;
}
update (deltaTime: number) {
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fa586b1e-eba7-4914-bfcc-44d35bbf264e",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,25 @@
import { _decorator, geometry, PhysicsSystem, PhysicsRayResult } from 'cc';
import { ActorEquipBase } from './actor-equip-base';
import { calculateDamage } from './damage-core';
const { ccclass, property } = _decorator;
@ccclass('ActorMeleeWeapon')
export class ActorMeleeWeapon extends ActorEquipBase {
onFire() {
this._bagData!.bulletCount--;
const forwardNode = this._actor!._forwardNode!;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
let ray = new geometry.Ray(origin.x, origin.y, origin.z, dir.x, dir.y , dir.z);
const mask = 1 << 3 | 1 << 4;
const distance = this._data.damage.distance;
let hit:PhysicsRayResult | undefined = undefined;
if (PhysicsSystem.instance.raycastClosest(ray, mask, distance)) {
hit = PhysicsSystem.instance.raycastClosestResult;
}
calculateDamage(this._data, hit, this._actor);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "4bb28e3d-fc72-42ea-b3bb-b52241fa1d05",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,49 @@
import { _decorator, Component, geometry, Node, PhysicsRayResult, PhysicsSystem, v3, Vec3 } from 'cc';
import { UtilVec3 } from '../../core/util/util';
const { ccclass, property } = _decorator;
@ccclass('ActorMoveSlope')
export class ActorMoveSlope extends Component {
ray = new geometry.Ray();
mask = 0;
distance = 0.4
p0 = v3(0, 0, 0);
p1 = v3(0, 0, 0);
direction = v3(0, 0, 0);
start() {
this.mask = 1 << 3 | 1 << 4;
UtilVec3.copy(this.ray.d, Vec3.ZERO);
this.ray.d = v3(0, -1, 0);
this.distance = 0.3;
}
updateSlope(moveDirection:Vec3):Vec3 {
const moveLength = moveDirection.length();
if(moveLength === 0) return Vec3.ZERO;
UtilVec3.copy(this.ray.o, this.node.worldPosition);
UtilVec3.copy(this.direction, moveDirection);
if (PhysicsSystem.instance.raycastClosest(this.ray, this.mask, this.distance)) {
const hit1 = PhysicsSystem.instance.raycastClosestResult;
UtilVec3.copy(this.p0, hit1.hitPoint);
this.ray.o.add(moveDirection.normalize().multiplyScalar(0.03));
if (PhysicsSystem.instance.raycastClosest(this.ray, this.mask, this.distance)) {
const hit2 = PhysicsSystem.instance.raycastClosestResult;
UtilVec3.copy(this.direction, hit2.hitPoint);
this.direction.subtract(this.p0).normalize().multiplyScalar(moveLength);
}
}
return this.direction;
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "ab95dc11-75d1-4161-a9f8-763a19f2421d",
"files": [],
"subMetas": {},
"userData": {}
}
+160
View File
@@ -0,0 +1,160 @@
import { _decorator, Component, math, Node, RigidBody, v3, Vec3, CCFloat } from 'cc';
import { ActorMoveSlope } from './actor-move-slope';
import { UtilVec3 } from '../../core/util/util';
import { SensorSlope } from '../../core/sensor/sensor-slope';
import { SensorGround } from '../../core/sensor/sensor-ground';
import { fun } from '../../core/util/fun';
import { Level } from '../level/level';
const { ccclass, property } = _decorator;
let tempRotationSideVector = v3(0, 0, 0);
@ccclass('ActorMove')
export class ActorMove extends Component {
@property({ type: CCFloat, tooltip: 'Move Speed. ' })
speed = 1;
@property({ tooltip: 'Jump Force.' })
jumpForce = v3(0, 6.0, 0);
@property({ type: CCFloat, tooltip: 'Move smooth value.' })
smoothMove = 5;
@property({ type: CCFloat, tooltip: 'Default angle value' })
angleVertical = 0;
@property({ type: SensorSlope, tooltip: ' Sensor slope.' })
sensorSlop: SensorSlope | undefined;
@property({ type: SensorGround, tooltip: ' Sensor ground.' })
sensorGround: SensorGround | undefined;
velocity = v3(0, 0, 0);
velocityLocal = v3(0, 0, 0);
currentVelocity: Vec3 = v3(0, 0, 0);
moveVec3 = new Vec3(0, 0, 0);
currentDirection = v3(0, 0, 0);
direction = v3(0, 0, 0);
angleHead = 0;
rigid: RigidBody | undefined;
@property
angleVerticalMax = 30;
@property
angleVerticalMin = -30;
@property
faceMove = true;
angle = 0;
isJump = false;
isStopMove = false;
start () {
this.rigid = this.getComponent(RigidBody)!;
this.sensorSlop = this.getComponent(SensorSlope)!;
this.sensorGround = this.getComponent(SensorGround)!;
this.node.setRotationFromEuler(0, 180, 0);
this.onRotation(180, 0);
}
lateUpdate (deltaTime: number) {
if (Level.Instance.stop) {
this.stop();
return;
}
if (this.isStopMove) return;
this.movePosition(deltaTime);
this.moveRotation();
}
movePosition (deltaTime: number) {
//Lerp velocity.
Vec3.lerp(this.velocityLocal, this.velocityLocal, this.moveVec3, deltaTime * this.smoothMove);
UtilVec3.copy(this.velocity, this.velocityLocal);
//rotate y.
if (this.faceMove)
Vec3.rotateY(this.velocity, this.velocity, Vec3.ZERO, math.toRadian(this.node.eulerAngles.y));
this.rigid?.getLinearVelocity(this.currentVelocity);
this.velocity.y = this.currentVelocity.y;
if (this.sensorGround?._isGround && this.sensorSlop!.checkSlope(this.velocity)) {
const moveLength = this.velocity.length();
UtilVec3.copy(this.velocity, this.sensorSlop!.vectorSlop);
this.velocity.normalize().multiplyScalar(moveLength);
}
this.rigid?.setLinearVelocity(this.velocity);
}
moveRotation () {
UtilVec3.copy(this.currentDirection, this.direction);
this.angle = Math.abs(Vec3.angle(this.currentDirection, this.node.forward));
if (this.angle > 0.001) {
UtilVec3.copy(tempRotationSideVector, this.currentDirection);
const side = Math.sign(-tempRotationSideVector.cross(this.node.forward).y);
const angle = side * this.angle * 20 + this.node.eulerAngles.y;
this.node.setRotationFromEuler(0, angle, 0);
}
}
moveDirection (direction: Vec3) {
UtilVec3.copy(this.moveVec3, direction);
this.moveVec3.multiplyScalar(this.speed);
}
jump () {
//this.rigid?.applyImpulse(this.jumpForce);
this.rigid?.getLinearVelocity(this.currentVelocity);
this.currentVelocity.y = 7;
this.rigid?.setLinearVelocity(this.currentVelocity);
}
onRotation (x: number, y: number) {
this.angleHead += x;
this.direction.z = -Math.cos(Math.PI / 180.0 * this.angleHead);
this.direction.x = Math.sin(Math.PI / 180.0 * this.angleHead);
this.angleVertical -= y;
if (this.angleVertical >= this.angleVerticalMax)
this.angleVertical = this.angleVerticalMax;
if (this.angleVertical <= this.angleVerticalMin)
this.angleVertical = this.angleVerticalMin;
}
onDirection (x: number, y: number, z: number) {
this.direction.x = x;
this.direction.z = z;
this.angleVertical = y;
if (this.angleVertical >= this.angleVerticalMax)
this.angleVertical = this.angleVerticalMax;
if (this.angleVertical <= this.angleVerticalMin)
this.angleVertical = this.angleVerticalMin;
}
stop () {
this.rigid!.getLinearVelocity(this.velocity);
this.velocity.x = 0;
this.velocity.z = 0;
this.velocity.y = 0;
this.rigid!.setLinearVelocity(this.velocity);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b31a5903-4723-43f3-8149-9e8ccfe4b8e8",
"files": [],
"subMetas": {},
"userData": {}
}
+17
View File
@@ -0,0 +1,17 @@
import { _decorator, Component, Node } from 'cc';
import { ActorBase } from '../../core/actor/actor-base';
import { UtilNode } from '../../core/util/util';
import { Actor } from './actor';
const { ccclass, property } = _decorator;
@ccclass('ActorPart')
export class ActorPart extends Component {
@property( { type:ActorBase } )
actor:ActorBase | undefined;
@property
part = 'body';
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "f8ec2ae9-27d0-455d-8cc0-985302d24894",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,51 @@
import { _decorator, Component, Vec3, v3, v2, random, RigidBody, inverseLerp } from 'cc';
import { SensorRaysAngle } from '../../core/sensor/sensor-rays-angle';
import { UtilNode } from '../../core/util/util';
const { ccclass } = _decorator;
@ccclass('ActorPhysicalSkin')
export class ActorPhysicalSkin extends Component {
sensor:SensorRaysAngle | undefined;
rigid:RigidBody | undefined;
velocity:Vec3 = v3(0, 0, 0);
dir:Vec3 = v3(0, 0, 0);
velocityPlane:Vec3 = v3(0, 0, 0);
inverseForce:Vec3 = v3(0, 0, 0);
start() {
this.sensor = UtilNode.getChildComponent(this.node, 'skin', SensorRaysAngle); //this.node.getChildByName('skin').getComponent(SensorRaysAngle);
this.rigid = UtilNode.getComponent(this.node, RigidBody); //this.getComponent(RigidBody);
this.velocity = v3(0, 0, 0);
}
lateUpdate(deltaTime:number) {
/*
if (this.sensor!.checked) {
this.rigid!.getLinearVelocity(this.velocity);
// change move direction.
const position = this.node.worldPosition;
this.dir.x = this.sensor!.hitPoint.x - position.x;
this.dir.z = this.sensor!.hitPoint.z - position.z;
this.velocityPlane.x = this.velocity.x;
this.velocityPlane.z = this.velocity.z;
if (Vec3.angle(this.dir, this.velocityPlane) < 10) {
//this.velocity.x = 0;
//this.velocity.z = 0;
this.velocity = this.velocity.normalize().multiplyScalar(3);
this.rigid!.setLinearVelocity(this.velocity);
// add inverse force.
//this.inverseForce.x = -this.velocity.x;
//this.inverseForce.z = -this.velocity.z;
//this.rigid.applyImpulse(this.inverseForce.normalize().multiplyScalar(1));
}
}
*/
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "cc90bda3-0f0d-45cb-9307-f9d1ffd14b3e",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,70 @@
import { _decorator, Component, Node } from 'cc';
import { ActorBase } from '../../core/actor/actor-base';
import { Brain } from '../../core/ai/brain';
const { ccclass, property } = _decorator;
@ccclass('ActorPiranha')
export class ActorPiranha extends ActorBase {
_brain:Brain;
start() {
this.init('actor-piranha');
this._brain = new Brain(this._data.brain, this);
}
update(deltaTime: number) {
}
//#region condition
noFoundPlayer() {
}
foundPlayer() {
}
nearPlayer() {
}
canEatPlayer() {
}
fleePlayer() {
}
feedPlayer() {
}
//#endregion
idle() {
}
move() {
}
jump() {
}
crossRoad() {
}
forcePrepareJump() {
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "88d40cc5-929d-4d41-b6e0-ac722abaceb8",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,56 @@
import { _decorator, Component, Node } from 'cc';
import { Msg } from '../../core/msg/msg';
import { SensorRays } from '../../core/sensor/sensor-rays';
import { Actor } from './actor';
const { ccclass, property } = _decorator;
@ccclass('ActorSensorDropItem')
export class ActorSensorDropItem extends Component {
//@property(Actor)
//actor:Actor | undefined | null;
@property
num = 3;
sensor: SensorRays | undefined | null;
pickedNode: Node | undefined
state = -1;
curState = -1;
start () {
this.sensor = this.getComponent(SensorRays);
if (this.sensor === null) {
throw new Error(`${this.node.name} node can not find 'SensorRays' component.`);
}
}
update (deltaTime: number) {
if (this.sensor!.checked) {
this.pickedNode = this.sensor!.checkedNode;
const dropName = this.pickedNode!.name
this.curState = 255;
console.log('check drop name:', dropName);
} else {
this.curState = 0;
this.pickedNode = undefined;
}
if (this.state !== this.curState) {
this.state = this.curState;
Msg.emit('msg_grp_take_info', this.state);
}
}
public getPicked () {
if (this.pickedNode != undefined) {
return this.pickedNode;
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d350878e-4198-4b48-99b7-c28950ab57a7",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,50 @@
import { _decorator, Component, Node, geometry, PhysicsSystem, game } from 'cc';
import { ActorBase } from '../../core/actor/actor-base';
import { ActorEquipBase } from './actor-equip-base';
import { ActorPart } from './actor-part';
const { ccclass, property } = _decorator;
@ccclass('ActorShotgun')
export class ActorShotgun extends ActorEquipBase {
onFire() {
this._bagData.bulletCount--;
const forwardNode = this._actor._forwardNode;
const origin = forwardNode.worldPosition;
const dir = forwardNode.forward;
let ray = new geometry.Ray(origin.x, origin.y, origin.z, dir.x, dir.y , dir.z);
const mask = 1 << 3;
const distance = this._data.damage.distance;
if (PhysicsSystem.instance.raycastClosest(ray, mask, distance)) {
const res = PhysicsSystem.instance.raycastClosestResult;
const hitName = res.collider.node.name;
console.log(`handgun fire hit ${hitName}`);
if (hitName.concat('actor')) {
const actorPart = res.collider.node.getComponent(ActorPart);
if (!actorPart) {
console.error(` damage part can not add actor part component. ${actorPart}`);
}
const actor = actorPart.actor;
const damage = this._data.damage[hitName];
if (damage === undefined) {
console.error(`hit part undefind ${hitName}`);
}
actor._data.hp -= damage;
if (actor._data.hp <= 0) {
this._actor._data.hp = 1;
actor.do('dead');
}
}else if (hitName === 'col_brick') {
}else if (hitName === 'col_metal') {
}else{
}
}else{
console.log('empty shoot.');
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "1f1b9b99-4829-479d-8974-688695b69e88",
"files": [],
"subMetas": {},
"userData": {}
}
+57
View File
@@ -0,0 +1,57 @@
import { _decorator, Component, randomRangeInt } from 'cc';
import { Sound } from '../../core/audio/sound';
import { KeyAnyType } from '../data/game-type';
import { Msg } from '../../core/msg/msg';
import { Actor } from './actor';
import { DataSoundInst } from '../data/data-core';
import { Level } from '../level/level';
const { ccclass, property } = _decorator;
@ccclass('ActorSound')
export class ActorSound extends Component {
@property
stepLength = 1.2;
_currentStepLength = 0;
_data:KeyAnyType = {};
actor: Actor | undefined;
start() {
this.actor = this.getComponent(Actor)!;
this._data = this.actor._data;
Msg.on('msg_walk_sfx', this.walkSfx.bind(this));
}
onDestroy () {
Msg.off('msg_walk_sfx', this.walkSfx.bind(this));
}
update(deltaTime:number) {
// If Level is stop return.
if(Level.Instance.stop) return;
if(this._data.is_ground)
this._currentStepLength += Math.abs(deltaTime * this.actor!._actorMove!.velocityLocal?.length());
if(this._currentStepLength >= this.stepLength) {
this.walkSfx();
this._currentStepLength -= this.stepLength;
}
}
walkSfx () {
const type = `walk_${this._data.walk_in_type}`;
const soundList = DataSoundInst.get(type);
const index = randomRangeInt(0, soundList.length);
Sound.on(soundList[index]);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "f7156bcd-3448-4ccf-a5f0-7c2b57694ba9",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,54 @@
import { _decorator, Component, Node, v3, Vec3 } from 'cc';
import { Actor } from './actor';
import { Msg } from '../../core/msg/msg';
const { ccclass, property } = _decorator;
@ccclass('ActorStatistics')
export class ActorStatistics extends Component {
actor:Actor | undefined;
_velocity = v3(0, 0, 0);
_statisticsTime = 1;
_moveDistance = 0;
_runDistance = 0;
start() {
this.actor = this.getComponent(Actor)!;
}
update(deltaTime: number) {
this.actor?._actorMove?.rigid?.getLinearVelocity(this._velocity);
this._velocity.y = 0;
const length = this._velocity.length();
if(length > 0.1) {
const distance = length * deltaTime;
this._moveDistance += distance;
if(this.actor?._data.isRun) {
this._runDistance += distance;
}
this._statisticsTime -= deltaTime;
if(this._statisticsTime <= 0) {
this._statisticsTime = 1;
Msg.emit('msg_stat_distance', {key:'move', distance:this._moveDistance});
if(this._runDistance > 0)
Msg.emit('msg_stat_distance', {key:'run', distance:this._runDistance});
this._moveDistance = 0;
this._runDistance = 0;
}
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "6dcab13a-96ff-4fad-ab1f-b14ef40a5667",
"files": [],
"subMetas": {},
"userData": {}
}
+383
View File
@@ -0,0 +1,383 @@
/*
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, Vec3, v3, game, Node, math } from 'cc';
import { ActorBase } from '../../core/actor/actor-base';
import { IActorInput } from '../../core/input/IActorInput';
import { Local } from '../../core/localization/local';
import { Msg } from '../../core/msg/msg';
import { UtilNode, UtilVec3 } from '../../core/util/util';
import { ActorAnimationGraph } from './actor-animation-graph';
import { ActorBag } from './actor-bag';
import { ActorEquipment } from './actor-equipment';
import { ActorSensorDropItem } from './actor-sensor-drop-item';
import { ActorMove } from './actor-move';
import { SensorGround } from '../../core/sensor/sensor-ground';
import { ActorFace } from './actor-face';
import { Sound } from '../../core/audio/sound';
const { ccclass, property } = _decorator;
let tempLinearVelocity = v3(0, 0, 0);
let tempAngleVelocity = v3(0, 0, 0);
@ccclass('Actor')
export class Actor extends ActorBase implements IActorInput {
_move = v3(0, 0, 0);
_actorBag: ActorBag | undefined;
_actorEquipment: ActorEquipment | undefined;
@property({ type: ActorSensorDropItem })
actorSensorDropItem: ActorSensorDropItem | undefined;
@property({ type: ActorFace })
_actorFace: ActorFace | undefined;
_actorSensorGround: SensorGround | undefined;
_actorMove: ActorMove | undefined;
_viewNoWeapon: Node = Object.create(null);
_forwardNode: Node | undefined;
_viewRoot: Node | undefined;
// forward
forward: Vec3 = v3(0, 0, 0);
_fps = 0;
isReady = false;
bulletBox = 2;
get noAction () {
return this._data.is_dead || this._data.is_win;
}
initView () {
super.initView();
this._actorBag = new ActorBag(this);
this._actorEquipment = new ActorEquipment(this);
this._actorSensorGround = this.node.getComponent(SensorGround)!;
this._actorMove = this.getComponent(ActorMove)!;
this._forwardNode = UtilNode.find(this.node, 'forwardNode');
this._viewRoot = UtilNode.find(this.node, 'animation_view');
this._animationGraph = this._viewRoot.getComponent(ActorAnimationGraph)!;
this.do('play');
}
onUpdate () {
super.onUpdate();
this._updates.push(this.updateAction.bind(this));
}
do (name: string) {
if (this.noAction) return;
super.do(name);
}
updateAction (deltaTime: number) {
this._fps = game.frameRate as number;
if (this._data.hit_recover > 0) {
this._data.hit_recover -= deltaTime;
this._actorMove!.isStopMove = true;
this._actorMove?.stop();
} else {
this._actorMove!.isStopMove = false;
}
// Check run strength
const canRun = this.calculateRunStrength(deltaTime);
this._actorMove!.speed = canRun ? -this._data.run_speed.z : -this._data.move_speed.z;
const normalizeSpeed = Math.abs(this._actorMove!.velocity.length() / this._actorMove!.speed);
this._actorEquipment?.updateAim(normalizeSpeed);
this.recoverStrength();
// Update forward info.
if (this._forwardNode) UtilVec3.copy(this.forward, this._forwardNode?.forward);
}
onJump () {
if (this._actorSensorGround!._isGround === false) return;
if (this._data.strength >= this._data.cost_jump_strength) {
this._data.strength -= this._data.cost_jump_strength;
}
this.do('jump');
}
onGround () {
this.do('on_ground');
}
offGround () {
this.do('off_ground');
}
onWin () { }
jump () {
this._actorMove?.jump();
}
onMove (move: Vec3) {
this._actorMove?.moveDirection(move);
}
onRotation (x: number, y: number) {
if (x > 90) x = 90;
if (x < -90) x = -90;
this._actorMove?.onRotation(x, y);
}
onDir (x: number, z: number) {
this._dir.z = z;
this._dir.x = x;
}
onPause () { }
onRun (isRun: boolean) { this._data.is_run = isRun; }
onPick () {
var pickedNode = this.actorSensorDropItem?.getPicked();
if (pickedNode !== undefined) {
// Picked health.
if (pickedNode.name == 'medkit') {
const recoverHP = this._data.max_hp - this._data.hp;
if (recoverHP <= 0) {
Msg.emit(
'msg_tips',
`${Local.Instance.get('full_hp')}`
);
return;
}
this._data.hp = this._data.max_hp;
Sound.on('sfx_recovery_hp')
this.updateHP();
Msg.emit(
'msg_tips',
`${Local.Instance.get('recovery_hp')} ${recoverHP}`
);
pickedNode.emit('picked');
return;
}
// Picked same weapon increase clip.
if (this._actorBag?.pickedSameWeaponIncreaseClips(pickedNode.name)) {
pickedNode.emit('picked');
Msg.emit(
'msg_tips',
`${Local.Instance.get('picked_clip')} ${pickedNode.name} x 1`
);
Msg.emit('msg_update_bag');
Msg.emit('msg_update_equip_info');
return;
}
// Picked bullet box.
if (pickedNode.name === 'bullet_box') {
this._actorBag?.pickedBulletBox()
pickedNode.emit('picked');
Msg.emit(
'msg_tips',
`${Local.Instance.get('picked_bullet_box')}`
);
Msg.emit('msg_update_equip_info');
return;
}
// Picked items
if (this._actorBag?.pickedItem(pickedNode.name)) {
pickedNode.emit('picked');
Msg.emit(
'msg_tips',
`${Local.Instance.get('picked')} ${Local.Instance.get(pickedNode.name)} x 1`
);
this.bulletBox++;
Msg.emit('msg_update_bag');
Msg.emit('msg_update_equip_info');
} else {
Msg.emit(
'msg_tips',
`${Local.Instance.get('bag_is_full')}`
);
}
}
}
onDrop () {
if (this._actorBag?.dropItem()) {
Msg.emit('msg_update_bag');
}
}
onCrouch () {
this._data.is_crouch = this._data.is_crouch ? false : true;
// set view height.
// set physic collider height.
// set hit part height.
this._animationGraph?.play('bool_crouch', this._data.is_crouch);
Msg.emit('msg_change_tps_camera_height', this._data.is_crouch ? this._data.stand_camera_height : this._data.crouch_camera_height);
}
onAim (isAim: boolean | undefined) {
if (isAim === undefined) {
this._data.is_aim = this._data.is_aim ? false : true;
} else {
if (isAim == this._data.is_aim) return;
this._data.is_aim = isAim;
}
// Get aim state.
this.do(this._data.is_aim ? 'on_aim' : 'off_aim');
if (this.isPlayer) Msg.emit('msg_change_tps_camera_target', this._data.is_aim ? 1 : 0);
}
/**
* Open fire interface.
* @returns
*/
onFire () {
// Determines if the current equipment is ready to fire.
// Includes the number of rounds in the magazine and the firing cooldown.
if (this._actorEquipment!.currentEquip?.checkUse() == false) return;
// Execute the fir action.
this._actorEquipment?.do('fire');
// Sets the aim stable value to the maximum.
this._actorEquipment?.updateAim(1, true);
/*
const canUseEquip = this.calculateStrengthUseEquip();
if (canUseEquip) {}
*/
}
/**
* Set Auto fire state.
* @param isAutoFire Auto fire state.
*/
onAutoFire (isAutoFire: boolean) { this._data.is_auto_fire = isAutoFire; }
onReload () {
if (this._actorEquipment?.currentEquip?.checkFullBullet()) return;
this._actorEquipment?.do('reload');
}
onEquip (index: number) {
if (this._actorEquipment?.equip(index)) {
if (this._data.has_multi_res) this._viewNoWeapon.active = false;
} else {
if (this._data.has_multi_res) this._viewNoWeapon.active = true;
}
}
onChangeEquips (): boolean { return false; }
calculateStrengthUseEquip (): boolean {
const canUseEquip = this._data.strength >= this._data.cost_use_equip_strength;
if (canUseEquip) {
this._data.strength -= this._data.cost_use_equip_strength;
this._data.strength = Math.max(this._data.strength, 0);
}
return canUseEquip;
}
calculateRunStrength (deltaTime: number): boolean {
const canRun = this._data.is_run && this._data.strength >= this._data.cost_run_strength;
if (canRun) {
this._data.strength -= this._data.cost_run_strength * deltaTime;
this._data.strength = Math.max(this._data.strength, 0);
}
return canRun;
}
recoverStrength () {
if (this._data.is_ground === false) return;
if (this._data.is_run) return;
this._data.strength += this._data.recover_ground_strength * game.deltaTime;
if (this._data.strength > this._data.max_strength) this._data.strength = this._data.max_strength;
const percent_value = this._data.strength / this._data.max_strength;
if (this.isPlayer) {
Msg.emit('fil_strength', percent_value);
}
}
lateUpdate (deltaTime: number) {
if (this._actorMove == undefined) return;
// Synchronize animation setup data.
const rigidBody = this._actorMove?.rigid;
rigidBody!.getLinearVelocity(tempLinearVelocity);
tempLinearVelocity.y = 0;
const linearVelocityLength = tempLinearVelocity.length();
const eulerAnglesY = this.node.eulerAngles.y;
//rotate y.
Vec3.rotateY(tempLinearVelocity, tempLinearVelocity, Vec3.ZERO, math.toRadian(-eulerAnglesY));
let num_velocity_x = tempLinearVelocity.x;
let num_velocity_y = tempLinearVelocity.z;
let moveSpeed = linearVelocityLength * this._data.linear_velocity_animation_rate;
// Check rotation.
const angleSpeed = this._actorMove!.angle;
if (linearVelocityLength < 0.01 && angleSpeed > 2) {
moveSpeed = angleSpeed * this._data.angle_velocity_animation_rate;
num_velocity_x = angleSpeed / this._data.angle_velocity_animation_scale;
}
this._animationGraph?.setValue('num_velocity_x', num_velocity_x);
this._animationGraph?.setValue('num_velocity_y', -num_velocity_y);
this._animationGraph?.setValue('num_move_speed', moveSpeed);
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "93422fc8-69fa-4ad1-9748-d74807c38cab",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,69 @@
import { _decorator, Component, Node, animation, CCFloat, CCString } from "cc";
import { Msg } from "../../core/msg/msg";
const { ccclass, property } = _decorator;
@ccclass("AnimationGraphMove")
export class AnimationGraphMove extends animation.StateMachineComponent {
@property
time = 0.5;
@property
msg = 'msg_walk_sfx';
_triggered: boolean = false;
/**
* Called right after a motion state is entered.
* @param controller The animation controller it within.
* @param motionStateStatus The status of the motion.
*/
public onMotionStateEnter (controller: animation.AnimationController, motionStateStatus: Readonly<animation.MotionStateStatus>): void {
// Can be overrode
}
/**
* Called when a motion state is about to exit.
* @param controller The animation controller it within.
* @param motionStateStatus The status of the motion.
*/
public onMotionStateExit (controller: animation.AnimationController, motionStateStatus: Readonly<animation.MotionStateStatus>): void {
// Can be overrode
this._triggered = false;
}
/**
* Called when a motion state updated except for the first and last frame.
* @param controller The animation controller it within.
* @param motionStateStatus The status of the motion.
*/
public onMotionStateUpdate (controller: animation.AnimationController, motionStateStatus: Readonly<animation.MotionStateStatus>): void {
// Can be overrode
if (motionStateStatus.progress > this.time && !this._triggered) {
// 触发事件
this._triggered = true;
Msg.emit(this.msg);
} else if (motionStateStatus.progress < this.time && this._triggered) {
this._triggered = false;
}
}
/**
* Called right after a state machine is entered.
* @param controller The animation controller it within.
*/
public onStateMachineEnter (controller: animation.AnimationController) {
// Can be overrode
}
/**
* Called right after a state machine is entered.
* @param controller The animation controller it within.
*/
public onStateMachineExit (controller: animation.AnimationController) {
// Can be overrode
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "4cc78b6c-8111-4ea7-acfd-b19d390703f8",
"files": [],
"subMetas": {},
"userData": {}
}
+115
View File
@@ -0,0 +1,115 @@
import { Node, PhysicsRayResult, Vec3 } from "cc";
import { Sound } from "../../core/audio/sound";
import { fx } from "../../core/effect/fx";
import { Local } from "../../core/localization/local";
import { Msg } from "../../core/msg/msg";
import { ActorPart } from "./actor-part";
import { Actor } from "./actor";
import { DataLevelInst } from "../data/data-core";
export function calculateDamageNode (data: any, node: Node, hitPoint: Vec3, shootActor: Actor | undefined) {
const hitName = node.name.split('_')[0];
let hitTag = `hit_${hitName}`;
const damage = data.damage;
const actorPart = node.getComponent(ActorPart);
if (shootActor?.isPlayer) Msg.emit('msg_stat_times', `enemy_fire`);
if (actorPart) {
const actorBodyName = actorPart.part;
const part_damage = damage[actorBodyName];
if (part_damage === undefined) throw new Error(`${node.name} node hit part undefine '${actorBodyName}'`);
const actor = actorPart.actor;
if (actor === undefined) throw new Error(`${node.name} node hit part '${actorBodyName}' undefine actor`);
if (shootActor?.isPlayer) {
Msg.emit('msg_stat_times', `hit_${actorBodyName}`);
}
if (actor.isPlayer) {
Msg.emit('msg_stat_times', `be_hit_${actorBodyName}`);
}
actor._data.hp -= part_damage;
if (actor._data.hp <= 0) {
actor._data.hp = 0;
fx.on(DataLevelInst._data.fx_dead, actor.node.worldPosition);
if (actor.isPlayer) Msg.emit('msg_stat_times', 'killed');
actor.do('dead');
} else {
actor.do('hit_gun');
}
if (actor.isPlayer) actor.updateHP();
hitTag = 'hit_body';
}
calculateDamageView(damage[hitTag], hitPoint);
}
export function calculateDamage (data: any, hit: PhysicsRayResult | undefined, shootActor: Actor | undefined) {
if (shootActor?.isPlayer) Msg.emit('msg_stat_times', `enemy_fire`);
if (hit === undefined) {
Msg.emit(
'msg_tips',
`${Local.Instance.get('hit_nothing')}`,
);
return;
}
const node: Node = hit.collider.node;
const hitName = node.name.split('_')[0];
let hitTag = `hit_${hitName}`;
const damage = data.damage;
const actorPart = node.getComponent(ActorPart);
if (actorPart) {
const actorBodyName = actorPart.part;
const part_damage = damage[actorBodyName];
if (part_damage === undefined) throw new Error(`${node.name} node hit part undefine '${actorBodyName}'`);
const actor = actorPart.actor;
if (actor === undefined) throw new Error(`${node.name} node hit part '${actorBodyName}' undefine actor`);
if (shootActor?.isPlayer) {
Msg.emit('msg_stat_times', `hit_${actorBodyName}`);
}
if (actor.isPlayer) {
Msg.emit('msg_stat_times', `be_hit_${actorBodyName}`);
}
actor._data.hp -= part_damage;
if (actor._data.hp <= 0) {
actor._data.hp = 1;
fx.on(DataLevelInst._data.fx_dead, actor.node.worldPosition);
if (shootActor?.isPlayer) Msg.emit('msg_stat_times', 'killed');
actor.do('dead');
} else {
actor.do('hit_gun')
}
hitTag = 'hit_body';
if (actor.isPlayer) actor.updateHP();
}
calculateDamageView(damage[hitTag], hit.hitPoint);
}
function calculateDamageView (damage: Record<string, any> | undefined, hitPoint: Vec3) {
if (damage === undefined) return;
if (damage.fx) fx.on(damage.fx, hitPoint);
if (damage.sfx) Sound.on(damage.sfx);
if (damage.notify === undefined) {
const showMsg = damage['notify'];
if (showMsg == undefined) return;
Msg.emit(
'msg_tips',
`${Local.Instance.get(damage['notify'])}`
);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d8d6abd9-1319-4ee5-88f5-8656e35e0e4b",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,68 @@
import { _decorator, Color, Component, geometry, Node, PhysicsRayResult, PhysicsSystem, v3, Vec2, Vec3, CCFloat } from 'cc';
import { Gizmo, Util, UtilVec3 } from '../../core/util/util';
import { FxRayLine } from '../effect/fx-ray-line';
import { EDITOR } from 'cc/env';
const { ccclass, property, executeInEditMode } = _decorator;
@ccclass('InfraredTracker')
@executeInEditMode
export class InfraredTracker extends Component {
@property([CCFloat])
masks: number[] = [];
@property
distance = 300;
@property(Node)
forwardNode: Node | undefined;
ray: geometry.Ray | undefined;
target: Node | undefined;
mask: number = 0;
hit: PhysicsRayResult | undefined;
endPosition = v3(0, 0, 0);
rayLine: FxRayLine | undefined;
forward = v3(0, 0, 0);
direction = v3(0, 0, 0);
onEnable () {
this.ray = new geometry.Ray();
this.mask = Util.calculateMask(this.masks);
this.rayLine = this.node.children[0].getComponent(FxRayLine)!;
}
update (deltaTime: number) {
UtilVec3.copy(this.ray!.o, this.node.worldPosition);
UtilVec3.copy(this.direction, this.forwardNode!.worldPosition);
this.direction.subtract(this.node.worldPosition).normalize();
UtilVec3.copy(this.ray!.d, this.direction);
this.hit = undefined;
this.target = undefined;
if (PhysicsSystem.instance.raycastClosest(this.ray!, this.mask, this.distance)) {
this.hit = PhysicsSystem.instance.raycastClosestResult;
}
if (this.hit !== undefined) {
this.target = this.hit.collider.node;
UtilVec3.copy(this.endPosition, this.hit.hitPoint);
} else {
UtilVec3.copy(this.endPosition, this.node.worldPosition);
//console.log('InfraredTracker forward:', this.direction);
UtilVec3.scaleDirection(this.endPosition, this.direction, this.distance);
}
// Update ray line.
this.rayLine?.setRayLine(this.node.worldPosition, this.endPosition);
if (EDITOR) Gizmo.drawLine(this.ray!.o, this.endPosition, Color.BLUE);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e6e9cce9-5439-4aa0-a61f-9e3efb73a9f0",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,15 @@
import { _decorator, Component, animation } from 'cc';
import { Level } from '../level/level';
import { Game } from '../data/game';
const { ccclass, property } = _decorator;
@ccclass('LevelEnablePlay')
export class LevelEnablePlay extends Component {
onEnable() {
if (Game.Instance._currentGameNodeName !== 'level') {
this.node.getComponent(animation.AnimationController)!.enabled = false;
}
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "35054940-62df-45b3-97fc-33648e5b206f",
"files": [],
"subMetas": {},
"userData": {}
}
@@ -0,0 +1,77 @@
import { _decorator, Collider, Component, ITriggerEvent, Node, PhysicsSystem, RigidBody, v3, Vec3, CCFloat } from 'cc';
import { calculateDamageNode } from './damage-core';
import { Sound } from '../../core/audio/sound';
import { Actor } from './actor';
const { ccclass, property } = _decorator;
@ccclass('ProjectileGrenade')
export class ProjectileGrenade extends Component {
_data: any;
_size = v3(1, 1, 1);
@property(CCFloat)
explodeTime = 3;
@property(Vec3)
endSize = v3(6, 6, 6);
@property(Collider)
collider: Collider | undefined;
@property(RigidBody)
rigidbody: RigidBody | undefined;
updateFunction: Function | undefined;
actor: Actor | undefined;
onThrow (weaponData: any, force: Vec3, shootActor: Actor | undefined) {
this._data = weaponData;
this.actor = shootActor;
this.rigidbody?.applyImpulse(force);
this.updateFunction = this.waitExplode;
}
onExplode () {
this.collider!.isTrigger = true;
this.rigidbody!.useGravity = false;
this.updateFunction = this.exploding;
this.collider!.on('onTriggerEnter', this.onTriggerEnter, this);
Sound.on(this._data.sound_explode);
}
onExplodeEnd () {
this.updateFunction = undefined;
this.collider!.off('onTriggerEnter', this.onTriggerEnter, this);
this.node.active = false;
}
onTriggerEnter (event: ITriggerEvent) {
const hitPoint = event.otherCollider.node.getWorldPosition();
calculateDamageNode(this._data, event.otherCollider.node, hitPoint, this.actor);
}
waitExplode (deltaTime: number) {
this.explodeTime -= deltaTime;
if (this.explodeTime <= 0) {
this.onExplode();
}
}
exploding (deltaTime: number) {
Vec3.lerp(this._size, this._size, this.endSize, deltaTime * 5);
this.node.setWorldScale(this._size);
if (Math.abs(this._size.x - this.endSize.x) < 0.1) {
this.onExplodeEnd();
}
}
update (deltaTime: number) {
if (this.updateFunction !== undefined)
this.updateFunction(deltaTime);
}
}
@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b56c0328-39d9-47c8-aaeb-b344a12fe602",
"files": [],
"subMetas": {},
"userData": {}
}