def update(self, dt): def f(arbiter): n = -arbiter.contacts[0].normal if n.y > 0.0: self.platformNormal = n self.platformBody = arbiter.shapes[1].body self.platformNormal = Vec2d.zero() self.platformBody = None self.body.each_arbiter(f) # if ground body is found and slope induced grounding normal is lower than feet friction # (find out if grounded) grounded = False ground_velocity = Vec2d.zero() if self.platformBody != None and abs(self.platformNormal.x / self.platformNormal.y) < self.feet.friction: grounded = True self.remaining_jumps = JUMP_TIMES ground_velocity = self.platformBody.velocity # control inputs targetXVel = 0 if self.keyboard[key.LEFT]: targetXVel -= PLAYER_VELOCITY if self.keyboard[key.RIGHT]: targetXVel += PLAYER_VELOCITY if self.keyboard[key.DOWN]: self.slide = True else: self.slide = False if self.jumpTrigger == True: self.jumpTrigger = False if grounded or self.remaining_jumps > 0: # add target jump velocity to body jumpVel = math.sqrt(2.0 * JUMP_HEIGHT * abs(self.scene.space.gravity.y)) self.body.velocity.y = ground_velocity.y + jumpVel self.remaining_jumps -= 1 # if on ground if self.platformBody != None: # if slide key and on slope (normal is (0,1) when on level ground) if self.slide == True and (self.platformNormal.x / self.platformNormal.y) != 0.0: self.feet.friction = 0 else: self.feet.friction = abs(PLAYER_GROUND_ACCEL / self.scene.space.gravity.y) self.head.friciton = HEAD_FRICTION # apply target x velocity to surface velocity of feet.. self.feet.surface_velocity = targetXVel, 0 else: self.feet.friction, self.head.friction = 0, 0 self.body.apply_impulse((targetXVel / 6, 0)) # fall rate limiter self.body.velocity.y = max(self.body.velocity.y, -FALL_VELOCITY) # clamp upwards as well? super(Avatar, self).update(dt)
def main(): pygame.init() screen = pygame.display.set_mode((width,height)) clock = pygame.time.Clock() running = True space = pymunk.Space() space.gravity = 0,-1000 # box walls static = [pymunk.Segment(space.static_body, (10, 50), (300, 50), 5) , pymunk.Segment(space.static_body, (300, 50), (325, 50), 5) , pymunk.Segment(space.static_body, (325, 50), (350, 50), 5) , pymunk.Segment(space.static_body, (350, 50), (375, 50), 5) , pymunk.Segment(space.static_body, (375, 50), (680, 50), 5) , pymunk.Segment(space.static_body, (680, 50), (680, 370), 5) , pymunk.Segment(space.static_body, (680, 370), (10, 370), 5) , pymunk.Segment(space.static_body, (10, 370), (10, 50), 5) ] static[1].color = pygame.color.THECOLORS['red'] static[2].color = pygame.color.THECOLORS['green'] static[3].color = pygame.color.THECOLORS['red'] # player body = pymunk.Body(5, pymunk.inf) body.position = 100,100 head = pymunk.Circle(body, 10, (0,5)) head2 = pymunk.Circle(body, 10, (0,13)) feet = pymunk.Circle(body, 10, (0,-5)) head.layers = head2.layers = 0b1000 feet.collision_type = 1 feet.ignore_draw = head.ignore_draw = head2.ignore_draw = True space.add(body, head, feet,head2) direction = 1 remaining_jumps = 2 landing = {'p':Vec2d.zero(), 'n':0} frame_number = 0 landed_previous = False while running: grounding = { 'normal' : Vec2d.zero(), 'penetration' : Vec2d.zero(), 'impulse' : Vec2d.zero(), 'position' : Vec2d.zero(), 'body' : None } # find out if player is standing on ground pass
def __init__(self): self.vel = Vec2d.zero() self.tile = Vec2d.zero() self.pos = Vec2d.zero() self.size = Vec2d(22, 23) self.half = self.size / 2 self.can_jump = True self.is_jump = False self.standing = True
def __init__(self): Entity.__init__(self, 2) self.head = pymunk.Circle(self, 18) self.head2 = pymunk.Circle(self, 18) self.head2.elasticity = 0.95 self.feet = pymunk.Circle(self, 18) self.head.color = pygame.Color(200, 78, 0) self.head2.color = pygame.Color(200, 78, 0) self.feet.color = pygame.Color(200, 78, 0) self.head.layers = self.head2.layers = 0b1000 self.feet.collision_type = 1 self.reset_rotation() self.moveStyle = MoveStyle.PHYSICS_DRIVEN self.direction = 1 self.jumpsLeft = 1 self.onGround = False self.helpless = False self.isBusy = False self.controller = Controller(self) self.__currentAttack = None self.__groundVelocity = Vec2d.zero()
def __init__(self): self.space = pymunk.Space() self.space.gravity = self.SPACEGRAVITY self.ground_velocity = Vec2d.zero() self.fps = 60 self.dt = 1. / self.fps
def initPhysics(self): self.feet = pymunk.Circle(self.body, 20) self.mid = pymunk.Circle(self.body, 20, (0,40)) self.head = pymunk.Circle(self.body, 20, (0,75)) self.feet.collisionType = platform_collType self.feet.elasticity = 1. self.platformNormal = Vec2d.zero() self.platformBody = None self.slide = False
def __init__(self, pos, collid, frame=0): self.pos = pos self.frame = frame self.body = pymunk.Body(body_type=pymunk.Body.STATIC) self.body.position = pos self.body.collected = False p = [] for i in range(6): p.append(cpoint(math.radians(i * 60 + 180), 5, Vector2.zero())) self.poly = pymunk.Poly(self.body, p) self.poly.sensor = True self.poly.collision_type = collid
def on_update(delta_time): global score # player actions if keys_pressed[arcade.key.SPACE]: lazer = player.fire_lazer() if lazer: player_lazerbolts.append(lazer) # movement if keys_pressed[arcade.key.W]: player.thrust_longitudinal(Ship.Thrust.FORWARD) if keys_pressed[arcade.key.S]: player.thrust_longitudinal(Ship.Thrust.BACKWARD) if keys_pressed[arcade.key.A]: player.thrust_rotational(Ship.Thrust.CCW) if keys_pressed[arcade.key.D]: player.thrust_rotational(Ship.Thrust.CW) player.update() powerups.update() player_lazerbolts.update() meteors.update() # lazer bolt distance checks for lazer in player_lazerbolts: center = Vec2d(WIDTH / 2, HEIGHT / 2) max_dist = center.get_distance(Vec2d.zero()) if lazer.position.get_distance(center) > max_dist: lazer.kill() powerup_collisions = arcade.check_for_collision_with_list(player, powerups) if powerup_collisions: for powerup in powerup_collisions: powerup.kill() score += 1 # powerup boundary checks for pu in powerups: if pu.position.x < 0: pu.position.x = 0 pu.velocity.x *= -1 elif pu.position.x > WIDTH: pu.position.x = WIDTH pu.velocity.x *= -1 if pu.position.y < 0: pu.position.y = 0 pu.velocity.y *= -1 elif pu.position.y > HEIGHT: pu.position.y = HEIGHT pu.velocity.y *= -1
def __init__(self): platform = pyglet.window.get_platform() display = platform.get_default_display() screen = display.get_default_screen() template = pyglet.gl.Config(double_buffer=True) config = screen.get_best_config(template) context = config.create_context(None) self.clock = pyglet.clock.Clock() self.kb_handler = pyglet.window.key.KeyStateHandler() super(Main, self).__init__(resizable=True, width=WIDTH, height=HEIGHT, caption="pymunk test" , context=context) self.push_handlers(self.kb_handler) self.batch = pyglet.graphics.Batch() self.direction = 1 self.remaining_jumps = 2 self.landing = {'p':Vec2d.zero(), 'n':0} self.landed_previous = False # box walls self.space = world.World() self.space.load() def passthrough_handler(space, arbiter): if arbiter.shapes[0].body.velocity.y < 0: return True else: return False self.space.add_collision_handler(1,2, begin=passthrough_handler) # player self.body = pymunk.Body(5, pymunk.inf) self.body.position = 100,100 self.head = pymunk.Circle(self.body, 10, (0,5)) self.head2 = pymunk.Circle(self.body, 10, (0,13)) self.feet = pymunk.Circle(self.body, 10, (0,-5)) self.head.layers = self.head2.layers = 0b1000 self.feet.collision_type = 1 self.feet.ignore_draw = self.head.ignore_draw = self.head2.ignore_draw = True self.space.add(self.body, self.head, self.feet, self.head2) self.target_vx = 0
def update(self, dt, socketio): for p in self.players: force = (BOOST_FORCE if p.is_boosting() else NORMAL_FORCE) * Vec2d.unit() force.angle = p.rotation if p.living: p.body.velocity += force / p.body.mass p.body.angular_velocity = 0 for body in self.space.bodies: speed = body.velocity.get_length() if speed > 0: fricDir = -body.velocity.normalized() fricAmount = body.mass * FRICTION frictionForce = fricDir * fricAmount * dt if speed < MIN_SPEED: body.velocity = Vec2d.zero() else: body.velocity += frictionForce / body.mass if body.velocity.get_length() > MAX_SPEED: if not body.player.living: max_speed = DEAD_MAX_SPEED elif body.player.is_boosting(): max_speed = BOOST_MAX_SPEED elif body.player.braking: max_speed = BRAKE_MAX_SPEED else: max_speed = MAX_SPEED body.velocity = max_speed * body.velocity.normalized() self.space.step(dt) socketio.emit('entities', self.getEncodedPositions(), namespace='/game', room=self.room_name)
def movement(self): grounding = { 'normal' : Vec2d.zero(), 'penetration' : Vec2d.zero(), 'impulse' : Vec2d.zero(), 'position' : Vec2d.zero(), 'body' : None } # find out if player is standing on ground def f(arbiter): n = -arbiter.contacts[0].normal if n.y > grounding['normal'].y: grounding['normal'] = n grounding['penetration'] = -arbiter.contacts[0].distance grounding['body'] = arbiter.shapes[1].body grounding['impulse'] = arbiter.total_impulse grounding['position'] = arbiter.contacts[0].position self.body.each_arbiter(f) self.well_grounded = False if grounding['body'] != None and abs(grounding['normal'].x/grounding['normal'].y) < self.feet.friction: self.well_grounded = True self.remaining_jumps = 2 self.ground_velocity = Vec2d.zero() if self.well_grounded: self.ground_velocity = grounding['body'].velocity self.target_vx = 0 if self.body.velocity.x > .01: self.direction = 1 elif self.body.velocity.x < -.01: self.direction = -1 if self.kb_handler[pyglet.window.key.LEFT]: self.direction = -1 self.target_vx -= PLAYER_VELOCITY if self.kb_handler[pyglet.window.key.RIGHT]: self.direction = 1 self.target_vx += PLAYER_VELOCITY if self.kb_handler[pyglet.window.key.DOWN]: self.direction = -3 self.feet.surface_velocity = self.target_vx, 0 if grounding['body'] != None: self.feet.friction = -PLAYER_GROUND_ACCEL/self.space.gravity.y #IGNORE:E1101 self.head.friciton = HEAD_FRICTION else: self.feet.friction, self.head.friction = 0, 0 # Air control if grounding['body'] == None: self.body.velocity.x = cpflerpconst(self.body.velocity.x, self.target_vx + self.ground_velocity.x, PLAYER_AIR_ACCEL * DT) self.body.velocity.y = max(self.body.velocity.y, -FALL_VELOCITY) # clamp upwards as well? # Move the moving platform destination = self.space.platform_path[self.space.platform_path_index] current = Vec2d(self.space.platform_body.position) distance = current.get_distance(destination) if distance < PLATFORM_SPEED: self.space.platform_path_index += 1 self.space.platform_path_index = self.space.platform_path_index % len(self.space.platform_path) t = 1 else: t = PLATFORM_SPEED / distance new = current.interpolate_to(destination, t) self.space.platform_body.position = new self.space.platform_body.velocity = (new - current) / DT # Did we land? if abs(grounding['impulse'].y) / self.body.mass > 200 and not self.landed_previous: #sound.play() self.landing = {'p':grounding['position'],'n':5} self.landed_previous = True else: self.landed_previous = False if self.landing['n'] > 0: #pygame.draw.circle(screen, pygame.color.THECOLORS['yellow'], to_pygame(landing['p'], screen), 5) self.landing['n'] -= 1
def update(self, dt): """ Run the physics simulation a step """ # find out if player is standing on ground # thanks to https://github.com/viblo/pymunk/blob/master/examples/platformer.py grounding = { "normal": Vec2d.zero(), "penetration": Vec2d.zero(), "impulse": Vec2d.zero(), "position": Vec2d.zero(), "body": None } def f(arbiter): #print(arbiter.elasticity) #print(arbiter.friction) #print(arbiter.shapes[0]) #print(arbiter.shapes[0].friction) #print(arbiter.shapes[1]) #print(arbiter.shapes[1].friction) n = arbiter.contact_point_set.normal #print(n) if n.y > grounding["normal"].y: grounding["normal"] = n grounding["penetration"] = -arbiter.contact_point_set.points[0].distance grounding["body"] = arbiter.shapes[1].body grounding["impulse"] = arbiter.total_impulse grounding["position"] = arbiter.contact_point_set.points[0].point_b self.player.body.each_arbiter(f) well_grounded = False self.player.grounded = False if grounding["body"] != None and abs(grounding["normal"].x/grounding["normal"].y) < 1: well_grounded = True self.player.grounded = True self.player.remaining_jumps = self.player.allowed_jumps # persistent keys keys = pygame.key.get_pressed() v = self.player.body.velocity if keys[K_d]: # NOTE: allow slowing down from going the opposite direction quickly if v.x < 0 and well_grounded: v = (min(v.x + 100, 0), v.y) elif well_grounded: v = (min(v.x + 20, 2000), v.y) else: v = (min(v.x + 15, 2000), v.y) if keys[K_a]: v = self.player.body.velocity if v.x > 0 and well_grounded: v = (max(v.x - 100, 0), v.y) elif well_grounded: v = (max(v.x - 20, -2000), v.y) else: v = (max(v.x - 15, -2000), v.y) self.player.body.velocity = v self.player.jump_refresh -= 1 if self.player.jump_refresh < 0: self.player.jump_refresh = 0 self.player.handle_movement() # mob movement for m in self.mobs: m.adjust_movement(self.player) # scroll viewport self.game.display.scroll_viewport(self.player) self.check_if_near_border() self.generate_mobs() self.cull() self.cull_mobs() self.space.step(dt)
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) sound = pygame.mixer.Sound("sfx.wav") img = pygame.image.load("xmasgirl1.png") ### Physics stuff space = pymunk.Space() space.gravity = 0, -1000 draw_options = pymunk.pygame_util.DrawOptions(screen) # box walls static = [ pymunk.Segment(space.static_body, (10, 50), (300, 50), 3), pymunk.Segment(space.static_body, (300, 50), (325, 50), 3), pymunk.Segment(space.static_body, (325, 50), (350, 50), 3), pymunk.Segment(space.static_body, (350, 50), (375, 50), 3), pymunk.Segment(space.static_body, (375, 50), (680, 50), 3), pymunk.Segment(space.static_body, (680, 50), (680, 370), 3), pymunk.Segment(space.static_body, (680, 370), (10, 370), 3), pymunk.Segment(space.static_body, (10, 370), (10, 50), 3) ] static[1].color = pygame.color.THECOLORS['red'] static[2].color = pygame.color.THECOLORS['green'] static[3].color = pygame.color.THECOLORS['red'] # rounded shape rounded = [ pymunk.Segment(space.static_body, (500, 50), (520, 60), 3), pymunk.Segment(space.static_body, (520, 60), (540, 80), 3), pymunk.Segment(space.static_body, (540, 80), (550, 100), 3), pymunk.Segment(space.static_body, (550, 100), (550, 150), 3) ] # static platforms platforms = [ pymunk.Segment(space.static_body, (170, 50), (270, 150), 3) #, pymunk.Segment(space.static_body, (270, 100), (300, 100), 5) , pymunk.Segment(space.static_body, (400, 150), (450, 150), 3), pymunk.Segment(space.static_body, (400, 200), (450, 200), 3), pymunk.Segment(space.static_body, (220, 200), (300, 200), 3), pymunk.Segment(space.static_body, (50, 250), (200, 250), 3), pymunk.Segment(space.static_body, (10, 370), (50, 250), 3) ] for s in static + platforms + rounded: s.friction = 1. s.group = 1 space.add(static, platforms + rounded) # moving platform platform_path = [(650, 100), (600, 200), (650, 300)] platform_path_index = 0 platform_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC) platform_body.position = 650, 100 s = pymunk.Segment(platform_body, (-25, 0), (25, 0), 5) s.friction = 1. s.group = 1 s.color = pygame.color.THECOLORS["blue"] space.add(s) # pass through platform passthrough = pymunk.Segment(space.static_body, (270, 100), (320, 100), 5) passthrough.color = pygame.color.THECOLORS["yellow"] passthrough.friction = 1. passthrough.collision_type = 2 passthrough.filter = pymunk.ShapeFilter(categories=0b1000) space.add(passthrough) def passthrough_handler(arbiter, space, data): if arbiter.shapes[0].body.velocity.y < 0: return True else: return False space.add_collision_handler(1, 2).begin = passthrough_handler # player body = pymunk.Body(5, pymunk.inf) body.position = 100, 100 head = pymunk.Circle(body, 10, (0, 5)) head2 = pymunk.Circle(body, 10, (0, 13)) feet = pymunk.Circle(body, 10, (0, -5)) # Since we use the debug draw we need to hide these circles. To make it # easy we just set their color to black. feet.color = 0, 0, 0, 0 head.color = 0, 0, 0, 0 head2.color = 0, 0, 0, 0 mask = pymunk.ShapeFilter.ALL_MASKS ^ passthrough.filter.categories sf = pymunk.ShapeFilter(mask=mask) head.filter = sf head2.filter = sf feet.collision_type = 1 feet.ignore_draw = head.ignore_draw = head2.ignore_draw = True space.add(body, head, feet, head2) direction = 1 remaining_jumps = 2 landing = {'p': Vec2d.zero(), 'n': 0} frame_number = 0 landed_previous = False while running: grounding = { 'normal': Vec2d.zero(), 'penetration': Vec2d.zero(), 'impulse': Vec2d.zero(), 'position': Vec2d.zero(), 'body': None } # find out if player is standing on ground def f(arbiter): n = -arbiter.contact_point_set.normal if n.y > grounding['normal'].y: grounding['normal'] = n grounding['penetration'] = -arbiter.contact_point_set.points[ 0].distance grounding['body'] = arbiter.shapes[1].body grounding['impulse'] = arbiter.total_impulse grounding['position'] = arbiter.contact_point_set.points[ 0].point_b body.each_arbiter(f) well_grounded = False if grounding['body'] != None and abs( grounding['normal'].x / grounding['normal'].y) < feet.friction: well_grounded = True remaining_jumps = 2 ground_velocity = Vec2d.zero() if well_grounded: ground_velocity = grounding['body'].velocity for event in pygame.event.get(): if event.type == QUIT or \ event.type == KEYDOWN and (event.key in [K_ESCAPE, K_q]): running = False elif event.type == KEYDOWN and event.key == K_p: pygame.image.save(screen, "platformer.png") elif event.type == KEYDOWN and event.key == K_UP: if well_grounded or remaining_jumps > 0: jump_v = math.sqrt(2.0 * JUMP_HEIGHT * abs(space.gravity.y)) impulse = (0, body.mass * (ground_velocity.y + jump_v)) body.apply_impulse_at_local_point(impulse) remaining_jumps -= 1 elif event.type == KEYUP and event.key == K_UP: body.velocity.y = min(body.velocity.y, JUMP_CUTOFF_VELOCITY) # Target horizontal velocity of player target_vx = 0 if body.velocity.x > .01: direction = 1 elif body.velocity.x < -.01: direction = -1 keys = pygame.key.get_pressed() if (keys[K_LEFT]): direction = -1 target_vx -= PLAYER_VELOCITY if (keys[K_RIGHT]): direction = 1 target_vx += PLAYER_VELOCITY if (keys[K_DOWN]): direction = -3 feet.surface_velocity = -target_vx, 0 if grounding['body'] != None: feet.friction = -PLAYER_GROUND_ACCEL / space.gravity.y head.friction = HEAD_FRICTION else: feet.friction, head.friction = 0, 0 # Air control if grounding['body'] == None: body.velocity = Vec2d( cpflerpconst(body.velocity.x, target_vx + ground_velocity.x, PLAYER_AIR_ACCEL * dt), body.velocity.y) body.velocity.y = max(body.velocity.y, -FALL_VELOCITY) # clamp upwards as well? # Move the moving platform destination = platform_path[platform_path_index] current = Vec2d(platform_body.position) distance = current.get_distance(destination) if distance < PLATFORM_SPEED: platform_path_index += 1 platform_path_index = platform_path_index % len(platform_path) t = 1 else: t = PLATFORM_SPEED / distance new = current.interpolate_to(destination, t) platform_body.position = new platform_body.velocity = (new - current) / dt ### Clear screen screen.fill(pygame.color.THECOLORS["black"]) ### Helper lines for y in [50, 100, 150, 200, 250, 300]: color = pygame.color.THECOLORS['darkgrey'] pygame.draw.line(screen, color, (10, y), (680, y), 1) ### Draw stuff space.debug_draw(draw_options) direction_offset = 48 + (1 * direction + 1) // 2 * 48 if grounding['body'] != None and abs(target_vx) > 1: animation_offset = 32 * (frame_number // 8 % 4) elif grounding['body'] is None: animation_offset = 32 * 1 else: animation_offset = 32 * 0 position = body.position + (-16, 28) p = pymunk.pygame_util.to_pygame(position, screen) screen.blit(img, p, (animation_offset, direction_offset, 32, 48)) # Did we land? if abs(grounding['impulse'].y ) / body.mass > 200 and not landed_previous: sound.play() landing = {'p': grounding['position'], 'n': 5} landed_previous = True else: landed_previous = False if landing['n'] > 0: p = pymunk.pygame_util.to_pygame(landing['p'], screen) pygame.draw.circle(screen, pygame.color.THECOLORS['yellow'], p, 5) landing['n'] -= 1 # Info and flip screen screen.blit( font.render("fps: " + str(clock.get_fps()), 1, THECOLORS["white"]), (0, 0)) screen.blit( font.render( "Move with Left/Right, jump with Up, press again to double jump", 1, THECOLORS["darkgrey"]), (5, height - 35)) screen.blit( font.render("Press ESC or Q to quit", 1, THECOLORS["darkgrey"]), (5, height - 20)) pygame.display.flip() frame_number += 1 ### Update physics space.step(dt) clock.tick(fps)
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) sound = pygame.mixer.Sound("sfx.wav") img = pygame.image.load("xmasgirl1.png") ### Physics stuff space = pymunk.Space() space.gravity = 0,-1000 # box walls static = [pymunk.Segment(space.static_body, (10, 50), (300, 50), 5) , pymunk.Segment(space.static_body, (300, 50), (325, 50), 5) , pymunk.Segment(space.static_body, (325, 50), (350, 50), 5) , pymunk.Segment(space.static_body, (350, 50), (375, 50), 5) , pymunk.Segment(space.static_body, (375, 50), (680, 50), 5) , pymunk.Segment(space.static_body, (680, 50), (680, 370), 5) , pymunk.Segment(space.static_body, (680, 370), (10, 370), 5) , pymunk.Segment(space.static_body, (10, 370), (10, 50), 5) ] static[1].color = pygame.color.THECOLORS['red'] static[2].color = pygame.color.THECOLORS['green'] static[3].color = pygame.color.THECOLORS['red'] # rounded shape rounded = [pymunk.Segment(space.static_body, (500, 50), (520, 60), 5) , pymunk.Segment(space.static_body, (520, 60), (540, 80), 5) , pymunk.Segment(space.static_body, (540, 80), (550, 100), 5) , pymunk.Segment(space.static_body, (550, 100), (550, 150), 5) ] # static platforms platforms = [pymunk.Segment(space.static_body, (170, 50), (270, 150), 5) #, pymunk.Segment(space.static_body, (270, 100), (300, 100), 5) , pymunk.Segment(space.static_body, (400, 150), (450, 150), 5) , pymunk.Segment(space.static_body, (400, 200), (450, 200), 5) , pymunk.Segment(space.static_body, (220, 200), (300, 200), 5) , pymunk.Segment(space.static_body, (50, 250), (200, 250), 5) , pymunk.Segment(space.static_body, (10, 370), (50, 250), 5) ] for s in static + platforms+rounded: s.friction = 1. s.group = 1 space.add(static, platforms+rounded) # moving platform platform_path = [(650,100),(600,200),(650,300)] platform_path_index = 0 platform_body = pymunk.Body(pymunk.inf, pymunk.inf) platform_body.position = 650,100 s = pymunk.Segment(platform_body, (-25, 0), (25, 0), 5) s.friction = 1. s.group = 1 s.color = pygame.color.THECOLORS["blue"] space.add(s) # pass through platform passthrough = pymunk.Segment(space.static_body, (270, 100), (320, 100), 5) passthrough.color = pygame.color.THECOLORS["yellow"] passthrough.friction = 1. passthrough.collision_type = 2 passthrough.layers = passthrough.layers ^ 0b1000 space.add(passthrough) def passthrough_handler(space, arbiter): if arbiter.shapes[0].body.velocity.y < 0: return True else: return False space.add_collision_handler(1,2, begin=passthrough_handler) # player body = pymunk.Body(5, pymunk.inf) body.position = 100,100 head = pymunk.Circle(body, 10, (0,5)) head2 = pymunk.Circle(body, 10, (0,13)) feet = pymunk.Circle(body, 10, (0,-5)) head.layers = head2.layers = 0b1000 feet.collision_type = 1 feet.ignore_draw = head.ignore_draw = head2.ignore_draw = True space.add(body, head, feet,head2) direction = 1 remaining_jumps = 2 landing = {'p':Vec2d.zero(), 'n':0} frame_number = 0 landed_previous = False while running: grounding = { 'normal' : Vec2d.zero(), 'penetration' : Vec2d.zero(), 'impulse' : Vec2d.zero(), 'position' : Vec2d.zero(), 'body' : None } # find out if player is standing on ground def f(arbiter): n = -arbiter.contacts[0].normal if n.y > grounding['normal'].y: grounding['normal'] = n grounding['penetration'] = -arbiter.contacts[0].distance grounding['body'] = arbiter.shapes[1].body grounding['impulse'] = arbiter.total_impulse grounding['position'] = arbiter.contacts[0].position body.each_arbiter(f) well_grounded = False if grounding['body'] != None and abs(grounding['normal'].x/grounding['normal'].y) < feet.friction: well_grounded = True remaining_jumps = 2 ground_velocity = Vec2d.zero() if well_grounded: ground_velocity = grounding['body'].velocity for event in pygame.event.get(): if event.type == QUIT or \ event.type == KEYDOWN and (event.key in [K_ESCAPE, K_q]): running = False elif event.type == KEYDOWN and event.key == K_p: pygame.image.save(screen, "platformer.png") elif event.type == KEYDOWN and event.key == K_d: feet.ignore_draw = not feet.ignore_draw head.ignore_draw = not head.ignore_draw head2.ignore_draw = not head2.ignore_draw elif event.type == KEYDOWN and event.key == K_UP: if well_grounded or remaining_jumps > 0: jump_v = math.sqrt(2.0 * JUMP_HEIGHT * abs(space.gravity.y)) body.velocity.y = ground_velocity.y + jump_v; remaining_jumps -=1 elif event.type == KEYUP and event.key == K_UP: body.velocity.y = min(body.velocity.y, JUMP_CUTOFF_VELOCITY) # Target horizontal velocity of player target_vx = 0 if body.velocity.x > .01: direction = 1 elif body.velocity.x < -.01: direction = -1 keys = pygame.key.get_pressed() if (keys[K_LEFT]): direction = -1 target_vx -= PLAYER_VELOCITY if (keys[K_RIGHT]): direction = 1 target_vx += PLAYER_VELOCITY if (keys[K_DOWN]): direction = -3 feet.surface_velocity = target_vx,0 if grounding['body'] != None: feet.friction = -PLAYER_GROUND_ACCEL/space.gravity.y head.friciton = HEAD_FRICTION else: feet.friction,head.friction = 0,0 # Air control if grounding['body'] == None: body.velocity.x = cpflerpconst(body.velocity.x, target_vx + ground_velocity.x, PLAYER_AIR_ACCEL*dt) body.velocity.y = max(body.velocity.y, -FALL_VELOCITY) # clamp upwards as well? # Move the moving platform destination = platform_path[platform_path_index] current = Vec2d(platform_body.position) distance = current.get_distance(destination) if distance < PLATFORM_SPEED: platform_path_index += 1 platform_path_index = platform_path_index % len(platform_path) t = 1 else: t = PLATFORM_SPEED / distance new = current.interpolate_to(destination, t) platform_body.position = new platform_body.velocity = (new - current) / dt ### Clear screen screen.fill(pygame.color.THECOLORS["black"]) ### Helper lines for y in [50,100,150,200,250,300]: color = pygame.color.THECOLORS['darkgrey'] pygame.draw.line(screen, color, (10,y), (680,y), 1) ### Draw stuff draw(screen, space) if feet.ignore_draw: direction_offset = 48+(1*direction+1)/2 * 48 if grounding['body'] != None and abs(target_vx) > 1: animation_offset = 32 * (frame_number / 8 % 4) elif grounding['body'] is None: animation_offset = 32*1 else: animation_offset = 32*0 position = body.position +(-16,28) screen.blit(img, to_pygame(position, screen), (animation_offset, direction_offset, 32, 48)) # Did we land? if abs(grounding['impulse'].y) / body.mass > 200 and not landed_previous: sound.play() landing = {'p':grounding['position'],'n':5} landed_previous = True else: landed_previous = False if landing['n'] > 0: pygame.draw.circle(screen, pygame.color.THECOLORS['yellow'], to_pygame(landing['p'], screen), 5) landing['n'] -= 1 # Info and flip screen screen.blit(font.render("fps: " + str(clock.get_fps()), 1, THECOLORS["white"]), (0,0)) screen.blit(font.render("Move with Left/Right, jump with Up, press again to double jump", 1, THECOLORS["darkgrey"]), (5,height - 35)) screen.blit(font.render("Press D to toggle sprite draw, ESC or Q to quit", 1, THECOLORS["darkgrey"]), (5,height - 20)) pygame.display.flip() frame_number += 1 ### Update physics space.step(dt) clock.tick(fps)
def update(self, delta): self.controller.update() self.isBusy = self.__currentAttack is not None if len(self.controller.events) > 0: inputEvent = self.controller.pop() if not self.isBusy and not self.helpless: self.onInput(inputEvent) if self.isBusy: try: self.__currentAttack.next() except StopIteration: self.__currentAttack = None self.onGround = False grounding = { 'normal' : Vec2d.zero(), 'penetration' : Vec2d.zero(), 'impulse' : Vec2d.zero(), 'position' : Vec2d.zero(), 'body' : None, } def onHit(arbiter): n = -arbiter.contacts[0].normal if n.y > grounding['normal'].y: grounding['normal'] = n grounding['penetration'] = -arbiter.contacts[0].distance grounding['body'] = arbiter.shapes[1].body grounding['impulse'] = arbiter.total_impulse grounding['position'] = arbiter.contacts[0].position self.each_arbiter(onHit) if grounding['body'] != None and abs(grounding['normal'].x/grounding['normal'].y) < self.feet.friction: self.onGround = True self.helpless = False self.jumpsLeft = 1 if self.moveStyle == MoveStyle.PHYSICS_DRIVEN: self.__groundVelocity = Vec2d.zero() if self.onGround: self.__groundVelocity = grounding['body'].velocity target_vx = 0 if not self.isBusy: xdir = self.controller.xdir if xdir != 0: if self.onGround: self.direction = xdir target_vx += PLAYER_VELOCITY * xdir self.feet.surface_velocity = target_vx,0 if grounding['body'] != None: self.feet.friction = -PLAYER_GROUND_ACCEL/self.scene.space.gravity.y self.head.friciton = HEAD_FRICTION else: self.feet.friction, self.head.friction = 0,0 # Air control if not self.isBusy: if grounding['body'] == None: self.velocity.x = cpflerpconst(self.velocity.x, target_vx + self.__groundVelocity.x, PLAYER_AIR_ACCEL*delta) self.velocity.y = max(self.velocity.y, -FALL_VELOCITY)
def tick(self, deltaTime): if self.body.position.y < -200: self.dead = True self.died = time.time() explosion.play() self.space.remove(self.body) self.space.remove(self.poly) return self.raycast_normal = Vec2d.zero() self.raycast_penetration = Vec2d.zero() self.raycast_impulse = Vec2d.zero() self.raycast_position = Vec2d.zero() self.raycast_body = None self.smoothTheta = math.atan2( math.sin(self.smoothTheta or 0) + math.sin(self.theta or 0) * 5 * deltaTime, math.cos(self.smoothTheta or 0) + math.cos(self.theta or 0) * 5 * deltaTime) self.smoothDist += (self.dist - self.smoothDist) * deltaTime * 5 # Do raycasting to check for collisions beneath player self.body.each_arbiter(lambda ray: self.raycastCallback(ray)) grounded = self.raycast_body != None and abs( self.raycast_normal.x / self.raycast_normal.y ) < -PLAYER_GROUND_ACCEL / self.space.gravity.y self.grounded = grounded if grounded: self.footTheta += self.body.velocity.x * 0.1 * deltaTime + math.pi * 2 elif self.jumping: self.jumping = False self.footTheta %= math.pi * 2 if grounded and self.jumping: jumpVelocity = math.sqrt(2.0 * JUMP_HEIGHT * abs(GRAVITY)) impulse = (0, self.body.mass * jumpVelocity) self.body.apply_impulse_at_local_point(impulse) self.jumping = False # Direction player is facing self.direction = self.body.velocity.x > 0 vx = 0 magnitude = math.cos(self.theta) * self.smoothDist if abs(magnitude) > 0.1: vx = PLAYER_VELOCITY * magnitude self.poly.surface_velocity = -vx, 0 if self.raycast_body != None: self.poly.friction = -PLAYER_GROUND_ACCEL / GRAVITY else: self.poly.friction = 0 # Air movement self.body.velocity.x = lerp(self.body.velocity.x, vx, PLAYER_AIR_ACCEL * deltaTime) # Falling max speed self.body.velocity.y = max(self.body.velocity.y, -FALL_VELOCITY)