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