Рассчитайте X и Y скорость, чтобы поразить цель на плоской 2d поверхности в Pygame - PullRequest
1 голос
/ 05 марта 2019

Я создаю игру с использованием 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 Ответ

1 голос
/ 05 марта 2019

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