python - 子弹看起来不像是从枪口里出来的 Pygame
问题描述
我遇到了一个问题,我的子弹看起来不像是从我的枪里出来的,它们看起来像是从玩家身体里出来的。左侧向上射得好,向下射得不好视频
***我想说的是我怎样才能让我的枪在我的鼠标位置精确旋转***
我尝试将我的枪调整到 120,但发生的情况是一切都适用于右侧而不是左侧VIDEO,因为你可以看到它只是小故障
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)
我的全枪课
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("hands.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)
how my images are blitted
```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)
# rotate and blit the image
surf.blit(rotated_image, origin)
我想我想说的是我怎样才能让我的枪完全在我的鼠标位置旋转而没有任何问题
我的完整代码脚本
解决方案
一种方法是计算出枪尖移动通过的弧相对于其x,y
坐标的椭圆。使用它来创建一个“查找表”
查找表,当索引为 0→360° 时,对于给定的角度,它给出了一对添加到“手臂”原点位置的偏移量。这个新点加在一起就是枪尖的坐标。例如,假设枪在 30°,我们访问end_of_gun_lookup[ 30 ]
,然后返回( 12, -6 )
,这对应于“手臂”精灵位置和枪尖之间的差异。
检查您的代码,角度似乎从大约-120
到120
. 显然我们不能对查找表有一个负索引,所以我们只需将所有内容移动120
,end_of_gun_lookup[ 0 ]
对于 angle -120
,end_of_gun_lookup[ 1 ]
对于 angle-119
等也是如此。
所以现在当你开始定位子弹时,它应该在“arm”位图上创建origin
,加上end_of_gun_lookup[ 120 + round( angle ) ]
但!我们如何创建该查找表?
一种方法是在位图旋转时以编程方式“跟随”枪尖。一旦找到枪尖,立即将该位置存储在查找表中以获得已知角度。
为了找到枪的尖端,我修改了“手臂”位图,在枪的末端有一个亮绿色的像素块 (3x3)。这可能是位图中尚未使用的任何颜色,但我选择了 green ( 8, 255, 0 )
。
然后我们创建函数,在每次旋转过程中,费力地在旋转位图的每个像素中寻找绿色像素。这很慢,而且不是您在玩游戏时想要做的事情。
这就是那个功能。这end_of_gun_lookup
是最终的查找表。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
. 也许代码需要处理这些,也许它们永远不会发生。
这给了我这样的结果:
end_of_gun_lookup = [(108, 160), (109, 162), (110, 163), (111, 163), (111, 163), (112, 164), (111, 166), (113, 167) , (114, 168), (114, 170), (115, 171), (116, 173), (116, 174), (118, 175), (118, 177), (120, 177), ( 120, 178), (121, 180), (122, 182), (124, 183), (125, 185), (95, 181), (126, 188), (129, 189), (130, 191), (130, 193), (133, 196), (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), (122, 140), (123, 140) ), (123, 142), (123, 142), (123, 143), (124, 145), (124, 146), (124, 147), (125, 147), (125, 149), (126, 151), (126, 151), (127, 153), (128, 154), (129, 156), (129, 157), (129, 158), (130, 159), (130) , 160), (132, 163), (133, 165), (134, 165), (135, 167), (136, 169), (105, 169), (137, 172), (107, 174) ), (137, 172), (103, 171), (103, 169), (102, 167), (131,163), (98, 165), (99, 162), (96, 160), (96, 159), (93, 159), (93, 157), (93, 155), (93, 154) , (91, 152), (89, 153), (89, 151), (89, 149), (87, 147), (86, 146), (85, 146), (84, 145), ( 85, 143), (84, 143), (82, 142), (83, 140), (82, 139), (83, 139), (82, 139), (82, 137), (82, 136),无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无]
最后的所有那些None
s 可能不会发生。至少不是通过鼠标旋转。
因此,一旦定义了此查找表,就可以将其合并到代码中,并删除(或注释掉)生成的代码。
编辑:
end_of_gun_lookup
因此,将上一步生成的查找表的定义添加到您的源中。然后修改blitRotate()
使用它。
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 )
参考代码:(使用上面的静态位图nug.png
)
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 ) )
推荐阅读
- java - 跳过 RegEx 分组
- wordpress - 如何将 Joomla K2 迁移到 Wordpress
- amazon-web-services - 尝试使用 AWS Amplify 从 Android 应用程序注册时遇到注册错误
- curl - cookies.txt 不适用于 Httrack 版本 3.49-2
- python-3.x - 在调度程序和 bash 脚本下读取泡菜文件的权限被拒绝
- android-studio - 当我将语言更改为阿拉伯语时如何解决颜色选择器中的大小问题
- android - Dagger 2.25 java.lang.NoClassDefFoundError: dagger/shaded/auto/common/BasicAnnotationProcessor
- android - Android中的自定义TextView
- xpages - xp:fileUpload 预加载可能吗?
- javascript - mySQL 数据库是否与编程语言分开工作