Python 子弹看起来不像是从枪里射出来的

Python 子弹看起来不像是从枪里射出来的,python,pygame,Python,Pygame,我有一个问题,我的子弹看起来不像是从我的枪里出来的,它们看起来像是从球员身上出来的,你可以在视频中看到,它在其他地方射击,或者是枪,左边也是一样,它向上射出好球,向下射出坏球 ***我想说的是,我怎样才能让我的枪在我的鼠标位置准确旋转*** 我试着把我的枪调到120,但是发生的事情是所有的事情都对右边有效,而不是左边,正如你所看到的,只是小故障 def draw(self,drawX,drawY): self.rect.topleft = (drawX,drawY

我有一个问题,我的子弹看起来不像是从我的枪里出来的,它们看起来像是从球员身上出来的,你可以在视频中看到,它在其他地方射击,或者是枪,左边也是一样,它向上射出好球,向下射出坏球

***我想说的是,我怎样才能让我的枪在我的鼠标位置准确旋转***

我试着把我的枪调到120,但是发生的事情是所有的事情都对右边有效,而不是左边,正如你所看到的,只是小故障


    def draw(self,drawX,drawY):
 
        self.rect.topleft =  (drawX,drawY)
 
            # the guns hitbox
 
            # rotatiing the gun
        dx = self.look_at_pos[0] - self.rect.centerx
        dy = self.look_at_pos[1] - self.rect.centery 
            
        angle = (190/math.pi) * math.atan2(-dy, dx)
      
        gun_size = self.image.get_size()
        pivot = (8, gun_size[1]//2)
            
 
        blitRotate(window, self.image, self.rect.center, pivot, angle)

        if((angle > 90 or angle < -90) and self.gunDirection != "left"):
            self.gunDirection = "left"
            self.image = pygame.transform.flip(self.image, False, True)
        if((angle < 90 and angle > -90) and self.gunDirection != "right"):
            self.gunDirection = "right"
            self.image = pygame.transform.flip(self.image, False, True)





我想我想说的是,我怎样才能让我的枪在我的鼠标位置准确地旋转而不出任何问题呢


我的完整代码

一种方法是计算出枪尖相对于其坐标x,y移动的弧的椭圆。使用此选项可创建一个“”

由0索引时的查找表→360°,其中,对于给定的角度,它给出了一对要添加到“手臂”原点位置的偏移。这个新点加在一起就是枪尖的坐标。例如,假设枪位于30°,我们访问枪查找[30]的
结束,它返回
(12,-6)
,这对应于“臂”精灵位置和枪尖之间的差异

检查代码时,角度似乎从大约
-120
120
。显然,我们不能对查找表使用负索引,所以我们只需将所有内容移动
120
,因此
end\u of_gun\u lookup[0]
用于角度
-120
end\u of_gun\u lookup[1]
用于角度
-119
,等等

因此,现在当您开始初始定位子弹时,应该在“手臂”位图中创建它
原点
,再加上
枪的末端查找[120+圆形(角度)]

但是!我们如何创建查找表

实现这一点的一种方法是在位图旋转时以编程方式“跟随”枪尖。一旦找到枪尖,立即将该位置存储在已知角度的查找表中

为了找到枪的尖端,我修改了“手臂”位图,在枪的末端有一个亮绿色像素块(3x3)。这可能是位图中尚未使用的任何颜色,但我选择了绿色
(8255,0)

然后我们创建一个函数,在每次旋转期间,在旋转位图的每个像素中费力地查找绿色像素。这是相当缓慢的,并且不是你想在游戏中做的事情

这就是这个函数。_gun_lookup的
end_是最终的查找表。首先,我们用“无值”
None
填充每个可能的角度

# Create empty look-up point for green-pixel offsets
SUPA_GREEN = ( 8, 255, 0 )
end_of_gun_lookup = [ None ] * 360
findGreenPixels()
函数可以在找到像素位置时填充此全局列表:

def findGreenPixels( origin, image, rotation_angle ):
    global end_of_gun_lookup
    
    result = None
    # Bitmap offset 
    origin_x, origin_y = origin
    # find the Super Green pixel at the end of the gun.
    # very slow, and inefficient 
    width = image.get_rect().width
    height = image.get_rect().height
    for y in range( height ):
        for x in range( width ):
            pixel_colour = image.get_at( ( x, y ) )
            if ( pixel_colour == SUPA_GREEN ):
                #print( "GREEN AT %d -> %d,%d" % ( rotation_angle, x, y ) )
                result = ( round( origin_x - x ), round( origin_y - y ) )
                # results go from -120 -> 120, so offset
                # before storing the point.
                # Distance is relative to bitmap orgin too
                end_of_gun_lookup[ round( rotation_angle ) + 120 ] = ( result )
            if ( result != None ):
                break
        if ( result != None ):
            break
    return result
它基本上遍历每个像素,寻找绿色。如果找到,将填充查找表。我使用了一个3x3像素块,因为在图像旋转过程中,像素被着色和模糊,一个像素块在保持完全相同的颜色方面有更好的变化

在程序结束时,我们转储查找表:

pygame.quit()

### PRINT THE LOOKUP TABLE
end_of_gun_lookup = fillLookupHoles( end_of_gun_lookup )
print( "end_of_gun_lookup = "+ str( end_of_gun_lookup ) )
在我的测试过程中,无论我移动鼠标有多慢,有时桌子上都有未定义的位置。虽然我只管理过一次完美的桌子。无论如何,我添加了一些代码,使用中点线算法来估计单个缺失值的位置。这把那些洞清理干净了。显然,您不能在表的末尾生成点,这些点保持为
None
。也许代码需要处理这些,也许它们永远不会发生

这给了我这样一个结果:

查表结束=[(108160),(109162),(110163),(111163),(111163),(112164),(111166),(113167),(114168),(114170),(115171),(116173),(116174),(118175),(118177),(120178),(121180),(122182),(124183),(125185),(95181),(126188),(129189),(130191),(130193),(133196),(103, 194), (104, 197), (137, 199), (107, 201), (106, 199), (137, 197), (105, 196), (104, 194), (101, 193), (101, 191), (101, 189), (130, 183), (99, 186), (99, 184), (99, 183), (97, 182), (98, 180), (98, 178), (95, 179), (96, 177), (96, 175), (94, 174), (95, 172), (94, 171), (94, 170), (94, 170), (93, 168), (94, 166), (95, 165), (95, 164), (95, 163), (95, 162), (94, 161), (94, 160), (95, 159), (95, 158), (96, 157), (97, 156), (98, 155), (98, 154), (98, 155), (98, 154), (98, 152), (101, 151), (101, 151), (101, 150), (102, 150), (102, 149), (104, 148), (105, 148), (106, 148), (107, 146), (108, 147), (109, 146), (110, 146), (110, 146), (112, 146), (114, 145), (115, 145), (117, 144), (117, 144), (119, 145), (119, 144), (122, 145), (123, 144), (126, 146), (126, 146), (128, 145), (129, 145), (131, 146), (134, 145), (134, 145), (136, 147), (138, 147), (140, 147), (142, 147), (144, 148), (144, 148), (148, 149), (149, 150), (151, 150), (153, 150), (154, 152), (158, 151), (159, 152), (161, 153), (163, 153), (166, 154), (169, 156), (170, 156), (172, 158), (175, 158), (177, 159), (179, 160), (178, 159), (176, 157), (174, 156), (173, 154), (171, 154), (169, 152), (168, 149), (164, 149), (163, 149), (163, 147), (161, 146), (160, 144), (159, 143), (155, 142), (154, 141), (154, 141), (154, 140), (151, 138), (151, 138), (148, 138), (146, 137), (145, 136), (144, 135), (144, 134), (143, 134), (142, 133), (139, 133), (140, 132), (138, 132), (137, 131), (136, 131), (135, 130), (134, 130), (133, 129), (133, 129), (132, 130), (130, 130), (130, 129), (129, 129), (129, 129), (128, 129), (127, 128), (128, 129), (126, 129), (126, 129), (125, 129), (125, 130), (124, 130), (124, 130), (123, 131), (124, 131), (124, 132), (123, 132), (122, 132), (122, 134), (122, 134), (123, 134), (122, 134), (122, 135), (122, 136), (122, 137), (123, 139), (122, 139), (12
def findGreenPixels( origin, image, rotation_angle ):
    global end_of_gun_lookup
    
    result = None
    # Bitmap offset 
    origin_x, origin_y = origin
    # find the Super Green pixel at the end of the gun.
    # very slow, and inefficient 
    width = image.get_rect().width
    height = image.get_rect().height
    for y in range( height ):
        for x in range( width ):
            pixel_colour = image.get_at( ( x, y ) )
            if ( pixel_colour == SUPA_GREEN ):
                #print( "GREEN AT %d -> %d,%d" % ( rotation_angle, x, y ) )
                result = ( round( origin_x - x ), round( origin_y - y ) )
                # results go from -120 -> 120, so offset
                # before storing the point.
                # Distance is relative to bitmap orgin too
                end_of_gun_lookup[ round( rotation_angle ) + 120 ] = ( result )
            if ( result != None ):
                break
        if ( result != None ):
            break
    return result
pygame.quit()

### PRINT THE LOOKUP TABLE
end_of_gun_lookup = fillLookupHoles( end_of_gun_lookup )
print( "end_of_gun_lookup = "+ str( end_of_gun_lookup ) )
def blitRotate(surf, image, pos, originPos, angle):

    ... 

    # use lookup table to find the end-of gun at this angle
    x_origin, y_origin = origin
    x_offset, y_offset = end_of_gun_lookup[ round( angle ) + 120 ]
    final_pos = ( x_origin + x_offset, y_origin + y_offset )

    # rotate and blit the image
    surf.blit( rotated_image, final_pos )
import pygame
import random
import math

# Window size
WINDOW_WIDTH    = 400
WINDOW_HEIGHT   = 400
WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
DARK_BLUE = (   3,   5,  54)


# Create empty look-up point for green-pixel offsets
SUPA_GREEN = ( 8, 255, 0 )
end_of_gun_lookup = [ None ] * 360

def midpoint( point_a, point_b ):
    """ Use the midpoint-line formula to return the point between 
        point_a and point_b """
    mid_x = round( ( point_a[0] + point_b[0] ) / 2 ) 
    mid_y = round( ( point_a[1] + point_b[1] ) / 2 ) 
    return ( mid_x, mid_y )

def fillLookupHoles( coord_list ):
    """ Find any gaps in the lookup table, by finding the mid-point line
        pixel between the two points, giving an estimated position """
    for i in range( 1, len ( coord_list )-1 ):  # we can't fix end-points, ignore first & last
        before = coord_list[ i-1 ]
        after  = coord_list[ i+1 ]
        if ( coord_list[ i ] == None and before != None and after != None ):
            coord_list[ i ] = midpoint( before, after )
            print( "Filled hole at angle %d" % ( i - 120 ) )
    return coord_list

def findGreenPixels( origin, image, rotation_angle ):
    global end_of_gun_lookup

    result = None
    # Bitmap offset
    origin_x, origin_y = origin
    # find the Super Green pixel at the end of the gun.
    # very slow, and inefficient
    width = image.get_rect().width
    height = image.get_rect().height
    for y in range( height ):
        for x in range( width ):
            pixel_colour = image.get_at( ( x, y ) )
            if ( pixel_colour == SUPA_GREEN ):
                #print( "GREEN AT %d -> %d,%d" % ( rotation_angle, x, y ) )
                result = ( round( origin_x - x ), round( origin_y - y ) )
                # results go from -120 -> 120, so offset
                # before storing the point.
                # Distance is relative to bitmap orgin too
                end_of_gun_lookup[ round( rotation_angle ) + 120 ] = ( result )
            if ( result != None ):
                break
        if ( result != None ):
            break
    return result



def blitRotate(surf, image, pos, originPos, angle):
 
    # calcaulate the axis aligned bounding box of the rotated image
    w, h = image.get_size()
    sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle)) 
    min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
 
        # calculate the translation of the pivot 
    pivot        = pygame.math.Vector2(originPos[0], -originPos[1])
    pivot_rotate = pivot.rotate(angle)
    pivot_move   = pivot_rotate - pivot
 
        # calculate the upper left origin of the rotated image
    origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
 
        # get a rotated image
    rotated_image = pygame.transform.rotate(image, angle)

    end_of_gun_coord = findGreenPixels( origin, rotated_image, angle ) 
 
        # rotate and blit the image
    surf.blit(rotated_image, origin)
 


 
class handgun():
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.color = color
        self.rect = pygame.Rect(x,y,height,width)
 
        # LOL THESE IS THE HAND
        self.shootsright = pygame.image.load("nug.png")
        self.image = self.shootsright
        self.rect  = self.image.get_rect(center = (self.x, self.y))
        self.look_at_pos = (self.x, self.y)
 
        self.isLookingAtPlayer = False
        self.look_at_pos = (x,y)
        self.hitbox = (self.x + -18, self.y, 46,60)

        self.gunDirection = "right"

    def draw(self,drawX,drawY):
        self.rect.topleft =  (drawX,drawY)
 
        # the guns hitbox
        # rotatiing the gun
        dx = self.look_at_pos[0] - self.rect.centerx
        dy = self.look_at_pos[1] - self.rect.centery 
            
        angle = (120/math.pi) * math.atan2(-dy, dx)
        gun_size = self.image.get_size()
        pivot = (8, gun_size[1]//2)
 
        blitRotate(window, self.image, self.rect.center, pivot, angle)

        if((angle > 90 or angle < -90) and self.gunDirection != "left"):
            self.gunDirection = "left"
            self.image = pygame.transform.flip(self.image, False, True)
        if((angle < 90 and angle > -90) and self.gunDirection != "right"):
            self.gunDirection = "right"
            self.image = pygame.transform.flip(self.image, False, True)

    def lookAt( self, coordinate ):
        self.look_at_pos = coordinate
 
 

 
white = (255,255,255)
handgun1 = handgun(300,300,10,10,white)
        



### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Track Path of Green")


### Main Loop
clock = pygame.time.Clock()
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.MOUSEBUTTONUP ):
            # On mouse-click
            pass

    handgun1.direction = "right"

    # gun rotation
    mousex, mousey = pygame.mouse.get_pos()
    if not handgun1.isLookingAtPlayer:
        handgun1.lookAt((mousex, mousey))


    # Update the window, but not more than 60fps
    window.fill( DARK_BLUE )
    handgun1.draw( 200, 200 )
    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop(60)

pygame.quit()

### PRINT THE LOOKUP TABLE
end_of_gun_lookup = fillLookupHoles( end_of_gun_lookup )
print( "end_of_gun_lookup = "+ str( end_of_gun_lookup ) )