微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在一个位置周围创建精灵?

如何解决如何在一个位置周围创建精灵?

对于我正在创建的游戏,我的敌舰会向玩家精灵发射激光。 这些敌人旋转以面向玩家,然后发射旨在与玩家飞船相撞的射弹。

然而,这些激光精灵当前生成一个固定位置,因此当玩家四处移动时,它们会与敌舰碰撞箱重叠,如您所见in this gif

如何让生成位置围绕敌方精灵的边缘移动,以便在敌方精灵之外创建激光?

相关部分在用于生成位置的 DroneArc 类在第 146 行 的 Shoot 方法内,以及 第 44 行的激光类

这里是简化的代码,如果需要可以复制:

import pygame
import sys
import time
import math

pygame.init()

WIDTH = 750
HEIGHT = 750
SIZE = WIDTH,HEIGHT 

CLOCK = pygame.time.Clock()
screen = pygame.display.set_mode(SIZE)

FPS = 120

def in_game():
    run = True
    global player
    player = MainShip(310,600)
    global enemies
    enemies = [Drone_Arc(50,50,(50,50),0),Drone_Arc(50,650,0)]

    while run:
        screen.fill(0)
        player.x,player.y = pygame.mouse.get_pos()
        player.draw()

        for enemy in enemies[:]:
            angle =90-math.degrees(math.atan2((player.y+player.get_height()/2 - (enemy.y+enemy.get_height()/2)),(player.x+player.get_width()/2- (enemy.x+enemy.get_width()/2))))
            enemy.rotate_ship(angle)
            enemy.draw()
            enemy.shoot(angle)
            enemy.move_lasers(player)

            if collide(enemy,player):
                    enemies.remove(enemy)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
    
        pygame.display.update()
        CLOCK.tick(FPS)

def collide(obj1,obj2):
    offset_x = obj2.x - obj1.x
    offset_y = obj2.y - obj1.y
    return obj1.mask.overlap(obj2.mask,((int(offset_x)),((int(offset_y)))))

class Laser(pygame.sprite.Sprite):
    def __init__(self,x,y,w,h,dx,dy):
        pygame.sprite.Sprite.__init__(self)
        self.original_image = pygame.Surface([w,h],pygame.SRCALPHA)
        self.color = (255,0)
        self.original_image.fill(self.color)
        self.image = self.original_image
        self.mask = pygame.mask.from_surface(self.image)
        self.dx = dx
        self.dy = dy
        self.x = x
        self.y = y
        self.rect = self.image.get_rect(center = (self.x,self.y)) 

    def draw(self,screen):
        screen.blit(self.image,self.rect)

    def rotate_laser(self,angle):
        self.image = pygame.transform.rotate(self.original_image,angle)
        self.rect = self.image.get_rect(center = (self.x,self.y)) 
        self.mask = pygame.mask.from_surface(self.image)

    def move(self,speed):
        self.x += self.dx*speed
        self.y += self.dy*speed
        self.rect = self.image.get_rect(center = (self.x,self.y))

    def collision(self,obj):
        return collide(self,obj)


class Ship(pygame.sprite.Sprite):
    def __init__(self,y):
        self.x = x
        self.y = y
        self.ship_img = None
        self.laser_img = None
        self.lasers = []
        self.cooldown_counter = 0

    def cooldown(self):
        if self.cooldown_counter >= self.COOLDOWN:
            self.cooldown_counter = 0
        elif self.cooldown_counter > 0:
            self.cooldown_counter += 1

    def get_width(self):
        return self.image.get_width()

    def get_height(self):
        return self.image.get_height()

    def rotate_ship(self,angle):

        w,h       = self.original_image.get_size()
        Box        = [pygame.math.Vector2(p) for p in [(0,(w,-h),(0,-h)]]
        Box_rotate = [p.rotate(angle) for p in Box]
        min_Box    = (min(Box_rotate,key=lambda p: p[0])[0],min(Box_rotate,key=lambda p: p[1])[1])
        max_Box    = (max(Box_rotate,max(Box_rotate,key=lambda p: p[1])[1])

        pivot        = pygame.math.Vector2(w/2,-h/2)
        pivot_rotate = pivot.rotate(angle)
        pivot_move   = pivot_rotate - pivot

        origin = (self.x - w/2 + min_Box[0] - pivot_move[0],self.y - h/2 - max_Box[1] + pivot_move[1])
        self.image = pygame.transform.rotate(self.original_image,angle)
        self.mask = pygame.mask.from_surface(self.image)

class MainShip(Ship): 
    COOLDOWN = 15
    def __init__(self,y):
        super().__init__(x,y)
        self.original_image = pygame.Surface([36,62],255,255)
        self.original_image.fill(self.color)
        self.image = self.original_image
        self.mask = pygame.mask.from_surface(self.image)

    def draw(self):
        screen.blit(self.image,(self.x,self.y))

class Drone_Arc(Ship):
    COOLDOWN = 50
    def __init__(self,path,speed):
        super().__init__(x,36],255)
        self.original_image.fill(self.color)
        self.image = self.original_image
        self.mask = pygame.mask.from_surface(self.image)
        self.laser_speed = 3
        self.angle = 0

    def shoot(self,angle):
        if self.cooldown_counter == 0:
            radians = math.atan2((player.y+player.get_height()/2 - (self.y+self.get_height()/2)),(player.x+player.get_width()/2- (self.x+self.get_width()/2)))
            dx = math.cos(radians)
            dy = math.sin(radians)
            
            cx,cy =  self.x + self.get_height() / 2,self.y + self.get_width()/2
            lx,ly = cx + dx * (self.get_height()/2 + 11),cy + dy * (self.get_height()/2 + 11)
            
            print(dx,dy)
            laser_1 = Laser(lx,ly,81,22,dy)
            laser_1.rotate_laser(angle)
            self.lasers.append(laser_1)
            self.cooldown_counter = 1

    def move_lasers(self,obj):
        self.cooldown()
        for laser in self.lasers:
            laser.move(self.laser_speed)
            if laser.collision(obj):
                self.lasers.remove(laser)
    
    def draw(self):
        screen.blit(self.image,self.y))

        pygame.draw.circle(screen,(255,(player.x + player.get_width()/2,player.y + player.get_height()/2),3)
        pygame.draw.circle(screen,(self.x+self.get_width()/2,self.y + self.get_height()/2),((((player.x + player.get_height()/2)+(self.x-self.get_width()/2))/2),(((player.y + player.get_height()/2)+(self.y+self.get_height()/2))/2)),3)

        for laser in self.lasers:
            laser.draw(screen)

in_game()

解决方法

阅读 How do I rotate an image around its center using PyGame? 并将建议应用于 Laser 类。这大大简化了您的代码:

class Laser(pygame.sprite.Sprite):
    def __init__(self,x,y,w,h,dx,dy):
        pygame.sprite.Sprite.__init__(self)
        self.original_image = pygame.Surface([w,h],pygame.SRCALPHA)
        self.color = (255,0)
        self.original_image.fill(self.color)
        self.image = self.original_image
        self.mask = pygame.mask.from_surface(self.image)
        self.dx = dx
        self.dy = dy
        self.x = x
        self.y = y
        self.rect = self.image.get_rect(center = (self.x,self.y)) 

    def draw(self,screen):
        screen.blit(self.image,self.rect)

    def rotate_laser(self,angle):
        self.image = pygame.transform.rotate(self.original_image,angle)
        self.rect = self.image.get_rect(center = (self.x,self.y)) 
        self.mask = pygame.mask.from_surface(self.image)

    def move(self,speed):
        self.x += self.dx*speed
        self.y += self.dy*speed
        self.rect = self.image.get_rect(center = (self.x,self.y)) 

在新代码中,属性 xy 指定了激光的中心点。当激光发射时,您所要做的就是计算激光的中心 (lx,ly),具体取决于船的中心 (cy,cy ) 和射击方向 (dx,dy):

class Drone_Arc(Ship):
    # [...]

     def shoot(self,angle):
        if self.cooldown_counter == 0:
            radians = math.atan2((player.y+player.get_height()/2 - (self.y+self.get_height()/2)),(player.x+player.get_width()/2- (self.x+self.get_width()/2)))
            dx = math.cos(radians)
            dy = math.sin(radians)
            
            cx,cy =  self.x + self.get_height() / 2,self.y + self.get_width()/2
            lx,ly = cx + dx * (self.get_height()/2 + 11),cy + dy * (self.get_height()/2 + 11)
            
            laser_1 = Laser(lx,ly,81,22,dy)
            laser_1.rotate_laser(angle)
            
            self.lasers.append(laser_1)
            self.cooldown_counter = 1


碰撞检测不再起作用,因为 pygame.mask.Mask.overlap 的第二个参数是掩码左上边缘之间的偏移:

def collide(obj1,obj2):
   offset_x = obj2.x - obj1.x
   offset_y = obj2.y - obj1.y
   return obj1.mask.overlap(obj2.mask,((int(offset_x)),((int(offset_y)))))

由于激光的属性xy不存储左上边缘而是存储枢轴点(中心点),因此偏移量的计算是错误的。

然而,这可以轻松解决。只需修复偏移量的计算:

class Laser(pygame.sprite.Sprite):
    # [...]

        def collision(self,obj):
        offset_x = obj.x - self.rect.left
        offset_y = obj.y - self.rect.top
        return self.mask.overlap(obj.mask,((int(offset_y)))))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。