制作一个敌人跟随攻击的功能

 

功能效果展示

 

 

运行环境

Win7,Win8,Win10

Reworld版本 体验版

vc_redist.x64 运行环境

 

针对零基础读者的补充

下载安装 Reworld对应版本

Reworld官网链接http://www.reworlder.com/

下载后安装后注册账号打开空地图

下载安装 vc_redist.x64.rar运行环境

redist.x64下载链接

 

思路分析

敌人自动跟随攻击玩家的功能实现主要分为两部分:

第一部分;实现敌人自动索敌,实现敌人雷达系统用来判定玩家和自己的距离,然后开始自动跟随玩家的功能。

第二部分:实现敌人这个角色的攻击动作表现,此处就涉及到角色动作替换的技巧。

综合以上两部分,我们实现敌人自动跟随并且攻击玩家的功能思路应该为:敌人判断玩家和自己的距离,当距离小于某个数值时,敌人开始自动跟随玩家,此时敌人执行的动作是奔跑动作。随着敌人的不断接近,敌人和玩家之间的距离缩小至敌人的攻击范围内时,敌人开始执行攻击动作。

 

敌人搭建

一、搭建过程

首先我们需要在工作区里面创建一个角色,并且给这个角色命名为Enemy,咱们的敌人一号就出现啦。

 

好的,敌人创建好了,我们需要给敌人添加攻击的动作,这样敌人就可以对玩家进行攻击了,如下图步骤,我们创建一个动作并把名称重命名为attack,在攻击动作下方把本地动作名修改为attack,这样敌人就拥有攻击表现啦。如果想让角色有不同的动作,只要在动作下将本地动作名修改成和Reworld动作列表大全中对应的动作名即可,例如:lianxupikan(连续劈砍),beijidao(被击倒),tiaowu(跳舞)等动作。(Reworld动作列表大全

 

二、补充说明

1.什么是工作区?

工作区中的对象是会被可视化显示到3D场景中的,并且只有在工作区中的对象才会发生物理交互。

服务对象。

不可创建。

不可复制。

不可删除。

 

2.什么是角色?

角色Avatar是一个特殊对象,它使模型具有物理走动和与各种组件交互的能力。Avatar作为父级,使用零件作为其子级组合成人体模型。默认情况下,Avatar的人体模型通常由:头、左手、左大碧、右大腿、右小腿、左大腿、左小腿、右手、右大臂、左脚、右脚、臀部、胸等13个部位组成,部位缺失或名称不符时,皆默认为缺失,在角色加载到客户端时,缺失部位为空。

添加自定义的外观时,保证其名称符合默认部位名称即可,并可添加衣服、配件等改变外观效果。 人物模型的物理交互都通过Avatar产生。

如何创建角色: 点击工作区WorkSpace后的"+",在可添加的对象中选择角色,可直接创建基础角色。

角色的特性:

角色由骨骼和零件构成,控制器控制其状态。

角色的每个身体部位(自定义零件)都有自己独立的刚体属性(尚未实现)。

角色的身体部位通过命名规则来对应自己的骨骼,命名规则见身体部位。

角色的各项属性都可以在角色参数组件中快速定义。

角色当前生命值为0时角色死亡,死亡时有布娃娃和碎裂两种效果可供选择,角色死亡后会在出生点复活。

运行后的角色属性由玩家初始化中的平台自定义角色来控制,外观来自平台,当在平台自定义角色之前创建一个角色对象则运行时生成该角色。

 

3.什么是动作?

角色对象的动作对象。

动作功能:

动作对象放在相应的角色对象下即可被该角色调用(也可放在角色子级的动作文件夹、角色配件或者工具下)。

动作ID为动作对象的地址。

动作名为状态机中的动作名,修改此属性可以把当前动作设置为受指定状态触发的动作;这是一个枚举类型,例如上传一个动作A,动作ID选择动作A的资源ID,动作名选择跑步,则运行后角色的跑步动作将被替换为动作A

本地动作名为reworld\Client\Assets\Resources\animation目录下的动作名称,填写相应动作名称即可调用相应的本地动作。

动作优先级:在动作名选择无的情况下才生效(状态机中所有动作的4个部位优先级均为0),通过改变优先级可以改变身体相应4个部位播放的动作,状态机中基础动作优先级均为0,优先级越大越优先,同级后者优先。

角色状态有:站立、跑步、起跳、下落、攀爬、坐下、驾驶,在角色对象下默认有对应每种状态的动作。

 

核心功能执行环境搭建

一、搭建过程

接下来我们需要创建一个服务器脚本,在脚本里我们需要实现敌人雷达系统用来判定玩家和自己的距离,看看有没有到达自己的索敌区域。

脚本创建好了,接下来就是去实现它的功能了,我把脚本功能放到下方的代码中:


local DISTANCE=5
local Enemy = WorkSpace.Enemy
local TableList=nil
local IgnoreList={} --要忽略检索的物体表
 
local trigger=false 
 
local avatar=nil --存储被找到的玩家
 
--合并表格方法
function MergeTables(...)
    local tabs = {...}
    if not tabs then
        return {}
    end
    local origin = tabs[1]
    for i = 2,#tabs do
        if origin then
            if tabs[i] then
                for k,v in pairs(tabs[i]) do
                    table.insert(origin,v)
                end
            end
        else
            origin = tabs[i]
        end
    end
    return origin
end
 
 
Players.PlayerAdded:Connect(function(Uid)
    local ren = Players:GetPlayerByUserId(Uid)
    ren.AvatarAdded:Connect(function()
            MergeTables(IgnoreList,Enemy:GetAllChild(),Enemy.动作:GetAllChild())--将表格信息合并到ignorelist中
            MergeTables(IgnoreList,ren.Avatar:GetAllChild(),ren.Avatar.动作:GetAllChild(),ren.Avatar.第一人称:GetAllChild())
            trigger=true
    end)
end)
 
function Radar()
    --判定检索范围
    local _StartPos=Vector3.New(Enemy.Position.x-DISTANCE,Enemy.Position.y-DISTANCE,Enemy.Position.z-DISTANCE)
    local _EndPos=Vector3.New(Enemy.Position.x+DISTANCE,Enemy.Position.y+DISTANCE,Enemy.Position.z+DISTANCE)
    --雷达监测范围内物体,忽略掉IgnoreList表中储存的物体
    TableList=WorkSpace:FindPartsInZoneWithIgnoreList(_StartPos,_EndPos,IgnoreList,100) 
    if TableList~=nil then
        for i=1,#TableList,1 do
            if TableList[i]:IsClass("Avatar") and  TableList[i].Name~="Enemy" then --这里做个剔除,剔除掉敌人自身
                avatar=TableList[i] --将获取到的玩家信息做一个记录存储
                return true
            end
        end
    end
    avatar=nil
    return false
end
 
function EnemyAttack()
    if avatar~=nil then
        local rot= avatar.Position-Enemy.Position
        Enemy:Move(Vector2(Vector3.Normalize(rot).x,Vector3.Normalize(rot).z))
        --如果敌人和人物的距离小于0.5
        if  Vector3.Distance(Enemy.Position,avatar.Position)<0.5 then
            --敌人停止移动,改为攻击
            Enemy:Move(Vector2(0,0))
            Enemy.动作.attack.Action= Enum.AnimationType.stand
            Enemy.动作.attack.LocalClipId ="attack"
        end
    end
end
 
GameRun.Update:Connect(function()
    if trigger==true and Radar() then
        EnemyAttack()
    end
end)

有些时候将脚本复制到编辑器中可能会出现问题,可以用TXT文档转换一下,或者删掉重新创建一个脚本试试,另外有些时候会出现复制不上的情况,这个时候可以关闭脚本编辑重新打开就可以了。

 

二、补充说明

1.什么是服务器脚本?

只会在服务器运行的Lua脚本代码,用于编写服务器逻辑。

 

2.为什么要使用服务器脚本?

基于敌人跟随攻击功能用於单人和多人等不同环境,所以采用通用的服务器脚本。

  1. 服务器脚本与客户端脚本不同,客户端执行的操作只有本地客户端,也就是玩家自己有效。而服务器执行的操作不仅针对单人有效,还针对与服务器相连的所有客户端同步生效。
  2. 在多人游戏中,如果这个对象的变化是针对一个人的,必须在客户端脚本进行编写;如果这个对象的变化是针对所有人的,那就必须在服务器脚本进行编写。
  3. 对于只能在客户端脚本修改的对象,如何让服务器知晓变化结果是很重要的。这里采用传统游戏的制作流程,也就是在客户端进行修改,把修改后的结果通过与服务器通信的方式发送到服务器,再通过服务器进行逻辑运算,把执行结果再同步给所有客户端。

好了,接下来我们点击开始游戏就可以了,记得把敌人放置的离玩家远一些,当你悄悄的靠近敌人的时候,进入到了索敌区域,敌人就会转身跑到你的身边攻击你啦。记得赶紧跑~~~

如果有什么问题或者有更好的实现方式,大家可以在下方积极交流讨论,我们也会参与进来和大家一起分享经验,期望能和大家共同进步~~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章