前提:泛型变体是C#针对泛型接口/委托的特向,用于让泛型类型参数的继承关系能传递到泛型类型本身。已实现里氏替换原则。
例如:允许将IEnumerable赋值给IEnumerable,这就是协变。反之就是逆变。
一、铺垫1.泛型的不变性比如,Dog:Animal(Dog是Animal的子类),但是**List不是List**的子类。这就是泛型的“不变性”(Invariance)。
2.变体的规则
变体只适用于泛型接口/委托,类、结构体、方法的泛型不支持。就比如上述的List是类所以不变。
仅适用于引用类型,因为变体依赖于OOP的向上转型机制,所以值类型不知此变体。比如A不能复制给A。
二、变体的核心类型C#提供两个关键字用来声明变体:out(协变)和in(逆变)。
1.协变(Covariance):out1.要点:泛型类型参数只能作为返回值/输出,此时泛型类型能顺着继承链向上兼容(子类—>父类)。
**2.理解:**因为多态的特性,子类对象可以赋值给父类变量(向上转型)。返回一个父类对象时,可以返回子类。
3.示例:
1234567891011121 ...
CanvasCanvas(画布)是UI的基础,创建Canvas时也会自动创建一个EventSystem用于处理UI交互事件。
Canvas持有的组件如下:
Rect Transform是Transform的特殊实现,用于所有UI元素。
根组件:没有预制锚点,面板灰色无法控制。
子组件:有预制锚地,面白正常可以控制。
Base:(会更具Anchors的设置而改变)
Pos X/Y/Z:局部坐标,等同于Transform的xyz。
Width/Height:定义矩形的宽度和高度。
Anchors(锚点):子物体可以使用预制Anchors。
Min:确定锚点x/y值较小的位置。
Max:确地锚点x/y值较大的位置。
Pivot(旋转轴):控制UI物件的旋转轴和中心,值代表百分比。UI物件的坐标点。
Rotation:控制物件选择角度
Scale:控制缩放
Anchors特别的,Anchors是由四个小三角形组成的,用于锚定UI矩形相对其父物体的Transform。
UI矩形的每个角对应一个“小三角形”,UI矩形每个角 ...
前言
shaderlab是unity提供的一套着色器方案。使用HLSL语法,并包含一些CG的关键字和一些文件。
注:像素着色器 == 片元着色器
注:本文基本是CG风格写法
CG和HLSL的区别,CG能自动导入shader库。HLSL则需要手动导入。
语法ulishader框架如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879Shader "Pao/BasicGrammar" // 这时shader的名称,可用与表示shader,游戏程序可以通过名称找到这个shader。{ Properties { _MainTex ("Texture", 2D) = "white" {} ...
闭包是现代类型编程语言的特性,本文将从委托开始逐步深入闭包的原理。
前置知识Delegate(委托)12345678910111213141516171819// 定义private delegate void Myfunc(int a);// 使用delegate关键字定义委托,void表示返回值,int a表示参数;// 创建委托变量Myfunc myfunc;// 使用// 定义函数private void func(int a){ ...}// 赋值,不赋值Myfunc == nullmyfunc = func;// 调用myfunc(1);// 判断是否有值myfunc?.Invoke(1);
所谓委托,可以类似于C++的函数指针。可视为是函数的“容器”。可以看做是创建了一种类型。
Multicasting(多播)一个委托可以储存多个函数,当委托调用时。储存的函数会按照存储的顺序逐个执行。
1234567891011121314151617181920// 定义private delegate int Myfunc(int a, int b);p ...
VScode配置
最近在学习计算机图形学课程games101,课程是很好。课程提供了虚拟机以保证统一的环境,但是我最初觉得虚拟机还是太占内存了,就头铁的打算用VScode直接自己配置环境。不料,遇到了特别多的坑。反复折腾了几天终于搞定了环境配置。于是写下这篇博客做个记录。注:本博客仅讨论windows系统。默认你已经了解如何使用VScode编写基础c++代码。
下载OpenCVgames101的作业中使用OpenCV作为图像库,所以需要下载配置OpenCV。不过如果下载OpenCV的源码需要自己使用mingw编译。这一部分确实很麻烦,编译过程中还需要科学上网。所以我建议下载别人编译好的OpenCV,缺点是版本会落后一些。
下载OpenCV的.zip文件,自行解压
我使用的是OpenCV-4.5.2-x64,如果使用其他版本失败可以试试这个。
此链接直接下载OpenCV-4.5.2-x64.zip
配置系统变量这一步可以上网搜一下,很简单。可以新建一个变量,如OpenCV_Dll之类的。路径就是D:\cpp_lib\OpenCV4.5.2\x64\mingw\bi(用你自己的路径,这 ...
游戏控制器MusicManager.cs 音乐控制器
本项目很简单,所以音乐控制器也很简单
脚本代码如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182using UnityEngine;public class MusicManager : MonoBehaviour{ // 做成单例模式 public static MusicManager Instance { get; private set; } // 作为音量数据的key,使用PlayerPrefs存储 private const string MUSICMANAGERVOLUME = "musicManagerVolume"; // 在游戏对象上挂载的音频组件的引用 priv ...
Unity新版输入系统的事件重复注册问题最近在学习unity,边学别做了个小游戏。发现一个奇怪的bug,游戏在加载的时候会莫名其妙的报错,出现空指针异常。还会让我的ScriptableObject的文件失效。
反复测试发现,错误出现都是在场景加载的时候。进一步发现是在暂停回到主菜单后再次开始游戏的时候。
检查后发现是inputSystem的问题,这里是我的源码:
1234567891011private void Awake(){ instance = this; gameControl = new GameControl(); // 启动玩家控制 gameControl.Player.Enable(); gameControl.Player.Interact.performed += Interact_Performed; gameControl.Player.Operate.performed += Operate_Performed; gameControl.Player.Stop.performed += Stop_per ...
引言
这个游戏主要是练手之用,全程跟的siki的一个课程,游戏使用最新的unity6制作。
项目使用的技术主要有:unity物理引擎,射线检测,inputSystem,animation、animator组件,UGUI系统,shader Graph,场景转换等。
架构设计场景设计
游戏主要只有三个场景——开始界面、加载界面、游戏界面。
代码组织架构
Counter (各种柜台的功能实现)
play (玩家的各种控制)
UI (ui界面控制,和按键控制)
Manager (各种控制器,如音乐,音效控制器)
游戏流程
开始界面点击开始
进入加载界面
进入游戏场景 (整个游戏场景处了游戏结束阶段,都能随时暂停)
进入等待阶段
进入倒计时阶段
开始游戏 (游戏过程中存在游戏倒计时)
游戏结束 (弹出游戏结束ui,点击菜单按钮返回开始界面)
代码实现输入控制inputSystem
使用unity新版输入系统inputSystem。需要先在场景中创建一个空物体Gameinput用于挂载输入脚本。创建GameInput脚本,把他添加到场景中的空物体GameInput上 ...
前面我们为模组添加了物品,当时我们没有深入到物品的不同类别。
本期我们就来为模组添加食物和燃料,一个可以通过API添加,一个不能。让我们了解食物组件和mixin。
另外推荐B站的一位mod教程up主——北山_Besson,我写的这些心得也可以说是看教程的课堂笔记。
AModFoodComponents.java要添加食物就需要写一个食物组件。在注册物品的时候给物品添加这个组件就行了。
123456789101112131415161718public class AModFoodComponents { public static final FoodComponent 组件名 = // 这里hunger()代表回复的饥饿值。 // saturationModifer()表示回复的饱和度的影响参数。计算公式:饥饿值*参数*2。 new FoodComponent.Builder().hunger(4).saturationModifier(0.7F) // 这里为食物添加食用 ...
java文件
因为我的世界这款游戏其实需要很多json文件,但手动书写很容易出现错误。所以fabric提供了数据生成类,用来实现自动生成json文件。减少工作量,避免出错。
注意:以下的文件生成类的类名没有要求,但建议起一个意义明确的名字。
AModBlockTagProvider.java此文件用于生成方块的tag数据。
12345678910111213141516171819202122public class AModBlockTagsProvider extends FabricTagProvider.BlockTagProvider { // 此类需要继承fabric提供的抽象类,并实现以下方法。 public AModBlockTagsProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) { super(output, registriesFuture); // su ...

