源战役客户端
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

450 行
11 KiB

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