GameMath = GameMath or {}
|
|
local GameMath = GameMath
|
|
local math = math
|
|
function GameMath.IsPointNear(p1x, p1y, p2x, p2y, near_val)
|
|
near_val = near_val or 1.0
|
|
|
|
local x_step = p1x - p2x
|
|
local y_step = p1y - p2y
|
|
local val = x_step*x_step + y_step*y_step
|
|
return val <= near_val*near_val
|
|
end
|
|
|
|
--检查两个点是否在x或y方向上接近
|
|
--用来判断p2是否在距离p1
|
|
function GameMath.IsPointNearRect(p1x, p1y, p2x, p2y, near_val)
|
|
if math.abs(p1x - p2x) > near_val then
|
|
return false
|
|
end
|
|
if math.abs(p1y - p2y) > near_val then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
function GameMath.IsPointNearAbs(p1, p2, val)
|
|
val = val or 1
|
|
return (math.abs(p1.x - p2.x) <= val) and (math.abs(p1.y - p2.y) <= val)
|
|
end
|
|
|
|
function GameMath.Round(x)
|
|
local val, pt = math.modf(x)
|
|
if pt > 0.5 then
|
|
val = val + 1
|
|
end
|
|
|
|
return val
|
|
end
|
|
|
|
--检测某点是否处于矩形内
|
|
function GameMath.IsInRect(px, py, rect_x, rect_y, rect_width, rect_height)
|
|
if px < rect_x - rect_width / 2 or px >= rect_x + rect_width / 2
|
|
or py < rect_y - rect_height / 2 or py >= rect_y + rect_height / 2 then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
|
|
--检测某点是否处于矩形内
|
|
function GameMath.HitRectTest(px, py, rect_x, rect_y, rect_width, rect_height)
|
|
if px < rect_x or px >= rect_x + rect_width
|
|
or py < rect_y or py >= rect_y + rect_height then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
--检测某点o是否a,b,c,d四个点组成的菱形内
|
|
function GameMath.inDiamond(o, a, b, c, d)
|
|
local l1 = co.Vector2(a.x - o.x,a.y - o.y)
|
|
local l2 = co.Vector2(b.x - o.x,b.y - o.y)
|
|
local l3 = co.Vector2(c.x - o.x,c.y - o.y)
|
|
local l4 = co.Vector2(d.x - o.x,d.y - o.y)
|
|
l1:normalise()
|
|
l2:normalise()
|
|
l3:normalise()
|
|
l4:normalise()
|
|
local total_degree = 0
|
|
total_degree = total_degree + math.acos(l2:dotProduct(l1))
|
|
total_degree = total_degree + math.acos(l3:dotProduct(l2))
|
|
total_degree = total_degree + math.acos(l4:dotProduct(l3))
|
|
total_degree = total_degree + math.acos(l1:dotProduct(l4))
|
|
if math.abs(total_degree / 2 - math.pi) <= 0.001 then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
--[[
|
|
求距离公式
|
|
@param need_sqrt 是否需要开方运算(不开方可以减少不必要的运算)
|
|
@x_mult,y_mult 距离倍率,小于1,两点距离扩大x_mult,y_mult倍 ,大于1,距离缩小x_mult,y_mult倍
|
|
]]--
|
|
function GameMath.GetDistance(p1x, p1y, p2x, p2y, need_sqrt,x_mult,y_mult)
|
|
local x_step_mult = x_mult or 1
|
|
local y_step_mult = y_mult or 1
|
|
|
|
local x_step = p1x - p2x
|
|
local y_step = p1y - p2y
|
|
local val = x_step*x_step*x_step_mult + y_step*y_step*y_step_mult
|
|
|
|
if need_sqrt then
|
|
return math.pow(val,0.5)
|
|
end
|
|
|
|
return val
|
|
end
|
|
|
|
--[[
|
|
求距离公式
|
|
@param need_sqrt 是否需要开方运算(不开方可以减少不必要的运算)
|
|
@x_mult,y_mult 距离倍率,小于1,两点距离扩大x_mult,y_mult倍 ,大于1,距离缩小x_mult,y_mult倍
|
|
]]--
|
|
function GameMath.GetDistance3D(p1x, p1y,p1z,p2x, p2y,p2z, need_sqrt,x_mult,y_mult)
|
|
local x_step_mult = x_mult or 1
|
|
local y_step_mult = y_mult or 1
|
|
|
|
local x_step = p1x - p2x
|
|
local y_step = p1y - p2y
|
|
local val = x_step*x_step*x_step_mult + y_step*y_step*y_step_mult
|
|
|
|
if need_sqrt then
|
|
return math.pow(val,0.5)
|
|
end
|
|
|
|
return val
|
|
end
|
|
|
|
--[[
|
|
求距离公式 椭圆
|
|
@param need_sqrt 是否需要开方运算(不开方可以减少不必要的运算)
|
|
]]--
|
|
function GameMath.GetEllipseDistance(p1x, p1y, p2x, p2y, need_sqrt)
|
|
|
|
local x_step = p1x - p2x
|
|
local y_step = p1y - p2y
|
|
local val = x_step*x_step + y_step*y_step * 4
|
|
|
|
if need_sqrt then
|
|
return math.pow(val,0.5)
|
|
end
|
|
|
|
return val
|
|
end
|
|
|
|
|
|
--把正圆的值转化成椭圆不同方向的值
|
|
function GameMath.ChangeEllipseValue(dir, value, ratio, type)
|
|
if dir then
|
|
ratio = ratio or 0.5
|
|
local radian = 0
|
|
if dir.x == 0 then
|
|
if dir.y > 0 then
|
|
radian = 90 / 180 * math.pi
|
|
elseif dir.y == 0 then
|
|
radian = 0
|
|
elseif dir.y < 0 then
|
|
radian = -270 / 180 * math.pi
|
|
end
|
|
else
|
|
radian = math.atan(dir.y / dir.x) --先计算夹角
|
|
end
|
|
|
|
local func = nil
|
|
if type == nil or type == 1 then --1为x方向较长 2 为y方向较长的椭圆
|
|
func = math.cos
|
|
else
|
|
func = math.sin
|
|
end
|
|
|
|
--椭圆处理
|
|
return value * ratio + math.abs(func(radian)) * value * (1 - ratio)
|
|
else
|
|
return value
|
|
end
|
|
end
|
|
--[[
|
|
取最近的点
|
|
@param point_list 坐标数组
|
|
@param px 参照点x坐标
|
|
@param py 参照点y坐标
|
|
@param get_point_func 从数组中的一个对象取出坐标,return x,y
|
|
]]--
|
|
function GameMath.GetNearestPoint(point_list,px,py,get_point_func)
|
|
|
|
local result
|
|
local prev_distance = -1
|
|
|
|
for _, point in pairs(point_list) do
|
|
local curr_distance
|
|
if get_point_handler == nil then
|
|
curr_distance = GameMath.GetDistance(px, py, point.x, point.y)
|
|
else
|
|
curr_distance = GameMath.GetDistance(px, py, get_point_func(point))
|
|
end
|
|
|
|
if prev_distance == -1 or prev_distance > curr_distance then
|
|
result = point
|
|
prev_distance = curr_distance
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
|
|
--判断点和直线的距离
|
|
function GameMath.DistancePointToLine(dir, pos, need_sqrt)
|
|
local x0, y0 = pos.x, pos.y --目标点相对于直线起点的相对坐标
|
|
local A, B = dir.y, -dir.x --直线方程的系数
|
|
local d1 = (A*x0 + B*y0)
|
|
local d = (d1*d1) / (A*A + B*B) --目标点和直线的距离的平方
|
|
|
|
if need_sqrt then
|
|
d = math.pow(d, 0.5)
|
|
end
|
|
return d
|
|
end
|
|
|
|
|
|
--二维角度值转成二维标准向量
|
|
function GameMath.AngleToDirection(angle)
|
|
local radian = angle / 180 * math.pi
|
|
local dir = co.TableXY(math.cos(radian), math.sin(radian))
|
|
co.NormaliseXYTable(dir)
|
|
return dir
|
|
end
|
|
|
|
function GameMath.Smooth(from, to, vel, smoothTime, timeDelta)
|
|
local omega = 2.0 / smoothTime
|
|
local x = omega * timeDelta
|
|
local exp = 1.0 / (1.0 + x + 0.48*x*x + 0.235*x*x*x)
|
|
local change = from - to
|
|
local temp = (vel + change * omega) * timeDelta
|
|
local new_vel = (vel - temp * omega) * exp
|
|
vel = new_vel
|
|
return to + (change + temp) * exp, vel
|
|
end
|
|
|
|
|
|
function GameMath.Lerp(from,to,t)
|
|
if t > 1 then
|
|
t = 1
|
|
elseif t < 0 then
|
|
t = 0
|
|
end
|
|
local delta = to - from
|
|
return from + delta * t
|
|
end
|
|
|
|
|
|
function GameMath.EaseOutQuad(from,to,value)
|
|
to = to - from
|
|
return -to * value * (value - 2) + from
|
|
end
|
|
|
|
function GameMath.EaseInQuad(from,to,value)
|
|
to = to - from
|
|
return to * value * value + from
|
|
end
|
|
|
|
function GameMath.EaseInOutQuad(from,to,value)
|
|
value = value /0.5
|
|
to = to - from
|
|
if (value < 1) then return to * 0.5 * value * value + from end
|
|
value = value - 1
|
|
return - to * 0.5 * (value * (value - 2) - 1) + from
|
|
end
|
|
|
|
function GameMath.EaseInOutQuart(from,to,value)
|
|
value = value /0.5
|
|
to = to - from
|
|
if (value < 1) then return to * 0.5 * value * value * value + from end
|
|
value = value - 1
|
|
return - to * 0.5 * (value * value * (value - 2) - 1) + from
|
|
end
|
|
|
|
|
|
|
|
function GameMath.EaseInOutCubic(from,to,value)
|
|
value = value /0.5
|
|
to = to - from
|
|
if value < 1 then
|
|
return to * 0.5 * value * value * value + from
|
|
end
|
|
|
|
value = value - 2
|
|
return to * 0.5 * (value * value * value + 2) + from
|
|
|
|
end
|
|
|
|
--获取中心点为x, y, 半径为dist的圆上的一个点
|
|
function GameMath.GetPosByCeterPoint(x, y, dist)
|
|
local angle = math.random(0, 360)
|
|
local dir = GameMath.AngleToDirection(angle)
|
|
local end_pos = co.TableXY((x + dir.x * dist), (y + dir.y * dist))
|
|
return end_pos
|
|
end
|
|
|
|
--[[
|
|
/**
|
|
*计算两点p1,p2连线上位置为pp的垂线上的某点,该点与连线的距离为l
|
|
* @param p1 起点
|
|
* @param p2 终点
|
|
* @param pp 0到1,表示p1到p2连线上的位置
|
|
* @param l 所求点与p1,p2连线的距离,可有正负
|
|
*/ ]]
|
|
function GameMath.GetVerticlePoint(p1, p2, pp, l)
|
|
local offset_x = p2.x-p1.x == 0 and 1 or p2.x-p1.x
|
|
local dir = co.Vector2((p1.y-p2.y)/offset_x, 1)
|
|
dir:normalise()
|
|
local p3 = p1 * (1-pp) + p2 * pp
|
|
p3 = p3 + dir * l
|
|
return p3
|
|
end
|
|
|
|
function GameMath.Bezier(list, t)
|
|
|
|
local point_list = DeepCopy(list)
|
|
local function lerp_xyz(from,to,t)
|
|
local x = GameMath.Lerp(from.x,to.x,t)
|
|
local y = GameMath.Lerp(from.y,to.y,t)
|
|
local z = GameMath.Lerp(from.z,to.z,t)
|
|
from.x = x
|
|
from.y = y
|
|
from.z = z
|
|
return from
|
|
end
|
|
|
|
local function calc_fun()
|
|
local lenth = #point_list
|
|
for i = 1, lenth-1 do
|
|
point_list[i] = lerp_xyz(point_list[i], point_list[i+1], t)
|
|
end
|
|
point_list[lenth] = nil
|
|
end
|
|
while #point_list > 2 do
|
|
calc_fun()
|
|
end
|
|
return GameMath.LerpXYZ(point_list[1], point_list[2], t)
|
|
end
|
|
function GameMath.LerpXYZ(from,to,t)
|
|
|
|
local x = GameMath.Lerp(from.x,to.x,t)
|
|
local y = GameMath.Lerp(from.y,to.y,t)
|
|
local z = GameMath.Lerp(from.z,to.z,t)
|
|
|
|
return co.TableXYZ(x,y,z)
|
|
end
|
|
function GameMath.GetDistanceXYZ(p1x,p1y,p1z,p2x,p2y,p2z)
|
|
local x_step = p1x - p2x
|
|
local y_step = p1y - p2y
|
|
local z_step = p1z - p2z
|
|
local val = x_step*x_step + y_step*y_step + z_step*z_step
|
|
|
|
return math.pow(val,0.5)
|
|
end
|
|
|
|
function GameMath.IsPointInDiamondRect(point,A,B,C,D)
|
|
local a = (B.x - A.x) * (point.y - A.y) - (B.y - A.y) * (point.x - A.x)
|
|
local b = (C.x - B.x) * (point.y - B.y) - (C.y - B.y) * (point.x - B.x)
|
|
local c = (D.x - C.x) * (point.y - C.y) - (D.y - C.y) * (point.x - C.x)
|
|
local d = (A.x - D.x) * (point.y - D.y) - (A.y - D.y) * (point.x - D.x)
|
|
|
|
if (a > 0 and b > 0 and c > 0 and d > 0) or (a < 0 and b < 0 and c < 0 and d < 0) then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
-- 判断点是否在多边形
|
|
function GameMath.IsPointInPolygonRect(checkPoint,polygonPoints)
|
|
local inside = false
|
|
local pointCount = #polygonPoints
|
|
local p1,p2
|
|
local i,j = 1,pointCount
|
|
for i = 1,pointCount do
|
|
p1 = polygonPoints[i]
|
|
p2 = polygonPoints[j]
|
|
if checkPoint.y < p2.y then
|
|
if p1.y <= checkPoint.y then
|
|
if ((checkPoint.y - p1.y) * (p2.x - p1.x) > (checkPoint.x - p1.x) * (p2.y - p1.y)) then
|
|
inside = not inside
|
|
end
|
|
end
|
|
elseif checkPoint.y < p1.y then
|
|
if ((checkPoint.y - p1.y) * (p2.x - p1.x) < (checkPoint.x - p1.x) * (p2.y - p1.y)) then
|
|
inside = not inside
|
|
end
|
|
end
|
|
j = i
|
|
end
|
|
return inside
|
|
end
|
|
--判断直线 AB 是否与线段CD 相交
|
|
function GameMath.LineIntersectSide(A,B,C,D)
|
|
local fC = (C.y - A.y) * (A.x - B.x) - (C.x - A.x) * (A.y - B.y)
|
|
local fD = (D.y - A.y) * (A.x - B.x) - (D.x - A.x) * (A.y - B.y)
|
|
|
|
if fC * fD > 0 then
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local GameMath_LineIntersectSide = GameMath.LineIntersectSide
|
|
|
|
function GameMath.SideIntersectSide(A,B,C,D)
|
|
if not GameMath_LineIntersectSide(A,B,C,D) then
|
|
return false
|
|
end
|
|
if not GameMath_LineIntersectSide(C,D,A,B) then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
function GameMath.PreciseDecimal(num, n)
|
|
|
|
n = n or 0
|
|
local nDecimal = 1/(10 ^ n)
|
|
local nLeft = num % nDecimal
|
|
local ret_val = num - nLeft
|
|
|
|
if nLeft*(10^n) >= 0.5 then
|
|
ret_val = ret_val + nDecimal
|
|
end
|
|
|
|
return ret_val
|
|
end
|
|
|
|
--两个向量之间的线性插值
|
|
function GameMath.GetVecLerp( v1, v2, alpha )
|
|
local result = {}
|
|
result.x = v1.x*(1 - alpha) + v2.x*alpha
|
|
result.y = v1.y*(1 - alpha) + v2.y*alpha
|
|
return result
|
|
end
|
|
|
|
function GameMath.PointRotate( p1, p2 )
|
|
local result = {}
|
|
result.x = p1.x*p2.x - p1.y*p2.y
|
|
result.y = p1.x*p2.y + p1.y*p2.x
|
|
return result
|
|
end
|
|
|
|
--vec向量以pivot为中心旋转angle角
|
|
function GameMath.RotateByAngle( vec, pivot, angle )
|
|
local Rad2Deg = 57.29578
|
|
angle = angle/Rad2Deg
|
|
local vec_angle = {x=math.cos(angle), y=math.sin(angle)}
|
|
local result = {}
|
|
result.x = vec.x - pivot.x
|
|
result.y = vec.y - pivot.y
|
|
result = GameMath.PointRotate(result, vec_angle)
|
|
result.x = result.x + pivot.x
|
|
result.y = result.y + pivot.y
|
|
return result
|
|
end
|