def throw_bomb(self): angle = self.knight.angle direction = Vector2() direction.from_polar((1, math.degrees(angle))) pos = Vector2(*self.knight.pos) + self.radius * direction vel = self.v + direction * Bomb.SPEED self.level.spawn_bomb(pos, vel)
def update(self, dt): self.v *= self.DRAG ** dt # drag if self.accel: # New acceleration this frame self.v += self.ACCELERATION * self.accel * dt da, accel_angle = self.accel.as_polar() accel_angle = math.radians(accel_angle) delta = angle_diff(accel_angle, self.knight.angle) if delta < 0: self.knight.angle += max(dt * da * -self.TURN, delta) else: self.knight.angle += min(dt * da * self.TURN, delta) # Keep within the play area sz = Vector2(self.knight.radius, self.knight.radius) scene = self.knight.scene self.knight.pos = np.clip( self.knight.pos + self.v * dt, sz, Vector2(scene.width, scene.height) - sz ) self.knight.v = self.v self.accel *= 0.0
def update(self, dt): """Update the knight this frame.""" if self.last_pos: displacement = Vector2(*self.pos - self.last_pos) distance = displacement.length() num = np.random.poisson(distance * self.SMOKE_RATE) if num: stern = self.pos - displacement.normalize() * 10 if self.game.use_particles: self.scene.smoke.emit( num=num, pos=stern, pos_spread=2, vel=displacement * 0.3, spin_spread=1, size=7, angle=self.knight.angle, angle_spread=3, ) self.step += distance # Scale the knight to simulate gait bob = 1.1 + 0.1 * np.sin(self.step / 500) self.knight.scale = bob self.last_pos = Vector2(*self.pos)
def __init__(self, level, color=(1, 1, 1, 1)): self.level = level self.game = level.game scene = self.scene = level.scene shield_sprite = scene.layers[Layers.ENTITIES].add_sprite('shield') sword_sprite = scene.layers[Layers.UPPER_EFFECTS].add_sprite('sword-gripped') sword_sprite.color = (1.4, 1.4, 1.4, 1) self.knight = scene.layers[Layers.ENTITIES].add_sprite( 'knight', color=color ) self.shield = Hand( sprite=shield_sprite, knight=self, radius=12, angle=-1.5, ) self.sword = Hand( sprite=sword_sprite, knight=self, radius=25, angle=0, ) self.sword.attack = False self.v = Vector2() self.pos = Vector2(scene.width, scene.height) * 0.5 self.last_pos = None # The distance the knight has travelled; this is used in # calculating his gait self.step = 0
def update(keyboard): x, y = alien.fpos vx, vy = alien.v y += vy alien.fpos.y = y eps = 1e-4 br, bl, tl, tr = bounds() if alien.stood: belowl = bl + Vector2(0, 1) belowr = br + Vector2(0, 1) if not (collide_point(belowl, belowr)): alien.stood = False alien.image = 'pc_standing' vy += GRAVITY else: if vy + eps > y - tile_floor(y) > 0: if collide_point(bl, br): alien.image = 'pc_standing' alien.stood = True vy = 0 y = tile_floor(y) else: alien.image = 'pc_falling' elif vy - eps < tl.y - tile_ceil(tl.y) < 0: if collide_point(tl, tr): print("oof") vy = 0 y = tile_ceil(y) if not alien.stood: vy += GRAVITY if not alien.crouch: if keyboard.left: vx -= ACCEL elif keyboard.right: vx += ACCEL vx *= DRAG x += vx alien.fpos.x = x br, bl, tl, tr = bounds() if vx + eps > tr.x - tile_floor(tr.x) > 0: alien.scale_x = 1 if collide_point(tr, br): vx = 0 x = tile_floor(tr.x) - 11 elif vx - eps < tl.x - tile_ceil(tl.x) < 0: alien.scale_x = -1 if collide_point(tl, bl): vx = 0 x = tile_ceil(tl.x) + 10 alien.fpos.x = vx alien.v = Vector2(vx, vy) alien.pos = alien.fpos = Vector2(x, y)
def accelerate(self, v): if self.can_move: self.accel += Vector2(v) if self.accel.length_squared() > 1: self.accel.normalize_ip() else: v = Vector2(v) if self.v and v: side = self.v.normalize().rotate(90) self.accel += 0.3 * v * abs(side.dot(v.normalize()))
async def thrust(duration): """Fire a little burst of thrust.""" prev_pos = Vector2(*ship.pos) async for _ in clock.coro.frames(seconds=duration): v = Vector2(*ship.pos) - prev_pos num = v.length() // 50 if num: trail.emit( num, pos=ship.pos, vel=-v.normalize() * 100, vel_spread=10, size=3, color='#80ffff', )
async def enemy(): color = colorsys.hsv_to_rgb(random.random(), 1, 1) pos = Vector2(random.uniform(50, scene.width - 50), random.uniform(50, scene.height - 50)) e = scene.layers[0].add_circle( radius=10, color=color, pos=pos, ) e.scale = 0.1 await animate( e, duration=0.3, scale=1, ) async for dt in clock.coro.frames_dt(): to_target = target - pos if to_target.magnitude() < e.radius: break pos += to_target.normalize() * 100 * dt e.pos = pos await animate(e, duration=0.5, scale=4, tween='accelerate', color=(*color, 0)) e.delete()
def on_key_down(key, mod): if key == key.F12: if mod & SHIFT: scene.toggle_recording() else: scene.screenshot() if key == key.F11: import pdb pdb.set_trace() elif key == key.K_1: lbl.align = 'left' elif key == key.K_2: lbl.align = 'center' elif key == key.K_3: lbl.align = 'right' elif key == key.SPACE: bullet = scene.layers[0].add_sprite('tiny_bullet', pos=ship.pos) bullet.color = (1, 0, 0, 1) bullet.vel = Vector2(600, 0).rotate_rad(ship.angle) bullet.power = 1.0 bullets.append(bullet) w2d.sounds.laser.play()
def update(dt): fps.text = f'FPS: {scene.fps:0.1f}' dt = min(dt, 0.5) dead = set() for o in objects: if o is star: continue sep = Vector2(*star.pos - o.pos) dist = sep.magnitude() if dist > 1500: # If it's flying off into space, kill it dead.add(o) o.silent = True o_u = o.v o.v += GRAVITY / (dist * dist) * sep.normalize() * dt o.pos += (o_u + o.v) * 0.5 * dt for a, b in collision_pairs(objects): dead |= {a, b} dead.discard(star) objects[:] = [o for o in objects if o not in dead] for o in dead: particles.emit(o.radius**2, size=1, pos=o.pos, pos_spread=o.radius * 0.7, vel=o.v * 0.2, vel_spread=50, color=GREEN) for obj, up, left, right, _ in controls: if obj in dead: dead.discard(obj) w2d.tone.play(20, 1.0, waveform='square') w2d.clock.coro.run(respawn(obj)) continue elif obj.dead: continue if up(): obj.v += forward(obj, ACCEL * dt) particles.emit(np.random.poisson(30 * dt), size=2, pos=obj.pos + forward(obj, -7), vel=obj.v + forward(obj, -100), vel_spread=4, color=GREEN) if left(): obj.angle -= ROTATION_SPEED * dt elif right(): obj.angle += ROTATION_SPEED * dt for o in dead: if not getattr(o, 'silent', False): w2d.tone.play(30, 0.3, waveform='square') o.delete()
def resolve_collisions(self): """Push actors apart. This is O(n^2) and can be improved. Note that this will not completely separate everything every frame due to a later collision causing a new intrusion on a previously resolved one. However over multiple frames this gives the desired effect. """ player = self.player for mob in self.enemies[:]: collision = player.compute_collision_with_bad_guy(mob) if collision == CollisionType.ZONE: player.on_collision_zone(mob) mob.on_collide_zone() elif collision == CollisionType.PLAYER: player.on_collision_body(mob) mob.on_collide_player() else: penetration_vector = self.detect_wall_collisions(mob) if penetration_vector: if mob.die_on_any_collision: mob.delete() return mob.pos -= penetration_vector mob.shape.pos = mob.pos for i, mob1 in enumerate(self.enemies): p1 = mob1.pos r1 = mob1.radius for mob2 in self.enemies[i + 1:]: r2 = mob2.radius r = r1 + r2 p2 = mob2.pos sep = Vector2(*p2 - p1) if sep.magnitude_squared() < r * r: mag = sep.magnitude() overlap = r - mag if mag: sep.normalize_ip() else: sep = Vector2(0, 1) frac = (r1 * r1) / (r1 * r1 + r2 * r2) mob1.pos = p1 - sep * overlap * (1.0 - frac) mob2.pos = p2 + sep * overlap * frac
def apply_damage(self): pos = Vector2(*self.pos) for mob in self.level.enemies: sep = mob.pos - pos mag = sep.magnitude dmg = 100 / (1 + mag) if mag < 150: mob.die(sep * 4) else: # TODO: apply impulse, rather than affecting position mob.move_delta(sep.normalized() * dmg)
def booster_on(self): """ When booster is firing we accelerate in the opposite direction, 180 degrees, from the way the ship is facing """ self.booster = True self.sprite.image = 'lander-thrust' angle_r = math.radians(self.angle + 180) accel = Vector2(math.sin(angle_r), math.cos(angle_r)) self.acceleration[:] = Ship.booster_power * accel self.particles.emit( 5, pos=self.position, pos_spread=2, vel=accel * -200 + Vector2(*self.velocity) * 60, vel_spread=50, size=2, color='#fff0c0', ) self.fuel -= 2
def make_player(pos, angle=0): ship = scene.layers[0].add_polygon( SHIP_PTS, fill=False, color=GREEN, stroke_width=LINE_W, ) ship.pos = ship.initial_pos = pos ship.angle = ship.initial_angle = angle ship.v = forward(ship, 160) ship.initial_v = Vector2(ship.v) ship.radius = 7 ship.dead = False return ship
def _charge(self, dt): self.charge_t += dt angle = self.knight.angle c, s = np.cos(angle), np.sin(angle) self.knight.accel = Vector2(c, s) * 2 x, y = self.knight.pos radius = self.knight.radius scene = self.knight.scene if self.charge_t > 1.5 or \ x < radius or x > scene.width - radius or \ y < radius or y > scene.height - radius: clock.unschedule(self._charge) self.sword.attack = False self.can_act.unlock() self.can_move.unlock()
def test_attacks(self): for pc in self.pcs: if not pc.sword.attack: continue pos = pc.pos sword = pc.sword.angle dir = Vector2(np.cos(sword), np.sin(sword)) start = pos + dir * 12 new_mobs = [] for mob in self.mobs: if line_segment_intersects_circle(start, dir * 40, mob.pos, 20) is not None: sep = mob.pos - pc.pos mob.die(pc.v + sep.normalize() * 30) else: new_mobs.append(mob) self.mobs[:] = new_mobs
async def respawn(obj): obj.score_label.value += 1 obj.score_label.text = str(obj.score_label.value) obj.dead = True obj.color = INVISIBLE await w2d.clock.coro.sleep(3) ring = scene.layers[0].add_circle( radius=40, pos=obj.initial_pos, color=TRANSPARENT_GREEN, fill=False, stroke_width=LINE_W, ) w2d.tone.play(256, 1.0) await w2d.animate( ring, 'accelerate', duration=0.5, scale=0.1, color=GREEN, stroke_width=10, ) ring.delete() objects.append(obj) obj.dead = False obj.angle = obj.initial_angle obj.pos = obj.initial_pos obj.v = Vector2(obj.initial_v) for i in range(11): obj.color = INVISIBLE if i % 2 else GREEN await w2d.clock.coro.sleep(0.1) if obj.dead: return
def on_key_down(key, mod): if key == key.F11: import pdb pdb.set_trace() elif key == key.K_1: lbl.align = 'left' elif key == key.K_2: lbl.align = 'center' elif key == key.K_3: lbl.align = 'right' elif key == key.SPACE: bullet = scene.layers[0].add_sprite('tiny_bullet', pos=ship.pos) bullet.color = (1, 0, 0, 1) bullet.vel = Vector2(600, 0).rotate_rad(ship.angle) bullet.power = 1.0 bullets.append(bullet) w2d.sounds.laser.play() w2d.animate(ship[0], 'accel_decel', 0.5, pos=next(orbiter_positions)) elif key == key.Z: pos = ship.local_to_world((-10, 0)) w2d.clock.coro.run(bomb(pos))
grid = set() grid.update((x, TILES_H) for x in range(TILES_W)) grid.update((-1, y) for y in range(-TILES_H, TILES_H)) grid.update((TILES_W, y) for y in range(-TILES_H, TILES_H)) scene = w2d.Scene(width=TILE * TILES_W, height=TILE * TILES_H, scaler=True) scene.background = '#5e81a2' scene.layers[1].set_effect('dropshadow', radius=2, offset=(0, 1)) alien = scene.layers[1].add_sprite( 'pc_standing', anchor_x=10, anchor_y=21, pos=(210, TILE * 9) ) alien.fpos = Vector2(*alien.pos) alien.v = Vector2(0, 0) alien.stood = True alien.crouch = False def create_platform(x1, x2, y): length = x2 - x1 if length == 1: grid.add((x1, y)) scene.layers[1].add_sprite( 'platform_single', pos=(x1 * TILE, y * TILE), anchor_x=0, anchor_y=0, )
def __post_init__(self): self.v = Vector2() self.accel = Vector2() # direction of the acceleration
def forward(ship, length=1) -> Vector2: """Get a vector in the direction of the ship.""" v = Vector2() v.from_polar((length, math.degrees(ship.angle))) return v
def collides(a, b) -> bool: """Test if two objects have collided.""" sep = a.pos - b.pos radii = a.radius + b.radius return Vector2(*sep).length_squared() < radii * radii
ship.pos = ship.initial_pos = pos ship.angle = ship.initial_angle = angle ship.v = forward(ship, 160) ship.initial_v = Vector2(ship.v) ship.radius = 7 ship.dead = False return ship scene = w2d.Scene(1200, 800) scene.chain = [ w2d.LayerRange().wrap_effect('trails', alpha=0.4, fade=0.08).wrap_effect('bloom', radius=8) ] center = Vector2(scene.width, scene.height) * 0.5 score1 = scene.layers[0].add_label('0', pos=(10, 40), fontsize=30, color=GREEN) score2 = scene.layers[0].add_label('0', pos=(scene.width - 10, 40), align='right', fontsize=30, color=GREEN) score1.value = score2.value = 0 fps = scene.layers[0].add_label( 'FPS: 60', pos=(10, scene.height - 10), fontsize=20, color=GREEN, )
poly.stroke_width = 0 scene.layers[1].set_effect('bloom', threshold=0.9, radius=50) particles = scene.layers[1].add_particle_group( texture='smoke', grow=3, max_age=2, gravity=(0, 100), drag=0.5, ) particles.add_color_stop(0, (5, 0, 0, 1)) particles.add_color_stop(0.3, (1.5, 1.5, 0, 1)) particles.add_color_stop(1.0, 'gray') particles.add_color_stop(2, (0.3, 0.3, 0.3, 0)) ship.vel = Vector2() bullets = [] SHIFT = pygame.KMOD_LSHIFT | pygame.KMOD_RSHIFT @event def on_key_down(key, mod): if key == key.F12: if mod & SHIFT: scene.toggle_recording() else: scene.screenshot() elif key == key.K_1:
"""Example of the light bloom effect.""" from wasabi2d import run, Scene, event, Vector2 from wasabi2d.actor import Actor scene = Scene() scene.background = 'red' logo = Actor(scene.layers[0].add_sprite( 'wasabi2d', pos=(scene.width / 2, scene.height / 2), )) logo.v = Vector2(1, -1) scene.layers[0].set_effect('trails', fade=0.7) @event def update(dt): logo.pos += logo.v if logo.top < 0 or logo.bottom >= scene.height: logo.v.y *= -1 if logo.left < 0 or logo.right >= scene.width: logo.v.x *= -1 run()
"""Example of the light bloom effect.""" from wasabi2d import run, Scene, event, keys, Vector2 from wasabi2d.actor import Actor scene = Scene() logo = Actor(scene.layers[0].add_sprite( 'wasabi2d', pos=(scene.width / 2, scene.height / 2), )) logo.v = Vector2(100, -100) scene.layers[0].set_effect('trails', fade=0.7) @event def update(dt): logo.pos += logo.v * dt if logo.top < 0 or logo.bottom >= scene.height: logo.v.y *= -1 if logo.left < 0 or logo.right >= scene.width: logo.v.x *= -1 @event def on_key_down(key, mod): if key == keys.F12: scene.screenshot() run()
def on_mouse_move(pos): global target target = Vector2(*pos)
def spawn_mobs(self, *, num: int): xs = np.random.uniform(30, self.scene.width - 30, size=num) ys = np.random.uniform(30, self.scene.height - 30, size=num) angles = np.random.uniform(-math.pi, math.pi, size=num) for x, y, angle in zip(xs, ys, angles): self.mobs.append(Mage(self, Vector2(x, y), angle))
import random import wasabi2d as w2d import colorsys from wasabi2d import clock, Vector2, animate, keyboard scene = w2d.Scene(title="Run!") scene.background = 'white' target = Vector2(scene.width / 2, scene.height / 2) scene.layers[0].set_effect('dropshadow', opacity=1, radius=1) async def spawn_baddies(): while True: clock.coro.run(enemy()) await clock.coro.sleep(3) async def enemy(): color = colorsys.hsv_to_rgb(random.random(), 1, 1) pos = Vector2(random.uniform(50, scene.width - 50), random.uniform(50, scene.height - 50)) e = scene.layers[0].add_circle( radius=10, color=color, pos=pos, ) e.scale = 0.1 await animate( e, duration=0.3, scale=1,
from wasabi2d import Scene, event, run, keys, Vector2 from ascend.triangle_intersect import polygon_collision from pygame import joystick scene = Scene() scene.background = (0.2, ) * 3 scene.layers[0].set_effect('dropshadow', radius=1) triangle = [Vector2(100, 200), Vector2(300, 300), Vector2(200, 400)] scene.layers[0].add_polygon(triangle, fill=False, color='yellow') circ = scene.layers[0].add_circle(radius=20, fill=False, color='red') @event def on_mouse_move(pos): circ.pos = pos pen = polygon_collision(triangle, pos, circ.radius) if pen: circ.pos -= pen circ.color = 'red' if pen else 'green' run()