简体   繁体   中英

Drawing line with infinity length in the direction of cursor in Pygame

I'm searching for some help with pygame. I'm developing simple game in Python to learn Pygame. I want to make spaceship which we can rotate and we can shooting with laser line. I have done controlling by arrow keys, we can also rotating spaceship with mouse position, but I've got a problem with shooting. I want to make a line with infinity length from spaceship position to mouse direction. How I can do that? Here is my code:

  def draw_objects(self):
        SCREEN.fill(BLACK)
        self.target = pygame.mouse.get_pos()
        self.x = self.player.position[0] #player x position
        self.y = self.player.position[1] #player y position
        self.mx = self.target[0] #mouse x position
        self.my = self.target[1] #mouse y position
        self.slope=float(float(self.y-self.my)/float(self.x-self.mx+0.1)) #slope
        self.x_new =  DISPLAY_WIDTH #ray length
        self.y_new = self.y + self.slope * (self.x_new - self.x) 
        self.player.draw()
        self.draw_columns()
        for agent in self.all_agents:
            agent.draw()
            agent.draw_vectors()
        if self.player.shoot == True:
            pygame.draw.line(SCREEN, GREEN, self.player.position,(self.x_new, self.y_new), 2)

        pygame.display.update()

在此处输入图片说明

It's not working properly, because it's work only to the right of spaceship. In other cases it draws a line in reflection to cursor.

在此处输入图片说明

I will be grateful for your help.

slope doesn't keep direction.
You have to get sign of player_x - mouse_x + 0.1 and use with x_new

    dx = player_x - mouse_x + 0.1

    reversed_sign_x = 1 if dx < 0 else -1

    x_new = reversed_sign_x * DISPLAY_WIDTH

Full working example:

  • move mouse to move line,
  • click left button to set player new position.

.

import pygame

# --- constants ---

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600

# --- functions ---

def calculate(player_x, player_y, mouse_x, mouse_y):
    dx = player_x - mouse_x + 0.1
    dy = player_y - mouse_y

    reversed_sign_x = 1 if dx < 0 else -1
    #reversed_sign_y = 1 if dy < 0 else -1

    slope = dy/dx

    x_new = reversed_sign_x * DISPLAY_WIDTH
    y_new = player_y + slope * (x_new - player_x)

    return x_new, y_new

# --- main ---

# - init -

pygame.init()
SCREEN = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))

# - objects -

player_x = DISPLAY_WIDTH // 2
player_y = DISPLAY_HEIGHT // 2

mouse_x = player_x
mouse_y = player_y

x_new, y_new = calculate(player_x, player_y, mouse_x, mouse_y)

# - mainloop -

clock = pygame.time.Clock()
running = True

while running:

    # - events -

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            player_x, player_y = event.pos
        elif event.type == pygame.MOUSEMOTION:
            x_new, y_new = calculate(player_x, player_y, event.pos[0], event.pos[1])

    # - updates -

    # empty

    # - draws -

    SCREEN.fill(BLACK)
    pygame.draw.line(SCREEN, GREEN, (player_x, player_y), (x_new, y_new), 2)
    pygame.display.flip()

    # - FPS -

    clock.tick(25)

# - end -

pygame.quit()

furas is right, you have to check whether the mouse is on the left or right side of the player and negate the DISPLAY_WIDTH if it's on the left. I came to a similar solution:

def target_coords(position):
    x, y = position  # Unpack player position into x, y.
    mx, my = pygame.mouse.get_pos()  # Unpack mouse pos into mx, my.
    slope = (y-my) / (x-mx+0.1)
    # This is a conditional expression, similar to `if condition: ... `else: ... `.
    x_new = DISPLAY_WIDTH if x < mx else -DISPLAY_WIDTH
    y_new = y + slope * (x_new - x)
    return x_new, y_new

Note that this function only computes the target coordinates and returns them (functions should preferably do only one thing). Draw the line and everything else in another function.

There's also an alternative solution: You could use pygame vectors and first calculate the vector to the target, normalize it and scale it by the desired length (the DISPLAY_WIDTH ).

import pygame
from pygame.math import Vector2


pygame.init()
DISPLAY_WIDTH = 640
GREEN = pygame.Color('aquamarine1')
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
position = Vector2(300, 200)  # A pygame.math.Vector2 as the position.
done = False

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    screen.fill((30, 30, 30))
    pygame.draw.circle(screen, GREEN, (int(position.x), int(position.y)), 7)
    # Calculate the vector to the target by subtracting pos from mouse pos.
    # Normalizing it gives you a unit vector which you can scale
    # by multiplying it with the DISPLAY_WIDTH.
    target_vec = (pygame.mouse.get_pos()-position).normalize() * DISPLAY_WIDTH
    pygame.draw.line(screen, GREEN, position, position+target_vec, 2)

    pygame.display.flip()
    clock.tick(30)

pygame.quit()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM