{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "f7b8452d-61fe-4356-8084-cac603096fef", "metadata": {}, "outputs": [], "source": [ "import sys\n", "if \"pyodide\" in sys.modules:\n", " import piplite\n", " await piplite.install('pyb2d-jupyterlite-backend>=0.4.2')" ] }, { "cell_type": "code", "execution_count": null, "id": "0bfa61e4-9817-4bea-aa66-6a660a423ae6", "metadata": {}, "outputs": [], "source": [ "from b2d.testbed import TestbedBase\n", "import random\n", "import numpy\n", "import b2d\n", "import math\n", "\n", "class Rocket(TestbedBase):\n", "\n", " name = \"Rocket\"\n", "\n", " def __init__(self, settings=None):\n", " super(Rocket, self).__init__(gravity=(0, 0), settings=settings)\n", "\n", " # gravitational constant\n", " self.gravitational_constant = 6.0\n", "\n", " self.planets = {}\n", "\n", " # home planet\n", " home_planet = self.world.create_kinematic_body(\n", " position=(10, 0),\n", " fixtures=b2d.fixture_def(shape=b2d.circle_shape(radius=20)),\n", " user_data=\"home_planet\",\n", " )\n", "\n", " # target planet\n", " target_planet = self.world.create_kinematic_body(\n", " position=(100, 100),\n", " fixtures=b2d.fixture_def(shape=b2d.circle_shape(radius=10)),\n", " user_data=\"target_planet\",\n", " )\n", "\n", " # black hole\n", " black_hole = self.world.create_kinematic_body(\n", " position=(0, 400),\n", " fixtures=b2d.fixture_def(shape=b2d.circle_shape(radius=1)),\n", " user_data=\"black_hole\",\n", " )\n", "\n", " self.planets = {\n", " home_planet: dict(radius=20, density=1, color=(0, 0.2, 1)),\n", " target_planet: dict(radius=10, density=1, color=(0.7, 0.7, 0.7)),\n", " black_hole: dict(radius=1, density=10000, color=(0.1, 0.1, 0.1)),\n", " }\n", "\n", " # a tiny rocket\n", " self.rocket = self.world.create_dynamic_body(\n", " position=(10, 10),\n", " fixtures=[\n", " b2d.fixture_def(shape=b2d.polygon_shape(box=[1, 1]), density=1),\n", " b2d.fixture_def(\n", " shape=b2d.polygon_shape(vertices=[(-1, 1), (0, 4), (1, 1)]),\n", " density=1,\n", " ),\n", " ],\n", " angular_damping=0.5,\n", " linear_damping=0.2,\n", " user_data=\"rocket\",\n", " )\n", " # check if the rocket is gone\n", " self.touched_black_hole = False\n", "\n", " # particle system\n", " pdef = b2d.particle_system_def(\n", " viscous_strength=0.9,\n", " spring_strength=0.0,\n", " damping_strength=100.5,\n", " pressure_strength=1.0,\n", " color_mixing_strength=0.05,\n", " density=0.1,\n", " )\n", "\n", " psystem = self.world.create_particle_system(pdef)\n", " psystem.radius = 0.1\n", " psystem.damping = 0.5\n", "\n", " self.emitters = []\n", " self.key_map = {\"w\": 0, \"a\": 1, \"d\": 2}\n", "\n", " angle_width = (math.pi * 2) / 16\n", " emitter_def = b2d.RandomizedRadialEmitterDef()\n", " emitter_def.emite_rate = 2000\n", " emitter_def.lifetime = 1.0\n", " emitter_def.enabled = False\n", " emitter_def.inner_radius = 1\n", " emitter_def.outer_radius = 1\n", " emitter_def.velocity_magnitude = 10.0\n", " emitter_def.start_angle = math.pi / 2 - angle_width / 2.0\n", " emitter_def.stop_angle = math.pi / 2 + angle_width / 2.0\n", " emitter_def.body = self.rocket\n", "\n", " delta = 0.2\n", " self.emitter_local_anchors = [\n", " (0, -delta), # main\n", " (-delta, -0.5), # left,\n", " (delta, -0.5), # right\n", " ]\n", " self.emitter_local_rot = [math.pi, math.pi / 2, -math.pi / 2] # main\n", "\n", " # main trust\n", " emitter_def.emite_rate = 2000\n", " world_anchor = self.rocket.get_world_point(self.emitter_local_anchors[0])\n", " emitter_def.transform = b2d.Transform(\n", " world_anchor, b2d.Rot(self.emitter_local_rot[0])\n", " )\n", " emitter = b2d.RandomizedRadialEmitter(psystem, emitter_def)\n", " self.emitters.append(emitter)\n", "\n", " # left\n", " emitter_def.emite_rate = 200\n", " world_anchor = self.rocket.get_world_point(self.emitter_local_anchors[1])\n", " emitter_def.transform = b2d.Transform(\n", " world_anchor, b2d.Rot(self.emitter_local_rot[1])\n", " )\n", " emitter = b2d.RandomizedRadialEmitter(psystem, emitter_def)\n", " self.emitters.append(emitter)\n", "\n", " # right\n", " emitter_def.emite_rate = 200\n", " world_anchor = self.rocket.get_world_point(self.emitter_local_anchors[1])\n", " emitter_def.transform = b2d.Transform(\n", " world_anchor, b2d.Rot(self.emitter_local_rot[1])\n", " )\n", " emitter = b2d.RandomizedRadialEmitter(psystem, emitter_def)\n", " self.emitters.append(emitter)\n", "\n", " def pre_step(self, dt):\n", "\n", " # check if the rocket has died\n", " if self.touched_black_hole:\n", " if self.rocket is not None:\n", " self.world.destroy_body(self.rocket)\n", " self.rocket = None\n", " else:\n", " rocket_center = self.rocket.world_center\n", " rocket_mass = self.rocket.mass\n", " # compute gravitational forces\n", " net_force = numpy.zeros([2])\n", " for planet, planet_def in self.planets.items():\n", " radius = planet_def[\"radius\"]\n", " planet_center = planet.position\n", " planet_mass = planet_def[\"density\"] * radius ** 2 * math.pi\n", " delta = rocket_center - planet_center\n", " distance = delta.normalize()\n", " f = (\n", " -self.gravitational_constant\n", " * rocket_mass\n", " * planet_mass\n", " / (distance * distance)\n", " )\n", " net_force += delta * f\n", " f = float(net_force[0]), float(net_force[1])\n", " self.rocket.apply_force_to_center(f)\n", "\n", " # run the rockets engines\n", " for emitter, local_anchor, local_rotation in zip(\n", " self.emitters, self.emitter_local_anchors, self.emitter_local_rot\n", " ):\n", " world_anchor = self.rocket.get_world_point(local_anchor)\n", " emitter.position = world_anchor\n", " emitter.angle = self.rocket.angle + local_rotation\n", " emitter.step(dt)\n", "\n", " def begin_contact(self, contact):\n", " body_a = contact.body_a\n", " body_b = contact.body_b\n", " if body_b.user_data == \"rocket\":\n", " body_a, body_b = body_b, body_a\n", "\n", " user_data_a = body_a.user_data\n", " user_data_b = body_b.user_data\n", " if body_a.user_data == \"rocket\":\n", " if user_data_b == \"black_hole\":\n", " self.touched_black_hole = True\n", "\n", " def on_keyboard_down(self, key):\n", " if key in self.key_map:\n", " self.emitters[self.key_map[key]].enabled = True\n", " return True\n", " return False\n", "\n", " def on_keyboard_up(self, key):\n", " if key in self.key_map:\n", " self.emitters[self.key_map[key]].enabled = False\n", " return False\n", " return False\n", "\n", " def pre_debug_draw(self):\n", " pass\n", "\n", " def post_debug_draw(self):\n", " for planet, planet_def in self.planets.items():\n", " pos = planet.position\n", " self.debug_draw.draw_solid_circle(\n", " pos, planet_def[\"radius\"] + 0.1, axis=None, color=planet_def[\"color\"]\n", " )\n", " if planet.user_data == \"black_hole\":\n", " self.debug_draw.draw_circle(\n", " pos, planet_def[\"radius\"] * 5, color=(1, 1, 1), line_width=0.1\n", " )" ] }, { "cell_type": "markdown", "id": "357866b3-876e-421f-8d2a-77d6697551d3", "metadata": {}, "source": [ "# Controlls\n", "* To play this game, use 'w','a','s','d' on your keyboard to steer the rocket\n", "* try to land on the other planet\n", "* avoid the black hole\n", "* Use the mouse-wheel to zoom in/out, a\n", "* Click and drag in the empty space to translate the view." ] }, { "cell_type": "code", "execution_count": null, "id": "7bab75b7-cec1-4348-b95d-9ffd282ded5c", "metadata": {}, "outputs": [], "source": [ "from pyb2d_jupyterlite_backend.async_jupyter_gui import JupyterAsyncGui\n", "s = JupyterAsyncGui.Settings()\n", "s.resolution = [1000,1000]\n", "s.scale = 3\n", "tb = b2d.testbed.run(Rocket, backend=JupyterAsyncGui, gui_settings=s);" ] }, { "cell_type": "code", "execution_count": null, "id": "674c57c8-b5b1-45a9-b75e-5ddc487f7d9b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 5 }