html5 如何实现自动射击,HTML5/Canvas机器人射击游戏

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

"use strict";

//set up canvas

const canvas = document.getElementById('canvas');

const ctx = canvas.getContext("2d");

function setupCanvas() {

canvas.width = window.innerWidth;

canvas.height = window.innerHeight;

ctx.font = "15px Arial";

ctx.lineJoin = 'round';

ctx.lineCap = "round";

}

setupCanvas();

window.onresize = function() {

setupCanvas();

};

//mouse move input

window.onmousemove = function(e) {

mech.getMousePos(e.clientX, e.clientY);

};

//mouse click input

//keyboard input

const keys = [];

document.body.addEventListener("keyup", function(e) {

keys[e.keyCode] = false;

});

document.body.addEventListener("keydown", function(e) {

keys[e.keyCode] = true;

if (keys[84]) { //t = testing mode

if (game.testing) {

game.testing = false;

} else {

game.testing = true;

}

}

});

const stats = new Stats(); //setup stats library to show FPS

stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom

//stats.domElement.style.opacity = '0.5'

// game Object Prototype *********************************************

//*********************************************************************

const gameProto = function() {

this.testing = false; //testing mode: shows wireframe and some variables

//time related vars and methods

this.cycle = 0; //total cycles, 60 per second

this.cyclePaused = 0;

this.lastTimeStamp = 0; //tracks time stamps for measuing delta

this.delta = 0; //measures how slow the engine is running compared to 60fps

this.buttonCD = 0

this.gravityDir = 0;

this.gravityFlip = function() {

if (keys[82] && this.buttonCD < this.cycle) {

this.buttonCD = this.cycle + 30;

//engine.world.gravity.scale = -engine.world.gravity.scale

if (this.gravityDir) {

this.gravityDir = 0;

} else {

this.gravityDir = 1;

}

Matter.Body.setPosition(player, {

x: player.position.x,

y: -player.position.y

})

Matter.Body.setVelocity(player, {

x: player.velocity.x,

y: -player.velocity.y

})

mech.testingMoveLook();

mech.Sy = mech.y

for (let i = 0; i < bullet.length; i++) {

Matter.Body.setPosition(bullet[i], {

x: bullet[i].position.x,

y: -bullet[i].position.y

})

Matter.Body.setVelocity(bullet[i], {

x: bullet[i].velocity.x,

y: -bullet[i].velocity.y

})

}

for (let i = 0; i < body.length; i++) {

Matter.Body.setPosition(body[i], {

x: body[i].position.x,

y: -body[i].position.y

})

Matter.Body.setVelocity(body[i], {

x: body[i].velocity.x,

y: -body[i].velocity.y

})

}

for (let i = 0; i < map.length; i++) {

Matter.Body.setPosition(map[i], {

x: map[i].position.x,

y: -map[i].position.y

})

//Matter.Body.rotate(map[i], Math.PI)

}

for (let i = 0; i < cons.length; i++) {

cons[i].pointA = {

x: cons[i].pointA.x,

y: -cons[i].pointA.y

}

}

//ctx.rotate(this.gravityDir);

//engine.world.gravity.scale = -engine.world.gravity.scale

//this.gravityDir = (this.gravityDir + Math.PI)%(Math.PI*2);

//Matter.Body.setAngle(player, this.gravityDir)

//Matter.Body.rotate(player, Math.PI);

}

};

this.timing = function() {

this.cycle++; //tracks game cycles

//delta is used to adjust forces on game slow down;

this.delta = (engine.timing.timestamp - this.lastTimeStamp) / 16.666666666666;

this.lastTimeStamp = engine.timing.timestamp; //track last engine timestamp

}

this.zoom = 1 / 300;

this.scaleZoom = function() {

if (this.zoom != 1) {

ctx.translate(canvas.width / 2, canvas.height / 2);

ctx.scale(this.zoom, this.zoom);

ctx.translate(-canvas.width / 2, -canvas.height / 2);

}

}

this.keyZoom = function() {

if (keys[187]) { //plus

this.zoom *= 1.01;

} else if (keys[189]) { //minus

this.zoom *= 0.99;

} else if (keys[48]) {

this.zoom = 1;

}

}

this.wipe = function() {

if (this.isPaused) {

ctx.fillStyle = "rgba(255,255,255,0.1)";

ctx.fillRect(0, 0, canvas.width, canvas.height);

} else {

ctx.clearRect(0, 0, canvas.width, canvas.height);

}

}

this.isPaused = false;

this.pause = function() {

if (keys[70] && mech.buttonCD < this.cycle) {

mech.buttonCD = this.cycle + 20;

if (!this.isPaused) {

this.cyclePaused = this.cycle;

this.isPaused = true;

for (let i = 0; i < body.length; i++) {

body[i].pausedVelocity = body[i].velocity; //sleep wipes velocity, so we need to keep track

body[i].pausedVelocityA = body[i].angularVelocity; //sleep wipes velocity, so we need to keep track

Matter.Sleeping.set(body[i], true);

}

for (let i = 0; i < bullet.length; i++) {

bullet[i].pausedVelocity = bullet[i].velocity; //sleep wipes velocity, so we need to keep track

bullet[i].pausedVelocityA = bullet[i].angularVelocity; //sleep wipes velocity, so we need to keep track

Matter.Sleeping.set(bullet[i], true);

}

} else {

this.isPaused = false;

for (let i = 0; i < body.length; i++) {

Matter.Sleeping.set(body[i], false);

Matter.Body.setVelocity(body[i], body[i].pausedVelocity); //return old velocity before pause

Matter.Body.setAngularVelocity(body[i], body[i].angularVelocity)

}

for (let i = 0; i < bullet.length; i++) {

bullet[i].birthCycle += this.cycle - this.cyclePaused; //extends the lifespan of a bullet

Matter.Sleeping.set(bullet[i], false);

if (bullet[i].pausedVelocity) {

Matter.Body.setVelocity(bullet[i], bullet[i].pausedVelocity); //return old velocity before pause

Matter.Body.setAngularVelocity(bullet[i], bullet[i].angularVelocity)

}

}

}

}

}

}

const game = new gameProto();

// player Object Prototype *********************************************

//**********************************************************************

//**********************************************************************

//**********************************************************************

const mechProto = function() {

this.width = 50;

this.radius = 30;

this.stroke = "#333";

this.fill = "#eee";

this.height = 42;

this.yOffWhen = {

crouch: 22,

stand: 49,

jump: 70

}

this.yOff = 70;

this.yOffGoal = 70;

this.onGround = false; //checks if on ground or in air

this.onBody = {};

this.numTouching = 0;

this.crouch = false;

this.isHeadClear = true;

this.spawnPos = {

x: 675,

y: 750

};

this.spawnVel = {

x: 0,

y: 0

};

this.x = this.spawnPos.x;

this.y = this.spawnPos.y;

this.Sy = this.y; //adds a smoothing effect to vertical only

this.Vx = 0;

this.VxMax = 7;

this.Vy = 0;

this.mass = 5;

this.Fx = 0.004 * this.mass; //run Force on ground

this.FxAir = 0.0006 * this.mass; //run Force in Air

this.Fy = -0.04 * this.mass; //jump Force

this.angle = 0;

this.walk_cycle = 0;

this.stepSize = 0;

this.flipLegs = -1;

this.hip = {

x: 12,

y: 24,

};

this.knee = {

x: 0,

y: 0,

x2: 0,

y2: 0

};

this.foot = {

x: 0,

y: 0

};

this.legLength1 = 55;

this.legLength2 = 45;

this.canvasX = canvas.width / 2;

this.canvasY = canvas.height / 2;

this.transX = this.canvasX - this.x;

this.transY = this.canvasX - this.x;

this.mouse = {

x: canvas.width / 3,

y: canvas.height

};

this.getMousePos = function(x, y) {

this.mouse.x = x;

this.mouse.y = y;

};

this.testingMoveLook = function() {

//move

this.x = player.position.x;

this.y = playerBody.position.y - this.yOff;

this.Vx = player.velocity.x;

this.Vy = player.velocity.y;

//look

this.canvasX = canvas.width / 2

this.canvasY = canvas.height / 2

this.transX = this.canvasX - this.x;

this.transY = this.canvasY - this.y;

this.angle = Math.atan2(this.mouse.y - this.canvasY, this.mouse.x - this.canvasX);

}

this.move = function() {

this.x = player.position.x;

//looking at player body, to ignore the other parts of the player composite

this.y = playerBody.position.y - this.yOff;

this.Vx = player.velocity.x;

this.Vy = player.velocity.y;

};

this.look = function() {

//set a max on mouse look

let mX = this.mouse.x;

if (mX > canvas.width * 0.8) {

mX = canvas.width * 0.8;

} else if (mX < canvas.width * 0.2) {

mX = canvas.width * 0.2;

}

let mY = this.mouse.y;

if (mY > canvas.height * 0.8) {

mY = canvas.height * 0.8;

} else if (mY < canvas.height * 0.2) {

mY = canvas.height * 0.2;

}

//set mouse look

this.canvasX = this.canvasX * 0.94 + (canvas.width - mX) * 0.06;

this.canvasY = this.canvasY * 0.94 + (canvas.height - mY) * 0.06;

//set translate values

this.transX = this.canvasX - this.x;

this.Sy = 0.99 * this.Sy + 0.01 * (this.y);

//hard caps how behind y position tracking can get.

if (this.Sy - this.y > canvas.height / 2) {

this.Sy = this.y + canvas.height / 2

} else if (this.Sy - this.y < -canvas.height / 2) {

this.Sy = this.y - canvas.height / 2

}

this.transY = this.canvasY - this.Sy;

//make player head angled towards mouse

this.angle = Math.atan2(this.mouse.y - this.canvasY, this.mouse.x - this.canvasX);

};

this.doCrouch = function() {

if (!this.crouch) {

this.crouch = true;

this.yOffGoal = this.yOffWhen.crouch;

Matter.Body.translate(playerHead, {

x: 0,

y: 40

})

}

}

this.undoCrouch = function() {

this.crouch = false;

this.yOffGoal = this.yOffWhen.stand;

Matter.Body.translate(playerHead, {

x: 0,

y: -40

})

}

this.enterAir = function() {

this.onGround = false;

player.frictionAir = 0.001;

if (this.isHeadClear) {

if (this.crouch) {

this.undoCrouch();

}

this.yOffGoal = this.yOffWhen.jump;

};

}

this.enterLand = function() {

this.onGround = true;

if (this.crouch) {

if (this.isHeadClear) {

this.undoCrouch();

player.frictionAir = 0.12;

} else {

this.yOffGoal = this.yOffWhen.crouch;

player.frictionAir = 0.5;

}

} else {

this.yOffGoal = this.yOffWhen.stand;

player.frictionAir = 0.12;

}

};

this.buttonCD_jump = 0; //cooldown for player buttons

this.keyMove = function() {

if (this.onGround) { //on ground **********************

if (this.crouch) { //crouch

if (!(keys[40] || keys[83]) && this.isHeadClear) { //not pressing crouch anymore

this.undoCrouch();

player.frictionAir = 0.12;

}

} else if (keys[40] || keys[83]) { //on ground && not crouched and pressing s or down

this.doCrouch();

player.frictionAir = 0.5;

} else if ((keys[32] || keys[38] || keys[87]) && this.buttonCD_jump + 20 < game.cycle) { //jump

this.buttonCD_jump = game.cycle; //can't jump until 20 cycles pass

Matter.Body.setVelocity(player, { //zero player velocity for consistant jumps

x: player.velocity.x,

y: 0

});

player.force.y = this.Fy / game.delta; //jump force / delta so that force is the same on game slowdowns

}

//horizontal move on ground

if (keys[37] || keys[65]) { //left or a

if (player.velocity.x > -this.VxMax) {

player.force.x = -this.Fx / game.delta;

}

} else if (keys[39] || keys[68]) { //right or d

if (player.velocity.x < this.VxMax) {

player.force.x = this.Fx / game.delta;

}

}

} else { // in air **********************************

//check for short jumps

if (this.buttonCD_jump + 60 > game.cycle && //just pressed jump

!(keys[32] || keys[38] || keys[87]) && //but not pressing jump key

this.Vy < 0) { // and velocity is up

Matter.Body.setVelocity(player, { //reduce player velocity every cycle until not true

x: player.velocity.x,

y: player.velocity.y * 0.94

});

}

if (keys[37] || keys[65]) { // move player left / a

if (player.velocity.x > -this.VxMax + 2) {

player.force.x = -this.FxAir / game.delta;

}

} else if (keys[39] || keys[68]) { //move player right / d

if (player.velocity.x < this.VxMax - 2) {

player.force.x = this.FxAir / game.delta;

}

}

}

//smoothly move height towards height goal ************

this.yOff = this.yOff * 0.85 + this.yOffGoal * 0.15

};

this.deathCheck = function() {

if (this.y > 4000) { // if player is 4000px deep reset to spawn Position and Velocity

Matter.Body.setPosition(player, this.spawnPos);

Matter.Body.setVelocity(player, this.spawnVel);

this.dropBody();

//this.testingMoveLook(); //updates mech position

//this.Sy = mech.y //moves camera to new position quickly

}

};

this.holdKeyDown = 0;

this.buttonCD = 0; //cooldown for player buttons

this.keyHold = function() { //checks for holding/dropping/picking up bodies

if (this.isHolding) {

//give the constaint more length and less stiffness if it is pulled out of position

const Dx = body[this.holdingBody].position.x - holdConstraint.pointA.x;

const Dy = body[this.holdingBody].position.y - holdConstraint.pointA.y;

holdConstraint.length = Math.sqrt(Dx * Dx + Dy * Dy) * 0.95;

holdConstraint.stiffness = -0.01 * holdConstraint.length + 1;

if (holdConstraint.length > 100) this.dropBody(); //drop it if the constraint gets too long

holdConstraint.pointA = { //set constraint position

x: this.x + 50 * Math.cos(this.angle), //just in front of player nose

y: this.y + 50 * Math.sin(this.angle)

};

if (keys[81]) { // q = rotate the body

body[this.holdingBody].torque = 0.05 * body[this.holdingBody].mass;

}

//look for dropping held body

if (this.buttonCD < game.cycle) {

if (keys[69]) { //if holding e drops

this.holdKeyDown++;

} else if (this.holdKeyDown && !keys[69]) {

this.dropBody(); //if you hold down e long enough the body is thrown

this.throwBody();

}

}

} else if (keys[69]) { //when not holding e = pick up body

this.findClosestBody();

if (this.closest.dist2 < 10000) { //pick up if distance closer then 100*100

this.isHolding = true;

this.holdKeyDown = 0;

this.buttonCD = game.cycle + 20;

body[this.holdingBody].collisionFilter.group = 2; //force old holdingBody to collide with player

this.holdingBody = this.closest.index; //set new body to be the holdingBody

//body[this.closest.index].isSensor = true; //sensor seems a bit inconsistant

body[this.holdingBody].collisionFilter.group = -2; //don't collide with player

body[this.holdingBody].frictionAir = 0.1; //makes the holding body less jittery

holdConstraint.bodyB = body[this.holdingBody];

holdConstraint.length = 0;

holdConstraint.pointA = {

x: this.x + 50 * Math.cos(this.angle),

y: this.y + 50 * Math.sin(this.angle)

};

}

}

};

this.dropBody = function() {

let timer; //reset player collision

function resetPlayerCollision() {

timer = setTimeout(function() {

const dx = mech.x - body[mech.holdingBody].position.x

const dy = mech.y - body[mech.holdingBody].position.y

if (dx * dx + dy * dy > 20000) {

body[mech.holdingBody].collisionFilter.group = 2; //can collide with player

} else {

resetPlayerCollision();

}

}, 100);

}

resetPlayerCollision();

this.isHolding = false;

body[this.holdingBody].frictionAir = 0.01;

holdConstraint.bodyB = jumpSensor; //set on sensor to get the constaint on somethign else

};

this.throwMax = 150;

this.throwBody = function() {

let throwMag = 0;

if (this.holdKeyDown > 20) {

if (this.holdKeyDown > this.throwMax) this.holdKeyDown = this.throwMax;

//scale fire with mass and with holdKeyDown time

throwMag = body[this.holdingBody].mass * this.holdKeyDown * 0.001;

}

body[this.holdingBody].force.x = throwMag * Math.cos(this.angle);

body[this.holdingBody].force.y = throwMag * Math.sin(this.angle);

};

this.isHolding = false;

this.holdingBody = 0;

this.closest = {

dist2: 1000000,

index: 0

};

this.findClosestBody = function() {

this.closest.dist2 = 100000;

for (let i = 0; i < body.length; i++) {

const Px = body[i].position.x - (this.x + 50 * Math.cos(this.angle));

const Py = body[i].position.y - (this.y + 50 * Math.sin(this.angle));

if (body[i].mass < player.mass && Px * Px + Py * Py < this.closest.dist2) {

this.closest.dist2 = Px * Px + Py * Py;

this.closest.index = i;

}

}

};

/* this.forcePoke = function() {

for (var i = 0; i < body.length; i++) {

var Dx = body[i].position.x - (this.mouse.x - this.transX);

var Dy = body[i].position.y - (this.mouse.y - this.transY);

var accel = 0.2 / Math.sqrt(Dx * Dx + Dy * Dy);

if (accel > 0.01) accel = 0.01; //cap accel

accel = accel * body[i].mass //scale with mass

var angle = Math.atan2(Dy, Dx);

body[i].force.x -= accel * Math.cos(angle);

body[i].force.y -= accel * Math.sin(angle);

}

}; */

this.drawLeg = function(stroke) {

ctx.save();

ctx.scale(this.flipLegs, 1); //leg lines

ctx.strokeStyle = stroke;

ctx.lineWidth = 7;

ctx.beginPath();

ctx.moveTo(this.hip.x, this.hip.y);

ctx.lineTo(this.knee.x, this.knee.y);

ctx.lineTo(this.foot.x, this.foot.y);

ctx.stroke();

//toe lines

ctx.lineWidth = 4;

ctx.beginPath();

ctx.moveTo(this.foot.x, this.foot.y);

ctx.lineTo(this.foot.x - 15, this.foot.y + 5);

ctx.moveTo(this.foot.x, this.foot.y);

ctx.lineTo(this.foot.x + 15, this.foot.y + 5);

ctx.stroke();

//hip joint

ctx.strokeStyle = this.stroke;

ctx.fillStyle = this.fill;

ctx.lineWidth = 2;

ctx.beginPath();

ctx.arc(this.hip.x, this.hip.y, 11, 0, 2 * Math.PI);

ctx.fill();

ctx.stroke();

//knee joint

ctx.beginPath();

ctx.arc(this.knee.x, this.knee.y, 7, 0, 2 * Math.PI);

ctx.fill();

ctx.stroke();

//foot joint

ctx.beginPath();

ctx.arc(this.foot.x, this.foot.y, 6, 0, 2 * Math.PI);

ctx.fill();

ctx.stroke();

ctx.restore();

};

this.calcLeg = function(cycle_offset, offset) {

this.hip.x = 12 + offset;

this.hip.y = 24 + offset;

//stepSize goes to zero if Vx is zero or not on ground (make this transition cleaner)

//changes to stepsize are smoothed by adding only a percent of the new value each cycle

this.stepSize = 0.9 * this.stepSize + 0.1 * (8 * Math.sqrt(Math.abs(this.Vx)) * this.onGround);

const stepAngle = 0.037 * this.walk_cycle + cycle_offset;

this.foot.x = 2 * this.stepSize * Math.cos(stepAngle) + offset;

this.foot.y = offset + this.stepSize * Math.sin(stepAngle) + this.yOff + this.height;

const Ymax = this.yOff + this.height;

if (this.foot.y > Ymax) this.foot.y = Ymax;

//calculate knee position as intersection of circle from hip and foot

const d = Math.sqrt((this.hip.x - this.foot.x) * (this.hip.x - this.foot.x) +

(this.hip.y - this.foot.y) * (this.hip.y - this.foot.y));

const l = (this.legLength1 * this.legLength1 - this.legLength2 * this.legLength2 + d * d) / (2 * d);

const h = Math.sqrt(this.legLength1 * this.legLength1 - l * l);

this.knee.x = l / d * (this.foot.x - this.hip.x) - h / d * (this.foot.y - this.hip.y) + this.hip.x + offset;

this.knee.y = l / d * (this.foot.y - this.hip.y) + h / d * (this.foot.x - this.hip.x) + this.hip.y;

};

this.draw = function() {

ctx.fillStyle = this.fill;

if (this.mouse.x > canvas.width / 2) {

this.flipLegs = 1;

} else {

this.flipLegs = -1;

}

this.walk_cycle += this.flipLegs * this.Vx;

//draw body

ctx.save();

// if(game.gravityDir){

// ctx.scale(1, -1);

// //ctx.translate(0,-1.5*canvas.height)

// ctx.translate(this.x, -this.y-this.yOff-this.height);

// } else{

// ctx.translate(this.x, this.y);

// }

ctx.translate(this.x, this.y);

this.calcLeg(Math.PI, -3);

this.drawLeg('#444');

this.calcLeg(0, 0);

this.drawLeg('#333');

ctx.rotate(this.angle);

ctx.strokeStyle = this.stroke;

ctx.lineWidth = 2;

//ctx.fillStyle = this.fill;

let grd = ctx.createLinearGradient(-30, 0, 30, 0);

grd.addColorStop(0, "#bbb");

grd.addColorStop(1, "#fff");

ctx.fillStyle = grd;

ctx.beginPath();

//ctx.moveTo(0, 0);

ctx.arc(0, 0, 30, 0, 2 * Math.PI);

ctx.arc(15, 0, 4, 0, 2 * Math.PI);

ctx.fill();

ctx.stroke();

ctx.restore();

//draw holding graphics

if (this.isHolding) {

if (this.holdKeyDown > 20) {

if (this.holdKeyDown > this.throwMax) {

ctx.strokeStyle = 'rgba(255, 0, 255, 0.8)';

} else {

ctx.strokeStyle = 'rgba(255, 0, 255, ' + (0.2 + 0.4 * this.holdKeyDown / this.throwMax) + ')';

}

} else {

ctx.strokeStyle = 'rgba(0, 255, 255, 0.2)';

}

ctx.lineWidth = 10;

ctx.beginPath();

ctx.moveTo(holdConstraint.bodyB.position.x + Math.random() * 2,

holdConstraint.bodyB.position.y + Math.random() * 2);

ctx.lineTo(this.x + 15 * Math.cos(this.angle), this.y + 15 * Math.sin(this.angle));

//ctx.lineTo(holdConstraint.pointA.x,holdConstraint.pointA.y);

ctx.stroke();

}

};

this.info = function() {

let line = 80;

ctx.fillStyle = "#000";

ctx.fillText("Press T to exit testing mode", 5, line);

line += 30;

ctx.fillText("cycle: " + game.cycle, 5, line);

line += 20;

ctx.fillText("delta: " + game.delta.toFixed(6), 5, line);

line += 20;

ctx.fillText("mX: " + (this.mouse.x - this.transX).toFixed(2), 5, line);

line += 20;

ctx.fillText("mY: " + (this.mouse.y - this.transY).toFixed(2), 5, line);

line += 20;

ctx.fillText("x: " + this.x.toFixed(0), 5, line);

line += 20;

ctx.fillText("y: " + this.y.toFixed(0), 5, line);

line += 20;

ctx.fillText("Vx: " + this.Vx.toFixed(2), 5, line);

line += 20;

ctx.fillText("Vy: " + this.Vy.toFixed(2), 5, line);

line += 20;

ctx.fillText("Fx: " + player.force.x.toFixed(3), 5, line);

line += 20;

ctx.fillText("Fy: " + player.force.y.toFixed(3), 5, line);

line += 20;

ctx.fillText("yOff: " + this.yOff.toFixed(1), 5, line);

line += 20;

ctx.fillText("mass: " + player.mass.toFixed(1), 5, line);

line += 20;

ctx.fillText("onGround: " + this.onGround, 5, line);

line += 20;

ctx.fillText("crouch: " + this.crouch, 5, line);

line += 20;

ctx.fillText("isHeadClear: " + this.isHeadClear, 5, line);

line += 20;

ctx.fillText("HeadIsSensor: " + headSensor.isSensor, 5, line);

line += 20;

ctx.fillText("frictionAir: " + player.frictionAir.toFixed(3), 5, line);

line += 20;

ctx.fillText("stepSize: " + this.stepSize.toFixed(2), 5, line);

line += 20;

ctx.fillText("zoom: " + game.zoom.toFixed(4), 5, line);

line += 20;

ctx.fillText("on body id: " + this.onBody, 5, line);

};

};

const mech = new mechProto();

//bullets**************************************************************

//*********************************************************************

//*********************************************************************

//*********************************************************************

const bullet = [];

//mouse click events

window.onmousedown = function(e) {

game.mouseDown = true;

};

window.onmouseup = function(e) {

game.mouseDown = false;

};

function fireBullet(type) {

const len = bullet.length;

//bullet[len] = Bodies.polygon(e.x - mech.transX, e.y- mech.transY, 5, 5);

const dist = 15 //radial distance mech head

const dir = (Math.random() - 0.5) * 0.1 + mech.angle

//spawn as a rectangle

bullet[len] = Bodies.rectangle(mech.x + dist * Math.cos(mech.angle), mech.y + dist * Math.sin(mech.angle), 10, 3, {

angle: dir,

//density: 0.001,

//friction: 0.05,

frictionAir: 0,

//frictionStatic: 0.2,

restitution: 0.25,

//sleepThreshold: 30, //bullets despawn on sleep after __ cycles

collisionFilter: {

group: -2 //can't collide with player (at first)

}

});

//fire polygons

// bullet[len] = Bodies.polygon(mech.x + dist*Math.cos(mech.angle), mech.y + dist*Math.sin(mech.angle),5, 5,{

// angle: Math.random(),

// collisionFilter: {group: -2 }

// );

//fire circles

//bullet[len] = Bodies.circle(mech.x + dist*Math.cos(mech.angle), mech.y + dist*Math.sin(mech.angle), 3,{ restitution: 0.5, sleepThreshold: 15, collisionFilter: { group: -2 }});

bullet[len].birthCycle = game.cycle;

bullet[len].blankfunc = function() { //blank functino for later

}

//bullet velocity in direction of player plus player velocity

// Matter.Body.setVelocity(bullet[len], {

// x: mech.Vx + vel * Math.cos(dir),

// y: mech.Vy + vel * Math.sin(dir)

// });

Matter.Body.setVelocity(bullet[len], {

x: mech.Vx,

y: mech.Vy

});

//add force to fire bullets

const vel = 0.0025;

const f = {

x: vel * Math.cos(dir) / game.delta,

y: vel * Math.sin(dir) / game.delta

}

bullet[len].force = f;

//equal but opposite force on player

player.force.x -= f.x;

player.force.y -= f.y;

World.add(engine.world, bullet[len]); //add bullet to world

}

let fireBulletCD = 0;

function bulletLoop() {

//fire check

//if (game.mouseDown && !(game.cycle % 2) && !game.isPaused) {

if (game.mouseDown && fireBulletCD < game.cycle && !game.isPaused) {

fireBulletCD = game.cycle + 5;

fireBullet();

}

//all bullet loop

let i = bullet.length;

while (i--) {

//soon after spawn bullets can collide with player

//this may need to be removed

if (bullet[i].birthCycle + 5 < game.cycle) {

bullet[i].collisionFilter.group = 1;

}

//bullets despawn if the sleep or if they fall down or after some cycles

//if (bullet[i].isSleeping || bullet[i].birthCycle + 360 < game.cycle) {

if (bullet[i].birthCycle + 200 < game.cycle && !game.isPaused) {

Matter.World.remove(engine.world, bullet[i]);

bullet.splice(i, 1);

}

}

}

//matter.js ***********************************************************

//*********************************************************************

//*********************************************************************

//*********************************************************************

//*********************************************************************

// module aliases

const Engine = Matter.Engine,

World = Matter.World,

Events = Matter.Events,

Composites = Matter.Composites,

Composite = Matter.Composite,

Constraint = Matter.Constraint,

Vertices = Matter.Vertices,

Query = Matter.Query,

Body = Matter.Body,

Bodies = Matter.Bodies;

// create an engine

const engine = Engine.create();

//engine.enableSleeping = true; //might want to turn this off to improve accuracy

//define player *************************************************************

//***************************************************************************

//player as a series of vertices

let vector = Vertices.fromPath('0 40 0 115 20 130 30 130 50 115 50 40');

const playerBody = Matter.Bodies.fromVertices(0, 0, vector);

//this sensor check if the player is on the ground to enable jumping

var jumpSensor = Bodies.rectangle(0, 46, 40, 20, {

sleepThreshold: 99999999999,

isSensor: true

});

//this part of the player lowers on crouch

vector = Vertices.fromPath('0 -66 18 -82 0 -37 50 -37 50 -66 32 -82');

const playerHead = Matter.Bodies.fromVertices(0, -55, vector);

//a part of player that senses if the player's head is empty and can return after crouching

const headSensor = Bodies.rectangle(0, -57, 48, 45, {

sleepThreshold: 99999999999,

isSensor: true,

});

const player = Body.create({ //combine jumpSensor and playerBody

parts: [playerBody, playerHead, jumpSensor, headSensor],

inertia: Infinity, //prevents player rotation

friction: 0.002,

//frictionStatic: 0.5,

restitution: 0.3,

sleepThreshold: Infinity,

collisionFilter: {

group: -2

},

});

Matter.Body.setPosition(player, mech.spawnPos);

Matter.Body.setVelocity(player, mech.spawnVel);

Matter.Body.setMass(player, mech.mass);

World.add(engine.world, [player]);

//holding body constraint

const holdConstraint = Constraint.create({

pointA: {

x: 0,

y: 0

},

//setting constaint to jump sensor because it has to be on something until the player picks up things

bodyB: jumpSensor,

stiffness: 0.4,

});

World.add(engine.world, holdConstraint);

//spawn bodies *************************************************************

//***************************************************************************

//arrays that hold all the elements that are drawn by the renderer

const body = []; //non static bodies

const map = []; //all static bodies

const cons = []; //all constaints between a point and a body

const consBB = []; //all constaints between two bodies

spawn();

function spawn() { //spawns bodies and map elements

function BodyRect(x, y, width, height, properties) { //speeds up adding reactangles to map array

body[body.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);

}

//premade property options

//Object.assign({}, propsHeavy, propsBouncy, propsNoRotation) //will combine properties into a new object

const propsBouncy = {

friction: 0,

frictionAir: 0,

frictionStatic: 0,

restitution: 1,

}

const propsOverBouncy = {

friction: 0,

frictionAir: 0,

frictionStatic: 0,

restitution: 1.05,

}

const propsHeavy = {

density: 0.01 //default density 0.001

}

const propsNoRotation = {

inertia: Infinity, //prevents player rotation

}

function constraintPB(x, y, bodyIndex, stiffness) {

cons[cons.length] = Constraint.create({

pointA: {

x: x,

y: y

},

bodyB: body[bodyIndex],

stiffness: stiffness,

})

}

function constraintBB(bodyIndexA, bodyIndexB, stiffness) {

consBB[consBB.length] = Constraint.create({

bodyA: body[bodyIndexA],

bodyB: body[bodyIndexB],

stiffness: stiffness,

})

}

BodyRect(1475, 0, 100, 800); //huge tall vertical box

BodyRect(800, 438, 250, 10); //long skinny box

for (let i = 0; i < 10; i++) { //random bouncy circles

body[body.length] = Bodies.circle(-800 + (0.5 - Math.random()) * 200, 600 + (0.5 - Math.random()) * 200, 7 + Math.ceil(Math.random() * 30), {

restitution: 0.8,

})

}

for (let i = 0; i < 10; i++) { //stack of medium hexagons

body[body.length] = Bodies.polygon(-400, 30 - i * 70, 6, 40, {

angle: Math.PI / 2,

});

}

for (let i = 0; i < 5; i++) { //stairs of boxes taller on left

for (let j = 0; j < 5 - i; j++) {

const r = 40;

body[body.length] = Bodies.rectangle(50 + r / 2 + i * r, 900 - r / 2 - i * r, r, r, {

restitution: 0.8,

});

}

}

for (let i = 0; i < 10; i++) { //stairs of boxes taller on right

for (let j = 0; j < i; j++) {

const r = 120;

body[body.length] = Bodies.rectangle(2639 + r / 2 + i * r, 900 + r - i * r, r, r, {

restitution: 0.6,

friction: 0.3,

frictionStatic: 0.9,

});

}

}

for (let i = 0; i < 12; i++) { //a stack of boxes

body[body.length] = Bodies.rectangle(936, 700 + i * 21, 25, 21);

}

for (let i = 0; i < 12; i++) { //a stack of boxes

body[body.length] = Bodies.rectangle(464, 700 + i * 21, 25, 21);

}

(function newtonsCradle() { //build a newton's cradle

const x = -600;

const r = 20;

const y = 200;

for (let i = 0; i < 5; i++) {

body[body.length] = Bodies.circle(x + i * r * 2, 490, r, Object.assign({}, propsHeavy, propsOverBouncy, propsNoRotation));

constraintPB(x + i * r * 2, 200, body.length - 1, 0.9);

}

body[body.length - 1].force.x = 0.02 * body[body.length - 1].mass; //give the last one a kick

})()

// body[body.length] = Bodies.circle(0, 570, 20)

// body[body.length] = Bodies.circle(30, 570, 20)

// body[body.length] = Bodies.circle(0, 600, 20)

// constraintBB(body.length - 2, body.length - 3, 0.2)

// constraintBB(body.length - 2, body.length - 1, 0.2)

//map statics **************************************************************

//***************************************************************************

function mapRect(x, y, width, height, properties) { //addes reactangles to map array

map[map.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);

}

function mapVertex(x, y, vector, properties) { //addes reactangles to map array

map[map.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties);

}

//mapVertex(-1700, 700, '0 0 0 -500 500 -500 1000 -400 1500 0'); //large ramp

//mapVertex(1285, 867, '200 0 200 100 0 100'); // ramp

mapVertex(1400, 854, '0 100 600 100 600 0 150 0'); // ramp

mapVertex(-1300, 670, '0 0 -500 0 -500 200'); //angeled ceiling

//mapVertex(-1650, 700, '0 0 500 0 500 200'); //angeled ceiling

//mapRect(1350, 800, 300, 100) //ground

mapRect(650, 890, 50, 10) //ground bump

mapRect(-600, 0, 400, 200); //left cave

mapRect(-600, 600, 400, 194); //left cave

mapRect(-50, 700, 100, 200); //left wall

mapRect(0, 100, 300, 25); //left high platform

mapRect(550, 450, 300, 25); //wide platform

mapRect(650, 250, 100, 25); //wide platform

mapRect(1000, 450, 400, 25); //platform

mapRect(1200, 250, 200, 25); //platform

mapRect(1300, 50, 100, 25); //platform

mapRect(-350, 885, 20, 20); //ground bump

map[map.length] = Bodies.rectangle(700, 650, 500, 30); //platform 1

map[map.length] = Bodies.rectangle(0, 1000, 4000, 200); //ground

map[map.length] = Bodies.rectangle(4600, 1000, 4000, 200); //far right ground

//add arrays to the world******************************************************

//*****************************************************************************

for (let i = 0; i < body.length; i++) {

body[i].collisionFilter.group = 1;

World.add(engine.world, body[i]); //add to world

}

for (let i = 0; i < map.length; i++) {

map[i].collisionFilter.group = -1;

Matter.Body.setStatic(map[i], true); //make static

World.add(engine.world, map[i]); //add to world

}

for (let i = 0; i < cons.length; i++) {

World.add(engine.world, cons[i]);

}

for (let i = 0; i < consBB.length; i++) {

World.add(engine.world, consBB[i]);

}

}

// matter events *********************************************************

//************************************************************************

//************************************************************************

//************************************************************************

function playerOnGroundCheck(event) { //runs on collisions events

function enter() {

mech.numTouching++;

if (!mech.onGround) mech.enterLand();

}

const pairs = event.pairs;

for (let i = 0, j = pairs.length; i != j; ++i) {

let pair = pairs[i];

if (pair.bodyA === jumpSensor) {

mech.onBody = pair.bodyB.id;

enter();

} else if (pair.bodyB === jumpSensor) {

enter();

mech.onBody = pair.bodyA.id;

}

}

}

function playerOffGroundCheck(event) { //runs on collisions events

function enter() {

if (mech.onGround && mech.numTouching === 0) mech.enterAir();

}

const pairs = event.pairs;

for (let i = 0, j = pairs.length; i != j; ++i) {

let pair = pairs[i];

if (pair.bodyA === jumpSensor) {

enter();

} else if (pair.bodyB === jumpSensor) {

enter();

}

}

}

function playerHeadCheck(event) { //runs on collisions events

if (mech.crouch) {

mech.isHeadClear = true;

const pairs = event.pairs;

for (let i = 0, j = pairs.length; i != j; ++i) {

let pair = pairs[i];

if (pair.bodyA === headSensor) {

mech.isHeadClear = false;

} else if (pair.bodyB === headSensor) {

mech.isHeadClear = false;

}

}

}

}

Events.on(engine, "beforeUpdate", function(event) {

mech.numTouching = 0;

});

//determine if player is on the ground

Events.on(engine, "collisionStart", function(event) {

playerOnGroundCheck(event);

playerHeadCheck(event);

});

Events.on(engine, "collisionActive", function(event) {

playerOnGroundCheck(event);

playerHeadCheck(event);

});

Events.on(engine, 'collisionEnd', function(event) {

playerOffGroundCheck(event);

});

// render ***********************************************************

//*******************************************************************

//*******************************************************************

//*******************************************************************

function drawMatterWireFrames() {

ctx.textAlign = "center";

ctx.textBaseline = "middle";

ctx.fillStyle = "#999";

const bodies = Composite.allBodies(engine.world);

ctx.beginPath();

for (let i = 0; i < bodies.length; i += 1) {

ctx.fillText(bodies[i].id, bodies[i].position.x, bodies[i].position.y);

let vertices = bodies[i].vertices;

ctx.moveTo(vertices[0].x, vertices[0].y);

for (let j = 1; j < vertices.length; j += 1) {

ctx.lineTo(vertices[j].x, vertices[j].y);

}

ctx.lineTo(vertices[0].x, vertices[0].y);

}

ctx.lineWidth = 1;

ctx.strokeStyle = '#000';

ctx.stroke();

}

function drawMap() {

//draw map

ctx.beginPath();

for (let i = 0; i < map.length; i += 1) {

let vertices = map[i].vertices;

ctx.moveTo(vertices[0].x, vertices[0].y);

for (let j = 1; j < vertices.length; j += 1) {

ctx.lineTo(vertices[j].x, vertices[j].y);

}

ctx.lineTo(vertices[0].x, vertices[0].y);

}

ctx.fillStyle = '#444';

ctx.fill();

}

function drawBody() {

//draw body

ctx.beginPath();

for (let i = 0; i < body.length; i += 1) {

let vertices = body[i].vertices;

ctx.moveTo(vertices[0].x, vertices[0].y);

for (let j = 1; j < vertices.length; j += 1) {

ctx.lineTo(vertices[j].x, vertices[j].y);

}

ctx.lineTo(vertices[0].x, vertices[0].y);

}

ctx.lineWidth = 1.5;

ctx.fillStyle = '#777';

ctx.fill();

ctx.strokeStyle = '#222';

ctx.stroke();

}

function drawBullet() {

//draw body

ctx.beginPath();

for (let i = 0; i < bullet.length; i += 1) {

let vertices = bullet[i].vertices;

ctx.moveTo(vertices[0].x, vertices[0].y);

for (let j = 1; j < vertices.length; j += 1) {

ctx.lineTo(vertices[j].x, vertices[j].y);

}

ctx.lineTo(vertices[0].x, vertices[0].y);

}

ctx.fillStyle = '#f34';

//ctx.fillStyle = '#0cc';

ctx.fill();

}

function drawCons() {

//draw body

ctx.beginPath();

for (let i = 0; i < cons.length; i += 1) {

ctx.moveTo(cons[i].pointA.x, cons[i].pointA.y);

ctx.lineTo(cons[i].bodyB.position.x, cons[i].bodyB.position.y);

}

ctx.lineWidth = 1;

ctx.strokeStyle = '#999';

ctx.stroke();

}

function drawPlayerBodyTesting() { //shows the different parts of the player body for testing

//jump

ctx.beginPath();

let bodyDraw = jumpSensor.vertices;

ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);

for (let j = 1; j < bodyDraw.length; j += 1) {

ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);

}

ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);

ctx.fillStyle = 'rgba(255, 0, 0, 0.3)';

ctx.fill();

ctx.strokeStyle = '#000';

ctx.stroke();

//main body

ctx.beginPath();

bodyDraw = playerBody.vertices;

ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);

for (let j = 1; j < bodyDraw.length; j += 1) {

ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);

}

ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);

ctx.fillStyle = 'rgba(0, 255, 255, 0.3)';

ctx.fill();

ctx.stroke();

//head

ctx.beginPath();

bodyDraw = playerHead.vertices;

ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);

for (let j = 1; j < bodyDraw.length; j += 1) {

ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);

}

ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);

ctx.fillStyle = 'rgba(255, 255, 0, 0.3)';

ctx.fill();

ctx.stroke();

//head sensor

ctx.beginPath();

bodyDraw = headSensor.vertices;

ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);

for (let j = 1; j < bodyDraw.length; j += 1) {

ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);

}

ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);

ctx.fillStyle = 'rgba(0, 0, 255, 0.3)';

ctx.fill();

ctx.stroke();

}

//main loop ************************************************************

//**********************************************************************

//**********************************************************************

//**********************************************************************

function cycle() {

stats.begin();

game.timing();

game.wipe();

mech.keyMove();

mech.keyHold();

game.keyZoom();

game.gravityFlip()

game.pause();

if (game.testing) {

mech.testingMoveLook();

mech.deathCheck();

bulletLoop();

ctx.save();

game.scaleZoom();

ctx.translate(mech.transX, mech.transY);

mech.draw();

drawMatterWireFrames();

drawPlayerBodyTesting();

ctx.restore();

mech.info();

} else {

mech.move();

mech.deathCheck();

bulletLoop();

mech.look();

game.wipe();

ctx.save();

game.scaleZoom();

ctx.translate(mech.transX, mech.transY);

ctx.drawImage(background_img, -600, -400);

drawCons();

drawBody();

mech.draw();

ctx.drawImage(foreground_img, -700, -1500);

drawMap();

drawBullet();

ctx.restore();

}

//svg graphics , just here until I convert svg to png in inkscape

/* document.getElementById('background').setAttribute('transform',

'translate(' + (canvas.width/2) + ',' + (canvas.height/2) + ')'

+ 'scale(' + game.zoom + ')'

+ 'translate(' + (mech.transX - canvas.width/2) + ',' + (mech.transY - canvas.height/2) + ')'); */

// document.getElementById('foreground').setAttribute('transform',

// 'translate(' + (canvas.width/2) + ',' + (canvas.height/2) + ')'

// + 'scale(' + game.zoom + ')'

// + 'translate(' + (mech.transX - canvas.width/2) + ',' + (mech.transY - canvas.height/2) + ')');

stats.end();

requestAnimationFrame(cycle);

}

const bmo_img = new Image(); // Create new img element

bmo_img.src = '/uploads/161101/Bmo.png'; // Set source path

const foreground_img = new Image(); // Create new img element

foreground_img.src = '/uploads/161101/circle3390.png'; // Set source path

const background_img = new Image(); // Create new img element

background_img.src = '/uploads/161101/background.png'; // Set source path

function runPlatformer(el) {

el.onclick = null; //removes the onclick effect so the function only runs once

el.style.display = 'none'; //hides the element that spawned the function

document.getElementById("keysright").innerHTML = '';

document.getElementById("keysleft").innerHTML = '';

document.body.appendChild(stats.dom); //show stats.js FPS tracker

Engine.run(engine); //starts game engine

console.clear(); //gets rid of annoying console message about vertecies not working

open();

requestAnimationFrame(cycle); //starts game loop

}

function open() {

const introCycles = 200;

game.zoom = game.cycle / introCycles;

if (game.cycle < introCycles) {

requestAnimationFrame(open);

} else {

ctx.restore();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值