Python 为什么当我试图消除道路上的塔楼招牌时,塔楼防御路径会变得一团糟?

Python 为什么当我试图消除道路上的塔楼招牌时,塔楼防御路径会变得一团糟?,python,math,Python,Math,我想尽快完成我的塔防游戏。 如果塔位于具有给定路径列表的路径上,我会遇到问题。 即使我尽了最大的努力,它也永远不会起作用 我已经试过很多次来解决这个问题,比如蒂姆的塔防youtube教程中的技术。这几乎完全解释了为什么它不起作用。 但不管我怎么努力,它似乎永远不会正常工作。 找到指向教程的链接。 警告:视频很长 x, y = tower.x, tower.y for n, point in enumerate(path): point_x, point_y = point[0], poi

我想尽快完成我的塔防游戏。 如果塔位于具有给定路径列表的路径上,我会遇到问题。 即使我尽了最大的努力,它也永远不会起作用

我已经试过很多次来解决这个问题,比如蒂姆的塔防youtube教程中的技术。这几乎完全解释了为什么它不起作用。 但不管我怎么努力,它似乎永远不会正常工作。 找到指向教程的链接。 警告:视频很长

x, y = tower.x, tower.y
for n, point in enumerate(path):
    point_x, point_y = point[0], point[1]
    dis_x = abs(point_x - x)
    dis_y = abs(point_y - y)
    dis = math.sqrt((dis_x - x)**2 + (dis_y - y)**2)
    print(dis)
    if dis < 130:
        return False
return True
x,y=tower.x,tower.y
对于n,枚举中的点(路径):
点x,点y=点[0],点[1]
dis_x=abs(点_x-x)
dis_y=abs(点y-y)
dis=数学sqrt((dis_x-x)**2+(dis_y-y)**2)
打印(dis)
如果dis<130:
返回错误
返回真值
你可能会想“我为什么要这样做”,所以我对它做了一些修改:

import numpy as np
closest = []
x, y = tower.x, tower.y
for n, point in enumerate(path):
    point_x, point_y = point[0], point[1]
    dis_x = abs(point_x - x)
    dis_y = abs(point_y - y)
    dis = math.sqrt((dis_x - x)**2 + (dis_y - y)**2)
    print(dis)
    if len(closest) <= 2:
        if dis < 130:
            closest.append(point)
p1 = np.array([x, y])
p2 = np.array(closest[0])
p3 = np.array(closest[1])
dis = np.cross(p2-p1,p3-p1)/np.linalg.norm(p2-p1)
if dis < 90:
    return False
return True
将numpy导入为np
最近的=[]
x、 y=塔.x,塔.y
对于n,枚举中的点(路径):
点x,点y=点[0],点[1]
dis_x=abs(点_x-x)
dis_y=abs(点y-y)
dis=数学sqrt((dis_x-x)**2+(dis_y-y)**2)
打印(dis)

如果len(nestest)如@ImperishableNight所述,那么问题在于函数仅比较路径上的每个点,并检查距离是否小于某个阈值(在您的情况下为130像素)。但这还不够,因为我们不仅对路径每段的端点感兴趣,而且对路径之间的所有点感兴趣。为此,我们需要计算点和线段之间的距离

我已经用一个简单的
Point
类来替换pygame提供的任何东西,编写并评论了以下代码。我把问题分解成一堆小函数来解决你的问题。如果有任何不清楚的地方,请告诉我

import math
import random

class Point:

    def __init__(self, x=0, y=0):
        """
        A really simple Point class.
        Replaces whatever pygame provides for this example.
        """
        self.x = x
        self.y = y

    def __repr__(self):
        """
        A convenient representation of a Point class.
        So we see the x and y values when printing these objects.
        """
        return "({0}, {1})".format(self.x, self.y)

def gen_rand_point(width, height):
    """
    Creates random x and y values for a Point object
    """
    rand_x = random.randint(0, width) 
    rand_y = random.randint(0, height)
    point = Point(x=rand_x, y=rand_y)
    return point

def gen_rand_point_list(width, height, num_points):
    """
    Creates a list of random points using the previous function.
    """
    points = []
    for i in range(num_points):
        point = gen_rand_point(width, height)
        points.append(point)
    return points

def points_to_segments(points, loop=False):
    """
    Converts a list of points into a list of segments.
    Offsets the point list and zips it to create "segments".
    A segment is just a tuple containing two Point objects.
    """
    starts = points
    ends = points[1:] + [points[0]]
    segments = list(zip(starts, ends))
    if loop:
        return segments
    else:
        return segments[:-1]

def calc_sqr_dist(point_a, point_b):
    """
    Calculates the square distance between two points.
    Can be useful to save a wasteful math.sqrt call.
    """
    delta_x = point_b.x - point_a.x
    delta_y = point_b.y - point_a.y
    sqr_dist = (delta_x ** 2) + (delta_y ** 2)
    return sqr_dist

def calc_dist(point_a, point_b):
    """
    Calculates the distance between two points.
    When you need a wasteful math.sqrt call.
    """
    sqr_dist = calc_sqr_dist(point_a, point_b)
    dist = math.sqrt(sqr_dist)
    return dist

def calc_dot_product(segment_a, segment_b):
    """
    Calculates the dot product of two segments.
    Info about what the dot product represents can be found here:
    https://math.stackexchange.com/q/805954
    """
    a0, a1 = segment_a
    b0, b1 = segment_b
    ax = a1.x - a0.x
    ay = a1.y - a0.y
    bx = b1.x - b0.x
    by = b1.y - b0.y
    dot = (ax * bx) + (ay * by)
    return dot

def calc_point_segment_dist(point, segment):
    """
    Gets the distance between a point and a line segment.
    Some explanation can be found here:
    https://stackoverflow.com/a/1501725/2588654
    """
    start, end = segment
    sqr_dist = calc_sqr_dist(start, end)

    #what if the segment's start and end are the same?
    if sqr_dist == 0:
        dist = calc_dist(point, start)
        return dist
    #what if it is not that easy?
    else:
        segment_a = (start, point)
        segment_b = (start, end)#really is just segment...
        dot = calc_dot_product(segment_a, segment_b)
        t = float(dot) / sqr_dist
        clamped_t = max(0, min(1, t))#clamps t to be just within the segment
        #the interpolation is basically like a lerp (linear interpolation)
        projection = Point(
            x = start.x + (t * (end.x - start.x)),
            y = start.y + (t * (end.y - start.y)),
        )
        dist = calc_dist(point, projection)
        return dist

def calc_point_path_dist(point, path):
    """
    Gets the distances between the point and each segment.
    Then returns the minimum distance of all of these distances.
    """
    dists = [calc_point_segment_dist(point, segment) for segment in path]
    min_dist = min(dists)
    return min_dist

if __name__ == "__main__":
    """
    A fun example!
    """
    width = 800
    height = 600
    num_path_points = 5
    tower_range = 50

    tower = gen_rand_point(width, height)
    path_points = gen_rand_point_list(width, height, num_path_points)
    path = points_to_segments(path_points)
    dist = calc_point_path_dist(tower, path)
    in_range = dist <= tower_range
    print(dist, in_range)
导入数学
随机输入
课程点:
定义初始化(self,x=0,y=0):
"""
一个非常简单的Point类。
替换pygame为此示例提供的任何内容。
"""
self.x=x
self.y=y
定义报告(自我):
"""
点类的方便表示形式。
所以我们在打印这些对象时会看到x和y值。
"""
返回“({0},{1})”.format(self.x,self.y)
def gen_rand_点(宽度、高度):
"""
为点对象创建随机的x和y值
"""
rand_x=random.randint(0,宽度)
rand_y=random.randint(0,高度)
点=点(x=rand\ux,y=rand\uy)
返回点
def gen_rand_point_列表(宽度、高度、点数):
"""
使用上一个函数创建随机点列表。
"""
点数=[]
对于范围内的i(num_点):
点=根和点(宽度、高度)
点。追加(点)
返回点
def点到段(点,循环=假):
"""
将点列表转换为线段列表。
偏移点列表并将其拉入拉链以创建“线段”。
段只是包含两个点对象的元组。
"""
起点=点数
结束=点[1::+[点[0]]
段=列表(zip(开始、结束))
如果循环:
返回段
其他:
返回段[:-1]
def calc_sqr_dist(点a、点b):
"""
计算两点之间的平方距离。
可用于保存浪费的math.sqrt调用。
"""
delta_x=点_b.x-点_a.x
delta_y=点_b.y-点_a.y
sqr_dist=(delta_x**2)+(delta_y**2)
返回sqr_区
def calc_dist(点a、点b):
"""
计算两点之间的距离。
当您需要一个浪费的math.sqrt调用时。
"""
sqr_dist=计算sqr_dist(点a、点b)
dist=math.sqrt(sqr\u dist)
返回区
def calc_dot_产品(段a、段b):
"""
计算两段的点积。
有关dot产品所代表内容的信息可在此处找到:
https://math.stackexchange.com/q/805954
"""
a0,a1=段_a
b0,b1=段_b
ax=a1.x-a0.x
ay=a1.y-a0.y
bx=b1.x-b0.x
by=b1.y-b0.y
点=(ax*bx)+(ay*by)
返回点
def calc_point_segment_dist(点,段):
"""
获取点和线段之间的距离。
这里可以找到一些解释:
https://stackoverflow.com/a/1501725/2588654
"""
开始,结束=段
sqr_dist=计算sqr_dist(开始、结束)
#如果线段的起点和终点相同怎么办?
如果sqr_dist==0:
距离=计算距离(点、起点)
返回区
#如果不是那么容易呢?
其他:
段a=(起点,点)
段b=(开始,结束)#实际上只是段。。。
点=计算点积(a段、b段)
t=浮动(点)/sqr\u距离
夹紧t=最大(0,最小(1,t))#夹紧t,使其正好位于管段内
#插值基本上类似于lerp(线性插值)
投影=点(
x=start.x+(t*(end.x-start.x)),
y=start.y+(t*(end.y-start.y)),
)
距离=计算距离(点、投影)
返回区
def计算点路径距离(点,路径):
"""
获取点与每个线段之间的距离。
然后返回所有这些距离的最小距离。
"""
距离=[计算点\段\路径段的距离(点,段)]
最小距离=最小(距离)
返回最小距离
如果名称=“\uuuuu main\uuuuuuuu”:
"""
一个有趣的例子!
"""
宽度=800
高度=600
路径点数=5
塔架_范围=50
塔=发电机和发电机点(宽度、高度)
路径点数=根点数列表(宽度、高度、路径点数)
路径=点到线段(路径点)
距离=计算点路径距离(塔,路径)

in_range=dist没有那么容易。如果dis<130,我会更改数字130,但它从来都不起作用,即使我尝试了所有可能的数字。帮助你,你期望什么