0% found this document useful (0 votes)
5 views15 pages

GC Lab5

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views15 pages

GC Lab5

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

MINISTERUL EDUCAT, IEI, CULTURII S, I CERCETĂRII

AL REPUBLICII MOLDOVA
Universitatea Tehnică a Moldovei
Facultatea Calculatoare, Informatică şi Microelectronică
Departamentul Inginerie Software s, i Automatică

BELIH DMITRII FAF-232

REPORT
Laboratory work n.7
of Computer Graphics

Checked by:
Olga Grosu, university assistant
DISA, FCIM, UTM

Chis, inău – 2024


1. The Purpose of the Laboratory Work
1. Design Complex Creatures: Combine multiple Box2D shapes to create intricate and creative creature
designs. Enhance the designs with visuals such as colors, images, and lines. Utilize the Box2D shapes as
the skeletons for these creatures.

2. Simulate Realistic Physics: Assign physical properties to the creatures, including density, friction, and
restitution (bounciness). Use these properties to simulate realistic interactions, such as gravity, collisions,
and forces.

3. Experiment with Joints: Build creature skeletons using Box2D distance joints and revolute joints. Simu-
late realistic appendage movements by combining these joints.

4. Interact and Control: Implement user interaction by allowing control of one or more creatures via key-
board or mouse input. Alternatively, program forces to simulate natural movements for the creatures.

5. Test in Varied Environments: Create multiple environments or obstacles to observe and analyze how the
creatures interact and adapt within these scenarios.

6. Compare Frameworks: Develop a report comparing the use of Processing’s native tools (e.g., PVectors,
forces, oscillations, particle systems) against the Box2D library for handling physics-based interactions.
Reflect on the strengths and challenges of each approach.

2. The Condition
Create an interactive Processing sketch using Box2D to simulate physics-based creatures with dynamic behaviors.
Your sketch should demonstrate the following:

1. Collision Detection and Event Triggering: Implement collision detection between the creatures and trig-
ger events upon collision.

2. Creature Design: Create your own creature by combining multiple shapes attached to a single body. Use
the PolygonShape class to create custom polygon designs, and explore making concave shapes by combin-
ing more than one polygon. You are not limited to the basic shape-drawing functions in Processing—feel
free to add images, colors, or even hair using lines to make your creature visually interesting. Box2D shapes
should be used as skeletons for your design, enhancing the creative aspects of the creature.

3. Creature Multiplication and Interaction: Multiply your creature design and use Box2D to allow for
interactions and collisions between multiple creatures. Consider using Box2D to augment the design, such
as building a skeleton with distance joints or creating appendages with revolute joints.

4. Assigning Physical Properties: Assign properties such as density, friction, and restitution (bounciness) to
your creatures. Make sure the creatures react realistically to forces, gravity, and collisions.

5. User Control and Movement Simulation: Allow the user to control one or more creatures via keyboard
or mouse input. Alternatively, apply forces to simulate natural movement and behaviors of the creatures.

1
6. Multiple Environments and Obstacles: Design multiple environments or obstacles for the creatures to
interact with. This will test how they adapt and react to various conditions within the simulation.

7. Box2D Example: Refer to examples in the Box2D library for guidance and inspiration in setting up the
physics and interactions for your creatures.

8. Final Report: In your report, describe the differences between using simple Processing with your own
creature using PVectors, forces, oscillation, and particle systems versus incorporating the Box2D library.
Conclude by discussing your own sketch, reflecting on the challenges and creative aspects of your design.

3. The Program Code


Task1

1 // Box2D
2 import shiffman.box2d.*;
3 import org.jbox2d.collision.shapes.*;
4 import org.jbox2d.common.*;
5 import org.jbox2d.dynamics.*;
6 import org.jbox2d.dynamics.contacts.*;
7

8 // Box2D
9 Box2DProcessing box2d;
10

11 //
12 ArrayList<Particle> particles;
13 ArrayList<Lollipop> pops;
14 ArrayList<Boundary> boundaries;
15

16 //
17 Portal portal;
18

19 void setup() {
20 size(640, 640);
21

22 // Box2D
23 box2d = new Box2DProcessing(this);
24 box2d.createWorld();
25 box2d.listenForCollisions(); //

26

27 //
28 particles = new ArrayList<Particle>();
29 pops = new ArrayList<Lollipop>();
30 boundaries = new ArrayList<Boundary>();
31

32 //
33 boundaries.add(new Boundary(width / 4, height - 5, width / 2 - 50, 10, 0));

2
34 boundaries.add(new Boundary(3 * width / 4, height - 50, width / 2 - 50, 10, 0));
35 boundaries.add(new Boundary(width - 5, height / 2, 10, height, 0));
36 boundaries.add(new Boundary(5, height / 2, 10, height, 0));
37

38 //
39 portal = new Portal();
40 }
41 void draw() {
42 background(0);
43

44 //
45 portal.display();
46 portal.update();
47

48 // Box2D
49 box2d.step();
50

51 //
52 for (int i = particles.size() - 1; i >= 0; i--) {
53 Particle p = particles.get(i);
54 p.display();
55 if (p.done()) {
56 particles.remove(i);
57 }
58 }
59

60 //
61 for (int i = pops.size() - 1; i >= 0; i--) {
62 Lollipop pop = pops.get(i);
63 pop.display();
64 if (pop.done()) {
65 pops.remove(i);
66 }
67 }
68

69 //
70 for (Boundary b : boundaries) {
71 b.display();
72 }
73 }
74

75 void mousePressed() {
76 //
77 pops.add(new Lollipop(mouseX, mouseY));
78 }
79 //
80 void beginContact(Contact cp) {
81 Fixture f1 = cp.getFixtureA();
82 Fixture f2 = cp.getFixtureB();

3
83 Body b1 = f1.getBody();
84 Body b2 = f2.getBody();
85

86 Object o1 = b1.getUserData();
87 Object o2 = b2.getUserData();
88

89 //

90 if (o1 != null) {
91 if (o1 instanceof Particle) {
92 ((Particle) o1).changeColor();
93 }
94 if (o1 instanceof Lollipop) {
95 ((Lollipop) o1).changeColor();
96 }
97 }
98 if (o2 != null) {
99 if (o2 instanceof Particle) {
100 ((Particle) o2).changeColor();
101 }
102 if (o2 instanceof Lollipop) {
103 ((Lollipop) o2).changeColor();
104 }
105 }
106 }
107

108 // (Boundary)
109 class Boundary {
110 float x, y, w, h;
111 Body b;
112

113 Boundary(float x_, float y_, float w_, float h_, float a) {
114 x = x_;
115 y = y_;
116 w = w_;
117 h = h_;
118

119 PolygonShape sd = new PolygonShape();


120 float box2dW = box2d.scalarPixelsToWorld(w / 2);
121 float box2dH = box2d.scalarPixelsToWorld(h / 2);
122 sd.setAsBox(box2dW, box2dH);
123

124 BodyDef bd = new BodyDef();


125 bd.type = BodyType.STATIC;
126 bd.angle = a;
127 bd.position.set(box2d.coordPixelsToWorld(x, y));
128 b = box2d.createBody(bd);
129 b.createFixture(sd, 1);
130 }

4
131

132 void display() {


133 fill(255, 255, 0); //
134 stroke(0);
135 strokeWeight(1);
136 rectMode(CENTER);
137 float a = b.getAngle();
138 pushMatrix();
139 translate(x, y);
140 rotate(-a);
141 rect(0, 0, w, h);
142 popMatrix();
143 }
144 }
145

146

147 // (Particle)
148 class Particle {
149 Body body;
150 float r;
151 color col;
152

153 Particle(float x, float y, float r_) {


154 r = r_;
155 col = color(127);
156 makeBody(x, y, r);
157 body.setUserData(this);
158 }
159

160 void display() {


161 Vec2 pos = box2d.getBodyPixelCoord(body);
162 float a = body.getAngle();
163 pushMatrix();
164 translate(pos.x, pos.y);
165 rotate(a);
166 fill(col);
167 stroke(0);
168 ellipse(0, 0, r * 2, r * 2);
169 popMatrix();
170 }
171

172 void changeColor() {


173 col = color(255, 0, 0); //
174 }
175

176 boolean done() {


177 Vec2 pos = box2d.getBodyPixelCoord(body);
178 if (pos.y > height + r * 2) {
179 box2d.destroyBody(body);

5
180 return true;
181 }
182 return false;
183 }
184

185 void makeBody(float x, float y, float r) {


186 BodyDef bd = new BodyDef();
187 bd.position = box2d.coordPixelsToWorld(x, y);
188 bd.type = BodyType.DYNAMIC;
189 body = box2d.createBody(bd);
190

191 CircleShape cs = new CircleShape();


192 cs.m_radius = box2d.scalarPixelsToWorld(r);
193

194 FixtureDef fd = new FixtureDef();


195 fd.shape = cs;
196 fd.density = 1;
197 fd.friction = 0.01;
198 fd.restitution = 0.3;
199

200 body.createFixture(fd);
201 }
202 }
203

204 class Lollipop {


205 Body body;
206 float r = 15; //
207 float bodyWidth = 30; //
208 float bodyHeight = 60; //
209 color col;
210

211 Lollipop(float x, float y) {


212 col = color(127);
213 makeBody(new Vec2(x, y));
214 body.setUserData(this);
215 }
216

217 void display() {


218 Vec2 pos = box2d.getBodyPixelCoord(body);
219 float a = body.getAngle();
220 pushMatrix();
221 translate(pos.x, pos.y);
222 rotate(-a);
223

224 // ( )
225 fill(150, 100, 255); //
226 noStroke();
227 rect(0, 0, bodyWidth, bodyHeight);
228

6
229 // ( )
230 fill(col);
231 ellipse(0, -bodyHeight / 2 - r, r * 2, r * 2);
232

233 // " "


234 stroke(255, 255, 0); //
235 strokeWeight(2);
236 for (int i = -3; i <= 3; i++) {
237 line(i * 5, -bodyHeight / 2 - r - 10, i * 5, -bodyHeight / 2 - r - 20);
238 }
239

240 //
241 fill(0);
242 ellipse(-5, -bodyHeight / 2 - r - 5, 4, 4);
243 ellipse(5, -bodyHeight / 2 - r - 5, 4, 4);
244

245 //
246 noFill();
247 stroke(0);
248 strokeWeight(1.5);
249 arc(0, -bodyHeight / 2 - r, 10, 6, 0, PI);
250

251 popMatrix();
252 }
253

254 void changeColor() {


255 col = color(255, 0, 0); //
256 }
257

258 boolean done() {


259 Vec2 pos = box2d.getBodyPixelCoord(body);
260 if (pos.y > height + r * 2) {
261 box2d.destroyBody(body);
262 return true;
263 }
264 return false;
265 }
266

267 void makeBody(Vec2 center) {


268 BodyDef bd = new BodyDef();
269 bd.type = BodyType.DYNAMIC;
270 bd.position.set(box2d.coordPixelsToWorld(center));
271 body = box2d.createBody(bd);
272

273 // ( )
274 CircleShape circle = new CircleShape();
275 circle.m_radius = box2d.scalarPixelsToWorld(r);
276 Vec2 offset = new Vec2(0, -bodyHeight / 2 - r); //

7
277 offset = box2d.vectorPixelsToWorld(offset);
278 circle.m_p.set(offset.x, offset.y);
279

280 // ( )
281 PolygonShape bodyShape = new PolygonShape();
282 float box2dW = box2d.scalarPixelsToWorld(bodyWidth / 2); //
283 float box2dH = box2d.scalarPixelsToWorld(bodyHeight / 2); //
284 bodyShape.setAsBox(box2dW, box2dH, new Vec2(0, -bodyHeight / 2), 0); //

285

286 //
287 body.createFixture(circle, 1.0);
288 body.createFixture(bodyShape, 1.0);
289

290 //
291 body.setLinearVelocity(new Vec2(random(-3, 3), random(2, 5)));
292 body.setAngularVelocity(random(-2, 2));
293 }
294 }
295

296 //
297 class Portal {
298 PVector pos;
299 float size;
300

301 color fillColor;


302

303 boolean invertShearTheta;


304 float origShearTheta;
305 float shearTheta;
306

307 Orb[] orbs;


308 Star[] stars;
309

310 Portal() {
311 pos = new PVector(width / 2, height / 2);
312 size = (width + height) / 4;
313

314 invertShearTheta = random(1) < 0.5;


315 origShearTheta = QUARTER_PI;
316 shearTheta = abs((invertShearTheta ? 255 : 0) - origShearTheta);
317

318 fillColor = lerpColor(color(155, 0, 200), color(100, 0, 255), random(1));


319

320 orbs = new Orb[75];


321 for (int i = 0; i < orbs.length; i++)
322 orbs[i] = new Orb();
323

324 stars = new Star[50];

8
325 for (int i = 0; i < stars.length; i++)
326 stars[i] = new Star();
327 }
328

329 void display() {


330 for (int i = 0; i < stars.length; i++) {
331 if (stars[i].size < 5)
332 stars[i].display();
333 }
334

335 pushMatrix();
336 translate(pos.x, pos.y);
337 shearX(shearTheta);
338

339 noFill();
340 for (float s = 0; s < size; s += 10) {
341 stroke(fillColor, (size - s) / size * 255);
342 strokeWeight(abs(cos((frameCount + (size - s) / size * 10) / 600.0)) * 10);
343

344 ellipse(0, 0, s, s);


345 }
346

347 for (int i = 0; i < orbs.length; i++)


348 orbs[i].display();
349 popMatrix();
350

351 for (int i = 0; i < stars.length; i++) {


352 if (stars[i].size >= 5)
353 stars[i].display();
354 }
355 }
356

357 void update() {


358 shearTheta = abs((invertShearTheta ? 255 : 0) - abs(cos(frameCount / 60000.0 *
TWO_PI)) * origShearTheta);
359

360 for (int i = 0; i < orbs.length; i++)


361 orbs[i].update();
362

363 for (int i = 0; i < stars.length; i++) {


364 stars[i].update();
365 }
366 }
367 }
368 class Orb {
369 PVector pos;
370 float size;
371

372 float start;

9
373 float end;
374

375 color strokeColor;


376 float strokeWeight;
377

378 float alpha;


379 float origAlpha;
380 float alphaSpeed;
381

382 float theta;


383 float thetaSpeed;
384

385 Orb() {
386 pos = new PVector(width/2, height/2);
387 size = random(1, (width+height)/4);
388

389 start = random(TWO_PI);


390 end = random(TWO_PI);
391

392 strokeColor = color(random(50, 200), 0, random(200, 255));


393 strokeWeight = random(3, 10);
394

395 alpha = random(255);


396 origAlpha = alpha;
397 alphaSpeed = random(600, 3000);
398

399 thetaSpeed = random(0.001, 0.045);


400 }
401

402 void display() {


403 noFill();
404 stroke(strokeColor, alpha);
405 strokeWeight(strokeWeight);
406

407 pushMatrix();
408 rotate(theta);
409

410 arc(0, 0, size, size, start, end);


411 popMatrix();
412 }
413

414 void update() {


415 alpha = abs(cos(frameCount/alphaSpeed*TWO_PI))*origAlpha;
416 theta+= thetaSpeed;
417 }
418 }
419

420

421 class Star {

10
422 PVector pos;
423 PVector vel;
424

425 float size;


426

427 float alpha;


428 float origAlpha;
429 float alphaSpeed;
430

431 Star() {
432 pos = new PVector(random(width), random(height));
433 vel = PVector.random2D();
434

435 size = random(1, 10);


436 vel.div(size);
437

438 alpha = random(255);


439 origAlpha = alpha;
440 alphaSpeed = random(600, 1200);
441 }
442

443 void display() {


444 fill(255, alpha);
445 noStroke();
446

447 ellipse(pos.x, pos.y, size, size);


448 }
449

450 boolean intersects(Lollipop pop) {


451 Vec2 popPos = box2d.getBodyPixelCoord(pop.body);
452 float popRadius = max(pop.bodyWidth / 2, pop.r); //

453

454 float distance = dist(pos.x, pos.y, popPos.x, popPos.y);


455 return distance < (size / 2 + popRadius);
456 }
457

458

459

460 void update() {


461 pos.add(vel);
462 alpha = lerp(alpha, abs(cos(frameCount/alphaSpeed*TWO_PI))*origAlpha, 0.1);
463

464 if (pos.x > width || pos.x < 0 || pos.y > height || pos.y < 0) {
465 pos = new PVector(width/2, height/2);
466 size = random(1, 10);
467

468 alpha = 0;
469 origAlpha = random(255);

11
470 }
471 //
472 for (int i = pops.size() - 1; i >= 0; i--) {
473 Lollipop pop = pops.get(i);
474 if (intersects(pop)) {
475 pops.remove(i); //
476 }
477 }
478 }
479 }

4. Screen Captures of the Program Execution

Figure 1: Program execution showing system

5. Comparison: Simple Processing vs Box2D Library


In this section, we will compare the approaches of using simple Processing with PVectors, forces, oscillations, and
particle systems against using the Box2D library for simulating physics-based creatures.

12
Using Simple Processing

In Processing, creating creatures with dynamic behaviors is often done using basic programming techniques such
as:

• PVectors: These are used to represent the position, velocity, and acceleration of the creature, allowing for
simple movement simulations.

• Forces: Custom forces like gravity, wind, or user interaction can be applied manually to the creature. These
forces are typically added or subtracted from the creature’s velocity in each frame of the sketch.

• Oscillation: Creatures can be made to oscillate by applying periodic forces, such as sine or cosine functions,
to simulate motion like bouncing, swinging, or floating.

• Particle Systems: Complex behaviors such as fluids or systems of interacting particles can be simulated,
but the behavior is often simplified compared to what would be expected in a full physics engine.

These techniques are useful for basic simulations but require significant manual calculations, especially when
it comes to interactions, collisions, or more complex behaviors.

Using the Box2D Library

In contrast, the Box2D library offers a more comprehensive solution for simulating physical interactions. By using
Box2D, the following benefits are achieved:

• Realistic Physics Engine: Box2D automatically handles the complexities of real-world physics, including
forces, gravity, friction, restitution (bounciness), and collision detection. This allows for much more realistic
and less error-prone simulations compared to hand-written physics code.

• Advanced Shape Handling: Unlike Processing, which requires you to manually manage and update the
positions of shapes, Box2D provides built-in shape classes (like circles, polygons, and chains) with their
own properties that automatically update in response to forces and collisions.

• Joints and Constraints: Box2D enables the use of joints and constraints, such as revolute joints or distance
joints, which allow the creation of complex structures like creatures with appendages or articulated bodies.
This is something that would be very difficult to manage manually in simple Processing.

• Collision Detection: The Box2D library simplifies collision detection and response. It can detect when two
objects interact, automatically calculating the appropriate response (e.g., bounce, stop, slide) based on their
physical properties.

• Performance Optimization: Box2D is optimized for handling many interacting objects efficiently, whereas
manual calculations in Processing may become slower as the number of creatures or interactions grows.

13
Key Differences

• Complexity: Simple Processing offers more flexibility for creating custom behaviors, but requires more
code and manual calculations for physics and interactions. Box2D abstracts away much of this complexity,
providing automatic solutions for many physical behaviors.

• Realism: Box2D provides more realistic simulations of physics-based interactions (collisions, forces, and
movement) than basic Processing, which relies on simpler mathematical models.

• Creativity and Control: While Box2D offers more realistic simulations, it might restrict creativity be-
cause you need to work within the constraints of the Box2D system (e.g., certain shapes, joints). Simple
Processing gives you more freedom to create custom behaviors, but at the cost of additional effort and less
automatic handling of physical interactions.

• Use Case: Simple Processing is well-suited for simpler, more artistic, or abstract simulations, while Box2D
is ideal for applications that require detailed and realistic physics, such as games or simulations involving
complex objects and interactions.

In conclusion, using Processing with PVectors and forces gives the user full control over the behavior of
objects, but can become cumbersome when managing complex interactions or larger simulations. Box2D provides
a more powerful and realistic approach for handling physics simulations, but it can be more rigid and requires
understanding of the physics engine’s structure.

6. Conclusion
In this lab, I studied a new libraries Box2D and what is it. (Processing for simulating physics-based creatures
with dynamic behaviors). I am able to create more realistic and complex simulations of creature movement,
collisions, and interactions than what could be achieved using simple Processing with PVectors and manual force
applications.
Throughout the lab, I designed creatures using multiple shapes and joints, allowing us to explore the capabil-
ities of Box2D for creating a simple boy with hairs who fly through black hole. The use of physical properties
such as density, and restitution enabled our creatures to react naturally to gravity, forces, and collisions, offering
an engaging and interactive experience.
The ability to multiply creatures and simulate interactions. How I add my simple boys. I initialize the array and
using the add function I add them and when they collide with white stars I remove it from the list so it disappears
PolygonShape how do I create it? I customized it and create it using a dictionary. I can add sides by passing
the parameters of the point where it should be located to the dictionary.
In conclusion, I understood how to work with libraries and how to integrate all this into processing. I was also
interested in understanding how to install libraries and how to integrate them into processing (even in two ways).

14

You might also like