[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

View File

@@ -0,0 +1,152 @@
/*
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, randomRange, random, randomRangeInt } from 'cc';
import { Msg } from '../../core/msg/msg';
import { DataLevelInst, DataUpgradeCardInst } from '../data/data-core';
import { Local } from '../../core/localization/local';
import { Level } from './level';
const { ccclass, property } = _decorator;
@ccclass('LevelEventsCard')
export class LevelEventsCard extends Component {
_interval:number = 0.1;
probability:any;
counter = 0;
groupCounter:Array<number> | undefined;
currentCards: Array<{ name: string; info: any; }> = new Array(3);
nextCounter = 2;
counterCard = 0;
start() {
this.probability = DataLevelInst._data.probability_drop_card;
this.groupCounter = new Array(DataLevelInst._data.cards.length);
this._interval = randomRange(this.probability.interval[0], this.probability.interval[1]);
this.nextCounter = DataUpgradeCardInst._data.next_show_card_param_a;
Msg.on('msg_kill_enemy', this.checkNextEvent.bind(this));
}
onDestroy() {
Msg.off('msg_kill_enemy', this.checkNextEvent.bind(this));
}
nextEvent() {
this.counterCard++;
this.nextCounter += DataUpgradeCardInst._data.next_show_card_param_a * DataUpgradeCardInst._data.next_show_card_param_b;
const odds = random();
const weights = this.probability.weights;
let excludeGroupIndex = -1;
for(let iWeight = 0; iWeight < weights.length; iWeight++) {
if (odds <= weights[iWeight]) {
excludeGroupIndex = iWeight;
break;
}
}
if (excludeGroupIndex === -1) {
throw new Error(`Error calculate weight level events card. value:${odds}`);
}
const currentMax = this.groupCounter![excludeGroupIndex];
const weightMax = this.probability.weights_max;
if (currentMax >= weightMax[excludeGroupIndex]) {
this._interval = this.probability.interval_weight_max;
return;
}
// Exclude 3, This is temp.
const excludeIndex = 3;//this.probability.weights_group[excludeGroupIndex];
// Get upgrade card list.
const cards = DataLevelInst._data.cards;
for(let i = 0; i < cards.length; i++) {
if(i === excludeIndex) continue;
this.currentCards[i] = {
name:cards[i],
info:this.calculateCardInfo(cards[i])
};
}
Level.Instance.currentCards = this.currentCards;
console.log('Current cards:', this.currentCards);
Msg.emit('push', 'upgrade_cards');
this.counter++;
this.groupCounter![excludeGroupIndex]++;
}
calculateCardInfo(name:string) {
const upgradeCards = DataUpgradeCardInst._data;
const selectCardData = upgradeCards[name];
const randomCardIndex = randomRangeInt(0, selectCardData.length);
const randomCardData = selectCardData[randomCardIndex];
const valueCount = randomCardData.values.length;
let values = new Array(valueCount);
let describe = Local.Instance.get(randomCardData.describe);
for(let i = 0; i < valueCount; i++) {
const tempData = randomCardData.values[i];
const tempValue = this.calculateRange(tempData.isFloat, tempData.range);
const showValue = tempData.isFloat ? `${tempValue * 100} %` : `${tempValue}`;
describe = describe.replace(`##${i}##`, showValue);
values[i] = {
"name":tempData.name,
"isFloat":tempData.isFloat,
"value": tempValue
}
}
return { describe, values }
}
calculateRange(isFloat:boolean, range:number[]):number {
if(range.length !== 2) return 0;
let value = isFloat? randomRange(range[0], range[1]) : randomRangeInt(range[0], range[1]);
if(isFloat) value = Number(value.toFixed(2));
return value;
}
checkNextEvent(counter:number) {
if (counter > this.nextCounter) {
this.nextEvent();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "c1692bc8-6ad8-499a-ae2a-16f9b994d6c9",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,184 @@
/*
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, randomRange, random } from 'cc';
import { Msg } from '../../core/msg/msg';
import { Level } from './level';
import { DataLevelInst } from '../data/data-core';
const { ccclass } = _decorator;
@ccclass('LevelEventsEnemy')
export class LevelEventsEnemy extends Component {
// Used to record the interval at which time occurs.
_interval: number = 0.1;
// The probability data of enemy drops.
probability: any;
// Used for the total number of enemies already generated.
counter = 0;
// Used to count the total number of each grouping.
groupCounter: Array<number> | undefined;
// Total number of deaths.
killCounter = 0;
start () {
// Get probability.
this.probability = DataLevelInst._data.probability_drop_enemy;
if ((globalThis as any).HrefSetting) {
this.probability.max = (globalThis as any).HrefSetting.maxEnemies
}
// Initialize group statistics based on the number of groups.
this.groupCounter = new Array(DataLevelInst._data.enemies.length);
for (let i = 0; i < DataLevelInst._data.enemies.length; i++) {
this.groupCounter[i] = 0;
}
// Get the time of the next decision cycle.
this._interval = randomRange(this.probability.interval[0], this.probability.interval[1]);
// Register enemy event logic.
Msg.on('msg_remove_enemy', this.remove.bind(this));
}
onDestroy () {
// Register enemy event logic.
Msg.off('msg_remove_enemy', this.remove.bind(this));
}
/**
* Calculates a monster generation event.
* @returns
*/
generateEvent () {
// If the total number of enemies in the scene is greater than or equal to the maximum value No enemy generation logic is performed.
// The total number of survivors is equal to the total number of generation minus the number of deaths.
if ((this.counter - this.killCounter) >= this.probability.max) return;
// Get a random value range [0-1].
const odds = random();
// Get a list of weights.
const weights = this.probability.weights;
// Set default occur group index.
let occurGroupIndex = -1;
// Find the matching index in a random list based on a random number.
for (let iWeight = 0; iWeight < weights.length; iWeight++) {
if (odds <= weights[iWeight]) {
occurGroupIndex = iWeight;
break;
}
}
// Determine if it is found, if not it means there is a problem with the data configuration.
// The set of random intervals contains all interval values from 0 - 1.
if (occurGroupIndex === -1) {
throw new Error(`Error calculate weight on Level events enemy. value:${odds}`);
}
// Get the maximum value of the current group.
const currentMax = this.groupCounter![occurGroupIndex];
//
const weightMax = this.probability.weights_max;
if (currentMax >= weightMax[occurGroupIndex]) {
this._interval = this.probability.interval_weight_max;
return;
}
const currentIndex = this.probability.weights_group[occurGroupIndex];
const res = DataLevelInst._data.enemies[currentIndex];
// Send add add enemy.
Msg.emit('msg_add_enemy', { res: res, groupID: occurGroupIndex })
// Increase event count.
this.counter++;
// Increase the mapping event group count.
this.groupCounter![occurGroupIndex]++;
// Send warning message.
if (res == 'boss_0') Msg.emit('level_action', 'warning');
}
/**
* Removes enemies and updates the corresponding stats.
* @param groupIndex Group ID to be removed.
*/
public remove (groupIndex: number) {
// Increase the number of kills once
this.killCounter++;
// The number of current index groups minus one.
this.groupCounter![groupIndex]--;
// Exception judgment, if it is less than 0 it means there is a duplicate count of enemy death statistics.
// You need to check the death-related logic to see if multiple deaths were executed.
if (this.groupCounter![groupIndex] < 0) {
throw new Error(`Multiply remove enemy. group index = ${groupIndex}`);
}
// Triggers a death execution message.
Msg.emit('msg_kill_enemy', this.killCounter);
}
/**
* The detection logic is executed per frame.
* @param deltaTime The incremental time of the current frame.
* @returns
*/
update (deltaTime: number) {
//
if (!Level.Instance._isStart && Level.Instance.stop && !Level.Instance._player) return;
this._interval -= deltaTime;
// Interval time less than 0 to start event detection.
if (this._interval <= 0) {
// Get the time of the next decision cycle.
this._interval = randomRange(this.probability.interval[0], this.probability.interval[1]);
// Execute generated events.
this.generateEvent();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "272c792a-5e63-47d0-8581-1836374665e6",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,118 @@
/*
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, randomRange, random } from 'cc';
import { Msg } from '../../core/msg/msg';
import { Level } from './level';
import { DataLevelInst } from '../data/data-core';
const { ccclass, property } = _decorator;
@ccclass('LevelEventsItems')
export class LevelEventsItems extends Component {
// Used to record the interval at which time occurs.
_interval: number = 0.1;
// The probability data of item drops.
probability: any;
// Used for the total number of items already generated.
counter = 0;
// Used to count the total number of each grouping.
groupCounter: Array<number> | undefined;
start () {
// Get probability.
this.probability = DataLevelInst._data.probability_drop_items;
this.groupCounter = new Array(DataLevelInst._data.items.length);
for (let i = 0; i < DataLevelInst._data.items.length; i++) {
this.groupCounter[i] = 0;
}
this._interval = randomRange(this.probability.interval[0], this.probability.interval[1]);
Msg.on('msg_remove_item', this.remove.bind(this));
}
onDestroy () {
Msg.off('msg_remove_item', this.remove.bind(this));
}
nextEvent () {
this._interval = randomRange(this.probability.interval[0], this.probability.interval[1]);
if (this.counter >= this.probability.max) return;
const odds = random();
const weights = this.probability.weights;
let occurGroupIndex = -1;
for (let iWeight = 0; iWeight < weights.length; iWeight++) {
if (odds <= weights[iWeight]) {
occurGroupIndex = iWeight;
break;
}
}
if (occurGroupIndex === -1) {
throw new Error(`Error calculate weight on Level Infinite Events. value:${odds}`);
}
const currentMax = this.groupCounter![occurGroupIndex];
const weightMax = this.probability.weights_max;
if (currentMax >= weightMax[occurGroupIndex]) {
this._interval = this.probability.interval_weight_max;
return;
}
const currentIndex = this.probability.weights_group[occurGroupIndex];
const res = DataLevelInst._data.items[currentIndex];
const sendData = { res: res, pos: undefined, groupIndex: currentIndex };
Msg.emit('msg_add_item', sendData);
this.counter++;
this.groupCounter![occurGroupIndex]++;
}
public remove (groupIndex: number) {
this.counter--;
this.groupCounter![groupIndex]--;
if (this.groupCounter![groupIndex] < 0) {
throw new Error(`Mutiply remove enemy. group index = ${groupIndex}`);
}
}
update (deltaTime: number) {
if (!Level.Instance._isStart && Level.Instance.stop && !Level.Instance._player) return;
this._interval -= deltaTime;
if (this._interval <= 0) {
this.nextEvent();
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "a92ca369-3717-4eea-bedd-13a27b811f8b",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,42 @@
import { _decorator, Component, Node } from 'cc';
import { Level } from './level';
const { ccclass, property } = _decorator;
@ccclass('LevelEvents')
export class LevelEvents extends Component {
_events:{ [key:string]:any } = {};
_time = 0;
_index = 0;
_max = 0;
_cur:any;
start() {
}
public init(events:any) {
this._events = events;
this._index = 0;
this._max = this._events.length;
this._cur = this._events[this._index];
}
updateEvent(deltaTime: number) {
if (this._index >= this._max) return;
this._time += deltaTime;
if (this._time > this._cur.time) {
Level.Instance.addEnemy(this._cur.res);
this._index++;
if (this._index < this._max)
this._cur = this._events[this._index];
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "1bf46fc9-4b7a-4723-96bb-450c443b9730",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,366 @@
/*
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, find, Vec3, v3, game } from 'cc';
import { Action } from '../../core/action/action';
import { Save } from '../data/save';
import { Msg } from '../../core/msg/msg';
import { Singleton } from '../../core/pattern/singleton';
import { Res } from '../../core/res/res';
import { ResCache } from '../../core/res/res-cache';
import { Actor } from '../actor/actor';
import { DropItem } from '../item/drop-item';
import { NavSystem } from '../navigation/navigation-system';
import { DataEquipInst, DataNavigationInst } from '../data/data-core';
import { fun } from '../../core/util/fun';
const { ccclass, property } = _decorator;
export class Level extends Singleton {
// Action objects are used to execute the current set of actions.
_action: Action | undefined;
// Level data object to store static game data.
_data: { [key: string]: any } = {};
// Level time.
_time: number = 0;
// The state at the beginning of the level.
_isStart = false;
// The spawn position of the player's level.
_spawn_pos = v3(0, 2, 0);
// The score rate of the level.
_scoreRate: number = 0;
// The player's game object.
_player: Actor | undefined;
// List of nodes of level enemies.
_enemies: Node[] = [];
// The root node of all objects at game runtime.
_objectNode: Node | null | undefined;
// Current upgrade cards.
currentCards: Array<{ name: string; info: any; }> = new Array(3);
// Level stop.
stop = false;
/**
* Initialize the level object.
*/
public init (): void {
// Get the level data and copy it for storage.
this._data = Object.assign(ResCache.Instance.getJson('data-level').json);
// Create an action object to manage the action of the level.
this._action = new Action('action-level');
// Find the root node of all objects.
this._objectNode = find('init')?.getChildByName('objects');
// Register external message access function mapping.
Msg.on('msg_level_start', this.onLevelStart.bind(this));
Msg.on('level_action', this.levelAction.bind(this));
Msg.on('level_do', this.do.bind(this));
Msg.on('msg_add_enemy', this.addEnemy.bind(this));
Msg.on('msg_add_item', this.addDrop.bind(this));
Msg.on('msg_replay', this.onReplay.bind(this));
}
/**
* Executes the function with the name specified by the current object.
* @param fun Name of the function to be executed.
*/
public do (fun: string) {
this[fun]();
}
/**
* This function is used to set the behavior related to the start of the level.
*/
public onLevelStart () {
// Set level stop is false.
this.stop = false;
this._isStart = true;
// Switch to the next statistic.
Save.Instance.nextStatistics();
// Initialize the current path finding data.
NavSystem.Init(DataNavigationInst._data);
this.levelAction('start');
}
public pause () {
this.stop = true;
}
public resume () {
this.stop = false;
}
/**
* This method is used to restart the game.
*/
public onReplay () {
fun.delay(() => {
Msg.emit('push', 'level');
}, 2);
}
public levelAction (name: string) {
this._action!.on(name);
}
/**
* Added level role method.
* Used to initialize the character game object.
*/
public addPlayer () {
// Get a random node from the navigation system.
//const point = NavSystem.randomPoint();
// Get the player's prefab object from the resource cache.
const prefab = ResCache.Instance.getPrefab(this._data.prefab_player);
// Instantiate player level game object.
const resPlayer = Res.inst(prefab, this._objectNode!, this._data.spawn_pos);
// Get the Actor from the player level game object.
this._player = resPlayer.getComponent(Actor)!;
// Detect if this actor exists
if (this._player === null) {
throw new Error(`Level add player can not bind Actor Component.`);
}
this._player.bulletBox = 5;
// Set the player tag value of this actor to true.
this._player.isPlayer = true;
// Initialize the player object.
this._player.init('data-player');
// Update player hp.
this._player.updateHP();
}
/**
* Add level enemy method.
* @param res Add enemy resource name.
* @param groupID Enemy group id.
* @returns Enemy game object.
*/
public addEnemy (data: { res: string, groupID: number }) {
// Get a random node from the navigation system.
const point = NavSystem.randomPoint();
// Get the enemy's prefab object from the resource cache.
var prefab = ResCache.Instance.getPrefab(data.res);
// Instantiate enemy level game object.
var enemy = Res.inst(prefab, this._objectNode!, point.position);
enemy.name = data.res;
const actor = enemy.getComponent(Actor);
if (!actor) {
console.error('error inst enemy lose actor component. the name is :', data.res);
return;
}
actor._groupIndex = data.groupID;
actor.init(`data-${data.res}`);
actor.bulletBox = 9999;
actor.isReady = true;
this._enemies.push(enemy);
return enemy;
}
public removeEnemy (node: Node) {
for (let i = 0; i < this._enemies.length; i++) {
if (this._enemies[i] === node) {
this._enemies.splice(i, 1);
break;
}
}
}
public addDrop (_data: { res: string, pos: Vec3 | undefined, groupIndex: number }) {
if (_data.pos === undefined) {
const point = NavSystem.randomPoint();
_data.pos = point.position;
}
const prefab = ResCache.Instance.getPrefab(this._data.prefab_drop_item);
const dropNode = Res.inst(prefab, this._objectNode!, _data.pos);
dropNode.name = _data.res;
const drop = dropNode.getComponent(DropItem);
const data = DataEquipInst.get(_data.res);
if (drop === null) {
throw new Error(`Drop node can not add component Drop Item.`);
}
drop.init(_data.res, data.drop_effect_index, _data.groupIndex);
}
public addObj (res: string) {
const point = NavSystem.randomPoint();
var prefab = ResCache.Instance.getPrefab(res);
var objNode = Res.inst(prefab, this._objectNode!, point.position);
return objNode;
}
public update (deltaTime: number): void {
if (!this._isStart) return;
if (this.stop) return;
this._time += deltaTime;
this._action!.update(deltaTime);
Msg.emit('msg_update_map');
}
/**
* Select a skill card to update player attributes.
* @param selectIndex Select upgrade card index.
*/
public upgradePlayerAttributes (selectIndex: number) {
// Get upgrade values.
const upgradeValues = this.currentCards[selectIndex].info.values;
// Upgrade player data.
const length = upgradeValues.length;
//Update all attributes of the card.
for (let i = 0; i < length; i++) {
console.log(upgradeValues[i]);
const data = upgradeValues[i];
this._player!._data[data.name] = data.value;
}
}
public getUpgradeCardInfo (selectIndex: number) {
return this.currentCards[selectIndex].info.describe;
}
public gameOver () {
// Set level stop is true.
this.stop = true;
this._isStart = false;
Msg.emit('msg_stat_time', { key: 'play', time: this._time });
this.calculateScore();
this._enemies = [];
Save.Instance.saveGameOver(this._time, this._scoreRate);
this._player = undefined;
}
/**
* Calculate level score.
*/
public calculateScore () {
// Save day.
let day = Save.Instance.get('day');
if (day === undefined) day = 0;
else day++;
Save.Instance.setValue('day', day);
// Get killed number.
const killedTimes = Save.Instance.getStatistics('killedTime');
// Calculate hit rate.
const hitBodyTimes = Save.Instance.getStatistics('hit_bodyTimes');
const hitHeadTimes = Save.Instance.getStatistics('hit_headTimes');
let fireTimes = Save.Instance.getStatistics('fireTimes');
const hitRate = fireTimes == 0 ? 0 : ((hitBodyTimes + hitHeadTimes) / fireTimes);
Save.Instance.setStatistics('hit_rate', Number(hitRate.toFixed(4)));
// Calculate be hit times.
const beHitBodyTimes = Save.Instance.getStatistics('be_hit_bodyTimes');
const beHitHeadTimes = Save.Instance.getStatistics('be_hit_headTimes');
const beHitTimes = beHitBodyTimes + beHitHeadTimes;
Save.Instance.setStatistics('be_hit_times', beHitTimes);
// Calculate dodge rate.
const enemyFireTimes = Math.max(beHitTimes, Save.Instance.getStatistics('enemy_fireTimes'));
const dodgeRate = enemyFireTimes == 0 ? 0 : (1 - beHitTimes / enemyFireTimes);
Save.Instance.setStatistics('dodge_rate', Number(dodgeRate.toFixed(4)));
// Calculate level score.
// level score = killed * killed_to_score + hitRate * eachRateValue + dodgeRate * eachRateValue + survivalTime * survival_time_to_score
const eachRateValue = this._data.each_rate_value;
const level_score = Math.floor(killedTimes * this._data.killed_to_score + hitRate * eachRateValue + dodgeRate * eachRateValue + this._time * this._data.survival_time_to_score);
Save.Instance.setStatistics('level_score', level_score);
// Calculate final score rate.
const scoreLevels = this._data.score_level;
let passLevel = true;
this._scoreRate = scoreLevels.length - 1;
for (let i = 0; i < scoreLevels.length; i++) {
const infos = scoreLevels[i];
passLevel = true;
for (let k in infos) {
if (k == 'score') continue;
if (Save.Instance._currentStatistics[k] < infos[k]) {
passLevel = false;
break;
}
}
if (passLevel) {
this._scoreRate = i;
break;
}
}
// Save score rate.
Save.Instance.setStatistics('score_rate', this._scoreRate);
}
/**
* Get final score rating
* @returns
*/
public getLevelScore () {
return this._data.score_level[this._scoreRate].score;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "de76ffef-f81d-4474-a75f-52ab347c1d33",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,24 @@
import { _decorator, Component, Node, Camera, director, game, MeshRenderer } from 'cc';
import { EDITOR } from 'cc/env';
const { ccclass, property } = _decorator;
@ccclass('SpawnsGroup')
export class SpawnsGroup extends Component {
onEnable() {
this.node.children.forEach(child => {
const meshRender = child.getComponent(MeshRenderer);
if (meshRender) meshRender.enabled = false;
});
}
start() {
}
update(deltaTime: number) {
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "aa3b76cd-e02d-4d5b-bb4f-786f54aee4b0",
"files": [],
"subMetas": {},
"userData": {}
}