2016-12-19 1 views
2

отредактирована, РЕШЕНИИ НА ДНЕ ВОПРОСАPython - Сделайте свой космический корабль, стрелять в направлении его облицовочная Часть 2

я имел некоторые усовершенствования с помощью некоторых хороших людей в этом вопросе: Python - Shoot a bullet in the direction (angle in degrees) my spaceship is facing.

Проблема в том, что, хотя принцип, с помощью которого ускоряется космический корабль в направлении, обращен к нему, кажется, не работает с снарядами. Кажется, странное смещение, когда пули стреляют с корабля под определенным углом.

enter image description here

Я собираюсь поставить код ниже, методы UPDATE() и BOOST() являются те, возглавляющие делает корабль движется, и это работает.

Снаряды используют почти тот же принцип, без ускорения.

Вот видео, так что вы можете визуализировать игру ход и посмотреть, что случилось https://youtu.be/-s7LGuLhePI

Это мой корабль и вектор класса, которые являются те, которые должны были сделать с этой проблемой. (я буду опускать и удалить методы, которые не нужны будут показаны здесь)

корабль класса содержит элемент судна, а также класс снаряд

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) 

КЛАСС VECTOR (Используется для расчета векторов основанные на элементах «заголовок» и применить скорости)

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 в качестве параметра позиции, из-за вычислений, которые мы делали, это было невозможно, потому что результаты расчетов угла всегда были числами с плавающей точкой.

Решение было изменить метод рисования использовать Ellipse вместо круга в снаряде Класс:

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) 
+1

BTW: pygame имеет свой собственный [pygame.math.Vector2] (http://pygame.org/docs/ref/math.html) – furas

+0

Я знаю, этот класс не означает, что он заменит этот класс. Смотрите это как класс помощника с методами, которые мне нужны для моей конкретной игры. Благодаря! –

+0

используйте 'print()' для просмотра значений в переменных типа 'self.direction' или' Vector2D(). Create_from_angle() ', и таким образом вы можете найти, в чем проблема. BTW в 'Projectile.update()' вы вычисляете 'Vector2D(). Create_from_angle()' все время, но вы можете сделать это только один раз в '__init__'. – furas

ответ

2

Оказывается, что ошибка удивительно в вашем Vector2D классе, но не в функции вы бы ожидать! Ваша функция Vector2D().create_from_angle() прекрасна и создает правильный угол, считая, что значение 0, а значение угла увеличивается по часовой стрелке, даже если оно против «стандартного математического соглашения» 0 вправо и против часовой стрелки, увеличивая значение угла.

реальная проблема в вашей Vector2D().int() функции, которая используется как часть вашей draw() функции в Projectile классе.Кастинг float номера для int просто отсекает от десятичных значений, так что вы можете использовать int литой вместе с round функции питона следующим образом:

def int(self) : 
    self.x = int(round(self.x)) 
    self.y = int(round(self.y)) 
    return self 

Однако, даже если вы делаете это исправить, вы заметите, что угол все еще слегка отключен из-за округления по сравнению с кончиком вашего корабля. Это связано с тем, что self.pos.int() под вашей функцией Projectile.draw()перезаписывает текущую позицию с неточной, округленной версией, которая продолжает добавляться в функцию Projectile.update(). Лучшее решение может быть, чтобы избежать вашой Vector2D.int() функции и заменить Projectile.draw() функции с этим:

def draw(self) : 
    pos_x = int(round(self.pos.x)) 
    pos_y = int(round(self.pos.y)) 
    pygame.draw.circle(self.screen, self.color, (pos_x, pos_y), 2, 0) 

выше модификация сделает ваши снаряды стрелять отлично от кончика вашего корабля, но приведет к дрожанию, как положение иногда округляется и иногда округляется по координате x или y. Использование модифицированной функции Vector2D.int() привело к нечеткой, но неточной, стрельбе из снаряда. Какая ошибка лучше всего зависит от вас. Дайте мне знать, если это ясно!

+0

Это имеет большой смысл. Функция draw.circle (..) от Pygame выдает ошибку (в отличие от draw.polygon), когда я помещаю значения, которые не являются int(), возможно, это корень проблемы, я думаю, что я изменю форму. Посмотрим. –

+0

Проверьте мой отредактированный вопрос, проблема решена, просто добавила что-то к вашему решению :)! Большое вам спасибо, сделал этот день! –

+0

@JuanBonnett Приятный звонок с эллипсом! Теперь вам не нужно беспокоиться о уродливом округлении! – CodeSurgeon

 Смежные вопросы

  • Нет связанных вопросов^_^