Skip to content

Instantly share code, notes, and snippets.

@rjack
Created December 20, 2011 12:41
Show Gist options
  • Save rjack/1501442 to your computer and use it in GitHub Desktop.
Save rjack/1501442 to your computer and use it in GitHub Desktop.
Linear algebra for game developers
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Notes from Linear Algebra for Game Developers Part 1

Vector examples:

Vector examples

  • position
  • velocity
  • direction
  • acceleration
  • ...

Important:

  • keep track of units
    • velocity is in meters/second or in pixels/frame
  • remember the context of the vector
    • (0, 1) is a velocity or a direction?
    • Same vector, different meanings

Example: (3, 5, 2) is a position in meters

Positional vector example

  1. east (3 methers east from the origin)
  2. up (z axis)
  3. north

Negative numbers represent opposite directions (west, down south).

Vector addition

(0,1,4) + (3,-2,5) = (0+3, 1-2, 4+5) = (3,-1,9)

Addition is a component-wise operation.

Useful for: physics integration

loop:
    position += velocity
    velocity += acceleration

Vector subtraction

Useful for getting a vector that points from one position to another.

Distance vector = destination - origin

Vector subtraction example

V1 = rifleman position
V2 = robot position
v3 = laser beam = V2 - V1
<!DOCTYPE html>
<html>
<head>
<title>Linear Algebra for Game Developers Part 1</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas">Your browser doesn't support canvas :(</canvas>
<script type="text/javascript" src="part-1.js"></script>
</body>
</html>
var cnv, ctx, red_chart_cnv, red_chart_ctx, game_loop, Actor, green, red, CANVAS_WIDTH, CANVAS_HEIGHT, FPS, vector_add, balls, actors_num, distance,
_hasProp = Object.prototype.hasOwnProperty,
__extends = function(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
// Configuration
CANVAS_WIDTH = 800;
CANVAS_HEIGHT = 600;
FPS = 1000/13;
// Functions
var vector_add = function (a, b, result) {
if (!result)
result = a;
a[0] = a[0] + b[0];
a[1] = a[1] + b[1];
};
var vector_sub = function (a, b, result) {
if (!result)
result = a;
result[0] = a[0] - b[0];
result[1] = a[1] - b[1];
};
var vector_scalprod = function (v, scalar, result) {
if (!result)
result = v;
result[0] = v[0] * scalar;
result[1] = v[1] * scalar;
};
var vector_prod = function (a, b) {
return a[0] * b[0] + a[1] * b[1];
};
var vector_norm = function (v) {
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
};
// Experimental requestAnimationFrame
// comde from: http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, FPS);
};
})();
// Classes
var Actor = (function () {
function Actor (opts) {
this.position = opts.position || [0, 0];
this.velocity = opts.velocity || [0, 0];
this.acceleration = opts.acceleration || [0, 0];
this.image_src = opts.image_src || "img/none.png";
this.image = new Image();
this.image.src = this.image_src;
this.width = opts.width;
this.height = opts.height;
}
Actor.prototype.accelerate = function (delta_a) {
vector_add(this.acceleration, delta_a);
};
Actor.prototype.update = function () {
vector_add(this.velocity, this.acceleration);
vector_add(this.position, this.velocity);
};
Actor.prototype.draw = function (ctx) {
ctx.drawImage(this.image, this.position[0], this.position[1]);
};
Actor.prototype.plot = function (cnv, ctx) {
var i, len;
ctx.beginPath();
ctx.moveTo(0, cnv.height/2);
len = this.plot_data.length;
for (i = 0; i < len; i++) {
ctx.lineTo(i, Math.floor(cnv.height/2) - Math.floor(this.plot_data[i].velocity[1]));
}
ctx.stroke();
};
Actor.prototype.collision = function (other) {
// No default collision
};
return Actor;
}());
var Ball = (function () {
__extends(Ball, Actor);
function Ball (opts) {
Ball.__super__.constructor.apply(this, arguments);
}
// TODO: implement cirleCollision and move this to boxCollision
Ball.prototype.collision = function (other) {
var x1, y1, x2, y2;
x1 = this.position[0];
y1 = this.position[1];
x2 = other.position[0];
y2 = other.position[1];
if (x1 + this.width < x2)
return false;
if (y1 + this.height < y2)
return false;
if (x1 > x2 + other.width)
return false;
if (y1 > y2 + other.height)
return false;
return true;
};
Ball.prototype.update = function () {
// TODO: update this.acceleration
Ball.__super__.update.apply(this, arguments);
};
return Ball;
}());
// Canvas setup
cnv = document.getElementById('canvas');
ctx = cnv.getContext('2d');
cnv.width = CANVAS_WIDTH;
cnv.height = CANVAS_HEIGHT;
//red_chart_cnv = document.getElementById('red-chart');
//red_chart_ctx = red_chart_cnv.getContext('2d');
//red_chart_cnv.width = CANVAS_WIDTH;
//red_chart_cnv.height = Math.floor(CANVAS_HEIGHT / 2);
//red_chart_ctx.strokeStyle = 'red';
// Player setup
actors = [
new Ball({
position: [700, 100],
velocity: [3, 0],
image_src: "img/red-ball-100px.png",
width: 100,
height: 100
}),
new Ball({
position: [100, 100],
velocity: [3, 0],
image_src: "img/green-ball-100px.png",
width: 100,
height: 100
})
];
actors_num = actors.length;
distance = [];
ctx.strokeStyle = 'orange';
(function loop () {
var i, actor;
requestAnimFrame(loop);
ctx.clearRect(0, 0, cnv.width, cnv.height);
for (i = 0; i < actors_num; i++) {
actor = actors[i];
// Bounce with left/right canvas borders
if (actor.position[0] >= CANVAS_WIDTH - actor.width) {
actor.position[0] = CANVAS_WIDTH - actor.width;
actor.velocity[0] *= -1;
} else if (actor.position[0] < 0) {
actor.position[0] = 0;
actor.velocity[0] *= -1;
}
// Bounce on the ground
if (actor.position[1] >= CANVAS_HEIGHT - actor.height) {
actor.position[1] = CANVAS_HEIGHT - actor.height;
actor.velocity[1] *= -1;
actor.acceleration[1] -= 0.2;
} else {
actor.acceleration[1] = 0.2;
}
actor.update();
actor.draw(ctx);
}
}());
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
body {
background-color: #000;
}
canvas {
border: 1px solid #fff;
display: block;
margin: auto;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment