1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use blobs::*;
use comfy::*;
// This example shows an integration between comfy and blobs, a simple 2d physics engine. It's not
// the most beautiful example, and maybe a bit verbose for what it does, but it tries to showcase
// some more extensible ways of using comfy.
comfy_game!("Physics Example", PhysicsGame);
pub enum BallSpawningSpeed {
Comfy,
Uncomfy,
}
pub struct PhysicsGame {
pub spawn_timer: f32,
pub physics: Physics,
pub ball_spawning_speed: BallSpawningSpeed,
}
impl GameLoop for PhysicsGame {
fn new(_c: &mut EngineState) -> Self {
let mut state = Self {
spawn_timer: 0.0,
physics: Physics::new(vec2(0.0, -20.0), false),
ball_spawning_speed: BallSpawningSpeed::Comfy,
};
let rbd_handle =
state.physics.insert_rbd(RigidBodyBuilder::new().build());
state.physics.insert_collider_with_parent(
ColliderBuilder::new().build(),
rbd_handle,
);
// We can add a circle constraint which prevents any body from leaving the constrained area.
// Note that currently blobs constraints work based on position and ignore collider radius.
state
.physics
.constraints
.push(Constraint { position: Vec2::ZERO, radius: 5.0 });
// We'll need SFX for this
load_sound_from_bytes(
// Every sound gets a string name later used to reference it.
"comfy-bell",
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../assets/bell-sfx.ogg"
)),
StaticSoundSettings::default(),
);
state
}
fn update(&mut self, _c: &mut EngineContext) {
self.spawn_timer -= delta();
let limit = match self.ball_spawning_speed {
BallSpawningSpeed::Comfy => 100,
BallSpawningSpeed::Uncomfy => 1000,
};
if self.spawn_timer <= 0.0 && self.physics.rbd_count() < limit {
let max_time = match self.ball_spawning_speed {
BallSpawningSpeed::Comfy => 0.4,
BallSpawningSpeed::Uncomfy => 0.01,
};
// Every time the timer expires we reset it to a random value.
self.spawn_timer = random_range(0.01, max_time);
let rbd_handle = self.physics.insert_rbd(
RigidBodyBuilder::new().position(random_circle(2.0)).build(),
);
self.physics.insert_collider_with_parent(
ColliderBuilder::new().radius(random_range(0.05, 0.4)).build(),
rbd_handle,
);
play_sound("comfy-bell");
}
self.physics.step(delta() as f64);
// We could iterate rigid bodies individually, but blobs also has a nice way of collecting
// debug data in a simple format for rendering/logginc that we'll use to draw all bodies and
// colliders.
let debug = self.physics.debug_data();
for body in debug.bodies.iter() {
draw_circle(body.transform.translation, 0.1, RED.alpha(0.8), 5);
}
for constraint in self.physics.constraints.iter() {
draw_circle(
constraint.position,
constraint.radius,
WHITE.alpha(0.1),
3,
);
}
// Let's use the colliders arena to draw the colliders for a change. We could
// also just use `debug.colliders`.
for (_, collider) in self.physics.col_set.iter() {
// We'll draw collider circles behind the rigid body circles using a lower z_index.
draw_circle(
collider.absolute_transform.translation,
collider.radius,
BLUE.alpha(0.5),
4,
);
}
draw_text(
"Be warned, blobs isn't very stable with many balls :)",
Position::screen_percent(0.5, 0.85).to_world(),
WHITE,
TextAlign::Center,
);
draw_text(
&format!("There are now {} balls", self.physics.rbd_count()),
Position::screen_percent(0.5, 0.15).to_world(),
WHITE,
TextAlign::Center,
);
egui::Window::new("More balls")
.anchor(egui::Align2::LEFT_TOP, egui::vec2(10.0, 10.0))
.show(egui(), |ui| {
match self.ball_spawning_speed {
BallSpawningSpeed::Comfy => {
if ui.button("Make it go faster").clicked() {
self.ball_spawning_speed =
BallSpawningSpeed::Uncomfy;
}
}
BallSpawningSpeed::Uncomfy => {
if ui
.add(egui::Button::new(
egui::RichText::new("NOOOO, PLS STOP!!!").size(
rescale(
self.physics.rbd_count() as f32,
0.0..limit as f32,
10.0..100.0,
),
),
))
.clicked()
{
self.ball_spawning_speed = BallSpawningSpeed::Comfy;
self.physics.reset();
}
}
}
});
}
}