游戏引擎学习第294天:增加手套

news2025/5/20 22:12:47

准备战斗

我们正在进行的是第294天的开发,目前暂时没有特别确定要做的内容,但我们决定继续研究移动模式相关的部分。虽然一些小型实体系统已经在运行,但并不确定最终效果如何。

今天我们决定实现一个全新的功能:战斗系统。这是游戏中的一项核心机制,此前我们只在早期简单尝试过类似“投掷剑”的效果,尚未真正地把攻击机制整合进来。现在,借助已有的“脑系统”,实现起来会更容易一些。

首先检查一下当前的状态,一切运行正常。我们角色可以跳跃、移动,但敌人蛇形实体太长了,不利于调试,因此将它们缩短以便测试。我们的目标是让主角可以攻击这些敌人。

我们已经有一些基本的实体属性,比如血量,玩家和敌人目前都有3点生命值,用小红块表示。敌人移动速度目前太快,之后需要调整。但首要任务是:让玩家可以攻击敌人

为此,我们设计了一个机制:

  • 玩家角色会有一个“魔法手套”作为攻击的实体
  • 这个手套是一个独立的实体,浮动在玩家身体附近。
  • 攻击通过按下方向键发起,方向决定攻击的朝向。
  • 移动仍由WASD控制,方向键专用于攻击。
  • 手套会在攻击时做出类似“弧线滑动”的动作,也就是一次快速的挥击。
  • 不同类型的手套未来可以带来不同的攻击方式,目前先做一个基础版本。

为实现这一点,我们计划:

  1. 添加一个手套实体,并让它始终跟随玩家身体部分的位置,而非像头和身体那样分离运动。
  2. 设置该手套在不攻击时静止悬浮在身体旁边,攻击时执行快速的滑动动作。
  3. 可能加入模糊效果或粒子特效,表现出手套滑动时的“轨迹”或“能量感”。
  4. 后续还可通过更换手套种类带来不同视觉风格或攻击效果。

我们在程序中会从 AddPlayer 函数开始着手,为角色添加这个手套实体。这是整个战斗系统开发的第一步。

总之,今天的目标是实现攻击系统的雏形,为后续的战斗逻辑、碰撞检测和动画表现打下基础。通过这个“魔法手套”,玩家将能主动参与战斗,打击敌人,并进一步推动游戏机制的完善。

game_world_mode.cpp:让 AddPlayer 初始化一个手套并调用 AddPiece 添加它

我们现在要实现“魔法手套”实体,并且可以看到代码中还保留了许多之前的残余设置,比如碰撞器(Collider)相关的标志位。这些旧的标志和碰撞逻辑现在已经到了该被重新整理和规范的时候。

目前的碰撞系统有些混乱,比如有些实体设置了碰撞器却不会参与碰撞,这种设定可能本身就是冗余的。如果实体不会发生碰撞,那它压根就不需要一个碰撞组件。而如果存在某些特殊情况,比如一个实体只在另一方有碰撞标志时才参与碰撞,可能又需要一种更复杂的双向判断逻辑。

不过现在我们已经具备了足够多的系统组件和实体行为逻辑,可以正式对这些碰撞标志的意义做出清晰定义,并决定哪些是必须保留的,哪些可以舍弃。

接下来,手套作为新的实体需要被添加进游戏世界中,并且被指定一个“思维槽位”(brain slot),它的类型为“Hero Glove”,并且会与主角共享一个脑ID,表示它是由主角的逻辑系统控制的。

除了设置基本的实体参数之外,我们还需要为它指定一个图形资源。我们检查了一下现有的素材资源包,在 file formats 中找到了一些可以使用的资源:比如影子(shadow)、树(tree)、石头(rock)、草丛(grass_tuft)、地砖(stone)、头部(head)、披风(cape)、字体(font)等等。

虽然理想状态下我们希望使用一个专属的手套资源,但在没有专用资源的情况下,临时用“石头”图形来代替手套。这其实是之前我们也用过的一个方法,所以目前继续采用。我们会复制一份“石头”资源,让它作为手套的临时代替物。

完成资源指定之后,我们将这个“手套实体”生成在主角附近,处于主角身体旁边,并浮在地面以上,具体高度和悬浮逻辑后续再调整。

至此,英雄的手套实体已经创建完毕,具备独立的逻辑控制能力、可以参与碰撞系统(或不参与,取决于最终定义),并带有图形资源用于可视化展示。接下来还需要进一步完善攻击时的动作表现和手套与主角之间的动态位置同步逻辑。

在这里插入图片描述

在这里插入图片描述

game_brain.h:在 brain_hero 中添加手套

我们需要在大脑系统(brain system)中为手套预留一个槽位,因为主角需要能够“感知”自己的手套。手套的行为应该由主角的逻辑控制器统一管理,因此手套必须作为主角的一个附属组件存在于其大脑逻辑结构中。

接下来也注意到了碰撞相关的处理。当前有一类叫做“身体碰撞”(body collision)的设置,暗示手套或其他部位可能会与游戏世界发生物理交互。我们需要明确这些实体的碰撞属性,比如:

  • 手套是否参与与怪物的碰撞;
  • 手套是否与主角自身发生碰撞;
  • 手套攻击时是否临时开启碰撞检测;
  • 是否手套的碰撞逻辑只在攻击动作执行时才生效。

这一切意味着我们需要在设计碰撞逻辑时更加细致,可能为不同类型的碰撞行为设置更明确的标志和状态条件。例如:

  • 正常状态下手套漂浮在主角身边,不参与任何碰撞;
  • 攻击触发时,临时启用其与敌人的碰撞检测,用以判断是否命中;
  • 攻击结束后,重新关闭碰撞状态,回到普通漂浮逻辑。

总之,现在是理清和统一碰撞系统的绝佳时机,确保逻辑清晰、实体行为一致。手套不仅仅是一个视觉效果的装饰物,它还将成为游戏中重要的战斗工具,必须在逻辑上与主角行为严密绑定,并具备独立交互能力。
在这里插入图片描述

game_world_mode.cpp:让 PlayWorld 设置手套不发生碰撞

我们现在还不确定手套的碰撞行为会如何发挥作用,因此目前先以一个占位实体(dummy)来处理,后续再根据实际需要进行完善。我们之所以需要这样做,是因为最终必须能够判断手套是否与其他对象发生了碰撞,比如敌人,这对于攻击逻辑非常关键。

系统中有一项设计约束:在构建实体时,资源注册(例如图形资源)必须按照相同的顺序进行“开启”和“关闭”。我们之前为此添加了一条断言(assertion),很好地帮助我们捕捉到了顺序不一致的问题,否则这个容易被忽略的细节可能导致运行时异常。也就是说,在创建手套实体的时候,资源注册必须是成对对称进行的,先打开、再关闭,顺序必须一致。

接着我们检查了当前是否正确加载了实体资源。发现手套目前设置的图形资源是“rock”(岩石),但似乎该资源并不存在,导致无法显示。于是我们尝试改用“sword”(剑)资源来代替。初步加载后发现显示的剑太大了,显然不适合作为手套的表现资源,所以我们调整其显示大小,使之更合理,最终成功让一个代表手套的图形出现在主角旁边。

此时,虽然图形上看起来只是一个“愚蠢的石头”在漂浮,但它已经作为手套的初步实体被创建出来并显示出来了。下一步,我们的目标是让这个手套实体能跟随主角的位置,并在我们按下方向键时执行“挥击”动作。

这意味着我们要:

  • 在游戏逻辑中让手套保持和主角同步的相对位置;
  • 监听方向输入,在接收到攻击命令时,驱动手套执行一次带有动画的挥击行为;
  • 同时配合碰撞检测判断是否击中目标。

这是我们正式开始实现手套攻击系统的关键一步。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

game_brain.cpp:让 ExecuteBrain 将手套放置在英雄身体旁边

我们需要为英雄的大脑(brain)系统添加逻辑,让手套根据英雄的朝向正确地出现在身体旁边。具体来说,我们需要在 game_brain.cppExecuteBrain 函数中,对手套的位置进行设置,使其随着英雄移动并保持在身体某个固定偏移的位置。

首先,在大脑逻辑中,我们可以通过实体部分(entity parts)获取与英雄关联的手套实体。如果存在手套实体,我们就可以对其进行位置更新。

我们的做法是:当英雄存在手套时,查询身体(body)的位置,并基于该位置设置手套的位置。手套应当相对身体保持一个固定的偏移。例如:

gloveP = bodyP + V3(0.5f, 0.0f, 0.5f);

初始设置中,我们将手套放在身体的右上方。偏移暂时为常数,只为了让手套在视觉上出现在合理位置。之后,我们希望该偏移能根据角色的朝向方向(facing direction)动态变化,从而使手套始终出现在角色面朝的那一侧。

目前,角色的朝向是以一个标量角度(angle)表示的。在逻辑中,我们可以直接使用这个角度,通过正余弦函数来计算偏移方向,从而实现让手套根据角度进行位置调整。这种方式可以让手套在角色旋转时自然地环绕主角,比如从右侧顺时针转到左侧时,手套会动态地随着朝向变化而移动。

测试中,我们先使用固定偏移值,观察手套是否随角色位置移动,确保基本逻辑可行。结果显示:手套实体能够跟随身体实体同步移动,并保持在身体一侧,位置也基本合理。如果我们日后替换为真正的手套图形资源,它将漂浮在主角旁边,看起来会更加自然。

总结目前阶段完成的内容:

  • 在大脑系统中添加了对手套实体的控制逻辑;
  • 获取主角朝向和身体位置;
  • 使用固定偏移将手套放置在身体一侧;
  • 验证了手套实体随主角移动而漂浮的效果;
  • 为后续实现基于朝向角度的动态偏移打下基础。

接下来计划:将固定偏移改为根据朝向角度自动计算,并逐步实现挥击动作逻辑。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

game_brain.cpp:让 ExecuteBrain 根据英雄的朝向偏移手套位置

我们当前的目标是让手套根据角色的朝向自动出现在正确的位置。为实现这一点,我们从角色当前的朝向角度出发,构建一个面向该角度的向量,并将其用于计算手套在 XY 平面上的偏移量。我们计划将这个偏移向量加到身体位置上,再加上一个用于高度浮动的 Z 轴偏移量,从而确定手套的三维位置。

目前角色的朝向是一个标量角度值(以弧度计),我们已经有了一个用于从该角度构造单位向量的方法。具体做法如下:

  • 获取角色身体的朝向角度;
  • 使用三角函数计算出这个角度所对应的二维单位向量(cos(angle), sin(angle)),这个向量指向角色面对的方向;
  • 使用这个单位向量乘以一个长度值(如 0.6)来作为手套的水平方向偏移;
  • 垂直方向(Z 轴)上的偏移仍需确定,目前尚未最终确定 Z 轴渲染和深度处理的方案。

在 Z 轴问题上,我们之前反复调整了许多次深度偏移规则和渲染顺序,但始终没有形成最终规范。现在借由“手套”的例子,正好是推动我们彻底完成 Z 高度和碰撞系统设计的好时机。我们可以把这两个长期悬而未决的核心系统——Z轴定位规范碰撞检测系统——作为当前阶段的开发重点,彻底定下来。

于是我们接下来实现了两个变量 armXarmY,它们代表手套相对于角色朝向的横向偏移。这种做法允许我们根据朝向自动调整手套在角色身体的哪一边。

总结本阶段关键进展:

  • 从角色朝向角度生成面向向量;
  • 利用该向量计算手套的 XY 平面偏移;
  • 计划结合 Z 轴偏移,使手套在 3D 空间内正确悬浮;
  • 意识到当前碰撞系统和 Z 渲染系统尚未完善,并决定以此为契机推进这两个系统的最终确定;
  • 为手套系统引入了一个与角度关联的动态偏移逻辑,后续可以结合动画或交互进行拓展。

下一步将继续完善 Z 轴处理逻辑,并将碰撞系统与实体状态更好地结合。
在这里插入图片描述

之前忘记加2Pi

在这里插入图片描述

黑板讲解:计算相对于朝向角度的角度

我们正在实现一个系统,让手套可以根据角色的朝向自动出现在其身体的侧面。为此,我们首先明确了角色朝向角度的表示方式。我们使用标准的弧度制将角色面朝的方向表示为一个角度,其中:

  • 面朝正右为 0 弧度(0 度);
  • 面朝正上为 π/2 弧度(90 度);
  • 面朝正左为 π 弧度(180 度);
  • 面朝正下为 3π/2 弧度(270 度);
  • 也可以用 τ(tau,等于 2π)来表示整圆,以 1/4 τ、1/2 τ、3/4 τ 来标记四个象限。

为了使手套始终位于角色身体的一侧(例如角色的右手边),我们不能直接使用角色的面朝方向来决定手套的偏移方向。因为直接使用当前朝向会让手套出现在面朝的正前方,而这不是我们想要的效果。

为了解决这个问题,我们将角色当前朝向角度加上 3/4 τ(即 270 度),这个角度偏移可以把手套从正前方转移到角色的右侧位置。

验证方法如下:

  • 首先关闭这个角度修正,可以看到手套出现在角色正前方;
  • 添加 3/4 τ 的偏移后,手套会自动移到角色的右边,不管角色转向哪个方向,手套始终在其一侧。

然后我们调整了手套的距离。默认情况下,单位偏移长度是 1 个单位,但这让手套看起来距离角色太远了。因此我们将其调整为约 0.5 个单位,让手套更贴近角色身体,使视觉上更加合理。

总结本阶段的关键内容:

  • 使用弧度表示角色朝向,并以 τ 为单位对角度进行统一理解;
  • 通过加上 3/4 τ 的方式,让手套始终出现在角色的右侧;
  • 视觉验证了修正是否正确;
  • 进一步优化偏移长度,让手套距离角色合适,不显得突兀。

下一步可能会继续细化这个偏移逻辑,例如根据角色的动画状态或动作动态调整位置,同时也可以引入高度的 Z 偏移。

运行游戏并看到“手套”出现

现在我们已经实现了让“手套”(目前是一个临时用的奇怪岩石模型)固定在角色身体侧边的位置,并随着角色的朝向变化而同步调整其相对位置。随着角色移动或旋转,手套的位置也会随之更新,效果上已经达到了“装备在身侧”的视觉需求。

下一步我们要实现的是让这个“手套”能够进行挥击攻击——即进行一个弧形的攻击动作,并且需要实现与其他物体的碰撞检测,判断是否击中了目标,例如角色面前的某个敌人或物体。

我们已经具备了一些基础数据来支持这一功能。当前在系统中已经存在与武器使用方向相关的输入数据,之前为剑攻击设定的方向被称为 dSword,表示玩家在特定时刻试图攻击的方向。这一变量可以用于确定当前的挥击方向,也能帮助我们得知角色当下的朝向。在设置角色朝向时,我们已经将该方向输入转换为角度,并用于计算朝向向量。

不过,这里存在一个潜在的低效处理方式:我们是先通过 atan2 将方向向量转换为角度(用于处理角色面朝方向),然后在使用该角度时又使用 cossin 重新将其转换回向量。也就是说,方向数据从向量变为角度后又还原为向量,形成不必要的重复计算。但由于当前主要聚焦在功能实现上,这个效率问题暂时不会处理。

总之,当前阶段我们得到了如下关键点:

  • 已实现手套模型跟随角色并根据朝向摆放;
  • 准备实现攻击时的挥击动作;
  • dSword 变量记录了攻击输入的方向,可用于驱动挥击行为;
  • 已知角色当前朝向并能进行角度计算;
  • 后续需要实现碰撞系统来判断是否击中敌人或物体;
  • 存在一定的角度与向量来回转换的低效逻辑,未来可优化。

下一步的工作包括构建一个真实的攻击轨迹,并在攻击过程中实时检测碰撞,判断是否命中目标实体。这样角色挥动“手套”时才能造成有效打击反馈。

game_brain.h:为 entity_movement_mode 添加 MovementMode_AttackSwipe(攻击挥击模式)

我们现在要实现一个“挥击”动作,也就是控制手套进行一次攻击性地挥动。这是一个与角色运动模式(movement mode)相关的行为,类似于之前已有的“跳跃”机制,但这次是“攻击”或“挥击”而非移动穿越区域。

我们已经定义了实体的“运动模式”,接下来计划增加一种新的模式,比如叫做 swipeattack,用于表示当前处于攻击动作中。在进入这种状态后,手套将在一段时间内锁定,不能立即重新挥击,也不能改变攻击方向,直到当前的攻击动作自然完成。这种设计避免了玩家快速连击造成的不自然视觉效果,并符合实际战斗中的“攻击需要时间”这一设定。

为了实现这一机制,我们准备将手套实体设置成攻击模式。期间,该手套将执行一个弧形轨迹的挥击动作。虽然它不像跳跃那样会占用新的空间区域或移动位置,但依然需要类似的逻辑处理来驱动动作流程。

此外,我们还提到了一个结构性改动的可能性。目前处理运动模式逻辑的相关代码可能集中在某些特定的地方(如 brain 模块),但其实这些逻辑本质上属于通用的实体行为,完全可以被提取到通用的实体模拟代码中,比如 simulate_entity。这样做可以统一实体行为管理逻辑,提高代码模块化程度,使后续添加更多动作模式(如游泳、攀爬、翻滚等)时更加容易。

尽管当前还未决定是否进行这个重构,但明确这一方向是为了后续开发的清晰性和可扩展性。

总结当前核心内容:

  • 准备新增一种实体运动模式用于挥击攻击;
  • 挥击动作为一个时间段内的弧形运动,过程中无法再次挥击或改变方向;
  • 攻击行为与跳跃机制类似,受限于动作时间;
  • 当前的代码可能迁移至通用的实体逻辑处理区,以实现更好的架构分离;
  • 接下来将开始具体实现该挥击行为的轨迹模拟与状态控制。
    在这里插入图片描述

在这里插入图片描述

game_world_mode.cpp:在 UpdateAndRenderWorld 中实现 AttackSwipe

现在我们为实体增加了一种新的运动模式,即“攻击挥击模式”(attack swipe mode)。在这模式中,实体(此处为手套)执行一次攻击性动作,该动作类似跳跃模式的处理流程,即在特定的运动周期结束后返回到默认的“站立模式”(planted)。

整个逻辑设计如下:

  1. 进入挥击模式:
    一旦某个条件触发攻击(例如玩家按键操作),我们将实体的 movement mode 设置为 attack_swipe,进入挥击状态。

  2. 处理挥击状态:
    当实体处于 attack_swipe 模式时,会执行一个特殊的轨迹行为。这类似跳跃的处理流程,即:

    • 判断是否仍处于攻击动作期间(通过某种参数化方法确定,类似 T movement phase);
    • 若攻击动作完成,则将 movement mode 设置回 planted,即恢复为静止状态;
    • 若仍在攻击中,则继续执行挥击轨迹更新逻辑。
  3. 参数化攻击轨迹:
    现在我们需要一种机制来定义挥击动作的轨迹参数。也就是说,挥击应该遵循某种“弧线”或“圆弧路径”,而不是线性移动。这需要设计一套参数,用来描述当前挥击处于整个动作的哪一阶段(例如起始点、中间、结束点等),以便正确地更新实体位置。

  4. “came_from”参数问题:
    提到了当前系统中某些参数,比如 came_from 可能已经不再合适。因为攻击动作本身并不是“从一个地方跳到另一个地方”的移动逻辑,而是一种“原地弧形运动”,因此像 came_from 这样描述位置变更的属性,在此上下文下可能不适用,未来可能考虑移除或替换。

  5. 轨迹实现策略:
    下一步关键任务就是确定如何参数化挥击轨迹,比如:

    • 使用角度与半径定义圆弧路径;
    • 根据时间线性或非线性插值生成挥击轨迹;
    • 将挥击路径的控制权交由一个专用函数,根据当前“攻击帧”或“进度”来更新位置;
    • 与碰撞检测系统集成,在轨迹范围内感知是否打中了敌人或其他对象。

总结要点:

  • 添加了新的 attack_swipe 运动模式;
  • 模式内执行一次弧形运动并限制再次发起攻击;
  • 动作结束后重置为 planted 模式;
  • 正在设计参数化的攻击轨迹机制;
  • 某些旧的状态参数(如 came_from)已不再适用;
  • 下一步是实现轨迹模拟与碰撞响应联动机制。

在这里插入图片描述

黑板讲解:参数化挥击弧线

我们现在要实现的是手套进行左右交替的挥击动作,即每次攻击时,手套从身体一侧划向另一侧,下一次攻击时再从另一侧划回来,形成“左-右-左-右”的攻击节奏。

当前的处理方式是:

  1. 明确动作方向与方式:
    攻击挥击是一种围绕角色身体某个轴心(可能是身体中心)的相对空间的旋转运动。因此手套的运动不是简单的线性移动,而是围绕主角进行的一段“弧形插值运动”。

  2. 定义左右切换:
    每次攻击应该记录当前挥击是向左还是向右,并在下次攻击时自动切换方向,从而产生交替的挥击效果。这个逻辑将形成一个简单的状态切换系统:

    • 初始状态为向一侧挥击;
    • 每次攻击完成后将方向状态切换;
    • 下次攻击根据该状态决定挥击路径。
  3. 参数化角度插值:
    在攻击挥击模式中,使用一个时间因子 tMovement 来控制动作进度,从 0 到 1 表示一次挥击的全过程。使用该进度值去插值起始角度和结束角度,从而形成顺滑的旋转轨迹。例如:

    angle = Lerp(startAngle, endAngle, tMovement);
    

    然后用这个角度再通过正余弦计算出手套当前应该处于的偏移向量:

    offset.x = cos(angle) * radius;
    offset.y = sin(angle) * radius;
    
  4. 保持可复用性:
    虽然这种运动轨迹和逻辑可以抽象为一个可重用的攻击动作模块,但当前还是优先选择直接硬编码实现逻辑,之后再逐步提取出通用机制。这种做法可以快速验证效果,也便于在视觉表现上调试优化。

  5. 后续扩展方向:

    • 可以为每次攻击设定一个 swipeSide 状态,控制是向左挥还是向右挥;
    • 还可以引入速度调节参数,影响插值速率;
    • 进一步整合碰撞检测模块,在挥击路径上检测是否命中目标;
    • 将该系统封装为组件或行为模块,供其他实体使用。

总的来说:

  • 挥击动作采用角度插值控制;
  • 每次攻击方向左右交替;
  • 插值角度用来生成当前帧的偏移;
  • 当前阶段使用硬编码快速实现;
  • 未来考虑封装为通用攻击组件。
    在这里插入图片描述

在这里插入图片描述

game_entity.h:为实体添加 SwipeAngleStart 和 SwipeAngleTarget

在实体的移动机制中,会包含关于挥击动作的角度参数,比如挥击的起始角度(swipe angle start)和目标角度(swipe angle target)。在挥击过程中,角色的朝向是固定的,即使玩家按了不同的方向键,朝向也不会发生变化,保证挥击动作的连贯性和稳定性。

挥击角度会在起始角度和目标角度之间插值,形成从一侧到另一侧的平滑挥动效果。这样设计的目的是让挥击动作既明确又流畅,不会因为输入变化导致挥击姿势混乱。

虽然目前对代码结构和放置位置还没有完全确定,整体思路是让挥击相关的代码随着开发进展逐步自然地稳定下来,便于后续维护和调整。当前还在观察和评估这种设计是否合理,以及是否适合敌人或其他实体的行为逻辑。

总结来说:

  • 挥击的起始角度和目标角度作为参数存在;
  • 角色朝向在挥击过程中保持不变,确保动作稳定;
  • 挥击角度在两个值之间平滑过渡;
  • 代码结构和设计仍在不断调整和完善中,追求合理的代码组织和复用;
  • 设计过程带有一定试错和反复优化的性质。

game_entity.h:为 entity_movement_mode 添加 MovementMode_AngleOffset 和 MovementMode_AngleAttackSwipe

我们考虑用攻击挥击模式来控制手臂的位置,设计一个相对于角色朝向的角度偏移和挥击角度。这个挥击角度会基于当前面向方向,通过插值逐渐变化,实现挥击动作的平滑过渡。

具体来说,我们会设置一个“角度偏移”的移动模式,作为手臂(比如手套)的初始定位方式。手臂的朝向默认和身体的朝向保持一致,这样手臂总是跟随身体方向对齐。在攻击挥击阶段,会将手臂的当前角度从起始角度插值到目标角度,通过一个参数(比如tMovement)来控制插值进度。

实现上,手臂实体的位置(entity P)是基于身体的位置再加上根据当前朝向和角度偏移计算出来的相对位移。这个位移会动态调整,反映挥击动作的弧线轨迹。

挥击动作期间,手臂的朝向不会随玩家按键方向即时改变,直到挥击动作完成才允许朝向更新,这避免了动作中断或方向混乱。

挥击结束后,移动模式会从“攻击挥击”切换回“角度偏移”,保证手臂回归到身体的基础位置和状态。同时,挥击角度的起点和终点会根据左手或右手交替切换,实现左右手交替挥击的效果。

此外,系统会在实体创建时初始化手臂的移动模式和起始角度,保证手臂在初始时正确摆放。

整体设计上,我们先写出明确、具体的代码逻辑,后续再优化成更加模块化和复用性强的形式。在这个过程中,需要合理管理插值参数(tMovement),负责更新挥击进度,确保动作连贯。

总结要点:

  • 设定“角度偏移”作为手臂的基础移动模式;
  • 手臂朝向默认与身体朝向一致,攻击时保持朝向固定;
  • 通过插值参数实现挥击角度从起始到目标的平滑过渡;
  • 挥击完成后,切换回基础移动模式,手臂回归默认位置;
  • 初始化阶段设定手臂的移动模式和起始角度,保证初始状态正确;
  • 挥击左右手交替切换,增加动作丰富度;
  • 插值参数tMovement由系统周期性更新,控制挥击进度;
  • 设计先写明确代码,后续逐步重构成复用代码。
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

game_brain.cpp:在 ExecuteBrain 中提供启动攻击的功能

我们要实现 D 剑的攻击发起流程。我们进入大脑逻辑中,在进行 D 剑初始化时,首先设置 attacked = false。接下来,在攻击发生的逻辑中,如果真的进行了攻击,我们就把 attacked 设置为 true。在攻击开始时,我们需要设置朝向的方向。

但考虑之后,我们发现设置朝向的更合适位置是在攻击真正发生之后。这是因为我们总是应该以“头部”的朝向为准。因此,逻辑上应该是这样的:如果尝试进行攻击,我们首先检查“手套”的运动模式是否是 angle offset 模式。如果不是该模式,我们就把 attacked 设置为 false,也就是说攻击并未发生。

具体来说,如果当前没有装备手套、手套处于静止状态,或者手套无法攻击,那么就表示攻击没有发生。只有在手套具备攻击能力的前提下,攻击才真正成立。这也意味着 attacked = true 的前提是我们有手套并且它处于可攻击状态。

当攻击真正进入执行阶段后,我们再设置朝向方向。如果我们在攻击过程中,并且我们拥有一个手套,而且攻击确实发生了,那么我们就把手套的运动模式设置为一个与角度相关的偏移模式(angle swipe 之类的)。我们还要设定起始角度为当前角度(虽然变量名不是叫 current angle,但含义是如此)。

然后我们需要设定目标角度。这个目标角度可能是 75 或 -25,具体取决于攻击方向。考虑到方向的连贯性,如果我们从 25 转向 -25,看起来会更加合理,因此我们设定起始角度为 25,目标角度为 -25。

但这也依赖于手套当前所处的位置。如果手套在角色左侧,那它应该向右挥动;如果在右侧,则应向左挥动。因此我们需要判断手套当前的角度是处于 0 的哪一侧,然后根据结果选择目标角度是 -25 还是 25,从而实现从当前方向向相反方向的攻击动作。这样可以让手套从一侧扫向另一侧,形成连贯的攻击动画与逻辑。
在这里插入图片描述

在这里插入图片描述

为了方便调试把随机偏移去掉

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

奇怪不对 得把break去掉

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

运行游戏并尝试挥击攻击

我们正在尝试实现预期的攻击机制。不过目前还存在一些问题和细节需要调整。

首先,攻击动作的速度太慢了,所以我们需要大幅提升挥击的速度。进入 movement mode 的相关配置后,找到攻击挥击(swipe)的部分,将其速度调快,调整后效果明显改善,动作更加迅速流畅。甚至可能还需要再稍微加快一点,最后找到了一个比较合适的速度,使得攻击效果符合预期。

接下来,我们注意到挥击动作本身虽然不错,但还有一个小问题:攻击时拳头没有足够地向前伸出,显得力度不足。为了提升视觉和手感效果,我们打算在挥击时加入一些手臂的伸展动作。

这个实现起来相对简单,因为我们已经有一个“位移(displacement)”的概念用于描述部位运动范围。虽然挥击动作和位移不是完全相同的概念,但可以利用已有的结构来扩展动作效果。具体做法是,在手套执行挥击动作时,通过在实体内部增加位移相关的逻辑,让手臂在攻击过程中有一个自然的前伸,这样拳击动作会显得更有力、更真实。

另外,这部分逻辑我们原本就需要在实体中进行处理,所以在已有的实体控制逻辑中添加手臂扩展的运动会非常自然,并不会破坏原有结构。最终可以通过调整位移参数与挥击角度结合,实现一个既快速又有冲击力的攻击动作。整体效果更接近预期的“出拳”表现。

game_entity.h:为实体添加 AngleCurrentDistance、AngleBaseDistance 和 AngleSwipeDistance

我们现在需要引入一个基于角度的距离控制机制,比如可以命名为 angle_based_distanceangle_swipe_distance。这样可以使手套在进行挥击动作时,不仅仅是角度发生变化,同时也在距离上有所位移,形成一种沿角度轨迹的外伸或回收动作,使攻击显得更加真实自然。

为实现这一点,我们还需要一个变量来记录“当前距离”,可以称为 current_distance。这就允许我们实时控制挥击动作过程中手套与角色本体之间的距离变化。

比如,当前硬编码为 0.5 的这个距离值,其实应该被替换成 entity_angle_current_distance,即实体当前的极坐标距离值。整个系统的运动实际上就是在使用极坐标系进行控制——一个角度配合一个距离值,决定了手套在空间中的位置。

这种做法的好处是可以通过角度与距离的组合实现手臂的自然伸缩与旋转,不再局限于单纯角度的旋转变化。我们可以控制挥击过程中手套的“远近”状态,例如:攻击开始时手套略微向前延伸,攻击结束时再收回,这样能增强攻击的动态表现。

整体逻辑如下:

  1. 定义 angle_swipe_distance 来设定攻击动作时手套的最大位移范围。
  2. 引入 current_distance 用于在动画过程中实时更新手套的实际位置。
  3. 用极坐标的方式,结合角度与距离,动态计算手套位置,实现更自然的出拳动作。

这种方式提供了更高的控制精度与更强的表现力,适用于构建更加丰富、生动的攻击动画。
在这里插入图片描述

在这里插入图片描述

game_world_mode.cpp:让 UpdateAndRenderWorld 参数化挥击弧线

我们正在实现一种基于角度的挥击距离系统,用于控制攻击动作中手套的前后位移效果。其核心目标是模拟出拳过程中手臂从身体伸出再收回的动态过程。

我们所定义的 entity_angle_current_distance 表示当前手套距离角色身体的实际位置,单位可为某种比例或世界坐标长度。这实际上表示的是手套从角色身体延伸出去的程度。

我们希望这种距离变化呈现出一种先增大后减小的自然曲线,也就是攻击时先向外推出,完成攻击后再回收。因此我们不会使用简单的线性插值(lerp),而是采用类似“抛物线”或“三角函数”的插值方式。可以称之为“parabola interpolation”或类似的命名方式。其基本逻辑是根据攻击动画的时间参数 T,在最中间阶段达到最大距离,两端则逐渐减小,形成攻击动作的自然起伏感。
parabola(抛物线)
在实现细节上,这个插值函数将接收以下参数:

  • 当前时间 T(从 0 到 1)
  • 起始距离(base distance)
  • 最大挥击距离(swipe distance)

函数的输出就是 entity_angle_current_distance,表示在动画进行到某一时刻时手套应当处于多远的位置。插值方式会在动画中段达到峰值,然后逐渐返回原始距离。

然后我们还需要在初始化角色时,设置好这些关键参数:

  • angle_base_distance:初始默认的手套距离,比如设置为 0.5,表示静止状态下手套稍微前伸;
  • angle_swipe_distance:攻击时的最大手套伸展距离,比如设置为 1.0,表示在出拳时手套会完全向前推出;
  • angle_current_distance:当前手套与角色之间的实时距离,初始化时也设为 0.5。

通过这种方式,我们实现了手套在攻击动作中的平滑、动态位移,不再只是角度的改变,而是结合了“角度+距离”双维度的极坐标运动模型,使出拳动作更加真实有力。这个结构也为后续更多复杂的动作提供了扩展基础。
在这里插入图片描述

game_math.h:引入 Sin01

我们现在需要一个“抛物线”函数(parabola function),或者说是某种非线性插值函数,用于控制动画中的插值效果。尽管不一定非要使用严格意义上的抛物线函数,但我们希望实现一种“中间值大、两端值小”的插值曲线,使攻击动作中的手臂或手套能够在中段伸展最远,开始和结束阶段则较近,从而更具自然感。

我们注意到之前的做法是直接在插值中嵌入非线性逻辑,但这样不够通用。因此更好的方式是:对 T 值(时间进度,范围为 0 到 1)进行一个“形状变换”(mapping),将其变成一个经过加工的 T,再传给现有的 lerp 插值函数。

也就是说,我们可以将原本的:

lerp(start, end, T)

改为:

lerp(start, end, mappedT)

其中 mappedT = parabolaMap(T)。这样就可以通用于所有 lerp 类型的函数,无论它们是对标量、向量还是其他结构进行插值,也无需为不同数据类型再编写新的插值逻辑函数。

这种 parabolaMap(T) 函数的目标是在 T 为 0 或 1 时返回 0,在 T 为 0.5 时返回 1,构造一个标准的“山峰型”插值曲线。一个简单的实现方式可以是:

parabolaMap(T) = 4 * T * (1 - T)

这个表达式在 T 为 0.5 时达到最大值 1,T 趋近于 0 或 1 时值为 0,形成一个对称的拱形曲线,效果类似于抛物线。

这样处理后,只要我们在插值前用这个函数处理 T,就可以让任何位置、角度、缩放等属性的插值具有动态起伏感。例如:

let curvedT = parabolaMap(T)
let result = lerp(startValue, endValue, curvedT)

通过这种方式,我们增强了插值逻辑的表现力,同时保持了接口的一致性和函数的通用性,不必为不同类型重写插值函数。最终用于控制攻击中手套的前伸和回缩,使动作显得更自然,更具物理感。
在这里插入图片描述

在这里插入图片描述

黑板讲解:余弦弧线

我们正在调整挥击动作中的非线性插值函数,以使手套(或手臂)从身体出发时形成更自然的“伸出—回收”运动。最初尝试使用抛物线形式来实现这种插值,但后来意识到抛物线并不一定最合适,可能更适合使用归一化后的余弦或正弦函数曲线。

目标是生成一个插值曲线,其行为如下:

  • 在 T=0 和 T=1 时返回 0(即手套靠近身体)
  • 在 T=0.5 时返回 1(即手套完全伸出)
  • 整体曲线呈现平滑拱形,即先快后慢地伸出,再慢后快地回收

于是我们尝试使用余弦函数构建一个归一化的曲线,即将 T 从区间 [0,1] 映射为余弦或正弦函数的一个完整半周期。初始想法是使用类似:

mappedT = cos(T * π)

但发现方向搞反了,因为 cos(0) = 1,而 cos(π) = -1,这并不能满足我们希望 T=0 和 T=1 对应 0 的要求。后来进一步调整,意识到其实更符合预期的是一个标准的正弦曲线的前半段,即:

mappedT = sin(T * π)

这样当:

  • T = 0 时,sin(0) = 0
  • T = 0.5 时,sin(π/2) = 1
  • T = 1 时,sin(π) = 0

完全满足我们需要的插值特性。

随后我们对这个函数进行了测试。首先尝试让函数始终返回 0,观察系统是否固定在最靠近身体的位置(0.5),结果正常;再尝试让函数始终返回 1,观察是否固定在完全伸出位置(1.0),也正常。这表明插值系统整体逻辑没有问题,问题出在映射函数本身的定义上。

确认用 sin(T * π) 后,插值结果就符合预期了:从靠近身体位置缓慢地向外伸出,到达中点后再缓慢回收,形成一个对称平滑的运动轨迹。

最终的插值形式如下:

let curvedT = sin(T * π)
let result = lerp(baseDistance, swipeDistance, curvedT)

通过这种结构,我们构建出了一个具有自然起伏节奏的攻击动作。手套运动不再是线性推进和回收,而是呈现真实的惯性和弹性节奏,显著增强了动画的流畅性和表现力。这个函数也具有良好的通用性,可用于其他需要动态缓进缓出的插值场景。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

运行游戏并测试挥击效果

我们当前对挥击动画中的插值函数进行了进一步的调整和思考。在上一阶段中,我们采用了一个正弦函数 sin(t * π) 来控制手套从身体伸出再收回的动态过程,该函数具有理想的0-1-0曲线,能够很好地控制动作的自然节奏。

但我们发现这个函数虽然行为正确,但有几个问题需要进一步处理:

  1. 命名不准确:虽然实现是正弦函数,但命名还叫 “parabola”,这显然不符合实际,因此我们打算重命名为更准确的名称,比如 sine01 或类似表示“从0到1的正弦曲线”的名称。

  2. 性能考虑:正弦函数相比抛物线函数在计算上开销更大。在性能敏感的环境下,使用类似抛物线的函数(如 4 * t * (1 - t))可能更合适,虽然运动曲线略有不同。

  3. 动作幅度问题:目前设定的 baseDistance(基础距离)是 0.5,swipeDistance(最大挥击距离)是 1.0,插值区间是从0.5到1.0,但我们观察到动画动作看起来可能还不够有张力或者太平缓。因此我们考虑调整 baseDistance 更低,比如 0.3,使得挥击动作更明显。同时根据不同手套的特性,还可以个别设置 swipeDistance,比如一些手套有更大的挥击范围。

  4. 参数归属问题:这些参数(baseDistance、swipeDistance、currentDistance)应该归属于实体(entity)本身,而不是硬编码或全局共享。因为不同手套或者不同角色可能有各自不同的攻击属性,所以更合理的做法是将这些参数作为实体的成员变量进行设置和管理。

  5. 下一阶段:碰撞检测
    我们的逻辑部分已经差不多完成,下一步计划是将碰撞检测系统与手套的运动轨迹挂钩。这样,当手套挥动时可以检测是否与敌人、障碍物等发生接触,并触发对应的攻击、命中反馈等逻辑。

  6. 玩法层面的思考
    我们注意到这个系统的设计本身就带来一些有趣的策略性。在此游戏中,攻击动作(手套)和角色的移动方向是分离的,也就是说,玩家攻击时需要考虑头部和身体的位置关系与朝向,这与传统动作游戏有所不同。这种机制增加了操作复杂度和策略性,会对战斗节奏产生独特影响。

  7. 未来可拓展性
    在目前系统的基础上,我们还可以加入更多细节和表现力,例如:

    • 手套挥击时浮动动作(比如“上下 bob 动”)
    • 根据不同手套类型设置不同的插值函数(更窄/更宽的攻击轨迹)
    • 更复杂的轨迹曲线(例如三角波、ease-in-ease-out、弹性曲线等)

综上,目前系统基础已构建完成,后续将继续围绕碰撞检测与更丰富的动画表现展开,进一步提高游戏动作的响应感与沉浸感。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

game_math.h:引入 Triangle01(三角形插值函数)

我们希望实现一个更加简单且高效的函数,用于控制挥击动作的插值过程。这次我们尝试的是一个 线性的三角函数(Triangle Wave),用于在 t 从 0 变化到 1 的过程中,创建一个先上升后下降的过渡曲线。

具体思路如下:

  1. 目标行为

    • t = 0 时,结果是 0。
    • t = 0.5 时,结果是 1(达到峰值)。
    • t = 1 时,结果又变回 0。
    • 中间插值以线性方式进行,不需要正弦或抛物线。
  2. 实现方式

    • 首先将 t 乘以 2,这样就得到了一个从 0 到 2 的值:

      result = t * 2;
      
    • 然后判断这个值是否超过 1,如果超过 1,说明已经处于下降阶段,我们就用 2 - result 得到镜像值,从而形成对称三角波:

      if (result > 1) {
          result = 2 - result;
      }
      
    • 最终这个 result 就是我们要插入 lerp 的 t 值,使得插值先升再降。

  3. 优点

    • 相比正弦或抛物线函数,这种实现方式计算更快,不涉及三角函数。
    • 行为明确且简单,峰值固定在中间,便于控制动画节奏。
    • 可用于任何需要“起伏”样式的运动轨迹,比如伸手、攻击、弹跳等。
  4. 应用场景

    • 在手套挥击动作中作为当前距离的插值控制函数。
    • 可被泛化使用在其它周期性或对称性变化的动画中。
    • 与 lerp 函数组合使用,生成如:lerp(baseDistance, swipeDistance, triangleT(t))
  5. 示例代码伪写

    function triangleT(t) {
        let result = t * 2;
        if (result > 1) {
            result = 2 - result;
        }
        return result;
    }
    

总的来说,这种方法非常适合我们当前的使用场景,既高效又能提供视觉上自然的出击-收回效果,并且更容易控制攻击幅度和时长。后续我们可以在不同手套上使用不同的插值函数,以增加游戏的策略性和手感差异。
在这里插入图片描述

在这里插入图片描述

game_world_mode.cpp:让 UpdateAndRenderWorld 调用 Triangle01 并运行游戏测试

我们尝试将插值函数替换为三角波函数后,当前的挥击动作看起来更自然了一些,手套从身体中心伸出再收回的运动更符合期望的攻击轨迹。不过,整体效果可能还不够“激进”或“不够夸张”,可能还需要进一步调整插值函数的形状,增加动作的剧烈程度或变化幅度

当前函数的表现

  • 使用的是一个简单的 三角波函数,控制 t 从 0 到 1 之间的插值值,使其先升后降,形成一个短暂冲刺、再快速收回的效果。
  • 相比之前尝试的正弦函数或抛物线函数,这个三角波的响应更直接,来得快、回得快,适合快速的挥击动画。

当前的调整反馈

  • 三角波的视觉效果比前面的正弦或抛物线更自然,挥击动作的动态更清晰、紧凑。
  • 但是动作幅度或者速度感可能还不够明显,也就是说,变化的“尖锐度”不够强烈,需要一个更“陡”的插值曲线。
  • 考虑下一步可能需要对该函数进一步偏移中点调整时间轴的非线性压缩,来控制峰值出现时间或波峰斜率。

未来改进方向

  • 可以尝试自定义插值函数,比如:

    • 提前达到峰值后迅速衰减;
    • 或者调整成非对称三角形,类似锯齿波;
    • 甚至使用分段插值,控制不同阶段的加速度。
  • 另外可以针对不同类型的手套,设置不同的挥击函数,让每种攻击方式都具有不同的动态风格和节奏感。

总的来说,当前这个实现虽然简单,但已经初步实现了动态攻击动作的插值控制。下一步可以围绕“如何让动作更有力、更明显”来进行微调和实验。接下来进入问答环节。

Q&A

它会支持任天堂的能量手套吗?

我们暂时不会支持任天堂的 Power Glove,主要原因如下:

  • 没有该设备,因此无法进行实测或开发调试。
  • 技术限制:该设备是老旧的外设,要让它与现代 PC 兼容,需要具备相当高的软硬件破解与电路改造能力,例如剪线、焊接、电路接驳等。
  • 缺乏驱动支持:Power Glove 并没有现代系统的驱动,因此即使硬件连接成功,还需要编写底层接口或驱动,才能读取其动作数据。
  • 投入产出不成比例:为一个极为小众的输入设备做深度支持,性价比过低。

至于游戏机制部分:

  • “酱油少年”是否能实现连锁攻击(chain attack),这一点可以根据游戏设计逻辑进行扩展。
  • 如果设计中包含“连击系统”,可以进一步实现连续输入手势或动作引发不同阶段的攻击,如轻击→重击→旋转击,或时间窗口内连打形成连续动作。
  • 此类机制适合增加游戏的深度与手感反馈,也能强化“拳套”作为武器的打击感和策略性。

总结来说,目前暂不支持 Power Glove,但连锁攻击机制是可以设计和实现的,后续若加入更多外设支持,也需评估技术可行性与实际意义。

会加入连击吗?例如“砍砍刺”?

在当前的设计中,不会存在“劈砍 / 刺击 / 横斩”等多种攻击方式之间的切换,原因如下:

  • 攻击操作并不依赖多个攻击按钮。攻击的输入方式主要是方向性输入,即玩家按下方向来指定攻击的方向,而不是通过按下不同的按钮来触发不同类型的攻击动作。
  • 游戏中不存在传统意义上的“攻击按钮组合”(比如常见格斗游戏中的“X X Y”连击),因此也就没有实现基于按键种类的攻击变化。

不过,虽然没有多种攻击按钮,但仍然存在基于输入节奏与模式的攻击差异:

  • 单击攻击按钮与双击攻击按钮,可能会被识别为不同的攻击意图,从而触发不同的攻击行为或动画。
  • 这种机制带来一定的输入节奏策略性,但本质上还是围绕少量输入信号(方向 + 攻击节奏)展开。

总结:

  • 不支持通过不同按键执行劈、刺、斩等不同攻击方式。
  • 攻击类型的变化主要依据输入节奏(如单击、双击)和方向控制,而非按钮组合。
  • 未来可能会在编码层面加入某种“动作识别逻辑”,用于解析玩家的输入模式,从而触发不同的效果。

你如何看待切换为模拟相邻房间而不是使用当前的模拟缓冲区(simulation apron)?

关于切换到模拟相邻房间而不是使用模拟“围裙”(simulation apron)的思路,我们的想法是:

  • 可能更倾向于将“围裙”设定为相邻的房间区域,但不想把它明确硬编码为相邻房间。
  • 这样做的原因是为了保持灵活性,比如房间大小可能会变动。如果硬编码为“模拟下一间房”,那么在房间结构不明确或房间是平滑滚动、连续延伸的情况下,代码逻辑就会变得模糊和不易维护。
  • 因此,“围裙”作为一个抽象区域概念,暂时是最合适的方案。模拟区域代码本身并不关心我们具体怎么去定义和收集这些区域,我们可以在后期灵活决定具体的实现细节。
  • 这个决策可以一直拖到游戏开发的后期,也不会对现有代码造成太大影响,保持开放性更好。

至于“伙伴”或“随从”(familiar)的攻击方式:

  • 目前尚未明确描述,但通常会根据具体设计需求来定,可能会有独立的攻击机制或者辅助攻击方式。
  • 需要进一步设计伙伴的攻击行为、触发条件和表现形式。

总结就是,我们在模拟游戏世界的区域时,倾向于用灵活且抽象的“围裙”概念,避免过早硬编码相邻房间关系,保持代码和设计的可扩展性;伙伴的攻击机制还需具体设计。

这个熟悉者(familiar)预期如何攻击?是发射投射物还是滑行击打敌人?

关于伙伴(familiars)的设计,目前主要考虑是他们可能会有某种投射物攻击或者滑行动作来物理接触敌人,但实际上还没有深入思考过具体细节。伙伴会出现在游戏中,但不是设计重点,相关内容也还未深入开发。

伙伴之所以在这段代码实现中出现,主要是因为它们是一个大家都熟悉且容易理解的概念,方便用来测试和验证系统功能是否支持这类角色的存在和运作。

后续可能会有更详细的设计说明发布,帮助理解游戏主角和相关系统的更多细节。

关于是否会有和手套匹配的“靴子”,目前没有明确提及。

关于手套的粒子特效,我们会不会像之前一样使用头部资源来做?

关于手套的粒子效果,我们会参考之前用头部资源做粒子系统的方法,但不会完全一样。粒子系统的基础原理是相同的,但手套的粒子效果不需要那么复杂的格子网格系统,整体会更简单一些。

手套的粒子效果会比之前演示的粒子系统更轻量,主要是因为需求不同,不需要那么多复杂的处理。总体来说思路相似,但实现会更简洁直接。

我在想,如果在挥击过程中可以改变面向方向,并由此延长挥击时间,甚至变成一个无限旋转的攻击,会不会是个很酷的机制?

在想一个很酷的机制,能不能通过挥动手套的同时改变面向方向,从而延长挥动动作,甚至变成一个几乎无尽的旋转拳击。手套的控制方式会根据不同的手套种类有所不同,之后还想尝试给它加入“挥动后的控制”(after touch)机制。不过现在还太早,不确定哪些机制最终会进入游戏,因为这些东西更靠感觉,需要实际玩一玩才能判断到底好不好玩。

关于《Planescape: Torment》有没有玩过的问题没有回答。

你玩过《异域镇魂曲》(Planescape: Torment)吗?主角真的需要一个类似 Morte 的熟悉者

游戏中的英雄确实非常需要一个像Mort风格的召唤物。其实如果要选召唤物,更偏好的是《星球大战:旧共和国》(KOTOR)里的HK-47,比起Mort更喜欢HK-47的风格。

攻击是否可以被打断?例如攻击未激活的实体,或被敌人从背后攻击后跳跃反击(类似早期《塞尔达》)?

关于攻击是否会打断动作,比如攻击一个不可打断的实体,或者有人从背后攻击玩家,玩家是否会向相反方向跳开——一般来说攻击不会打断玩家动作,除非是非常特殊的攻击。攻击可能会打断敌人的动作,比如敌人在做某事时会被击退或受影响。玩家有时也可能被击退,但大多数敌人通常不会有这种能力,因为频繁被击退会很烦人。不过可能会有一些特殊的手套赋予玩家这种击退敌人甚至被击退的能力,有了这种能力可以更频繁地使用这种效果。

为什么不把手套的挥击动作交给游戏的美术或动画师来做?

关于是否将手套挥击动作交给游戏的艺术家或动画师来制作,考虑到如果没有动画师就不存在动画,若有动画师也需要权衡。即使有动画师,也不一定要完全依赖动画,因为动画本身不是参数化的,没有逻辑,只是固定的动作序列。对于玩家跳跃动作或手套挥击这种关键动作,用固定动画的方式表现是有限的,可能不够灵活。希望动作有更多逻辑和参数化的表现,比如不同的手套根据其属性能有不同的挥击表现。因此,即便游戏中有动画师负责其他动画(比如怪物攻击),跳跃和手套挥击这类关键动作还是倾向于用代码手工控制,实现更灵活、更动态的表现,而不是完全依赖预设动画。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2380278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# Try Catch Finally 执行顺序是什么?有返回值呢?

Try Catch Finally 执行顺序是什么?有返回值呢? 大部分程序员都认为:C#异常处理执行顺序,很简单,没什么可说的。 正常情况:执行顺序为 1、3(下图) 异常情况:执行顺序为1、2、3 文章目录 Tr…

水库雨水情测报与安全监测系统解决方案

一、方案概述 本水库雨水情测报与安全监测解决方案的核心目标在于利用尖端的技术手段,确保对水库雨水情势以及大坝安全状况的持续监控和及时预警,从而为水库的稳定运行提供坚实的支持和保障。该方案严格遵循“统筹协调、因库制宜、实用有效、信息共享”的…

架构选择/区别

目录 一、分层架构(Layered Architecture) 二、微服务架构(Microservices Architecture) 三、分布式架构(Distributed Architecture) 四、单体架构(Monolithic Architecture) 五…

嵌入式学习笔记 - STM32 ADC 模块工作模式总结

ADC 模式总结: 一 单ADC模式(是指ADC1,ADC2,ADC3中只有一个ADC被使用) ①单通道: 非连续模式:非连续的意思就是单次,一次转换完成后就停止转换,除非再次被软件或者被外部触发启动&#xff1b…

IPLOOK | 2025 MVNOs 世界大会:从Wi-Fi通话到卫星覆盖

2025 MVNOs 世界大会于5月12日至14日在奥地利维也纳举行,汇聚了来自50多个国家的550余位行业领袖,共同探讨移动虚拟网络运营商(MVNO)领域的变革趋势。本届大会聚焦数字化转型、技术创新与战略合作,其中IPLOOK凭借其创新…

零基础搭建!基于PP-ShiTuV2的轻量级图像识别系统(Docker+API部署指南)

以下是对该图像分类识别系统的的简单介绍: PP-ShiTuV2 是一个由百度飞桨团队发布的实用轻量级通用图像识别系统,由主体检测、特征提取、向量检索三个模块构成,适用于快速构建轻量级、高精度、可落地的图像识别应用image_classification是一个…

【C语言】贪吃蛇小游戏

文章目录 前言一、贪吃蛇游戏代码test.c文件Snake.h文件Snake.c文件 二、相关函数的介绍1.COORD2.Win32 API的介绍3.GetStdHandle4.GetConsoleCursorInfo5.CONSOLE_CURSOR_INFO5.SetConsoleCursorInf6.SetConsoleCursorPosition7.GetAsyncKeyState 总结 前言 哈喽各位好呀。今…

大语言模型 07 - 从0开始训练GPT 0.25B参数量 - MiniMind 实机训练 预训练 监督微调

写在前面 GPT(Generative Pre-trained Transformer)是目前最广泛应用的大语言模型架构之一,其强大的自然语言理解与生成能力背后,是一个庞大而精细的训练流程。本文将从宏观到微观,系统讲解GPT的训练过程,…

[免费]苍穹微信小程序外卖点餐系统修改版(跑腿点餐系统)(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序医院预约挂号管理系统(uni-appSpringBoot后端Vue管理端),分享下哈。 项目视频演示 【免费】苍穹微信小程序外卖点餐系统修改版(跑腿点餐系统)(SpringBoot后端Vue管理端) Java毕业设计…

【RAG】RAG-MCP:基于检索增强生成来缓解大语言模型工具选择中的提示膨胀问题

摘要 由于提示膨胀和选择复杂性,大型语言模型 (LLM) 难以有效利用越来越多的外部工具,例如模型上下文协议 (MCP)[1]中定义的那些工具。 我们引入了 RAG-MCP,这是一个检索增强生成框架,通过卸载工具发现来克服这一挑战。 RAG-MCP …

甘特图工具怎么选?免费/付费项目管理工具对比测评(2025最新版)

2025年甘特图工具的全面指南 在项目管理领域,甘特图作为最直观的任务规划和进度追踪工具,已成为团队协作和项目执行的核心手段。随着数字化技术的快速发展,2025年的甘特图工具市场呈现出前所未有的多元化和智能化趋势。从开源软件到云端协作…

AIGC与数字金融:人工智能金融创新的新纪元

AIGC与数字金融:人工智能金融创新的新纪元 引言 人工智能生成内容(AIGC)在数字金融领域发挥着关键作用,从金融内容生成到智能风控,从个性化服务到投资决策,AIGC正在重塑金融的方式和效果。本文将深入探讨A…

手机怎么查看网络ip地址?安卓/iOS设备查询指南

在移动互联网时代,IP地址作为设备的网络身份证,无论是网络调试、远程连接还是排查故障都至关重要。本文将系统介绍安卓和iOS设备查看IP地址的多种方法,帮助您快速掌握这一实用技能。 一、安卓手机查看IP地址方法 1、通过WiFi设置查看 打开设…

无损耗协议:PROFINET和EtherNet IP网关的高效安装指南

作为风力发电机组监控系统的重要组成部分,PROFINET和EtherNet/IP协议转换网关倍讯BX-606-EIP的安装至关重要。作为安装工,我们要确保网关安装的高效顺利,保证风力发电机组的稳定运行。 首先,我们需要仔细检查网关的硬件接口,确保所有连接线缆与设备端口相匹配。网关…

【知识产权出版社-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…

基于OAuth2+SpringSecurity+Jwt实现身份认证和权限管理后端服务

1、简介 本文讲述了如何实现简易的后端鉴权服务。所谓“鉴权”,就是“身份鉴定”“权限判断”。涉及的技术有:OAuth2、SpringSecurity、Jwt、过滤器、拦截器。OAuth2用于授权,使用Jwt签发Access Token和Refresh Token,并管理token…

liunx定时任务,centos定时任务

yum install cronie crontabs -y直接运行 crond -n 在前台运行 crond -i 守护进程在没有inotify支持的情况下运行systemctl service crond start # 启动服务 systemctl enable crond.service # 设置开机自启 sudo systemctl restart crond # 重启 cron 服务systemctl serv…

三种嵌入式开发常用的组网方式

一、三种嵌入式开发常用的组网方式 这里记录了三种嵌入式开发常用的网络环境,最终目标也就是让开发板、虚拟机、物理机在同一个局域网下。一般的网络环境下都非常容易实现,但是对于学生校园网可得想些法子了,因为校园网一般会有设备连接数限…

ubuntu 20.04 ping baidu.coom可以通,ping www.baidu.com不通 【DNS出现问题】解决方案

ping baidu.coom可以通,ping www.baidu.com不通【DNS出现问题】解决方案 检查IPV6是否有问题 # 1. 检查 IPv6 地址,记住网络接口的名称 ip -6 addr show# 2. 测试本地 IPv6,eth0换成自己的网络接口名称 ping6 ff02::1%eth0# 3. 检查路由 ip…

城市排水管网流量监测系统解决方案

一、方案背景 随着工业的不断发展和城市人口的急剧增加,工业废水和城市污水的排放量也大量增加。目前,我国已成为世界上污水排放量大、增加速度快的国家之一。然而,总体而言污水处理能力较低,有相当部分未经处理的污水直接或间接排…