Cloth Simulation

Cloth simulation with gravity, wind, and collision detection.

Cloth simulation is a rather complex task to accomplish. For this project specifically, an entire physics engine was built from scratch to simulate gravity, spring movement, and wind motion.

The cloth was built from 2500 particles, each with its own mass, position, and velocity.

typedef struct Particle {

int blocked;
float fMass; // Total mass
Vector vPosition; // Position
Vector vVelocity; // Velocity
float fSpeed; // Speed (magnitude of the velocity)
Vector vForces; // Total force acting on the particle
float fRadius; // Particle radius used for collision detection
Vector vGravity; // Gravity force vector

} Particle;

Each particle is connected to 3 springs, which interconnects all the springs to each other, ultimately creating a 50 x 50 mesh.

The physics engine itself is composed of vector math to calculate surface normals, magnitude, cross products, dot products, and euclidean distances.

i.e.

 float magnitude (Vector v) {

float mag = 0;
float x = pow(v.x,2);
float y = pow(v.y,2);
float z = pow(v.z,2);
float add = x + y + z;
float sqroot = sqrt(add);
return sqroot;

}

/*
* Function that finds the surface normal with 3 particles in space
*/

Vector findSurfaceNormal(Particle p1, Particle p2, Particle p3) {

Vector V;
Vector W;
Vector N;
Vector A;

V = subtractVectors(p2.vPosition,p1.vPosition);
W = subtractVectors(p3.vPosition,p1.vPosition);

N.x = (V.y * W.z) – (V.z * W.y);
N.y = (V.z * W.x) – (V.x * W.z);
N.z = (V.x * W.y) – (V.y * W.x);

return N;

}

Spring forces are calculated with F = -kx and the gravitational pull needs to be adjusted according to how the mesh is set up. It’s very difficult to fine tune each variable.

All spring constants, gravitational pulls, and wind forces need to be applied to each particle in the mesh.

Collision detection is handled at the end of the simulation. We need to consider the distance between the center of the ball and each particle in the cloth. If the distance between the center and the particle is less than or equal to the radius, then we have a collision and the particle must be pushed to the top of the ball.

WormHol3 – GameMaker

Are you ready to travel through a wormhole?

Link to game: https://drive.google.com/file/d/0Bytu2SMne9N9WlZOb05wb1BIOTA/view?pageId=113648142431079282642

I created a game in outer space using GameMaker. I got inspiration from the classic NES 2D side-scroller shooters and the movie Interstellar. I loved the scene in the movie where they travel through the wormhole and a ton of asteroids and bright lights are flying all around them.

Although my game may seem like a typical “scroller/shoot them up” game, Wormhol3 doesn’t have shooting mechanics whatsoever. In fact, the entire game is based around the “dodging” mechanic where you dodge the asteroids approaching you and collect the stars that randomly appear on the screen. The stars are the main source of points. The difficulty rises as you collect more points. The main goal of the game is to reach the end of the wormhole and collect as many points as you can. Yes, this game does have and ending. It is not an endless loop of survival. Wormhol3 did start as an endless loop where you collected as many points as you could before you died, but that changed during game development. The controls are very basic, you just move the spaceship with the arrow keys and hope for the best!

Sadly, nobody has been able to beat this game except for myself. It took me about 200+ tries and a few hours of grinding. The highest score someone other than myself has been able to get is around 70,000, and this is just where the fun starts. This game is absolutely brutal.

Marching Squares

The marching squares algorithm is used to approximate the shape of a 2D object. In this example, we have a variety of balls floating around the screen. The goal is to implement the marching squares algorithm to approximate the shape of each ball and create a blobby effect when the balls collide with each other.

Essentially, we want to create a grid (depending on the size of your screen). The size of each square in the grid will determine how well the shape approximation is displayed (i.e. smaller squares yield tighter approximations).

In order to draw each square, we need to consider how a ball is intersecting it. For instance, each square has 4 corners and the ball can intersect one, two, three, or all four corners. All together, 16 scenarios are possible. Each configuration can be hardcoded and each can be stored in a data structure. Depending which corners are intersected, a specific square will be displayed on the grid.

Now how do we detect when a ball has intersected a square? To answer this question, we need two things: we need to keep track of the position of each square in the grid, and we need the ball’s center (x, y) location at all times. By having these variables, we can determine the square intersection by using euclidean distances.

Key point:

If the square’s corner lies between the center and outer edge of the ball, then the corner has been intersected.

Euclidean distance can be used to find the distance between the ball’s center location and the squares center location (+ or – corner distance) to find whether or not a corner has been intersected.

d = sqrt((x2 – x1)^2 + (y2 – y1)^2)

From here, we can loop the same process for all squares in the grid and all floating balls to create the effect seen above.

Cube Explosion

This cube explosion is achieved by implementing a simple vector struct that requires a x, y, z coordinates and a variable for direction. Each particle in the cube explosion has randomized x, y, z constants which determine the direction in which the particle will travel in a straight line.

i.e.

typedef struct Vector {

float x;
float y;
float z;
int direction;

} Vector;

typedef struct Particle {

Vector vPosition; // Position in space

} Particle;

10,000 particles were used for the explosion and all particles originate at the center of the cube. Particles move at a constant velocity and gradually fade into the darkness over time.