diff --git a/main.cmi b/main.cmi index 1791ce3..7027dde 100644 Binary files a/main.cmi and b/main.cmi differ diff --git a/main.cmx b/main.cmx index 718ac98..bf6be06 100644 Binary files a/main.cmx and b/main.cmx differ diff --git a/main.ml b/main.ml index dcdc8fd..4b17b4c 100644 --- a/main.ml +++ b/main.ml @@ -47,6 +47,19 @@ type sphere = { score : int ; } ;; +type flipper_side = Left | Right ;; +type flipper = { + side : flipper_side ; + xy : pt_2d ; + radius : float ; + length : float ; + mutable theta : float (* in degrees *) ; + mutable dtheta : float ; + agmin : float ; + agmax : float ; + vtxs : polygon +} ;; + type ball = { mutable active : bool ; radius : float ; @@ -83,8 +96,21 @@ let default_sphere = { score = 0 ; } ;; +let default_flipper = { + side = Left ; + xy = {x = 0. ; y = 0.} ; + radius = 0. ; + length = 0. ; + theta = 0. (* in degrees *) ; + dtheta = 0. ; + agmin = 0. ; + agmax = 0. ; + vtxs = default_polygon ; +} ;; + let univ_g = 750.0 ;; let pi = 3.14159265358979343 ;; +let epsilon = (1. /. 131072.) ;; let winBL = { x = 0. ; @@ -103,8 +129,8 @@ let winball = { let gforce = {x = 0. ; y = -. univ_g} ;; +let remaining = ref 8 ;; let score = ref 0 ;; -let epsilon = (1. /. 131072.) ;; (* ------------------------------------------------------------------------------------- *) (* ------------------------------------------------------------------------------------- *) @@ -335,7 +361,6 @@ let distance_infinite_segment (m : pt_2d) (spt : pt_2d) (ept : pt_2d) = vect_dist_2D (vect_convexf spt ept theta) m ;; let is_collision_p (b : ball) (poly : polygon) (dt : float) = - (* returns the 1st point of the closest line that the ball collides with *) if not (is_in_bounding_box_p b poly) then ([||], 0) else begin @@ -373,7 +398,7 @@ let is_collision_s (b : ball) (s : sphere) (dt : float) = else vect_dist_2D (step_one_ball b dt) (s.center) <= (s.radius +. b.radius) ;; -let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) (dt : float) = +let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) (flips : flipper dynamic) (dt : float) = b.fres.x <- 0. ; b.fres.y <- 0. ; @@ -382,39 +407,39 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) if hitlen > 0 then begin for h = 0 to hitlen -1 do let hit = hitarr.(h) in - if hit <> -1 then begin - score := !score + polys.(p).score ; + score := !score + polys.(p).score ; - if h = 0 && polys.(p).score > 0 then - playbeep () ; - if polys.(p).restitution = 0. then - b.active <- false ; + if h = 0 && polys.(p).score > 0 then + playbeep () ; + if polys.(p).restitution = 0. then begin + b.active <- false ; + decr remaining ; + end; - (* apply normal reaction force *) - let hit2 = (hit +1) mod (Array.length polys.(p).vertexes) in - let proj = return_proj_of_point b.xy polys.(p).vertexes.(hit) polys.(p).vertexes.(hit2) in - let proj_n = vect_normalize_2D (vect_diff_2D b.xy proj) in - let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in - if scal > 0. then begin - let reaction_force_2 = vect_mult_2D proj_n (univ_g *. b.mass *. scal) in - b.fres.x <- b.fres.x +. reaction_force_2.x *. polys.(p).restitution /. float_of_int hitlen ; - b.fres.y <- b.fres.y +. reaction_force_2.y *. polys.(p).restitution /. float_of_int hitlen ; - end; + (* apply normal reaction force *) + let hit2 = (hit +1) mod (Array.length polys.(p).vertexes) in + let proj = return_proj_of_point b.xy polys.(p).vertexes.(hit) polys.(p).vertexes.(hit2) in + let proj_n = vect_normalize_2D (vect_diff_2D b.xy proj) in + let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in + if scal > 0. then begin + let reaction_force_2 = vect_mult_2D proj_n (univ_g *. b.mass *. scal) in + b.fres.x <- b.fres.x +. reaction_force_2.x *. polys.(p).restitution /. float_of_int hitlen ; + b.fres.y <- b.fres.y +. reaction_force_2.y *. polys.(p).restitution /. float_of_int hitlen ; + end; - (* change velocity according to angle *) - if hitlen = 1 then begin - let director = vect_diff_2D polys.(p).vertexes.(hit2) polys.(p).vertexes.(hit) in - let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in + (* change velocity according to angle *) + if hitlen = 1 then begin + let director = vect_diff_2D polys.(p).vertexes.(hit2) polys.(p).vertexes.(hit) in + let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in - b.v.x <- symmetric.x ; - b.v.y <- symmetric.y ; - end - else begin - let newv = vect_mult_2D (vect_normalize_2D (vect_diff_2D b.xy proj)) (vect_norm_2D b.v) in + b.v.x <- symmetric.x ; + b.v.y <- symmetric.y ; + end + else begin + let newv = vect_mult_2D (vect_normalize_2D (vect_diff_2D b.xy proj)) (vect_norm_2D b.v) in - b.v.x <- newv.x ; - b.v.y <- newv.y ; - end + b.v.x <- newv.x ; + b.v.y <- newv.y ; end done end @@ -426,8 +451,10 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) if spheres.(s).score > 0 then playbeep () ; - if spheres.(s).restitution = 0. then + if spheres.(s).restitution = 0. then begin b.active <- false ; + decr remaining ; + end; (* apply normal reaction force *) let proj_n = vect_normalize_2D (vect_diff_2D b.xy spheres.(s).center) in @@ -449,6 +476,47 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) end done ; + for f = 0 to flips.len -1 do + let (hitarr, hitlen) = (is_collision_p b flips.tab.(f).vtxs dt) in + if hitlen > 0 then begin + for h = 0 to hitlen -1 do + let hit = hitarr.(h) in + + (* apply normal reaction force *) + let hit2 = (hit +1) mod (Array.length flips.tab.(f).vtxs.vertexes) in + let proj = return_proj_of_point b.xy flips.tab.(f).vtxs.vertexes.(hit) flips.tab.(f).vtxs.vertexes.(hit2) in + let proj_n = vect_normalize_2D (vect_diff_2D b.xy proj) in + let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in + if scal > 0. then begin + let reaction_force_2 = vect_mult_2D proj_n (univ_g *. b.mass *. scal) in + b.fres.x <- b.fres.x +. reaction_force_2.x *. flips.tab.(f).vtxs.restitution /. float_of_int hitlen ; + b.fres.y <- b.fres.y +. reaction_force_2.y *. flips.tab.(f).vtxs.restitution /. float_of_int hitlen ; + end; + + (* change velocity according to angle *) + if hitlen = 1 then begin + let director = vect_diff_2D flips.tab.(f).vtxs.vertexes.(hit2) flips.tab.(f).vtxs.vertexes.(hit) in + let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in + + b.v.x <- symmetric.x ; + b.v.y <- symmetric.y ; + end + else begin + let newv = vect_mult_2D (vect_normalize_2D (vect_diff_2D b.xy proj)) (vect_norm_2D b.v) in + + b.v.x <- newv.x ; + b.v.y <- newv.y ; + end; + + (* add relative velocity [disabled for physical reasons] *) + if false && ((flips.tab.(f).side = Left && flips.tab.(f).dtheta > 0.) || (flips.tab.(f).side = Right && flips.tab.(f).dtheta < 0.)) then begin + b.v.x <- 0.5 *. b.v.x +. flips.tab.(f).dtheta *. 3.14159 /. 180. *. (vect_dist_2D flips.tab.(f).xy b.xy) *. (cos (flips.tab.(f).theta *. 3.14159 /. 180.)); + b.v.y <- 0.5 *. b.v.y +. flips.tab.(f).dtheta *. 3.14159 /. 180. *. (vect_dist_2D flips.tab.(f).xy b.xy) *. (sin (flips.tab.(f).theta *. 3.14159 /. 180.)); + end + done + end + done; + (* P = mg *) b.fres.y <- b.fres.y -. univ_g *. b.mass ; @@ -462,10 +530,67 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array) b.xy.x <- b.xy.x +. b.v.x *. dt ; b.xy.y <- b.xy.y +. b.v.y *. dt ;; -let update_balls (bl : ball array) (polys : polygon array) (spheres : sphere array) (dt : float) = +let update_balls (bl : ball array) (polys : polygon array) (spheres : sphere array) (flips : flipper dynamic) (dt : float) = for b = 0 to Array.length bl -1 do if bl.(b).active then - update_ball_data bl.(b) polys spheres dt + update_ball_data bl.(b) polys spheres flips dt + done ;; + +let update_flippers (flips : flipper dynamic) (dt : float) = + for fl = 0 to flips.len -1 do + if flips.tab.(fl).dtheta <> 0. then begin + let x0 = flips.tab.(fl).xy.x + and y0 = flips.tab.(fl).xy.y + and rd = flips.tab.(fl).radius + and len = flips.tab.(fl).length + and theta0 = flips.tab.(fl).theta in + match flips.tab.(fl).side with + | Left -> + let theta_dt = flips.tab.(fl).theta +. flips.tab.(fl).dtheta *. dt in + if theta_dt > flips.tab.(fl).agmax then + flips.tab.(fl).dtheta <- -.(flips.tab.(fl).dtheta) ; + + if theta_dt < flips.tab.(fl).agmin then + flips.tab.(fl).dtheta <- 0. ; + + flips.tab.(fl).theta <- theta_dt ; + + flips.tab.(fl).vtxs.vertexes.(0) <- { + x = x0 +. len *. (cos (theta0 *. 3.14159 /. 180.)); + y = y0 +. len *. (sin (theta0 *. 3.14159 /. 180.)) + }; + flips.tab.(fl).vtxs.vertexes.(1) <- { + x = x0 +. rd *. (cos ((theta0 +. 90.) *. 3.14159 /. 180.)); + y = y0 +. rd *. (sin ((theta0 +. 90.) *. 3.14159 /. 180.)) + }; + flips.tab.(fl).vtxs.vertexes.(2) <- { + x = x0 +. rd *. (cos ((theta0 -. 90.) *. 3.14159 /. 180.)); + y = y0 +. rd *. (sin ((theta0 -. 90.) *. 3.14159 /. 180.)) + }; + + | Right -> + let theta_dt = flips.tab.(fl).theta +. flips.tab.(fl).dtheta *. dt in + if theta_dt > flips.tab.(fl).agmax then + flips.tab.(fl).dtheta <- 0. ; + + if theta_dt < flips.tab.(fl).agmin then + flips.tab.(fl).dtheta <- -.(flips.tab.(fl).dtheta) ; + + flips.tab.(fl).theta <- theta_dt ; + + flips.tab.(fl).vtxs.vertexes.(0) <- { + x = x0 +. len *. (cos (theta0 *. 3.14159 /. 180.)); + y = y0 +. len *. (sin (theta0 *. 3.14159 /. 180.)) + }; + flips.tab.(fl).vtxs.vertexes.(1) <- { + x = x0 +. rd *. (cos ((theta0 +. 90.) *. 3.14159 /. 180.)); + y = y0 +. rd *. (sin ((theta0 +. 90.) *. 3.14159 /. 180.)) + }; + flips.tab.(fl).vtxs.vertexes.(2) <- { + x = x0 +. rd *. (cos ((theta0 -. 90.) *. 3.14159 /. 180.)); + y = y0 +. rd *. (sin ((theta0 -. 90.) *. 3.14159 /. 180.)) + }; + end done ;; (* ------------------------------------------------------------------------------------- *) @@ -561,6 +686,11 @@ let draw_sphere (s : sphere) = set_color (rgb (s.rgb mod 256) ((s.rgb / 256) mod 256) ((s.rgb / (256*256)) mod 256)) ; fill_circle (int_of_float s.center.x) (int_of_float s.center.y) (int_of_float s.radius) ;; +let draw_flipper (f : flipper) = + set_color (rgb 64 64 64) ; + fill_circle (int_of_float f.xy.x) (int_of_float f.xy.y) (int_of_float f.radius) ; + draw_polygon f.vtxs ;; + let draw_ball (b : ball) = set_color (rgb (b.rgb mod 256) ((b.rgb / 256) mod 256) ((b.rgb / (256*256)) mod 256)) ; fill_circle (int_of_float b.xy.x) (int_of_float b.xy.y) (int_of_float b.radius) ; @@ -583,6 +713,20 @@ let get1char_plus () = else '@' ;; +let control_flippers (flips : flipper dynamic) = + match get1char_plus () with + | 'q' -> + for fl = 0 to flips.len -1 do + if flips.tab.(fl).side = Left && flips.tab.(fl).dtheta = 0. then + flips.tab.(fl).dtheta <- 600. ; + done + | 'd' -> + for fl = 0 to flips.len -1 do + if flips.tab.(fl).side = Right && flips.tab.(fl).dtheta = 0. then + flips.tab.(fl).dtheta <- -. 600. ; + done + | _ -> () ;; + let create_ball (r : float) (x0 : int) (y0 : int) (m : float) (red : int) (green : int) (blue : int) = { active = true ; @@ -621,6 +765,23 @@ let create_sphere (x00 : int) (y00 : int) (rd : float) (rest : float) (pts : int score = pts ; } ;; +let create_flipper (side : flipper_side) (x0 : int) (y0 : int) (rd : float) (len : float) (theta0 : float) (thmin : float) (thmax : float) = + { + side = side ; + xy = {x = float_of_int x0 ; y = float_of_int y0} ; + radius = rd ; + length = len ; + theta = theta0 (* in degrees *) ; + dtheta = 0. ; + agmin = thmin ; + agmax = thmax ; + vtxs = create_polygon [| + (x0 + int_of_float (len *. (cos (theta0 *. 3.14159 /. 180.))) , y0 + int_of_float (len *. (sin (theta0 *. 3.14159 /. 180.)))); + (x0 + int_of_float (rd *. (cos ((theta0 -. 90.) *. 3.14159 /. 180.))), y0 + int_of_float (rd *. (sin ((theta0 -. 90.) *. 3.14159 /. 180.)))); + (x0 + int_of_float (rd *. (cos ((theta0 +. 90.) *. 3.14159 /. 180.))), y0 + int_of_float (rd *. (sin ((theta0 +. 90.) *. 3.14159 /. 180.)))) + |] 1. 0 128 128 128 + } ;; + let generate_pinballs (count : int) (r : float) (x0 : int) (y0 : int) (m : float) (red : int) (green : int) (blue : int) = Array.init count (fun k -> create_ball r x0 y0 m red green blue) ;; @@ -687,11 +848,11 @@ let customize lvl_name = (* ------------------------------------------------------------------------------------- *) (* WALUIGI_TIME Main *) -let simulate (data : polygon dynamic) (dats : sphere dynamic) = +let simulate (data : polygon dynamic) (dats : sphere dynamic) (flips : flipper dynamic) = open_graph __istr__ ; set_window_title "WAH" ; - let pinballs = generate_pinballs 100 10.0 600 800 0.15 255 255 0 in + let pinballs = generate_pinballs 8 10.0 600 800 0.15 255 255 0 in let stime = Unix.gettimeofday () in let ctime = ref (Unix.gettimeofday ()) in @@ -700,12 +861,18 @@ let simulate (data : polygon dynamic) (dats : sphere dynamic) = auto_synchronize false ; clear_graph () ; + set_line_width 4 ; + draw_integer 600 100 !remaining 40 ; + set_line_width 1 ; + for d = 0 to dats.len -1 do + draw_sphere dats.tab.(d) + done; for d = 0 to data.len -1 do draw_polygon data.tab.(d) done; - for d = 0 to dats.len -1 do - draw_sphere dats.tab.(d) + for d = 0 to flips.len -1 do + draw_flipper flips.tab.(d) done; draw_all_balls pinballs ; @@ -717,18 +884,24 @@ let simulate (data : polygon dynamic) (dats : sphere dynamic) = draw_integer 600 770 !score 50 ; auto_synchronize true ; + + control_flippers flips ; + Unix.sleepf univ_dt ; let __end = Unix.gettimeofday () in ctime := !ctime +. (__end -. __start) ; - update_balls pinballs data.tab dats.tab (__end -. __start) ; + update_balls pinballs data.tab dats.tab flips (__end -. __start) ; + update_flippers flips (__end -. __start) ; done; close_graph () ;; let polygons = dyn_create default_polygon ;; let spheres = dyn_create default_sphere ;; +let flippers = dyn_create default_flipper ;; +(* |-------------------------------------------------------------------------------------------------------| *) (* kill platform *) dyn_add polygons (create_polygon [|(700, -20); (500, -20); (500, 1); (700, 1)|] 0. 0 255 32 32) ;; @@ -741,17 +914,75 @@ dyn_add polygons (create_polygon [|(1180, 0); (1200, 0); (1200, 800); (1180, 800 dyn_add polygons (create_polygon [|(0, 0); (20, 0); (20, 800); (0, 800)|] 1. 0 32 32 32) ;; (* side ramps *) -dyn_add polygons (create_polygon [|(20, 20); (20, 300); (500, 150); (500, 20)|] 1. 0 32 32 32) ;; -dyn_add polygons (create_polygon [|(1200, 20); (1200, 300); (700, 150); (700, 20)|] 1. 0 32 32 32) ;; +dyn_add polygons (create_polygon [|(20, 20); (20, 300); (420, 150); (420, 20)|] 1. 0 32 32 32) ;; +dyn_add polygons (create_polygon [|(1200, 20); (1200, 300); (780, 150); (780, 20)|] 1. 0 32 32 32) ;; (* starting platform *) dyn_add polygons (create_polygon [|(600, 700); (400, 550); (800, 550)|] 1. 0 32 32 32) ;; +(* |-------------------------------------------------------------------------------------------------------| *) +(* corner scoring spots *) +dyn_add spheres (create_sphere 20 780 30. 1. 50 128 128 32) ;; +dyn_add spheres (create_sphere 1180 780 30. 1. 50 128 128 32) ;; -simulate polygons spheres ;; +(* under the starting platform *) +dyn_add spheres (create_sphere 440 550 20. 1. 5 32 128 32) ;; +dyn_add spheres (create_sphere 520 550 20. 1. 5 32 192 32) ;; +dyn_add spheres (create_sphere 600 550 20. 1. 5 32 255 32) ;; +dyn_add spheres (create_sphere 680 550 20. 1. 5 32 192 32) ;; +dyn_add spheres (create_sphere 760 550 20. 1. 5 32 128 32) ;; + +dyn_add spheres (create_sphere 480 450 20. 1. 3 32 156 32) ;; +dyn_add spheres (create_sphere 560 450 20. 1. 3 32 220 32) ;; +dyn_add spheres (create_sphere 640 450 20. 1. 3 32 220 32) ;; +dyn_add spheres (create_sphere 720 450 20. 1. 3 32 156 32) ;; + +dyn_add spheres (create_sphere 520 350 20. 1. 1 32 192 32) ;; +dyn_add spheres (create_sphere 600 350 20. 1. 1 32 255 32) ;; +dyn_add spheres (create_sphere 680 350 20. 1. 1 32 192 32) ;; + +(* left side *) +dyn_add spheres (create_sphere 20 480 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 95 555 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 170 630 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 245 705 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 320 780 10. 1. 3 32 32 192) ;; + +dyn_add spheres (create_sphere 20 630 15. 1. 5 32 32 255) ;; +dyn_add spheres (create_sphere 95 705 15. 1. 5 32 32 255) ;; +dyn_add spheres (create_sphere 170 780 15. 1. 5 32 32 255) ;; + +dyn_add spheres (create_sphere 300 300 15. 1. 5 128 128 128) ;; + +(* right side *) +dyn_add spheres (create_sphere 1180 480 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 1105 555 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 1030 630 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 965 705 10. 1. 3 32 32 192) ;; +dyn_add spheres (create_sphere 890 780 10. 1. 3 32 32 192) ;; + +dyn_add spheres (create_sphere 1180 630 15. 1. 5 32 32 255) ;; +dyn_add spheres (create_sphere 1105 705 15. 1. 5 32 32 255) ;; +dyn_add spheres (create_sphere 1030 780 15. 1. 5 32 32 255) ;; + +dyn_add spheres (create_sphere 900 300 15. 1. 5 128 128 128) ;; + +(* on the ramps *) +dyn_add spheres (create_sphere 20 300 20. 1. 7 128 128 128) ;; +dyn_add spheres (create_sphere 1180 300 20. 1. 7 128 128 128) ;; + +(* |-------------------------------------------------------------------------------------------------------| *) + +dyn_add flippers (create_flipper Left 420 125 20. 160. (-. 20.) (-. 20.) 20.) ;; +dyn_add flippers (create_flipper Right 780 125 20. 160. 200. 160. 200.) ;; + +(* |-------------------------------------------------------------------------------------------------------| *) + +simulate polygons spheres flippers ;; (* let create_polygon (arr : (int * int) array) (rest : float) (pts : int) (red : int) (green : int) (blue : int) -let create_sphere (x00 : int) (y00 : int) (radius : float) (rest : float) (pts : int) +let create_sphere (x00 : int) (y00 : int) (radius : float) (rest : float) (pts : int) red green blue +let create_flipper (x0 : int) (y0 : int) (rd : float) (len : float) (theta0 : float) (thmin : float) (thmax : float) *) (* ocamlfind ocamlopt -linkpkg -package unix -linkpkg -package graphics -thread -package threads -linkpkg main.ml *) \ No newline at end of file diff --git a/main.o b/main.o index 7f67e44..9e76cae 100644 Binary files a/main.o and b/main.o differ diff --git a/pinball b/pinball index bb8af94..4930d4d 100755 Binary files a/pinball and b/pinball differ