Machine gun shooting
My question is related to this question: revolving pistol with limited movement
What calculations do you need to get cannon bullets?
my code is below
def gun_radar(self):
for p in self.gameobjects:
if "R" in p.name or "L" in p.name:
if abs(p.rect.centerx - self.hero.rect.centerx) < p.radar and abs(p.rect.centery - self.hero.rect.centery) < p.radar: # if hero within radar
p.vec_to_target = pygame.math.Vector2(self.hero.rect.center) - p.rect.center
p.direction = p.orig_direction.rotate(p.current_angle)
p.orientation = p.vec_to_target.dot(p.direction)
if p.orientation > 2:
p.current_angle += 1
elif p.orientation < -2:
p.current_angle -= 1
p.current_angle = p.clamp(p.current_angle, p.clamp_min, p.clamp_max)
p.gun_rotate(-p.current_angle)
self.blt_timer -= 1 #count down the timer. when zero calculate vector and add bullet to fired_blts
if self.blt_timer<= 0:
w, h = p.rect.center
angle_in_rad = p.current_angle * (math.pi) / 180
w = w + math.cos(angle_in_rad)
h = h + math.sin(-angle_in_rad)
bullet = Bombullet(bulletimage, w, h)
bullet.xvel = bullet.speed * math.cos(angle_in_rad)
bullet.yvel = bullet.speed * math.sin(angle_in_rad)
bullet.rect.x += bullet.xvel
bullet.rect.y += bullet.yvel
self.fired_blts.add(bullet)
self.blt_timer = 100
when the hero hits the round area of ββthe pistol, it activates and the bullet fires from the center of the pistol.
I move the bullet with
def move(self):
self.rect.x += self.xvel
self.rect.y += self.yvel
print self.rect.x, self.rect.y, self.life
self.life -= 1
the bullet refreshes and fires in the right direction, but fires from the center of the pistol. How to transfer the shooting point to the face?
source to share
Here's an example of a firing cannon. You just need to pass the current angle and rect.center of the cannon to the newly created bullet, and then rotate your image and velocity vector in the method __init__
.
import math
import pygame as pg
from pygame.math import Vector2
pg.init()
screen = pg.display.set_mode((640, 480))
FONT = pg.font.Font(None, 24)
BLACK = pg.Color('black')
BG_COLOR = pg.Color('darkseagreen4')
class Bullet(pg.sprite.Sprite):
def __init__(self, pos, angle):
super(Bullet, self).__init__()
self.image = pg.Surface((20, 11), pg.SRCALPHA)
pg.draw.rect(self.image, pg.Color('grey11'), [0, 0, 13, 11])
pg.draw.polygon(
self.image, pg.Color('grey11'), [(13, 0), (20, 5), (13, 10)])
self.image = pg.transform.rotate(self.image, -angle)
self.rect = self.image.get_rect(center=pos)
# To apply an offset to the start position,
# create another vector and rotate it as well.
offset = Vector2(80, 0).rotate(angle)
# Use the offset to change the starting position.
self.pos = Vector2(pos) + offset
self.velocity = Vector2(5, 0)
self.velocity.rotate_ip(angle)
def update(self):
self.pos += self.velocity
self.rect.center = self.pos
def main():
clock = pg.time.Clock()
# The cannon image and rect.
surf = pg.Surface((40, 22), pg.SRCALPHA)
surf.fill(pg.Color('grey27'))
pg.draw.rect(surf, pg.Color('grey11'), [30, 6, 10, 10])
orig_surf = surf
rect = surf.get_rect(center=(320, 240))
angle = 0 # Angle of the cannon.
# Add bullets to this group.
bullet_group = pg.sprite.Group()
playing = True
while playing:
for event in pg.event.get():
if event.type == pg.QUIT:
playing = False
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1: # Left button fires bullet.
# Fire a bullet from cannon center with current angle.
bullet_group.add(Bullet(rect.center, angle))
bullet_group.update()
# Find angle to target (mouse pos).
x, y = Vector2(pg.mouse.get_pos()) - rect.center
angle = math.degrees(math.atan2(y, x))
# Rotate the cannon image.
surf = pg.transform.rotate(orig_surf, -angle)
rect = surf.get_rect(center=rect.center)
# Draw
screen.fill(BG_COLOR)
bullet_group.draw(screen)
screen.blit(surf, rect)
txt = FONT.render('angle {:.1f}'.format(angle), True, BLACK)
screen.blit(txt, (10, 10))
pg.draw.line(
screen, pg.Color(150, 60, 20), rect.center, pg.mouse.get_pos(), 2)
pg.display.update()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
You can also use math.cos and sin to calculate the offset.
run = math.cos(math.radians(angle)) * 80
rise = math.sin(math.radians(angle)) * 80
offset = run, rise
source to share
I achieved what I needed to do with the following code, which was the same as above, with very little modification explained in the code. @skrx's answer and Nick A.'s comment helped me achieve this.
def gun_radar(self):
for p in self.gameobjects:
if "R" in p.name or "L" in p.name:
if abs(p.rect.centerx - self.hero.rect.centerx) < p.radar and abs(p.rect.centery - self.hero.rect.centery) < p.radar: # if hero within radar
p.vec_to_target = pygame.math.Vector2(self.hero.rect.center) - p.rect.center
p.direction = p.orig_direction.rotate(p.current_angle)
p.orientation = p.vec_to_target.dot(p.direction)
if p.orientation > 2:
p.current_angle += 1
elif p.orientation < -2:
p.current_angle -= 1
p.current_angle = p.clamp(p.current_angle, p.clamp_min, p.clamp_max)
p.gun_rotate(-p.current_angle)
p.timer -= 1 #count down the timer. when zero calculate vector and add bullet to fired_blts
if p.timer<= 0:
w, h = p.rect.center
# adjust for the distance fromm the gun center to the gun muzzle
w = w + math.cos(math.radians(p.current_angle)) * 28
h = h + math.sin(math.radians(p.current_angle)) * 28
bullet = Bombullet(bulletimage, w, h) # create the bullet
# calculate the velocity
bullet.xvel = bullet.speed * math.cos(math.radians(p.current_angle))
bullet.yvel = bullet.speed * math.sin(math.radians(p.current_angle))
self.fired_blts.add(bullet)
p.timer = 100
source to share