class RingShape(Shape): def __init__(self, inner_radius, outer_radius): Shape.__init__(self) self.inner_radius = inner_radius self.outer_radius = outer_radius self.nbOfPoints = 360 #TODO: This is a big hack to make it work with ProceduralVirtualTextureSource self.lod = 0 self.coord = 0 #TexCoord.Flat self.x0 = 0 self.y0 = 0 self.lod_scale_x = 1 self.lod_scale_y = 1 self.face = -1 def is_spherical(self): return False def create_instance(self): self.instance = NodePath("ring") node = GeomNode('ring-up') node.addGeom( geometry.RingFaceGeometry(1.0, self.inner_radius, self.outer_radius, self.nbOfPoints)) up = self.instance.attach_new_node(node) up.setDepthOffset(-1) node = GeomNode('ring-down') node.addGeom( geometry.RingFaceGeometry(-1.0, self.inner_radius, self.outer_radius, self.nbOfPoints)) down = self.instance.attach_new_node(node) down.setDepthOffset(-1) self.apply_owner() self.instance.set_depth_write(False) return self.instance
def test_sphere_into_heightfield(): root = NodePath("root") world = BulletWorld() # Create PNMImage to construct Heightfield with img = PNMImage(10, 10, 1) img.fill_val(255) # Make our nodes heightfield = make_node("Heightfield", BulletHeightfieldShape, img, 1, ZUp) sphere = make_node("Sphere", BulletSphereShape, 1) # Attach to world np1 = root.attach_new_node(sphere) np1.set_pos(0, 0, 1) world.attach(sphere) np2 = root.attach_new_node(heightfield) np2.set_pos(0, 0, 0) world.attach(heightfield) assert world.get_num_rigid_bodies() == 2 test = world.contact_test_pair(sphere, heightfield) assert test.get_num_contacts() > 0 assert test.get_contact(0).get_node0() == sphere assert test.get_contact(0).get_node1() == heightfield # Increment sphere's Z coordinate, no longer colliding np1.set_pos(0, 0, 2) test = world.contact_test_pair(sphere, heightfield) assert test.get_num_contacts() == 0
class RingShape(Shape): def __init__(self, inner_radius, outer_radius): Shape.__init__(self) self.inner_radius = inner_radius self.outer_radius = outer_radius self.nbOfPoints = 360 def is_spherical(self): return False def create_instance(self): self.instance = NodePath("ring") node = GeomNode('ring-up') node.addGeom( geometry.RingFaceGeometry(1.0, self.inner_radius, self.outer_radius, self.nbOfPoints)) up = self.instance.attach_new_node(node) up.setDepthOffset(-1) node = GeomNode('ring-down') node.addGeom( geometry.RingFaceGeometry(-1.0, self.inner_radius, self.outer_radius, self.nbOfPoints)) down = self.instance.attach_new_node(node) down.setDepthOffset(-1) self.apply_owner() self.instance.set_depth_write(False) return self.instance
def __init__(self, structure: NDArray[(Any, Any, Any), np.uint8], mask: np.uint8, parent: NodePath, name: str = 'old_dynamic_voxel_mesh', default_colour: Colour = WHITE) -> None: self.name = name self.__structure = structure self.__mask = mask self.__default_colour = default_colour self.__body = parent.attach_new_node(self.name) self.__wireframe = parent.attach_new_node(self.name + "_wf") self.__cube_mesh = CubeMesh() self.__wireframe_instance = self.__wireframe.attach_new_node(self.__cube_mesh.wireframe_node) self.__wireframe_instance.detach_node() self.__wireframe_instance_name = name + '_wf_inst' self.__cube_instance = self.__body.attach_new_node(self.__cube_mesh.body_node) self.__cube_instance.detach_node() self.__cube_instance_name = name + '_cube_inst' self.__cube_default_coloured = np.full(self.structure.shape, True, dtype=bool) self.__wireframes = np.empty(self.structure.shape, dtype=NodePath) self.__cubes = np.empty(self.structure.shape, dtype=NodePath) for idx in np.ndindex(self.structure.shape): if bool(self.structure[idx] & self.mask): self.__cubes[idx] = path = self.__body.attach_new_node(self.__cube_instance_name) self.__cube_instance.instance_to(path) path.set_color(*self.__default_colour) path.set_pos(*idx) self.__wireframes[idx] = path = self.__wireframe.attach_new_node(self.__wireframe_instance_name) self.__wireframe_instance.instance_to(path) path.set_pos(*idx)
def animated_tile(self, tsx, tile): node = NodePath("animated tile") sequence = SequenceNode("animated tile") duration = int(tile[0][0].get("duration")) if duration >= 9000: sequence.set_frame_rate(0) else: sequence.set_frame_rate(1000 / duration) for frame in tile[0]: tileid = int(frame.get("tileid")) tile_node = self.build_tile(tsx, tileid) sequence.add_child(tile_node.node()) sequence.loop(True) node.attach_new_node(sequence) return node
class Satallite(): def __init__(self, name, distance): self.pivot = NodePath(name + " pivot") self.root = self.pivot.attach_new_node(name) self.name = name self.distance = distance self.parent = None self.satallites = [] self.hpr_velocity = Vec3() # Determines trajectory sorta # random initial rotation self.pivot.set_hpr(uniform(0, 360), uniform(0, 360), uniform(0, 360)) self.hpr_velocity[0] = uniform(1, 2) self.hpr_velocity[1] = uniform(1, 2) def update_orbit(self, recursive=True): hpr = self.hpr_velocity * CURRENT_TIME self.pivot.set_hpr(hpr) if recursive: for satallite in self.satallites: satallite.update_orbit(recursive) def connect(self, recursive=True): for satallite in self.satallites: satallite.pivot.reparent_to(self.root) satallite.root.set_y(satallite.distance) satallite.parent = self self.update_orbit(recursive=False) if recursive: satallite.connect(True)
def make_circle(scene: core.NodePath, position: core.Point3, radius: float, point_count: int): vertex_data = _make_vertex_data(point_count) position_writer = core.GeomVertexWriter(vertex_data, "vertex") colour_writer = core.GeomVertexWriter(vertex_data, "color") for index in range(point_count): theta = (2 * math.pi * index) / point_count x = math.cos(theta) * radius y = math.sin(theta) * radius position_writer.add_data3(position.x + x, position.y + y, position.z) colour_writer.add_data4(1, 1, 1, 1) primitive = core.GeomTriangles(core.Geom.UH_static) for index in range(1, point_count + 1): point_2 = (index + 1) % point_count point_3 = (index + 2) % point_count primitive.add_vertices(0, point_2, point_3) primitive.close_primitive() geometry = core.Geom(vertex_data) geometry.add_primitive(primitive) geometry_node = core.GeomNode("circle") geometry_node.add_geom(geometry) result: core.NodePath = scene.attach_new_node(geometry_node) result.set_two_sided(True) result.set_transparency(True) return result
def __init__(self, render: NodePath): self._alight = AmbientLight('pb_alight') self._dlight = DirectionalLight('pb_dlight') self._anode = render.attach_new_node(self._alight) self._dnode = render.attach_new_node(self._dlight) self._render = render self._is_active = False self.set_active(True)
def test_reduce_persist(): from panda3d.core import NodePath parent = NodePath("parent") child = parent.attach_new_node("child") parent2, child2 = loads(dumps([parent, child])) assert tuple(parent2.children) == (child2, )
def create(parent: NodePath, way: Way) -> NodePath: """Create node for given way and attach it to the parent.""" geom = _generate_mesh(way) node = GeomNode(str(way.id)) node.add_geom(geom) node.adjust_draw_mask(0x00000000, 0x00010000, 0xfffeffff) node_path = parent.attach_new_node(node) node_path.set_texture(textures.get('road'), 1) return node_path
def create(parent: NodePath, node: Node) -> NodePath: """Create node for given node and attach it to the parent.""" geom = _generate_mesh(node) node_ = GeomNode(str(node.id)) node_.add_geom(geom) node_.adjust_draw_mask(0x00000000, 0x00010000, 0xfffeffff) node_path = parent.attach_new_node(node_) node_path.set_texture(textures.get('intersection')) return node_path
def create(parent: NodePath, radius: float, count: int) -> NodePath: """Create and add the ground plane to the scene.""" geom = _generate_mesh(radius, count) node = GeomNode('world') node.add_geom(geom) node_path = parent.attach_new_node(node) node_path.set_texture(textures.get('ground')) node_path.set_effect(DecalEffect.make()) return node_path
def make_sprite_node( sprite: Texture, size: tuple = None, name: str = None, is_two_sided: bool = True, is_transparent: bool = True, parent: NodePath = None, position: Vec3 = None, scale: float = 0.0, ) -> NodePath: """Make flat single-sprite node out of provided data""" # Using WM_clamp instead of WM_mirror, to avoid issue with black 1-pixel # bars appearing on top of spritesheet randomly. # Idk if this needs to have possibility to override it #TODO sprite.set_wrap_u(Texture.WM_clamp) sprite.set_wrap_v(Texture.WM_clamp) # Creating CardMaker frame card = CardMaker(name or sprite.get_name() or "sprite") # This will fail if texture has been generated with no set_orig_file_size() size = size or (sprite.get_orig_file_x_size(), sprite.get_orig_file_y_size()) # Been told that its not in pixels, thus accepting either 1, 2 or 4 values # Kinda jank, I know if len(size) > 3: card.set_frame(-size[0], size[1], -size[2], size[3]) elif len(size) > 1: card.set_frame(-size[0], size[0], -size[1], size[1]) else: card.set_frame(-size[0], size[0], -size[0], size[0]) parent = parent or NodePath() node = parent.attach_new_node(card.generate()) node.set_texture(sprite) # Making it possible to utilize texture's alpha channel settings # This is a float from 0 to 1, but I dont think there is a point to only # show half of actual object's transparency. # Do it manually afterwards if thats what you need if is_transparent: node.set_transparency(1) # Enabling ability to render texture on both front and back of card if is_two_sided: node.set_two_sided(True) # Setting object's position. This is done relatively to parent, thus if you # didnt pass any, it may be a bit janky if position: node.set_pos(*position) if scale and scale > 0: node.set_scale(scale) return node
def flatten_animated_tiles(self, group_node): # FIXME: hard to read: get_child() everywhere # Makes a new node for each frame using all its tiles # flatten the s*** out of the node and add to a new SequenceNode. tiles = group_node.get_children() flattened_sequence = SequenceNode(tiles[0].name) for a, animation in enumerate(tiles[0].node().get_children()): for f, frame in enumerate(animation.get_child(0).get_children()): combined_frame = NodePath("frame " + str(f)) for tile in tiles: new_np = NodePath("frame") new_np.set_pos(tile.get_pos()) animation = tile.node().get_child(a).get_child(0) new_np.attach_new_node(animation.get_child(f)) new_np.reparent_to(combined_frame) combined_frame.flattenStrong() flattened_sequence.add_child(combined_frame.node()) framerate = animation.get_frame_rate() flattened_sequence.set_frame_rate(framerate) flattened_sequence.loop(True) return NodePath(flattened_sequence)
def create_lane_connections_card(node: Node, parent: NodePath) -> NodePath: """Create textured mesh showing lane connectins and attach it.""" image = _create_lane_connections_image(node) texture = create_texture(image) card = parent.attach_new_node(CARD_MAKER.generate()) card.set_pos((*node.position, 0.25)) card.look_at(card, (0.0, 0.0, -1.0)) card.set_texture(texture) card.set_transparency(TransparencyAttrib.M_alpha) card.set_shader_off() return card
def load_objectgroup(self, objectgroup): layer_node = NodePath(objectgroup.get("name")) for object in objectgroup: name = object.get("name") if not name: name = "object" node = NodePath(name) if len(object) > 0: # Has a type, so it's either a polygon, text, point or ellipse # Points and ellipses are just an empty for now. kind = object[0].tag if kind == "polygon": node.attach_new_node(self.build_polygon(object)) elif kind == "text": node.attach_new_node(self.build_text(object)) node.set_p(-90) self.attributes_to_tags(node, object[0]) else: # Doesn't have a type, so it's either an image or a rectangle node = NodePath(name) w = float(object.get("width")) / self.xscale h = float(object.get("height")) / self.yscale if object.get("gid"): # Has a gid, so it's an image self.get_tile(int(object.get("gid"))).copy_to(node) node.set_scale(w, h, 1) else: # It's none of the above, so it's a rectangle node.attach_new_node(self.build_rectangle(w, h)) x = y = 0 if object.get("x"): x = float(object.get("x")) / self.xscale if object.get("y"): y = float(object.get("y")) / self.yscale node.set_pos(x, -y, 0) self.attributes_to_tags(node, object) node.reparent_to(layer_node) self.append_layer(layer_node, objectgroup.find("properties"))
def make_station(name, size=5): if size == 0: size = 0.1 maker = base.shapes root = NodePath(str(name)) root.set_scale(0.02) model = root.attach_new_node("station model") torus_color = random_color() sphere_color = random_color() cap_color = random_color() # Make poker w = uniform(0.01*size, 0.05*size) shape = choice(("Cylinder", "Cone")) maker.new( shape,random_color(), parent=model, pos=(0,0,0), hpr=(0,0,0), scale=(w,w,size) ) # Add kebab rings = int(size+1)#int(randint(1,4)) distance = size/rings for i in range(rings): z = (distance*(i+1))+ distance w = uniform(min(0.2,0.05*size),0.5*size) shape = choice(("Torus", "Torus", "Sphere")) h = uniform(0.5,2) # Spheres should be flattened and not so wide. color = torus_color if shape == "Sphere": h/=randint(2,5) w/=2 color = sphere_color maker.new( shape, color, parent=model, pos=(0,0,z), hpr=(0,0,0), scale=(w,w,h) ) # Add top and bottom cap def cap(z,p): shape = choice(("Cone", "Sphere")) w = uniform(0.1*size,0.3*size) l = uniform(0.1,1) maker.new( shape, cap_color, parent=model, pos=(0,0,z), hpr=(0,p,0), scale=(w,w,l) ) if not randint(0,2): cap(size*2,0) if not randint(0,2): cap(0,180) model.set_pos(0,0,-size/2) root.flatten_strong() return root
def __init__(self, spacing: float, size: float, parent: NodePath, focus: NodePath): self.spacing = spacing self.size = size self.focus = focus self._create_geom() node = GeomNode('grid') node.add_geom(self.geom) self.node_path = parent.attach_new_node(node) self.node_path.set_z(0.1) self.node_path.set_transparency(TransparencyAttrib.M_alpha) self.node_path.set_light_off() self.node_path.set_shader_off()
def createPlane(self, frame=None, color=VBase4(1, 1, 1, 1)): """ Creates a Plane/Card with the Panda3d Cardmaker() class Keyword Arguments: frame {list} -- The coordinates [x1,y1,x2,y2] of the planes/cards edges (default: {[-1, -1, 1, 1]}) color {VBase4} -- The color of the planes/cards (default: {VBase4(1, 1, 1, 1)}) """ frame = frame or [-1, -1, 1, 1] card = CardMaker("plane") card.set_color(color) card.set_frame(frame[0], frame[1], frame[2], frame[3]) n = NodePath() self.plane = n.attach_new_node(card.generate()) self.plane.reparentTo(self.render) self.plane.setHpr(0, 270, 0)
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False): card_maker = CardMaker(name) card_maker.set_frame(-1, 1, -1, 1) node_path = NodePath(name) node = card_maker.generate() final_node_path = node_path.attach_new_node(node) final_node_path.set_billboard_point_eye() from panda3d.core import Filename shaders = Shader.load(Shader.SL_GLSL, Filename('Shader/Star/vertex.glsl'), Filename('Shader/Star/fragment.glsl'), Filename(''), Filename(''), Filename('')) if not shaders: print("WARNING. STAR SHADER FAILED TO LOAD", type(shaders)) else: final_node_path.set_shader_input('cameraSpherePos', 1, 1, 1) final_node_path.set_shader_input('sphereRadius', 1.0) final_node_path.set_shader_input('myCamera', base.camera) final_node_path.set_shader(shaders) final_node_path.set_shader_input('blackbody', color) material = Material() material.set_emission(VBase4(color, 1.0)) final_node_path.set_material(material) xn = PerlinNoise3(0.5, 0.5, 0.5) #yn = PerlinNoise3(0.5, 0.5, 0.5) texture = Texture('star') texture.setup_3d_texture() for z in range(texture_size): p = PNMImage(texture_size, texture_size) for y in range(texture_size): for x in range(texture_size): p.set_gray(x, y, abs(xn.noise(x, y, z))) texture.load(p, z, 0) diffuse = texture diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setAnisotropicDegree(4) final_node_path.set_texture(diffuse) normal = sandbox.base.loader.loadTexture('data/empty_textures/empty_normal.png') normalts = TextureStage('normalts') final_node_path.set_texture(normalts, normal) specular = sandbox.base.loader.loadTexture('data/empty_textures/empty_specular.png') spects = TextureStage('spects') final_node_path.set_texture(spects, specular) roughness = sandbox.base.loader.loadTexture('data/empty_textures/empty_roughness.png') roughts= TextureStage('roughts') final_node_path.set_texture(roughts, roughness) return final_node_path
def make_ship(name): maker = base.shapes root = NodePath(str(name)) root.set_scale(0.007) model = root.attach_new_node("station model") maker.new( "Cone", random_color(), parent=model, pos=(0,0,0), hpr=(0,0,0), scale=(0.2,0.2,1) ) maker.new( "Cone", random_color(), parent=model, pos=(0,0,0.3), hpr=(0,0,0), scale=(0.2,1,0.5) ) root.flatten_strong() return root
def make_character(name): maker = base.shapes root = NodePath(str(name)) root.set_scale(0.0005) model = root.attach_new_node("station model") maker.new( "Cone", random_color(), parent=model, pos=(0,0,0), hpr=(0,180,0), scale=(0.2,1,1) ) maker.new( "Sphere", random_color(), parent=model, pos=(0,0,1), hpr=(0,0,0), scale=(1,1,1) ) root.flatten_strong() return root
def test_nodepath_replace_texture(): from panda3d.core import NodePath, Texture tex1 = Texture() tex2 = Texture() path1 = NodePath("node1") path1.set_texture(tex1) path1.replace_texture(tex1, tex2) assert path1.get_texture() == tex2 path1 = NodePath("node1") path2 = path1.attach_new_node("node2") path2.set_texture(tex1) path1.replace_texture(tex1, tex2) assert not path1.has_texture() assert path2.get_texture() == tex2
def __init__(self, camera_collection: cameras.Cameras, map_scene: core.NodePath): self._camera_collection = camera_collection self._grid_parent: core.NodePath = map_scene.attach_new_node("grid_3d") self._grid_parent.set_transparency(True) self._small_grid = shapes.make_grid( self._camera_collection, "movement_grid", 2, 100, core.Vec4(0.5, 0.55, 0.8, 0.85), ) self._small_grid.reparent_to(self._grid_parent) self._big_grid = shapes.make_grid( self._camera_collection, "big_movement_grid", 4, 100, core.Vec4(1, 0, 0, 0.95), ) self._big_grid.reparent_to(self._grid_parent) self._big_grid.set_scale(self._LARGE_GRID_SIZE) self._vertical_grid = shapes.make_z_grid( self._camera_collection, "big_movement_grid", 2, 100, core.Vec4(0, 0, 1, 0.95), ) self._vertical_grid.reparent_to(self._grid_parent) self._grid_parent.set_depth_offset(constants.DEPTH_OFFSET, 1) self._grid_parent.hide() self.set_color_scale = self._grid_parent.set_color_scale self.show = self._grid_parent.show self.hide = self._grid_parent.hide self.is_hidden = self._grid_parent.is_hidden
def make_arc( scene: core.NodePath, position: core.Point3, radius: float, theta_degrees: float, point_count: int, ): theta_radians = math.radians(theta_degrees) vertex_data = _make_vertex_data(point_count + 1) position_writer = core.GeomVertexWriter(vertex_data, "vertex") colour_writer = core.GeomVertexWriter(vertex_data, "color") position_writer.add_data3(position.x, position.y, position.z) colour_writer.add_data4(1, 1, 1, 1) for index in range(point_count): theta = (theta_radians * index) / (point_count - 1) x = math.cos(theta) * radius y = math.sin(theta) * radius position_writer.add_data3(position.x + x, position.y + y, position.z) colour_writer.add_data4(1, 1, 1, 1) primitive = core.GeomTriangles(core.Geom.UH_static) total_point_count = point_count + 1 for index in range(point_count): point_2 = (index + 1) % total_point_count point_3 = (index + 2) % total_point_count primitive.add_vertices(0, point_2, point_3) primitive.close_primitive() geometry = core.Geom(vertex_data) geometry.add_primitive(primitive) geometry_node = core.GeomNode("arc") geometry_node.add_geom(geometry) result: core.NodePath = scene.attach_new_node(geometry_node) result.set_two_sided(True) result.set_transparency(True) return result
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False): card_maker = CardMaker(name) card_maker.set_frame(-1, 1, -1, 1) node_path = NodePath(name) node = card_maker.generate() final_node_path = node_path.attach_new_node(node) final_node_path.set_billboard_point_eye() shaders = Shader.load(Shader.SLGLSL, 'Shader/Star/vertex.glsl', 'Shader/Star/fragment.glsl') final_node_path.set_shader_input(b'cameraSpherePos', 1, 1, 1) final_node_path.set_shader_input(b'sphereRadius', 1.0) final_node_path.set_shader_input(b'myCamera', base.camera) final_node_path.set_shader(shaders) final_node_path.set_shader_input(b'blackbody', color) material = Material() material.set_emission(VBase4(color, 1.0)) final_node_path.set_material(material) xn = PerlinNoise3(0.5, 0.5, 0.5) #yn = PerlinNoise3(0.5, 0.5, 0.5) texture = Texture('star') texture.setup_3d_texture() for z in range(texture_size): p = PNMImage(texture_size, texture_size) for y in range(texture_size): for x in range(texture_size): p.set_gray(x, y, abs(xn.noise(x, y, z))) texture.load(p, z, 0) diffuse = texture diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setAnisotropicDegree(4) final_node_path.set_texture(diffuse) normal = base.loader.loadTexture('Data/Textures/EmptyNormalTexture.png') normalts = TextureStage('normalts') final_node_path.set_texture(normalts, normal) specular = base.loader.loadTexture('Data/Textures/EmptySpecularTexture.png') spects = TextureStage('spects') final_node_path.set_texture(spects, specular) roughness = base.loader.loadTexture('Data/Textures/EmptyRoughnessTexture.png') roughts= TextureStage('roughts') final_node_path.set_texture(roughts, roughness) return final_node_path
def create(parent: NodePath, path: Path) -> NodePath: """Create node for given path and attach it to the parent.""" points = path.oriented_points() if len(points) >= 2: geom = _generate_mesh(points) node = GeomNode('path') node.add_geom(geom) node.adjust_draw_mask(0x00000000, 0x00010000, 0xfffeffff) node_path = parent.attach_new_node(node) node_path.set_light_off() # Setting depth write to false solves the problem of this big flat # polygon obscuring other semi-transparent things (like the lane # connections card) depending on the camera angle. See: # https://docs.panda3d.org/1.10/python/programming/texturing/transparency-and-blending node_path.set_depth_write(False) node_path.set_transparency(TransparencyAttrib.M_alpha) else: node_path = None return node_path
def make_collision(solid_from, solid_into): node_from = CollisionNode("from") node_from.add_solid(solid_from) node_into = CollisionNode("into") node_into.add_solid(solid_into) root = NodePath("root") trav = CollisionTraverser() queue = CollisionHandlerQueue() np_from = root.attach_new_node(node_from) np_into = root.attach_new_node(node_into) trav.add_collider(np_from, queue) trav.traverse(root) entry = None for e in queue.get_entries(): if e.get_into() == solid_into: entry = e return (entry, np_from, np_into)
class RayMarchingShape(Shape): templates = {} def __init__(self, radius=1.0, scale=None): Shape.__init__(self) self.radius = radius if scale is None: self.radius = radius self.scale = LVecBase3(self.radius, self.radius, self.radius) else: self.scale = LVecBase3(*scale) * radius self.radius = max(scale) * radius self.blend = TransparencyBlend.TB_PremultipliedAlpha self.scale_factor = 1.0 def shape_id(self): return '' def get_apparent_radius(self): return self.radius def create_instance(self): self.instance = NodePath("card") card_maker = CardMaker("card") card_maker.set_frame(-1, 1, -1, 1) node = card_maker.generate() self.card_instance = self.instance.attach_new_node(node) self.card_instance.setBillboardPointWorld() TransparencyBlend.apply(self.blend, self.instance) self.instance.node().setBounds(OmniBoundingVolume()) self.instance.node().setFinal(True) return self.instance def get_scale(self): return Shape.get_scale(self) * self.scale_factor def update_instance(self, camera_pos, orientation): alpha = asin(self.radius / self.owner.distance_to_obs) self.scale_factor = 1.0 / cos(alpha)
class PointBall(object): def __init__(self, position, value): #Invisiible point so that both spheres have the same parent self.name = "pointball" self.center = NodePath(PandaNode("Pointball center")) self.ttl = 15 #Time to live in seconds self.ttl_max = 15 self.max_size = 9000 self.attraction_distance = 900000 self.center.setPos(position) self.center.setTag("value", str(value)) # Create 1st sphere self.one = loader.loadModel("./Models/sphere.egg") self.one.setColor(colors.get("blue-transparent")) self.one.setScale(self.max_size, self.max_size, self.max_size) self.one.setLightOff() self.one.reparentTo(self.center) #Create 2nd sphere self.two = loader.loadModel("./Models/sphere.egg") self.two.setColor(colors.get("lightblue-transparent")) self.two.setScale(self.max_size, self.max_size, self.max_size) self.two.setLightOff() self.two.reparentTo(self.center) #Create the light so the missle glows plight = PointLight('plight') plight.setColor(colors.get("blue")) plight.setAttenuation(LVector3(0, 0.000008, 0)) plight.setMaxDistance(100) self.plnp = self.center.attachNewNode(plight) #point light node point render.setLight(self.plnp) # Create Collision hitsphere cNode = CollisionNode(self.name) cNode.addSolid(CollisionSphere(0, 0, 0, self.max_size * 20)) self.c_np = self.center.attach_new_node(cNode) #Render to scene self.center.reparentTo(render)
def __init__(self, services: Services, data: NDArray[(Any, Any, Any), bool], parent: NodePath, name: str = "map"): self._services = services self.__name = name self.__colour_callbacks = {} self.data = data self.logical_w = int(self.data.shape[0]) self.logical_h = int(self.data.shape[1]) self.logical_d = int(self.data.shape[2]) self._services.ev_manager.register_listener(self) self.__root = parent.attach_new_node(self.name) self.root.set_transparency(TransparencyAttrib.M_alpha) self._add_colour(MapData.BG, callback=lambda dc: self._services.graphics.window. set_background_color(*dc()))
class PostProcessRegion(RPObject): """ Simple wrapper class to create fullscreen triangles and quads """ @classmethod def make(cls, internal_buffer, *args): return cls(internal_buffer, *args) def __init__(self, internal_buffer, *args): RPObject.__init__(self) self._buffer = internal_buffer self._region = self._buffer.make_display_region(*args) self._node = NodePath("RTRoot") self._make_fullscreen_tri() self._make_fullscreen_cam() self._init_function_pointers() def _init_function_pointers(self): self.set_sort = self._region.set_sort self.set_instance_count = self._tri.set_instance_count self.disable_clears = self._region.disable_clears self.set_active = self._region.set_active self.set_clear_depth_active = self._region.set_clear_depth_active self.set_clear_depth = self._region.set_clear_depth self.set_shader = self._tri.set_shader self.set_camera = self._region.set_camera self.set_clear_color_active = self._region.set_clear_color_active self.set_clear_color = self._region.set_clear_color self.set_attrib = self._tri.set_attrib def _make_fullscreen_tri(self): """ Creates the oversized triangle used for rendering """ vformat = GeomVertexFormat.get_v3() vdata = GeomVertexData("vertices", vformat, Geom.UH_static) vdata.set_num_rows(3) vwriter = GeomVertexWriter(vdata, "vertex") vwriter.add_data3f(-1, 0, -1) vwriter.add_data3f(3, 0, -1) vwriter.add_data3f(-1, 0, 3) gtris = GeomTriangles(Geom.UH_static) gtris.add_next_vertices(3) geom = Geom(vdata) geom.add_primitive(gtris) geom_node = GeomNode("gn") geom_node.add_geom(geom) geom_node.set_final(True) geom_node.set_bounds(OmniBoundingVolume()) tri = NodePath(geom_node) tri.set_depth_test(False) tri.set_depth_write(False) tri.set_attrib(TransparencyAttrib.make(TransparencyAttrib.M_none), 10000) tri.set_color(Vec4(1)) tri.set_bin("unsorted", 10) tri.reparent_to(self._node) self._tri = tri def set_shader_input(self, *args, **kwargs): if kwargs.get("override", False): self._node.set_shader_input(*args, priority=100000) else: self._tri.set_shader_input(*args) def _make_fullscreen_cam(self): """ Creates an orthographic camera for the buffer """ buffer_cam = Camera("BufferCamera") lens = OrthographicLens() lens.set_film_size(2, 2) lens.set_film_offset(0, 0) lens.set_near_far(-100, 100) buffer_cam.set_lens(lens) buffer_cam.set_cull_bounds(OmniBoundingVolume()) self._camera = self._node.attach_new_node(buffer_cam) self._region.set_camera(self._camera)
def v(): return (random.random() - .5) * 2 * r roots = [] idx2ori_nps = {} for k in range(50): root = NodePath("flatten_root:%s" % k) root.reparent_to(G.render) nps = [] for i in range(50): model = G.loader.loadModel('../assets/blender/twig.egg') # one trap here. # getChildren() at first, flatten() won't touch any geoms under model node path. new_np = root.attach_new_node('child_%s_%s' % (k, i)) model.get_children().reparentTo(new_np) new_np.set_pos(v(), v(), v()) #nps.append(new_np) roots.append(root) idx2ori_nps[k] = nps var = {'ts': 0} def flatten(idx=0): if idx >= len(roots): return import time var['ts'] = time.time()
class World (object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.render = NodePath('world') self.camera = camera self.audio3d = audio3d self.ambient = self._make_ambient() self.celestials = CompositeObject() self.sky = self.attach(Sky()) # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug self.client = client self.server = server if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.render.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def _make_ambient(self): alight = AmbientLight('ambient') alight.set_color(VBase4(*DEFAULT_AMBIENT_COLOR)) node = self.render.attach_new_node(alight) self.render.set_light(node) return node def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.render.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.render) elif obj.solid: obj.node = self.render.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def get_incarn(self): return random.choice(self.incarnators) def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def set_ambient(self, color): """ Sets the ambient light to the given color. """ self.ambient.node().set_color(VBase4(*color)) def add_celestial(self, azimuth, elevation, color, intensity, radius, visible): """ Adds a celestial light source to the scene. If it is a visible celestial, also add a sphere model. """ if not self.camera: return location = Vec3(to_cartesian(azimuth, elevation, 1000.0 * 255.0 / 256.0)) if intensity: dlight = DirectionalLight('celestial') dlight.set_color((color[0] * intensity, color[1] * intensity, color[2] * intensity, 1.0)) node = self.render.attach_new_node(dlight) node.look_at(*(location * -1)) self.render.set_light(node) if visible: if radius <= 2.0: samples = 6 elif radius >= 36.0: samples = 40 else: samples = int(round(((1.5 * radius) * (2 / 3.0)) + 3.75)) celestial = Dome(radius * 1.5, samples, 2, color, 0, location, ((-(math.degrees(azimuth))), 90 + math.degrees(elevation), 0)) self.celestials.attach(celestial) def create_celestial_node(self): bounds = self.camera.node().get_lens().make_bounds() self.celestials = self.celestials.create_node() self.celestials.set_transparency(TransparencyAttrib.MAlpha) self.celestials.set_light_off() self.celestials.set_effect(CompassEffect.make(self.camera, CompassEffect.PPos)) self.celestials.node().set_bounds(bounds) self.celestials.node().set_final(True) self.celestials.reparent_to(self.render) def register_collider(self, obj): assert isinstance(obj, PhysicalObject) self.collidables.add(obj) def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def do_explosion(self, node, radius, force): center = node.get_pos(self.render); expl_body = BulletGhostNode("expl") expl_shape = BulletSphereShape(radius) expl_body.add_shape(expl_shape) expl_bodyNP = self.render.attach_new_node(expl_body) expl_bodyNP.set_pos(center) self.physics.attach_ghost(expl_body) result = self.physics.contact_test(expl_body) for contact in result.getContacts(): n0_name = contact.getNode0().get_name() n1_name = contact.getNode1().get_name() obj = None try: obj = self.objects[n1_name] except: break if n0_name == "expl" and n1_name not in EXPLOSIONS_DONT_PUSH and not n1_name.startswith('Walker'): # repeat contact test with just this pair of objects # otherwise all manifold point values will be the same # for all objects in original result real_c = self.physics.contact_test_pair(expl_body, obj.solid) mpoint = real_c.getContacts()[0].getManifoldPoint() distance = mpoint.getDistance() if distance < 0: if hasattr(obj, 'decompose'): obj.decompose() else: expl_vec = Vec3(mpoint.getPositionWorldOnA() - mpoint.getPositionWorldOnB()) expl_vec.normalize() magnitude = force * 1.0/math.sqrt(abs(radius - abs(distance))) obj.solid.set_active(True) obj.solid.apply_impulse(expl_vec*magnitude, mpoint.getLocalPointB()) if hasattr(obj, 'damage'): obj.damage(magnitude/5) self.physics.remove_ghost(expl_body) expl_bodyNP.detach_node() del(expl_body, expl_bodyNP) def do_plasma_push(self, plasma, node, energy): obj = None try: obj = self.objects[node] except: raise if node not in EXPLOSIONS_DONT_PUSH and not node.startswith('Walker'): if hasattr(obj, 'decompose'): obj.decompose() else: solid = obj.solid dummy_node = NodePath('tmp') dummy_node.set_hpr(plasma.hpr) dummy_node.set_pos(plasma.pos) f_vec = render.get_relative_vector(dummy_node, Vec3(0,0,1)) local_point = (obj.node.get_pos() - dummy_node.get_pos()) *-1 f_vec.normalize() solid.set_active(True) try: solid.apply_impulse(f_vec*(energy*35), Point3(local_point)) except: pass del(dummy_node) if hasattr(obj, 'damage'): obj.damage(energy*5) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break; trash = self.garbage.pop() if(isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if(isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del(trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont
class ColorWorld(object): def __init__(self, config=None): # keep track of velocity, this allows me to counteract joystick with keyboard self.velocity = LVector3(0) if config is None: self.config = {} execfile('config.py', self.config) else: self.config = config self.reward = None if pydaq: self.reward = pydaq.GiveReward() self.reward_count = 0 # self.color_map always corresponds to (r, g, b) # does not change during game, each game uses a particular color space self.color_dict = square.make_color_map(self.config['colors']) # sets the range of colors for this map self.c_range = self.config['c_range'] # color variables (make dictionary?) # color_list is set in beginning, and then after that this is only # called again for non-random (training) self.color_list = square.set_start_position_colors(self.config) self.color_match = [0, 0, 0] self.color_tolerance = [] self.last_avt, self.avt_factor = square.translate_color_map(self.config, self.color_dict, self.color_list) print 'starting avt position', self.last_avt print 'map avatar factor', self.avt_factor self.random = True if self.config.get('match_direction'): self.random = False # adjustment to speed so corresponds to gobananas task # 7 seconds to cross original environment # speed needs to be adjusted to both speed in original # environment and c_range of colors # self.speed = 0.05 * (self.c_range[1] - self.c_range[0]) # speed is own variable, so can be changed during training. self.speed = self.config['speed'] # map avatar variables self.render2d = None self.match_square = None self.map_avt_node = [] # need a multiplier to the joystick output to tolerable speed self.vel_base = 3 self.max_vel = [500, 500, 0] self.card = None self.base = ShowBase() self.base.disableMouse() # assume we are showing windows unless proven otherwise if self.config.get('win', True): # only need inputs if we have a window self.inputs = Inputs(self.base) props = WindowProperties() props.setCursorHidden(True) props.setForeground(True) print self.config.get('resolution') if self.config.get('resolution'): props.set_size(int(self.config['resolution'][0]), int(self.config['resolution'][1])) props.set_origin(0, 0) else: props.set_size(600, 600) props.set_origin(400, 50) self.base.win.requestProperties(props) # print self.base.win.get_size() # setup color map on second window sq_node = square.setup_square(self.config) self.setup_display2(sq_node) # print 'background color', self.base.getBackgroundColor() # create the avatar self.avatar = NodePath(ActorNode("avatar")) self.avatar.reparentTo(self.base.render) self.avatar.setH(self.base.camera.getH()) self.base.camera.reparentTo(self.avatar) self.base.camera.setPos(0, 0, 0) # initialize task variables self.frame_task = None self.started_game = None self.showed_match = None self.gave_reward = None # initialize and start the game self.set_next_trial() # print 'end init' def start_loop(self): # need to get new match print 'start loop' self.started_game = self.base.taskMgr.doMethodLater(5, self.start_play, 'start_play') self.showed_match = self.base.taskMgr.add(self.show_match_sample, 'match_image') # Task methods def show_match_sample(self, task): print 'show match sample' print self.color_match[:] # match_image.fill(*self.color_match[:]) card = CardMaker('card') color_match = self.color_match[:] # add alpha channel color_match.append(1) print color_match card.set_color(*color_match[:]) card.set_frame(-12, -8, 0, 4) # log this self.card = self.base.render.attach_new_node(card.generate()) return task.done def start_play(self, task): print 'start play' # log this self.base.taskMgr.remove('match_image') self.card.removeNode() # print self.base.render.ls() self.frame_task = self.base.taskMgr.add(self.game_loop, "game_loop") self.frame_task.last = 0 # initiate task time of the last frame # log this self.base.setBackgroundColor(self.color_list[:]) return task.done def game_loop(self, task): dt = task.time - task.last task.last = task.time self.velocity = self.inputs.poll_inputs(self.velocity) move = self.move_avatar(dt) stop = self.change_background(move) self.move_map_avatar(move, stop) match = self.check_color_match() if match: self.give_reward() return task.done return task.cont def reward_loop(self, task): self.reward_count += 1 if self.reward_count <= self.config['num_beeps']: if self.reward: # log this print 'give a bloody reward already' self.reward.pumpOut() print 'give reward' return task.again else: self.end_loop() return task.done def move_avatar(self, dt): # print 'velocity', self.velocity # this makes for smooth (correct speed) diagonal movement # print 'velocity', self.velocity magnitude = max(abs(self.velocity[0]), abs(self.velocity[1])) move = None if self.velocity.normalize(): # go left in increasing amount # print 'dt', dt # print 'normalized' # print 'velocity', self.velocity # print 'magnitude', magnitude self.velocity *= magnitude # print 'velocity', self.velocity # this makes for smooth movement move = self.velocity * self.vel_base * dt # print move self.avatar.setFluidPos(self.avatar, move) return move def change_background(self, move): stop = [True, True, True] if move: # print move move *= self.speed for i in range(3): value = self.color_dict[i] if value is not None: stop[i] = False # keys correspond to x,y,z # values correspond to r,g,b if i == 2: # z axis is treated differently # need to work on this. z should # be at min when both x and y are at max # taking the average is not quite right... z_move = (move[0] + move[1])/2 # print z_move self.color_list[value] -= z_move else: self.color_list[value] += move[i] if self.color_list[value] < self.c_range[0]: self.color_list[value] = self.c_range[0] stop[i] = True elif self.color_list[value] > self.c_range[1]: self.color_list[value] = self.c_range[1] stop[i] = True # log this self.base.setBackgroundColor(self.color_list[:]) # print self.base.getBackgroundColor() return stop def move_map_avatar(self, move, stop): # print move # avatar is mapped assuming c_range of 0.5. What do I need to # change to use a different c_range? c_range of one is twice # the if move: avt = LineSegs() avt.setThickness(1) avt.setColor(1, 1, 1) # print 'last', self.last_avt avt.move_to(self.last_avt[0], -5, self.last_avt[1]) # print 'move', move new_move = [i + (j * self.avt_factor) for i, j in zip(self.last_avt, move)] # new_move = [i + j for i, j in zip(self.last_avt, move)] # would it be better to have a local stop condition? if stop[0]: new_move[0] = self.last_avt[0] # print 'stop x', self.last_avt[0] if stop[1]: new_move[1] = self.last_avt[1] # print 'stop y', self.last_avt[1] # print 'new', new_move self.last_avt = [new_move[0], new_move[1]] avt.draw_to(new_move[0], -5, new_move[1]) self.map_avt_node.append(self.render2d.attach_new_node(avt.create())) # print self.map_avt_node[-1] # can't let too many nodes pile up if len(self.map_avt_node) > 299: # removing the node does not remove the object from the list for i, j in enumerate(self.map_avt_node): j.removeNode() if i > 49: break del self.map_avt_node[0:50] def check_color_match(self): # print 'match this', self.color_tolerance # print self.color_list check_color = [j[0] < self.color_list[i] < j[1] for i, j in enumerate(self.color_tolerance)] # print check_color if all(check_color): return True else: return False def give_reward(self): # clear the background self.base.setBackgroundColor(0.41, 0.41, 0.41) print 'give first reward' self.reward_count = 1 if self.reward: # log this self.reward.pumpOut() self.gave_reward = self.base.taskMgr.doMethodLater(self.config['pump_delay'], self.reward_loop, 'reward_loop') def end_loop(self): print 'end loop' # clear avatar map self.clear_avatar_map() # if there is a match set, return to center of color gradient, # set new match, if applicable self.set_next_trial() def clear_avatar_map(self): for i, j in enumerate(self.map_avt_node): j.removeNode() self.map_avt_node = [] def plot_match_square(self, corners): print 'plot match square' print corners match = LineSegs() match.setThickness(1.5) match.setColor(0, 0, 0) match.move_to(corners[0][0], -5, corners[1][0]) match.draw_to(corners[0][1], -5, corners[1][0]) match.draw_to(corners[0][1], -5, corners[1][1]) match.draw_to(corners[0][0], -5, corners[1][1]) match.draw_to(corners[0][0], -5, corners[1][0]) # print self.render2d self.match_square = self.render2d.attach_new_node(match.create()) def create_avatar_map_match_square(self, config=None): print 'make new square for map' if config is not None: config_dict = config else: config_dict = self.config # create square on avatar map for new color match map_color_match, factor = square.translate_color_map(config_dict, self.color_dict, self.color_match) tolerance = config_dict['tolerance'] * factor map_color_tolerance = [(i - tolerance, i + tolerance) for i in map_color_match] print map_color_tolerance if self.render2d: if self.match_square: self.match_square.removeNode() self.plot_match_square(map_color_tolerance) def set_next_trial(self): print 'set next trial' # move avatar back to beginning position, only matters for # showing card for next color match self.avatar.set_pos(-10, -10, 2) # set color_list with starting color # if random, won't use this again, but for manual, will # return to center # need to update self.config to new direction, if there is one if self.config.get('match_direction'): self.check_key_map() # return to center, otherwise random will start where you left off self.color_list = square.set_start_position_colors(self.config) # starting position for map avatar, just translate new color_list self.last_avt, self.avt_factor = square.translate_color_map(self.config, self.color_dict, self.color_list) print 'start color', self.color_list print self.color_dict # again need to update self.config for match if using keys self.color_match = square.set_match_colors(self.config, self.color_dict) # sets the tolerance for how close to a color for reward self.color_tolerance = [(i - self.config['tolerance'], i + self.config['tolerance']) for i in self.color_match] print 'color match', self.color_match print 'color tolerance', self.color_tolerance self.create_avatar_map_match_square(self.config) # start the game self.start_loop() def check_key_map(self): if self.config['colors'][0]: if self.inputs.key_map['r']: self.config['match_direction'] = ['right'] elif self.inputs.key_map['r'] is not None: self.config['match_direction'] = ['left'] elif self.config['colors'][1]: if self.inputs.key_map['f']: self.config['match_direction'] = ['front'] elif self.inputs.key_map['f'] is not None: self.config['match_direction'] = ['back'] def setup_display2(self, display_node): print 'setup display2' props = WindowProperties() props.set_cursor_hidden(True) props.set_foreground(False) if self.config.get('resolution'): props.setSize(700, 700) props.setOrigin(-int(self.config['resolution'][0] - 5), 5) else: props.setSize(300, 300) props.setOrigin(10, 10) window2 = self.base.openWindow(props=props, aspectRatio=1) lens = OrthographicLens() lens.set_film_size(2, 2) lens.setNearFar(-100, 100) self.render2d = NodePath('render2d') self.render2d.attach_new_node(display_node) camera2d = self.base.makeCamera(window2) camera2d.setPos(0, -10, 0) camera2d.node().setLens(lens) camera2d.reparentTo(self.render2d)
class PlayWorld(object): def __init__(self, config=None): if config is None: self.config = {} execfile('play_config.py', self.config) else: self.config = config self.reward = None print self.config['pydaq'] if pydaq and self.config.setdefault('pydaq', True) is not None: self.reward = pydaq.GiveReward() self.reward_count = 0 # adjustment to speed so corresponds to gobananas task # 7 seconds to cross original environment # speed needs to be adjusted to both speed in original # environment and c_range of colors # self.speed = 0.05 * (self.c_range[1] - self.c_range[0]) # speed is own variable, so can be changed during training. self.speed = self.config['speed'] # need a multiplier to the joystick output to tolerable speed self.vel_base = 4 self.max_vel = [500, 500, 0] self.base = ShowBase() self.base.disableMouse() # self.base.setFrameRateMeter(True) # assume we are showing windows unless proven otherwise if self.config.get('win', True): # only need inputs if we have a window self.inputs = Inputs(self.base) props = WindowProperties() props.setCursorHidden(True) props.setForeground(True) print self.config.get('resolution') if self.config.get('resolution'): # main window props.set_size(int(self.config['resolution'][0]), int(self.config['resolution'][1])) # props.set_origin(1920, 0) props.set_origin(500, 0) else: props.set_size(600, 600) props.set_origin(400, 50) self.base.win.requestProperties(props) # print 'background color', self.base.getBackgroundColor() # field = self.base.loader.loadModel("../goBananas/models/play_space/field.bam") field = self.base.loader.loadModel("../goBananas/models/play_space/round_courtyard.bam") field.setPos(0, 0, 0) field.reparent_to(self.base.render) field_node_path = field.find('**/+CollisionNode') field_node_path.node().setIntoCollideMask(0) sky = self.base.loader.loadModel("../goBananas/models/sky/sky_kahana2.bam") sky.setPos(0, 0, 0) sky.setScale(1.6) sky.reparentTo(self.base.render) windmill = self.base.loader.loadModel("../goBananas/models/windmill/windmill.bam") windmill.setPos(-10, 30, -1) windmill.setScale(0.03) windmill.reparentTo(self.base.render) # mountain = self.base.loader.loadModel("../goBananas/models/mountain/mountain.bam") # mountain.setScale(0.0005) # mountain.setPos(10, 30, -0.5) # create the avatar self.avatar = NodePath(ActorNode("avatar")) self.avatar.reparentTo(self.base.render) self.avatar.setPos(0, 0, 1) self.avatar.setScale(0.5) pl = self.base.cam.node().getLens() pl.setFov(60) self.base.cam.node().setLens(pl) self.base.camera.reparentTo(self.avatar) # initialize task variables self.frame_task = None self.started_game = None self.showed_match = None self.gave_reward = None # initialize and start the game self.set_next_trial() # print 'end init' def start_loop(self): # need to get new match self.start_play() def start_play(self): print 'start play' # log this # print self.base.render.ls() self.frame_task = self.base.taskMgr.add(self.game_loop, "game_loop") self.frame_task.last = 0 # initiate task time of the last frame def game_loop(self, task): dt = task.time - task.last task.last = task.time velocity = self.inputs.poll_inputs(LVector3(0)) self.move_avatar(dt, velocity) return task.cont def reward_loop(self, task): self.reward_count += 1 if self.reward_count <= self.config['num_beeps']: if self.reward: # log this print 'give a bloody reward already' self.reward.pumpOut() print 'give reward' return task.again else: self.end_loop() return task.done def move_avatar(self, dt, velocity): # print 'velocity', self.velocity self.avatar.setH(self.avatar.getH() - velocity[0] * 1.1) move = LVector3(0, velocity[1], 0) self.avatar.setPos(self.avatar, move * dt * self.vel_base) def give_reward(self): # clear the background self.base.setBackgroundColor(0.41, 0.41, 0.41) print 'give first reward' self.reward_count = 1 if self.reward: # log this self.reward.pumpOut() self.gave_reward = self.base.taskMgr.doMethodLater(self.config['pump_delay'], self.reward_loop, 'reward_loop') def end_loop(self): print 'end loop' # clear avatar map # if there is a match set, return to center of color gradient, # set new match, if applicable self.set_next_trial() def set_next_trial(self): print 'set next trial' # move avatar back to beginning position, only matters for # showing card for next color match # self.avatar.set_pos(-10, -10, 2) # start the game self.start_loop() def check_key_map(self): if self.config['colors'][0]: if self.inputs.key_map['r']: self.config['match_direction'] = ['right'] elif self.inputs.key_map['r'] is not None: self.config['match_direction'] = ['left'] elif self.config['colors'][1]: if self.inputs.key_map['f']: self.config['match_direction'] = ['front'] elif self.inputs.key_map['f'] is not None: self.config['match_direction'] = ['back'] def setup_display2(self, display_node): print 'setup display2' props = WindowProperties() props.set_cursor_hidden(True) props.set_foreground(False) if self.config.get('resolution'): props.setSize(700, 700) props.setOrigin(-int(self.config['resolution'][0] - 5), 5) else: props.setSize(300, 300) props.setOrigin(10, 10) window2 = self.base.openWindow(props=props, aspectRatio=1) lens = OrthographicLens() lens.set_film_size(2, 2) lens.setNearFar(-100, 100) self.render2d = NodePath('render2d') self.render2d.attach_new_node(display_node) camera2d = self.base.makeCamera(window2) camera2d.setPos(0, -10, 0) camera2d.node().setLens(lens) camera2d.reparentTo(self.render2d)
class World: def __init__(self, loader=None, camera=None, debug=False): self.loader = loader self.camera = camera self.physics = BulletWorld() self.gravity = Vec3(0, 0, -30.0) self.physics.set_gravity(self.gravity) self.objects = {} self.frame = 0 self.last_object_id = 0 self.incarnators = [] self.debug = debug self.setup() self.commands = [] def setup(self): self.node = NodePath('world') self.node.set_transparency(TransparencyAttrib.MAlpha) if self.debug: d = BulletDebugNode('Debug') d.show_wireframe(True) d.show_normals(True) self.node.attach_new_node(d).show() self.physics.set_debug_node(d) if self.camera: self.camera.node().get_lens().set_fov(80.0, 50.0) self.camera.node().get_lens().set_near(0.1) # Default ambient light alight = AmbientLight('ambient') alight.set_color(DEFAULT_AMBIENT_COLOR) self.ambient = self.node.attach_new_node(alight) self.node.set_light(self.ambient) # Default directional lights self.add_celestial(math.radians(20), math.radians(45), (1, 1, 1, 1), 0.4, 30.0) self.add_celestial(math.radians(200), math.radians(20), (1, 1, 1, 1), 0.3, 30.0) def tick(self, dt): self.frame += 1 self.physics.doPhysics(dt, 4, 1.0 / 60.0) state = {} for obj in list(self.objects.values()): if obj.update(self, dt): state[obj.world_id] = obj.get_state() for cmd, args in self.commands: yield cmd, args if state: yield 'state', {'frame': self.frame, 'state': state} self.commands = [] def attach(self, obj): obj.setup(self) if obj.world_id is None: self.last_object_id += 1 obj.world_id = self.last_object_id self.objects[obj.world_id] = obj obj.attached(self) if self.frame > 0 and False: self.commands.append(('attached', { 'objects': [obj.serialize()], 'state': { obj.world_id: obj.get_state(), } })) return obj def remove(self, world_id): if isinstance(world_id, GameObject): world_id = world_id.world_id if world_id not in self.objects: return self.objects[world_id].removed(self) del self.objects[world_id] if self.frame > 0: self.commands.append(('removed', {'world_ids': [world_id]})) def find(self, pos, radius): for obj in self.objects.values(): if isinstance(obj, PhysicalObject): d = (obj.node.get_pos() - pos).length() if d <= radius: yield obj, d def add_incarnator(self, pos, heading): self.incarnators.append((pos, heading)) def load_model(self, name): """ Stubbed out here in case we want to allow adding/loading custom models from map XML. """ return self.loader.load_model(name) if self.loader else None def serialize(self): return {world_id: obj.serialize() for world_id, obj in self.objects.items()} def deserialize(self, data): self.node.remove_node() self.setup() for world_id, obj_data in data.items(): self.attach(GameObject.deserialize(obj_data)) def get_state(self): states = {} for world_id, obj in self.objects.items(): states[world_id] = obj.get_state() return states def set_state(self, states, fluid=True): for world_id, state in states.items(): self.objects[world_id].set_state(state, fluid=fluid) def add_celestial(self, azimuth, elevation, color, intensity, radius): location = Vec3(to_cartesian(azimuth, elevation, 1000.0 * 255.0 / 256.0)) if intensity: dlight = DirectionalLight('celestial') dlight.set_color((color[0] * intensity, color[1] * intensity, color[2] * intensity, 1.0)) node = self.node.attach_new_node(dlight) node.look_at(*(location * -1)) self.node.set_light(node)
class World (object): """ The World models basically everything about a map, including gravity, ambient light, the sky, and all map objects. """ def __init__(self, camera, debug=False, audio3d=None, client=None, server=None): self.objects = {} self.incarnators = [] self.collidables = set() self.updatables = set() self.updatables_to_add = set() self.garbage = set() self.scene = NodePath('world') # Set up the physics world. TODO: let maps set gravity. self.gravity = DEFAULT_GRAVITY self.physics = BulletWorld() self.physics.set_gravity(self.gravity) self.debug = debug if debug: debug_node = BulletDebugNode('Debug') debug_node.show_wireframe(True) debug_node.show_constraints(True) debug_node.show_bounding_boxes(False) debug_node.show_normals(False) np = self.scene.attach_new_node(debug_node) np.show() self.physics.set_debug_node(debug_node) def get_incarn(self): return random.choice(self.incarnators) def attach(self, obj): assert hasattr(obj, 'world') and hasattr(obj, 'name') assert obj.name not in self.objects obj.world = self if obj.name.startswith('Incarnator'): self.incarnators.append(obj) if hasattr(obj, 'create_node') and hasattr(obj, 'create_solid'): # Let each object define it's own NodePath, then reparent them. obj.node = obj.create_node() obj.solid = obj.create_solid() if obj.solid: if isinstance(obj.solid, BulletRigidBodyNode): self.physics.attach_rigid_body(obj.solid) elif isinstance(obj.solid, BulletGhostNode): self.physics.attach_ghost(obj.solid) if obj.node: if obj.solid: # If this is a solid visible object, create a new physics node and reparent the visual node to that. phys_node = self.scene.attach_new_node(obj.solid) obj.node.reparent_to(phys_node) obj.node = phys_node else: # Otherwise just reparent the visual node to the root. obj.node.reparent_to(self.scene) elif obj.solid: obj.node = self.scene.attach_new_node(obj.solid) if obj.solid and obj.collide_bits is not None: obj.solid.set_into_collide_mask(obj.collide_bits) self.objects[obj.name] = obj # Let the object know it has been attached. obj.attached() return obj def create_hector(self, name=None): # TODO: get random incarn, start there h = self.attach(Hector(name)) h.move((0, 15, 0)) return h def register_updater(self, obj): assert isinstance(obj, WorldObject) self.updatables.add(obj) def register_updater_later(self, obj): assert isinstance(obj, WorldObject) self.updatables_to_add.add(obj) def update(self, task): """ Called every frame to update the physics, etc. """ dt = globalClock.getDt() for obj in self.updatables_to_add: self.updatables.add(obj) self.updatables_to_add = set() for obj in self.updatables: obj.update(dt) self.updatables -= self.garbage self.collidables -= self.garbage while True: if len(self.garbage) < 1: break; trash = self.garbage.pop() if(isinstance(trash.solid, BulletGhostNode)): self.physics.remove_ghost(trash.solid) if(isinstance(trash.solid, BulletRigidBodyNode)): self.physics.remove_rigid_body(trash.solid) if hasattr(trash, 'dead'): trash.dead() trash.node.remove_node() del(trash) self.physics.do_physics(dt) for obj in self.collidables: result = self.physics.contact_test(obj.node.node()) for contact in result.get_contacts(): obj1 = self.objects.get(contact.get_node0().get_name()) obj2 = self.objects.get(contact.get_node1().get_name()) if obj1 and obj2: # Check the collision bits to see if the two objects should collide. should_collide = obj1.collide_bits & obj2.collide_bits if not should_collide.is_zero(): pt = contact.get_manifold_point() if obj1 in self.collidables: obj1.collision(obj2, pt, True) if obj2 in self.collidables: obj2.collision(obj1, pt, False) return task.cont