indexing description: "[ Testsuite for the 2d collision engine of EiffelMedia. Usage: - Drag & Drop with the left mouse button - Rotate collidables with the right mouse button ]" date: "$Date$" revision: "$Revision$" class FIRST_SCENE inherit EM_SCENE redefine handle_mouse_motion_event, handle_mouse_button_down_event, handle_mouse_button_up_event, handle_key_down_event, handle_quit_event, handle_update_event end create make_scene feature -- Initialization initialize_scene is -- local circle1, circle2, circle3, circle4: EM_CIRCLE_COLLIDABLE rect1, rect2, rect3: EM_RECTANGLE_COLLIDABLE poly1, poly2, poly3: EM_POLYGON_CONVEX_COLLIDABLE comp1: EM_COLLIDABLE_COMPOSITION list1, list2, list3: DS_LINKED_LIST [EM_VECTOR_2D] do -- create collidables -- circles create circle1.make_through_three_points (create {EM_VECTOR_2D}.make (0, 0), create {EM_VECTOR_2D}.make (100, 0), create {EM_VECTOR_2D}.make (50, 50)) circle1.move_by (600, 300) circle1.move_by (0, 0) create circle2.make (create {EM_VECTOR_2D}.make (300,100), 100) create circle3.make (create {EM_VECTOR_2D}.make (400,400), 80) create circle4.make (create {EM_VECTOR_2D}.make (250,400), 20) -- rectangles (not rotatable) create rect1.make (create {EM_VECTOR_2D}.make (100, 100), create {EM_VECTOR_2D}.make (280, 280)) create rect2.make (create {EM_VECTOR_2D}.make (650, 300), create {EM_VECTOR_2D}.make (780, 340)) create rect3.make (create {EM_VECTOR_2D}.make (500, 100), create {EM_VECTOR_2D}.make (510, 135)) -- polygons create list1.make list1.force_last (create {EM_VECTOR_2D}.make (180, 370)) list1.force_last (create {EM_VECTOR_2D}.make (280, 350)) list1.force_last (create {EM_VECTOR_2D}.make (190, 300)) create poly1.make_from_absolute_list (create {EM_VECTOR_2D}.make (200, 350), list1) -- if you are unsure where to put the center, EM_POLYGON_CONVEX_COLLIDABLE provides -- the means of finding an approximation of the smalles circumcircle poly1.set_center_only (poly1.circumcircle.first) create list2.make list2.force_last (create {EM_VECTOR_2D}.make (0, -50)) list2.force_last (create {EM_VECTOR_2D}.make (50, 10)) list2.force_last (create {EM_VECTOR_2D}.make (-5, 40)) list2.force_last (create {EM_VECTOR_2D}.make (-50, 25)) list2.force_last (create {EM_VECTOR_2D}.make (-25, -20)) create poly2.make_from_relative_list (create {EM_VECTOR_2D}.make (200, 400), list2) create list3.make list3.force_last (create {EM_VECTOR_2D}.make (0, 0)) list3.force_last (create {EM_VECTOR_2D}.make (0, 100)) list3.force_last (create {EM_VECTOR_2D}.make (100, 100)) list3.force_last (create {EM_VECTOR_2D}.make (100, 0)) create poly3.make_from_absolute_list (create {EM_VECTOR_2D}.make (50, 50), list3) poly3.move_by (600, 450) -- create a composition of poly1, poly2 and circle4 create comp1.make (poly1, create {EM_VECTOR_2D}.make (200, 400)) comp1.add (poly2) comp1.add (circle4) comp1.set_rotatable (True) -- create collision detector with 10 collision groups (the groups are not checked for collisions with -- the other elements of the same group). create collision_detector.make (10) -- add collidables to the detector, all in a different collision group collision_detector.add (circle1, 1) collision_detector.add (circle2, 2) collision_detector.add (circle3, 3) collision_detector.add (rect1, 5) collision_detector.add (rect2, 6) collision_detector.add (rect3, 7) collision_detector.add (poly3, 9) collision_detector.add (comp1, 10) -- if search depth should be enabled, please uncomment the following line -- see the function for more detailt -- collision_detector.set_search_depth (6) -- if movement_check should be enabled, please uncomment the following line -- see the function for more detail -- collision_detector.set_movement_check (3) -- if the circumcircles of the collidables (used for a first collision check) should be -- displayed, please uncomment the following lines -- collision_detector.set_draw_circumcircle (True) -- collision_detector.set_draw_circumcircle_color (create {EM_COLOR}.make_with_rgb (255, 0,0)) update_intersection_output end feature {NONE} -- Implementation redraw is -- Draws the collidables and intersection points on the screen do -- clear screen screen.clear -- draw collidables collision_detector.draw (screen) -- draw collision points draw_collision_points -- draw compositions if dragged /= Void then draw_compositions end -- redraw screen screen.redraw end draw_collision_points is -- draws the collision points (red dots and red lines) local pos: EM_VECTOR_2D dir: EM_DIRECTION_2D circle: EM_CIRCLE cursor1: DS_LINKED_LIST_CURSOR [EM_COLLISION_COMPOSITION [EM_COLLIDABLE]] cursor2: DS_LINKED_LIST_CURSOR [EM_COLLISION [EM_COLLIDABLE]] do -- set color screen.set_line_width (1) screen.set_drawing_color (create {EM_COLOR}.make_with_rgb (255, 0, 0)) create cursor1.make (collision_detector.last_collisions) -- loop through collision compositions from cursor1.start until cursor1.off loop cursor2 := create {DS_LINKED_LIST_CURSOR [EM_COLLISION [EM_COLLIDABLE]]}.make (cursor1.item) -- loop through collisions of a composition from cursor2.start until cursor2.off loop pos := cursor2.item.collision_point if pos /= Void then -- draw collision direction (red line) dir := cursor2.item.collision_direction if dir /= Void then screen.draw_line_segment (create {EM_VECTOR_2D}.make (pos.x - dir.x*intersection_line_length, pos.y - dir.y*intersection_line_length), create {EM_VECTOR_2D}.make (pos.x + dir.x*intersection_line_length, pos.y + dir.y*intersection_line_length)) end -- draw collision point (red small circle) circle := create {EM_CIRCLE}.make (pos, 2) circle.set_filled (True) circle.set_line_color (create {EM_COLOR}.make_with_rgb (255, 0, 0)) circle.set_fill_color (create {EM_COLOR}.make_with_rgb (255, 0, 0)) circle.draw (screen) end cursor2.forth end cursor1.forth end end draw_compositions is -- draws the composition of collidables (green lines between each connection) local cursor1: DS_LINKED_LIST_CURSOR [EM_COLLISION_COMPOSITION [EM_COLLIDABLE]] cursor2, cursor3: DS_LINKED_LIST_CURSOR [EM_COLLIDABLE] base_pos: EM_VECTOR_2D do -- set color screen.set_line_width (1) screen.set_drawing_color (create {EM_COLOR}.make_with_rgb (0, 255, 0)) create cursor1.make (collision_detector.last_collisions) from cursor1.start until cursor1.off loop -- loop through composition cursor2 := create {DS_LINKED_LIST_CURSOR [EM_COLLIDABLE]}.make (cursor1.item.collidables) cursor3 := create {DS_LINKED_LIST_CURSOR [EM_COLLIDABLE]}.make (cursor1.item.collidables) from cursor2.start until cursor2.off loop base_pos := cursor2.item.center -- loop through the rest of the composition from cursor3.copy (cursor2) until cursor3.off loop if cursor3.item /= cursor2.item then screen.draw_line_segment (base_pos, cursor3.item.center) end cursor3.forth end cursor2.forth end cursor1.forth end end feature -- Event handling handle_mouse_button_down_event (a_mouse_event: EM_MOUSEBUTTON_EVENT) is -- Handle Mousebutton events. do if a_mouse_event.is_left_button then -- the left mouse button was pressed -- if the mouse collides with an object, it will be dragged, until released dragged := collision_detector.collides_with_position (create {EM_VECTOR_2D}.make (x.to_double, y.to_double)) if dragged /= Void then dragged.set_draw_color (create {EM_COLOR}.make_with_rgb (80, 130, 190)) end end if a_mouse_event.is_right_button then -- right mouse button was pressed, rotate the collidable rotator := collision_detector.collides_with_position (create {EM_VECTOR_2D}.make (x.to_double, y.to_double)) end end handle_mouse_button_up_event (a_mouse_event: EM_MOUSEBUTTON_EVENT) is -- Handle Mousebutton events. do if a_mouse_event.is_left_button then dragged := Void elseif a_mouse_event.is_right_button then rotator := Void end ensure then reset_correct: a_mouse_event.is_left_button implies dragged = Void reset_correct: a_mouse_event.is_right_button implies rotator = Void end handle_mouse_motion_event (a_mouse_event: EM_MOUSEMOTION_EVENT) is -- Handle Mousemotion events. local a_collidable: EM_COLLIDABLE do if dragged /= Void then -- a collidable is currently being dragged dragged.move_by (a_mouse_event.x - x, a_mouse_event.y - y) else -- nothing is beeing dragged. highlight the one moved over with the mouse a_collidable := collision_detector.collides_with_position (create {EM_VECTOR_2D}.make (a_mouse_event.x.to_double, a_mouse_event.y.to_double)) collision_detector.set_draw_color (create {EM_COLOR}.make_white) if a_collidable /= Void then -- the mouse is moved over a collidable, set color to blueish-green a_collidable.set_draw_color (create {EM_COLOR}.make_with_rgb (94, 158, 217)) end end x := a_mouse_event.x y := a_mouse_event.y update_intersection_output ensure then x = a_mouse_event.x y = a_mouse_event.y end handle_key_down_event (a_keyboard_event: EM_KEYBOARD_EVENT) is -- Handle keyboard events. do if a_keyboard_event.key = a_keyboard_event.sdlk_escape then event_loop.stop end end handle_quit_event (a_quit_event: EM_QUIT_EVENT) is -- Handle quit events. do event_loop.stop end handle_update_event is -- Handle the outside event. do if rotator /= Void then rotator.rotate_by_around_center (0.1, create {EM_VECTOR_2D}.make (x, y)) end end feature {NONE} -- Implementation collision_detector: EM_COLLISION_DETECTOR [EM_COLLIDABLE] -- Collision Detector update_intersection_output is -- updates intersection output do collision_detector.check_for_collision end x, y: INTEGER -- positions of the mouse dragged: EM_COLLIDABLE -- a collidable, that is currently dragged rotator: EM_COLLIDABLE -- The mouse is currently over this collidable intersection_line_length: DOUBLE is 60.0 end