计算 X 和 Y 速度以在 pygame 内击中二维平面上的目标
Calculate X and Y velocity to hit the target on flat 2d surface in pygame
我正在使用 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
子弹 class:
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
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]))
我正在使用 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
子弹 class:
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
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]))