在pygame中计算X和Y速度以击中2d平面上的目标

时间:2019-03-05 18:02:57

标签: python pygame game-physics game-development

我正在使用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

1 个答案:

答案 0 :(得分:1)

self.bulletpygame.Rect对象。子弹的位置由矩形(self.bullet.xself.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)

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

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]))