diff --git a/assets/tables/table3.json b/assets/tables/table3.json new file mode 100644 index 00000000..24a3c897 --- /dev/null +++ b/assets/tables/table3.json @@ -0,0 +1,236 @@ + { + "name": "Loop Trap", + "width": 20, + "height": 30, + + "delegate": "Field3Delegate", + "targetTimeRatio": 2.3, + "gravity": 4.0, + + "numballs": 3, + "ballradius": 0.5, + "ballcolor": [192, 192, 224], + "launch": {"position": [19.3, 3.0], "velocity": [0, 15.4], "random_velocity": [0, 0.6], "deadzone": [18.8, 0, 20, 1.4]}, + + "values": { + "RotatingBumper1Speed": 0.75, + "RotatingBumper1CenterX": 7, + "RotatingBumper1CenterY": 25 + }, + + "elements": [ + + "launch rail", + {"class": "WallElement", "position": [18.7, 0.1, 18.7, 23]}, + {"class": "WallElement", "position": [19.9, 0.1, 19.9, 23]}, + + "main outside arc", + { + "class": "WallArcElement", + "center": [10,23], + "xradius": 9.9, + "yradius": 7, + "minangle": 0, + "maxangle": 180, + "segments": 30 + }, + + "right inside arc", + { + "class": "WallArcElement", + "center": [10,23], + "xradius": 8.7, + "yradius": 5.6, + "minangle": 0, + "maxangle": 54.5, + "segments": 12 + }, + + "outer bottom borders", + {"class": "WallElement", "position": [0.1, 0.1, 18.7, 0.1], "color": [0,0,0], "kill": true}, + {"class": "WallElement", "position": [18.7, 0.1, 19.9, 0.1]}, + + "left bottom", + {"class": "WallElement", "position": [0.1, 4, 6, 1]}, + "right bottom", + {"class": "WallElement", "position": [18.7, 4, 12.7, 1]}, + + "left side", + {"class": "WallElement", "position": [0.1, 4, 0.1, 23], "name": "left border"}, + + "left outlane", + {"class": "WallElement", "position": [1.45, 8.5, 1.45, 4.8]}, + + "right outlane", + {"class": "WallElement", "position": [17.35, 8.5, 17.35, 4.8]}, + + "barrier covering launch rail once the ball enters play, initially disabled", + {"class": "WallElement", "id": "LaunchBarrier", "position": [15.05, 27.53, 15.75, 28.74], "disabled": true, "color": [128, 128, 128]}, + "sensor to enable launch barrier", + {"class": "SensorElement", "id": "LaunchBarrierSensor", "rect": [14.05, 27.53, 15.05, 29]}, + "sensor to retract launch barrier for multi-ball", + {"class": "SensorElement", "id": "LaunchBarrierRetract", "rect": [16, 26.5, 17, 28.5]}, + + "flipper lanes", + {"class": "WallElement", "position": [1.45, 4.8, 6.25, 2.3]}, + {"class": "WallElement", "position": [17.35, 4.8, 12.45, 2.3]}, + + "ball savers, disappear when hit and reappear when drop targets are cleared, controlled by Field1Delegate", + {"class": "WallElement", "id": "BallSaver-left", "position": [0.15, 5.0, 1.35, 5.0], + "kick": 6.0, "color": [0, 255, 0], "retractWhenHit": true}, + + {"class": "WallElement", "id": "BallSaver-right", "position": [17.45, 5.0, 18.65, 5.0], + "kick": 6.0, "color": [0, 255, 0], "retractWhenHit": true}, + + "left kicker, 60 degree angle", + { + "class": "WallElement", + "position": [3.2, 8.77, 5.7, 4.43], + "kick": 3.5, + "score": 100, + "color": [0, 0, 255] + }, + "top/bottom of left kicker without kick, x goes .25 (=0.5*cos(pi/3)), y goes .43 (=0.5*sin(pi/3))", + {"class": "WallElement", "position": [2.95, 9.2, 3.2, 8.77]}, + {"class": "WallElement", "position": [5.95, 4, 5.7, 4.43]}, + + "around left kicker", + {"class": "WallElement", "position": [2.95, 9.2, 2.95, 5.8]}, + {"class": "WallElement", "position": [2.95, 5.8, 5.95, 4]}, + + "right kicker", + { + "class": "WallElement", + "position": [15.6, 8.77, 13.1, 4.43], + "kick": 3.5, + "score": 100, + "color": [0, 0, 255] + }, + "top/bottom of right kicker without kick", + {"class": "WallElement", "position": [15.85, 9.2, 15.6, 8.77]}, + {"class": "WallElement", "position": [12.85, 4, 13.1, 4.43]}, + + "around right kicker", + {"class": "WallElement", "position": [15.85, 9.2, 15.85, 5.8]}, + {"class": "WallElement", "position": [15.85, 5.8, 12.85, 4]}, + + "above left outlane, top arc position [1.379, 12.457]", + { + "class": "WallArcElement", + "center": [3.1,10], + "xradius": 3.0, + "yradius": 3.0, + "minangle": 125, + "maxangle": 180, + "segments": 8 + }, + {"class": "WallElement", "position": [1.379, 12.457, 0.1, 14], "kick": 3, "score": 200, "color": [0, 0, 255]}, + + "rollovers for flipper lanes", + {"class": "RolloverGroupElement", "id": "FlipperRollovers", "color": [0, 224, 224], "radius": 0.4, "score": 500, "cycleOnFlipper": true, + "rollovers": [{"position": [0.775, 7.0]}, + {"position": [2.2, 7.0]}, + {"position": [16.6, 7.0]}, + {"position": [18.025, 7.0]} + ] + }, + + "rollovers in middle for extra ball when all lit", + {"class": "RolloverGroupElement", "id": "ExtraBallRollovers", "radius": 0.5, "ignoreBall": true, + "rollovers": [{"position": [9.4, 13], "color": [224, 224, 224]}, + {"position": [12.0, 11.5], "color": [224, 224, 0]}, + {"position": [9.4, 9], "color": [0, 224, 0]}, + {"position": [9.4, 7], "color": [0, 224, 224]}, + {"position": [9.4, 11], "color": [0, 0, 224]}, + {"position": [6.8, 11.5], "color": [224, 0, 224]} + ] + }, + + "Drop Target group bottom right", + {"class": "DropTargetGroupElement", "id": "DropTargetRightSave", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[16.22, 20.751, 16.66, 19.853], + [16.88, 19.404, 17.32, 18.506], + [17.54, 18.057, 17.98, 17.159]]}, + + "Drop Target group bottom left", + {"class": "DropTargetGroupElement", "id": "DropTargetLeftSave", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[3.315, 20.649, 2.565, 19.987], + [2.28, 19.736, 1.53, 19.074], + [1.245, 18.823, 0.495, 18.161]]}, + + "Drop Target group top right", + {"class": "WallElement", "position": [17.7, 23.8, 13.5, 26.5]}, + {"class": "DropTargetGroupElement", "id": "DropTargetRightTop", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[17.18, 23.97, 16.34, 24.51], + [15.92, 24.78, 15.08, 25.32], + [14.66, 25.59, 13.82, 26.13]]}, + + "Walls on the left of the Drop Target group top right", + {"class": "WallElement", "position": [15.05, 27.53, 13.5, 26.5]}, + {"class": "WallElement", "position": [13.5, 26.5, 11.9,24.1]}, + + "Walls on the right of the Drop Target group top right", + {"class": "WallElement", "position": [17.7, 23.8, 16.1, 21.3]}, + {"class": "WallElement", "position": [16.1, 21.3, 18.7, 16]}, + + "path under top left flipper", + {"class": "WallPathElement", "positions": [[18.7, 15.7], [17.1, 14.3],[18.7, 13]]}, + + "path on the left of the field", + {"class": "WallPathElement", "positions": [[0.1, 18], [3.5, 21],[0.1, 23]]}, + + "rollovers for top lanes", + {"class": "RolloverGroupElement", "id": "TopRollovers", "radius": 0.5, "score": 500, "cycleOnFlipper": true, + "rollovers": [{"position": [15.48, 22.27],"color": [255, 0, 0]}, + {"position": [14.22, 23.08],"color": [0, 255, 0]}, + {"position": [12.96, 23.89],"color": [0, 0, 255]} + ] + }, + + "Walls between top rollovers", + {"class": "WallElement", "position": [14.63, 22.245, 15.169, 23.089]}, + {"class": "WallElement", "position": [13.37, 23.055, 13.909, 23.897]}, + + "bumpers below top lanes", + {"class": "BumperElement", "radius": 0.8, "position": [4, 15], "kick": 3, "color": [225, 10, 20], "score": 500}, + {"class": "BumperElement", "radius": 0.8, "position": [14, 13], "kick": 3, "color": [225, 10, 20], "score": 500}, + + "Hole in the center of the field", + {"class": "HoleElement", "radius": 0.8, "position": [8.5, 19], "id": "CenterHole", "color": [225, 10, 80], "kick": 3, "active" : false, "score": 500}, + + "bumpers on top", + {"class": "BumperElement", "position": [7, 25], "radius": 0.5, "kick": 4, "score": 1000, "color": [224,32,32]}, + {"class": "BumperElement", "position": [4.5, 23.6], "radius": 0.75, "kick": 3, "score": 500}, + {"class": "BumperElement", "position": [9.5, 26.4], "radius": 0.75, "kick": 3, "score": 500} + + ], + + "flippers": [ + { + "position": [6.35, 2.2], + "length": 2.5, + "minangle": -20, + "maxangle": 20, + "upspeed": 7, + "downspeed": 3 + }, + { + "position": [12.35, 2.2], + "length": -2.5, + "minangle": -20, + "maxangle": 20, + "upspeed": 7, + "downspeed": 3 + }, + { + "position": [18.46, 15.96], + "length": -2, + "minangle": -40, + "maxangle": 3, + "upspeed": 9, + "downspeed": 4 + } + + ] + } + diff --git a/assets/tables/table4.json b/assets/tables/table4.json new file mode 100644 index 00000000..059b50db --- /dev/null +++ b/assets/tables/table4.json @@ -0,0 +1,266 @@ + { + "name": "Hexagon", + "width": 20, + "height": 30, + + "delegate": "Field3Delegate", + "targetTimeRatio": 2.3, + "gravity": 4.0, + + "numballs": 3, + "ballradius": 0.5, + "ballcolor": [192, 192, 224], + "launch": {"position": [19.3, 3.0], "velocity": [0, 15.4], "random_velocity": [0, 0.6], "deadzone": [18.8, 0, 20, 1.4]}, + + "values": { + "RotatingBumper1Speed": 0.75 + }, + + "elements": [ + + "launch rail", + {"class": "WallElement", "position": [18.7, 0.1, 18.7, 23]}, + {"class": "WallElement", "position": [19.9, 0.1, 19.9, 23]}, + + "main outside arc", + { + "class": "WallArcElement", + "center": [10,23], + "xradius": 9.9, + "yradius": 7, + "minangle": 0, + "maxangle": 180, + "segments": 30 + }, + + "right inside arc", + { + "class": "WallArcElement", + "center": [10,23], + "xradius": 8.7, + "yradius": 5.6, + "minangle": 0, + "maxangle": 70, + "segments": 12 + }, + + "left inside arc", + { + "class": "WallArcElement", + "center": [10,23], + "xradius": 8.7, + "yradius": 5.6, + "minangle": 110, + "maxangle": 180, + "segments": 12 + }, + + "outer bottom borders", + {"class": "WallElement", "position": [0.1, 0.1, 18.7, 0.1], "color": [0,0,0], "kill": true}, + {"class": "WallElement", "position": [18.7, 0.1, 19.9, 0.1]}, + + "left bottom", + {"class": "WallElement", "position": [0.1, 4, 6, 1]}, + "right bottom", + {"class": "WallElement", "position": [18.7, 4, 12.7, 1]}, + + "left side", + {"class": "WallElement", "position": [0.1, 4, 0.1, 23], "name": "left border"}, + + "left outlane", + {"class": "WallElement", "position": [1.45, 8.5, 1.45, 4.8]}, + + "right outlane", + {"class": "WallElement", "position": [17.35, 8.5, 17.35, 4.8]}, + + "barrier covering launch rail once the ball enters play, initially disabled", + {"class": "WallElement", "id": "LaunchBarrier", "position": [13.05, 28.2, 13.05, 29.7], "disabled": true, "color": [128, 128, 128]}, + "sensor to enable launch barrier", + {"class": "SensorElement", "id": "LaunchBarrierSensor", "rect": [12.05, 28.2, 12.35, 29.7]}, + "sensor to retract launch barrier for multi-ball", + {"class": "SensorElement", "id": "LaunchBarrierRetract", "rect": [16, 26.5, 17, 28.5]}, + + "flipper lanes", + {"class": "WallElement", "position": [1.45, 4.8, 6.25, 2.3]}, + {"class": "WallElement", "position": [17.35, 4.8, 12.45, 2.3]}, + + "ball savers, disappear when hit and reappear when drop targets are cleared, controlled by Field1Delegate", + {"class": "WallElement", "id": "BallSaver-left", "position": [0.15, 5.0, 1.35, 5.0], + "kick": 6.0, "color": [0, 255, 0], "retractWhenHit": true}, + + {"class": "WallElement", "id": "BallSaver-right", "position": [17.45, 5.0, 18.65, 5.0], + "kick": 6.0, "color": [0, 255, 0], "retractWhenHit": true}, + + "left kicker, 60 degree angle", + { + "class": "WallElement", + "position": [3.2, 8.77, 5.7, 4.43], + "kick": 3.5, + "score": 100, + "color": [0, 0, 255] + }, + "top/bottom of left kicker without kick, x goes .25 (=0.5*cos(pi/3)), y goes .43 (=0.5*sin(pi/3))", + {"class": "WallElement", "position": [2.95, 9.2, 3.2, 8.77]}, + {"class": "WallElement", "position": [5.95, 4, 5.7, 4.43]}, + + "around left kicker", + {"class": "WallElement", "position": [2.95, 9.2, 2.95, 5.8]}, + {"class": "WallElement", "position": [2.95, 5.8, 5.95, 4]}, + + "right kicker", + { + "class": "WallElement", + "position": [15.6, 8.77, 13.1, 4.43], + "kick": 3.5, + "score": 100, + "color": [0, 0, 255] + }, + "top/bottom of right kicker without kick", + {"class": "WallElement", "position": [15.85, 9.2, 15.6, 8.77]}, + {"class": "WallElement", "position": [12.85, 4, 13.1, 4.43]}, + + "around right kicker", + {"class": "WallElement", "position": [15.85, 9.2, 15.85, 5.8]}, + {"class": "WallElement", "position": [15.85, 5.8, 12.85, 4]}, + + "rollovers for flipper lanes", + {"class": "RolloverGroupElement", "id": "FlipperRollovers", "color": [0, 224, 224], "radius": 0.4, "score": 500, "cycleOnFlipper": true, + "rollovers": [{"position": [0.775, 7.0]}, + {"position": [2.2, 7.0]}, + {"position": [16.6, 7.0]}, + {"position": [18.025, 7.0]} + ] + }, + + "rollovers in middle for extra ball when all lit", + {"class": "RolloverGroupElement", "id": "ExtraBallRollovers", "radius": 0.5, "ignoreBall": true, + "rollovers": [{"position": [9.4, 8], "color": [224, 224, 224]}, + {"position": [12.0, 10.5], "color": [224, 224, 0]}, + {"position": [14.6, 11.5], "color": [0, 224, 0]}, + {"position": [4.2, 11.5], "color": [0, 224, 224]}, + {"position": [9.4, 10], "color": [100, 100, 224]}, + {"position": [6.8, 10.5], "color": [224, 0, 224]} + ] + }, + + + "bottom right hexagon", + {"class": "WallElement", "position": [11.6, 14.5, 12.35, 15.799]}, + {"class": "WallElement", "position": [12.35, 15.779, 13.85, 15.779], "kick": 3, "score": 200, "color": [0, 0, 255]}, + {"class": "WallElement", "position": [13.85, 15.779, 14.6, 14.5]}, + {"class": "WallElement", "position": [14.6, 14.5, 13.85, 13.201]}, + {"class": "WallElement", "position": [13.85, 13.201, 12.35, 13.201]}, + {"class": "WallElement", "position": [12.35, 13.201, 11.6, 14.5]}, + + "middle left hexagon", + {"class": "WallElement", "position": [3.8, 19.5, 4.55, 20.799]}, + {"class": "WallElement", "position": [4.55, 20.779, 6.05, 20.779], "kick": 3, "score": 200, "color": [0, 0, 255]}, + {"class": "WallElement", "position": [6.05, 20.779, 6.8, 19.5]}, + {"class": "WallElement", "position": [6.8, 19.5, 6.05, 18.201]}, + {"class": "WallElement", "position": [6.05, 18.201, 4.55, 18.201]}, + {"class": "WallElement", "position": [4.55, 18.201, 3.8, 19.5]}, + + "top right hexagon", + {"class": "WallElement", "position": [11.6, 24.5, 12.35, 25.799]}, + {"class": "WallElement", "position": [12.35, 25.779, 13.85, 25.779], "kick": 3, "score": 200, "color": [0, 0, 255]}, + {"class": "WallElement", "position": [13.85, 25.779, 14.6, 24.5]}, + {"class": "WallElement", "position": [14.6, 24.5, 13.85, 23.201]}, + {"class": "WallElement", "position": [13.85, 23.201, 12.35, 23.201]}, + {"class": "WallElement", "position": [12.35, 23.201, 11.6, 24.5]}, + + "Drop Target group top right hexagon", + {"class": "DropTargetGroupElement", "id": "DropTargetRightTop", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[11.6, 24.674, 12.2, 25.712], + [13.75, 23.085, 12.45, 23.085], + [12.2, 23.288, 11.6, 24.326]]}, + + "Drop Target group middle left hexagon", + {"class": "DropTargetGroupElement", "id": "DropTargetLeftSave", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[6.2, 20.692, 6.8, 19.674], + [6.8, 19.326, 6.2, 18.288], + [5.95, 18.085, 4.65, 18.085]]}, + + "Drop Target group bottom right hexagon", + {"class": "DropTargetGroupElement", "id": "DropTargetRightSave", "color": [0, 255, 0], "score": 500, "reset": 2.0, + "positions": [[11.6, 14.674, 12.2, 15.712], + [13.75, 13.085, 12.45, 13.085], + [12.2, 13.288, 11.6, 14.326]]}, + + "big bumpers between hexagons", + {"class": "BumperElement", "radius": 0.85, "position": [5.3, 14.49], "kick": 3, "color": [224, 10, 20], "score": 500}, + {"class": "BumperElement", "radius": 0.85, "position": [13.1, 19.49], "kick": 3, "color": [224, 10, 20], "score": 500}, + + "small bumpers between hexagons", + {"class": "BumperElement", "radius": 0.45, "position": [9.2, 16.99], "kick": 3, "color": [0, 0, 224], "score": 500}, + {"class": "BumperElement", "radius": 0.45, "position": [9.2, 21.99], "kick": 3, "color": [0, 0, 224], "score": 500}, + + {"class": "MagnetElement", "radius": 0.45, "position": [9.2, 13.99], "color": [0, 0, 224]}, + "above left outlane, top arc position [1.379, 12.457]", + { + "class": "WallArcElement", + "center": [3.1,10], + "xradius": 3.0, + "yradius": 3.0, + "minangle": 125, + "maxangle": 180, + "segments": 8 + }, + {"class": "WallElement", "position": [1.379, 12.457, 0.1, 14], "kick": 3, "score": 200, "color": [0, 0, 255]}, + + "above right outlane, top arc position [16.872, 12.762]", + { + "class": "WallArcElement", + "center": [15.7,10], + "xradius": 3.0, + "yradius": 3.0, + "minangle": 0, + "maxangle": 67, + "segments": 8 + }, + {"class": "WallElement", "position": [16.872, 12.762, 18.7, 14], "kick": 3, "score": 200, "color": [0, 0, 255]}, + + "path on the left", + {"class": "WallPathElement", "positions": [[0.1, 17], [1.5, 19],[1.5, 21],[0.1, 23]]}, + {"class": "WallElement", "position": [1.5, 21, 1.3, 23]}, + + "separators between top lanes", + {"class": "WallElement", "position": [7.0, 27.0, 7.0, 29.7]}, + {"class": "WallElement", "position": [8.5, 27.0, 8.5, 28.3]}, + {"class": "WallElement", "position": [10.0, 27.0, 10.0, 28.3]}, + {"class": "WallElement", "position": [11.5, 27.0, 11.5, 28.3]}, + {"class": "WallElement", "position": [13.0, 27.0, 13.0, 28.2]}, + + "rollovers for top lanes", + {"class": "RolloverGroupElement", "id": "TopRollovers", "color": [0, 224, 224], "radius": 0.45, "score": 500, "cycleOnFlipper": true, + "rollovers": [{"position": [7.75, 27.7]}, + {"position": [9.25, 27.7]}, + {"position": [10.75, 27.7]}, + {"position": [12.25, 27.7]} + ] + }, + + "path on the right", + {"class": "WallPathElement", "positions": [[18.7, 17], [17.3, 19],[17.3, 21],[18.7, 23]]} + ], + + "flippers": [ + { + "position": [6.35, 2.2], + "length": 2.5, + "minangle": -20, + "maxangle": 20, + "upspeed": 7, + "downspeed": 3 + }, + { + "position": [12.35, 2.2], + "length": -2.5, + "minangle": -20, + "maxangle": 20, + "upspeed": 7, + "downspeed": 3 + } + + ] + } + diff --git a/src/com/dozingcatsoftware/bouncy/ScoreView.java b/src/com/dozingcatsoftware/bouncy/ScoreView.java index ef0b7a3f..965a02cd 100644 --- a/src/com/dozingcatsoftware/bouncy/ScoreView.java +++ b/src/com/dozingcatsoftware/bouncy/ScoreView.java @@ -22,7 +22,7 @@ public class ScoreView extends View { Field field; Paint textPaint = new Paint(); Rect textRect = new Rect(); - + Paint fpsPaint = new Paint(); Rect fpsRect = new Rect(); @@ -60,7 +60,7 @@ public void draw(Canvas c) { if (displayString==null) { // show score if game is in progress, otherwise cycle between "Touch to start"/previous score/high score if (field.getGameState().isGameInProgress()) { - displayString = SCORE_FORMAT.format(field.getGameState().getScore()); + displayString = "B=" + (field.getGameState().totalBalls - field.getGameState().ballNumber) + "| " + SCORE_FORMAT.format(field.getGameState().getScore()) + " |M=x" + field.getGameState().scoreMultiplier;; } else { boolean cycle = false; @@ -75,10 +75,10 @@ else if (System.currentTimeMillis() - lastUpdateTime > gameOverMessageCycleTime) } } } - textPaint.getTextBounds(displayString, 0, displayString.length(), textRect); // textRect ends up being too high c.drawText(displayString, this.getWidth()/2 - textRect.width()/2, this.getHeight()/2, textPaint); + if (showFPS && fps>0) { c.drawText(String.format("%.1f fps", fps), 0, 20, fpsPaint); } diff --git a/src/com/dozingcatsoftware/bouncy/elements/HoleElement.java b/src/com/dozingcatsoftware/bouncy/elements/HoleElement.java new file mode 100644 index 00000000..9f334821 --- /dev/null +++ b/src/com/dozingcatsoftware/bouncy/elements/HoleElement.java @@ -0,0 +1,95 @@ +package com.dozingcatsoftware.bouncy.elements; + +import static com.dozingcatsoftware.bouncy.util.MathUtils.asFloat; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.World; +import com.dozingcatsoftware.bouncy.Field; +import com.dozingcatsoftware.bouncy.IFieldRenderer; + +/** This FieldElement subclass represents a hole that ends the game when a ball hits it. If inactive it functions like a bumper + * that applies an impulse to a ball when it hits. The impulse magnitude is controlled + * by the "kick" parameter and if it's active or not by the "active" parameter in the configuration map . + */ + +public class HoleElement extends FieldElement{ + + Body holeBody; + List holeBodySet; + + float radius; + float cx, cy; + boolean isActive; + float kick; + + public void finishCreate(Map params, World world) { + List pos = (List)params.get("position"); + this.radius = asFloat(params.get("radius")); + this.cx = asFloat(pos.get(0)); + this.cy = asFloat(pos.get(1)); + this.isActive = (Boolean.TRUE.equals(params.get("active"))); + this.kick = asFloat(params.get("kick")); + + holeBody = Box2DFactory.createCircle(world, cx, cy, radius, true); + holeBodySet = Collections.singletonList(holeBody); + } + + @Override + public boolean shouldCallTick() { + return true; + } + + @Override + public List getBodies() { + return holeBodySet; + } + + @Override + public void handleCollision(Body ball, Body bodyHit, Field field) { + if (isActive) { //if the element is active the ball falls in and the game ends + field.removeBall(ball); + } + else{ //if the element is inactive it functions like a bumper + Vector2 impulse = this.impulseForBall(ball); + if (impulse!=null) { + ball.applyLinearImpulse(impulse, ball.getWorldCenter()); + flashForFrames(3); + } + } + + } + + //set the element active or inactive + public void setActivation(boolean active){ + isActive = active; + } + + Vector2 impulseForBall(Body ball) { + if (this.kick <= 0.01f) return null; + // compute unit vector from center of hole to ball, and scale by kick value to get impulse + Vector2 ballpos = ball.getWorldCenter(); + Vector2 thisPos = holeBody.getPosition(); + float ix = ballpos.x - thisPos.x; + float iy = ballpos.y - thisPos.y; + float mag = (float)Math.sqrt(ix*ix + iy*iy); + float scale = this.kick / mag; + return new Vector2(ix*scale, iy*scale); + } + + @Override + public void draw(IFieldRenderer renderer) { + //when element active draws a circle and when inactive draws a filled circle to look like a bumper + float px = holeBody.getPosition().x; + float py = holeBody.getPosition().y; + if(isActive){ + renderer.frameCircle(px, py, radius, redColorComponent(0), greenColorComponent(0), blueColorComponent(255)); + }else{ + renderer.fillCircle(px, py, radius, redColorComponent(0), greenColorComponent(0), blueColorComponent(255)); + } + } +} diff --git a/src/com/dozingcatsoftware/bouncy/elements/MagnetElement.java b/src/com/dozingcatsoftware/bouncy/elements/MagnetElement.java new file mode 100644 index 00000000..311ad1c5 --- /dev/null +++ b/src/com/dozingcatsoftware/bouncy/elements/MagnetElement.java @@ -0,0 +1,61 @@ +package com.dozingcatsoftware.bouncy.elements; + +import static com.dozingcatsoftware.bouncy.util.MathUtils.asFloat; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.World; +import com.dozingcatsoftware.bouncy.Field; +import com.dozingcatsoftware.bouncy.IFieldRenderer; + +public class MagnetElement extends FieldElement { + Body magnetBody; + List magnetBodySet; + + float radius; + float cx, cy; + + public void finishCreate(Map params, World world) { + List pos = (List)params.get("position"); + this.radius = asFloat(params.get("radius")); + this.cx = asFloat(pos.get(0)); + this.cy = asFloat(pos.get(1)); + + magnetBody = Box2DFactory.createCircle(world, cx, cy, radius, true); + magnetBodySet = Collections.singletonList(magnetBody); + } + + @Override + public List getBodies() { + return magnetBodySet; + } + + public boolean shouldCallTick() { + // needs to call tick to decrement flash counter (but can use superclass tick() implementation) + return true; + } + + @Override + public void handleCollision(Body ball, Body bodyHit, Field field) { + flashForFrames(3); + try { + field.wait(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + field.addScore(200); + } + + + @Override + public void draw(IFieldRenderer renderer) { + float px = magnetBody.getPosition().x; + float py = magnetBody.getPosition().y; + renderer.fillCircle(px, py, radius, redColorComponent(0), greenColorComponent(0), blueColorComponent(255)); + } +} + diff --git a/src/com/dozingcatsoftware/bouncy/fields/Field3Delegate.java b/src/com/dozingcatsoftware/bouncy/fields/Field3Delegate.java new file mode 100644 index 00000000..5df3bb8d --- /dev/null +++ b/src/com/dozingcatsoftware/bouncy/fields/Field3Delegate.java @@ -0,0 +1,100 @@ +package com.dozingcatsoftware.bouncy.fields; + +import com.badlogic.gdx.physics.box2d.Body; +import com.dozingcatsoftware.bouncy.BaseFieldDelegate; +import com.dozingcatsoftware.bouncy.Field; +import com.dozingcatsoftware.bouncy.elements.DropTargetGroupElement; +import com.dozingcatsoftware.bouncy.elements.RolloverGroupElement; +import com.dozingcatsoftware.bouncy.elements.SensorElement; +import com.dozingcatsoftware.bouncy.elements.WallElement; +import com.dozingcatsoftware.bouncy.elements.HoleElement; + + +public class Field3Delegate extends BaseFieldDelegate { + + + + @Override + public void allRolloversInGroupActivated(Field field, RolloverGroupElement rolloverGroup) { + // rollover groups increment field multiplier when all rollovers are activated, also reset to inactive + rolloverGroup.setAllRolloversActivated(false); + field.getGameState().incrementScoreMultiplier(); + field.showGameMessage(field.getGameState().getScoreMultiplier() + "x Multiplier", 1500); + + // extra ball for ramp shot if extra ball rollovers all lit + if ("RampRollovers".equals(rolloverGroup.getElementID())) { + RolloverGroupElement extraBallRollovers = (RolloverGroupElement)field.getFieldElementByID("ExtraBallRollovers"); + if (extraBallRollovers.allRolloversActive()) { + extraBallRollovers.setAllRolloversActivated(false); + startMultiball(field); + } + } + } + + + void startMultiball(final Field field) { + field.showGameMessage("Multiball!", 2000); + Runnable launchBall = new Runnable() { + public void run() { + if (field.getBalls().size()<3) field.launchBall(); + } + }; + field.scheduleAction(1000, launchBall); + field.scheduleAction(3500, launchBall); + } + + @Override + public void allDropTargetsInGroupHit(Field field, DropTargetGroupElement targetGroup) { + // activate ball saver for left and right groups + String id = targetGroup.getElementID(); + if ("DropTargetLeftSave".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-left")).setRetracted(false); + field.showGameMessage("Left Save Enabled", 1500); + } + else if ("DropTargetRightSave".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-right")).setRetracted(false); + field.showGameMessage("Right Save Enabled", 1500); + } + else if ("DropTargetRightTop".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-right")).setRetracted(false); + ((WallElement)field.getFieldElementByID("BallSaver-left")).setRetracted(false); + field.showGameMessage("Both Save Enabled", 1500); + ((HoleElement)field.getFieldElementByID("CenterHole")).setActivation(true); + field.showGameMessage("Center Hole Enabled", 1500); + } + // for all groups, increment extra ball rollover + RolloverGroupElement extraBallRollovers = (RolloverGroupElement)field.getFieldElementByID("ExtraBallRollovers"); + if (!extraBallRollovers.allRolloversActive()) { + extraBallRollovers.activateFirstUnactivatedRollover(); + if (extraBallRollovers.allRolloversActive()) { + field.showGameMessage("Shoot Ramp for Multiball", 1500); + } + } + } + + void setLaunchBarrierEnabled(Field field, boolean enabled) { + WallElement barrier = (WallElement)field.getFieldElementByID("LaunchBarrier"); + barrier.setRetracted(!enabled); + } + + public void ballInSensorRange(Field field, SensorElement sensor, Body ball) { + // enable launch barrier + if ("LaunchBarrierSensor".equals(sensor.getElementID())) { + setLaunchBarrierEnabled(field, true); + } + else if ("LaunchBarrierRetract".equals(sensor.getElementID())) { + setLaunchBarrierEnabled(field, false); + } + } + + @Override + public void gameStarted(Field field) { + setLaunchBarrierEnabled(field, false); + } + + @Override + public void ballLost(Field field) { + setLaunchBarrierEnabled(field, false); + } +} + diff --git a/src/com/dozingcatsoftware/bouncy/fields/Field4Delegate.java b/src/com/dozingcatsoftware/bouncy/fields/Field4Delegate.java new file mode 100644 index 00000000..7b7aed13 --- /dev/null +++ b/src/com/dozingcatsoftware/bouncy/fields/Field4Delegate.java @@ -0,0 +1,91 @@ +package com.dozingcatsoftware.bouncy.fields; + +import com.badlogic.gdx.physics.box2d.Body; +import com.dozingcatsoftware.bouncy.BaseFieldDelegate; +import com.dozingcatsoftware.bouncy.Field; +import com.dozingcatsoftware.bouncy.elements.DropTargetGroupElement; +import com.dozingcatsoftware.bouncy.elements.RolloverGroupElement; +import com.dozingcatsoftware.bouncy.elements.SensorElement; +import com.dozingcatsoftware.bouncy.elements.WallElement; + +public class Field4Delegate extends BaseFieldDelegate { + + public void allRolloversInGroupActivated(Field field, RolloverGroupElement rolloverGroup) { + // rollover groups increment field multiplier when all rollovers are activated, also reset to inactive + rolloverGroup.setAllRolloversActivated(false); + field.getGameState().incrementScoreMultiplier(); + field.showGameMessage(field.getGameState().getScoreMultiplier() + "x Multiplier", 1500); + + // extra ball for ramp shot if extra ball rollovers all lit + if ("RampRollovers".equals(rolloverGroup.getElementID())) { + RolloverGroupElement extraBallRollovers = (RolloverGroupElement)field.getFieldElementByID("ExtraBallRollovers"); + if (extraBallRollovers.allRolloversActive()) { + extraBallRollovers.setAllRolloversActivated(false); + startMultiball(field); + } + } + } + + @Override + public void allDropTargetsInGroupHit(Field field, DropTargetGroupElement targetGroup) { + // activate ball saver for left and right groups + String id = targetGroup.getElementID(); + if ("DropTargetLeftSave".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-left")).setRetracted(false); + field.showGameMessage("Left Save Enabled", 1500); + } + else if ("DropTargetRightSave".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-right")).setRetracted(false); + field.showGameMessage("Right Save Enabled", 1500); + } + else if ("DropTargetRightTop".equals(id)) { + ((WallElement)field.getFieldElementByID("BallSaver-right")).setRetracted(false); + ((WallElement)field.getFieldElementByID("BallSaver-left")).setRetracted(false); + field.showGameMessage("Both Save Enabled", 1500); + } + // for all groups, increment extra ball rollover + RolloverGroupElement extraBallRollovers = (RolloverGroupElement)field.getFieldElementByID("ExtraBallRollovers"); + if (!extraBallRollovers.allRolloversActive()) { + extraBallRollovers.activateFirstUnactivatedRollover(); + if (extraBallRollovers.allRolloversActive()) { + field.showGameMessage("Shoot Ramp for Multiball", 1500); + } + } + } + void startMultiball(final Field field) { + field.showGameMessage("Multiball!", 2000); + Runnable launchBall = new Runnable() { + public void run() { + if (field.getBalls().size()<3) field.launchBall(); + } + }; + field.scheduleAction(1000, launchBall); + field.scheduleAction(3500, launchBall); + } + + void setLaunchBarrierEnabled(Field field, boolean enabled) { + WallElement barrier = (WallElement)field.getFieldElementByID("LaunchBarrier"); + barrier.setRetracted(!enabled); + } + + public void ballInSensorRange(Field field, SensorElement sensor, Body ball) { + // enable launch barrier + if ("LaunchBarrierSensor".equals(sensor.getElementID())) { + setLaunchBarrierEnabled(field, true); + } + else if ("LaunchBarrierRetract".equals(sensor.getElementID())) { + setLaunchBarrierEnabled(field, false); + } + } + + @Override + public void gameStarted(Field field) { + setLaunchBarrierEnabled(field, false); + } + + @Override + public void ballLost(Field field) { + setLaunchBarrierEnabled(field, false); + } +} +