def update(self, dt, global_velocity=(0, 0)): velocity = vector.add(global_velocity, vector.multiply(self.force, dt)) self.force = vector.multiply(self.force, FORCE_DRAG) self.position = vector.add(self.position, vector.multiply(velocity, dt * self.speed)) self.bounce_from_boundaries()
def explode(self): self.set_weight(int(self.get_weight() * BLOB_EXPLOSION_SHRINK + 0.5)) has_divided = False while self.get_weight( ) >= 2 * BLOB_INIT_WEIGHT and self.blob_family.number_of_blobs( ) < BLOB_MAX_NUM: direction = vector.random_direction() position = vector.add( self.get_position(), vector.multiply(direction, self.get_radius())) shoot = random.randint(0, BLOB_EXPLOSION_SHOOT_CHANCE) == 0 if shoot: self.add_weight(-BULLET_WEIGHT) bullet_blob = BulletBlob( self.model, position, self.player_id, vector.multiply(direction, BLOB_SHOOT_STRENGTH)) self.model.add_bullet_blob(bullet_blob) else: weight = min( random.randint( BLOB_INIT_WEIGHT, max(BLOB_INIT_WEIGHT, int(self.get_weight() / 4))), self.get_weight() - BLOB_INIT_WEIGHT) self.add_weight(-weight) new_blob = Blob(self.model, position, self.player_id, self.blob_family, (0, 0), weight) self.blob_family.add_blob(new_blob) self.model.add_blob(new_blob) has_divided = True if has_divided: self.blob_family.set_countdown()
def __shoot(self): shooting_blob = self.main_blob if shooting_blob.get_weight() >= 2*BLOB_INIT_WEIGHT: shooting_blob.add_weight(-BULLET_WEIGHT) position = vector.add(shooting_blob.get_position(), vector.multiply(self.velocity, shooting_blob.get_radius())) new_blob = BulletBlob(self.model, position, self.player_id, vector.multiply(vector.normalize(self.velocity), BLOB_SHOOT_STRENGTH)) self.model.add_bullet_blob(new_blob)
def get_bbox(self): start = vector.add(self.pos, vector.multiply(self.size, -0.5)) end = vector.add(self.pos, vector.multiply(self.size, 0.5)) return ( self.pos[0] - self.size[0] / 2, self.pos[1] - self.size[1] / 2, self.pos[0] + self.size[0] / 2, self.pos[1] + self.size[1] / 2 )
def repel_from_each_other(self, blob): difference = vector.substract(blob.get_position(), self.position) distance = vector.norm(difference) strength = distance - self.radius - blob.get_radius() self.add_force( vector.multiply( difference, BLOB_REPEL_STRENGTH * strength / distance - BLOB_REPEL_BASE_STRENGTH)) blob.add_force( vector.multiply( difference, -BLOB_REPEL_STRENGTH * strength / distance + BLOB_REPEL_BASE_STRENGTH))
def bounce2(self, p2): """ More complicated bounce, should give better angles. Takes in the particle it is bouncing against and updates its speed too """ avgSpeed = vector.scale(vector.absAdd(self.speed, p2.speed), 0.5) # Average speed # Find the normalised vector from p1 to p2 n = vector.unit(vector.subtract(self.position, p2.position)) self.speed = vector.multiply(n, avgSpeed) p2.speed = vector.scale(vector.multiply(n, avgSpeed), -1) self.limitSpeed() p2.limitSpeed()
def __divide(self): has_divided = False for blob in self.blobs[:]: if blob.get_weight() >= 2*BLOB_INIT_WEIGHT and self.number_of_blobs() < BLOB_MAX_NUM: blob.set_weight(int(blob.get_weight() / 2)) position = vector.add(blob.get_position(), vector.multiply(self.velocity, blob.get_radius() * 2)) new_blob = Blob(self.model, position, self.player_id, self, vector.multiply(vector.normalize(self.velocity), BLOB_DIVIDE_STRENGTH)) new_blob.set_weight(blob.get_weight()) self.add_blob(new_blob) self.model.add_blob(new_blob) has_divided = True if has_divided: self.set_countdown()
def update(self, walls, acceleration, friction): # Move by a given acceleration self.move(Vector(acceleration[0], acceleration[1])) # Iterate through all walls # and check for collisions for wall in walls: # Don't check walls if # they're too far from # a particle wallToLine = vector.subtract(wall.start, self.position) if (vector.magnitude(wallToLine) > vector.magnitude(wall.line)): continue # If the returned value is # greater than 0, the ball # is colliding with the wall clipVal = self.intersectsWall(wall) if (clipVal > 0): # Move the particle out of the wall dPos = vector.multiply(wall.normal, clipVal) self.position.addVector(dPos) # Bounce the particle off of the wall self.velocity = self.getReflection(copy.copy(wall.normal)) # Reduce the particle's velocity by # the friction coefficient self.velocity.scalarMultiply(friction)
def push(self, bullet_blob, strength): direction = vector.normalize( vector.substract(self.position, bullet_blob.get_position())) bullet_force = bullet_blob.get_force() self_force_strength = vector.dot_product(direction, bullet_force) * strength self.add_force(vector.multiply(direction, self_force_strength)) bullet_blob.set_force(vector.substract(bullet_force, self.force))
def draw_point(position): c = level[position[X]][position[Y]] position = vector.multiply(position, UNIT) if c == '.': pygame.draw.circle( surface, DOT_COLOR, vector.to_int(vector.add(position, vector.divide_scalar(UNIT, 2))), int(DOT_RADIUS)) elif c == '|': pygame.draw.rect(surface, WALL_COLOR, position + UNIT)
def tick(): start_time = time.time() # user input keys = py.key.get_pressed() try: fps_mod = 1 / global_data.fps except ZeroDivisionError: fps_mod = 10 # movement forwards_movement = vector.multiply( global_data.camera_look_direction, global_data.camera_movement_speed * fps_mod) if keys[py.K_SPACE]: global_data.camera_position.y -= global_data.camera_movement_speed * fps_mod if keys[py.K_LSHIFT]: global_data.camera_position.y += global_data.camera_movement_speed * fps_mod if keys[py.K_d]: global_data.camera_position.x += global_data.camera_movement_speed * fps_mod if keys[py.K_a]: global_data.camera_position.x -= global_data.camera_movement_speed * fps_mod if keys[py.K_w]: global_data.camera_position = vector.add(global_data.camera_position, forwards_movement) if keys[py.K_s]: print(global_data.camera_position.z) global_data.camera_position = vector.subtract( global_data.camera_position, forwards_movement) # looking if keys[py.K_LEFT]: global_data.yaw += global_data.camera_movement_speed * fps_mod / 4 if keys[py.K_RIGHT]: global_data.yaw -= global_data.camera_movement_speed * fps_mod / 4 renderer.pygame_tick() renderer.draw_mesh(global_data.cube.triangles) global_data.tick += 1 global_data.fps = round(1 / (time.time() - start_time), 1) if global_data.tick % 10 == 0: py.display.set_caption(f'FPS: {global_data.fps}')
def point_at(pos: Vector3, target: Vector3, up: Vector3): # Calculate new forward direction new_forward = vector.subtract(target, pos) new_forward.normalise() # Calculate new Up direction a: Vector3 = vector.multiply(new_forward, vector.dot_product(up, new_forward)) new_up: Vector3 = vector.subtract(up, a) new_up.normalise() # New Right direction is easy, its just cross product new_right: vector.Vector3 = vector.cross_product(new_up, new_forward) # Construct Dimensioning and Translation Matrix matrix = Matrix4() matrix.m[0][0] = new_right.x; matrix.m[0][1] = new_right.y; matrix.m[0][2] = new_right.z; matrix.m[0][3] = 0 matrix.m[1][0] = new_up.x; matrix.m[1][1] = new_up.y; matrix.m[1][2] = new_up.z; matrix.m[1][3] = 0 matrix.m[2][0] = new_forward.x; matrix.m[2][1] = new_forward.y; matrix.m[2][2] = new_forward.z; matrix.m[2][3] = 0 matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1 return matrix
def _makeJointDirections(): """Generate a lookup table for the backtracking head. It contains lists of all possible new directions at a joint element. When the backtracking head encounters a joint element, it can lookup possible new directions in this dict. With our snake cube we only have one interesting kind of joint element (the 90 degree joint), thus one lookup table suffices. Returns: dict: The generated lookup table. key = The current direction. value = The list of all possible new directions for a given key. """ # number of base directions (base vectors and their inverse) in a 3D plane N_PLANE_BASEDIR = 4 # number of base vectors in 3D space N_BASEVEC = 3 mapVtoRM = dict() mapVtoRM[str(Vector3D(1,0,0))] = rotx mapVtoRM[str(Vector3D(0,1,0))] = roty mapVtoRM[str(Vector3D(0,0,1))] = rotz jointDirections = dict() for i, vector in enumerate(baseVectors): newDirections = [] rotmat = mapVtoRM[str(vector)] # add one other (random) base vector which is perpendicular ... newDirections.append(baseVectors[(i+1)%N_BASEVEC]) # ... and include all other base directions in that plane (+/-) for j in range(N_PLANE_BASEDIR): newDirections.append(multiply(rotmat, newDirections[-1])) jointDirections[str(vector)] = newDirections jointDirections[str(-1*vector)] = newDirections return jointDirections
def __init__(self, pos, velocity, radius): self.pos = pos self.velocity = velocity self.size = vector.multiply((radius, radius), 2)
def _map_coord_to_screen(self, coord): return vector.add(vector.multiply(coord, self._get_resize_ratio()), self._get_resize_offset())
def get_bbox(self): start = vector.add(self.pos, vector.multiply(self.size, -0.5)) end = vector.add(self.pos, vector.multiply(self.size, 0.5)) return start + end
def get_average_position(self): position_sum = reduce(lambda x, y: vector.add(x, y), [vector.multiply(blob.get_position(), blob.get_weight()) for blob in self.blobs]) return vector.divide(position_sum, sum([blob.get_weight() for blob in self.blobs]))
def __init__(self, x, y, radius): self.pos = (x, y) self.size = vector.multiply((radius, radius), 2)
def __set_resize_offset(self): screen_center = vector.divide(self.screen.get_size(), 2) scale_position = vector.multiply( self.center_blob_family.get_largest_blob().get_position(), self._get_resize_ratio()) self.resize_offset = vector.substract(screen_center, scale_position)
if __name__ == "__main__": try: list1 = random.sample(range(-10, 20), 4) list2 = random.sample(range(-10, 20), 4) text = '\n\t First: {}\n\tSecond: {}\n' print('Values:' + text.format(list1, list2)) vect1 = vector.create(*list1) vect2 = vector.create(*list2) print('Vectors:' + text.format(vect1, vect2)) print('is_vector:\n') print(' Values:' + text.format(vector.is_vector(list1), vector.is_vector(list2))) print(' Vectors:' + text.format(vector.is_vector(vect1), vector.is_vector(vect2))) print('Length:' + text.format(vector.length(vect1), vector.length(vect2))) a = random.randrange(-15, 30) b = round(random.uniform(-15, 30), 4) print('Multiplication:' + '\n\tFirst and {}: {}\n\tSecond and {}: {}\n'.format( a, vector.multiply(vect1, a), b, vector.multiply(vect2, b))) print('Scalar multiplication:', round(vector.scalar_product(vect1, vect2), 4)) print('\nAngle:', vector.angle_between(vect1, vect2)) except Exception as err: print('Error occured during execution:', err) print('Type:', type(err))
def test_multiply_vector(self): result = vector.multiply((10, 20), 4) self.assertEqual(result, (40, 80))
def draw_entity(entity): animation = vector.add_scalar(vector.multiply(entity.animation, UNIT), PADDING) position = animation + vector.subtract_scalar(UNIT, PADDING * 2) pygame.draw.rect(surface, entity.color, position)
def main(): """Demonstrate usage of the Backtrack class with an example chain.""" logger.debug('jointDirections:') for key in jointDirections: logger.debug("\t%s: %s", key, jointDirections[key]) # Unique (except for start/end orientation) representation of the chain. # Every element is assigned a number, based on the number and configuration # of its joints. # 0 = element with only one joint (start/end of the chain) # 1 = element with two joints on opposite sides (straight joint element) # 2 = element with two joints on adjacent sides (90 degree joint element) chain_elements = [0, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 0] # Unique (except for start/end orientation) representation of the chain. # Every slice is assigned a number, based on its length. All slices are # assumed to be connected by the same type of joint: a 90 degree dual-joint # element. Every 90 degree dual-joint element is part of two slices. # 1 = slice with 2 elements (backtracking head can be incremented by 1). # 2 = slice with 3 elements (backtracking head can be incremented by 2). chain_slices = [2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2] # Use a 3x3x3 cube. cubesize = 3 # # Backtracking # # These are all the interesting starting points and directions. btheads = [ BacktrackHead(Vector3D(0, 0, 0), Vector3D(1, 0, 0)), BacktrackHead(Vector3D(1, 0, 0), Vector3D(1, 0, 0)), BacktrackHead(Vector3D(1, 0, 0), Vector3D(0, 1, 0)), BacktrackHead(Vector3D(1, 1, 0), Vector3D(1, 0, 0)), BacktrackHead(Vector3D(1, 1, 0), Vector3D(0, 0, 1)), BacktrackHead(Vector3D(1, 1, 1), Vector3D(1, 0, 0)), ] all_solutions = [] for bthead in btheads: backtrack = Backtrack(chain_slices, cubesize, bthead) print(f'>> start backtracking with starting point {bthead}') solutions = backtrack.solve() # print solutions print('==== solutions ====') for i, path in enumerate(solutions): all_solutions.append(path) path_bases = list(map(lambda x: x.base.to_list(), path)) path_directions = list(map(lambda x: x.direction.to_list(), path)) print(f'solution {i} (as base points): {path_bases}') #print(f'solution {i} (as directions): {path_directions}') if len(solutions) == 0: print('no solutions') print() # Demonstrate that the only two solutions found are similar. path0points = list(map(lambda x: x.base.to_list(), all_solutions[0])) path1points = list(map(lambda x: x.base.to_list(), all_solutions[1])) f = lambda x: multiply(rotz, multiply(rotz, multiply(rotx, multiply(mirror_yz, x)))).to_list() if path1points == list(map(f, path0points)): print('The two solutions are similar! Just mirror one solution at the ' 'yz-plane, rotate 90 degree about the x axis and 180 degree ' 'about the z axis, and you got the other solution.')
def test_multiply_vector(self): result = vector.multiply((10,20),4) self.assertEqual(result, (40,80))
def get_together(self, center): difference = vector.substract(center, self.position) self.add_force(vector.multiply(difference, BLOB_GRAVITATION))