indexing description: "[ The main physics engine and the core of EM_GOOF. Processes and draws all EM_GOOF_OBJECT and processes all EM_GOOF_FORCE. Coordinates with EM_COLLISION_DETECTOR. Use 'get_registered_object' and 'get_registered_forces' to get named objects loaded from xml file. You can add this to every scene as it is an EM_DRAWABLE. ]" date: "$Date$" revision: "$Revision$" class EM_GOOF_PHYSICS inherit EM_DRAWABLE redefine draw end EM_SHARED_BITMAP_FACTORY export {NONE} all undefine default_create end create make feature -- Initialization make(a_background_file: STRING a_level_size,a_level_position,a_screen_size,a_screen_position: EM_VECTOR_2D a_speed: DOUBLE collision_set_no: INTEGER movement_check: INTEGER) is -- Make physics require a_level_size_not_void: a_level_size /= void a_level_position_not_void: a_level_position /= void a_screen_size_not_void: a_screen_size /= void a_screen_position_not_void: a_screen_position /= void a_background_file_not_void: a_background_file /= void collision_set_no_positive: collision_set_no > 0 movement_check_non_negative: movement_check >= 0 local string_equality_tester: UC_STRING_EQUALITY_TESTER do bitmap_factory.create_bitmap_from_image(a_background_file) check bitmap_factory.last_bitmap /= void end background := bitmap_factory.last_bitmap speed := a_speed screen_size := a_screen_size screen_position := a_screen_position internal_size := a_level_size internal_position := a_level_position background.set_x_y(screen_position.x.rounded, screen_position.y.rounded) set_x_y(screen_position.x.rounded, screen_position.y.rounded) create objects.make create objects_deletor.make(128) create forces.make create forces_deletor.make(32) create string_equality_tester create registered_objects.make_with_equality_testers (128, void, string_equality_tester) create registered_forces.make_with_equality_testers (32, void, string_equality_tester) create collision_detector.make(collision_set_no) collision_detector.set_movement_check(movement_check) end feature -- Load add_object(a_object: EM_GOOF_OBJECT) is -- Add this object (used by loader) require a_object_not_void: a_object /= void do objects.put_last(a_object) ensure object_added: objects.has(a_object) end add_force(a_force: EM_GOOF_FORCE) is -- Add this object (used by loader) require a_force_not_void: a_force /= void do forces.put_last(a_force) ensure force_added: forces.has(a_force) end remove_object(a_object: EM_GOOF_OBJECT) is -- Add this object (used by loader) require a_object_not_void: a_object /= void do objects_deletor.put(a_object) end remove_force(a_force: EM_GOOF_FORCE) is -- Add this object (used by loader) require a_force_not_void: a_force /= void do forces_deletor.put(a_force) end register_object(name: STRING object: EM_GOOF_OBJECT) is -- Register 'object' with 'name' require name_not_void: name /= void object_not_void: object /= void do registered_objects.put_new(object, name) ensure registered: registered_objects.has(name) end register_force(name: STRING force: EM_GOOF_FORCE) is -- Register 'force' with 'name' require name_not_void: name /= void force_not_void: force /= void do registered_forces.put_new(force, name) ensure registered: registered_forces.has(name) end unregister_object(name: STRING) is -- Register 'object' with 'name' require name_not_void: name /= void do registered_objects.remove(name) ensure unregistered: not registered_objects.has(name) end unregister_force(name: STRING) is -- Register 'force' with 'name' require name_not_void: name /= void do registered_forces.remove(name) ensure unregistered: not registered_forces.has(name) end feature -- Access get_registered_object(name: STRING): EM_GOOF_OBJECT is -- Get a registered object require name_not_void: name /= void do Result := registered_objects.item(name) ensure result_not_void: result /= void end get_registered_force(name: STRING): EM_GOOF_FORCE is -- Get a registered force require name_not_void: name /= void do Result := registered_forces.item(name) ensure result_not_void: result /= void end feature {EM_GOOF_LOADER_NODE_PROCESSOR, EM_GOOF_LEVEL_SCENE, EM_GOOF_OBJECT} -- Properties collision_detector: EM_COLLISION_DETECTOR [EM_COLLIDABLE] -- Detects collisions feature {EM_GOOF_LEVEL_SCENE} -- Properties speed: DOUBLE -- How fast do things happen? set_speed(a_speed: DOUBLE) is -- Set 'speed' do speed := a_speed ensure speed_set: speed = a_speed end feature {NONE} -- Properties registered_objects: DS_HASH_TABLE[EM_GOOF_OBJECT,STRING] -- Registered objects for access registered_forces: DS_HASH_TABLE[EM_GOOF_FORCE,STRING] -- Registered forces for access objects: DS_LINKED_LIST[EM_GOOF_OBJECT] -- All objects in the physics objects_deletor: ARRAYED_STACK[EM_GOOF_OBJECT] -- Added objects will be deleted forces: DS_LINKED_LIST[EM_GOOF_FORCE] -- All forces in the physics¨ forces_deletor: ARRAYED_STACK[EM_GOOF_FORCE] -- Added forces will be deleted screen_position: EM_VECTOR_2D -- Start position of the physics on screen screen_size: EM_VECTOR_2D -- Size of physics/level on screen internal_position: EM_VECTOR_2D -- Internal position (screen in level) internal_size: EM_VECTOR_2D -- Internal physics/level size height: INTEGER is -- Output for screen_size (deferred in ancestor) do Result := screen_size.y.rounded end width: INTEGER is -- Output for screen_size (deferred in ancestor) do Result := screen_size.x.rounded end background: EM_BITMAP -- Background feature -- Operate move_camera(by_x,by_y: DOUBLE) is -- Move the camera (internal_position) -- No strict precondition but disallowed -- values will do nothing do internal_position.set_x((internal_position.x+by_x).max(0).min(internal_size.x-screen_size.x)) internal_position.set_y((internal_position.y+by_y).max(0).min(internal_size.y-screen_size.y)) end feature -- Processing process(time_length: DOUBLE) is -- Process all physics local object_cursor: DS_LINKED_LIST_CURSOR[EM_GOOF_OBJECT] force_cursor: DS_LINKED_LIST_CURSOR[EM_GOOF_FORCE] collision_cursor: DS_LINKED_LIST_CURSOR[EM_COLLISION_COMPOSITION [EM_COLLIDABLE]] collision_cursor_2: DS_LINKED_LIST_CURSOR[EM_COLLISION [EM_COLLIDABLE]] collidable_object: EM_GOOF_COLLIDABLE speeded_time_length: DOUBLE do speeded_time_length := time_length * speed collision_detector.check_for_collision from collision_cursor := collision_detector.last_collisions.new_cursor collision_cursor.start until collision_cursor.after loop from collision_cursor_2 := collision_cursor.item.new_cursor collision_cursor_2.start until collision_cursor_2.after loop collidable_object ?= collision_cursor_2.item.collidables.first.holder if collidable_object /= void then collidable_object.collide(collision_cursor_2.item) end collidable_object ?= collision_cursor_2.item.collidables.second.holder if collidable_object /= void then collidable_object.collide(collision_cursor_2.item) end collision_cursor_2.forth end collision_cursor.forth end from force_cursor := forces.new_cursor force_cursor.start until force_cursor.after loop force_cursor.item.process(objects) force_cursor.forth end from object_cursor := objects.new_cursor object_cursor.start until object_cursor.after loop object_cursor.item.process(speeded_time_length) object_cursor.forth end from until objects_deletor.is_empty loop objects.delete(objects_deletor.item) objects_deletor.remove end from until forces_deletor.is_empty loop forces.delete(forces_deletor.item) forces_deletor.remove end end feature -- Drawing draw(screen: EM_VIDEO_SURFACE) is -- Draw physic objects local cursor: DS_LINKED_LIST_CURSOR[EM_GOOF_OBJECT] do screen.draw_bitmap(background) from cursor := objects.new_cursor cursor.start until cursor.after loop if cursor.item.position.x > internal_position.x and cursor.item.position.x < internal_position.x + screen_size.x and cursor.item.position.y > internal_position.y and cursor.item.position.y < internal_position.y + screen_size.y then cursor.item.draw(screen, screen_position - internal_position, 0) end cursor.forth end end invariant internal_size_not_void: internal_size /= void internal_position_not_void: internal_position /= void screen_size_not_void: screen_size /= void screen_position_not_void: screen_position /= void level_large_enough: internal_size.x >= screen_size.x and internal_size.x >= screen_size.x level_position_positive: internal_position.x >= 0 and internal_position.y >= 0 level_position_alllowed: internal_position.x <= internal_size.x - screen_size.x and internal_position.y <= internal_size.y - screen_size.y forces_not_void: forces /= void objects_not_void: objects /= void objects_deletor_not_void: objects_deletor /= void forces_deletor_not_void: forces_deletor /= void registered_objects_not_void: registered_objects /= void registered_forces_not_void: registered_forces /= void end