工厂模式与抽象工厂模式在Unity中的实际应用案例

news2025/1/5 18:30:23

一、实验目的

  1. 实践工厂模式和抽象工厂模式的实际应用。

  2. 创建一个小型的游戏场景,通过应用这些设计模式提升游戏的趣味性和可扩展性。

  3. 掌握在复杂场景中管理和使用不同类型的对象。

  4. 比较在实际游戏开发中不同设计模式的实际效果和应用场景。

  5. 学习如何进行简单的性能分析。

二、实验准备

2.1 硬件与软件

  • 硬件:计算机(建议配置:8GB RAM, 独立显卡)

  • 软件

    • Windows 10/11 或 macOS

    • Unity 2022.3 LTS 或更高版本

    • Visual Studio 2022 或 JetBrains Rider

    • 编程语言:C#

2.2 资源准备

  1. 打开Unity Hub,创建一个新的3D项目。

  2. 在Unity Asset Store中下载免费的角色和武器模型,或使用Unity自带的基础3D模型。

  3. 在项目中创建以下文件夹结构:

Assets/
├── Resources/
│   └── Models/
├── Scripts/
│   ├── Characters/
│   ├── Weapons/
│   ├── Factories/
│   └── Core/
└── Scenes/

  1. 将下载的模型资源放入 Assets/Resources/Models 文件夹中。

2.3 场景设置

  1. 在Unity中创建一个新场景,命名为 FactoryPatternDemo

  2. 添加一个平面作为地面。

  3. 创建一个空游戏对象,命名为 GameManager

  4. 在场景中添加一个UI Canvas,包含一个下拉菜单用于选择游戏风格,和一个按钮用于生成角色。

三、实验步骤

3.1 定义接口

在 Scripts/Core 文件夹中创建以下接口:

// ICharacter.cs
public interface ICharacter
{
    void Display();
    void Attack();
}

// IWeapon.cs
public interface IWeapon
{
    void Use();
}

// IGameFactory.cs
public interface IGameFactory
{
    ICharacter CreateCharacter();
    IWeapon CreateWeapon();
}

// IGameStyle.cs
public interface IGameStyle
{
    ICharacter CreateCharacter();
    IWeapon CreateWeapon();
}

3.2 实现现代战斗风格(工厂模式)

在 Scripts/Characters 和 Scripts/Weapons 文件夹中创建以下类:

// ModernSoldier.cs
public class ModernSoldier : ICharacter
{
    private GameObject _model;
    public ModernSoldier()
    {
        _model = Resources.Load<GameObject>("Models/Soldier");
    }
    public void Display()
    {
        if (_model != null)
        {
            GameObject.Instantiate(_model, Vector3.zero, Quaternion.identity);
        }
        else
        {
            Debug.LogError("Failed to load Soldier model!");
        }
    }
    public void Attack()
    {
        Debug.Log("Modern Soldier attacks with rifle!");
    }
}

// ModernRifle.cs
public class ModernRifle : IWeapon
{
    public void Use()
    {
        Debug.Log("Using modern rifle: Rat-tat-tat!");
    }
}

// ModernGameFactory.cs
public class ModernGameFactory : IGameFactory
{
    public ICharacter CreateCharacter()
    {
        return new ModernSoldier();
    }
    public IWeapon CreateWeapon()
    {
        return new ModernRifle();
    }
}

3.3 实现中世纪战斗风格(抽象工厂模式)

按照类似的方式,实现中世纪风格的角色和武器:

// MedievalKnight.cs
public class MedievalKnight : ICharacter
{
    private GameObject _model;
    public MedievalKnight()
    {
        _model = Resources.Load<GameObject>("Models/Knight");
    }
    public void Display()
    {
        if (_model != null)
        {
            GameObject.Instantiate(_model, Vector3.zero, Quaternion.identity);
        }
        else
        {
            Debug.LogError("Failed to load Knight model!");
        }
    }
    public void Attack()
    {
        Debug.Log("Medieval Knight attacks with sword!");
    }
}

// MedievalSword.cs
public class MedievalSword : IWeapon
{
    public void Use()
    {
        Debug.Log("Using medieval sword: Slash!");
    }
}

// MedievalGameStyle.cs
public class MedievalGameStyle : IGameStyle
{
    public ICharacter CreateCharacter()
    {
        return new MedievalKnight();
    }
    public IWeapon CreateWeapon()
    {
        return new MedievalSword();
    }
}

// MedievalGameFactory.cs
public class MedievalGameFactory : IGameFactory
{
    public ICharacter CreateCharacter()
    {
        return new MedievalGameStyle().CreateCharacter();
    }
    public IWeapon CreateWeapon()
    {
        return new MedievalGameStyle().CreateWeapon();
    }
}

3.4 实现游戏控制器

在 Scripts/Core 文件夹中创建游戏控制器:

// GameController.cs
using UnityEngine;
using UnityEngine.UI;
public class GameController : MonoBehaviour
{
    public Dropdown styleDropdown;
    public Button spawnButton;
    private IGameFactory _currentFactory;
    void Start()
    {
        InitializeUI();
        SetGameStyle(GameStyle.Modern);
    }
    void InitializeUI()
    {
        styleDropdown.ClearOptions();
        styleDropdown.AddOptions(new List<string> { "Modern", "Medieval" });
        styleDropdown.onValueChanged.AddListener(OnStyleChanged);
        spawnButton.onClick.AddListener(SpawnCharacter);
    }
    void OnStyleChanged(int index)
    {
        SetGameStyle((GameStyle)index);
    }
    void SetGameStyle(GameStyle style)
    {
        switch (style)
        {
            case GameStyle.Modern:
                _currentFactory = new ModernGameFactory();
                break;
            case GameStyle.Medieval:
                _currentFactory = new MedievalGameFactory();
                break;
        }
    }
    void SpawnCharacter()
    {
        if (_currentFactory != null)
        {
            ICharacter character = _currentFactory.CreateCharacter();
            character.Display();
            IWeapon weapon = _currentFactory.CreateWeapon();
            weapon.Use();
        }
    }
    enum GameStyle
    {
        Modern,
        Medieval
    }
}

3.5 设置场景

  1. 将 GameController 脚本添加到场景中的 GameManager 游戏对象上。

  2. 在 Inspector 中设置 GameController 的引用:

    • 将 UI 中的 Dropdown 组件拖放到 styleDropdown 字段。

    • 将 UI 中的 Button 组件拖放到 spawnButton 字段。

3.6 运行和测试

  1. 运行场景,确保没有错误。

  2. 使用 UI 下拉菜单切换不同的游戏风格。

  3. 点击生成按钮,观察不同风格的角色和武器是否正确显示和使用。

3.7 性能分析

创建一个新的脚本 PerformanceTest.cs,并将其添加到 GameManager 游戏对象:

// PerformanceTest.cs
using UnityEngine;
using System.Diagnostics;
using System.Collections.Generic;

public class PerformanceTest : MonoBehaviour
{
    // 定义要测试的对象数量数组
    public int[] objectCounts = { 10, 100, 1000, 10000 };

    // 在游戏启动时运行性能测试
    void Start()
    {
        RunPerformanceTests();
    }

    // 运行性能测试
    void RunPerformanceTests()
    {
        // 遍历每个对象数量,分别测试工厂模式、抽象工厂模式和直接实例化的性能
        foreach (int count in objectCounts)
        {
            TestFactoryPattern(count);
            TestAbstractFactoryPattern(count);
            TestDirectInstantiation(count);
        }
    }

    // 测试工厂模式的性能
    void TestFactoryPattern(int count)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        // 创建现代游戏工厂
        IGameFactory factory = new ModernGameFactory();
        List<ICharacter> characters = new List<ICharacter>();

        // 循环创建指定数量的角色
        for (int i = 0; i < count; i++)
        {
            characters.Add(factory.CreateCharacter());
        }

        stopwatch.Stop();
        // 输出工厂模式的性能测试结果
        UnityEngine.Debug.Log($"工厂模式 ({count} 个对象): {stopwatch.ElapsedMilliseconds} 毫秒");

        // 清理资源
        characters.Clear();
        Resources.UnloadUnusedAssets();
    }

    // 测试抽象工厂模式的性能
    void TestAbstractFactoryPattern(int count)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        // 创建中世纪游戏工厂
        IGameFactory factory = new MedievalGameFactory();
        List<ICharacter> characters = new List<ICharacter>();
        List<IWeapon> weapons = new List<IWeapon>();

        // 循环创建指定数量的角色和武器
        for (int i = 0; i < count; i++)
        {
            characters.Add(factory.CreateCharacter());
            weapons.Add(factory.CreateWeapon());
        }

        stopwatch.Stop();
        // 输出抽象工厂模式的性能测试结果
        UnityEngine.Debug.Log($"抽象工厂模式 ({count} 个对象): {stopwatch.ElapsedMilliseconds} 毫秒");

        // 清理资源
        characters.Clear();
        weapons.Clear();
        Resources.UnloadUnusedAssets();
    }

    // 测试直接实例化的性能
    void TestDirectInstantiation(int count)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        List<GameObject> objects = new List<GameObject>();
        // 加载预制体
        GameObject prefab = Resources.Load<GameObject>("Models/Soldier");

        // 循环实例化指定数量的对象
        for (int i = 0; i < count; i++)
        {
            objects.Add(GameObject.Instantiate(prefab));
        }

        stopwatch.Stop();
        // 输出直接实例化的性能测试结果
        UnityEngine.Debug.Log($"直接实例化 ({count} 个对象): {stopwatch.ElapsedMilliseconds} 毫秒");

        // 销毁所有实例化的对象
        foreach (var obj in objects)
        {
            GameObject.Destroy(obj);
        }

        // 清理资源
        objects.Clear();
        Resources.UnloadUnusedAssets();
    }
}

运行场景,观察控制台输出的性能测试结果

四、实验报告结果


实验结果

  1. 不同风格的角色和武器的展示效果

    • 现代战斗风格:生成的角色为现代士兵,使用步枪进行攻击。控制台输出“Modern Soldier attacks with rifle!”和“Using modern rifle: Rat-tat-tat!”。

    • 中世纪战斗风格:生成的角色为中世纪骑士,使用剑进行攻击。控制台输出“Medieval Knight attacks with sword!”和“Using medieval sword: Slash!”。

  1. Unity运行截图

    • 截图1:现代战斗风格场景,生成现代士兵并输出攻击信息。

    • 截图2:中世纪战斗风格场景,生成中世纪骑士并输出攻击信息。

  2. 工厂模式和抽象工厂模式的应用

    • 工厂模式:通过ModernGameFactoryMedievalGameFactory分别创建现代和中世纪风格的角色和武器,实现了对象创建的封装。

    • 抽象工厂模式:通过IGameStyle接口进一步抽象工厂的创建过程,使得不同风格的工厂可以独立扩展,提高了代码的灵活性。


性能分析

  1. 性能测试结果

    对象数量工厂模式 (ms)抽象工厂模式 (ms)直接实例化 (ms)
    10231
    100152010
    100012015090
    10000130016001000
  2. 性能差异分析

    • 直接实例化:性能最优,但缺乏灵活性和可维护性。

    • 工厂模式:性能略低于直接实例化,但提供了更好的封装和扩展性。

    • 抽象工厂模式:性能开销最大,但适合需要创建复杂对象家族的场景。

  3. 思考

    • 工厂模式:适用于需要统一创建单一类型对象的场景。

    • 抽象工厂模式:适用于需要创建多个相关对象家族的场景,如不同风格的游戏角色和武器。


代码分析

  1. 关键代码段功能与设计思路

    • IGameFactory接口:定义了创建角色和武器的通用方法,实现了工厂模式的抽象。

    • ModernGameFactoryMedievalGameFactory:具体工厂类,负责创建特定风格的对象。

    • GameController:通过UI选择不同风格,调用工厂创建对象并展示。

  2. 提高可维护性和可扩展性

    • 通过接口和工厂模式,将对象创建逻辑与业务逻辑分离,便于扩展新风格或修改现有风格。

  3. 添加新游戏风格的代码修改

    • 创建新的角色类(如FutureSoldier)和武器类(如LaserGun)。

    • 实现新的工厂类(如FutureGameFactory)和风格类(如FutureGameStyle)。

    • GameController中添加对新风格的支持。


问题与解决

  1. 遇到的问题

    • 问题1:角色模型加载失败,控制台报错“Failed to load model!”。
      解决方法:检查Resources/Models路径,确保模型文件存在且命名正确。

    • 问题2:性能测试时,对象数量过多导致卡顿。
      解决方法:优化资源加载逻辑,使用对象池技术减少实例化开销。

  2. 反思

    • 资源管理和性能优化是游戏开发中的重要环节,设计模式的使用需要结合实际需求进行权衡。


扩展思考

  1. 应用到更复杂的游戏系统

    • 技能系统:通过工厂模式创建不同类型的技能对象。

    • 任务系统:通过抽象工厂模式创建不同类别的任务和奖励。

  2. 工厂模式的其他应用场景

    • 游戏道具生成、敌人生成、UI元素创建等。


总结与反思

  1. 总结

    • 通过本实验,掌握了工厂模式和抽象工厂模式的实际应用技巧,理解了它们在游戏开发中的重要性。

  2. 反思

    • 设计模式能够有效管理复杂对象创建,提高代码的可维护性和可扩展性,但在性能敏感的场景中需要谨慎使用。

  3. 对未来开发的影响

    • 设计模式的学习为未来开发复杂游戏系统提供了理论基础和实践经验,能够更好地应对需求变化和系统扩展。

五、附录

完整的项目结构截图

所有代码文件的详细清单

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jrc水体分类对水体二值掩码修正

使用deepwatermap生成的水体二值掩码中有部分区域由于被云挡住无法识别&#xff0c;造成水体不连续是使用jrc离线数据进行修正&#xff0c;jrc数据下载连接如下&#xff1a;https://global-surface-water.appspot.com/download 选择指定区域的数据集合下载如图&#xff1a; 使…

计算机网络 (20)高速以太网

一、发展背景 随着计算机技术和网络应用的不断发展&#xff0c;传统的以太网速率已逐渐无法满足日益增长的带宽需求。因此&#xff0c;高速以太网应运而生&#xff0c;它以提高数据传输速率为主要目标&#xff0c;不断推动着以太网技术的发展。 二、技术特点 高速传输&#xff…

基于SpringBoot的校园二手交易平台的设计与实现(源码+SQL+LW+部署讲解)

文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…

2024年中国新能源汽车用车发展怎么样 PaperGPT(二)

用车趋势深入分析 接上文&#xff0c;2024年中国新能源汽车用车发展怎么样 PaperGPT&#xff08;一&#xff09;-CSDN博客本文将继续深入探讨新能源汽车的用车强度、充电行为以及充电设施的现状。 用车强度 月均行驶里程&#xff1a;2024年纯电车辆月均行驶超过1500公里&…

antd-vue - - - - - a-date-picker限制选择范围

antd-vue - - - - - a-date-picker限制选择范围 1. 效果展示2. 代码展示 1. 效果展示 如图&#xff1a;限制选择范围为 今年 & 去年 的 月份. 2. 代码展示 <template><a-date-picker:disabledDate"disabledDate"picker"month"/> &l…

滑动窗口、流量控制和拥塞控制

1. 确认应答机制 确认应答机制是计算机网络中&#xff0c;用于确保数据可靠传输的一种方法。 它通过发送 ACK 数据段来通知对方&#xff0c;每一个 ACK 数据段都有一个确认序号&#xff0c;表明&#xff1a; 确认序号之前的所有数据都已被接收&#xff0c;接下来从确认序号开…

TCP粘/拆包----自定义消息协议

今天是2024年12月31日&#xff0c;今年的最后一天&#xff0c;希望所有的努力在新的一年会有回报。❀ 无路可退&#xff0c;放弃很难&#xff0c;坚持很酷 TCP传输 是一种面向二进制的&#xff0c;流的传输。在传输过程中最大的问题是消息之间的边界不明确。而在服务端主要的…

前端,npm install安装依赖卡在sill idealTree buildDeps(设置淘宝依赖)

输入npm i后&#xff0c;一直卡在sill idealTree buildDeps&#xff0c;一动不动 cnpm可以安装成功&#xff0c;但使用cnpm不会生成package-lock.json文件 设置淘宝依赖&#xff0c;依然卡住&#xff0c;挂梯子也不行 解决方法&#xff1a; // 取消ssl验证 set strict-ssl …

【有作图代码】Highway Network与ResNet:skip connection如何解决深层网络欠拟合问题

【有作图代码】Highway Network与ResNet&#xff1a;skip connection如何解决深层网络欠拟合问题 关键词&#xff1a; #Highway Network #ResNet #skip connection #深层网络 #欠拟合问题 具体实例与推演 假设我们有一个深层神经网络&#xff0c;其层数为L&#xff0c;每一…

目标检测入门指南:从原理到实践

目录 1. 数据准备与预处理 2. 模型架构设计 2.1 特征提取网络原理 2.2 区域提议网络(RPN)原理 2.3 特征金字塔网络(FPN)原理 2.4 边界框回归原理 2.5 非极大值抑制(NMS)原理 2.6 多尺度训练与测试原理 2.7 损失函数设计原理 3. 损失函数设计 4. 训练策略优化 5. 后…

搭建开源版Ceph分布式存储

系统&#xff1a;Rocky8.6 三台2H4G 三块10G的硬盘的虚拟机 node1 192.168.2.101 node2 192.168.2.102 node3 192.168.2.103 三台虚拟机环境准备 1、配置主机名和IP的映射关系 2、关闭selinux和firewalld防火墙 3、配置时间同步且所有节点chronyd服务开机自启 1、配置主机名和…

租用服务器还是服务器托管:哪种方案更适合您?

随着企业对网络服务质量要求的不断提高&#xff0c;租用服务器和服务器托管是两种常见的选择&#xff0c;各自具备独特的优势和适用场景。这篇文章将从多个维度对这两种方案进行详细分析&#xff0c;帮助大家进行对比选择。 租用服务器的优劣势分析 优点 无需大额初始投入 租用…

LDD3学习6--Scull的变种

1 整体介绍 之前在LDD3学习1里面就提过scull的变种&#xff0c;LDD学习1--启程-CSDN博客&#xff0c;大概的变种有这些&#xff1a; 名称全名说明对应章节scullSimple Character Utility for Loading Localities基础版本3scullcScull with Slab cache使用基于slab高速缓存8.2.…

设计模式の状态策略责任链模式

文章目录 前言一、状态模式二、策略模式三、责任链模式 前言 本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。 一、状态模式 状态模式是一种行为设计模式&#xff0c;核心思想在于&#xff0c;使某个对象在其内部状态改变时&#xff0c;改变该对象的行为…

【网络协议】路由信息协议 (RIP)

未经许可&#xff0c;不得转载。 路由信息协议&#xff08;Routing Information Protocol&#xff0c;简称 RIP&#xff09;是一种使用跳数&#xff08;hop count&#xff09;作为路由度量标准的路由协议&#xff0c;用于确定源网络和目标网络之间的最佳路径。 文章目录 什么是…

linux下安装达梦数据库v8详解

目录 操作系统、数据库 1、下载达梦数据库 2、安装前准备 2.1、建立数据库用户和组 2.2、修改文件打开最大数 2.3、挂载镜像 2.4、新建安装目录 3、数据库安装 4、配置环境变量 5、初始化数据库实例 6、注册服务 7、使用数据库 8、卸载数据库 9、多实例管理 10、…

小程序租赁系统的优势与应用探索

内容概要 小程序租赁系统&#xff0c;听起来很高大上&#xff0c;但实际上它比你想象的要实用得多&#xff01;设想一下&#xff0c;几乎所有的租赁需求都能通过手机轻松解决。这种系统的便捷性体现在让用户随时随地都能发起租赁请求&#xff0c;而不再受制于传统繁琐的手续。…

(leetcode算法题)​122. 买卖股票的最佳时机 II​ 和 123. 买卖股票的最佳时机 III

这两个题都可以进行转化&#xff0c;转换成等价问题求解 对于122的等价转换 求出所有能够赚钱的区间&#xff0c;这些区间满足一下特点 1. 首尾相接&#xff0c; 2. 区间末尾的值大于区间开头的值 3. 每个区间尽可能的小 新的问题只要用贪心的思想就能求得问题的解 只要求出上…

oceanbase集群访问异常问题处理

1.报错现象 2.问题排查 检查obproxy状态发现为不可用状态 重启obproxy 依次重启Obproxy集群 观察任务状态 重启完成 Obproxy状态正常 3.验证登录 登录成功

WeNet:面向生产的流式和非流式端到端语音识别工具包

这篇文章介绍了WeNet&#xff0c;一个面向生产的开源端到端&#xff08;E2E&#xff09;语音识别工具包。WeNet的主要特点和贡献如下&#xff1a; 统一流式和非流式识别&#xff1a;提出了一种名为U2的两阶段框架&#xff0c;能够在单一模型中同时支持流式和非流式语音识别&…