【红点系统基础篇】游戏开发之红点树构建

一、定义

游戏开发中的红点系统是一种用于提示玩家未处理信息的核心功能设计,其核心目标是引导玩家关注关键内容,并通过层级联动的逻辑实现高效状态管理。
在界面表现上常用普通小红点、数字红点以及自定义样式的红点等等,在逻辑上常有可领取奖励、可升级操作、新功能提示等等,不管是红点表现还是判断逻辑,都是建立在一套基础的红点系统之上的,这篇文章先实现一套基础的红点管理系统,下一篇文章再给大家说明红点表现、判断逻辑以及优化方面的内容。

二、需求设计

1、核心功能

  • 状态提示:通过视觉标识(如红点、数字或图标)提示玩家未处理信息,需支持动态数值显示(如未读消息数量);
  • 层级联动:子节点状态变化需自动触发父节点更新,例如任务详情页的红点需同时点亮上级菜单的对应标识;
  • 项目定制化:根据所开发的项目进行规范约束,以提高拓展性和易用性。

2、代码结构设计(TypeScript为例)

因为红点表现天然具备层级关系,所以我们这里的红点树采用前缀树(Trie)进行管理。

基础的红点系统由以下三件套组成,可以很方便的转化为其他语言版本,或者移植到其他项目进行使用。

  • RedPointNode:作为基础的红点数据结构,保存数据
  • RedPointTree:红点树,用于组织管理红点数据
  • RedPointSystem:封装接口,供外部调用,并负责通过事件完成和其他系统的逻辑交互

三、代码实现

1、RedPointNode

因为红点结构的变量定义和函数功能比较简单,除了基本的变量定义,还需要有数量改变、回调触发以及通知父节点三处逻辑,这里直接贴完整的代码。

import { BaseClass } from "../BaseClass";

export class RedPointNode extends BaseClass {
    public node_path: string;   //完整的红点路径
    public node_name: string;   //当前层级的节点名称
    public point_num: number;   //红点数量
    public state: boolean;      //红点状态
    public parent_node: RedPointNode;   //父节点
    public child_node_dic;  //子节点
    private notify_event;   //红点状态改变触发的函数,由RedPointSystem传入,内置统一的回调逻辑

    //构造函数
    public constructor(node_path: string, node_name: string, parent_node: RedPointNode, notify_event){
        super();
        this.node_path = node_path;
        this.node_name = node_name;
        this.point_num = 0;
        this.state = false;
        this.parent_node = parent_node;
        this.child_node_dic = {};
        this.notify_event = notify_event;
    }

    //设置红点数量
    public SetRedPointNum(num: number){
        this.point_num = num;
        let new_state = this.point_num > 0;
        if(this.state != new_state){
            this.state = new_state;
            this.NotifyPointNumChange();
        }
        if(this.parent_node){
            this.parent_node.ChangePredPointNum();
        }
    }

    //通知红点数量变更
    private NotifyPointNumChange(){
        if(this.node_name == "Main") return;   //根节点不触发事件

        if(this.notify_event){
            this.notify_event(this.node_path, this.state);
        }
    }

    //更新父节点红点数量
    public ChangePredPointNum(){
        let num = 0;
        for(let key in this.child_node_dic){
            num = num + this.child_node_dic[key].point_num;
        }
        if(num != this.point_num){
            this.SetRedPointNum(num);
        }
    }
}

2、RedPointTree

首先进行红点树的初始化

    //初始化
    public constructor(notify_event){
        super();
        this.notify_event = notify_event;
        this.node_dic = {};	//这里缓存的是所有叶子节点,方便获取红点信息,避免每次因为查找而导致的字符串切分

        this.root_node = new RedPointNode("Main", "Main", null, this.notify_event);	//将"Main"作为根节点
    }

红点树需要对红点进行层级管理,因此需要有注册红点逻辑,也是最核心的部分,具体是通过指定的分隔符(这里我用的是 “_”)来切分红点路径,然后逐层查找并形成父子关系,以此来构造红点树。

    //注册红点
    public RegisterNode(node_path){
        let register_str = "";
        let node = this.root_node;
        let node_array = node_path.split("_");
        if(this.node_dic[node_path]){
            register_str = "节点已注册";
        }else if(node_array.length < 1 || node_array[0] != this.root_node.node_name){
            register_str = "节点格式错误";	//正确示例,坐骑-强化:"Main_Horse_Strength"
        }else{
            let full_name = node_array[0];
            for(let i = 1; i < node_array.length; i++){
                full_name = full_name + "_" + node_array[i];
                if(!node.child_node_dic[node_array[i]]){
                    node.child_node_dic[node_array[i]] = new RedPointNode(full_name, node_array[i], node, this.notify_event);
                    this.node_dic[full_name] = node.child_node_dic[node_array[i]];
                }
                node = node.child_node_dic[node_array[i]];
            }
        }
        return register_str;
    }

除了注册逻辑,还有销毁逻辑、获取红点信息、以及调试使用的红点树打印等内容,代码比较容易理解,大家可以查看完整代码。

3、RedPointSystem

红点系统的责任是封装好接口供外部调用,比如注册红点、红点信息获取等等;其次是通过事件监测,响应其他功能条件的变化,来更新红点的数量和状态。

同样的,先进行初始化

    //默认红点状态变化的回调函数
    public static DefaultNotifyChange(node_path, state){
        console.log("打印-触发红点更新事件:", node_path, state);
        RedPointSystem.GetInstance().Fire(node_path, state);
    }

    //红点系统初始化方法
    public Init(){
        this.red_point_tree = new RedPointTree(RedPointSystem.DefaultNotifyChange);
        this.subject_dic = {};	//缓存红点的判断条件列表

        this.BindEvent();
    }

因为注册红点时我们会将判断条件也一并注册,所以在上述代码中使用 subject_dic 来缓存条件,当对应的条件(诸如等级、奖励状态)发生变化时,通过事件进行触发判断,然后将判断结果,也就是红点状态写入到红点树中。

先对比较常用的条件做一个定义,这样就不用自己手动去触发红点更新逻辑了

export enum RedConditionDef {
    CustomCheck = "CustomCheck",	//自定义判断,可以自行传入判断函数和参数,需功能模块在相关条件发生变化的时候自行触发
    GoodsNumTypeID = "GoodsNumTypeID",      //指定物品的数量变化,发生变化时由物品模块自动触发
    ActReward = "ActReward",	//活动奖励领取状态变化,发生变化时由通用活动模块自动触发
}

下面是红点注册逻辑和对应的示例:

    /*
        举例:
        	let node_path = "Main_Horse_Strength";
            let condition_list = 
            {
            	//ref代表对应的模块,将对应的函数以及参数传入即可,在条件变更时需要手动触发
                [RedConditionDef.CustemCheck]: {ref: DeityModel.getInstance(), check_red_func = "CheckGoodsChange", args: {}},
                
                [RedConditionDef.GoodsNumID]: {good_id: good_id, value = 0},
                
                //项目中的奖励是按照活动主类型->活动子类型->奖励档位来做区分的
                [RedConditionDef.ActReward]: {base_type: base_type, sub_type: sub_type, grade: grade},
            }
            //这样就会将三个条件注册进去,只有三个条件同时满足了,才会将红点状态设置为true
            RedPointSystem.GetInstance().RegisterSubjectAndCheck(node_path, condition_list);
    */ 

	//红点注册方法(内部方法)
    private RegisterSubject(node_path, condition_list){
        let register_str = this.red_point_tree.RegisterNode(node_path);
        if(register_str != ""){
            console.log(register_str);
            return false;
        }
        if(!this.red_point_tree.IsLeafNode(node_path)){
            console.log("只能注册叶子节点:" + node_path);
            return false;
        }

        this.UnRegisterSubject(node_path);	

        this.subject_dic[node_path] = {	//缓存条件列表
            node_path: node_path,
            condition_list: condition_list,
            is_all_reach: false
        }

        //这里将条件分类型存放,方便进行遍历判断,比如物品数量变化时,只需要将物品数量的条件列表遍历判断即可
        let list;
        let condition_result;
        for(let key in condition_list){
            condition_list[key].is_reach = false;
            condition_result = this.GetConditionList(key);
            list = condition_result[0];
            list.push(node_path);
        }
        return true;
    }

    //注册红点节点变化条件,并做一次节点红点初始化状态检查(仅限于叶子节点)(供外部调用)
    public RegisterSubjectAndCheck(node_path, condition_list){
        let rt = this.RegisterSubject(node_path, condition_list);
        if(rt){
            let subject = this.subject_dic[node_path];
            let func;
            let condition;
            for(let condition_def in subject.condition_list){
                func = this.GetConditionFunc(condition_def);
                if(func){
                    if(condition_def == RedConditionDef.ActReward){
                        condition = subject.condition_list[condition_def];
                        func(this, subject, condition_def, condition.base_type, condition.sub_type, condition.grade);
                    }else{
                        func(this, subject, condition_def);
                    }
                }
            }
            let state = this.GetRedPointState(node_path);
            if(subject.is_all_reach != state){
                this.SetRedPointState(node_path, subject.is_all_reach);
            }
        }
    }

注册完红点后,接下来就是条件变更所引起的判断逻辑了,先绑定对应的事件供外部触发,这里自定义条件 CustomCheck 是需要自行调用 InvokeFunc 函数触发的,所以不需要绑定事件。

    public BindEvent(){
        let onGoodsChange = (type_id, num) => {
            this.InvokeFunc(RedConditionDef.GoodsNumTypeID, type_id, num);
        }
        //物品数量变更,由GoodsModel触发
        this.goods_change_event_id = GoodsModel.GetInstance().Bind(GoodsModel.UPDATE_GOODS_NUM, onGoodsChange);

        let onRewardChange = (base_type, sub_type, grade) => {
            this.InvokeFunc(RedConditionDef.ActReward, base_type, sub_type, grade);
        }
        //奖励状态变更,由通用活动模块ActivityModel触发
        this.reward_change_event_id = ActivityModel.GetInstance().Bind(ActivityModel.UPDATE_ACT_REWARD, onRewardChange);
    }

实现不同条件和不同判断函数的映射关系,比如上述定义物品数量条件为 GoodsNumTypeID = “GoodsNumTypeID”,则对应的判断函数名称为 GoodsNumTypeIDChange,这里不加Change也行,看个人代码风格哈哈。

    //触发对应类型的所有条件进行判断更新
    public InvokeFunc(condition_def, ...params){
        let condition_result = this.GetConditionList(condition_def);
        let list = condition_result[0];
        let func = this.GetConditionFunc(condition_def);
        if(list && list.length > 0 && func){
            let subject;
            for(let key in list){
                subject = this.subject_dic[list[key]];
                if(subject && subject.condition_list[condition_def]){
                    func(this, subject, condition_def, ...params);
                }
            }
        }
    }

    //获取对应类型的条件列表
    public GetConditionList(condition_def){
        let list_index = condition_def + "List";
        this[list_index] = this[list_index] ?? [];
        return [this[list_index], list_index];
    }

    //获取对应类型条件的函数判断
    public GetConditionFunc(condition_def){
        let func_index = condition_def + "Change";
        return this[func_index];
    }

做完映射之后,就可以实现具体的判断函数了,这里以物品数量判断为例,其余的可参考完整代码。

    public GoodsNumTypeIDChange(red_point_system, subject, condition_def, type_id, num){
        type_id = type_id ?? subject.condition_list[condition_def].type_id;
        if(subject.condition_list[condition_def].type_id == type_id){	//如果发生数量变更的物品和注册的物品一致,则进行判断,做一层筛选,减少运算,对于频繁变更的条件非常有用
            num = GoodsModel.GetInstance().getGoodsCntByMaterials(type_id); //获取物品数量
            let is_reach;
            if(num >= subject.condition_list[condition_def].value){
                is_reach =  true;
            }else{
                is_reach = false;
            }
          	//获取到最新的结果后,如果和保存的不一致,则触发更新
            if(subject.condition_list[condition_def].is_reach != is_reach){
                subject.condition_list[condition_def].is_reach = is_reach;
                red_point_system.CheckSubjectReach(subject);
            }
        }
    }

    //判断所有的条件汇总状态是否发生变化,如果发生变化,就可以通知红点树干活了
    public CheckSubjectReach(subject){
        let is_all_reach = true;
        let item;
        for(let key in subject.condition_list){
            item = subject.condition_list[key];
            if(!item.is_reach){
                is_all_reach = false;
                break;
            }
        }

        if(subject.is_all_reach != is_all_reach){
            subject.is_all_reach = is_all_reach;
            this.SetRedPointState(subject.node_path, is_all_reach);
        }
    }

四、总结

以上就是一套基础的红点系统,实现了红点注册、层级管理、条件判断,大家可以根据项目需要自行添加通用的条件预设,减少手动触发。接下来就是红点的UI表现、红点路径的使用规范以及一些优化方面的内容,下一篇文章进行详细说明。

五、完整代码

1、RedPointTree

import { BaseClass } from "../BaseClass";
import { Split, Util } from "../Util";
import { RedPointNode } from "./RedPointNode";

export class RedPointTree extends BaseClass {
    private root_node;
    private notify_event;
    private node_dic;

    //初始化
    public constructor(notify_event){
        super();
        this.notify_event = notify_event;
        this.node_dic = {};

        this.root_node = new RedPointNode("Main", "Main", null, this.notify_event);
    }

    //红点树销毁
    public DeleteMe(){
        this.node_dic = null;
        this.root_node = null;
    }

    //注册红点
    public RegisterNode(node_path){
        let register_str = "";
        let node = this.root_node;
        let node_array = node_path.split("_");
        if(this.node_dic[node_path]){
            register_str = "节点已注册";
        }else if(node_array.length < 1 || node_array[0] != this.root_node.node_name){
            register_str = "节点格式错误";
        }else{
            let full_name = node_array[0];
            for(let i = 1; i < node_array.length; i++){
                full_name = full_name + "_" + node_array[i];
                if(!node.child_node_dic[node_array[i]]){
                    node.child_node_dic[node_array[i]] = new RedPointNode(full_name, node_array[i], node, this.notify_event);
                    this.node_dic[full_name] = node.child_node_dic[node_array[i]];
                }
                node = node.child_node_dic[node_array[i]];
            }
        }
        return register_str;
    }

    //注销红点
    public UnRegisterNode(node_path){
        let node = this.GetNode(node_path);
        let parent = node.parent_node;
        if(parent){
            parent.child_node_dic[node.node_name] = null;
        }

        if(this.node_dic[node_path]){
            this.node_dic[node_path] = null;
        }
    }

    //获取红点
    public GetNode(node_path){
        if(this.node_dic[node_path]){
            return this.node_dic[node_path];
        }
    }

    //设置红点数量
    public SetRedPointNum(node_path, value){
        let node = this.GetNode(node_path);
        if(!node){
            return;
        }

        if(Util.TableSize(node.child_node_dic, true) > 0){
            console.log("只有叶子节点才能设置红点数量");
            return;
        }
        node.SetRedPointNum(value);
    }

    //获取红点状态
    public GetRedPointState(node_path){
        let bool = false;
        let point_num = 0;
        let node = this.GetNode(node_path);
        if(node){
            bool = node.state;
            point_num = node.point_num;
        }
        return [bool, point_num];
    }

    //判断是否为叶子节点
    public IsLeafNode(node_path){
        let node = this.GetNode(node_path);
        if(!node){
            return false;
        }
        if(Util.TableSize(node.child_node_dic, true) > 0){
            return false;
        }
        return true;
    }

    //打印红点树
    public ToString(){
        let print_node = (node, level) => {
            let indent_str = "";
            for(let i = 0; i < level - 1; i++){
                indent_str = indent_str + "	";
            }
            if(Util.TableSize(node.child_node_dic, true) > 0){
                let item_str = `${indent_str}${node.node_name} = ${node.point_num}`;
                console.log(item_str);
                console.log(indent_str + "{");
                for(let key in node.child_node_dic){
                    print_node(node.child_node_dic[key], level + 1);
                }
                console.log(indent_str + "}");
            }else{
                let item_str = `${indent_str}${node.node_name} = ${node.point_num}`;
                console.log(item_str);
            }
        }
        console.log("红点树数据:", Util.TableSize(this.node_dic, true));
        print_node(this.root_node, 1);
    }
}

2、RedPointSystem

import { ActivityModel } from "../../commonModel/ActivityModel";
import { GoodsModel } from "../../commonModel/GoodsModel";
import { RoleManager } from "../../commonModel/RoleManager";
import { ActivityUtil } from "../ActivityUtil";
import { EventDispatcher } from "../EventDispatcher";
import { EventName } from "../EventName";
import { RedPointTree } from "./RedPointTree";

export enum RedConditionDef {
    CustomCheck = "CustomCheck",	//自定义判断,可以自行传入判断函数和参数,需功能模块在相关条件发生变化的时候自行触发
    GoodsNumTypeID = "GoodsNumTypeID",      //指定物品的数量变化,发生变化时由物品模块自动触发
    ActReward = "ActReward",	//活动奖励领取状态变化,发生变化时由通用活动模块自动触发
}

    /*
        举例:
        	let node_path = "Main_Horse_Strength";
            let condition_list = 
            {
            	//ref代表对应的模块,将对应的函数以及参数传入即可,在条件变更时需要手动触发
                [RedConditionDef.CustemCheck]: {ref: DeityModel.getInstance(), check_red_func = "CheckGoodsChange", args: {}},
                
                [RedConditionDef.GoodsNumID]: {good_id: good_id, value = 0},
                
                //项目中的奖励是按照活动主类型->活动子类型->奖励档位来做区分的
                [RedConditionDef.ActReward]: {base_type: base_type, sub_type: sub_type, grade: grade},
            }
            //这样就会将三个条件注册进去,只有三个条件同时满足了,才会将红点状态设置为true
            RedPointSystem.GetInstance().RegisterSubjectAndCheck(node_path, condition_list);
    */ 

export class RedPointSystem extends EventDispatcher {   

    private static Instance: RedPointSystem;
    red_point_tree: RedPointTree;
    subject_dic: {};
    goods_change_event_id: number;
    level_change_event_id: number;
    reward_change_event_id: number;
    public constructor(){
        super();
    }

    public DeleteMe(){

    }

    public static GetInstance() {
        if (!RedPointSystem.Instance) {
            RedPointSystem.Instance = new RedPointSystem()
        }
        return RedPointSystem.Instance
    }

 

    //销毁红点系统方法
    public Dispose(){
        if(this.red_point_tree){
            this.red_point_tree.DeleteMe();
            this.red_point_tree = null;
        }
        this.subject_dic = null;
        for(let key in RedConditionDef){
            let condition_result = this.GetConditionList(RedConditionDef[key]);
            this[condition_result[1]] = null;
        }
        this.UnBindEvent();
        this.UnBindAll();
    }

	//红点注册方法(内部方法)
    public RegisterSubject(node_path, condition_list){
        let register_str = this.red_point_tree.RegisterNode(node_path);
        if(register_str != ""){
            console.log(register_str);
            return false;
        }
        if(!this.red_point_tree.IsLeafNode(node_path)){
            console.log("只能注册叶子节点:" + node_path);
            return false;
        }

        this.UnRegisterSubject(node_path);  //注册前先执行销毁逻辑,清除旧的条件列表

        this.subject_dic[node_path] = { //缓存红点的条件列表
            node_path: node_path,
            condition_list: condition_list,
            is_all_reach: false
        }

        //这里将条件分类型存放,方便进行遍历判断,比如物品数量变化时,只需要将物品数量的条件列表遍历判断即可
        let list;
        let condition_result;
        for(let key in condition_list){
            condition_list[key].is_reach = false;
            condition_result = this.GetConditionList(key);
            list = condition_result[0];
            list.push(node_path);
        }
        return true;
    }

    //注册红点节点变化条件,并做一次节点红点初始化状态检查(仅限于叶子节点)(供外部调用)
    public RegisterSubjectAndCheck(node_path, condition_list){
        let rt = this.RegisterSubject(node_path, condition_list);
        if(rt){
            let subject = this.subject_dic[node_path];
            let func;
            let condition;
            for(let condition_def in subject.condition_list){
                func = this.GetConditionFunc(condition_def);
                if(func){
                    if(condition_def == RedConditionDef.ActReward){
                        condition = subject.condition_list[condition_def];
                        func(this, subject, condition_def, condition.base_type, condition.sub_type, condition.grade);
                    }else{
                        func(this, subject, condition_def);
                    }
                }
            }
            let state = this.GetRedPointState(node_path);
            if(subject.is_all_reach != state){
                this.SetRedPointState(node_path, subject.is_all_reach);
            }
        }
    }

    //注销红点
    public UnRegisterSubject(node_path){
        let subject = this.subject_dic[node_path];
        if(subject){
            this.subject_dic[node_path] = null;

            let list;
            let remove_index;
            let condition_result;
            for(let key in subject.condition_list){
                condition_result = this.GetConditionList(key);
                list = condition_result[0];
                for(let i in list){
                    if(node_path == list[i]){
                        remove_index = i;
                    }
                }
                if(remove_index){
                    list.splice(remove_index, 1);
                    remove_index = null;
                }
            }
            this.red_point_tree.UnRegisterNode(node_path);
        }
    }

    //设置红点数量
    public SetRedPointNum(node_path, value){
        this.red_point_tree.SetRedPointNum(node_path, value);
    }

    //设置红点状态
    public SetRedPointState(node_path, bool){
        if(bool){
            this.SetRedPointNum(node_path, 1);
        }else{
            this.SetRedPointNum(node_path, 0);
        }
    }

    //获取红点状态
    public GetRedPointState(node_path){
        let red_result = this.red_point_tree.GetRedPointState(node_path);
        return Boolean(red_result[0]);
    }

    //获取红点数量
    public GetRedPointNum(node_path){
        let red_result = this.red_point_tree.GetRedPointState(node_path);
        return Number(red_result[1]);
    }

    //打印红点树
    public RedTreeToString(){
        this.red_point_tree.ToString();
    }

    //打印所有叶子节点的条件列表
    public ConditionListToString(){
        console.log("红点树条件列表:")
        console.log(this.subject_dic);
    }

    //触发对应条件进行更新
    public InvokeCondition(node_path, condition_def, ...params){
        let subject = this.subject_dic[node_path];
        if(subject){
            if(subject.condition_list[condition_def]){
                let func = this.GetConditionFunc(condition_def);
                if(func){
                    func(this, subject, condition_def, ...params);
                }
            }
        }
    }

    //触发对应类型的所有条件进行判断更新
    public InvokeFunc(condition_def, ...params){
        let condition_result = this.GetConditionList(condition_def);
        let list = condition_result[0];
        let func = this.GetConditionFunc(condition_def);
        if(list && list.length > 0 && func){
            let subject;
            for(let key in list){
                subject = this.subject_dic[list[key]];
                if(subject && subject.condition_list[condition_def]){
                    func(this, subject, condition_def, ...params);
                }
            }
        }
    }

    //获取对应类型的条件列表
    public GetConditionList(condition_def){
        let list_index = condition_def + "List";
        this[list_index] = this[list_index] ?? [];
        return [this[list_index], list_index];
    }

    //获取对应类型条件的函数判断
    public GetConditionFunc(condition_def){
        let func_index = condition_def + "Change";
        return this[func_index];
    }

    //判断所有的条件汇总状态是否发生变化
    public CheckSubjectReach(subject){
        let is_all_reach = true;
        let item;
        for(let key in subject.condition_list){
            item = subject.condition_list[key];
            if(!item.is_reach){
                is_all_reach = false;
                break;
            }
        }

        if(subject.is_all_reach != is_all_reach){
            subject.is_all_reach = is_all_reach;
            this.SetRedPointState(subject.node_path, is_all_reach);
        }
    }

    /*      ↓处理事件引起的条件改变↓      */
    public BindEvent(){
        let onGoodsChange = (type_id, num) => {
            this.InvokeFunc(RedConditionDef.GoodsNumTypeID, type_id, num);
        }
        this.goods_change_event_id = GoodsModel.GetInstance().Bind(GoodsModel.UPDATE_GOODS_NUM, onGoodsChange);

        let onRewardChange = (base_type, sub_type, grade) => {
            this.InvokeFunc(RedConditionDef.ActReward, base_type, sub_type, grade);
        }
        this.reward_change_event_id = ActivityModel.GetInstance().Bind(ActivityModel.UPDATE_ACT_REWARD, onRewardChange);
    }
    

    public UnBindEvent(){
        if(this.level_change_event_id){
            RoleManager.Instance.mainRoleInfo.UnBind(this.level_change_event_id);
        }

        if(this.goods_change_event_id){
            GoodsModel.GetInstance().UnBind(this.goods_change_event_id);
        }

        if(this.reward_change_event_id){
            ActivityModel.GetInstance().UnBind(this.reward_change_event_id);
        }
    }

    public CustomCheckChange(red_point_system, subject, condition_def, ...params){
        let is_reach = false;
        let ref = subject.condition_list[condition_def].ref;
        let check_red_func = subject.condition_list[condition_def].check_red_func;
        let args = subject.condition_list[condition_def].args;
        if(ref && check_red_func){
            is_reach = ref[check_red_func](args);
        }

        if(subject.condition_list[condition_def].is_reach != is_reach){
            subject.condition_list[condition_def].is_reach = is_reach;
            red_point_system.CheckSubjectReach(subject);
        }
    }

    public MainRoleLevelChange(red_point_system, subject, condition_def){
        let lv = RoleManager.Instance.mainRoleInfo.level;
        let is_reach;
        if(lv >= subject.condition_list[condition_def].value){
            is_reach = true;
        }else{
            is_reach = false;
        }
        if(subject.condition_list[condition_def].is_reach != is_reach){
            subject.condition_list[condition_def].is_reach = is_reach;
            red_point_system.CheckSubjectReach(subject);
        }
    }

    public GoodsNumTypeIDChange(red_point_system, subject, condition_def, type_id, num){
        type_id = type_id ?? subject.condition_list[condition_def].type_id;
        if(subject.condition_list[condition_def].type_id == type_id){	//如果发生数量变更的物品和注册的物品一致,则进行判断,做一层筛选,减少运算,对于频繁变更的条件非常有用
            num = GoodsModel.GetInstance().getGoodsCntByMaterials(type_id); //获取物品数量
            let is_reach;
            if(num >= subject.condition_list[condition_def].value){
                is_reach =  true;
            }else{
                is_reach = false;
            }
          	//获取到最新的结果后,如果和保存的不一致,则触发更新
            if(subject.condition_list[condition_def].is_reach != is_reach){
                subject.condition_list[condition_def].is_reach = is_reach;
                red_point_system.CheckSubjectReach(subject);
            }
        }
    }

    /* 
        通用奖励领取状态变更时触发此函数
        如果在注册条件中配置了check_red_func, 则按照自定义逻辑进行判断;
        如果没有配置check_red_func, 则按照通用的奖励状态来进行判断;
    */
    public ActRewardChange(red_point_system, subject, condition_def, base_type, sub_type, grade?){
        if(subject.condition_list[condition_def].base_type == base_type && subject.condition_list[condition_def].sub_type == sub_type){
            let condition = subject.condition_list[condition_def];
            if(!grade || !condition.grade || condition.grade == grade){
                let check_red_func = condition.check_red_func;
                let is_reach = false;
                if(check_red_func){
                    let ref = condition.ref;
                    let args = condition.args;
                    if(ref){
                        is_reach = ref[check_red_func](args);
                    }
                }else{
                    is_reach = ActivityUtil.CheckActRewardIsRed(condition.base_type, condition.sub_type, condition.grade);
                }
                if(condition.is_reach != is_reach){
                    condition.is_reach = is_reach;
                    red_point_system.CheckSubjectReach(subject);
                }
            }
        }
    }
    /*      ↑处理事件引起的条件改变↑      */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值