[简化版 GAMES 104] 现代游戏引擎 04:从0到1构建你的游戏世界

简化版 GAMES 104 现代游戏引擎 04:从0到1构建你的游戏世界

  • [✨ 写在前面:小明的困惑](#✨ 写在前面:小明的困惑)
  • [Bilibili 同步视频](#Bilibili 同步视频)
  • [🎯 第一章:万物皆GO------游戏世界的统一抽象](#🎯 第一章:万物皆GO——游戏世界的统一抽象)
    • [1.1 先拆个游戏世界看看里面有啥 🧐](#1.1 先拆个游戏世界看看里面有啥 🧐)
    • [1.2 核心方法论:Everything is GO 🎯](#1.2 核心方法论:Everything is GO 🎯)
  • [🧩 第二章:组件化大法好------告别继承的噩梦](#🧩 第二章:组件化大法好——告别继承的噩梦)
    • [2.1 早期方案:面向对象继承 👴](#2.1 早期方案:面向对象继承 👴)
    • [2.2 致命缺陷:钻石继承难题 💎](#2.2 致命缺陷:钻石继承难题 💎)
    • [2.3 现代方案:组件化Component 🧱](#2.3 现代方案:组件化Component 🧱)
    • [2.4 代码层面怎么实现? 💻](#2.4 代码层面怎么实现? 💻)
    • [2.5 商业引擎都是这么干的! 🏢](#2.5 商业引擎都是这么干的! 🏢)
    • [2.6 继承 vs 组件化 大比拼 🆚](#2.6 继承 vs 组件化 大比拼 🆚)
  • [⏱️ 第三章:Tick循环------让世界"活"起来的秘密](#⏱️ 第三章:Tick循环——让世界"活"起来的秘密)
    • [3.1 Tick是什么? 🤔](#3.1 Tick是什么? 🤔)
    • [3.2 直觉方案:Per Object Tick 🏃](#3.2 直觉方案:Per Object Tick 🏃)
    • [3.3 反直觉但更高效:Per System Tick 🏭](#3.3 反直觉但更高效:Per System Tick 🏭)
    • [3.4 流水线的魔力 🍔](#3.4 流水线的魔力 🍔)
    • [3.5 两种Tick模式对比 📊](#3.5 两种Tick模式对比 📊)
  • [📬 第四章:事件机制------解耦交互的优雅方案](#📬 第四章:事件机制——解耦交互的优雅方案)
    • [1 问题来了:GO之间怎么交互? 🤝](#1 问题来了:GO之间怎么交互? 🤝)
    • [4.2 原始方案:硬编码Hard Code 🔨](#4.2 原始方案:硬编码Hard Code 🔨)
    • [4.3 优雅方案:Event事件机制 📮](#4.3 优雅方案:Event事件机制 📮)
    • [4.4 这就叫解耦! ✂️](#4.4 这就叫解耦! ✂️)
    • [4.5 商业引擎怎么实现? 🏢](#4.5 商业引擎怎么实现? 🏢)
  • [🌳 第五章:场景管理------N²灾难的破局之道](#🌳 第五章:场景管理——N²灾难的破局之道)
    • [5.1 新问题:GO太多了怎么办? 📈](#5.1 新问题:GO太多了怎么办? 📈)
    • [5.2 基础管理:UID + 位置 🆔](#5.2 基础管理:UID + 位置 🆔)
    • [5.3 最朴素方案:全遍历 ❌](#5.3 最朴素方案:全遍历 ❌)
    • [5.4 N平方的噩梦 😱](#5.4 N平方的噩梦 😱)
    • [5.5 分而治之:画格子 📐](#5.5 分而治之:画格子 📐)
    • [5.6 进阶方案:层级空间树 🌲](#5.6 进阶方案:层级空间树 🌲)
    • [5.7 常见的空间数据结构 📚](#5.7 常见的空间数据结构 📚)
  • [🎯 总结:四大核心心法,速速收藏!](#🎯 总结:四大核心心法,速速收藏!)
  • [💬 写在最后](#💬 写在最后)

✨ 写在前面:小明的困惑

哈喽各位技术小伙伴们!👋 今天咱们来聊一个超级硬核但又贼有意思的话题------如何构建一个真正的游戏世界

话说上节课,我们聪明好学又蜜汁自信的小明同学,已经掌握了游戏引擎的五层架构:从最底层的硬件平台层,到核心层、资源层、功能层,再到最上层的工具层,整个大厦的结构门儿清。🏗️

但是!重点来了------知道大厦长啥样,不等于知道大厦里的砖石水电是怎么一起work的啊!🤯

就像你背熟了汽车的构造图,不代表你会造发动机对吧?所以今天这节课,含金量直接拉满💯,咱们就来扒一扒:游戏世界到底是怎么从一堆代码变成能玩能嗨的虚拟世界的?


Bilibili 同步视频

简化版 GAMES 104 现代游戏引擎 04:从0到1构建你的游戏世界

🎯 第一章:万物皆GO------游戏世界的统一抽象

1.1 先拆个游戏世界看看里面有啥 🧐

小明玩了《战地2042》,觉得好玩是好玩,但bug多到离谱,一拍大腿:"爷自己做一个!"💪 那首先得想想,这个战争游戏世界里都有啥?

第一类:最吸睛的动态物 Dynamic Game Objects 🚁

地上跑的坦克、天上飞的无人机、端着枪冲的NPC小兵、火炮、导弹......这些玩意儿能动能交互,甚至你能直接上去操作,是大家最容易注意到的明星选手。

第二类:默默奉献的静态物 🏠

高高的瞭望塔、飞机的机棚、各种房子......它们安安静静待在那儿,虽然不能交互,但构成了游戏的关键玩法元素,属于幕后英雄。

第三类:无处不在的环境系统 🌍

  • 地形系统:无限绵延的大地,是所有物体的"托盘",独立系统,后面单独讲

  • 天空系统TOD:Time of Day日夜变换,阴晴云雨,云卷云舒,看着简单做起来贼复杂

  • 植被系统:最神奇的存在!说它是静态吧,风吹会摇、炸弹炸了会倒;说它是动态吧,又固定在那儿。而且量特别特别大,属于环境界的"卷王"🌳

第四类:你看不见但无处不在的"隐形GO" 👻

这就有意思了!游戏里很多东西你根本看不见,但缺了它们真不行:

  • Trigger Box检测体:走到夺奇点积分就涨?就是它在干活!

  • 空气墙:玩家最恨的东西没有之一!开飞机飞得正嗨,突然提示"你已飞出作战区域,5秒后击落",就是它搞的鬼😤

  • 游戏规则:没错,连玩法规则本身都可以抽象成一个物体!

1.2 核心方法论:Everything is GO 🎯

划重点!在现代游戏引擎中,无论你是静态的、动态的、看得见的、看不见的,甚至连游戏规则本身,都会被统一抽象成一个东西------Game Object,简称GO

注意啊!这个GO和Go语言、围棋的Go都不是一回事,别搞混了~ 😄

所以构建游戏世界的本质,说白了就是:管理好这一大堆GO。就这么简单?对,就这么简单!但简单的概念背后,是一整套精妙的设计哲学。


🧩 第二章:组件化大法好------告别继承的噩梦

2.1 早期方案:面向对象继承 👴

咱们先从最朴素的想法说起。描述一个物体,无非就是两类东西:

  • 属性Property:外形、位置、血量、油量、电量......就是数据嘛

  • 行为Behavior:移动、巡逻、攻击......就是函数嘛

于是乎,早期的游戏引擎很自然地就用了面向对象+类继承的思路。比如定义一个Drone无人机类:

cpp 复制代码
class Drone {
    // 属性
    Vector3 position;  // 位置
    float health;      // 血量 0-100
    float battery;     // 电量 0-1

    // 行为
    void Move();       // 移动
    void Patrol();     // 巡逻
};

想做个查打一体无人机?简单!继承一下,加个攻击行为和弹药属性:

cpp 复制代码
class CombatDrone : public Drone {
    int ammo;          // 弹药量
    void Attack();     // 攻击
};

看上去很完美对不对?非常直觉,非常符合人类对世界的认知。早期游戏还真就是这么写的。

2.2 致命缺陷:钻石继承难题 💎

但是!随着游戏世界越来越复杂,问题就来了------很多物体根本没有清晰的父子关系,全是"混血儿"啊!🤯

举个经典例子:水陆两栖坦克。

坦克派生于车辆,船派生于船舶,那水陆两栖坦克它爹到底是坦克还是船?它爷爷到底是车辆还是船舶?

这就是经典的钻石继承问题,不仅游戏引擎有,现代编程语言里也是个老大难问题。

2.3 现代方案:组件化Component 🧱

怎么解?有一个非常经典、也是现在引擎最常用的方法------组件化

啥意思呢?就是把对象拆分成一个个独立的组件,就像乐高积木一样。你看那个玩具挖土机,把铲子换成压路机的滚筒,它就变成压路机了;换成推土机的推板,它就变成推土机了。同一个基础底盘,配上不同组件,就能变出各种花样~ 🎮

这思想其实大家天天见!玩射击游戏自定义枪械的时候,加个三倍镜就是狙击枪,加个消音器就是微冲,这不就是组件化嘛!

核心思想:把物体的各种能力拆成独立、可插拔的组件,一个GO可以自由增删组件来实现不同功能。

咱们用无人机来重新理解一下:

  • Transform组件:管空间位置、位移,"我在哪儿"

  • Model组件:管模型外形,"我长啥样"

  • Motor组件:管移动属性,最快速度、加速度、惯性,"我能怎么动"

  • Health组件:管血量,"我有多抗揍"

  • AI组件:管行为逻辑,巡逻、追踪,"我要干啥"

  • Animation组件:管动画,"我怎么动才好看"

  • Physics组件:管物理碰撞,"我撞了会咋样"

把这些组件拼到一起,哎~ 一架无人机就出来了!想做查打一体无人机?简单!把AI组件换成AttackAI,再加个Combat战斗组件,齐活!✨

2.4 代码层面怎么实现? 💻

说穿了也很简单:

  1. 定义一个 ComponentBase 基类,统一所有组件的基础接口,必须包含一个 tick() 函数(后面会讲为啥)

  2. Transform、Model、Animation等所有功能组件都继承自这个基类

  3. 一个GO里面管理一组各种各样的组件,大家协同工作

cpp 复制代码
// 组件基类
class ComponentBase {
public:
    virtual void Tick(float deltaTime) = 0;  // 每个组件必须实现Tick
    virtual ~ComponentBase() = default;
};

// 具体组件
class TransformComponent : public ComponentBase { /* ... */ };
class ModelComponent : public ComponentBase { /* ... */ };
class HealthComponent : public ComponentBase { /* ... */ };

// 游戏对象
class GameObject {
    std::vector<ComponentBase*> components;  // 一组组件
public:
    void Tick(float deltaTime) {
        for (auto* comp : components) {
            comp->Tick(deltaTime);
        }
    }
};

2.5 商业引擎都是这么干的! 🏢

你去玩Unity、Unreal这些商业引擎,会发现它们全是这个路子:

  • Unity:点开任何一个物体,下面就是一长串组件,还能自己加组件、写脚本

  • Unreal:Actor就对应咱们说的GO概念,里面也是各种组件

注意区分:Unreal里的UObject不是咱们说的GO哦!UObject更像C#里的object,是用来管理生命周期、内存释放、GC的基类,是个底层句柄。真正对应GO概念的是Actor派生的那一系列东西,别搞混了~

2.6 继承 vs 组件化 大比拼 🆚

光说不练假把式,咱们来个直观对比:

对比维度 面向对象继承 组件化架构
直观程度 ⭐⭐⭐⭐⭐ 非常符合直觉 ⭐⭐⭐ 需要转变思维
代码复用 ⭐⭐ 父类强耦合 ⭐⭐⭐⭐⭐ 组件独立复用
扩展灵活性 ⭐⭐ 受限于继承树 ⭐⭐⭐⭐⭐ 自由组合拼装
多类型混合 💥 钻石继承灾难 ✅ 完美解决
性能优化 ⭐⭐ 数据分散 ⭐⭐⭐⭐⭐ 便于批处理
适用场景 简单小游戏、类型清晰 现代3A大作、复杂世界

表1:继承 vs 组件化全方位对比

一句话总结:游戏引擎的本质是生产力工具,要让开发者好维护、好理解,还要让艺术家和设计师用着顺手。组件化就是这么一个符合直觉、又极其灵活的设计,是现代游戏引擎的核心理念。


⏱️ 第三章:Tick循环------让世界"活"起来的秘密

3.1 Tick是什么? 🤔

好了,现在我们有了GO,有了组件,但是......这个世界是静止的啊!坦克开不起来,飞机飞不起来,跟个模型展似的,有啥意思?😅

怎么让世界动起来?答案就是------Tick

还记得上节课说的吗?游戏引擎最核心的一个函数叫tick,每隔1/30秒(或者1/60秒)就让整个世界往前走一步。就像真实世界里的普朗克时间一样------如果咱们生活在一个模拟世界里,那每个普朗克时间就是上帝给咱们设的tick。🕐

3.2 直觉方案:Per Object Tick 🏃

最直觉的想法是什么?每个GO依次tick,每个GO里的每个组件再依次tick。

比如一辆坦克:

  1. 先Tick Motor组件:速度10m/s,1/30秒就是0.03秒,往前挪30厘米

  2. 再Tick Animation组件:履带卷一下,主炮转一下

  3. 再Tick Combat组件:看看要不要开火

把整个游戏世界所有物体都Tick一遍,世界不就动起来了吗?完美!

这就是最直觉的 Per Object Tick 模式,每个对象自己把自己的事儿干完。

3.3 反直觉但更高效:Per System Tick 🏭

但是!现代游戏引擎一般不这么干。它们会把同类型的组件放一起,按系统批量Tick:

  1. 先把所有Motor系统全部Tick一遍:所有移动物体统一算位移

  2. 再把所有Controller系统Tick一遍:统一做物理碰撞检测

  3. 再把所有Animation系统Tick一遍:统一算动画

  4. ......以此类推

哎?这听上去有点反直觉啊!就好像说,一个人你不让他先动头再动手再动脚,你非得让所有人先一起动头,再所有人一起动手,再所有人一起动脚......这不是神经病吗?🤪

为啥要这么设计?答案就两个字:效率

3.4 流水线的魔力 🍔

给大家举个最简单的类比:做汉堡包。🍔

假设汉堡店有5个工人,最直觉的做法是什么?每个人从头到尾做一个汉堡------烤面包、烤牛肉、洗蔬菜、抹黄油、组合起来。一个香甜可口的汉堡就出炉啦~

但这样效率高吗?显然不高!

现代工业最核心的概念叫什么?Pipeline流水线啊!

最高效的做法是:有人专门烤面包,有人专门烤牛肉,有人专门洗菜,大家配合好,到点啪的一下合成一个汉堡。这才是效率最高的。

放到计算机上还有个更大的好处:数据局部性

图灵机小知识:还记得上节课讲的图灵机故事吗?在图灵机上效率最高的处理方式,就是把同样的数据尽可能放到一起,然后一次批处理完。无论读写都在一起,缓存命中率贼高,效率贼好!

这就是为什么高级课会讲ECS、DOTS这些架构------它们就是把这个思路做到了极致。

3.5 两种Tick模式对比 📊

咱们用图来直观感受一下两种模式的区别:

图1:两种Tick模式架构对比

一句话记住:造个流水线,批处理干活,效率就是高!就这么简单~ 😎


📬 第四章:事件机制------解耦交互的优雅方案

1 问题来了:GO之间怎么交互? 🤝

好了,现在世界能动了。但是......每个GO都在自顾自表演,坦克自己开,飞机自己飞,互相之间半毛钱关系没有,这叫啥游戏啊?😅

举个最简单的例子:我跳上坦克,朝远处敌人开了一炮,要把敌人击倒。那问题来了------我开炮这事儿,怎么让敌人那个GO知道自己被打了?

4.2 原始方案:硬编码Hard Code 🔨

最朴素的想法是什么?炮弹爆炸的时候,遍历周围所有物体,一个一个看:

  • 你是人?扣你血!

  • 你是飞机?扣你血!

  • 你是坦克?扣你血!

  • 你是石头?哦没事,你继续待着。

这就是所谓的Hard Code硬编码

大家别笑,早期游戏引擎真就这么写的。但是世界一复杂,这就崩了------每次加个新物体类型,你就得去所有爆炸逻辑里改一遍,维护起来简直是噩梦。😱

4.3 优雅方案:Event事件机制 📮

那怎么解?现代游戏引擎有一个非常优雅的机制------Event事件机制,也叫消息机制。

啥意思呢?咱们别那么粗暴,直接敲人家门说"你被我打了"。咱们换个方式:**写邮件!**📧

每个人家门口都放个邮箱,我不需要认识你,我只需要知道方圆20米内的邻居,给你们每家寄一封邮件。邮件内容是:"不好意思,我炸了,扣你100点血。"(这邮件叫blackmail,敲诈信,哈哈)😂

然后呢,下个tick的时候,你打开邮箱一看:"哦?我被扣了100点血?"然后你的Health组件一查,自己只有70点血,那好吧,只能死给你看了。💀

就这么简单!一个本来超级复杂的耦合问题,通过一个事件机制,瞬间变得清晰又干净。

4.4 这就叫解耦! ✂️

在系统架构里,这叫解耦

本来GO和GO之间通讯,需要知道所有其他GO的类型、每个GO里有哪些组件,太复杂了。现在统一变成事件机制,你只要发个事件给对应的GO,让它自己处理就完事儿了。

各个GO和组件之间的逻辑,干干净净,互不干扰。加新物体?不用改爆炸逻辑,只要给新物体加个事件处理函数就行。完美!👌

4.5 商业引擎怎么实现? 🏢

  • Unity:简单粗暴,用字符串匹配。注册一个叫"DAMAGE_EVENT"的事件,SendEvent就完事儿了。物体的Health组件收到事件,回调函数激活,自己扣血。

  • Unreal:复杂一些,用C++原生代码加反射机制。注册事件,绑定回调函数。好处是蓝图里也能用,可视化操作,策划也能上手。

引擎设计核心:做游戏引擎最核心的就是做一个可扩展的消息系统。让开发者能在引擎之上,不断定制和自己玩法相关的各种消息类型,再定制各种组件来处理这些事件------这就是现代游戏引擎最核心的工作。


🌳 第五章:场景管理------N²灾难的破局之道

5.1 新问题:GO太多了怎么办? 📈

等等,先别急着高兴。还有个问题:游戏世界里有那么多GO啊!

单机游戏里一般几百个动态GO,多的几千甚至上万个。那每次发生个事件,我怎么通知到这些GO?每次爆炸,我怎么找周围的物体?

咱们回到小明的战争游戏:NPC大兵、飞机、坦克、大炮......这么多东西,怎么管?

5.2 基础管理:UID + 位置 🆔

先讲两个最基本的概念:

  1. UID唯一编号:每个GO都有一个全局唯一ID,就像门牌号一样,用来标识定位物体。还记得上节课讲的GUID吗?一个道理。

  2. Position空间位置:每个GO都有个三维坐标,告诉我们它在哪儿。

有了这俩,我们就能开始做场景管理了。

5.3 最朴素方案:全遍历 ❌

最简单的管理是什么?不管理!😎

小明很粗暴:反正我也没几个兵,炮弹爆炸的时候,把场景里所有GO全部查一遍位置,判断是不是在爆炸半径内,是的话就发伤害消息。

这写行不行?做小游戏完全没问题,跑得动。但是!当场景里有几千上万个GO的时候,这就是一场灾难!

5.4 N平方的噩梦 😱

这就是游戏引擎里经典的N²挑战

什么意思?每个物体都可能和其他物体发生互动,如果每次都要和其他所有物体问一遍,那就是N×(N-1)≈N²次运算。

一万个物体的话,N²是多少?**一亿!**💥

这对计算机来说是巨大的负载,尤其如果数据还分散在内存各个地方,那效率低到没法看。

5.5 分而治之:画格子 📐

那怎么破?最简单的方法:画格子!

Divide and Conquer,分而治之。把整个世界画成均匀的格子,每个格子里放哪些GO我都记着。爆炸的时候,我只需要查爆炸所在的格子和周围几个格子就行了,工作量瞬间降下来!

这方法听上去土,但很多场景真的好用。如果场景不大、物体分布均匀,简单画格子就够了,又快又好写。

5.6 进阶方案:层级空间树 🌲

但是画格子有个问题:如果场景物体分布不均匀呢?

实话告诉大家,现代3A游戏里,看着世界很广阔,实际上玩家能走的地方非常受限。以前在国外做游戏的时候,这叫Trench战壕------设计师给玩家挖了很多条战壕,玩家只能在战壕里走来走去。战壕里的东西放得又密又细,战壕外面稀稀拉拉啥也没有。

这时候你均匀打格子,是不是又慢又浪费?

于是就有了更聪明的方案:层级结构空间树

啥意思呢?就像地图一样:整个世界很大,分成国家,国家分成省,省分成城市,城市分成街区,街区再分成街道。有事件发生在北京海淀区某条大街,那我只需要在北京海淀区那个小区域里找就行了,犯不着把全中国都搜一遍。🇨🇳

5.7 常见的空间数据结构 📚

数据结构 原理 适用场景 复杂度
均匀网格 世界均匀切分成格子 小型场景、物体分布均匀 O(1) 查找
四叉树(2D) 递归四等分空间,密集区细分 2D游戏、地面场景管理 O(log N)
八叉树Octree(3D) 递归八等分3D空间 3D空间、全空间管理 O(log N)
BSP二叉树 沿平面分割空间,常沿墙体 室内场景、FPS游戏 O(log N)
BVH包围体层次树 物体包围盒自底向上合并 现代3A主流、射线检测、视锥裁剪 O(log N)

表2:常见空间管理数据结构对比

咱们用图来看看四叉树是怎么工作的:

图2:四叉树空间细分示意图(红色区域为物体密集区,持续细分)

**怎么选?**看你的游戏类型。做个2D超级马里奥那种平台游戏,根本不需要复杂的场景管理。但做COD、战地这种3A射击游戏,那必须花心思好好设计,才能尽量节约计算资源。

对小明的战争游戏来说,用个四叉树或者BVH,基本就够用了。


🎯 总结:四大核心心法,速速收藏!

好了,讲到这里,今天的核心内容就差不多了。动手能力强的小伙伴,估计已经手痒痒想去写代码了吧?😏

咱们来总结一下,今天这节课你只需要记住四件事,就掌握了现代游戏引擎的核心逻辑:

万物皆GO 🎯

游戏世界里几乎所有东西,全部统一抽象成Game Object。无论是看得见的坦克飞机,还是看不见的触发器、游戏规则,全都是GO。

组件是GO的原子 🧩

每个GO由各种各样的组件组合而成,用组件拼装替代类继承,灵活扩展,完美解决多类型混合的问题。

Tick驱动世界运行 ⏱️

每一帧Tick一次,世界往前走一步。现代引擎采用按系统批量Tick的流水线模式,追求极致性能。

事件+空间树 📬🌳

事件系统实现跨GO交互,完美解耦;空间树结构管理海量游戏对象,规避N平方性能灾难。

就这四点,记住了,你就明白了现代游戏引擎的组合基础逻辑。是不是感觉自己离做出下一个3A大作又近了一步?🚀


💬 写在最后

其实游戏引擎这东西,说难也难,说简单也简单。很多核心思想,说穿了都是些很朴素的道理------分而治之、流水线、解耦......这些计算机科学的经典思想,换个场景换个包装,就变成了游戏引擎里的核心设计。

最重要的是什么?是理解这些设计背后的为什么。为什么要用组件化不用继承?为什么要按系统Tick不按对象Tick?为什么要有事件系统?想明白这些"为什么",你才是真的懂了,而不是死记硬背几个概念。

毕竟,引擎不是用来炫技的,它是个生产力工具。让大家方便、容易理解,才是引擎设计最底层的需求。

好啦,今天的硬核分享就到这里!如果觉得有帮助,别忘了**点赞👍 收藏⭐ 关注👀**三连一波,咱们下节课继续扒游戏引擎的那些事儿~

有啥问题欢迎在评论区交流,咱们一起学习一起进步!💪

--- EOF ---

相关推荐
旖旎夜光3 小时前
LeetCode 991: 坏了的计算器(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法
旖旎夜光4 小时前
LeetCode 553:最优除法(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法
Dr.kangder6 小时前
嵌入式处理器架构解析(七)——SPARC
架构·嵌入式·软件工程
oier_Asad.Chen6 小时前
【OI学习笔记】Floyed-Warshall算法解决传递闭包问题
c++·笔记·学习·算法·图论·最短路·传递闭包
zmzb01036 小时前
C++课后习题训练记录Day179
开发语言·c++
hansang_IR6 小时前
【题解】[COCI 2024/2025 #2] 流明 / Blistavost
c++·算法·动态规划·dp
不正经学生6 小时前
C语言指针进阶:const 和野指针——给指针加锁,向野指针宣战
c语言·开发语言·c++·算法·c#
程序喵大人6 小时前
【C++进阶】STL算法与函数对象 - 01 让算法去处理一段迭代器范围
开发语言·c++·算法·函数对象
爱勇宝7 小时前
《完蛋!我被男同学包围了》为什么会火?不只是因为“高中生玩票”
游戏·游戏开发