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

一、实验目的

  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. 对未来开发的影响

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

五、附录

完整的项目结构截图

所有代码文件的详细清单

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3+Echarts+ts实现甘特图

项目场景&#xff1a; vue3Echartsts实现甘特图;发布任务 代码实现 封装ganttEcharts.vue <template><!-- Echarts 甘特图 --><div ref"progressChart" class"w100 h100"></div> </template> <script lang"ts&qu…

[Linux]redis5.0.x升级至7.x完整操作流程

1. 从官网下载最新版redis&#xff1a; 官网地址&#xff1a;https://redis.io/download 注&#xff1a;下载需要的登录&#xff0c;如果选择使用github账号登录&#xff0c;那么需要提前在github账号中取消勾选“Keep my email addresses private”&#xff08;隐藏我的邮箱…

android 外挂modem模块实现Telephony相关功能(上网,发短信,打电话)

一.背景 当前模块不支持Telephony相关的功能,例如上网、发短信等功能,就需要外挂另一个模块实现此功能,这就是外挂modem模块实现Telephony功能,此篇主要就是说实现外挂modem模块功能中的Framework层实现逻辑,如下流程是在Android 13中实现的外挂pcie模块的流程 二.ril库相…

倍思氮化镓充电器分享:Super GaN伸缩线快充35W

快节奏的时代,在旅游、办公等场景下,一款高效、便捷的充电器可以让我们的生活更便捷、高效。今天就给大家推荐一款倍思氮化镓充电器——Super GaN伸缩线快充35W。它具备多重亮点,可以满足我们在许多场景下的充电需求,成为我们的得力助手。 倍思氮化镓Super GaN伸缩线快充35W的亮…

若依前后端分离项目部署(使用docker)

文章目录 一、搭建后端1.1 搭建流程&#xff1a;1.2 后端零件:1.2.1 mysql容器创建&#xff1a;1.2.2 redis容器创建&#xff1a;1.2.3 Dockerfile内容&#xff1a;1.2.4 构建项目镜像&#xff1a;1.2.5 创建后端容器&#xff1a; 二、前端搭建&#xff1a;2.1 搭建流程&#x…

STM32驱动NRF24L01

一、NRF24L01的相关介绍 1.2 引脚的介绍 关于SPI的引脚就不再说了&#xff0c;这里介绍其余的两个引脚&#xff1a; CE 模块控制引脚&#xff1a;芯片开启信号&#xff0c;激活RX或TX模式 IRQ 模块中断信号输出引脚&#xff1a;其低电平有效&#xff0c;也就是中断时变为低电平…

OneOS操作系统入门-驱动-03:I2C总线及驱动

一、I2C总线 1.1、I2C总线简介 IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的两线式串行总线&#xff0c;用于连接微控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线&#xff0c;可发送和接收数据&#xff0c;在 CPU 与被控 IC…

【可实战】Bug的判定标准、分类、优先级、定位方法、提交Bug(包含常见面试题)

一、Bug相关概念 &#xff08;一&#xff09;bug判定标准 &#xff08;二&#xff09;常见 Bug 分类 &#xff08;三&#xff09;bug优先级 1.bug严重程度与优先级的关系 有些很严重的Bug&#xff0c;只在极端的条件下才出现&#xff0c;用户碰到的概率很低&#xff0c;这种情…

nginx学习之路-nginx配置https服务器

文章目录 1. 生成证书2. 配置证书1. 拷贝证书文件2. 修改conf/nginx.conf文件内容 3. 查看效果1. 重载配置2. 访问 1. 生成证书 在linux系统下执行&#xff0c;使用openssl命令。&#xff08;windows环境也可以使用cmder&#xff09; # 1. 生成私钥 server2025.key(无密码保护…

【mybatis】Mybatis整体架构解析

从本篇开始我们开始学习mybatis的系列源码&#xff0c;主要的主题可能就是四个方面 从整体把握mybatis系统架构通过一个查询SQL 源码解析核心流程mybatis的缓存机制-源码级别mybatis的插件机制-源码级别spring是如何整合的mybatis框架的 1.整体架构 上述是mybatis的源码&…

DDcGAN_多分辨率图像融合的双鉴别条件生成对抗网络_y译文马佳义

摘要&#xff1a; 在本文中&#xff0c;我们提出了一种新的端到端模型&#xff0c;称为双鉴别条件生成对抗网络&#xff08;DDcGAN&#xff09;&#xff0c;用于融合不同分辨率的红外和可见光图像。我们的方法建立了一个生成器和两个鉴别器之间的对抗博弈。生成器的目的是基于特…

K8s高可用集群之Kubernetes集群管理平台、命令补全工具、资源监控工具部署及常用命令

K8s高可用集群之Kubernetes管理平台、补全命令工具、资源监控工具部署及常用命令 1.Kuboard可视化管理平台2.kubectl命令tab补全工具3.MetricsServer资源监控工具4.Kubernetes常用命令 1.Kuboard可视化管理平台 可以选择安装k8s官网的管理平台&#xff1b;我这里是安装的其他开…

计算机网络-数据链路层(CSMA/CD协议,CSMA/CA协议)

2.2 ppp协议 点对点协议ppp是目前使用最广泛的点对点数据链路层协议。 2.3 媒体接入控制基本概念 共享信道要着重考虑的一个问题就是如何协调多个发送和接收站点对一个共享传输媒体的占用&#xff0c;即媒体接入控制MAC。 2.3.1 静态划分信道 频分复用 时分复用 波分复用 码分复…

富芮坤FR800X系列之软件开发工具链(如IDE、编译器、调试器等)

文章目录 一、IDE&#xff08;集成开发环境&#xff09;二、编译器三、调试器四、其他辅助工具五、小结 FR800x系列作为一款低功耗蓝牙芯片&#xff0c;其软件开发工具链对于开发者来说至关重要。以下是对FR800x软件开发工具链的详细介绍&#xff0c;包括IDE&#xff08;集成开…

Oracle数据库如何找到 Top Hard Parsing SQL 语句?

有一个数据库应用程序存在过多的解析问题&#xff0c;因此需要找到产生大量硬解析的主要语句。 什么是硬解析 Oracle数据库中的硬解析&#xff08;Hard Parse&#xff09;是指在执行SQL语句时&#xff0c;数据库需要重新解析该SQL语句&#xff0c;并创建新的执行计划的过程。这…

从零开始开发纯血鸿蒙应用之实现起始页

从零开始开发纯血鸿蒙应用 一、前言二、主要页面三、应用起始页四、MainPageContent 实现1、一级结构2、二级结构2.1、EmptyContent2.2、FileListContent2.2.1、ViewAction&#xff1a;2.2.2、EditAction2.2.3、DeleteAction2.2.4、ShareAction 五、载入起始页的时机五、总结 一…

5G NTN(七) 高层(1)

说明&#xff1a;本专题主要基于3GPP协议38.821 目录 1. Idle态移动性增强 1.1 TA问题 1.1.1 TA的大小 1.1.2 针对NTN LEO的移动TA&#xff0c;场景C2和D2 1.1.3 针对NTN LEO的固定TA&#xff0c;场景C2和D2 1.1.3.1 方法1&#xff1a;当UE位置信息无法获取的时候 1.1.…

Spring Cloud微服务多模块架构:父子工程搭建实践

一、前言 在现代微服务架构中&#xff0c;Spring Cloud 提供了一整套工具和技术栈来简化分布式系统的开发。为了更好地组织和管理复杂的微服务项目&#xff0c;使用 Maven 多模块&#xff08;父子工程&#xff09; 是一种高效的方法。 ‍ 父子工程 是 Maven 中的一种项目结构…

PDF2Audio - 阅读 PDF 的新方式

1000 Stars 127 Forks 10 Issues 0 贡献者 Apache-2.0 License Python 语言 代码: GitHub - lamm-mit/PDF2Audio 更多AI开源软件&#xff1a;AI开源 - 小众AI PDF2Audio&#xff0c;它将彻底改变我们阅读和理解 PDF 文件的方式。我们不再需要盯着屏幕&#xff0c;而是让信息以声…

pdf预览 报:Failed to load module script

pdf 预览报&#xff1a; Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “application/octet-stream”. Strict MIME type checking is enforced for module scripts per HTML spec. 报错原因&#xff1a…