added destructible blocks and fixed flippers

This commit is contained in:
Alexandre 2024-12-21 16:21:28 +01:00
parent 7847ab0e17
commit e413fcdff2
6 changed files with 147 additions and 34 deletions

3
execution.sh Normal file
View File

@ -0,0 +1,3 @@
ocamlfind ocamlopt -linkpkg -package unix -linkpkg -package graphics -thread -package threads -linkpkg main.ml -o pinball
gcc playsound.c -lSDL2 -lSDL2_image -o sound
./pinball

BIN
main.cmi

Binary file not shown.

BIN
main.cmx

Binary file not shown.

178
main.ml
View File

@ -33,6 +33,8 @@ type polygon = {
ymax : float ; ymax : float ;
mutable restitution : float ; mutable restitution : float ;
score : int ; score : int ;
mutable max_hp : int ;
mutable hp : int ;
} ;; } ;;
type sphere = { type sphere = {
@ -82,6 +84,8 @@ let default_polygon = {
ymax = -. 1. ; ymax = -. 1. ;
restitution = 0. ; restitution = 0. ;
score = 0 ; score = 0 ;
max_hp = 1;
hp = 1 ;
} ;; } ;;
let default_sphere = { let default_sphere = {
@ -254,6 +258,21 @@ let dyn_remove (dyn : 'a dynamic) (elt : 'a) =
dyn.memlen <- dyn.memlen/2 ; dyn.memlen <- dyn.memlen/2 ;
end ;; end ;;
let dyn_remove_id (dyn : 'a dynamic) (id : int) =
assert (id >= 0 && id < dyn.len) ;
let temp = dyn.tab.(dyn.len -1) in
dyn.tab.(dyn.len -1) <- dyn.tab.(id) ;
dyn.tab.(id) <- temp ;
dyn.len <- dyn.len - 1;
if (dyn.memlen >= 32) && (dyn.len * 4 <= dyn.memlen) then begin
let _new = Array.make (dyn.memlen/2) dyn.tab.(0) in
for i = 0 to dyn.len -1 do
_new.(i) <- dyn.tab.(i)
done;
dyn.tab <- _new ;
dyn.memlen <- dyn.memlen/2 ;
end ;;
let dyn_fold_left (f : 'b -> 'a -> 'b) (acc0 : 'b) (dyn : 'a dynamic) = let dyn_fold_left (f : 'b -> 'a -> 'b) (acc0 : 'b) (dyn : 'a dynamic) =
let acc = ref acc0 in let acc = ref acc0 in
for i = 0 to dyn.len -1 do for i = 0 to dyn.len -1 do
@ -398,38 +417,48 @@ let is_collision_s (b : ball) (s : sphere) (dt : float) =
else else
vect_dist_2D (step_one_ball b dt) (s.center) <= (s.radius +. b.radius) ;; 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) (flips : flipper dynamic) (dt : float) = let remove_dead_destr (destr : polygon dynamic) (cand : int list) =
let rec aux = function
| [] -> ()
| h::t ->
dyn_remove_id destr h ;
aux t
in aux cand ;;
let update_ball_data (b : ball) (polys : polygon dynamic) (destr : polygon dynamic) (spheres : sphere dynamic) (flips : flipper dynamic) (dt : float) =
b.fres.x <- 0. ; b.fres.x <- 0. ;
b.fres.y <- 0. ; b.fres.y <- 0. ;
for p = 0 to (Array.length polys -1) do let destr_remove = ref [] in
let (hitarr, hitlen) = (is_collision_p b polys.(p) dt) in
for p = 0 to polys.len -1 do
let (hitarr, hitlen) = (is_collision_p b polys.tab.(p) dt) in
if hitlen > 0 then begin if hitlen > 0 then begin
for h = 0 to hitlen -1 do for h = 0 to hitlen -1 do
let hit = hitarr.(h) in let hit = hitarr.(h) in
score := !score + polys.(p).score ; score := !score + polys.tab.(p).score ;
if h = 0 && polys.(p).score > 0 then if h = 0 && polys.tab.(p).score > 0 then
playbeep () ; playbeep () ;
if polys.(p).restitution = 0. then begin if polys.tab.(p).restitution = 0. then begin
b.active <- false ; b.active <- false ;
decr remaining ; decr remaining ;
end; end;
(* apply normal reaction force *) (* apply normal reaction force *)
let hit2 = (hit +1) mod (Array.length polys.(p).vertexes) in let hit2 = (hit +1) mod (Array.length polys.tab.(p).vertexes) in
let proj = return_proj_of_point b.xy polys.(p).vertexes.(hit) polys.(p).vertexes.(hit2) in let proj = return_proj_of_point b.xy polys.tab.(p).vertexes.(hit) polys.tab.(p).vertexes.(hit2) in
let proj_n = vect_normalize_2D (vect_diff_2D b.xy proj) 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 let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in
if scal > 0. then begin if scal > 0. then begin
let reaction_force_2 = vect_mult_2D proj_n (univ_g *. b.mass *. scal) in 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.x <- b.fres.x +. reaction_force_2.x *. polys.tab.(p).restitution /. float_of_int hitlen ;
b.fres.y <- b.fres.y +. reaction_force_2.y *. polys.(p).restitution /. float_of_int hitlen ; b.fres.y <- b.fres.y +. reaction_force_2.y *. polys.tab.(p).restitution /. float_of_int hitlen ;
end; end;
(* change velocity according to angle *) (* change velocity according to angle *)
if hitlen = 1 then begin if hitlen = 1 then begin
let director = vect_diff_2D polys.(p).vertexes.(hit2) polys.(p).vertexes.(hit) in let director = vect_diff_2D polys.tab.(p).vertexes.(hit2) polys.tab.(p).vertexes.(hit) in
let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in
b.v.x <- symmetric.x ; b.v.x <- symmetric.x ;
@ -445,29 +474,78 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array)
end end
done ; done ;
for s = 0 to (Array.length spheres -1) do for p = 0 to destr.len -1 do
if is_collision_s b spheres.(s) dt then begin if destr.tab.(p).hp > 0 then begin
score := !score + spheres.(s).score ; let (hitarr, hitlen) = (is_collision_p b destr.tab.(p) dt) in
if hitlen > 0 then begin
for h = 0 to hitlen -1 do
let hit = hitarr.(h) in
score := !score + destr.tab.(p).score ;
destr.tab.(p).hp <- destr.tab.(p).hp -1 ;
if spheres.(s).score > 0 then if h = 0 && destr.tab.(p).score > 0 then
playbeep () ;
if destr.tab.(p).restitution = 0. then begin
b.active <- false ;
decr remaining ;
end;
(* apply normal reaction force *)
let hit2 = (hit +1) mod (Array.length destr.tab.(p).vertexes) in
let proj = return_proj_of_point b.xy destr.tab.(p).vertexes.(hit) destr.tab.(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 *. destr.tab.(p).restitution /. float_of_int hitlen ;
b.fres.y <- b.fres.y +. reaction_force_2.y *. destr.tab.(p).restitution /. float_of_int hitlen ;
end;
(* change velocity according to angle *)
if hitlen = 1 then begin
let director = vect_diff_2D destr.tab.(p).vertexes.(hit2) destr.tab.(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 <- newv.x ;
b.v.y <- newv.y ;
end
done
end
end
else begin
destr_remove := (p)::(!destr_remove) ;
end
done ;
for s = 0 to spheres.len -1 do
if is_collision_s b spheres.tab.(s) dt then begin
score := !score + spheres.tab.(s).score ;
if spheres.tab.(s).score > 0 then
playbeep () ; playbeep () ;
if spheres.(s).restitution = 0. then begin if spheres.tab.(s).restitution = 0. then begin
b.active <- false ; b.active <- false ;
decr remaining ; decr remaining ;
end; end;
(* apply normal reaction force *) (* apply normal reaction force *)
let proj_n = vect_normalize_2D (vect_diff_2D b.xy spheres.(s).center) in let proj_n = vect_normalize_2D (vect_diff_2D b.xy spheres.tab.(s).center) in
let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in let scal = (vect_dot_product_2D (vect_normalize_2D gforce) proj_n) in
if scal > 0. then begin if scal > 0. then begin
let reaction_force_2 = vect_mult_2D proj_n (univ_g *. b.mass *. scal) in 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 *. spheres.(s).restitution *. 1.1 ; b.fres.x <- b.fres.x +. reaction_force_2.x *. spheres.tab.(s).restitution *. 1.1 ;
b.fres.y <- b.fres.y +. reaction_force_2.y *. spheres.(s).restitution *. 1.1 ; b.fres.y <- b.fres.y +. reaction_force_2.y *. spheres.tab.(s).restitution *. 1.1 ;
end; end;
(* change velocity according to angle *) (* change velocity according to angle *)
let theta = b.radius /. (vect_norm_2D (vect_diff_2D b.xy spheres.(s).center)) in let theta = b.radius /. (vect_norm_2D (vect_diff_2D b.xy spheres.tab.(s).center)) in
let intersection = (vect_convexf b.xy spheres.(s).center theta) in let intersection = (vect_convexf b.xy spheres.tab.(s).center theta) in
let director = vect_normal_2D intersection (vect_sum_2D intersection proj_n) in let director = vect_normal_2D intersection (vect_sum_2D intersection proj_n) in
let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in let symmetric = vect_symmetry b.v {x = 0. ; y = 0.} director in
@ -508,10 +586,10 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array)
b.v.y <- newv.y ; b.v.y <- newv.y ;
end; end;
(* add relative velocity [disabled for physical reasons] *) (* add relative velocity *)
if false && ((flips.tab.(f).side = Left && flips.tab.(f).dtheta > 0.) || (flips.tab.(f).side = Right && flips.tab.(f).dtheta < 0.)) then begin if ((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.x <- 0.7 *. b.v.x +. flips.tab.(f).dtheta *. 3.14159 /. 180. *. (vect_dist_2D flips.tab.(f).xy b.xy) *. (cos ((flips.tab.(f).theta +. 90.) *. 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.)); b.v.y <- 0.7 *. b.v.y +. flips.tab.(f).dtheta *. 3.14159 /. 180. *. (vect_dist_2D flips.tab.(f).xy b.xy) *. (sin ((flips.tab.(f).theta +. 90.) *. 3.14159 /. 180.));
end end
done done
end end
@ -528,12 +606,17 @@ let update_ball_data (b : ball) (polys : polygon array) (spheres : sphere array)
b.v.y <- b.v.y +. b.a.y *. dt ; b.v.y <- b.v.y +. b.a.y *. dt ;
b.xy.x <- b.xy.x +. b.v.x *. dt ; b.xy.x <- b.xy.x +. b.v.x *. dt ;
b.xy.y <- b.xy.y +. b.v.y *. dt ;; b.xy.y <- b.xy.y +. b.v.y *. dt ;
let update_balls (bl : ball array) (polys : polygon array) (spheres : sphere array) (flips : flipper dynamic) (dt : float) = if !destr_remove <> [] then begin
remove_dead_destr destr !destr_remove
end ;;
let update_balls (bl : ball array) (polys : polygon dynamic) (destr : polygon dynamic) (spheres : sphere dynamic) (flips : flipper dynamic) (dt : float) =
for b = 0 to Array.length bl -1 do for b = 0 to Array.length bl -1 do
if bl.(b).active then if bl.(b).active then begin
update_ball_data bl.(b) polys spheres flips dt update_ball_data bl.(b) polys destr spheres flips dt ;
end
done ;; done ;;
let update_flippers (flips : flipper dynamic) (dt : float) = let update_flippers (flips : flipper dynamic) (dt : float) =
@ -718,12 +801,12 @@ let control_flippers (flips : flipper dynamic) =
| 'q' -> | 'q' ->
for fl = 0 to flips.len -1 do for fl = 0 to flips.len -1 do
if flips.tab.(fl).side = Left && flips.tab.(fl).dtheta = 0. then if flips.tab.(fl).side = Left && flips.tab.(fl).dtheta = 0. then
flips.tab.(fl).dtheta <- 600. ; flips.tab.(fl).dtheta <- 300. ;
done done
| 'd' -> | 'd' ->
for fl = 0 to flips.len -1 do for fl = 0 to flips.len -1 do
if flips.tab.(fl).side = Right && flips.tab.(fl).dtheta = 0. then if flips.tab.(fl).side = Right && flips.tab.(fl).dtheta = 0. then
flips.tab.(fl).dtheta <- -. 600. ; flips.tab.(fl).dtheta <- -. 300. ;
done done
| _ -> () ;; | _ -> () ;;
@ -749,6 +832,22 @@ let create_polygon (arr : (int * int) array) (rest : float) (pts : int) (red : i
ymax = float_of_int (Array.fold_left (fun acc k -> max acc (snd k)) (-99999) arr) ; ymax = float_of_int (Array.fold_left (fun acc k -> max acc (snd k)) (-99999) arr) ;
restitution = rest ; restitution = rest ;
score = pts ; score = pts ;
max_hp = 1;
hp = 1
} ;;
let create_destructible (arr : (int * int) array) (rest : float) (pts : int) (hitp : int) (red : int) (green : int) (blue : int) =
{
vertexes = Array.init (Array.length arr) (fun k -> {x = float_of_int (fst arr.(k)); y = float_of_int (snd arr.(k))}) ;
rgb = red + 256 * green + 256 * 256 * blue ;
xmin = float_of_int (Array.fold_left (fun acc k -> min acc (fst k)) 99999 arr) ;
xmax = float_of_int (Array.fold_left (fun acc k -> max acc (fst k)) (-99999) arr) ;
ymin = float_of_int (Array.fold_left (fun acc k -> min acc (snd k)) 99999 arr) ;
ymax = float_of_int (Array.fold_left (fun acc k -> max acc (snd k)) (-99999) arr) ;
restitution = rest ;
score = pts ;
max_hp = hitp;
hp = hitp
} ;; } ;;
let create_sphere (x00 : int) (y00 : int) (rd : float) (rest : float) (pts : int) (red : int) (green : int) (blue : int) = let create_sphere (x00 : int) (y00 : int) (rd : float) (rest : float) (pts : int) (red : int) (green : int) (blue : int) =
@ -827,6 +926,8 @@ let customize lvl_name =
ymax = Array.fold_left (fun acc k -> max acc k.y) (-.999999.) newVTX ; ymax = Array.fold_left (fun acc k -> max acc k.y) (-.999999.) newVTX ;
restitution = 1. ; restitution = 1. ;
score = 0 ; score = 0 ;
max_hp = 1;
hp = 1;
} ; } ;
cpoly.len <- 0 ; cpoly.len <- 0 ;
end end
@ -848,7 +949,7 @@ let customize lvl_name =
(* ------------------------------------------------------------------------------------- *) (* ------------------------------------------------------------------------------------- *)
(* WALUIGI_TIME Main *) (* WALUIGI_TIME Main *)
let simulate (data : polygon dynamic) (dats : sphere dynamic) (flips : flipper dynamic) = let simulate (data : polygon dynamic) (destructible : polygon dynamic) (dats : sphere dynamic) (flips : flipper dynamic) =
open_graph __istr__ ; open_graph __istr__ ;
set_window_title "WAH" ; set_window_title "WAH" ;
@ -871,6 +972,9 @@ let simulate (data : polygon dynamic) (dats : sphere dynamic) (flips : flipper d
for d = 0 to data.len -1 do for d = 0 to data.len -1 do
draw_polygon data.tab.(d) draw_polygon data.tab.(d)
done; done;
for d = 0 to destructible.len -1 do
draw_polygon destructible.tab.(d)
done;
for d = 0 to flips.len -1 do for d = 0 to flips.len -1 do
draw_flipper flips.tab.(d) draw_flipper flips.tab.(d)
done; done;
@ -891,13 +995,14 @@ let simulate (data : polygon dynamic) (dats : sphere dynamic) (flips : flipper d
let __end = Unix.gettimeofday () in let __end = Unix.gettimeofday () in
ctime := !ctime +. (__end -. __start) ; ctime := !ctime +. (__end -. __start) ;
update_balls pinballs data.tab dats.tab flips (__end -. __start) ; update_balls pinballs data destructible dats flips (__end -. __start) ;
update_flippers flips (__end -. __start) ; update_flippers flips (__end -. __start) ;
done; done;
close_graph () ;; close_graph () ;;
let polygons = dyn_create default_polygon ;; let polygons = dyn_create default_polygon ;;
let destructible = dyn_create default_polygon ;;
let spheres = dyn_create default_sphere ;; let spheres = dyn_create default_sphere ;;
let flippers = dyn_create default_flipper ;; let flippers = dyn_create default_flipper ;;
@ -973,14 +1078,19 @@ dyn_add spheres (create_sphere 1180 300 20. 1. 7 128 128 128) ;;
(* |-------------------------------------------------------------------------------------------------------| *) (* |-------------------------------------------------------------------------------------------------------| *)
dyn_add destructible (create_destructible [|(500, 200); (700, 200); (700, 400); (500, 400)|] 1. 10 5 255 255 32) ;;
(* |-------------------------------------------------------------------------------------------------------| *)
dyn_add flippers (create_flipper Left 420 125 20. 160. (-. 20.) (-. 20.) 20.) ;; 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.) ;; dyn_add flippers (create_flipper Right 780 125 20. 160. 200. 160. 200.) ;;
(* |-------------------------------------------------------------------------------------------------------| *) (* |-------------------------------------------------------------------------------------------------------| *)
simulate polygons spheres flippers ;; simulate polygons destructible spheres flippers ;;
(* (*
let create_polygon (arr : (int * int) array) (rest : float) (pts : int) (red : int) (green : int) (blue : int) let create_polygon (arr : (int * int) array) (rest : float) (pts : int) (red : int) (green : int) (blue : int)
let create_destructible (arr : (int * int) array) (rest : float) (pts : int) (hitp : int) (red : int) (green : int) (blue : int)
let create_sphere (x00 : int) (y00 : int) (radius : float) (rest : float) (pts : int) red green blue 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) let create_flipper (x0 : int) (y0 : int) (rd : float) (len : float) (theta0 : float) (thmin : float) (thmax : float)
*) *)

BIN
main.o

Binary file not shown.

BIN
pinball

Binary file not shown.