
Fixed level rendering at edges. Fixed clipping through tiles at high speeds. Added more levels. Fixed particle collisions. Added mouse click detection. Added particle spawning on mouse click. Added water. Added death with animation. Particles and actors now only render when on screen and only run when within 2000 pixels. Added speed multiplier to movement, you can now play with a low frame rate. Added sound with option for it in main menu. Particles get pushed away if you go near them. Added enemy that goes back and forth and spawns with the level. Added xvel and yvel monitors. Added blur to menu title. Changed credits. Removed loader. Other minor changes.
879 lines
No EOL
24 KiB
JavaScript
879 lines
No EOL
24 KiB
JavaScript
window.onload = function(){
|
||
canvas = document.getElementById('game');
|
||
context = canvas.getContext('2d');
|
||
canvas.style.display = 'block'; // Set up canvas
|
||
canvas.style.border = '1px solid #ddd';
|
||
canvas.style.background = '#fff'; // Set canvas style
|
||
canvas.style.margin = (window.innerHeight > 360 ? window.innerHeight / 2 - 180 + 'px auto' : '10px auto');
|
||
start();
|
||
};
|
||
|
||
window.requestAnimFrame = (function(){
|
||
return window.requestAnimationFrame ||
|
||
window.webkitRequestAnimationFrame ||
|
||
window.mozRequestAnimationFrame ||
|
||
window.oRequestAnimationFrame ||
|
||
window.msRequestAnimationFrame ||
|
||
function(callback, element){
|
||
window.setTimeout(callback, 1000 / 60);
|
||
};
|
||
})();
|
||
|
||
function start(){
|
||
reset();
|
||
}
|
||
|
||
// Get mouse position
|
||
function getMouse(evt) {
|
||
var rect = canvas.getBoundingClientRect();
|
||
return {
|
||
x: evt.clientX - rect.left,
|
||
y: evt.clientY - rect.top,
|
||
click: false
|
||
};
|
||
}
|
||
|
||
// Set up variables
|
||
function reset(){
|
||
// Create arrays
|
||
actors = [];
|
||
controllers = [];
|
||
particles = [];
|
||
camera = [];
|
||
ais = [];
|
||
keys = [];
|
||
test = [];
|
||
level = ['','','','','','','','','','','','','','','','','','','',''];
|
||
partsInserted = [];
|
||
optionvars = [50, 50];
|
||
mouse = {
|
||
x: 0,
|
||
y: 0,
|
||
down: false,
|
||
click: false
|
||
};
|
||
slow = false;
|
||
sound = {
|
||
shoot1: new Audio('sfx.wav'),
|
||
jump: new Audio('Funk.mp3'),
|
||
lol: new Audio('lol.mp3')
|
||
}
|
||
game = 'menu';
|
||
ui = {
|
||
select : 0,
|
||
area : 0
|
||
}
|
||
menu = [
|
||
[
|
||
['Singleplayer', 2, true],
|
||
['Multiplayer', 3, true],
|
||
['Options', 1, true],
|
||
['Credits', 4, true]
|
||
],
|
||
[
|
||
['Music', 's', 0, 0, 100, false],
|
||
['Sound', 's', 1, 0, 100, false],
|
||
['Back', 0, true]
|
||
],
|
||
['r', 'play'],
|
||
['r', 'play'],
|
||
['t', 'Sint', '', 'Programming and graphics by Asraelite', 'Sound from a source that does not deserve credit']
|
||
]
|
||
lastspeed = 0;
|
||
|
||
|
||
//controllers[1] = new Controller(actors[2], [[39, 'moveRight'], [37, 'moveLeft'], [38, 'jump'], [88, 'camera'], [78, 'bounce', 100]]);
|
||
|
||
// type, affiliation, lifespan, xpos, ypos, xvel, yvel
|
||
particles[0] = new Particle('mouse', 0, 10000000000, 0, 0, 0, 0);
|
||
defineLevels(); // Call function to create level variables
|
||
//level = 2 // Set level
|
||
spritesheet = new Image(); // Define spritesheet
|
||
spritesheet.src = 'actors.png';
|
||
document.addEventListener('keydown', keyDown, true); // Add key events
|
||
document.addEventListener('keyup', keyUp, true);
|
||
document.addEventListener('mousemove', function(evt){mouse.x = getMouse(evt).x; mouse.y = getMouse(evt).y}, false);
|
||
document.addEventListener('mousedown', function(evt){mouse.down = true}, false);
|
||
document.addEventListener('mouseup', function(evt){mouse.down = false}, false);
|
||
animate();
|
||
}
|
||
|
||
function play(){
|
||
// Create player and its key controller
|
||
actors[0] = new Actor(0, 'player', 200, 3, 128, 64, 16, 16);
|
||
controllers[0] = new Controller(actors[0], [[68, 'moveRight'], [65, 'moveLeft'], [87, 'jump'], [67, 'camera'], /*[69, 'stream', 100]*/, [81, 'suicide']]);
|
||
|
||
actors[1] = new Actor(6, 'all', 200, 3, 256, 64, 16, 16);
|
||
ais[0] = new Ai(1, 'pace');
|
||
|
||
camera = [actors[0]]; // Set camera.
|
||
}
|
||
|
||
function animate() {
|
||
requestAnimFrame(animate);
|
||
loopGame();
|
||
}
|
||
|
||
// Modified from W3C
|
||
function readFile() {
|
||
var file = document.getElementById('file').files[0];
|
||
if(file){
|
||
getAsText(file);
|
||
}
|
||
}
|
||
|
||
function getAsText(readFile) {
|
||
|
||
var reader = new FileReader();
|
||
|
||
// Read file into memory as UTF-16
|
||
reader.readAsText(readFile, "UTF-16");
|
||
|
||
// Handle progress, success, and errors
|
||
reader.onprogress = updateProgress;
|
||
reader.onload = loaded;
|
||
reader.onerror = errorHandler;
|
||
}
|
||
|
||
// Round a number.
|
||
function r(num){
|
||
return Math.round(num);
|
||
}
|
||
|
||
function setStrChar(string , index, letter) {
|
||
if(index > string.length-1){
|
||
return string;
|
||
}
|
||
return string.substr(0, index) + letter + string.substr(index + 1);
|
||
}
|
||
|
||
// Generate random number from seed (not used)
|
||
function seed(num){
|
||
return ((num * 467 + ((num * 6) % 9)) % 1000) / 1000;
|
||
}
|
||
|
||
// Add key pressed to key list.
|
||
function keyDown(e){
|
||
var keyPress;
|
||
if (typeof event !== 'undefined') {
|
||
keyPress = event.keyCode;
|
||
}else if(e){
|
||
keyPress = e.which;
|
||
}
|
||
if(keys.indexOf(keyPress) == -1){
|
||
keys.push(keyPress);
|
||
}
|
||
}
|
||
|
||
// Remove key from key list.
|
||
function keyUp(e){
|
||
var keyPress;
|
||
if (typeof event !== 'undefined') {
|
||
keyPress = event.keyCode;
|
||
}else if(e){
|
||
keyPress = e.which;
|
||
}
|
||
keys.splice(keys.indexOf(keyPress), 1);
|
||
}
|
||
|
||
// Define objects.
|
||
|
||
function Controller(object, actions){
|
||
this.actor = object;
|
||
this.checkKeys = function(){
|
||
for(i in actions){
|
||
if(keys.indexOf(actions[i][0]) > -1){
|
||
this.actor.action(actions[i][1]);
|
||
}
|
||
if(mouse.click && actions[i][0] == 'c'){
|
||
this.actor.action(actions[i][1]);
|
||
}
|
||
}
|
||
this.actor.refreshActions();
|
||
}
|
||
}
|
||
|
||
function Ai(index, ai){
|
||
this.index = index;
|
||
this.actor = actors[index];
|
||
this.aivars = [0, 0, 0];
|
||
this.action = function(act){
|
||
this.actor.action(act);
|
||
}
|
||
this.run = function(){
|
||
this.actor = actors[index];
|
||
switch(ai){
|
||
case 'alphaBot': // Work in progress following melee AI
|
||
var playerIndex = -1;
|
||
var topDistance = 400;
|
||
var distanceAway = Math.abs(actors[0].x - this.actor.x);
|
||
if((this.aivars[0] == 0 ? distanceAway > 150 : distanceAway < 200)){
|
||
if(actors[0].x > this.actor.x){
|
||
this.action((this.aivars[0] == 0 ? 'moveRight' : 'moveLeft'));
|
||
}else{
|
||
this.action((this.aivars[0] == 0 ? 'moveLeft' : 'moveRight'));
|
||
}
|
||
if(actors[index].xvel < 0.1){
|
||
this.action('jump');
|
||
}
|
||
actors[index].xvel *= Math.pow(0.995, speed);
|
||
}else{
|
||
|
||
}
|
||
if(Math.random() < 0.03 || this.aivars[2] > 0){
|
||
if(this.aivars[0] == 0){
|
||
this.aivars[2] += 1;
|
||
this.action('dark');
|
||
}else{
|
||
this.aivars[0] -= 1;
|
||
}
|
||
}
|
||
if(this.aivars[2] == 75){
|
||
this.action('jump');
|
||
}
|
||
if(this.aivars[2] > 75 && actors[index].yvel >= 0){
|
||
actors[index].vars = [false, (actors[0].x - this.actor.x) / 15, (actors[0].y - this.actor.y) / 10];
|
||
this.action('shoot');
|
||
}
|
||
if(this.aivars[2] >= 95){
|
||
this.aivars[0] = 10;
|
||
this.aivars[1] = 0;
|
||
this.aivars[2] = 0;
|
||
actors[index].vars = [false, false, false];
|
||
}
|
||
break;
|
||
case 'pace': // Walking back and forth
|
||
if(this.actor.xvel == 0){
|
||
this.aivars[0] = (1 - this.aivars[0]);
|
||
}
|
||
this.action(this.aivars[0] == 0 ? 'moveRight' : 'moveLeft');
|
||
break;
|
||
case 'still':
|
||
break;
|
||
case 'test': // Jumping AI
|
||
this.action('jump');
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Actor class for all solid cubes
|
||
function Actor(image, type, health, power, xpos, ypos, width, height){
|
||
this.image = image;
|
||
this.group = type;
|
||
this.health = health;
|
||
this.power = power;
|
||
this.yvel = 0;
|
||
this.xvel = 0;
|
||
this.imageLoad = 2;
|
||
this.right = this.up = this.down = false;
|
||
this.left = false;
|
||
this.x = xpos;
|
||
this.y = ypos;
|
||
this.w = width;
|
||
this.h = height;
|
||
//this.box = new Box(this.x, this.y, this.w, this.h, this.xvel, this.yvel, ['player', 'pacer'], true); // Set physics class for this actor
|
||
this.box = new Box(this.x, this.y, this.w, this.h, this.xvel, this.yvel, [], true);
|
||
this.oneactions = [];
|
||
this.actionsturn = [];
|
||
this.index = actors.length;
|
||
this.vars = [false, false, false]; // for use by AIs to control particles
|
||
|
||
this.refreshActions = function(){
|
||
this.oneactions = [];
|
||
for(i in this.actionsturn){
|
||
this.oneactions.push(this.actionsturn[i]);
|
||
}
|
||
}
|
||
|
||
// Actions to call from controllers
|
||
this.action = function(type){
|
||
switch(type){
|
||
case 'moveLeft':
|
||
this.xvel -= (0.08 * speed);
|
||
break;
|
||
case 'moveRight':
|
||
this.xvel += (0.08 * speed);
|
||
break;
|
||
case 'jump':
|
||
this.box.y += 1;
|
||
if(this.box.collide() || this.box.inlava){
|
||
this.yvel = (-4 - this.power) * (this.box.inlava ? 0.2 : 1);
|
||
distanceToSound = Math.abs(this.x - lookx - 250);
|
||
if(Math.abs(this.x - lookx) < 300){
|
||
sound.jump.volume = r(((optionvars[1]) / 100) / (distanceToSound < 100 ? 1 : distanceToSound / 50));
|
||
sound.jump.play();
|
||
}
|
||
}
|
||
this.box.y -= 1;
|
||
break;
|
||
case 'melee':
|
||
this.yvel = 10;
|
||
break;
|
||
case 'camera':
|
||
camera = [this];
|
||
break;
|
||
case 'stream':
|
||
var angle = Math.atan2((this.y) - mouse.y, mouse.x - (this.x - lookx));
|
||
particles.push(new Particle(0, 0, 9000, this.x + 8, this.y - 8, Math.sin(angle) * 15, Math.cos(angle) * 15));
|
||
sound.shoot1.volume = r(optionvars[1]) / 100;
|
||
sound.shoot1.play();
|
||
break;
|
||
case 'bounce':
|
||
particles.push(new Particle(1, 0, 5000, this.x, this.y - 1, this.xvel * 2 + ((Math.random() - 0.5) * 5), 1));
|
||
break;
|
||
case 'flo':
|
||
particles.push(new Particle(2, 0, 100000, this.x, this.y - 16, this.xvel * 4 + ((Math.random() - 0.5) * 10), -10));
|
||
break;
|
||
case 'dark':
|
||
particles.push(new Particle(3, this.index, 3000, this.x + (Math.random() * 16), this.y - (Math.random() * 16), this.xvel, this.yvel));
|
||
this.vars = [false, false, false]
|
||
break;
|
||
case 'shoot':
|
||
this.vars = [true, this.vars[1], this.vars[2]];
|
||
break;
|
||
case 'suicide':
|
||
this.health = (this.y > -50 ? 0 : this.health);
|
||
break;
|
||
}
|
||
this.actionsturn.push(type);
|
||
}
|
||
|
||
this.simulate = function(){
|
||
this.box.xvel = this.xvel;
|
||
this.box.yvel = this.yvel;
|
||
this.box.x = this.x;
|
||
this.box.y = this.y;
|
||
this.box.health = this.health;
|
||
this.box.run();
|
||
this.x = this.box.x;
|
||
this.y = this.box.y;
|
||
this.xvel = this.box.xvel;
|
||
this.yvel = this.box.yvel;
|
||
this.health = this.box.health;
|
||
if(this.health <= 0){
|
||
this.health = 200;
|
||
for(i = 0; i < 64; i++){
|
||
particles.push(new Particle(0, 0, Math.random() * 500 + 2500, this.x + ((i % 8) * 2), this.y - ((i % 8) * 2), (Math.random() - 0.5) * 10, (Math.random() - 0.8) * 10));
|
||
}
|
||
this.y = -500;
|
||
}
|
||
//this.xvel *= Math.pow(0.992, speed);
|
||
}
|
||
|
||
this.draw = function(){
|
||
var reflect = 100; // Depth reflection goes before fading completely
|
||
var drawx = r(this.x - lookx + this.xvel);
|
||
var drawy = 200;
|
||
context.drawImage(spritesheet, this.image * 16, 16, 16, 16, drawx, r(this.y - 16 - looky), this.w, this.h);
|
||
context.globalAlpha = 1;
|
||
//context.drawImage(spritesheet, this.image * 16, 16, 16, 16, drawx, r((216 - (this.y - 216)) - looky), 16, 16);
|
||
// StartX, StartY, EndX, EndY
|
||
var gradient = context.createLinearGradient(drawx, r((216 - this.y + 216) - looky - 5), drawx, r((214 - (this.y - 216)) - looky) + 16);
|
||
gradient.addColorStop(0.1, 'rgba(255, 255, 255, ' + (this.y < 120 ? 1 : ((200 - this.y) / 35) + 0.2) +')');
|
||
gradient.addColorStop(0.9, 'rgba(255, 255, 255, 1)');
|
||
context.fillStyle = gradient;
|
||
//context.fillRect(drawx, r((216 - (this.y - 216)) - looky), 16, 16);
|
||
}
|
||
}
|
||
|
||
function Particle(type, affiliation, lifespan, xpos, ypos, xvel, yvel, gravity){
|
||
this.gravity = typeof gravty !== 'undefined' ? gravity : true;
|
||
this.x = xpos;
|
||
this.y = ypos;
|
||
this.xvel = xvel;
|
||
this.yvel = yvel;
|
||
this.type = type;
|
||
this.life = lifespan;
|
||
this.size = [3, 5, 7, 5][type];
|
||
this.created = this.timeup = new Date();
|
||
this.timeup = new Date(this.timeup.getTime() + lifespan);
|
||
this.deleteme = false;
|
||
this.aff = affiliation;
|
||
this.vars = [false, false];
|
||
var angle = Math.random() * 360;
|
||
this.addx = Math.sin(angle) * ((particles.length + 200) / 5);
|
||
this.addy = Math.cos(angle) * ((particles.length + 200) / 10);
|
||
this.box = new Box(this.x, this.y, this.size, this.size, this.xvel, this.yvel, [], gravity);
|
||
this.box.unstuck();
|
||
|
||
this.draw = function(){
|
||
//context.beginPath();
|
||
//context.rect(this.x, this.y, 3, 3);
|
||
if(this.x > lookx - 50 && this.x < lookx + 550 && this.y < 300 && this.y > -50){
|
||
switch(this.type){
|
||
case 'mouse':
|
||
context.globalAlpha = 0.7;
|
||
context.lineWidth = 2;
|
||
context.strokeStyle = '#33d';
|
||
context.strokeRect(mouse.x - this.vars[0] / 2, mouse.y - this.vars[0] / 2, this.vars[0], this.vars[0]);
|
||
break;
|
||
case 0:
|
||
context.globalAlpha = 1;
|
||
context.lineWidth = 1;
|
||
context.strokeStyle = '#66b';
|
||
context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 2, 2);
|
||
break;
|
||
case 1:
|
||
context.globalAlpha = 1;
|
||
context.lineWidth = 2;
|
||
context.strokeStyle = '#b79';
|
||
context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 4, 4);
|
||
break;
|
||
case 2:
|
||
context.globalAlpha = 0.2;
|
||
context.lineWidth = 1;
|
||
context.strokeStyle = '#363';
|
||
context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 5, 5);
|
||
break;
|
||
case 3:
|
||
context.globalAlpha = 0.5;
|
||
context.lineWidth = 1;
|
||
context.strokeStyle = '#000';
|
||
context.strokeRect(r(this.x - lookx) + 0.5, r(this.y - looky) + 0.5, 4, 4);ha = 1;
|
||
}
|
||
context.globalAlpha = 1;
|
||
}
|
||
}
|
||
|
||
this.onGround = function(){
|
||
return false;
|
||
}
|
||
|
||
|
||
this.simulate = function(){
|
||
switch(this.type){
|
||
case 'mouse':
|
||
if(this.vars[0] == false){
|
||
this.vars[0] = 8;
|
||
}
|
||
if(this.vars[1] == true){
|
||
this.vars[0] += 0.4;
|
||
if(this.vars[0] >= 10){
|
||
this.vars[1] = false;
|
||
}
|
||
}else{
|
||
this.vars[0] -= 0.4;
|
||
if(this.vars[0] <= 7){
|
||
this.vars[1] = true;
|
||
}
|
||
}
|
||
this.x = lookx;
|
||
if(mouse.down){
|
||
particles.push(new Particle(0, 0, 9000, lookx + mouse.x, mouse.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5));
|
||
}
|
||
break;
|
||
default:
|
||
for(j in actors){
|
||
if(Math.abs(this.x - (actors[j].x + 8)) < 20 && Math.abs(this.y - (actors[j].y + 8)) < 20){
|
||
this.xvel += (20 - Math.abs(this.x - (actors[j].x + 8))) / (this.x > (actors[j].x + 8) ? 5 : -5);
|
||
this.yvel += (20 - Math.abs(this.y - (actors[j].y + 8))) / (this.y > (actors[j].y + 8) ? 5 : -5);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
if(thisLoop > this.timeup){
|
||
this.deleteme = true;
|
||
}
|
||
this.box.xvel = this.xvel;
|
||
this.box.yvel = this.yvel;
|
||
this.box.x = this.x;
|
||
this.box.y = this.y + 16;
|
||
this.box.run();
|
||
this.x = this.box.x;
|
||
this.y = this.box.y - 16;
|
||
this.xvel = this.box.xvel;
|
||
this.yvel = this.box.yvel;
|
||
}
|
||
}
|
||
|
||
// Collision detection class
|
||
function Box(x, y, w, h, xvel, yvel, colgroup, gravity){
|
||
this.x = x;
|
||
this.y = y;
|
||
this.width = w;
|
||
this.height = h;
|
||
this.col = colgroup;
|
||
this.right = false;
|
||
this.left = false;
|
||
this.up = false;
|
||
this.down = false;
|
||
this.gravity = gravity;
|
||
this.health = 0;
|
||
this.inlava = false;
|
||
|
||
this.reset = function(){
|
||
this.right = false;
|
||
this.left = false;
|
||
this.up = false;
|
||
if(!this.inlava){
|
||
this.down = false;
|
||
}
|
||
}
|
||
|
||
this.collide = function(){
|
||
// Check for collision with level
|
||
var lv = level;
|
||
var colareax = ((this.width - 2) >> 4) + 2;
|
||
var colareay = ((this.height - 2) >> 4) + 2;
|
||
var collision = false;
|
||
var type = 'level';
|
||
this.inlava = false;
|
||
test = [];
|
||
for(var hr = 0; hr < colareax; hr++){
|
||
for(var vr = 0; vr < colareay; vr++){
|
||
var xcol = (((this.x - (hr == colareax - 1 ? 1 + 16 - (((this.width - 1) % 16) + 1): 0)) >> 4) + hr);
|
||
var ycol = (((this.y - (vr == colareay - 1 ? 1 + 16 - (((this.height - 1) % 16) + 1) : 0)) >> 4) + vr);
|
||
if(ycol - 1 >= 0 && ycol <= lv.length){
|
||
if(xcol >= 0 && xcol < lv[ycol].length){
|
||
if(lv[ycol - 1][xcol] == '#'){
|
||
collision = true;
|
||
}else if(lv[ycol - 1][xcol] == 'x'){
|
||
this.health -= 0.01 * speed;
|
||
this.inlava = true;
|
||
this.xvel *= Math.pow(0.997, speed);
|
||
this.yvel *= Math.pow(0.997, speed);
|
||
}else if(lv[ycol - 1][xcol] == 'w'){
|
||
this.inlava = true;
|
||
this.xvel *= Math.pow(0.999, speed);
|
||
this.yvel *= Math.pow(0.999, speed);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for(j in actors){
|
||
var obj = actors[j];
|
||
if(this.y < obj.y + obj.h && this.y + obj.h > obj.y && this.x + obj.w > obj.x && this.x < obj.x + obj.w && obj.box != this){
|
||
collision = true;
|
||
}
|
||
}
|
||
|
||
return collision;
|
||
}
|
||
|
||
this.move = function(){
|
||
if(!this.inlava){
|
||
this.down = false;
|
||
}
|
||
var apparentVel = (this.xvel * speed) / (1000 / 60);
|
||
var velToKill = Math.abs(apparentVel)
|
||
var maxMove = Math.floor(this.width / 2);
|
||
while(velToKill > 0){ // If velocity is more than half the box size, only move in increments of half box size to prevent clipping
|
||
if(velToKill > maxMove){
|
||
this.x += (this.xvel > 0 ? maxMove : -maxMove);
|
||
velToKill -= maxMove;
|
||
}else{
|
||
this.x += (this.xvel > 0 ? velToKill : -velToKill);
|
||
velToKill = 0;
|
||
}
|
||
if(this.collide() && Math.abs(this.xvel) > 0){
|
||
this.x = ((this.x >> 4) << 4) + (this.xvel > 0 ? 16 - (((this.width - 1) % 16) + 1) : 16);
|
||
this.xvel = 0;
|
||
velToKill = 0;
|
||
}
|
||
}
|
||
|
||
var apparentVel = (this.yvel * speed) / (1000 / 60);
|
||
var velToKill = Math.abs(apparentVel);
|
||
var maxMove = Math.floor(this.height / 2);
|
||
while(velToKill > 0){
|
||
if(velToKill > maxMove){
|
||
this.y += (this.yvel > 0 ? maxMove : -maxMove);
|
||
velToKill -= maxMove;
|
||
}else{
|
||
this.y += (this.yvel > 0 ? velToKill : velToKill * -1);
|
||
velToKill = 0;
|
||
|
||
}
|
||
if(this.collide()){
|
||
this.y = ((this.y >> 4) << 4) + (this.yvel > 0 ? 16 - (((this.height - 1) % 16) + 1) : 16);
|
||
if(this.yvel < 0){
|
||
this.down = true;
|
||
}
|
||
this.yvel = 0;
|
||
velToKill = 0;
|
||
}
|
||
}
|
||
|
||
if(this.collide()){
|
||
this.unstuck(5000);
|
||
}
|
||
|
||
this.reset();
|
||
|
||
}
|
||
|
||
this.unstuck = function(limit){
|
||
var j = 0;
|
||
var originalx = this.x;
|
||
var originaly = this.y;
|
||
while(this.collide() && j < limit){
|
||
this.x = r(originalx + (Math.sin(Math.PI * 2 * ((j % 16) / 16)) * (j / 4)));
|
||
this.y = r(originaly + (Math.cos(Math.PI * 2 * ((j % 16) / 16)) * (j / 4)));
|
||
j++;
|
||
}
|
||
if(j >= limit){
|
||
this.x = originalx;
|
||
this.y = originaly;
|
||
}
|
||
}
|
||
|
||
this.run = function(){
|
||
this.y += 1;
|
||
if(this.collide() == false && this.gravity){
|
||
this.yvel += 0.025 * speed;
|
||
}
|
||
this.y -= 1;
|
||
this.xvel *= Math.pow(0.99, speed);
|
||
if(!this.gravity){
|
||
this.yvel *= Math.pow(0.99, speed);
|
||
}
|
||
this.move();
|
||
}
|
||
}
|
||
|
||
// Run game.
|
||
|
||
var speed;
|
||
var lastLoop = new Date();
|
||
var thisLoop = lastLoop;
|
||
function loopGame(){
|
||
canvas.style.margin = (window.innerHeight > 360 ? window.innerHeight / 2 - 180 + 'px auto' : '10px auto');
|
||
lastLoop = thisLoop;
|
||
thisLoop = new Date();
|
||
speed = (thisLoop - lastLoop);
|
||
speed = (speed > 50 ? 50 : speed);
|
||
context.clearRect(0, 0, 500, 350);
|
||
lookx = looky = 0;
|
||
looky = -0;
|
||
var maxx = 0;
|
||
for(i in actors){
|
||
if(actors[i].x > maxx){
|
||
maxx = actors[i].x;
|
||
}
|
||
}
|
||
maxx += 1;
|
||
while(level[0].length < maxx){
|
||
partIndex = Math.floor(Math.random() * (levelparts.length - 1)) + 1;
|
||
partFound = false;
|
||
if(partsInserted.length == 0){
|
||
var toInsert = levelparts[0];
|
||
partsInserted.push([false, '5n', 1, 1, 0]);
|
||
partFound = true;
|
||
}else{
|
||
thisPart = levelparts[partIndex];
|
||
if(thisPart[20] == partsInserted[partsInserted.length - 1][1] && (Math.random() * thisPart[24]) < 1){
|
||
partsInserted.push([thisPart[20], thisPart[21], thisPart[22], thisPart[23], thisPart[24]]);
|
||
toInsert = thisPart;
|
||
partFound = true;
|
||
}
|
||
}
|
||
if(partFound){
|
||
for(i = 0; i < 20; i++){
|
||
level[i] += toInsert[i];
|
||
}
|
||
}
|
||
}
|
||
for(i in controllers){
|
||
controllers[i].checkKeys();
|
||
}
|
||
for(i in actors){
|
||
actors[i].simulate();
|
||
}
|
||
for(i in camera){
|
||
lookx += (camera[i] instanceof Array ? camera[i][0] : camera[i].x + camera[i].xvel * 1) - 250;
|
||
// looky += (camera[i] == instanceof Array ? camera[i][1] : camera[i].y) - 175;
|
||
}
|
||
lookx /= camera.length;
|
||
looky /= camera.length;
|
||
|
||
context.globalAlpha = 1;
|
||
context.lineWidth = 1;
|
||
var lv = level;
|
||
for(i = 0; i < lv.length; i++){ // Draw level
|
||
for(j = (lookx > 300 ? r((lookx - 300) / 16) : 0); j < r((lookx + 600) / 16); j++){
|
||
if(lv[i][j] == '#' || lv[i][j] == 'x' || lv[i][j] == 'w'){
|
||
//#efefef
|
||
var edgeTile = false;
|
||
if((j < lv[i].length && j > 0 && i < lv.length - 1 && i > 0)){
|
||
var edgeChecks = [[-1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0]];
|
||
for(k in edgeChecks){
|
||
if(lv[i + edgeChecks[k][0]][j + edgeChecks[k][1]] != '#'){
|
||
edgeTile = true;
|
||
}
|
||
}
|
||
if(edgeTile){
|
||
context.fillStyle = '#ddd';
|
||
}else{
|
||
context.fillStyle = '#eee';
|
||
}
|
||
}
|
||
if(lv[i][j] == 'x'){
|
||
context.fillStyle = '#d77';
|
||
}
|
||
if(lv[i][j] == 'w'){
|
||
context.fillStyle = '#47d';
|
||
}
|
||
context.fillRect((j << 4) - r(lookx), i << 4, 16, 16);
|
||
}else if(lv[i][j] == 'E'){
|
||
actors[actors.length] = new Actor(6, 'all', 200, 3, j << 4, i << 4, 16, 16);
|
||
ais[ais.length] = new Ai(actors.length - 1, 'pace');
|
||
level[i] = setStrChar(level[i], j, '.');
|
||
}
|
||
}
|
||
}
|
||
context.fillStyle = 'rgba(255, 200, 200, 0.7)';
|
||
for(i in test){
|
||
context.fillRect((test[i][0] << 4) - lookx, test[i][1] << 4, 16, 16);
|
||
}
|
||
for(i in actors){
|
||
if(actors[i].x < lookx + 550 && actors[i].x > lookx - 50){
|
||
actors[i].draw();
|
||
}
|
||
}
|
||
context.globalAlpha = 1;
|
||
context.fillStyle = "#444";
|
||
context.font = "10pt Arial";
|
||
context.textAlign = 'left';
|
||
if(game == 'playing'){
|
||
context.fillText('Health: ' + r(camera[0].health), 10, 270);
|
||
context.fillText('X: ' + r(camera[0].x), 10, 290);
|
||
context.fillText('Y: ' + r(camera[0].y), 70, 290);
|
||
context.fillText('Xvel: ' + r(camera[0].xvel * 10) / 10, 10, 310);
|
||
context.fillText('Yvel: ' + r(camera[0].yvel * 10) / 10, 70, 310);
|
||
}else{
|
||
context.fillText('W and S to move', 10, 270);
|
||
context.fillText('Enter to select', 10, 290);
|
||
context.fillText('A and D to change slider value', 10, 310);
|
||
}
|
||
lastspeed = (new Date() % 10 == 0 ? r(1000 / speed) : lastspeed);
|
||
context.fillText('FPS: ' + lastspeed, 10, 20);
|
||
context.textAlign = 'right';
|
||
context.fillText('Sint version α 0.4.2', 490, 310);
|
||
context.fillText(test, 490, 290);
|
||
if(game == 'playing'){
|
||
context.fillText('Actors: ' + actors.length, 490, 20);
|
||
context.fillText('Particles: ' + particles.length, 490, 40);
|
||
}
|
||
for(i in ais){
|
||
if(Math.abs(ais[i].actor.x - lookx) < 2000){
|
||
ais[i].run();
|
||
}
|
||
}
|
||
for(i in particles){
|
||
particles[i].simulate()
|
||
particles[i]. draw()
|
||
if(particles[i].deleteme || particles.length > 3000){
|
||
particles.splice(i, 1);
|
||
i--;
|
||
}
|
||
}
|
||
if(game == 'menu'){
|
||
if(keys.indexOf(83) > -1){
|
||
if(menudown == false){
|
||
menudown = true;
|
||
ui.select += 1;
|
||
}
|
||
}else{
|
||
menudown = false;
|
||
}
|
||
if(keys.indexOf(87) > -1){
|
||
if(menuup == false){
|
||
menuup = true;
|
||
ui.select -= 1;
|
||
}
|
||
}else{
|
||
menuup = false;
|
||
}
|
||
if(keys.indexOf(13) > -1){
|
||
if(menuenter == false){
|
||
menuenter = true;
|
||
if(menu[ui.area][ui.select][2]){
|
||
ui.area = menu[ui.area][ui.select][1];
|
||
ui.select = 0;
|
||
}else if(menu[ui.area][0] == 't'){
|
||
ui.area = 0;
|
||
ui.select = 0;
|
||
}
|
||
}
|
||
}else{
|
||
menuenter = false;
|
||
}
|
||
ui.select = (ui.select + menu[ui.area].length) % menu[ui.area].length;
|
||
context.fillStyle = '69d';
|
||
context.font = '40pt Helvetica';
|
||
context.textAlign = 'center';
|
||
context.shadowColor = '69d';
|
||
context.shadowBlur = 10;
|
||
context.fillText('Sint', 250, 100);
|
||
context.shadowBlur = 0;
|
||
// Main menu
|
||
if(menu[ui.area][0] == 'r'){
|
||
switch(menu[ui.area][1]){
|
||
case 'play':
|
||
play();
|
||
game = 'playing';
|
||
break;
|
||
case 'fractal':
|
||
game = 'test';
|
||
break;
|
||
default:
|
||
ui.area = 0;
|
||
break;
|
||
}
|
||
}else if(menu[ui.area][0] == 't'){
|
||
context.fillStyle = '#78a';
|
||
context.font = '12pt Helvetica';
|
||
for(i = 1; i < menu[ui.area].length; i++){
|
||
context.fillText(menu[ui.area][i], 250, 120 + (20 * i));
|
||
}
|
||
context.fillStyle = '#9bf';
|
||
context.fillRect(150, 150 + (20 * i), 200, 25);
|
||
context.font = '12pt Helvetica';
|
||
context.fillStyle = '#fff';
|
||
context.fillText('Back', 250, 168 + (20 * i));
|
||
}else{
|
||
for(i in menu[ui.area]){
|
||
if(menu[ui.area][i][1] == 's'){
|
||
context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
|
||
context.fillRect(150, 150 + (30 * i), 80, 25);
|
||
context.font = '12pt Helvetica';
|
||
context.fillStyle = (ui.select == i ? '#fff' : '#eef');
|
||
context.fillText(menu[ui.area][i][0], 190, 168 + (30 * i));
|
||
context.fillStyle = '#eee';
|
||
context.strokeStyle = (ui.select == i ? '#cdf' : '#ddf');
|
||
context.fillRect(240, 160 + (30 * i), 110, 5);
|
||
context.strokeRect(240, 160 + (30 * i), 110, 5);
|
||
context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
|
||
context.strokeStyle = (ui.select == i ? '#79f' : '#abf');
|
||
var thisoption = menu[ui.area][i][2];
|
||
var optionaddx = 100 * (optionvars[thisoption] / (menu[ui.area][i][4] - menu[ui.area][i][3]));
|
||
context.strokeRect(240 + optionaddx, 155 + (30 * i), 10, 10);
|
||
context.fillRect(240 + optionaddx, 155 + (30 * i), 10, 10);
|
||
if(ui.select == i){
|
||
if(keys.indexOf(65) > -1 && optionvars[thisoption] > menu[ui.area][i][3]){
|
||
optionvars[thisoption] -= 0.05 * speed;
|
||
}
|
||
if(keys.indexOf(68) > -1 && optionvars[thisoption] < menu[ui.area][i][4]){
|
||
optionvars[thisoption] += 0.05 * speed;
|
||
}
|
||
}
|
||
}else{
|
||
context.fillStyle = (ui.select == i ? '#9bf' : '#cdf');
|
||
context.fillRect(150, 150 + (30 * i), 200, 25);
|
||
context.font = '12pt Helvetica';
|
||
context.fillStyle = (ui.select == i ? '#fff' : '#eef');
|
||
context.fillText(menu[ui.area][i][0], 250, 168 + (30 * i));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// Slow down game to test low framerates
|
||
if(slow){
|
||
for(var j=1; j < 10000000; j++){
|
||
j = j;
|
||
}
|
||
}
|
||
} |