How it Works?
GyroDodge makes use of javascript's Device Orientation API to move the small white dot around your mobile screen & you can shoot projectiles at the direction you are heading toward by tapping on your screen. also also used p5js in gyrododge for making my life bit more easier
here's the code to get the device orientation of the device
// check if browser supports DeviceOrientationEvent event
if (!window.DeviceOrientationEvent) {
alert("Sorry, your browser doesn't support Device Orientation")
} else {
window.addEventListener("deviceorientation", e => {
let alpha = event.alpha
let beta = event.beta
let gamma = event.gamma
})
}
to move the player in the desired location with these parameters, I add them to the player's acceleration
by using p5.js's Vector
class
window.addEventListener("deviceorientation", e => {
this.tiltLR = e.gamma
this.tiltFB = e.beta
let gyro = createVector(this.tiltLR, this.tiltFB)
// add the force
this.applyForce(gyro)
})
How I created those asteroids?
To create those polygonal asteroids, I created a Rock.js
class, which updates, renders, and generates them.
class Rock {
constructor(x, y, radius) {
this.pos = createVector(x || random(width), y || random(height))
this.vel = p5.Vector.random2D()
this.radius = radius || random(15, 30)
this.vertices = []
this.offsets = []
this.total = random(5, 15)
for (let i = 0; i < this.total; i++) {
this.offsets[i] = random(-5, 5)
}
for (let i = 0; i < this.total; i++) {
let angle = map(i, 0, this.total, 0, TWO_PI)
let r = this.radius + this.offsets[i]
let x = r * cos(angle)
let y = r * sin(angle)
this.vertices.push({ x, y })
}
}
}
In the update method, I added the velocity
to the position
at each frame. I also checked for collision with the boundaries. If the rock hits the wall, then it just bounces back off them.
update() {
this.pos.add(this.vel);
if (this.pos.x > (width + this.radius) || this.pos.x < this.radius) {
this.vel.x *= -1;
}
if (this.pos.y > (height + this.radius) || this.pos.y < this.radius) {
this.vel.y *= -1;
}
}
In render function, I just used p5js's vertex
method to draw the polygonal shape
render() {
noFill();
stroke(255);
beginShape();
for (const v of this.vertices) {
vertex(this.pos.x + v.x, this.pos.y + v.y);
}
endShape(CLOSE);
}
In gyrodoge I also have a game mechanism where if you hit an asteroid it can break into multiple asteroids, here's how it works
breakup() {
let newA = [];
newA[0] = new Rock(this.pos.x, this.pos.y, this.radius * 0.8);
newA[1] = new Rock(this.pos.x, this.pos.y, this.radius * 0.8);
return newA;
}
And that's it, for the Rock.js class.
Particles Class
I also added Particles class which emits particles in a random direction, and it extends the Bullet class
class Particle extends Bullet {
constructor(spos, angle) {
super(spos, angle)
this.vel = p5.Vector.random2D()
this.life = 1
}
render() {
this.vel.y += random(-0.2, 0.2)
push()
stroke(255, this.life * 255)
strokeWeight(2)
point(this.pos.x, this.pos.y)
pop()
}
die() {
this.life -= 0.03
}
}
Bullet Class
In bullet class, there's not much going on just basic stuff
class Bullet {
constructor(spos, angle) {
this.pos = createVector(spos.x, spos.y)
this.vel = p5.Vector.fromAngle(angle)
this.vel.mult(10)
this.angle = angle
}
update() {
this.pos.add(this.vel);
}
render() {
...
}
// checks for hits
hits(target) {
var d = dist(this.pos.x, this.pos.y, target.pos.x, target.pos.y)
if (d < target.radius) {
return true
}
return false
}
// if offscreen we will remove it from the bullet array
offscreen() {
if (this.pos.x > width || this.pos.x < 0) {
return true
}
if (this.pos.y > height || this.pos.y < 0) {
return true
}
return false
}
}
Player Class
In Player class we have some exciting stuff, let's see the constructor first
class Player {
constructor() {
this.pos = createVector(width / 2, height / 2);
this.acc = createVector(0, 0);
this.vel = createVector(0, 0);
this.radius = 8;
this.tiltLR = 0;
this.tiltFB = 0;
this.isUsingKeyboard = false; // is using desktop?
if (!window.DeviceOrientationEvent) {
alert("Sorry, your browser doesn't support Device Orientation")
}
if (!('ontouchstart' in window)) {
this.isUsingKeyboard = true;
window.addEventListener('mousemove', (e) => {
let pos = p5.Vector.sub(this.pos, createVector(e.offsetX, e.offsetY))
this.applyForce(pos)
})
} else {
window.addEventListener('deviceorientation', (e) => {
this.tiltLR = e.gamma;
this.tiltFB = e.beta;
let gyro = createVector(this.tiltLR, this.tiltFB);
this.applyForce(gyro);
});
}
}
As you can see, I initialized the deviceorientation
events and player's position and velocity stuff. The most basic method of the Player class is collidePointPoly
which detects if a point hits a polygon.
collidePointPoly(px, py, target, vertices) {
var collision = false;
// go through each of the vertices, plus the next vertex in the list
var next = 0;
for (var current = 0; current < vertices.length; current++) {
// get next vertex in list if we've hit the end, wrap around to 0
next = current + 1;
if (next == vertices.length) next = 0;
// get the PVectors at our current position this makes our if statement a little cleaner
var vc = vertices[current];
var vn = vertices[next];
let vcy = target.pos.y + vc.y;
let vny = target.pos.y + vn.y;
let vcx = target.pos.x + vc.x;
let vnx = target.pos.x + vn.x;
if (((vcy > py && vny < py) || (vcy < py && vny > py)) &&
(px < (vnx - vcx) * (py - vcy) / (vny - vcy) + vcx)) {
collision = !collision;
}
}
return collision;
}
It's the vital part of the class because it checks if the Player hits any Asteroids (rock), and depending on that, it determines if the game is over or not.
Game Class
Game class is just a state manager for the game, which holds all the variables and state management.
we also have AssetMan class which preloads all the assets for the game (sound effects)
Setting Up
And lastly but not least, we have index.js where I wrote all the necessary game logic and initialization.