Attention
This tutorial is work in progress. Take a look at the arrows.py example file in Examples for fully working code for the arrows.
This tutorial will explain one way to make arrows/sticky projectiles that can stick on the target.
The tutorial is heavily inspired by the Box2d tutorial “Box2D C++ tutorials - Sticky projectiles” found here http://www.iforce2d.net/b2dtut/sticky-projectiles (but adjusted for python, pymunk and chipmunk).
For this tutorial you will need to know some pymunk basics. I recommend that you read the other tutorial(s) and try out easier examples first before you continue.
Except for pymunk you will also need pygame to follow this tutorial. However, it should be no problem to use another graphics and input library if you want, for example pyglet.
We will try to accomplish
In the end we should have a cannon like object shooting arrows that flies in a believable way and sticks to objects if they hit hard enough.
Before we start with the arrow we need a scene to contain it and a “cannon” that can aim:
import sys
import pygame
from pygame.locals import *
from pygame.color import *
import pymunk
from pymunk.vec2d import Vec2d
from pymunk.pygame_draw import draw_space, from_pygame
width = height = 600
def main():
### PyGame init
pygame.init()
screen = pygame.display.set_mode((width,height))
clock = pygame.time.Clock()
running = True
font = pygame.font.SysFont("Arial", 16)
### Physics stuff
space = pymunk.Space()
# walls - the left-top-right-bottom walls
static_lines = [pymunk.Segment(space.static_body, (50, 50), (50, 550), 5)
,pymunk.Segment(space.static_body, (50, 550), (550, 550), 5)
,pymunk.Segment(space.static_body, (550, 550), (550, 50), 5)
,pymunk.Segment(space.static_body, (50, 50), (550, 50), 5)
]
space.add_static(static_lines)
### "Cannon" that can fire arrows
cannon_body = pymunk.Body()
player_shape = pymunk.Circle(cannon_body, 25)
cannon_body.position = 100,100
space.add(player_shape)
while running:
for event in pygame.event.get():
if event.type == QUIT or \
event.type == KEYDOWN and (event.key in [K_ESCAPE, K_q]):
running = False
mpos = pygame.mouse.get_pos()
p = from_pygame( Vec2d(mpos), screen )
mouse_position = p
cannon_body.angle = (mouse_position - cannon_body.position).angle
### Clear screen
screen.fill(pygame.color.THECOLORS["black"])
### Draw stuff
draw_space(screen, space)
### Update physics
fps = 60
dt = 1./fps
space.step(dt)
### Info and flip screen
screen.blit(font.render("fps: " + str(clock.get_fps()), 1, THECOLORS["white"]), (0,0))
screen.blit(font.render("Aim with mouse, click to fire", 1, THECOLORS["darkgrey"]), (5,height - 35))
screen.blit(font.render("Press R to reset, ESC or Q to quit", 1, THECOLORS["darkgrey"]), (5,height - 20))
pygame.display.flip()
clock.tick(fps)
if __name__ == '__main__':
sys.exit(main())