如何找到 Sprite 和屏幕角之间的距离(以像素为单位)? [英] How to find the distance (in pixels) between the Sprite and screen corners?
本文介绍了如何找到 Sprite 和屏幕角之间的距离(以像素为单位)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我需要找到动画 worker
对象与屏幕的 4 个角(左上、右上、左下、右下)之间的距离(以像素为单位).pygame
的哪个函数给出了这个信息?我需要在每次 update
迭代时获取此信息.
I need to find the distance (in pixels) between the animated worker
objects and the 4 corners of the screen (upper left, upper right, lower left, lower right).
Which function of pygame
gives this information? I need to get this information at each update
iteration.
import pygame, random
import sys
WHITE = (255, 255, 255)
GREEN = (20, 255, 140)
GREY = (210, 210 ,210)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)
SCREENWIDTH=1000
SCREENHEIGHT=578
IMG_BACKGROUND = "background.jpg"
IMG_WORKER_RUNNING = "images/workers/worker_1.png"
IMG_WORKER_IDLE = "images/workers/worker_2.png"
IMG_WORKER_ACCIDENT = "images/workers/accident.png"
class Background(pygame.sprite.Sprite):
def __init__(self, image_file, location, *groups):
# we set a _layer attribute before adding this sprite to the sprite groups
# we want the background to be actually in the back
self._layer = -1
pygame.sprite.Sprite.__init__(self, groups)
# let's resize the background image now and only once
self.image = pygame.transform.scale(pygame.image.load(image_file).convert(), (SCREENWIDTH, SCREENHEIGHT))
self.rect = self.image.get_rect(topleft=location)
class GeoFenceInfluenceZone(pygame.sprite.Sprite):
def __init__(self, rect, *groups):
# we set a _layer attribute before adding this sprite to the sprite groups
self._layer = 0
pygame.sprite.Sprite.__init__(self, groups)
self.image = pygame.surface.Surface((rect.width, rect.height))
self.image.fill(GREY)
self.rect = rect
class GeoFence(pygame.sprite.Sprite):
def __init__(self, rect, risk_level, *groups):
# we set a _layer attribute before adding this sprite to the sprite groups
self._layer = 1
pygame.sprite.Sprite.__init__(self, groups)
self.image = pygame.surface.Surface((rect.width, rect.height))
self.image.fill(GREEN)
self.rect = rect
self.risk_level = risk_level
self.font = pygame.font.SysFont('Arial', 20)
text = self.font.render(risk_level, 1, (255,0,0), GREEN)
text_rect = text.get_rect(center=(rect.width/2, rect.height/2))
self.image.blit(text, text_rect)
class Worker(pygame.sprite.Sprite):
# we introduce to possible states: RUNNING and IDLE
RUNNING = 0
IDLE = 1
ACCIDENT = 2
NUMBER_OF_ACCIDENTS = 0
def __init__(self, image_running, image_idle, image_accident, location, *groups):
self.font = pygame.font.SysFont('Arial', 10)
# each state has it's own image
self.images = {
Worker.RUNNING: pygame.transform.scale(get_image(image_running), (45, 45)),
Worker.IDLE: pygame.transform.scale(get_image(image_idle), (20, 45)),
Worker.ACCIDENT: pygame.transform.scale(get_image(image_accident), (40, 40))
}
# we set a _layer attribute before adding this sprite to the sprite groups
# we want the workers on top
self._layer = 2
pygame.sprite.Sprite.__init__(self, groups)
# let's keep track of the state and how long we are in this state already
self.state = Worker.IDLE
self.ticks_in_state = 0
self.image = self.images[self.state]
self.rect = self.image.get_rect(topleft=location)
self.direction = pygame.math.Vector2(0, 0)
self.speed = random.randint(1, 3)
self.set_random_direction()
def set_random_direction(self):
# random new direction or standing still
vec = pygame.math.Vector2(random.randint(-100,100), random.randint(-100,100)) if random.randint(0, 5) > 1 else pygame.math.Vector2(0, 0)
# check the new vector and decide if we are running or fooling around
length = vec.length()
speed = sum(abs(int(v)) for v in vec.normalize() * self.speed) if length > 0 else 0
if (length == 0 or speed == 0) and (self.state != Worker.ACCIDENT):
new_state = Worker.IDLE
self.direction = pygame.math.Vector2(0, 0)
elif self.state != Worker.ACCIDENT:
new_state = Worker.RUNNING
self.direction = vec.normalize()
else:
new_state = Worker.ACCIDENT
self.ticks_in_state = 0
self.state = new_state
# use the right image for the current state
self.image = self.images[self.state]
def update(self, screen):
self.ticks_in_state += 1
# the longer we are in a certain state, the more likely is we change direction
if random.randint(0, self.ticks_in_state) > 70:
self.set_random_direction()
# now let's multiply our direction with our speed and move the rect
vec = [int(v) for v in self.direction * self.speed]
self.rect.move_ip(*vec)
# if we're going outside the screen, change direction
if not screen.get_rect().contains(self.rect):
self.direction = self.direction * -1
# spritecollide returns a list of all sprites in the group that collide with
# the given sprite, but if the sprite is in this group itself, we have
# to ignore a collision with itself
if any(s for s in pygame.sprite.spritecollide(self, building_materials, False) if s != self):
self.direction = self.direction * -1
if any(s for s in pygame.sprite.spritecollide(self, machines, False) if s != self):
self.direction = self.direction * -1
# Risk handling
self.handle_risks()
self.rect.clamp_ip(screen.get_rect())
def handle_risks(self):
for s in pygame.sprite.spritecollide(self, fences, False):
if s != self:
self.speed = 0
self.state = Worker.ACCIDENT
self.image = self.images[self.state]
Worker.NUMBER_OF_ACCIDENTS += 1
class BuildingMaterials(pygame.sprite.Sprite):
def __init__(self, image_file, location, *groups):
# we set a _layer attribute before adding this sprite to the sprite groups
self._layer = 2
pygame.sprite.Sprite.__init__(self, groups)
self.image = pygame.transform.scale(pygame.image.load(image_file).convert_alpha(), (40, 40))
self.rect = self.image.get_rect(topleft=location)
class Excavator(pygame.sprite.Sprite):
def __init__(self, image_file, location, *groups):
# we set a _layer attribute before adding this sprite to the sprite groups
self._layer = 3
pygame.sprite.Sprite.__init__(self, groups)
self.image = pygame.transform.scale(pygame.image.load(image_file).convert_alpha(), (170, 170))
self.rect = self.image.get_rect(topleft=location)
image_cache = {}
def get_image(key):
if not key in image_cache:
image_cache[key] = pygame.image.load(key)
return image_cache[key]
pygame.init()
# currently, one group would be enough
# but if you want to use some collision handling in the future
# it's best to group all sprites into special groups (no pun intended)
all_sprites = pygame.sprite.LayeredUpdates()
workers = pygame.sprite.Group()
building_materials = pygame.sprite.Group()
fences = pygame.sprite.Group()
fences_infl_zones = pygame.sprite.Group()
screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption("TEST")
# create multiple workers
for pos in ((30,30), (50, 400), (200, 100), (700, 200)):
Worker(IMG_WORKER_RUNNING, IMG_WORKER_IDLE, IMG_WORKER_ACCIDENT, pos, all_sprites, workers, building_materials, machines, fences)
# create multiple building material stocks
for pos in ((50,460),(50,500),(100,500),(850,30),(800,30)):
BuildingMaterials("images/materials/building_blocks{}.png".format(random.randint(1,3)), pos, all_sprites, building_materials)
# create multiple geo-fences
risks = ["H","M","L"]
for rect in (pygame.Rect(510,150,75,52), pygame.Rect(450,250,68,40), pygame.Rect(450,370,68,48),
pygame.Rect(0,0,20,SCREENHEIGHT),pygame.Rect(0,0,SCREENWIDTH,20),
pygame.Rect(SCREENWIDTH-20,0,20,SCREENHEIGHT),pygame.Rect(0,SCREENHEIGHT-20,SCREENWIDTH,20)):
risk = risks[random.randint(0,2)]
GeoFence(rect, risk, all_sprites, fences)
# create influence zones for all geo-fences
for rect in (pygame.Rect(495,135,105,80), pygame.Rect(435,235,98,68), pygame.Rect(435,355,98,76)):
GeoFenceInfluenceZone(rect, all_sprites, fences_infl_zones)
# and the background
Background(IMG_BACKGROUND, [0,0], all_sprites)
carryOn = True
clock = pygame.time.Clock()
while carryOn:
for event in pygame.event.get():
if event.type==pygame.QUIT:
carryOn = False
pygame.display.quit()
pygame.quit()
quit()
all_sprites.update(screen)
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(20)
推荐答案
您可以为角创建点向量,然后只需减去精灵的位置(我在这里只使用鼠标位置)以获得指向角的向量角,最后调用length
方法得到这些向量的长度.
You could create point vectors for the corners and then just subtract the position of the sprite (I just use the mouse pos here) to get vectors that point to the corners and finally call the length
method to get the lengths of these vectors.
import pygame as pg
from pygame.math import Vector2
pg.init()
screen = pg.display.set_mode((640, 480))
width, height = screen.get_size()
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
# Create point vectors for the corners.
corners = [
Vector2(0, 0), Vector2(width, 0),
Vector2(0, height), Vector2(width, height),
]
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
mouse_pos = pg.mouse.get_pos()
# Subtract the position from the point vectors and call the `length`
# method of the resulting vectors to get the distances to the points.
# Subtract the position from the point vectors and call the `length`
# method of the resulting vectors to get the distances to the points.
distances = []
for vec in corners:
distance = (vec - mouse_pos).length()
distances.append(distance)
# The 4 lines above can be replaced by a list comprehension.
# distances = [(vec - mouse_pos).length() for vec in corners]
# I just display the distances in the window title here.
pg.display.set_caption('{:.1f}, {:.1f}, {:.1f}, {:.1f}'.format(*distances))
screen.fill(BG_COLOR)
pg.display.flip()
clock.tick(60)
这篇关于如何找到 Sprite 和屏幕角之间的距离(以像素为单位)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文