【发布时间】:2016-12-20 01:41:05
【问题描述】:
已编辑,问题底部的解决方案
在这个问题的一些好人的帮助下,我有了一些改进:Python - Shoot a bullet in the direction (angle in degrees) my spaceship is facing。
现在的问题是,虽然使飞船朝所面对的方向加速的原理,但似乎不适用于弹丸。当子弹从船上以特定角度射出时,似乎有一个奇怪的偏移。
我将把代码放在下面,UPDATE() 和 BOOST() 方法负责使船移动并且可以正常工作。
射弹使用几乎相同的原理,没有加速。
这是一个视频,让您可以直观地看到正在运行的游戏并查看问题所在https://youtu.be/-s7LGuLhePI
这是我的 Ship 和 vector 类,它们与问题有关。 (我将省略并删除此处不需要显示的方法)
类 Ship 包含 ship 元素以及 Projectile 类
import pygame
import colors
import math
from vectors import Vector2D
from polygon import Polygon
from helpers import *
class Ship(Polygon) :
def __init__(self, x, y, screen) :
self.screen = screen
self.pos = Vector2D(x, y)
self.size = 18
self.color = colors.green
self.rotation = 0
self.points = [
(-self.size, self.size),
(0, self.size / 3),
(self.size, self.size),
(0, -self.size)
]
self.translate((self.pos.x, self.pos.y))
self.velocity = Vector2D(0, 0)
self.projectiles = []
def shoot(self) :
p = Projectile(self.pos.x, self.pos.y, self.rotation, self.screen)
self.projectiles.append(p)
def turn(self, dir) :
turn_rate = 4
if dir == 'left' :
deg = -turn_rate
elif dir == 'right' :
deg = turn_rate
else :
deg = 0
self.rotate((self.pos.x, self.pos.y), deg)
if self.rotation > 360 :
self.rotation -= 360
elif self.rotation < 0 :
self.rotation += 360
else :
self.rotation += deg
#print('HDG: ' + str(self.rotation))
def boost(self) :
#print(self.velocity.x, ',', self.velocity.y)
force = Vector2D().create_from_angle(self.rotation, 0.1, True)
#Limits the speed
if (((self.velocity.x <= 4) and (self.velocity.x >= -4))
or
((self.velocity.y <= 4) and (self.velocity.y >= -4))) :
self.velocity.add(force)
#print('Velocity: ' + str(self.velocity.x) + ',' + str(self.velocity.y))
def update(self) :
#Adds friction
f = 0.98
self.velocity.mult((f, f))
# Resets ship possition when it's out of the screen
if self.pos.x > (self.screen.get_width() + self.size) :
#print('COLLIDED RIGHT')
self.pos.x -= self.screen.get_width() + self.size
self.translate((-(self.screen.get_width() + self.size), 0))
elif self.pos.x < -self.size :
#print('COLLIDED LEFT')
self.pos.x += self.screen.get_width() + self.size
self.translate(((self.screen.get_width() + self.size), 0))
if self.pos.y > (self.screen.get_height() + self.size) :
#print('COLLIDED BOTTOM')
self.pos.y -= self.screen.get_height() + self.size
self.translate((0, -(self.screen.get_height() + self.size)))
elif self.pos.y < -self.size :
#print('COLLIDED TOP')
self.pos.y += self.screen.get_height() + self.size
self.translate((0, (self.screen.get_height() + self.size)))
self.pos.x += self.velocity.x #TODO: simplify using V2D add function
self.pos.y += self.velocity.y
self.translate(self.velocity.tuple())
#Update projectiles that have been shot
for p in self.projectiles :
p.update()
def draw(self) :
stroke = 3
pygame.draw.polygon(self.screen, self.color, self.points, stroke)
#Draws projectiles that have been shot
for p in self.projectiles :
p.draw()
class Projectile(object) :
def __init__(self, x, y, ship_angle, screen) :
self.screen = screen
self.speed = 3 #Slow at the moment while we test it
self.direction = ship_angle;
self.pos = Vector2D(x, y)
self.color = colors.green
def update(self) :
self.pos.add(Vector2D().create_from_angle(self.direction, self.speed, return_instance = True))
def draw(self) :
pygame.draw.circle(self.screen, self.color, self.pos.int().tuple(), 2, 0)
类向量(用于根据元素“航向”计算向量并应用速度)
import math
class Vector2D() :
def __init__(self, x = None, y = None) :
self.x = x
self.y = y
def create_from_angle(self, angle, magnitude, return_instance = False) :
angle = math.radians(angle) - math.pi / 2
x = math.cos(angle) * magnitude
y = math.sin(angle) * magnitude
self.x = x
self.y = y
if return_instance :
return self
def tuple(self) :
return (self.x, self.y)
def int(self) :
self.x = int(self.x)
self.y = int(self.y)
return self
def add(self, vector) :
if isinstance(vector, self.__class__) : # vector is an instance of this class
self.x += vector.x
self.y += vector.y
else : # vector is a tuple
self.x += vector[0]
self.y += vector[1]
def mult(self, vector) :
if isinstance(vector, self.__class__) : # vector is an instance of this class
self.x *= vector.x
self.y *= vector.y
else : # vector is a tuple
self.x *= vector[0]
self.y *= vector[1]
基于标记答案的解决方案
Pygame.draw.circle() 只接受 INTEGER 值元组作为位置参数,由于我们正在进行的计算,这是不可能的,因为角度计算的结果总是浮点数。
解决方案是在 Projectile 类中将绘制方法更改为使用 Ellipse 而不是 Circle:
class Projectile(object) :
def __init__(self, x, y, ship_angle, screen) :
self.screen = screen
self.speed = 3 #Slow at the moment while we test it
self.direction = ship_angle;
self.velocity = Vector2D().create_from_angle(self.direction, self.speed, return_instance = True)
self.pos = Vector2D(x, y)
self.color = colors.green
# Properties neccesary to draw the ellipse in the projectile position
self.size = 4
self.box = (0,0,0,0)
def update(self) :
self.pos.add(self.velocity)
self.box = (self.pos.x, self.pos.y, self.size, self.size)
def draw(self) :
stroke = 2
pygame.draw.ellipse(self.screen, self.color, self.box, stroke)
【问题讨论】:
-
顺便说一句:pygame 有自己的pygame.math.Vector2
-
我知道,这个类并不是要取代那个类。将其视为具有特定游戏所需方法的 Helper 类。谢谢!
-
使用
print()来查看变量中的值,例如self.direction或Vector2D().create_from_angle(),这样您就可以找出问题所在。顺便说一句,Projectile.update()你一直在计算Vector2D().create_from_angle(),但你只能在__init__计算一次。 -
试过了,没啥区别。我会把它留给构造函数,因为它看起来更有效率。谢谢你。并且输出实际上是很长的浮点数,并没有说太多:s
-
@JuanBonnett 在无法运行的情况下进行测试很难。能否提供源代码?我的主要问题是关于
Vector2D().create_from_angle()的问题。为什么该函数中有- math.pi / 2?从我在这里看到的情况来看,错误可能在那里或Ship().turn()函数中。那里有一个对rotate()函数的调用,但我在此处发布的源代码中没有找到其他提及它的内容。另外,我认为您应该先将deg添加到旋转中,然后再检查它是否在 0 到 360 之间(模函数可以摆脱 if 语句)。