首页 > 解决方案 > 在pygame中计算X和Y速度以击中平面二维表面上的目标

问题描述

我正在使用 Python 和 Pygame 创建游戏。

在将 JS 与 p5.js 和 Java 与 libwjgl 一起使用之前,我已经使用过这个函数,但由于某种原因,它不适用于 Pygame。

我正在尝试从移动物体击中静态目标。现在我错过了目标。你可以在 gif 中看到它。每个射弹都应该击中目标(现在一切都未命中,但朝正确的方向射击)

一旦玩家点击鼠标按钮,子弹就会被发射。

这就是我这样做的方式:

def shoot(self):
  posX, posY = 100, 100 # Static target coordinates

  diffX = self.player.x - posX               
  diffY = self.player.y - posY                 

  distance = math.sqrt((diffX * diffX) + (diffY * diffY)) # Calculate the distance

  velX = float((-1 / distance * diffX * 6)) # Calculate volocity required to hit the target
  velY = float((-1 / distance * diffY * 6)) # Calculate volocity required to hit the target 

  # Bullet(x, y, width, height, velocityX, velocityY)
  # Will be rendered on the screen
  self.bullets.append(Bullet(self.player.x, self.player.y, 10, 10,  velX, velY)) # The bullet is added to array, which later gets rendered on the screen

子弹类:

import pygame

class Bullet(object):
  def __init__(self, x, y, width, height, velY, velX):
    self.width = width
    self.height = height
    self.x = x
    self.y = y
    self.velX = velX
    self.velY  = velY
    self.bullet = pygame.Rect(self.x, self.y, self.width, self.height)


  def render(self, screen):
    pygame.draw.rect(screen, (255, 255, 255), self.bullet)

  def update(self):
    self.bullet.x += self.velX
    self.bullet.y += self.velY

这与我提到的其他语言完美配合,但在 Python 中,发射的弹丸已关闭......

这是它的外观。红色方块是目标:

谢谢大家的帮助。对此,我真的非常感激 :)

编辑:完整的游戏代码

import pygame
from PodSixNet.Connection import connection, ConnectionListener
from objects.Button import Button
from time import sleep
from STATE import STATE
import sys, os
from objects.Text import Text
from resources.hubColours import ColoursClass
from pathlib import Path
from objects.Bullet import Bullet
import math

class DefenseGame(ConnectionListener):
def __init__(self, hub, width, height, soundController, fontController, fps=60):
    #Hub
    self.hub = hub

    #COLOURS
    self.color = ColoursClass("alt")

    #SOUNDS
    self.soundController = soundController

    #SCREEN
    self.width = width
    self.height = height
    self.background = pygame.Surface((self.width, self.height), pygame.HWSURFACE | pygame.DOUBLEBUF).convert()  
    self.background.fill(self.color.getColour(7)) # fill background white

    #INFO
    self.fps = fps
    self.playtime = 0.0

    #FONTS
    self.fontController = fontController

    #STATE
    # All player related stuff is stored in the HUB.
    # TODO:
    # Player class
    self.isRunning = True


    self.moveLeft = False
    self.moveRight = False
    self.moveUp = False
    self.moveDown = False

    self.bullets = []

    self.moveAmnt = 5

    self.timeLeft = "Waiting for players..."


    self.clock = pygame.time.Clock()

    #OBJECTS
    self.on_init()

#Initialize game objects
def on_init(self):
  self.char = pygame.transform.smoothscale(pygame.image.load(str(Path("character.png"))), (50, 50))

# Draws on screen
def render(self, screen):                               # Update all objects (through object handler)                                            # This will update the contents of the entire display
    screen.blit(self.background, (0, 0))
    self.drawInfoText("Color: " + self.hub.playerColorName, 10, 10, self.fontController.tiny, screen)
    self.drawInfoText("Player Count: " + str(self.hub.getInGamePlayerCount()), 10, 20, self.fontController.tiny, screen)
    self.drawInfoText("FPS: " + str(round(self.getFPS(), 2)), 10, 30, self.fontController.tiny, screen)
    self.drawInfoText("Network Status: " + self.hub.statusLabel, 10, 40, self.fontController.tiny, screen)
    self.player.render(screen)
    self.player2.render(screen)
    # screen.blit(self.char, (self.posX, self.posY))

    if len(self.bullets) > 0:
      for b in self.bullets:
        b.render(screen)

def onMove(self):
  connection.Send({"action": "playerMove", 'x': self.player.x , 'y': self.player.y, 'id': self.hub.playerId})


def shoot(self):
  posX, posY = pygame.mouse.get_pos()

  diffX = self.player.x - posX               
  diffY = self.player.y - posY                 

  distance = math.sqrt((diffX * diffX) + (diffY * diffY))
  print("DISTANCE: ", distance)

  velX = float((-1 / distance * diffX * 20))
  velY = float((-1 / distance * diffY * 20))  

  print(velX, velY)

  self.bullets.append(Bullet(self.player.x, self.player.y, 10, 10,  velX, velY))

# Looks for events
def handle_events(self, events):
    for event in events:
        if event.type == pygame.QUIT: 
            self.exitGame(event)
            self.hub.setState(STATE.Home)
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                self.exitGame(event)
                self.hub.setState(STATE.SelectGame)

            if event.key == pygame.K_w:
              self.moveUp = True
            if event.key == pygame.K_a:
              self.moveLeft = True
            if event.key == pygame.K_s:
              self.moveDown = True
            if event.key == pygame.K_d:
              self.moveRight = True

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_w:
              self.moveUp = False
            if event.key == pygame.K_a:
              self.moveLeft = False
            if event.key == pygame.K_s:
              self.moveDown = False
            if event.key == pygame.K_d:
              self.moveRight = False

        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:          # Mouse first button
                self.shoot()

# Update stuff (loop)
def update(self):
    self.Pump()                 # Connection
    connection.Pump()           # Connection

    timer = self.clock.tick(self.fps)
    if self.moveLeft:
      self.player.x -= timer
      self.onMove()
    if self.moveRight:
      self.player.x += timer
      self.onMove()
    if self.moveUp:
      self.player.y -= timer
      self.onMove()
    if self.moveDown:
      self.player.y += timer
      self.onMove()

    if len(self.bullets) > 0:
      for b in self.bullets:
        b.update()
    # sleep(0.001)


# returns FPS
def getFPS(self):
    self.clock.tick(self.fps)
    return  self.clock.get_fps()

# Helper for quickly drawing on screen
def drawInfoText(self, text, x, y, font, screen):
    surface = font.render(str(text), 1, self.color.getColour(8))
    screen.blit(surface, (x, y))

# Exits the game to home
def exitGame(self, e):
    self.soundController.stopSoundEffects()
    connection.Send({"action":"exitGame", "isInGame": False})
    self.hub.isInGame = False

标签: pythonpygamegame-physicsgame-development

解决方案


self.bullet是一个pygame.Rect对象。子弹的位置由矩形 ( self.bullet.x, self.bullet.y) 的位置跟踪。由于矩形位置是积分的,因此每次更新位置时都会导致不准确。

使用浮点数据来跟踪位置。使用 c。

存储子弹的位置和pygame.math.Vector2物体的速度。

class Bullet(object):
    def __init__(self, x, y, width, height, velX, velY):
        self.width = width
        self.height = height
        self.x = x
        self.y = y
        self.bullet = pygame.Rect(self.x, self.y, self.width, self.height)
        self.pos = pygame.math.Vector2(self.bullet.center)
        self.vel = pygame.math.Vector2(velX, velY)

更新位置属性而不是矩形位置:

class Bullet(object):

    # [...]

    def update(self):
        self.pos = self.pos + self.vel

在绘制子弹之前更新矩形的位置:

class Bullet(object):

    # [...]

    def render(self, screen):
        self.bullet.center = (int(self.pos[0]), int(self.pos[1]))
        pygame.draw.rect(screen, (255, 255, 255), self.bullet)

用于pygame.math.Vector2计算速度:

def shoot(self):
    posX, posY = 100, 100 # Static target coordinates

    traget = pygame.math.Vector2(posX, posY)
    start  = pygame.math.Vector2(self.player.x, self.player.y)

    delta = traget - start
    distance = delta.length() 
    direction = delta.normalize()

    vel = direction * 6
    self.bullets.append(Bullet(self.player.x, self.player.y, 10, 10, vel[0], vel[1])) 

推荐阅读