找回密码
 点一下
查看: 4635|回复: 27

矩形区域选择单位的一个函数

[复制链接]
发表于 2009-4-18 01:41:15 | 显示全部楼层 |阅读模式
不知道有没有人写过,今天正好要用就写了个
[jass]
globals
    boolexpr udg_B
endglobals
function H2I takes handle h returns integer
    return h
    return 0
endfunction
function RectCon takes nothing returns boolean
    return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0
endfunction
function RectAct takes real length,real width,real a,real x,real y,boolean IsPlayerUnit,boolean IsAlly,integer i returns group
    local real Sina=Sin(a)
    local real Cosa=Cos(a)
    local real x1=x+width*Sina/2
    local real y1=y-width*Cosa/2
    local real x2=x-width*Sina/2
    local real y2=y+width*Cosa/2
    local real x3=x2+length*Cosa
    local real y3=y2+length*Sina
    local real x4=x1+length*Cosa
    local real y4=y1+length*Sina
    local group g=CreateGroup()
    local group gg=CreateGroup()
    local integer ig=H2I(gg)
    local unit u=null
    call GroupEnumUnitsInRange(g,x+length*Cosa/2,y+length*Sina/2,SquareRoot(length*length+width*width)/2,udg_B)
    if IsPlayerUnit then
        loop
            set u=FirstOfGroup(g)
            call GroupRemoveUnit(g,u)
            set x=GetUnitX(u)
            set y=GetUnitY(u)
            if GetPlayerId(GetOwningPlayer(u))==i then
                if (x1-x)*Sina-(y1-y)*Cosa>=0 and (x2-x)*Cosa+(y2-y)*Sina<=0 and (x3-x)*Sina-(y3-y)*Cosa<=0 and (x4-x)*Cosa+(y4-y)*Sina>=0 then
                    call GroupAddUnit(gg,u)
                endif
            endif
            exitwhen u==null
        endloop
    else
        loop
            set u=FirstOfGroup(g)
            call GroupRemoveUnit(g,u)
            set x=GetUnitX(u)
            set y=GetUnitY(u)
            if (IsUnitAlly(u,Player(i)) and IsAlly)or(IsUnitEnemy(u,Player(i))and not IsAlly) then
                if (x1-x)*Sina-(y1-y)*Cosa>=0 and (x2-x)*Cosa+(y2-y)*Sina<=0 and (x3-x)*Sina-(y3-y)*Cosa<=0 and (x4-x)*Cosa+(y4-y)*Sina>=0 then
                    call GroupAddUnit(gg,u)
                endif
            endif
            exitwhen u==null
        endloop
    endif
    set u=null
    call DestroyGroup(g)
    set g=null
    set gg=null
    return ig
    return null
endfunction

funcion Init takes nothing returns nothing
    set udg_B=Condition(functino RectCon)
endfunction
[/jass]

用向量的方法判断的,四个交点作为参考,在直线的同一侧或直线上,点乘>=0,去掉了一些不影响正负的参数 (x1-x)*Sina-(y1-y)*Cosa>=0 and (x2-x)*Cosa+(y2-y)*Sina<=0 and (x3-x)*Sina-(y3-y)*Cosa<=0 and (x4-x)*Cosa+(y4-y)*Sina>=0
调用方式:
call RectAct(长度,宽度,角度,位置x,位置y,是否选择玩家单位,选择盟友,整数)
选取以(x,y)一边中点,位于角度方向的矩形区域内单位 “是否选择玩家”为true,则选择玩家索引为“整数”的玩家的单位
若为false,则当“选择盟友”为true,则选择玩家索引为“整数”的玩家的友军单位,若为false,则选择敌军单位

顺便附上一个用这个做的技能:崩拳 没找到合适的模型和动作,不太好看
对面前的单位造成多次伤害,并且将其推到前方,最多造成10次伤害。每次造成(英雄力量)点伤害
多发了点 ,这个不需要H2I,I2G

test.w3x

24 KB, 下载次数: 47

评分

参与人数 1威望 +1 收起 理由
eff + 1

查看全部评分

发表于 2009-4-18 06:53:18 | 显示全部楼层
回答LZ第一句话,很多人写过.
回复

使用道具 举报

发表于 2009-4-18 23:16:53 | 显示全部楼层
写没写过不是关键,问题是用sin判断是有问题的。。。

问题是不精确。
回复

使用道具 举报

 楼主| 发表于 2009-4-18 23:21:05 | 显示全部楼层
引用第2楼eff于2009-04-18 23:16发表的 :
写没写过不是关键,问题是用sin判断是有问题的。。。

问题是不精确。


不太明白,麻烦具体点
回复

使用道具 举报

发表于 2009-4-19 00:59:31 | 显示全部楼层
先划个大圆 再在圆里找矩形区域 而且罗嗦了点 还有就是参数里存在没有意义的gg
其实为了不泄漏 可以利用return bug 给你举个例子
function aa takes nothing returns unit
&#160; &#160; local integer u = H2I(CreateUnit(xx))&#160; &#160;
&#160; &#160; return u
&#160; &#160; return null
endfunction
回复

使用道具 举报

发表于 2009-4-19 01:16:48 | 显示全部楼层
还有就是LZ为了追求那一点点可以忽略的效率 把代码写的可读性很差
并且 condition创建了没删掉 会泄漏...
回复

使用道具 举报

发表于 2009-4-19 01:27:41 | 显示全部楼层
[jass]function IsInRectangle takes real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, real x, real y returns boolean
    local real r1=(-y1+y2)*x+(x1-x2)*y+x2*y1-x1*y2
    local real r2=(-y2+y3)*x+(x2-x3)*y+x3*y2-x2*y3
    local real r3=(-y3+y4)*x+(x3-x4)*y+x4*y3-x3*y4
    local real r4=(-y4+y1)*x+(x4-x1)*y+x1*y4-x4*y1
    return (r1*r3>0 and r2*r4>0)
endfunction[/jass]
上面是判断一个点是不是在凸四边形A(x1,y1)-B(x2,y2)-C(x3,y3)-D(x4,y4)内部的函数.
回复

使用道具 举报

发表于 2009-4-19 01:33:40 | 显示全部楼层
为什么我上面的代码里同样的格式,却没有对齐呢?好奇怪。。。
回复

使用道具 举报

发表于 2009-4-19 02:07:51 | 显示全部楼层
LZ的想法是旋转矩形区域 但是矩形区域有4个关键点 要旋转4次 很麻烦 不如反过来旋转待判断的单位坐标点 于是我给出我的方法 只写了关键的部分 判断单位是否在指定区域中
function Rotation takes real CenX,real CenY,real TarX,real TarY,real rotation returns location
    local real A = TarX-CenX
    local real B = TarY-CenY
    local real NewX = A*Cos(rotation)-B*Sin(rotation)+CenX
    local real NewY = A*Sin(rotation)+B*Cos(rotation)+CenY
    return Location(NewX,NewY)
endfunction
function IsUnitInRect takes unit u,real rotation,real Xlen,real Ylen,real CenX,real CenY returns boolean
    local location uP = Rotation(CenX,CenY,GetUnitX(u),GetUnitY(u),-rotation)
    local real L = CenX-Xlen/2
    local real R = CenX+Xlen/2
    local real U = CenY+Ylen/2
    local real D = CenY-Ylen/2
    local real uX = GetLocationX(uP)
    local real uY = GetLocationY(uP)
    call RemoveLocation(uP)
    set uP = null
    if uX<L or uX>R or uY>U or uY<D then
    return false
    endif
    return true        
endfunction
回复

使用道具 举报

 楼主| 发表于 2009-4-19 08:36:52 | 显示全部楼层
关于如何判断点在矩形区域中的各种方法我考虑过,感觉这种方法是效率最高的
回复

使用道具 举报

 楼主| 发表于 2009-4-19 08:39:40 | 显示全部楼层
关于麻烦,其实只要算出来其他工作很简单,计算机不去管我们写的代码的原理,它只会计算
感谢4L的RETURN BUG
用到Sin和Cos是因为参数的限制,这个函数是为我的技能需要,这些参数是最直接的参数。其他所有量只有由这几个参数计算出的
回复

使用道具 举报

发表于 2009-4-19 11:33:48 | 显示全部楼层
你去测试一下就知道了,多摆几个单位,往诡异的地方释放技能可以看出Sin的严重不精确
回复

使用道具 举报

 楼主| 发表于 2009-4-19 11:56:00 | 显示全部楼层
但是我传递的参数中有角度,要根据施法者的状态来选取矩形区域,Sin不得不用 - -!!!
如果已经有了四个顶点,就不用了
回复

使用道具 举报

发表于 2009-4-19 12:02:53 | 显示全部楼层
引用第11楼eff于2009-04-19 11:33发表的  :
你去测试一下就知道了,多摆几个单位,往诡异的地方释放技能可以看出Sin的严重不精确
这么一说 我想起来 以前碰到过诡异现象 但是实际上后来发现并不是sin cos 函数不准确造成的 而是自己写代码没考虑极端情况造成的 比如说背刺技能的判定 一般想法是 被攻击单位角度减去攻击单位面向角度的绝对值是否小于某角度 大部分情况是没问题的 但是 比如允许角度30度 一个单位5度 另一个355度 显然从表面上说 两者是符合背刺条件的 然而按照上面的算法却不会造成背刺 我的解决方法是 假设上面的减法差值是a 则Acos(Cos(a))将这个角度映射到0~180度的范围 于是可以完美解决 可以肯定地说 cos sin函数已经算很精确了 就算到了微分的角度都很精确 jass在这点上真的比AS好上千倍了 AS才叫不准哩
回复

使用道具 举报

 楼主| 发表于 2009-4-19 12:16:10 | 显示全部楼层
引用第13楼c_kuhn于2009-04-19 12:02发表的 :

这么一说 我想起来 以前碰到过诡异现象 但是实际上后来发现并不是sin cos 函数不准确造成的 而是自己写代码没考虑极端情况造成的 比如说背刺技能的判定 一般想法是 被攻击单位角度减去攻击单位面向角度的绝对值是否小于某角度 大部分情况是没问题的 但是 比如允许角度30度 一个单位5度 另一个355度 显然从表面上说 两者是符合背刺条件的 然而按照上面的算法却不会造成背刺 我的解决方法是 假设上面的减法差值是a 则Acos(Cos(a))将这个角度映射到0~180度的范围 于是可以完美解决 可以肯定地说 cos sin函数已经算很精确了 就算到了微分的角度都很精确 jass在这点上真的比AS好上千倍了 AS才叫不准哩


那个用Cos(a)>=0.866就可以了吧
回复

使用道具 举报

发表于 2009-4-19 12:22:10 | 显示全部楼层
不行
注意范围
我觉得LZ没必要去追求那一点点可有可无的效率 真的 写代码 可读性第一 其次才是效率
回复

使用道具 举报

 楼主| 发表于 2009-4-19 12:26:58 | 显示全部楼层
习惯不同吧,我不是学习计算机的。
而且习惯现用现写,不喜欢系统,用到的都是根据需要量身定做的。

LS用的是degree?用radius 应该没问题
回复

使用道具 举报

发表于 2009-4-19 12:42:54 | 显示全部楼层
还是上面的例子
cos350 明显小于0 吧 符合Cos(a)>=0.866这个吗?
弧度和角度在符号上没有差别
回复

使用道具 举报

 楼主| 发表于 2009-4-19 12:47:48 | 显示全部楼层
Cos(350)>0 .........................
回复

使用道具 举报

发表于 2009-4-19 12:56:03 | 显示全部楼层
嗯 我错了 没注意看弧度跟角度 对着计算器弧度按了角度 看来是可以的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-5-3 10:11 , Processed in 0.233620 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表