Exemple #1
0
    def init_batch(self, batch, parent):
        tex = self.textures['piece']
        vertices = []
        tex_coords = []

        da = self.wobble_angle / self.height
        pos = self.pos
        step = Vec2(0, self.PIECE_HEIGHT).rotate(self.base_angle)
        radius = Vec2(self.RADIUS, 0).rotate(self.base_angle)

        for v in self.tree_vertices():
            vertices += [v.x, v.y]

        for i in range(self.height + 1):
            tex_coords += [
                tex.tex_coords[0], (i + 1) * self.TEX_PERIOD,
                tex.tex_coords[3], (i + 1) * self.TEX_PERIOD
            ]

        vertices = vertices[:2] + vertices + vertices[-2:]
        tex_coords = tex_coords[:2] + tex_coords + tex_coords[-2:]

        parent_group = self.get_parent_group(parent)
        group = pyglet.sprite.SpriteGroup(self.textures['piece'],
                                          GL_SRC_ALPHA,
                                          GL_ONE_MINUS_SRC_ALPHA,
                                          parent=parent_group)
        self.vertex_list = batch.add((self.height + 2) * 2, GL_QUAD_STRIP,
                                     group, ('v2f/stream', vertices),
                                     ('t2f/static', tex_coords))

        self.foliage = []
        for i in range(self.height):
            prob = self.height - i
            if random.random() * prob < 1:
                l = random.choice(['leaf1-l', 'leaf2-l'])
                right = pyglet.sprite.Sprite(self.graphics[l],
                                             x=self.pos.x,
                                             y=self.PIECE_HEIGHT * i +
                                             self.pos.y,
                                             batch=batch,
                                             group=parent_group)
            else:
                right = None
            if random.random() * prob < 1:
                l = random.choice(['leaf1-r', 'leaf2-r'])
                left = pyglet.sprite.Sprite(self.graphics[l],
                                            x=self.pos.x,
                                            y=self.PIECE_HEIGHT * i +
                                            self.pos.y,
                                            batch=batch,
                                            group=parent_group)
            else:
                left = None
            self.foliage.append((left, None, right))
        top = pyglet.sprite.Sprite(self.graphics['top'],
                                   batch=batch,
                                   group=parent_group)
        self.foliage.append((None, top, None))
 def throw_projectile(self, target, kls):
     if not self.can_attack():
         return
     start = self.pos + Vec2(0, 80)
     v = target - start
     if not v:
         return
     v += Vec2(0, (0.02 * v.x)**2)  # aim above
     v = v.normalized() * 30
     self.level.spawn(kls(v, self), x=start.x, y=start.y)
Exemple #3
0
	def update(self):
		from bamboo.actors.particles import Smoke
		if random.randint(0, 10) == 0:
			v = Vec2(random.random() * 2 - 1, random.random() * 2) 
			s = Smoke(v)
			s.scale = 0.1
			self.level.spawn(s, x=self.pos.x + random.random() * 20 - 10, y=self.pos.y + 40)
Exemple #4
0
	def move_to(self, pos):
		hw = self.width * self.scale / 2.0
		hh = self.height * self.scale / 2.0
		x = max(hw, min(self.level.width - hw, pos.x))
		y = max(hh, pos.y)
		# NB: floating point camera centers can cause fringes on sprites
		# integer camera centers seem jumpy
		self.center = Vec2(x, y)
Exemple #5
0
 def __init__(self, x=60, height=9, angle=0):
     Climbable.__init__(self)
     self.height = height
     self.pos = Vec2(x, 0)
     self.base_angle = angle
     self.wobble_angle = 0
     self.wind_phase = 0
     self.batch = None
Exemple #6
0
def create_puff_of_smoke(rect, level):
	import random
	c = rect.center()
	for i in range(10):
		x = random.gauss(c.x, rect.w/3)
		y = random.gauss(c.y, rect.h/3)
		v = (Vec2(x, y) - c) * 0.05
		s = Smoke(v)
		level.spawn(s, x=x, y=y)
Exemple #7
0
    def height_for_y(self, y):
        """Estimate the height in this tree for a coordinate of y. This only works for small wobble angles."""
        da = self.wobble_angle / self.height

        rotation = Matrix2.rotation(da)
        pos = self.pos
        step = Vec2(0, self.PIECE_HEIGHT).rotate(self.base_angle)
        radius = Vec2(self.RADIUS, 0).rotate(self.base_angle)

        for i in range(self.height + 1):
            if step.y <= 0:
                raise ValueError("Tree does not reach a height of %f." % y)
            next = pos + step
            if next.y >= y:
                return i + float(y - pos.y) / step.y
            pos += step
            step = rotation * step
        raise ValueError("Tree does not reach a height of %f." % y)
Exemple #8
0
 def load_object(self, use):
     name = use.get('{%s}href' % XLINK_NS).replace('#', '')
     transform = use.get('transform')
     mo = re.match(r'translate\(([\d.-]+),([\d.-]+)\)', transform)
     if not mo:
         raise LevelParseError("Cannot parse transform attribute '%s'" %
                               transform)
     pos = Vec2(float(mo.group(1)), self.height - float(mo.group(2)))
     return ActorSpawn(name, pos)
Exemple #9
0
    def distance_from(self, p):
        """Estimate the distance from x, y to this tree. This only works for small wobbly angles."""
        da = self.wobble_angle / self.height

        rotation = Matrix2.rotation(da)
        pos = self.pos
        step = Vec2(0, self.PIECE_HEIGHT).rotate(self.base_angle)
        radius = Vec2(self.RADIUS, 0).rotate(self.base_angle)

        if pos.y > p.y:
            return (p - pos).mag()

        for i in range(self.height + 1):
            if pos.y > p.y:
                return abs(pos.x - p.x)
            pos += step
            step = rotation * step

        return (p - pos).mag()
 def hit(self, point, force, damage=10):
     for s in range(4):
         off = Vec2(random.random() * 20 - 10, random.random() * 10 - 5)
         self.level.spawn(BloodSpray(v=force + off), x=point.x, y=point.y)
     if not self.is_climbing():
         self.apply_impulse(force / self.MASS)
     self.health -= damage
     if self.health <= 0:
         self.create_corpse()
         self.on_death()
         self.die()
Exemple #11
0
    def update(self):
        f = self.get_net_force()
        accel = f / self.MASS

        g = self.ground_level()
        if self.pos.y < g:
            self.pos -= self.ground_normal().component_of(
                Vec2(0, self.pos.y - g))

        self.v = (self.v + accel) * (1 - self.LINEAR_DAMPING)
        self.pos += self.v
Exemple #12
0
    def compute_wobble(self):
        """Generator for the vertex list. Iterate to give a sequence of Vec2 objects"""
        da = self.wobble_angle / self.height

        pos = self.pos
        rotation = Matrix2.rotation(da)
        step = Vec2(0, self.PIECE_HEIGHT)
        radius = Vec2(self.RADIUS, 0)
        angle = 0

        steprotation = -da * 180 / math.pi

        actor_segments = {}
        for a in self.actors:
            h = int(a.climbing_height)
            actor_segments.setdefault(h, []).append(a)

        vertices = []
        for i in range(self.height + 1):
            vertices.append(pos - radius)
            vertices.append(pos + radius)
            for side, f in enumerate(self.foliage[i]):
                if f is None:
                    continue
                p = pos + (side - 1) * radius
                f.x = p.x
                f.y = p.y
                f.rotation = angle

            for a in actor_segments.get(i, []):
                h = a.climbing_height - i
                apos = pos + h * step
                a.v = apos - a.pos
                a.pos = apos
                a.rotation = angle

            pos += step
            step = rotation * step
            angle += steprotation
            radius = (rotation * radius) * self.THINNING
        return vertices
    def strategy_treesniping(self):
        if not self.character.is_climbing():
            self.pick_strategy()
            return

        alt = self.character.pos.y - self.character.ground_level()
        if alt < 400:
            self.character.climb_up()
        elif self.character.can_attack():
            self.character.throw_projectile(self.target.pos + Vec2(0, 80),
                                            Shuriken)
            self.set_strategy('treefight')
Exemple #14
0
	def __init__(self, v=Vec2(0, 0), dir=None):
		super(Smoke, self).__init__()
		if dir is None:
			self.dir = random.choice(['l', 'r'])
		else:
			self.dir = dir

		self.v = v
		self.scale = 0.3 + random.random() * 0.4
		self.time = 0
		self.lifetime = 30 + int(random.random() * 30)

		self.spin = 30 if self.dir == 'l' else -30
Exemple #15
0
 def collide(self):
     for i, a in enumerate(self.characters):
         for b in self.characters[i + 1:]:
             intersection = a.bounds().intersection(b.bounds())
             if intersection:
                 d = min(intersection.w,
                         intersection.h)  # amount of intersection
                 ab = (b.pos - a.pos)
                 if not ab:
                     ab = Vec2(0, 1)
                 v = ab.normalized()  # direction AB
                 a.pos -= v
                 b.pos += v
 def run_left(self):
     if self.is_climbing():
         self.apply_force(Vec2(-10, 0))
         self.looking = 'l'
         self.climb_rate = 0
     else:
         self.dir = 'l'
         if self.is_on_ground():
             self.apply_force(self.run_speed() *
                              self.ground_normal().perpendicular())
         else:
             self.apply_force(-self.AIR_ACCEL)
         self.crouching = False
 def jump(self):
     if self.is_on_ground():
         self.crouching = False
         self.apply_impulse(self.JUMP_IMPULSE)
         self.on_jump()
     elif self.is_climbing():
         self.climbing.remove_actor(self)
         if self.looking:
             self.dir = self.looking
         if self.looking == 'r':
             self.apply_impulse(self.TREE_JUMP_IMPULSE)
         elif self.looking == 'l':
             ix, iy = self.TREE_JUMP_IMPULSE
             self.apply_impulse(Vec2(-ix, iy))
         self.on_tree_jump()
    def attack(self):
        if not self.can_attack():
            return

        self.attack_timer = self.ATTACK_RATE + 6

        off = 0
        if self.is_climbing():
            if self.dir == 'r':
                off = -30
            else:
                off = +30
            if self.dir != self.looking:
                off *= 1.2
            c = self.pos + Vec2(off, 60)
        elif self.crouching:
            c = self.pos + Vec2(off, 72)
        else:
            c = self.pos + Vec2(off, 100)

        dir = self.looking or self.dir
        if dir == 'r':
            attack_region = Rect.from_corners(c - Vec2(0, 15),
                                              c + Vec2(180, 25))
            force = Vec2(50, 0) + self.v
        else:
            attack_region = Rect.from_corners(c - Vec2(0, 15),
                                              c + Vec2(-180, 25))
            force = Vec2(-50, 0) + self.v

        victims = [
            a for a in self.level.characters_colliding(attack_region)
            if a != self
        ]
        if not victims:
            return
        damage = 10.0 / len(victims)
        force = force / len(victims)
        for a in victims:
            point = attack_region.intersection(a.bounds()).center()
            a.hit(point, force, damage)
 def update(self):
     if self.death_timer < 200:
         super(Corpse, self).update()
     self.death_timer += 1
     if self.death_timer < 15:
         rot = 1 if self.dir == 'l' else -1
         self.rotation = min(
             50, self.rotation + 2 + 0.5 * rot * self.death_timer)
     elif self.death_timer == 15:
         self.rotation = 0
         self.play_animation('dead', directional=True)
     elif self.death_timer == 350:
         self.level.kill(self)
     elif self.death_timer > 200:
         self.pos += Vec2(0, -0.5)
Exemple #20
0
    def tree_vertices(self):
        da = self.wobble_angle / self.height

        pos = self.pos
        rotation = Matrix2.rotation(da)
        step = Vec2(0, self.PIECE_HEIGHT)
        radius = Vec2(self.RADIUS, 0)
        angle = 0

        actor_segments = {}
        for a in self.actors:
            h = int(a.climbing_height)
            actor_segments.setdefault(h, []).append(a)

        vertices = []
        for i in range(self.height + 1):
            vertices.append(pos - radius)
            vertices.append(pos + radius)

            pos += step
            step = rotation * step
            angle = angle + da
            radius = (rotation * radius) * self.THINNING
        return vertices
Exemple #21
0
class LeadingCamera(RegionTrackingCamera):
	"""A region tracking camera, which doesn't let the tracked object go out of frame, but tries to
	scroll the camera away in the direction of its movement"""
	last_track_point = None
	lead = Vec2(0, 0)

	def track(self, p):
		if self.last_track_point is not None:
			v = p - self.last_track_point
			if v.mag() > 100:
				self.lead *= 0.9
			else:
				self.lead = (self.lead + 0.5 * v) * 0.95
			self.center = p + self.lead 
		self.last_track_point = p
		super(LeadingCamera, self).track(p)
Exemple #22
0
	def from_region(self, p):
		"""The shortest vector to p from the focus region"""
		r = self.get_region()
		if p.x < r.l:
			x = p.x - r.l
		elif p.x > r.r:
			x = p.x - r.r
		else:
			x = 0

		if p.y < r.b:
			y = p.y - r.b
		elif p.y > r.t:
			y = p.y - r.t
		else:
			y = 0
		return Vec2(x, y)
Exemple #23
0
    def parse(self):
        self.start_contour()
        self.closed = False  # until proven guilty
        state = None
        pos = Vec2(0, 0)

        x = None  # hold x coordinate while we wait for the y
        for tok in self.tokens():
            # read until we have a coordinate pair
            try:
                v = float(tok)
            except ValueError:
                if tok in 'Zz':
                    self.closed = True
                    self.end_contour()
                # M/m actually means move with pen up, which
                # would end the contour too, except that we need
                # closed contours
                state = tok
                continue

            if x is None:
                if state == 'v':
                    pos += Vec2(0, v)
                    self.add_vertex(pos)
                elif state == 'V':
                    pos = Vec2(pos.x, v)
                    self.add_vertex(pos)
                elif state == 'h':
                    pos += Vec2(v, 0)
                    self.add_vertex(pos)
                elif state == 'H':
                    pos = Vec2(v, pos.y)
                    self.add_vertex(pos)
                else:
                    x = v
                continue

            # we have a coordinate pair, work out what to do with it in the current state
            v = Vec2(x, v)
            x = None

            if state in 'lm':
                pos += v
                self.add_vertex(pos)
            elif state in 'LM':
                pos = v
                self.add_vertex(pos)
            else:
                raise LevelParseError(
                    "Coordinate pair in state %s is unsupported." % state)
        self.end_contour()
        return self.polygon
Exemple #24
0
    def update(self):
        """Run physics, update everything in the world"""
        from bamboo.actors.characters import Character
        self.ground.update()

        for c in self.controllers:
            c.update()

#		self.collide()

        for a in self.actors:
            if isinstance(a, Character):
                if a.pos.x < 0:
                    a.pos = Vec2(0, a.pos.y)
                elif a.pos > self.width:
                    # TODO: fire level completion event
                    pass
            a.update()
Exemple #25
0
class Actor(ResourceTracker):
    initial_animation = None
    current = None
    next = None  # sprite to change to at next frame
    sprite = None

    controller = None
    collision_mask = 0x00

    level = None
    rotation = 0
    scale = 1.0
    opacity = 255

    dir = 'r'

    def _get_pos(self):
        return self._pos

    def _set_pos(self, pos):
        self._pos = pos
        if self.level:
            # TODO: tell level we've moved, so level can optimise
            self._ground_level = self.level.ground.height_at(pos.x)
            self._ground_normal = self.level.ground.normal_at(pos.x)

    _pos = Vec2(0, 0)
    pos = property(_get_pos, _set_pos)

    def add_death_listener(self, callback):
        try:
            self.death_listeners.add(callback)
        except AttributeError:
            self.death_listeners = set([callback])

    def remove_death_listener(self, callback):
        try:
            self.death_listeners.remove(callback)
        except AttributeError, KeyError:
            pass
Exemple #26
0
    def spawn(self, actor, x, y=None, controller=None):
        if not actor._resources_loaded:
            actor.load_resources()

        if y is None:
            y = self.ground.height_at(x)
        actor.pos = Vec2(x, y)
        actor.level = self

        if controller is not None:
            actor.controller = controller
            self.controllers.append(controller)

        from bamboo.actors.samurai import Character
        from bamboo.actors.trees import Climbable
        if isinstance(actor, Character):
            self.characters.append(actor)
        elif isinstance(actor, Climbable):
            if actor.is_climbable():
                self.climbables.append(actor)
        self.actors.append(actor)
        actor.on_spawn()
Exemple #27
0
class Smoke(Actor):
	layer = 6	

	GRAVITY = Vec2(0, 0.5)

	def __init__(self, v=Vec2(0, 0), dir=None):
		super(Smoke, self).__init__()
		if dir is None:
			self.dir = random.choice(['l', 'r'])
		else:
			self.dir = dir

		self.v = v
		self.scale = 0.3 + random.random() * 0.4
		self.time = 0
		self.lifetime = 30 + int(random.random() * 30)

		self.spin = 30 if self.dir == 'l' else -30
	
	def on_spawn(self):
		self.play_animation('smoke', directional=True)

	@classmethod
	def on_class_load(cls):
		cls.load_directional_sprite('smoke', 'smoke.png', anchor_x='center', anchor_y='center')

	def update(self):
		self.time += 1
		if self.time >= self.lifetime:
			self.die()

		self.v = (self.v + Smoke.GRAVITY) * 0.9
		self.pos += self.v
		self.rotation += self.spin
		self.scale += 0.02
		self.opacity = 255 - (self.time / float(self.lifetime)) * 255
Exemple #28
0
 def __init__(self, pos=Vec2(0, 0)):
     self.pos = Vec2(0, 0)
     self.v = Vec2(0, 0)
     self.f = self.get_weight()
     self.runforce = 0
Exemple #29
0
    def delete(self):
        """Remove from batch"""
        if self.sprite:
            self.sprite.delete()
            self.sprite = None

    def update(self):
        """Subclasses can implement this method if necessary to implement game logic"""

    def on_spawn(self):
        """Subclasses can implement this method to initialise the actor"""
        if self.initial_animation:
            self.play_animation(self.initial_animation)


GRAVITY = Vec2(0, -2.3)


class PhysicalObject(Actor):
    """A PhysicalObject is an actor bound by simple platform physics"""
    MASS = 15
    FRICTION = 0.6
    LINEAR_DAMPING = 0.0

    def __init__(self, pos=Vec2(0, 0)):
        self.pos = Vec2(0, 0)
        self.v = Vec2(0, 0)
        self.f = self.get_weight()
        self.runforce = 0

    def apply_force(self, vec):
Exemple #30
0
 def spawn_p2(self):
     self.pc2.dir = 'l'
     self.pc2.v = Vec2(0, 0)
     self.level.spawn(self.pc2,
                      x=self.level.width - 60,
                      controller=self.player2)