【C】-->【C#】-->【游戏实践】

本文主要介绍:
一:由c基础过度到c#,所需的基础知识板块。
二:由介绍的c#_板块,基于unity开发游戏的功能实践与练习。
 



框架

一、C 到 C# 过渡的基础知识

  1. 四大类型金刚
    • 基础类型
    • 委托类型
    • 类的类型与多态
    • 接口
  2. 其他知识点
    • Lambda 表达式
    • 属性
    • 泛型
    • List<T> 详解
      • 初始化与容量管理
      • 元素操作
      • 查询与查找
      • 排序与转换
    • 事件

二、待补充的 C# 知识点

  • 异步编程(async/await)

    • 游戏应用:资源加载(如 AssetBundle.LoadAsync)、网络请求、长时间运算(如寻路)。
    • 替代方案:Unity 的协程(IEnumerator + yield return),但 async/await 语法更简洁。
  • 扩展方法

    • 游戏应用:为 Unity 内置类型(如 TransformGameObject)添加自定义工具方法,减少重复代码。
  • 异常处理(try-catch-finally)

    • 游戏应用:防止因外部资源加载失败(如配置文件损坏)导致游戏崩溃。
  • LINQ 查询

    • 游戏应用:快速筛选游戏对象集合(如查找所有敌人、最近的道具)。
  • 任务并行库(TPL)

    • 游戏应用:后台线程处理非 UI 逻辑(如数据计算、AI 决策),避免阻塞主线程。
  • 内存管理(GC)

    • 游戏应用:优化频繁创建的对象(如子弹、特效),减少 GC 卡顿(使用对象池)。
  • 反射与特性

    • 游戏应用:自动绑定 UI 组件(通过特性标记)、插件系统(动态加载程序集)。

一:
基础类型四金刚:
基础类型:
就和c里面一样,int,double,float,char,bool等....还有var(隐式类型,根据右边自动转换)。
委托类型:
先看举例:

【第一步】
delegate void DeliveryCallback(string address); // 定义委托类型
/*
其他定义方法:
// 无参数
Action sayHello = () => Console.WriteLine("Hi");

// 单参数可省略括号
Func<int, int> square = x => x * x; 

// 多参数必须用括号
Func<int, int, int> add = (a, b) => a + b;
*/
class 奶茶店 {
【第二步】
    public DeliveryCallback 外卖小哥; // 委托实例

    public void 订单来了() {
        外卖小哥?.Invoke("北京市海淀区"); // 调用委托链,也可以:外卖小哥("北京市海淀区"); 
    }
}

class 美团骑手 {
    public void 开始送餐(string addr) {
       print($"美团骑手出发去{addr}");
    }
}

class 饿了么骑手 {
    public void 配送流程(string addr) {
        print($"饿了么骑手已接单,目标:{addr}");
    }
}


var 店铺 = new 奶茶店();
var 美团 = new 美团骑手();
var 饿了么 = new 饿了么骑手();

【第三步】
// 登记多个外卖员(+= 是委托链的关键操作)
店铺.外卖小哥 += 美团.开始送餐;
店铺.外卖小哥 += 饿了么.配送流程;//如果最后饿了么用的是=而非+=,就会只保留最后=的,也就是饿了么,美团OUT。


【跑起来】
// 触发事件
店铺.订单来了(); 
// 输出:
// 美团骑手出发去北京市海淀区
// 饿了么骑手已接单,目标:北京市海淀区


本质是实现一个“在一定情况下,去调用某或某些满足基本格式的方法“的一个功能。具体实现为:【第一步】,
相当于定义了一个公告板(可以用构建无名方法的关键字delegate,也可以用NET框架里面的委托泛型Action无返回值,Func有返回值的方法定义),并且防止传参与返回错误,简单定义了一下参数和返回值这两个东西,基本还是属于白板。
【第二步】,
相当于需要公告板的class类,去实例化一下公告板,并且去类里面自己设定逻辑,什么逻辑下去调用啊,就是实现调用某或某些满足格式的方法的行为,使用委托实例.Invoke(参数)。
【第三步】,
将满足委托公告板要求的那些需要被调用的某或某些方法给“+=”或者直接=(单情况)去实现委托链的构建。
类的类型:
先看举例:

// 父类
class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("动物发出声音");
    }
}

// 子类
class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("狗汪汪叫");
    }
}

// 子类
class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("猫喵喵叫");
    }
}

// 使用多态
class Program
{
    static void Main()
    {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        animal1.Speak(); // 输出:狗汪汪叫
        animal2.Speak(); // 输出:猫喵喵叫
    }
}
// 抽象类
abstract class Shape
{
    public abstract double Area();
}

// 子类
class Circle : Shape
{
    public double Radius { get; set; }

    public override double Area()
    {
        return Math.PI * Radius * Radius;
    }
}

// 子类
class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public override double Area()
    {
        return Width * Height;
    }
}

// 使用多态
class Program
{
    static void Main()
    {
        Shape shape1 = new Circle { Radius = 5 };
        Shape shape2 = new Rectangle { Width = 4, Height = 6 };

        Console.WriteLine($"圆形面积: {shape1.Area()}"); // 输出:圆形面积: 78.53981633974483
        Console.WriteLine($"矩形面积: {shape2.Area()}"); // 输出:矩形面积: 24
    }
}
// 接口
interface IPrintable
{
    void Print();
}

// 类实现接口
class Book : IPrintable
{
    public string Title { get; set; }

    public void Print()
    {
        Console.WriteLine($"打印书籍: {Title}");
    }
}

// 类实现接口
class Document : IPrintable
{
    public string Content { get; set; }

    public void Print()
    {
        Console.WriteLine($"打印文档: {Content}");
    }
}

// 使用多态
class Program
{
    static void Main()
    {
        IPrintable printable1 = new Book { Title = "C#编程指南" };
        IPrintable printable2 = new Document { Content = "重要文件内容" };

        printable1.Print(); // 输出:打印书籍: C#编程指南
        printable2.Print(); // 输出:打印文档: 重要文件内容
    }
}


介绍:
就是面向对象编程,将一个功能需要的方法和变量,这边c#里面还有属性,封装在类calss里面,用修饰符修饰这个访问权限。,一个一个类即功能块之间呢又可以通过父子继承,来实现子类对父类的复用、异化、扩充、升级。然后通过:“virtual虚方法,override重写虚方法”、“abstract 抽象类,抽象方法,等待不同子类实现”、“insert接口与实现”。来实现一个模版,多个阐述的多态性。(c#是单继承,多接口),补充:sealed 关键字修饰的类称为 “密封类”,其核心作用是禁止被其他类继承。

修饰符_c#
修饰符说明
public公开的,任何地方都能访问。
private私有的,只有类内部能访问(默认修饰符)。
protected受保护的,类内部和子类能访问。
internal内部的,同一程序集(Assembly)内可访问(常用于项目内部分享)。
protected internal受保护的内部成员,同一程序集或子类可访问。
多态的体现通道
多态体现通道说明
virtual        虚方法虚方法不一定要被重写,只是提供一个override重写方法,
体现多态的通道。
abstract     抽象类抽象类里面可以有普通方法或抽象方法
(抽象方法必须在抽象类里面,抽象类里面不一定要抽象方法)
抽象方法只是声明,不实现,是契约。等待子类继承者【必须重写】
insert         接口一个类可以实现多个接口,接口里面只声明,不实习,全是契约。
等待实现接口的类直接实现,不用重写关键字。并且不是强制契约。

接口类型:
只有些注意事项,因为第三个类型已经基本介绍了。
当两个接口有同名方法时,需用显式接口实现指定具体实现哪个接口的方法:
C# 8.0 允许接口为方法提供默认实现,实现类可以选择是否重写(类似虚方法)。
二、其他
lamade表达式
额lamade表达式在c#里面说白了就是,取代delegate关键字的一种不命名创建函数的方法,用(参数)=>{}来代替函数声明。

// 传统委托
delegate int Calculate(int a, int b);

Calculate add = delegate(int a, int b) { return a + b; };

// Lambda 表达式(无需命名,直接定义函数体)
Calculate addLambda = (a, b) => a + b;


属性
属性public string Name { get; set; } = "Unnamed";比如这个,其实成员本身就有set,get但是是没有任何限制的,但是我们可以通过对get,set进行设置,来筛选更改和获取。
泛型:
看代码:

// 普通类:只能存储 int
class IntList {
    private int[] items;
    public void Add(int item) { /* ... */ }
    public int Get(int index) { return items[index]; }
}

// 泛型类:可以存储任意类型(T 是占位符)
class GenericList<T> {
    private T[] items;
    public void Add(T item) { /* ... */ }
    public T Get(int index) { return items[index]; }
}

// 使用泛型类
var intList = new GenericList<int>();  // 指定 T 为 int
intList.Add(10);
int value = intList.Get(0);  // 返回 int

var stringList = new GenericList<string>();  // 指定 T 为 string
stringList.Add("hello");
string text = stringList.Get(0);  // 返回 string


说白了,在想用泛型类,接口,方法前,在类,接口,方法的名后面加<T>,这个里面就可以用T来占位了

对标STL_C++:
这个内容太大,我会单开一篇幅总结,关注蹲后续

C# 泛型类类似 C++ STL说明
List<T>vector<T>动态数组,自动扩容,支持随机访问。
Dictionary<TKey, TValue>map<TKey, TValue>基于哈希表的键值对集合,查找速度 O (1)。
LinkedList<T>list<T>双向链表,支持 O (1) 插入 / 删除。
Queue<T>queue<T>先进先出(FIFO)队列。
Stack<T>stack<T>后进先出(LIFO)栈。
HashSet<T>unordered_set<T>不重复元素的集合,基于哈希表。
SortedSet<T>set<T>排序的不重复元素集合,基于红黑树。
SortedDictionary<TKey, TValue>map<TKey, TValue>排序的键值对集合,基于红黑树。

 

简单聊一下第一个List<T>:
 

 

一、List<T> 的核心方法与属性

List<T> 位于 System.Collections.Generic 命名空间,提供了动态数组的功能,无需手动管理内存。以下是常用方法和属性:

1. 初始化与容量管理

方法 / 属性说明
List<T>()无参构造函数,初始容量为 0,添加元素时自动扩容。
List<T>(int capacity)指定初始容量,减少扩容次数,提高性能。
Capacity获取或设置当前容量(元素数量超过容量时自动翻倍)。
TrimExcess()将容量调整为当前元素数量,减少内存占用。

2. 元素操作

方法 / 属性说明
Add(T item)在列表末尾添加一个元素。
AddRange(IEnumerable<T> collection)添加多个元素(如另一个列表)。
Insert(int index, T item)在指定位置插入元素,后续元素后移。
Remove(T item)删除第一个匹配的元素,返回是否删除成功。
RemoveAt(int index)删除指定位置的元素。
RemoveRange(int index, int count)删除指定范围的元素。
Clear()清空所有元素,容量不变。
[index]通过索引访问或修改元素(如 list[0] = value)。

3. 查询与查找

方法 / 属性说明
Count获取当前元素数量(只读)。
Contains(T item)判断列表是否包含指定元素(使用 Equals 比较)。
IndexOf(T item)返回第一个匹配元素的索引,不存在则返回 -1。
LastIndexOf(T item)返回最后一个匹配元素的索引。
Find(Predicate<T> match)返回第一个满足条件的元素,不存在则返回 default(T)
FindAll(Predicate<T> match)返回所有满足条件的元素组成的新列表。
Exists(Predicate<T> match)判断是否存在满足条件的元素。

4. 排序与转换

方法 / 属性说明
Sort()对列表元素进行排序(默认按元素的 IComparable<T> 实现)。
Sort(Comparison<T> comparison)使用自定义比较器排序。
Reverse()反转列表元素的顺序。
ToArray()将列表转换为数组。
ConvertAll<TOutput>(Converter<T, TOutput> converter)将列表元素转换为另一种类型。

using System;
using System.Collections.Generic;

class ListMethodDemo
{
    static void Main()
    {
        #region 1. 初始化与容量管理
        // 无参构造(初始容量 0,自动扩容)
        List<int> numbers = new List<int>();
        Console.WriteLine("1. 初始化后容量: " + numbers.Capacity);  // 输出: 0

        // 带初始容量构造(减少扩容次数)
        List<string> names = new List<string>(5);  // 初始容量 5
        Console.WriteLine("1. 带容量初始化后容量: " + names.Capacity);  // 输出: 5

        // 手动设置容量(不会改变元素数量)
        numbers.Capacity = 10;
        Console.WriteLine("1. 手动设置容量后容量: " + numbers.Capacity);  // 输出: 10

        // 裁剪容量(仅当当前容量 > 125% 元素数量时生效)
        numbers.TrimExcess();  // 此时元素数量为 0,容量可能变为 0
        #endregion

        #region 2. 元素操作(增、插、删)
        // 2.1 添加单个元素
        numbers.Add(3);
        numbers.Add(1);
        numbers.Add(4);
        Console.WriteLine("\n2.1 Add 后元素: " + string.Join(", ", numbers));  // 输出: 3, 1, 4

        // 2.2 添加多个元素(AddRange)
        numbers.AddRange(new int[] { 1, 5, 9 });
        Console.WriteLine("2.2 AddRange 后元素: " + string.Join(", ", numbers));  // 输出: 3, 1, 4, 1, 5, 9

        // 2.3 在指定位置插入元素(Insert)
        numbers.Insert(2, 100);  // 在索引 2 插入 100
        Console.WriteLine("2.3 Insert 后元素: " + string.Join(", ", numbers));  // 输出: 3, 1, 100, 4, 1, 5, 9

        // 2.4 删除第一个匹配元素(Remove)
        bool removed = numbers.Remove(1);  // 删除第一个 1
        Console.WriteLine($"2.4 Remove 成功: {removed}, 剩余元素: " + string.Join(", ", numbers));  // 输出: 成功, 3, 100, 4, 1, 5, 9

        // 2.5 删除指定索引元素(RemoveAt)
        numbers.RemoveAt(1);  // 删除索引 1 的 100
        Console.WriteLine("2.5 RemoveAt 后元素: " + string.Join(", ", numbers));  // 输出: 3, 4, 1, 5, 9

        // 2.6 删除指定范围元素(RemoveRange)
        numbers.RemoveRange(1, 2);  // 从索引 1 开始删除 2 个元素(4, 1)
        Console.WriteLine("2.6 RemoveRange 后元素: " + string.Join(", ", numbers));  // 输出: 3, 5, 9

        // 2.7 清空所有元素(Clear)
        // numbers.Clear();  // 测试时可取消注释
        #endregion

        #region 3. 查询与查找
        // 3.1 获取元素数量(Count)
        int count = numbers.Count;
        Console.WriteLine("\n3.1 元素数量: " + count);  // 输出: 3

        // 3.2 判断是否包含元素(Contains)
        bool has3 = numbers.Contains(3);
        Console.WriteLine("3.2 是否包含 3: " + has3);  // 输出: True

        // 3.3 查找元素索引(IndexOf)
        int indexOf5 = numbers.IndexOf(5);
        Console.WriteLine("3.3 元素 5 的索引: " + indexOf5);  // 输出: 1

        // 3.4 查找最后一个匹配元素的索引(LastIndexOf)
        numbers.Add(5);  // 现在列表: 3, 5, 9, 5
        int lastIndexOf5 = numbers.LastIndexOf(5);
        Console.WriteLine("3.4 最后一个 5 的索引: " + lastIndexOf5);  // 输出: 3

        // 3.5 查找第一个满足条件的元素(Find)
        int firstLarge = numbers.Find(n => n > 5);  // 找第一个 >5 的数
        Console.WriteLine("3.5 第一个大于 5 的元素: " + firstLarge);  // 输出: 9

        // 3.6 查找所有满足条件的元素(FindAll)
        List<int> allLarge = numbers.FindAll(n => n > 5);
        Console.WriteLine("3.6 所有大于 5 的元素: " + string.Join(", ", allLarge));  // 输出: 9, 5(注意 5 不大于 5,实际应为 9)

        // 3.7 判断是否存在满足条件的元素(Exists)
        bool hasLarge = numbers.Exists(n => n > 10);
        Console.WriteLine("3.7 是否存在大于 10 的元素: " + hasLarge);  // 输出: False
        #endregion

        #region 4. 排序与转换(重点:自定义排序)
        // 4.1 默认排序(升序,依赖元素的 IComparable 实现)
        numbers.Sort();
        Console.WriteLine("\n4.1 默认排序后: " + string.Join(", ", numbers));  // 输出: 3, 5, 5, 9

        // 4.2 自定义排序(降序,使用 Comparison<T> 委托)
        // 方式 1:直接传入 lambda 表达式(推荐)
        numbers.Sort((a, b) => b.CompareTo(a));  // 降序:b - a
        Console.WriteLine("4.2 自定义降序排序后: " + string.Join(", ", numbers));  // 输出: 9, 5, 5, 3

        // 方式 2:通过自定义方法(适合复杂逻辑)
        numbers.Sort(MyCustomComparison);  // 调用自定义比较方法
        Console.WriteLine("4.2 自定义升序排序后: " + string.Join(", ", numbers));  // 输出: 3, 5, 5, 9

        // 4.3 反转元素顺序(Reverse)
        numbers.Reverse();
        Console.WriteLine("4.3 反转后: " + string.Join(", ", numbers));  // 输出: 9, 5, 5, 3

        // 4.4 转换为数组(ToArray)
        int[] numberArray = numbers.ToArray();
        Console.WriteLine("4.4 转换为数组: " + string.Join(", ", numberArray));  // 输出: 9, 5, 5, 3

        // 4.5 转换元素类型(ConvertAll)
        List<string> stringNumbers = numbers.ConvertAll(n => $"数字: {n}");
        Console.WriteLine("4.5 转换为字符串列表: " + string.Join(", ", stringNumbers));  // 输出: 数字: 9, 数字: 5, 数字: 5, 数字: 3
        #endregion
    }

    // 自定义比较方法(实现升序排序)
    static int MyCustomComparison(int a, int b)
    {
        // 升序逻辑:a - b
        // 降序逻辑:b - a
        return a.CompareTo(b);  // 等价于 a - b(int 实现了 IComparable)
    }
}


事件:
事件是被保护的委托,是安全性更高,防止误触与恶意攻击的保护写法:

public class Publisher {
    // 事件(带保护)
    public event Action<string> OnEvent;

    // 委托变量(无保护)
    public Action<string> OnAction;

    public void TriggerEvent() {
        // 发布者内部触发事件(合法)
        OnEvent?.Invoke("事件被发布者触发");
    }

    public void TriggerAction() {
        // 发布者内部触发委托(合法)
        OnAction?.Invoke("委托被发布者触发");
    }
}

public class Subscriber {
    public void Test(Publisher pub) {
        // 尝试触发事件(编译错误!)
        // pub.OnEvent?.Invoke("外部触发事件");  ❌ 事件无法直接调用

        // 尝试覆盖事件(编译错误!)
        // pub.OnEvent = s => Console.WriteLine("覆盖事件");  ❌ 事件禁止赋值

        // 尝试触发委托(合法,但危险!)
        pub.OnAction("外部触发委托");  ✅ 委托可被外部调用

        // 尝试覆盖委托(合法,但危险!)
        pub.OnAction = s => Console.WriteLine("覆盖委托");  ✅ 委托可被外部赋值
    }
}
特性事件(event)委托变量(非事件)
调用权限仅声明类内部可调用外部可直接调用(public 时)
订阅 / 取消订阅仅支持 +=/-=支持 +=/-=/=(覆盖)
外部覆盖订阅者禁止(编译错误)允许(= 直接赋值)
空引用异常自动处理(?.Invoke()需手动判空(因为可以直接调用)
设计目的安全的发布 - 订阅模式通用方法引用

二:
关于c#->unity,我下一篇再发。然后要补充的c#的知识点也下一篇发,前面的足够基础入门去写小游戏了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值