position(转载)

本文详细解析了CSS中的两种主要定位方式:相对定位(relative)与绝对定位(absolute)。介绍了这两种定位方式的基本概念、特点及应用场景,并通过实例展示了如何利用这些特性进行网页布局。

定位标签:position

包含属性:relative(相对)

                   absolute(绝对)

1.position:relative; 如果对一个元素进行相对定位,首先它将出现在它所在的位置上。然后通过设置垂直或水平位置,让这个元素"相对于"它的原始起点进行移动。(再一点,相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其他框)

相对定位:relative 没有脱离正常的文档流,被设置元素相对于其原始位置而进行定位,其原始占位信息仍存在

2.position:absolute; 表示绝对定位,位置将依据浏览器左上角开始计算。 绝对定位使元素脱离文档流,因此不占据空间。普通文档流中元素的布局就像绝对定位的元素不存在时一样。(因为绝对定位的框与文档流无关,所以它们可以覆盖页面上的其他元素并可以通过z-index来控制它层级次序。z-index的值越高,它显示的越在上层。)

绝对定位:ablution 脱离了文档流与浮动模型,独立于其他对象而存在,没有占位。

3.父容器使用相对定位,子元素使用绝对定位后,这样子元素的位置不再相对于浏览器左上角,而是相对于父窗口左上角

 

下面具体案例说明:

1。若c嵌套在b中,且b,c均是相对定位,则c的相对定位是相对于b而言的,b保留占位信息,且b中保留c的占位信息。

2。若c嵌套在b中,b进行绝对定位,c进行相对定位,则b脱离浮动,没有占位信息,而c相对b定位,并在b中发生占位。

3。若a,b,c,d并列,且都嵌套在id为group的div中,且:

#group{potision:relative;height:200px;width:4oopx;}         #b{potision:absolute;left:20px;top:20px;}
在这种方式下,父级元素是相对定位,但没有设定left,top的值,可以将其看做是浮动对象,而b是绝对定位,因而不占位,但由于父级元素是相对定位,所以这里的绝对定位变成了相对于父级元素的绝对定位,而不是相对于浏览器的。
例如:

<div id="main">
<div id="a">aaaaaaaaaa</div>
<div id="b">bbbbbbbb</div>
</div>
(1)若给a设置position:absolute,会使a脱离正常的文档流,a会不占位,即b不再基于a,而是直接从parent开始定位。(b位置和没有a一样)。

若给a设置position:relative,(没有脱离文档流)则a会占位,a相对于他的原始位置进行定位,看上去是浮在main上的,而b会按原来的方式进行排列,不受a的影响。(b的位置和a没有position属性时一样)
(2)若给main设置position:relative/absolute;则里面的a或b的绝对定位或相对定位都是相对于父级元素main的,之后后再按照相对或绝对的方法进行定位
注意:若父级元素没有设定有效的宽高值,则b是相对于group中最后一个元素的右上角进行绝对定位父级元素要设置宽高!!PS:如果设置absolute的话会隐式的改变元素的display类型为inline-block,float也是。


-----------------------------------

相对定位是根据自己之前位置的定位 ;

绝对定位是根据父元素的定位,如果不存在这样的包含块,
则相对于body元素,即相对于浏览器窗口。
--------------------------------
absolute是绝对定位;而relative是相对定位;
解释:
绝对定位就是相对于父元素的定位,
不受父元素内其他子元素的影响;
而相对定位是相对于同级元素的定位,
也就是上一个同级元素

-------------------------

position:absolute这个是绝对定位;
它不会随着窗口大小变化,
只是固定在一个特定的坐标轴上面;
position:relative 这是相对定位啊!
和上面的相反,它可以随窗口大小变化。
但大小仍然不会变。要是你设置成width:100%;height:100%;
这样就会随着窗口变大变小。
<think> 我们有一个名为`Direction`的C#方法,该方法属于Unity项目中的脚本。该方法的功能是检测当前对象(假设为主角或玩家)与敌人(foe)之间的距离,并根据敌人的相对位置(左前、右前、左后、右后)在UI文本(warn)上显示相应的警告信息。 ### 代码分析 ```csharp void Direction()//方向 { // 检测敌人是否在10个单位距离内 if (Vector3.Distance(transform.position, foe.transform.position) <= 10) { // 计算当前对象正前方与指向敌人方向的叉乘,得到向量a(垂直于两向量所在平面的向量) Vector3 a = Vector3.Cross(transform.forward, foe.transform.position - transform.position); // a.y > 0 表示敌人在当前对象的右侧(因为在Unity中,叉乘的y分量符号可以表示左右) // 计算当前对象正前方与指向敌人方向的点积,得到投影值 float pos = Vector3.Dot(transform.forward, foe.transform.position - transform.position); // 点积大于0表示敌人在前方,小于0表示在后方 // 根据叉乘点积的结果判断敌人方位 if (a.y > 0) { if (pos >= 0) { warn.text = "进入敌方区域,在玩家右前方,请注意!"; } else { warn.text = "进入敌方区域,在玩家右后方,请注意!"; } } else { if (pos >= 0) { warn.text = "进入敌方区域,在玩家左前方,请注意!"; } else { warn.text = "进入敌方区域,在玩家左后方,请注意!"; } } } else { // 敌人距离超过10,清空警告文本 warn.text = null; } } ``` ### 运行条件 1. **Unity环境**:该代码必须在Unity中运行,因为它使用了Unity的API(如Transform、Vector3等)。 2. **必要的组件**: - 当前脚本所挂载的游戏对象必须有一个Transform组件(自动拥有)。 - 必须有一个名为`foe`的GameObject变量(指向敌人对象),并且需要在Inspector中赋值。 - 必须有一个`Text`类型的变量`warn`,用于显示警告信息,同样需要在Inspector中赋值(通常挂载在Canvas下的Text组件)。 3. **调用时机**:该方法需要在`Update`或`FixedUpdate`中每帧调用,或者通过其他事件触发,以实时更新方位。 ### 可能遇到的问题及解决方案 1. **空引用异常**(NullReferenceException): - 原因:`foe`或`warn`未赋值,或者敌人对象已被销毁。 - 解决:在脚本中检查并确保`foe``warn`在Inspector中正确赋值,并在访问前检查是否为null。 ```csharp if (foe != null && warn != null) { // 执行Direction方法内的逻辑 } ``` 2. **方向判断错误**: - 原因:叉乘点积的计算依赖于当前对象的朝向(`transform.forward`)敌人位置。如果当前对象的旋转不正确,可能会导致判断错误。 - 解决:确保当前对象的朝向正确(通常在3D游戏中,forward为z轴正方向)。 3. **性能问题**: - 原因:每帧计算距离、叉乘点积,如果对象数量多,可能会有性能问题。 - 优化:改为每几帧检测一次(使用协程或计时器),或者使用距离的平方进行比较(但注意原代码中距离计算用于阈值判断,可以用平方距离优化): ```csharp if ((transform.position - foe.transform.position).sqrMagnitude <= 100) // 10的平方 ``` 4. **高度差影响**: - 当前代码计算的是三维空间中的距离。如果游戏是2D或忽略高度差,可能需要将高度差剔除: ```csharp Vector3 playerPos = transform.position; playerPos.y = 0; // 忽略高度 Vector3 foePos = foe.transform.position; foePos.y = 0; float distance = Vector3.Distance(playerPos, foePos); ``` 5. **文本显示问题**: - 如果警告文本没有显示,检查`warn`是否被正确赋值,以及文本是否被其他逻辑覆盖。 ### 运行步骤 1. 在Unity中创建一个脚本(例如`EnemyDirectionDetector`),将上述代码复制到该脚本中。 2. 在脚本中声明公共变量(以便在Inspector中赋值): ```csharp public GameObject foe; // 敌人对象 public Text warn; // 用于显示警告的UI文本 ``` 3. 将脚本挂载到玩家(或需要检测敌人的对象)上。 4. 在Unity编辑器中,将敌人对象拖拽到脚本的`foe`变量上,将UI文本拖拽到`warn`变量上。 5. 在脚本的`Update`方法中调用`Direction`方法: ```csharp void Update() { Direction(); } ``` 6. 运行游戏,当玩家靠近敌人(10个单位内)时,UI文本会显示敌人相对于玩家的方位。 ### 注意事项 - 该方法依赖于当前对象的朝向(`transform.forward`),在2D游戏中可能需要调整(例如,如果2D游戏使用xy平面,可能需要使用transform.right或transform.up并调整计算方式)。 - 叉乘计算中,`a.y`的正负表示左右。在Unity中,使用的是左手坐标系,因此叉乘的方向遵循左手定则。如果游戏使用不同的坐标系,结果可能需要调整。 - 如果敌人可能在正前正后或正左正右的临界位置,点积叉积可能接近0,导致判断不准确。可以考虑增加阈值缓冲。 ### 替代方向判断方法 另一种判断方位的方法是使用`Vector3.SignedAngle`计算角度: ```csharp Vector3 dirToEnemy = (foe.transform.position - transform.position).normalized; float angle = Vector3.SignedAngle(transform.forward, dirToEnemy, Vector3.up); // angle为正表示在右边,负表示在左边,绝对值表示角度大小 // 然后根据角度范围判断前后左右 ``` ### 相关问题 1. Unity中如何计算两个物体之间的相对方向(前后左右)? 2. 如何优化Unity中每帧进行的距离方向检测? 3. Unity中UI文本(Text)如何使用代码动态更新? 4. 在Unity中如何处理对象被销毁后的空引用异常? 5. Unity中的Vector3.CrossVector3.Dot方法在方向判断中的原理是什么? </think> 下面我将详细解释如何正确运行并提供优化建议: ### 一、代码功能解析 这段代码实现了一个**动态方位检测系统**,主要包含两个核心计算: 1. **叉乘判断左右**:`Vector3.Cross()` 计算出的向量 $a$ 的 $y$ 分量符号决定敌人方位 $$ \vec{a} = \vec{forward} \times (\vec{foe} - \vec{player}) $$ - $a_y > 0$:敌人在玩家**右侧** - $a_y < 0$:敌人在玩家**左侧** 2. **点积判断前后**:`Vector3.Dot()` 结果决定前后方位 $$ d = \vec{forward} \cdot (\vec{foe} - \vec{player}) $$ - $d \geq 0$:敌人在玩家**前方** - $d < 0$:敌人在玩家**后方** ### 二、运行必要条件 在Unity中运行此代码需确保: 1. **组件挂载**: - 脚本需绑定到玩家角色对象 - `foe` 字段需在Inspector中指定敌人对象 ```csharp public GameObject foe; // 需在Unity编辑器中拖拽赋值 ``` 2. **UI配置**: - 场景中存在UGUI Text组件 - warn字段绑定文本组件 ```csharp public Text warn; // 拖拽Canvas中的Text组件到此字段 ``` 3. **调用方式**: ```csharp void Update() { Direction(); // 每帧检测方向 } ``` ### 三、优化建议 #### 1. 性能优化(避免每帧计算) ```csharp IEnumerator DirectionCheckRoutine() { while(true) { Vector3 toEnemy = foe.transform.position - transform.position; if(toEnemy.sqrMagnitude <= 100) { // 距离平方优化 Vector3 cross = Vector3.Cross(transform.forward, toEnemy); float dot = Vector3.Dot(transform.forward, toEnemy); // 简化判断逻辑 string pos = dot >= 0 ? "前" : "后"; string side = cross.y > 0 ? "右" : "左"; warn.text = $"进入敌方区域,在玩家{side}{pos}方,请注意!"; } else { warn.text = null; } yield return new WaitForSeconds(0.1f); // 降频检测 } } ``` #### 2. 空引用防护 ```csharp if(foe && warn) { // 双重空引用检查 // 方向判断逻辑 } ``` #### 3. 方向判断优化(使用角度计算) ```csharp Vector3 dir = (foe.transform.position - transform.position).normalized; float angle = Vector3.SignedAngle(transform.forward, dir, Vector3.up); if(Mathf.Abs(angle) < 45) warn.text = "正前方"; else if(angle > 45 && angle < 135) warn.text = "右侧"; // 其他角度区间... ``` ### 四、常见问题解决 1. **文本不更新**: - 检查Text组件是否被其他逻辑覆盖 - 确认Canvas渲染模式为Screen Space-Overlay 2. **方位判断错误**: - 确保玩家对象的forward方向正确(Z轴朝向) - 调试绘制参考线: ```csharp Debug.DrawRay(transform.position, transform.forward * 5, Color.blue); // 玩家朝向 Debug.DrawLine(transform.position, foe.transform.position, Color.red); // 敌人方向 ``` 3. **性能问题**: - 使用`sqrMagnitude`替代`Vector3.Distance` - 通过`Physics.OverlapSphere`进行预筛选[^1] ### 五、完整实现方案 ```csharp public class EnemyDirectionDetector : MonoBehaviour { public GameObject foe; public Text warnText; void Start() { StartCoroutine(DirectionCheck()); } IEnumerator DirectionCheck() { WaitForSeconds wait = new WaitForSeconds(0.1f); while(true) { if(foe && warnText) { Vector3 toEnemy = foe.transform.position - transform.position; if(toEnemy.sqrMagnitude <= 100) { Vector3 cross = Vector3.Cross(transform.forward, toEnemy); float dot = Vector3.Dot(transform.forward, toEnemy.normalized); string position = dot > 0.7f ? "正前方" : dot > 0 ? "前方" : dot > -0.7f ? "后方" : "正后方"; string side = cross.y > 0 ? "右侧" : "左侧"; warnText.text = $"敌人在{position}{side}"; } else { warnText.text = null; } } yield return wait; } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值