Unity 可配置鼠标指针与 UI 射线检测
在游戏开发中,使用鼠标指针与场景进行互动是很常见的需求。我们可能需要使用鼠标来选中场景中的物体,为主角选择一个移动目标点,或是一款建造游戏中玩家选择关卡中的某个点来放置建筑等;进一步地我们可能需要让鼠标悬浮在不同物体上时显示不同外观的光标,如鼠标悬浮在敌人上方时将光标显示为一把剑、悬浮在 UI 按钮上时改变光标颜色、悬浮在主角不可到达的位置时显示为一个红叉等。
本文将介绍一种实现可灵活配置光标的技巧,其能便于我们在制作 Unity 游戏时方便地配置不同场景下光标的外观,同时介绍检查鼠标是否悬浮 UI 控件上的方法。后者旨在系统性解决以往我和我的朋友们使用 Unity 开发游戏过程中,我们常常遇到的射线检测穿透 UI 导致 UI 点击事件和光标与场景交互事件相互干扰的问题。
最终效果
Unity 版本:2021.3.29f1
源码:
地址:https://wwit.lanzout.com/iQxWh16lfkcb
密码:5zm9
如上图所示,可以想象这是一个 RPG 或者 RTS 游戏的场景,玩家需要用点击 UI 或场景中的物体来指示主角或单位进行移动与战斗。在本例中,白色的 ...
GAMES 202 作业代码框架剖析
《GAMES202:高质量实时渲染》是由闫令琪老师开设的计算机图形学进阶课程。相比 GAMES 101,GAMES 202 不仅作业内容的难度更高,其代码框架也更难以理解。由于对代码框架、尤其是 WebGL API 的理解直接影响到完成作业的思路,并且 GAMES 202 代码框架也是使用 WebGL 封装简易图形渲染引擎的一次很好的实践,因此本文将对 GAMES 202 使用了 WebGL 的部分作业代码框架进行剖析,尝试解释代码框架中每一个文件、每一行代码做了什么,从而为更好更深入地理解和完成作业内容打下坚实基础。
WebGL 使用方法回顾
WebGL 是 OpenGL 的一个子集,是一套光栅化 API。浏览器在底层实现了 OpenGL 标准接口并在以 JavaScript 封装的方式提供给开发者使用,开发者首先通过 canvas 元素获取 WebGL 上下文对象,通过操作该对象上的 WebGL 接口并输出到画布上,从而实现各类渲染功能。
要在 WebGL 中实现渲染物体,比如渲染一个三角形,需要向着色器提供以下几类数据:
Attributes 和 Buffer:Buffer 通 ...
使用 TS-Check 针对 React/Redux 项目的渐进式静态检查指南
最近正在尝试在自己参与的 JavaScript 前端项目中引入静态类型检查。
至于引入的原因,很明显,源自 JavaScript 是一门【弱类型-动态类型】语言。这使得每次调用已写好的组件或者给已写好的组件打补丁时,都需要重新阅读相关组件的源代码、了解相关变量的类型,以确定可以在这些变量上调用哪些方法,然后再开始 Debug。肉眼检查代码很难完全发现和消除代码中的类型错误,这使得项目中频频出现 Cannot read property 'x' of undefined 或 xxx.map is not a function 等问题。这些 Uncaught Error 轻则使得某些功能无法使用,重则引起 React 引擎中断渲染,导致界面白屏(通常称为阻断性 bug)。此类 bug 往往需要很多时间进行排查,尤其是组件中存在异步事件时,bug 的修复将变得更加棘手。
更糟糕的是,当项目引入 Redux 进行状态管理时,在不使用 Redux Toolkit 的情况下,不论是 Selector、Reducer ,还是 Dispatch、Action ,它们的信息都分布在项目的其他目录里的若干 ...
HIT-软件构造 | 考前讲座 Lecture 03
By Von Brank | 2022/06/12
第 9 章 可复用性
概念
软件复用是什么?
两类软件复用:
面向复用编程:开发出可复用的软件
基于复用编程:利用已有的可复用软件搭建应用系统
为什么要复用:
降低开发时间和成本
让复用的组件得以经过充分测试,保证其可靠、稳定
实现组件标准化,令其在不同应用中保持一致
开发初期成本:复用 > 不复用;后期成本:复用 < 不复用
如何衡量可复用性?
复用的机会有多频繁?复用的场合有多少?
复用的代价有多大?
组件复用级别
复用的级别:
源代码级别的复用
模块级别的复用(类,抽象类,接口)
库级别的复用(API/包)
系统级别的复用(框架)
源码级别的复用
最主要的复用是代码层面的复用。
代码层面的复用中,以下内容都可能被复用:
需求
设计/规约spec
数据
测试用例
文档
两类源码级别的复用:
白盒复用:
源代码可见,可修改和扩展
黑盒复用:
源代码不可见,不能修改
只能通过 API 接口来使用
模块级别的复用(类,接口)
设计可复用类:
继承与重写
重载
参数多态性与泛型编程
行为子 ...
HIT-软件构造 | Java 函数式编程
函数式编程(Functional Programming)是编程范式的一种,常见的编程范式还有面向过程编程、面向对象编程(OOP)、面向数据编程(DOP)等。
程序设计语言发展的早期,人们将一段封装起来可供调用的代码块称为 “过程” 或 “函数” ;当函数绑定到对象上用于对象的操作时又被称为 “方法” ;有人始终认为编程语言中应该有真正数学意义上的函数,它应该是一种,对于确定的输入,有确定的输出、没有副作用的纯函数。
Lambda 表达式
函数式编程的特点之一是,它将函数视作变量,可以作为函数的参数值,也可以作为返回值。我们通常将作为变量的函数称为 “匿名函数” 或 Lambda 表达式。
在 Java 中如果我们要遍历这样一个列表:
1List<String> fruits = List.of("Apple", "Banana", "Orange", "Pear", "Grape");
可能会这样写:
123for(int i = 0; i< fruits.size( ...
HIT-软件构造 | Java 反射
在 Java 运行时,如果我们拿到一个 Object ,它可能是某个类的实例。如果我们想使用这个类的某个方法,却不知道这个类的名字,即连强制类型转换也做不了,那如何调用我们想要执行的方法呢。解决方案是使用 Java 反射。
Class 类与实例
如果我们有两个类 Type1 和 Type2 的实例,然后将其转换成 Object 实例。表面上我们看不出这两个 Object 实例的区别,因为我们对他们的信息一无所知,但是这只是因为他们的引用是 Object 类型的而已。
Java runtime 提供了一种数据类型,称为 Class ,Java 程序开始运行后,每次首次加载一个 class ,都会用这个 class 的信息创建一个 Class 实例,即这个 Class 实例将会包含这个类的所有信息。Object 类提供了一个接口能让我们拿到任何一个对象的 Class 实例。也就是说,对于上述的 Type1 和 Type2 转换成 Object 后的实例,我们可以拿到它们的 Class 实例,来区分这两个实例哪一个是 Type1 的实例、哪一个是 Type2 。
1234567891011c ...
HIT-软件构造 | 设计模式选讲
装饰器模式
假设我们要渲染一段 HTML 文本,HTML 可以标记文本的附加效果,比如一段加粗、加删除线的文本的 HTML 实现可以是:
1<del><b>Hello World</b></del>
效果: Hello World
当然,现代 Web 前端技术主张使用 CSS 实现这些样式。
实现类似附加效果最 naive 的方法可以是直接写一个类来实现:
1234567891011121314151617181920interface TextNode { String getText();}class BlackNode implements TextNode { private String text; public void BlackNode(String text) { this.text = text; } public String getText() { return "<b>&qu ...
HIT-软件构造 | Lab1 项目配置
⚠️ 警告:
本文所述内容仅能帮助你在 JetBrains IDEA 下以不修改代码框架中任何 package 命名的方式,优雅地完成实验内容,但注意到 实验指导-Lab0-3.3.4 中所述:
在提交至 GitHub 仓库前,请将实验代码从 Eclipse / IDEA 环境脱离开来,建议你自行使用 JDK、Ant (http://ant.apache.org)、Maven (http://maven.apache.org)、Gradle (https://gradle.org)等工具进行 build,或者在提交至 GitHub 仓库之后使用 Travis-CI (https://travis-ci.org)进行在线 build。如果因为缺少某些库文件导致你的程序无法运行,TA 不再为其评分。
这意味着完成实验后需要将基于 Eclipse / IDEA 的项目转换成某一通用的构建系统描述的项目,以应对 TA 可能采取的自动编译评测方式。
如果你已经熟悉 IDEA 的基本使用,本文后半部分会讲述如何将 IDEA 普通 Java 项目迁移至使用 Gradle 构建,可直接转跳阅读 ➡️ ...
【阅读笔记】深入理解计算机系统
计算机系统漫游
信息的处理及表示
2.1 信息存储
练习 2.2
nnn
2n2^n2n (十进制)
2n2^n2n (十六进制)
9
512
0x200
19
524288
0x80000
14
16384
0x4000
17 16
131072 65536
0x10000
17
131072
0x10000 0x20000
5
32
0x10
11
2048
0x800
练习 2.3
十进制
二进制
十六进制
0
0000 0000
0x00
167
1010 0111
0xA7
62
0100 0011
0x43
188
1011 1100
0xBC
55
0011 0111
0x37
1000 1000
1111 0011
52 5 ×\times× 16 +++ 2 === 82
0101 0010
0x52
0xAC
0xE7
练习 2.4
十六进制加减法,不得使用进制转换。
A. 0x503c + 0x8 = 0x5044
B. 0x503c - ...
【课程笔记】Udemy - The Complete JavaScript Course 2022: From Zero to Expert!
JavaScript 基础
数据、运算与判断
隐式转换
当运算符两端数据类型不同时,如 '1' + 2 ,若没有进行显式类型转换,则 JavaScript 解释器将对其做隐式类型转换。JavaScripit 的隐式类型转换常常让初学者感到疑惑,这是因为 JavaScript 不同基本数据类型之间没有明确的优先级关系,不存在所谓的“低级转向高级”,也不存在类似 C/C++ 的重载运算符操作;此外,优先级相同的运算符如 + 和 - 可导致截然不同的隐式转换逻辑。
即便如此,JavaScript 的的隐式转换规则仍然有迹可循。
+ 运算可将两侧变量隐式转换为 String 类型:
1"12" + 34; // -> '1234'
- 运算可将两侧变量隐式转换为 Number 类型:
1"12" - 34; // -> -22
<=, <, >=, > 可将两侧变量隐式转换为 Number 类型:
同级运算与隐式转换从左到右顺次进行:
15 + 6 + "4&qu ...