indexing description: "Brick Breaker Balls" date: "$Date$" revision: "$Revision$" class BB_BALL inherit BB_OBJECT undefine make_from_other end DOUBLE_MATH export {NONE} all end MATH_CONST export {ANY} all end create make, make_from_vector, make_on_bar, make_from_other feature -- Initialization make (a_x, a_y: DOUBLE; a_level: like level) is -- create a ball at (`a_x', `a_y') as top left corner require a_level_not_void: a_level /= Void do load_image ("./images/ball.gif") create center.make (a_x + half_width, a_y + half_height) initialize level := a_level last_collision := 0 number_of_successive_hits := 0 object_type := Object_type_ball set_stopped (True) set_first_collision_time (1.0) -- set ball speed according to selected game difficulty create speed_array.make (1, 3) inspect level.difficulty when Difficulty_foolproof then speed_array.put (speed_low_foolproof, Low_speed) speed_array.put (speed_normal_foolproof, Normal_speed) speed_array.put (speed_high_foolproof, High_speed) when Difficulty_easy then speed_array.put (speed_low_easy, Low_speed) speed_array.put (speed_normal_easy, Normal_speed) speed_array.put (speed_high_easy, High_speed) when Difficulty_normal then speed_array.put (speed_low_normal, Low_speed) speed_array.put (speed_normal_normal, Normal_speed) speed_array.put (speed_high_normal, High_speed) when Difficulty_hard then speed_array.put (speed_low_hard, Low_speed) speed_array.put (speed_normal_hard, Normal_speed) speed_array.put (speed_high_hard, High_speed) when Difficulty_insane then speed_array.put (speed_low_insane, Low_speed) speed_array.put (speed_normal_insane, Normal_speed) speed_array.put (speed_high_insane, High_speed) else speed_array.put (speed_low_normal, Low_speed) speed_array.put (speed_normal_normal, Normal_speed) speed_array.put (speed_high_normal, High_speed) end speed := speed_array.item (Normal_speed) set_movement_angle (Pi / 2) level.collision_detector.add (Current, object_type) level.balls.force_last (Current) is_transparent := False is_fast := False is_slow := False end make_from_vector (position: EM_VECTOR_2D; a_level: like level) is -- create a ball at `position' require a_level_not_void: a_level /= Void do make (position.x, position.y, a_level) end make_on_bar (a_bar: BB_BAR) is -- create a ball on `a_bar' require a_bar_not_void: a_bar /= Void do load_image ("./images/ball.gif") make(a_bar.center.x - half_width, a_bar.border_top - height - 0.0001, a_bar.level) a_bar.balls_on_bar.force_last (Current) end make_from_other (other: like Current) is -- create another ball and copy some fields do make (other.border_left, other.border_top, other.level) set_stopped (other.is_stopped) speed := other.speed create movement.make_from_other (other.movement) is_transparent := other.is_transparent is_fast := other.is_fast is_slow := other.is_slow if is_transparent then set_transparent end if level.bars.first.balls_on_bar.has (other) then level.bars.first.balls_on_bar.force_last (Current) end end feature -- Status report movement: EM_VECTOR_2D -- current movement last_collision: INTEGER -- time of last collision movement_angle: DOUBLE is -- angle between positive x-axis and `movement', counterclock wise do Result := arc_cosine (movement.x / speed) if movement.y > 0 then Result := 2 * Pi - Result end end is_stopped: BOOLEAN -- is the ball stopped? first_collision_time: DOUBLE -- time of very first collision this frame of `Current' -- 0 <= `first_collision_time' <= 1, is set to 1 while moving number_of_successive_hits: INTEGER -- number of block hits since last bar hit is_transparent: BOOLEAN -- is `Current' transparent? is_fast: BOOLEAN -- is `Current' fast? is_slow: BOOLEAN -- is `Current' slow? feature -- Status setting set_movement (a_vector: EM_VECTOR_2D) is -- set movement require a_vector_not_void: a_vector /= Void do movement := a_vector ensure movement_set: movement = a_vector end set_last_collision (a_time: INTEGER) is -- set `last_collision' do last_collision := a_time ensure last_collision_set: last_collision = a_time end set_movement_angle (an_angle: DOUBLE) is -- set `movement_angle' and speed require angle_in_bound: (an_angle >= Minimum_angle and an_angle <= Pi - Minimum_angle) or (an_angle >= Pi + Minimum_angle and an_angle <= 2 * Pi - Minimum_angle) do create movement.make (0.0, 0.0) movement.set_y (- sine (an_angle) * speed) movement.set_x (cosine (an_angle) * speed) end set_stopped (a_boolean: BOOLEAN) is -- set `is_stooped' do is_stopped := a_boolean ensure is_stopped_set: is_stopped = a_boolean end set_first_collision_time (a_double: DOUBLE) is -- sets `first_collision_time' require a_double_in_bounds: 0.0 <= a_double and a_double <= 1.0 do first_collision_time := a_double ensure first_collision_time_set: a_double = first_collision_time end set_number_of_successive_hits (an_integer: INTEGER) is -- sets `number_of_successive_hits' require an_integer_not_negative: an_integer >= 0 do number_of_successive_hits := an_integer ensure value_set: number_of_successive_hits = an_integer end set_transparent is -- make `Current' transparent do load_image ("images/ball_transparent.jpg") image.set_transparent_color (0, 255, 0) is_transparent := True ensure is_transparent: is_transparent end set_opaque is -- make `Current' opaque do load_image ("images/ball.gif") is_transparent := False ensure is_opaque: not is_transparent end set_fast is -- make `Current' fast do speed := speed_array.item (High_speed) movement.scale_to (speed) is_fast := True is_slow := False ensure is_fast: is_fast and not is_slow speed_set: speed = speed_array.item (High_speed) end set_slow is -- make `Current' slow do speed := speed_array.item (Low_speed) movement.scale_to (speed) is_fast := False is_slow := True ensure is_fast: not is_fast and is_slow speed_set: speed = speed_array.item (Low_speed) end set_normal_speed is -- make `Current's speed normal do speed := speed_array.item (Normal_speed) movement.scale_to (speed) is_fast := False is_slow := False ensure is_fast: not is_fast and not is_slow speed_set: speed = speed_array.item (Normal_speed) end feature -- Element change move (delay: INTEGER) is -- move `Current' do if not is_stopped then move_by (movement.x / 1000 * delay, movement.y / 1000 * delay) else move_by (0.0, 0.0) end -- reset `first_collision_time' set_first_collision_time (1.0) ensure -- moved: not is_stopped implies (center.x = old center.x + movement.x / 1000 * delay) and (center.y = old center.y + movement.y / 1000 * delay) end rotate_movement (rotation_angle: DOUBLE) is -- rotate `movement' by `angle' counterclockwise and ensure that it's in angle bounds local move_angle: DOUBLE do movement.rotate (rotation_angle) -- ensure angle bounds move_angle := movement_angle if move_angle < Minimum_angle then set_movement_angle (Minimum_angle) elseif move_angle <= Pi and move_angle > Pi - Minimum_angle then set_movement_angle (Pi - Minimum_angle) elseif move_angle > Pi and move_angle < Pi + Minimum_angle then set_movement_angle (Pi + Minimum_angle) elseif move_angle > 2 * Pi - Minimum_angle then set_movement_angle (2 * Pi - Minimum_angle) end end feature {BB_BALL} -- Impelementation speed_array : ARRAY [DOUBLE] -- current low, normal and high speed speed: DOUBLE -- current speed speed_normal_foolproof: DOUBLE is 150.0 speed_low_foolproof: DOUBLE is 75.0 speed_high_foolproof: DOUBLE is 200.0 speed_normal_easy: DOUBLE is 225.0 speed_low_easy: DOUBLE is 112.5 speed_high_easy: DOUBLE is 300.0 speed_normal_normal: DOUBLE is 300.0 speed_low_normal: DOUBLE is 150.0 speed_high_normal: DOUBLE is 400.0 speed_normal_hard: DOUBLE is 300.0 speed_low_hard: DOUBLE is 150.0 speed_high_hard: DOUBLE is 400.0 speed_normal_insane: DOUBLE is 300.0 speed_low_insane: DOUBLE is 150.0 speed_high_insane: DOUBLE is 400.0 invariant movement_not_void: movement /= Void end