Expression2无人机脚本开发:地图绕飞避障+聊天指令锁敌返航
Expression2 无人机脚本修复:解决撞墙问题+添加返航功能
问题说明
需要开发一款Expression2(E2)芯片脚本,实现两个核心功能:
- 无人机在地图中自主绕飞,全程不碰撞墙体
- 通过聊天指令设置目标玩家名称后,无人机向该玩家位置返航
现有脚本存在两个问题:
- 无人机频繁撞墙
- 缺失玩家指定返航功能
现有代码
@inputs EGP:wirelink @persist [UAV]:entity @persist [AngPull Speed RngLength]:number @persist RotAng:angle @persist [Positions]:table interval(10) if(first()){ AngPull = 1 Speed = 2 #Multiplier RngLength = 8000 #EGP = spawnEgp("models/hunter/plates/plate2x2.mdl",entity():pos(),ang(),1):wirelink() propSpawnUndo(0) if(EGP){ entity():setPos(entity():toWorld(vec(0,0,-10))) } UAV = propSpawn("models/xqm/jetbody3_s2.mdl",entity():toWorld(vec(0,0,30)),entity():angles(),0) UAV:setColor(vec(randint(40,100))) UAV:propGravity(0) UAV:setTrails(30,30,1,"trails/smoke",vec(100),255) rangerPersist(1) rangerFilter(UAV) RotAng = ang() UAV:soundPlay(1,inf(),"Phx.HoverLight") noCollideAll(UAV,1)#so we dont kill players } if(owner():keyZoom()){UAV:propFreeze(0)} if(changed(EGP)){ if(EGP){ entity():setPos(entity():toWorld(vec(0,0,-10))) }else{ entity():setPos(entity():toWorld(vec(0,0,10))) } } Ranger = rangerOffset(RngLength,UAV:pos(),UAV:right()) Height = abs(-11519.968750 - UAV:pos()[3]) if(Ranger:hit()){RotAng+=ang(1,1*((RngLength-Ranger:distance())/(RngLength)),0),Mul=((RngLength-Ranger:distance())/(RngLength/150))*Speed}else{Mul=20*Speed} if(Height<1500){RotAng+=ang(0,0,-1)}else{RotAng = RotAng:setRoll(0)} timer("soundplay",5000) soundPitch(1,UAV:vel():length()) UAV:applyForce(UAV:right()*UAV:mass()*Mul - UAV:vel()) UAV:applyTorque( ( ( (UAV:toLocalAxis(rotationVector(quat( RotAng )/quat(UAV)))) *200-UAV:angVelVector()*20)*UAV:inertia() ) *AngPull) foreach(Key,Ply:entity = players()){ local Ranger = rangerOffset(100000,UAV:pos(),Ply:pos()-UAV:pos()) if(Ranger:entity() == Ply){ Positions[Ply:steamID(),vector] = Ply:pos() EGP:egpBox(Key,vec2(clamp(Ply:pos()[1]/50+200,0,500), clamp(Ply:pos()[2]/50+200,0,500) ),vec2(7.5)) EGP:egpColor(Key,teamColor(Ply:team())) EGP:egpTextLayout(Key+20,Ply:name(),vec2(clamp(Ply:pos()[1]/50+200,0,500), clamp(Ply:pos()[2]/50+200,0,500) ),vec2(100,50)) EGP:egpFont(Key+20,"",12) } } if(changed(UAV)){ if(!UAV){ selfDestructAll() } }
修复方案
1. 撞墙问题修复
原脚本仅检测无人机右侧障碍物,且转向逻辑简单,导致无人机无法提前避让前方/左侧障碍,容易卡墙。修改点:
- 增加前、左、右三个方向的障碍物检测
- 优化转向权重:障碍物越近,转向幅度越大
- 调整高度控制逻辑,避免因固定高度值导致的异常升降
2. 返航功能添加
- 监听聊天指令
!return [玩家名],设置返航目标 - 增加状态变量区分绕飞模式和返航模式
- 返航时向目标玩家位置移动,到达指定距离后悬停
修复后完整代码
@inputs EGP:wirelink @persist [UAV TargetPlayer]:entity @persist [AngPull Speed RngLength ReturnDistance]:number @persist RotAng:angle @persist [Positions]:table @persist ReturnMode:boolean # 返航状态标记 interval(10) if(first()){ AngPull = 1.2 Speed = 2.5 # 优化速度系数 RngLength = 6000 # 缩短检测距离,提前反应 ReturnDistance = 500 # 到达目标附近后悬停的距离 ReturnMode = false propSpawnUndo(0) if(EGP){ entity():setPos(entity():toWorld(vec(0,0,-10))) } UAV = propSpawn("models/xqm/jetbody3_s2.mdl",entity():toWorld(vec(0,0,30)),entity():angles(),0) UAV:setColor(vec(randint(40,100))) UAV:propGravity(0) UAV:setTrails(30,30,1,"trails/smoke",vec(100),255) rangerPersist(1) rangerFilter(UAV) RotAng = ang() UAV:soundPlay(1,inf(),"Phx.HoverLight") noCollideAll(UAV,1) } # 监听聊天指令设置返航目标 if(owner():chat()){ local Msg = owner():chatText() if(Msg:sub(1,7) == "!return "){ local TargetName = Msg:sub(8) foreach(Ply:entity = players()){ if(Ply:name():lower() == TargetName:lower()){ TargetPlayer = Ply ReturnMode = true print("已设置返航目标: "..Ply:name()) break } } if(!TargetPlayer){ print("未找到玩家: "..TargetName) } } # 取消返航指令 if(Msg == "!cancelreturn"){ ReturnMode = false TargetPlayer = null print("已取消返航") } } # 返航模式逻辑 if(ReturnMode && TargetPlayer:isValid()){ local TargetPos = TargetPlayer:pos() # 计算无人机到目标的方向向量 local Dir = (TargetPos - UAV:pos()):normalize() local Distance = (TargetPos - UAV:pos()):length() # 到达目标附近后悬停 if(Distance <= ReturnDistance){ Mul = 0 # 调整朝向目标 RotAng = Dir:toAngle() }else{ Mul = Speed * 15 # 朝目标方向转向 RotAng = Dir:toAngle() } # 高度保持:跟随玩家高度 local HeightDiff = TargetPos[3] - UAV:pos()[3] if(HeightDiff > 200){ RotAng:add(ang(0,0,0.5)) }else if(HeightDiff < -200){ RotAng:add(ang(0,0,-0.5)) } }else{ # 绕飞模式:多方向障碍物检测 local RangerFront = rangerOffset(RngLength, UAV:pos(), UAV:forward()) local RangerRight = rangerOffset(RngLength, UAV:pos(), UAV:right()) local RangerLeft = rangerOffset(RngLength, UAV:pos(), -UAV:right()) Mul = 20 * Speed RotAng:add(ang(0, 0.2, 0)) # 基础绕飞转向 # 前方障碍物:大幅左转 if(RangerFront:hit()){ local DistRatio = (RngLength - RangerFront:distance())/RngLength RotAng:add(ang(0, 0, DistRatio * 8)) Mul = Speed * (10 - DistRatio * 8) } # 右侧障碍物:左转 if(RangerRight:hit()){ local DistRatio = (RngLength - RangerRight:distance())/RngLength RotAng:add(ang(0, 0, DistRatio * 5)) Mul = Speed * (15 - DistRatio * 5) } # 左侧障碍物:右转 if(RangerLeft:hit()){ local DistRatio = (RngLength - RangerLeft:distance())/RngLength RotAng:add(ang(0, 0, -DistRatio * 5)) Mul = Speed * (15 - DistRatio * 5) } # 高度控制:保持在地面上方1500单位(可根据地图调整) local GroundPos = UAV:pos() GroundPos[3] = -11519.968750 local Height = (UAV:pos() - GroundPos):length() if(Height < 1200){ RotAng:add(ang(0,0,-0.8)) }else if(Height > 1800){ RotAng:add(ang(0,0,0.8)) } } # 通用运动控制 UAV:applyForce(UAV:right()*UAV:mass()*Mul - UAV:vel()) UAV:applyTorque( ( ( (UAV:toLocalAxis(rotationVector(quat( RotAng )/quat(UAV)))) *200-UAV:angVelVector()*20)*UAV:inertia() ) *AngPull) # EGP玩家显示(保留原逻辑) if(EGP){ foreach(Key,Ply:entity = players()){ local Ranger = rangerOffset(100000,UAV:pos(),Ply:pos()-UAV:pos()) if(Ranger:entity() == Ply){ Positions[Ply:steamID(),vector] = Ply:pos() local ScreenPos = vec2(clamp(Ply:pos()[1]/50+200,0,500), clamp(Ply:pos()[2]/50+200,0,500)) EGP:egpBox(Key,ScreenPos,vec2(7.5)) EGP:egpColor(Key,teamColor(Ply:team())) EGP:egpTextLayout(Key+20,Ply:name(),ScreenPos,vec2(100,50)) EGP:egpFont(Key+20,"",12) } } } # 无人机销毁处理 if(changed(UAV)){ if(!UAV){ selfDestructAll() } } # 音效处理(保留原逻辑) timer("soundplay",5000) soundPitch(1,UAV:vel():length())
使用说明
- 设置返航:在聊天框输入
!return [玩家名称],无人机将向目标玩家飞去 - 取消返航:输入
!cancelreturn,无人机恢复绕飞模式 - 撞墙避让:无人机现在会检测前、左、右三个方向的障碍,提前调整方向避免碰撞
内容的提问来源于stack exchange,提问作者homura-akemi-f02-22
相关产品推荐
相关产品推荐

