Unity 接口、抽象类、具体类对象的配合使用案例

news2024/11/15 15:54:10

文章目录

      • 示例1:接口(Interface)
      • 示例2:抽象类(Abstract Class)
      • 示例3:结合使用接口与抽象类
      • 示例4:多接口实现
      • 示例5:抽象类与接口结合

在Unity中使用C#编程时,接口、抽象类与具体类是面向对象设计中的重要概念。以下通过三个代码实例来讲解它们的设计与使用场景:

示例1:接口(Interface)

场景
假设我们正在开发一个游戏,需要定义一个“可移动”(IMovable)的接口,以便于所有角色、敌人和道具等都可以实现这个接口,从而具备移动的能力。

// 定义接口IMovable
public interface IMovable
{
    void Move(Vector3 direction);
    float Speed { get; set; }
}

// 具体类Player实现IMovable接口
public class Player : MonoBehaviour, IMovable
{
    public float speed;

    public float Speed
    {
        get => speed;
        set => speed = value;
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            Move(Vector3.forward * Time.deltaTime * Speed);
        }
    }

    void Move(Vector3 direction)
    {
        transform.position += direction;
    }
}

// 同样,Enemy类也可以实现IMovable接口
public class Enemy : MonoBehaviour, IMovable
{
    // 实现Move方法和Speed属性...
}

示例2:抽象类(Abstract Class)

场景
考虑一个更为复杂的场景,我们有一个基础的实体基类,其中包含一些通用功能,同时希望某些实体具有攻击能力,但不直接提供具体的攻击逻辑,这时可以定义一个抽象的Actor类,并包含一个抽象的Attack方法。

// 抽象类Actor
public abstract class Actor : MonoBehaviour
{
    public int Health { get; protected set; }

    protected Actor(int initialHealth)
    {
        Health = initialHealth;
    }

    // 抽象方法,由子类实现具体的攻击行为
    public abstract void Attack(Actor target);

    // 通用功能,例如显示血量
    public void DisplayHealthUI()
    {
        // 假设此处有UI更新代码
    }
}

// 具体类Knight继承自Actor并实现Attack方法
public class Knight : Actor
{
    public Knight(int health) : base(health)
    {
    }

    public override void Attack(Actor target)
    {
        if (target is not null)
        {
            target.Health -= 10; // 假设每次攻击造成10点伤害
        }
    }
}

// 另一个具体类Mage同样继承自Actor并实现Attack方法
public class Mage : Actor
{
    public Mage(int health) : base(health)
    {
    }

    public override void Attack(Actor target)
    {
        if (target is not null)
        {
            target.Health -= 20; // 假设每次攻击造成20点伤害
        }
    }
}

示例3:结合使用接口与抽象类

场景
假设我们的游戏包含不同类型的NPC,有些NPC会说话,有些则不会。我们可以先定义一个抽象的NPC类,然后用一个ISpeakable接口来表示那些能说话的NPC。

// 抽象类NPC
public abstract class NPC : MonoBehaviour
{
    public string Name { get; set; }

    public abstract void Interact();
}

// ISpeakable接口
public interface ISpeakable
{
    string Speak();
}

// 具体类Merchant继承自NPC并实现ISpeakable接口
public class Merchant : NPC, ISpeakable
{
    public Merchant(string name) 
    {
        Name = name;
    }

    public override void Interact()
    {
        Debug.Log($"你与{Name}交谈...");
        if (this is ISpeakable speakable)
        {
            Debug.Log(speakable.Speak());
        }
    }

    public string Speak()
    {
        return $"欢迎光临,我这里有各种商品出售!";
    }
}

// 具体类Guard类也继承自NPC,但并不实现ISpeakable接口
public class Guard : NPC
{
    public Guard(string name) 
    {
        Name = name;
    }

    public override void Interact()
    {
        Debug.Log($"你尝试与{Name}交谈,但他只是坚守岗位并未回应...");
    }
}

示例4:多接口实现

场景
在Unity中,我们可能需要设计一些对象既可以被玩家控制也可以被AI控制。这时可以定义IControllable(可控制)和IAIControlled(AI控制)两个接口。

// 定义可控制接口
public interface IControllable
{
    void TakePlayerInput();
}

// 定义AI控制接口
public interface IAIControlled
{
    void UpdateAI();
}

// 具体类Character同时实现两个接口
public class Character : MonoBehaviour, IControllable, IAIControlled
{
    public void TakePlayerInput()
    {
        // 处理玩家输入,例如移动、攻击等
        Debug.Log("处理玩家输入...");
    }

    public void UpdateAI()
    {
        // 更新AI逻辑,例如自动寻路、决策等
        Debug.Log("执行AI逻辑...");
    }
    
    void Update()
    {
        if (isPlayerControlled)
        {
            TakePlayerInput();
        }
        else if (isAIControlled)
        {
            UpdateAI();
        }
    }
}

在这个例子中,Character类可以根据游戏运行时的状态,选择使用玩家输入还是AI逻辑进行操作,体现了接口的灵活性和解耦性。

示例5:抽象类与接口结合

场景
考虑一个角色系统,角色分为基础角色和英雄角色,基础角色有基本属性如生命值和攻击力,而英雄角色除了基础属性外还有特殊技能。我们可以创建一个抽象角色类,并使用接口来表示具有特定技能的角色。

// 抽象角色类
public abstract class BaseCharacter : MonoBehaviour
{
    public int Health { get; protected set; }
    public int AttackPower { get; set; }

    protected BaseCharacter(int health, int attackPower)
    {
        Health = health;
        AttackPower = attackPower;
    }

    // 基础攻击方法
    public virtual void Attack(BaseCharacter target)
    {
        target.Health -= AttackPower;
    }
}

// 特殊技能接口
public interface ISpecialAbility
{
    void UseSpecialAbility();
}

// 英雄角色类继承自BaseCharacter并实现ISpecialAbility接口
public class Hero : BaseCharacter, ISpecialAbility
{
    public Hero(int health, int attackPower, string specialSkillDescription) 
        : base(health, attackPower)
    {
        SpecialSkillDescription = specialSkillDescription;
    }

    public string SpecialSkillDescription { get; private set; }

    // 实现特殊技能
    public override void Attack(BaseCharacter target)
    {
        base.Attack(target);
        UseSpecialAbility();
    }

    public void UseSpecialAbility()
    {
        Debug.Log($"英雄施展{SpecialSkillDescription},对目标造成额外伤害...");
    }
}

这个示例展示了如何通过抽象类来封装共享的基础功能,并通过接口让某些具体类具备额外的能力,从而构建出丰富且灵活的角色系统。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

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

相关文章

SSL协议是什么?关于SSL和TLS的常见问题解答

SSL(安全套接字层)及其后继者TLS(传输层安全)是用于在联网计算机之间建立经过身份验证和加密的链接的协议。尽管SSL协议在 1999年已经随着TLS 1.0的发布而被弃用,但我们仍将这些相关技术称为“SSL”或“SSL/TLS”。那么…

[C/C++] -- JSON for Modern C++

JSON for Modern C(nlohmann/json)是一个流行的 C JSON 库,由德国开发者nlohmann编写。这个库提供了简洁而灵活的 API,使得在C中解析和生成JSON数据变得非常方便。 1.JSON简介 JSON(JavaScript Object Notation&…

sqli-labs-master靶场训练笔记(54-65|决战紫禁之巓)

2024.2.5 level-54 1、先判断类型和闭合类型 ?id1/0 #正常 证明不是数字型 ?id1 #错误 ?id1 -- a #正常 判断是 闭合 2、 判断列数 这里需要运气,但是根据前面50多关的经验直接猜测是3列 ?id-1 union select 1,2,3 -- a 3、爆表名&#xf…

时序数据库Influxdb查询多个字段_field同一时间的值,组成一条数据

Influxdb将表格数据多个字段_field从垂直列布局聚合成水平布局行字段。 问题 1、Influxdb 是一种时间序列数据库,在我的项目中主要用来存储换热站的测点数据的。换热站有非常多的测点,我们用Flux 语法去查询测点数据,返回的数据结构是每个测…

阿里云增加数据库访问白名单

阿里云增加数据库访问白名单 概况 我们希望在外网访问数据库时,可能会遇到无法连接的问题,这有可能是被拦截了。这时就需要去查看自己的ip有没有在白名单里面,没有的话就把ip加入到白名单。 路径 阿里云控制台-搜索RDS-进入RDS管理控制台…

每日一题——LeetCode1413.逐步求和得到正数的最小值

方法一 个人方法: 找出数组求和过程中出现的最小值,如果这个值最小都>0,那么startValue只需要取最小正数1, 反之startValue取最小值的绝对值1,那么startValuemin一定>1 var minStartValue function(nums) {l…

MTK 多帧算法集成实现流程

和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、选择feature和配置feature table二、 挂载算法三、自定义metadata四、APP调用算法五、结语 一、选择feature和配置feature table 1.1 选择feature …

双面板设计的一套经验规则-笔记

过大的分布电感导致信号地干扰也就是地弹(专业名词) 还有就是输出瞬态电流导致的地弹 图中可以看到最高 0.5V 的信号地干扰,这只是单一块开发板的测试结果。如果接上外围电路,甚至面包板电路可以想象噪声水平可能会更高。 双面电路板 经验规则 下面来…

I.MX6u嵌入式linux驱动开发

1:Ubuntu 系统入门 当 Ubuntu 系统入门以后,我们重点要学的就是如何在 Linux 下进行 C 语言开发,如何使 用 gcc 编译器、如何编写 Makefile 文件等等 首先安装虚拟机软件VM: Vmware Workstation 软件可以在 Wmeare …

架构学习(五):scrapy实现自定义代理中间件

scrapy实现自定义代理中间件 前言关卡:实现自定义代理中间件代理中间件源码解析代理池自定义代理中间件 结束 前言 ip检测是比较常规的反爬手段,一般站点会限制ip的访问频率,或者根据ip的访问规律和频率来识别异常访问,从而点对点…

Stable Diffusion 模型下载:majicMIX fantasy 麦橘幻想

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 非常推荐的一个非常绚丽、充满幻想的大模型,由国人“Merjic”发布,下载量颇高。这个模型风格炸裂,远距离脸部需要inpaint以达成…

Leetcode—135. 分发糖果【中等】

2024每日刷题(113) Leetcode—135. 分发糖果 算法思想 这里可以利用贪心策略,求局部最优解,然后合并为全局最优解。具体来说,将原问题中相邻孩子的条件划分为左相邻孩子和右相邻孩子两个条件,依次求解出两…

NLP中的嵌入和距离度量

本文将深入研究嵌入、矢量数据库和各种距离度量的概念,并提供示例和演示代码。 NLP中的嵌入 嵌入是连续向量空间中对象、单词或实体的数值表示。在NLP中,词嵌入捕获词之间的语义关系,使算法能够更好地理解文本的上下文和含义。 让我们试着用…

Linux操作系统运维-Docker的基础知识梳理总结

Linux操作系统运维-Docker的基础知识梳理总结 docker用来解决不同开发人员软件调试时环境不统一的问题,保证了程序调试时运行环境的一致性。docker的设计理念便是一处镜像,处处运行,即通过产生用户软件,运行环境及其运行配置的统一…

PKI - 01 散列(Hash)函数

文章目录 PKI概述散列日产生活中的指纹的工作原理散列函数的工作原理散列函数的四大特点使用散列函数验证数据的完整性 PKI概述 PKI(Public Key Infrastructure,公钥基础设施)证书系统是一种用于保护网络通信安全的技术。它基于非对称加密算法…

自己动手打包element UI官方手册文档教程

经常用element ui朋友开发的比较郁闷,官方文档网基本上都是打不开的, 官方:https://element.eleme.io/ 一直打不开,分析下是里面用的cdn链接ssl证书无效。 就想着自己搭建一个element UI文档 自己搭建的: Element文档网…

python 动态显示数据。

界面显示动态的数据。 from time import sleep import serialimport tkinter as tklis[1,10,40] # 打开串行端口 ser serial.Serial(COM3, 9600) # 9600为波特率,根据实际情况进行调整# 创建窗口和画布 window tk.Tk() canvas tk.Canvas(window, width400, heig…

牛客错题整理——C语言(实时更新)

1.以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main() { int sum, pad,pAd; sum pad 5; pAd sum, pAd, pad; printf("%d\n",pAd); }答案为7 由于赋值运算符的优先级高于逗号表达式&#xff0c;因此pAd sum, pAd, pad;等价于(…

大厂聚合支付系统架构演进(上)

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 关注我&#xff0c;紧跟本系列专栏文章&#xff0c;咱们下篇再续&#xff01; 作者简介&#xff1a;魔都国企技术专家兼架构&#xff0c;多家大厂后端一线研发经验&#xff0c;各大技术社区…

OpenCV与机器学习:使用opencv和sklearn实现线性回归

前言 线性回归是一种统计分析方法&#xff0c;用于确定两种或两种以上变量之间相互依赖的定量关系。在统计学中&#xff0c;线性回归利用线性回归方程&#xff08;最小二乘函数&#xff09;对一个或多个自变量&#xff08;特征值&#xff09;和因变量&#xff08;目标值&#…