《UE5_C++多人TPS完整教程》学习笔记14 ——《P15 创建我们自己的子系统(Creating Our Own Subsystem)》


本文为B站系列教学视频 《UE5_C++多人TPS完整教程》 —— 《P15 创建我们自己的子系统(Creating Our Own Subsystem)》 的学习笔记,该系列教学视频为 Udemy 课程 《Unreal Engine 5 C++ Multiplayer Shooter》 的中文字幕翻译版,UP主(也是译者)为 游戏引擎能吃么



P15 创建在线子系统

本节课将尝试创建我们自己的子系统类,并进一步探讨游戏实例子系统类的基本概念、工作原理及方式。
在这里插入图片描述


15.1 游戏实例和游戏实例子系统

  1. 在创建处理多人游戏会话的新类时,一个基本问题就是如何选择这个新类的父类。其中,一个不错的选择(Pretty option)就是游戏实例类:我们的游戏实例在游戏创建时生成,在游戏关闭之前它是不会被销毁的,当我们在关卡之间跳转时也持续存在。然而创建游戏实例类的主要功能并不是管理多人游戏会话(毕竟在前几课中我们在第三人称角色类也可以做到)。
  2. 游戏实例子系统类和游戏实例类相似,它可以和游戏实例类共存(Coexist along with)。我们可以在游戏实例子系统类中独立处理与多人游戏会话相关的功能。所以这里的重点是在游戏是里创建完成后创建一个游戏实例子系统类,在游戏实例关闭时将其销毁并进行垃圾回收。
    在这里插入图片描述

    虚幻引擎(UE) 中的子系统是生命周期受控(Managed lifetimes)的自动实例化类(Automatically instanced classes)。这些类提供了易用的扩展点(Extension points),程序员可直接获得蓝图和 Python 公开(Exposure),同时避免繁复的引擎类修改或覆盖(Avoiding the complexity of modifying or overriding engine class)。
    当前支持的子系统生命周期包括:

    子系统继承自
    引擎UEngineSubsystem
    编辑器UEditorSubsystem
    游戏实例UGameInstanceSubsystem
    本地玩家ULocalPlayerSubsystem

    举例而言,如果创建了一个派生自此基类的类:

    class UMyGamesSubsystem : public UGameInstanceSubsystem
    

    将出现以下结果:
    ① 创建 UGameInstance 之后,还会创建一个名为 UMyGamesSubsystem 的实例。
    UGameInstance 初始化时,将在子系统上调用 Initialize()
    UGameInstance 关闭时,将在子系统上调用 Deinitialize()
    ④ 此时将放弃(Dropped)对子系统的引用,如果不再有对子系统的引用,则其将被垃圾回收(Garbage-collected)。


    使用编程子系统有以下几个原因:

    • 子系统可节省编程时间。
    • 子系统使您无需覆盖引擎类。
    • 子系统使您无需在已经很复杂(Busy)的类上添加更多 API 。
    • 子系统使您能通过用户友好的类型化节点(User friendly typed nodes)来访问蓝图
    • 子系统允许访问 Python 脚本来编写编辑器脚本或编写测试代码。
    • 子系统在代码库中提供模块化和一致性(Modularity and consistency)。

    子系统在创建插件时尤为实用。您不需要代码相关的说明即可让插件工作。用户只需将插件添加到游戏中,就可以确切了解插件将在何时被实例化和初始化。因此,您可以专注于UE4中提供的API和功能的使用方式。


    GameInstance子系统

    class UMyGameSubsystem : public UGameInstanceSubsystem { ... };
    

    这些子系统可通过 UGameInstance 访问,如下所示。

    UGameInstance* GameInstance = ...;
    UMyGameSubsystem* MySubsystem = GameInstance->GetSubsystem<UMyGameSubsystem>();
    

    —— 虚幻引擎官方文档《编程子系统》


15.2 创建游戏实例子系统类

  1. 在虚幻引擎内容浏览器中展开目录 “C++类\MenuSystem”,添加一个新的游戏实例子系统 C++ 类。
    在这里插入图片描述
  2. 将新添加的游戏实例子系统 C++ 类命名为 “MultiplayerSessionsSubsystem”,选择模块为我们上节课新建的插件 “MultiplayerSessions (Runtime)”。
    在这里插入图片描述
  3. 点击 “创建类” 按钮,VS 中出现弹窗,选择 “全部重新加载(A)”。
    在这里插入图片描述
  1. VS 中可以看到解决方案资源管理器出现了头文件 “MultiplayerSessionsSubsystem.h” 和源文件 “MultiplayerSessionsSubsystem.cpp”;在虚幻引擎的内容浏览器中展开目录 “Plugins/MultiplayerSessionsC++类/MultiplayerSessions/Public” 也可以看到新建的游戏实例子系统 C++ 类 “MultiplayerSessionsSubsystem”(如果没看到,可能的解决办法是关闭虚幻引擎然后在 VS 中重新生成解决方案)。
    在这里插入图片描述
    在这里插入图片描述

  2. 在 “MultiplayerSessionsSubsystem.h” 中添加代码,定义游戏实例子系统类构造函数 “UMultiplayerSessionSubsystem()” 和在线会话接口智能指针 “SessionInterface”。

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Subsystems/GameInstanceSubsystem.h"
    
    /* P15 创建我们自己的子系统 */
    #include "Interfaces/OnlineSessionInterface.h"
    #include "OnlineSubsystem.h"
    /* P15 创建我们自己的子系统 */
    
    #include "MultiplayerSessionsSubsystem.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class MULTIPLAYERSESSIONS_API UMultiplayerSessionsSubsystem : public UGameInstanceSubsystem
    {
    	GENERATED_BODY()
    
    /* P15 创建我们自己的子系统 */
    public:
    	UMultiplayerSessionsSubsystem();
    
    protected:
    
    private:
    	// 会话接口智能指针
    	IOnlineSessionPtr OnlineSessionInterface;	// 添加头文件 "Interfaces/OnlineSessionInterface.h" 后使用,更具可读性
    	// TSharedPtr<class IOnlineSession, ESPMode::ThreadSafe> OnlineSessionInterface;	// 使用 TSharedPtr 智能指针包装器进行声明
    
    /* P15 创建我们自己的子系统 */
    
    };
    
  3. 在 “MultiplayerSessionsSubsystem.cpp” 中完善构造函数 “UMultiplayerSessionSubsystem()”,进行编译。

    // Fill out your copyright notice in the Description page of Project Settings.
    
    
    #include "MultiplayerSessionsSubsystem.h"
    
    /* P15 创建我们自己的子系统 */
    UMultiplayerSessionsSubsystem::UMultiplayerSessionsSubsystem()
    {
    	IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get();			// 获取当前的在线子系统指针
    	if (OnlineSubsystem) {													// 如果当前在线子系统有效
    		OnlineSessionInterface = OnlineSubsystem->GetSessionInterface();	// 获取会话接口智能指针
    	}
    }
    /* P15 创建我们自己的子系统 */
    

15.3 Summary

本节课探讨游戏实例类和游戏实例子系统类的基本概念、工作原理及方式,新建了我们自己的游戏实例子系统 C++ 类 “MultiplayerSessionsSubsystem”,并为该类定义在线会话接口智能指针 “SessionInterface”、完善了游戏实例子系统类构造函数 “UMultiplayerSessionSubsystem()” 。
在这里插入图片描述


  • 55
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下基于STC12C5A60S2芯片的MAX30102使用P15、P16引脚的代码,供参考: ```c #include <STC12C5A60S2.H> #include <intrins.h> #define uint8_t unsigned char #define uint16_t unsigned int #define uint32_t unsigned long #define bool bit #define true 1 #define false 0 #define SCL P1_5 #define SDA P1_4 #define ADDR 0xAE #define I2C_DELAY() _nop_() void delay_ms(uint16_t ms) { uint16_t i, j; for (i = ms; i > 0; i--) { for (j = 110; j > 0; j--); } } void i2c_start() { SDA = 1; SCL = 1; I2C_DELAY(); SDA = 0; I2C_DELAY(); SCL = 0; I2C_DELAY(); } void i2c_stop() { SDA = 0; SCL = 1; I2C_DELAY(); SDA = 1; I2C_DELAY(); } void i2c_write_byte(uint8_t data) { uint8_t i; for (i = 0; i < 8; i++) { SDA = (data & 0x80) >> 7; data <<= 1; SCL = 1; I2C_DELAY(); SCL = 0; I2C_DELAY(); } SDA = 1; SCL = 1; I2C_DELAY(); SCL = 0; I2C_DELAY(); } uint8_t i2c_read_byte(bool ack) { uint8_t i, data = 0; SDA = 1; for (i = 0; i < 8; i++) { SCL = 1; I2C_DELAY(); data = (data << 1) | SDA; SCL = 0; I2C_DELAY(); } SDA = ack ? 0 : 1; SCL = 1; I2C_DELAY(); SCL = 0; I2C_DELAY(); return data; } bool max30102_init() { i2c_start(); i2c_write_byte(ADDR << 1 | 0x00); //写I2C地址 i2c_write_byte(0x06); //写配置寄存器1 i2c_write_byte(0x03); //设置采样率为50Hz i2c_stop(); i2c_start(); i2c_write_byte(ADDR << 1 | 0x00); //写I2C地址 i2c_write_byte(0x07); //写配置寄存器2 i2c_write_byte(0x03); //设置LED1和LED2驱动电流 i2c_stop(); i2c_start(); i2c_write_byte(ADDR << 1 | 0x00); //写I2C地址 i2c_write_byte(0x08); //写配置寄存器3 i2c_write_byte(0x07); //设置LED3和LED4驱动电流 i2c_stop(); return true; } void max30102_read_fifo(uint32_t *red, uint32_t *ir) { uint32_t data; *red = 0; *ir = 0; i2c_start(); i2c_write_byte(ADDR << 1 | 0x00); //写I2C地址 i2c_write_byte(0x02); //写FIFO数据寄存器指针 i2c_stop(); i2c_start(); i2c_write_byte(ADDR << 1 | 0x01); //读I2C地址 data = i2c_read_byte(true) << 16; data |= i2c_read_byte(true) << 8; data |= i2c_read_byte(false); *red = data & 0x3FFFF; data = i2c_read_byte(true) << 16; data |= i2c_read_byte(true) << 8; data |= i2c_read_byte(false); *ir = data & 0x3FFFF; i2c_stop(); } void main() { uint32_t red, ir; P1M1 = 0x00; P1M0 = 0xFF; max30102_init(); while (true) { max30102_read_fifo(&red, &ir); //在这里处理红光和红外光信号 delay_ms(10); } } ``` 注意:以上代码仅供参考,具体实现可能需要根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值