मैं पायथन और पाइगेम स्प्राइट्स का उपयोग करके एक विशिष्ट प्रकार का अंतरिक्ष आक्रमणकारी खेल बना रहा हूं। मैंने ज्यादातर चीजें की हैं और यह ठीक काम कर रहा है। लेकिन वास्तव में मेरे खेल में, गोली हमेशा सीधी जाती है, लेकिन मैं चाहता हूं कि यह दुश्मन को निशाना बनाए और हमेशा वहीं गोली मारे जहां दुश्मन है।

अपने प्लेयर अपडेट में मैं बस इतना कर रहा हूं कि जब भी स्पेस हिट होता है, तो वह गोली चलाता है।

if (keys[pygame.K_SPACE]):
    self.fire()

यह नीचे मेरी fire विधि है जो सिर्फ हैंडगन (जो मेरी बुलेट क्लास है) को कॉल कर रही है:

def fire(self):
    now = pygame.time.get_ticks()
    self.shoot_delay = 600
    self.shot_position = handguns.rect.x - enemy.rect.x
    print (self.shot_position)
    if (now - self.last_shot > self.shoot_delay):
        self.last_shot = now
        shot = HandGun(self.rect.centerx, self.rect.top)
        Every_Sprite.add(shot)
        handgun.add(shot)

यह नीचे मेरा दुश्मन वर्ग है जहां स्थिति सिर्फ यादृच्छिक है:

class Enemy_Agent(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(img_folder, "ship2.png")).convert()
        self.image.set_colorkey(WHITE)
        self.rect =self.image.get_rect()
        self.rect.x = random.randrange(width - self.rect.width)
        self.rect.y = random.randrange(-100, -40)

        self.speed = random.randrange(1,8)
        self.speedx = random.randrange(-3,3)
    def update(self):
        if (self.rect.right > width):
            self.rect.right = width
        if (self.rect.left < 0):
            self.rect.left = 0

        self.rect.y += self.speed
        #print("pos: ", self.rect.y)
        self.rect.x += self.speedx
        if(self.rect.top > Height - 10 or self.rect.left < -30 or     self.rect.right > width + 20):
            self.rect.x = random.randrange(width - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.speed = random.randrange(1, 8)

और, यह मेरी HandGun कक्षा अंतिम है। अगर कोई मेरी मदद कर सकता है और मुझे दुश्मन को गोली मारने की सलाह दे सकता है तो यह बहुत मददगार होगा।

class HandGun(pygame.sprite.Sprite):
    def __init__(self, cx, cy):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(img_folder, "bullet.png")).convert()
        self.image.set_colorkey(WHITE)
        self.rect = self.image.get_rect()
        self.rect.bottom = cy
        self.rect.centerx =cx
        self.speedy = -1
        self.speedx = None
    def update(self):
        self.rect.y += self.speedy + enemy.rect.centerx
        if(self.rect.bottom < 0):
            self.kill()
        pass
1
Paras Sharma 15 मई 2018, 13:38

1 उत्तर

सबसे बढ़िया उत्तर

यहां एक न्यूनतम उदाहरण दिया गया है जिसमें मैं सिर्फ माउस की स्थिति से लक्ष्य की ओर गोलियां चलाता हूं।

सबसे पहले हमें एक वेक्टर चाहिए जो लक्ष्य की ओर इशारा करता है (यहां direction कहा जाता है), इसलिए हम लक्ष्य स्थिति से माउस की स्थिति घटाते हैं।

हम direction वेक्टर के कोण का उपयोग करते हैं (जिसे आप as_polar विधि (ध्रुवीय निर्देशांक )) गोली घुमाने के लिए।

वेग वेक्टर प्राप्त करने के लिए, हम direction को सामान्य कर सकते हैं और इसे वांछित लंबाई (यानी गति) तक स्केल करने के लिए एक अदिश से गुणा कर सकते हैं।

import pygame as pg
from pygame.math import Vector2


BACKGROUND_COLOR = pg.Color(30, 30, 50)
BLUE = pg.Color('dodgerblue1')
LIME = pg.Color(192, 255, 0)


class Bullet(pg.sprite.Sprite):
    """ This class represents the bullet. """

    def __init__(self, pos, target, screen_rect):
        """Take the pos, direction and angle of the player."""
        super().__init__()
        self.image = pg.Surface((16, 10), pg.SRCALPHA)
        pg.draw.polygon(self.image, LIME, ((0, 0), (16, 5), (0, 10)))
        # The `pos` parameter is the center of the bullet.rect.
        self.rect = self.image.get_rect(center=pos)
        self.position = Vector2(pos)  # The position of the bullet.

        # This vector points from the mouse pos to the target.
        direction = target - pos
        # The polar coordinates of the direction vector.
        radius, angle = direction.as_polar()
        # Rotate the image by the negative angle (because the y-axis is flipped).
        self.image = pg.transform.rotozoom(self.image, -angle, 1)
        # The velocity is the normalized direction vector scaled to the desired length.
        self.velocity = direction.normalize() * 11
        self.screen_rect = screen_rect

    def update(self):
        """Move the bullet."""
        self.position += self.velocity  # Update the position vector.
        self.rect.center = self.position  # And the rect.

        # Remove the bullet when it leaves the screen.
        if not self.screen_rect.contains(self.rect):
            self.kill()


def main():
    pg.init()
    screen = pg.display.set_mode((800, 600))
    screen_rect = screen.get_rect()
    clock = pg.time.Clock()

    all_sprites = pg.sprite.Group()
    bullet_group = pg.sprite.Group()

    target = Vector2(400, 300)

    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.MOUSEBUTTONDOWN:
                # Shoot a bullet. Pass the start position (in this
                # case the mouse position) and the direction vector.
                bullet = Bullet(event.pos, target, screen_rect)
                all_sprites.add(bullet)
                bullet_group.add(bullet)

        all_sprites.update()

        screen.fill(BACKGROUND_COLOR)
        all_sprites.draw(screen)
        pg.draw.rect(screen, BLUE, (target, (3, 3)), 1)
        pg.display.flip()
        clock.tick(60)


if __name__ == '__main__':
    main()
    pg.quit()

यदि आप वैक्टर से परिचित नहीं हैं, तो आप त्रिकोणमिति का भी उपयोग कर सकते हैं।

यदि आप एक होमिंग मिसाइल चाहते हैं, तो आपको वर्तमान लक्ष्य स्थिति को बुलेट तक पहुंचाना होगा और प्रत्येक फ्रेम direction और velocity की पुनर्गणना करनी होगी।


एक गतिशील लक्ष्य को लक्षित करने के लिए, आपको भविष्य की स्थिति की गणना करने की आवश्यकता है जहां प्रक्षेप्य लक्ष्य से टकराएगा। आप इसे द्विघात समीकरण के साथ कर सकते हैं। मैं यहां जेफरी हंटिन के समाधान इस उत्तर से का उपयोग कर रहा हूं। आपको गोली की प्रारंभिक स्थिति, उसकी गति और लक्ष्य की स्थिति और वेग को intercept फ़ंक्शन में पास करना होगा और फिर द्विघात समीकरण को हल करना होगा। यह उस स्थिति वेक्टर को वापस कर देगा जहां गोली और लक्ष्य मिलते हैं। फिर वर्तमान लक्ष्य बिंदु के बजाय बस इस बिंदु पर शूट करें (आप अभी भी उसी कोड का उपयोग Bullet कक्षा में कर सकते हैं)।

import math

import pygame as pg
from pygame.math import Vector2


BACKGROUND_COLOR = pg.Color(30, 30, 50)
BLUE = pg.Color('dodgerblue1')
LIME = pg.Color(192, 255, 0)


class Bullet(pg.sprite.Sprite):
    """ This class represents the bullet. """

    def __init__(self, pos, target, screen_rect):
        """Take the pos, direction and angle of the player."""
        super().__init__()
        self.image = pg.Surface((16, 10), pg.SRCALPHA)
        pg.draw.polygon(self.image, LIME, ((0, 0), (16, 5), (0, 10)))
        # The `pos` parameter is the center of the bullet.rect.
        self.rect = self.image.get_rect(center=pos)
        self.position = Vector2(pos)  # The position of the bullet.

        # This vector points from the mouse pos to the target.
        direction = target - pos
        # The polar coordinates of the direction vector.
        radius, angle = direction.as_polar()
        # Rotate the image by the negative angle (because the y-axis is flipped).
        self.image = pg.transform.rotozoom(self.image, -angle, 1)
        # The velocity is the normalized direction vector scaled to the desired length.
        self.velocity = direction.normalize() * 11
        self.screen_rect = screen_rect

    def update(self):
        """Move the bullet."""
        self.position += self.velocity  # Update the position vector.
        self.rect.center = self.position  # And the rect.

        # Remove the bullet when it leaves the screen.
        if not self.screen_rect.contains(self.rect):
            self.kill()


def intercept(position, bullet_speed, target, target_velocity):
    a = target_velocity.x**2 + target_velocity.y**2 - bullet_speed**2
    b = 2 * (target_velocity.x * (target.x - position.x) + target_velocity.y * (target.y - position.y))
    c = (target.x - position.x)**2 + (target.y - position.y)**2

    discriminant = b*b - 4*a*c
    if discriminant < 0:
        print("Target can't be reached.")
        return None
    else:
        t1 = (-b + math.sqrt(discriminant)) / (2*a)
        t2 = (-b - math.sqrt(discriminant)) / (2*a)
        t = max(t1, t2)
        x = target_velocity.x * t + target.x
        y = target_velocity.y * t + target.y
        return Vector2(x, y)


def main():
    pg.init()
    screen = pg.display.set_mode((800, 600))
    screen_rect = screen.get_rect()
    clock = pg.time.Clock()

    all_sprites = pg.sprite.Group()
    bullet_group = pg.sprite.Group()

    target = Vector2(50, 300)
    target_velocity = Vector2(4, 3)

    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.MOUSEBUTTONDOWN:
                target_vector = intercept(Vector2(event.pos), 11, target, target_velocity)
                # Shoot a bullet. Pass the start position (in this
                # case the mouse position) and the target position vector.
                if target_vector is not None:  # Shoots only if the target can be reached.
                    bullet = Bullet(event.pos, target_vector, screen_rect)
                    all_sprites.add(bullet)
                    bullet_group.add(bullet)

        target += target_velocity
        if target.x >= screen_rect.right or target.x < 0:
            target_velocity.x *= -1
        if target.y >= screen_rect.bottom or target.y < 0:
            target_velocity.y *= -1

        all_sprites.update()

        screen.fill(BACKGROUND_COLOR)
        all_sprites.draw(screen)
        pg.draw.rect(screen, BLUE, (target, (5, 5)))
        pg.display.flip()
        clock.tick(60)


if __name__ == '__main__':
    main()
    pg.quit()

दरअसल, broofa's Solution का उपयोग करना बेहतर होगा क्योंकि यह कुछ विशेष मामलों को ध्यान में रखता है।

def intercept(position, bullet_speed, target, target_velocity):
    tx, ty = target - position
    tvx, tvy = target_velocity
    v = bullet_speed
    dstx, dsty = target

    a = tvx*tvx + tvy*tvy - v*v
    b = 2 * (tvx*tx + tvy*ty)
    c = tx*tx + ty*ty

    ts = quad(a, b, c)

    sol = None

    if ts:
        t0 = ts[0]
        t1 = ts[1]
        t = min(t0, t1)
        if t < 0:
            t = max(t0, t1)
        if t > 0:
            sol = Vector2(dstx + tvx * t,
                          dsty + tvy * t)

    return sol


def quad(a, b, c):
    sol = None
    if abs(a) < 1e-6:
        if abs(b) < 1e-6:
            sol = [0, 0] if abs(c) < 1e-6 else None
        else:
            sol = [-c/b, -c/b]
    else:
        disc = b*b - 4*a*c
        if disc >= 0:
            disc = math.sqrt(disc)
            a = 2*a
            sol = [(-b-disc)/a, (-b+disc)/a]

    return sol
3
skrx 18 मई 2018, 11:18