class Player { constructor(x, y) { this.x = x; this.y = y; this.w = constants.player.width; this.h = constants.player.height; this.hipLeft = { x: this.x - constants.player.hip.offset_x, y: this.y + constants.player.hip.offset_y }; this.hipRight = { x: this.x + constants.player.hip.offset_x, y: this.y + constants.player.hip.offset_y }; this.leftLeg = new Leg(this.hipLeft.x, this.hipLeft.y, 50, -Math.PI / 4); this.rightLeg = new Leg(this.hipRight.x, this.hipRight.y, 50, Math.PI / 2); this.legSelected = "R"; this.shouldMoveLeg = false; this.collided = false; this.lastBodyX = x; this.lastBodyY = y; this.hover = { active: false, leg: "R" }; } } Player.prototype.getActiveLeg = function(){ if (this.legSelected === "L") { return this.leftLeg; } return this.rightLeg; } Player.prototype.getLockedLeg = function(){ if (this.legSelected === "R") { return this.leftLeg; } return this.rightLeg; } Player.prototype.update = function() { var curLeg = this.getActiveLeg(); // select if (this.shouldMoveLeg) { this.moveLeg(); if(mousePress[0]) {// if (collidingWithWorld({ x: curLeg.x2, y: curLeg.y2, w: 4, h: 4 })) { if (this.legSelected === "R") { this.leftLeg.angle += pi; } else { this.rightLeg.angle += pi; } this.shouldMoveLeg = false; } // deselect } else { var targetPos = mousePosition(); var curLeg = this.getActiveLeg(); this.hover.active = false; //left if (distanceToLineSegment(this.leftLeg.x, this.leftLeg.y, this.leftLeg.x2, this.leftLeg.y2, targetPos.x, targetPos.y) < constants.player.select_range) { this.hover.active = true; this.hover.leg = "L"; if(mousePress[0]) { this.shouldMoveLeg = true; this.legSelected = "L"; this.hover.active = false; } // right } else if (distanceToLineSegment(this.rightLeg.x, this.rightLeg.y, this.rightLeg.x2, this.rightLeg.y2, targetPos.x, targetPos.y) < constants.player.select_range) { this.hover.active = true; this.hover.leg = "R"; if(mousePress[0]) { this.shouldMoveLeg = true; this.legSelected = "R"; this.hover.active = false; } } } centerCameraOn(this.x,this.y); } // leg has been selected, move leg towards mouse Player.prototype.moveLeg = function(){ var targetPos = mousePosition(); // gets active leg & target var curLeg = this.getActiveLeg(); var target = targetPos; // Last leg position var lastX = curLeg.x2; var lastY = curLeg.y2; // move selected leg towards mouse // console.log(curLeg.angle.toPrecision(5),pointTo(curLeg,target).toPrecision(5)); curLeg.angle = turn(curLeg.angle, pointTo(curLeg, target), constants.player.leg_speed); // var angle = pointTo(curLeg,target); curLeg.x2 = curLeg.x + curLeg.len * Math.cos(curLeg.angle); curLeg.y2 = curLeg.y + curLeg.len * Math.sin(curLeg.angle); // Collision if(collidingWithWorld({x:curLeg.x2,y:curLeg.y2,w:4,h:4})){ this.collided = true; curLeg.x2 = lastX; curLeg.y2 = lastY; return 0; } if(collidingWithWorld({x:this.x, y:this.y, w:this.w, h:this.h})){ this.x = this.lastBodyX; this.y = this.lastBodyY; } if (dist(curLeg, target) > curLeg.len) { // move towards mouse this.x += Math.cos(pointTo(curLeg, target)) * clamp(dist(curLeg, target) / constants.player.movement_divider, 1, constants.player.max_movement_speed); this.y += Math.sin(pointTo(curLeg, target)) * clamp(dist(curLeg, target) / constants.player.movement_divider, 1, constants.player.max_movement_speed); this.updateHips(); } // if leg is right update it accordingly if (this.legSelected === "R") { // set angle to the locked foot to the locked hip oppLeg = this.getLockedLeg(); oppLeg.angle = pointTo({ x: oppLeg.x2, y: oppLeg.y2 }, this.hipRight); // snap body to a position where the hip is attached to the leg this.x = (oppLeg.x2 + oppLeg.len * Math.cos(oppLeg.angle)) - constants.player.hip.offset_x; this.y = (oppLeg.y2 + oppLeg.len * Math.sin(oppLeg.angle)) - constants.player.hip.offset_y; this.updateHips(); // make sure each leg ends at the hips oppLeg.x = this.hipRight.x; oppLeg.y = this.hipRight.y; curLeg.x = this.hipLeft.x; curLeg.y = this.hipLeft.y; // if leg is left update it accordingly } else { // set angle to the locked foot to the locked hip oppLeg = this.getLockedLeg(); oppLeg.angle = pointTo({ x: oppLeg.x2, y: oppLeg.y2 }, this.hipLeft); // snap body to a position where the hip is attached to the leg this.x = (oppLeg.x2 + oppLeg.len * Math.cos(oppLeg.angle)) + constants.player.hip.offset_x; this.y = (oppLeg.y2 + oppLeg.len * Math.sin(oppLeg.angle)) - constants.player.hip.offset_y; this.updateHips(); // make sure each leg ends at the hips oppLeg.x = this.hipLeft.x; oppLeg.y = this.hipLeft.y; curLeg.x = this.hipRight.x; curLeg.y = this.hipRight.y; } this.lastBodyX = this.x; this.lastBodyY = this.y; } Player.prototype.updateHips = function() { this.hipLeft = { x: this.x - constants.player.hip.offset_x, y: this.y + constants.player.hip.offset_y }; this.hipRight = { x: this.x + constants.player.hip.offset_x, y: this.y + constants.player.hip.offset_y }; } Player.prototype.draw = function() { rect(this.x, this.y, this.w, this.h, "green"); if(this.hover.active) { if(this.hover.leg === "R") { curCtx.shadowBlur = 10; curCtx.shadowColor = "yellow"; curCtx.lineWidth = 3; this.rightLeg.draw(); curCtx.lineWidth = 1; curCtx.shadowBlur = 0; curCtx.shadowColor = "black"; this.leftLeg.draw(); } else { curCtx.shadowBlur = 10; curCtx.shadowColor = "yellow"; curCtx.lineWidth = 3; this.leftLeg.draw(); curCtx.lineWidth = 1; curCtx.shadowBlur = 0; curCtx.shadowColor = "black"; this.rightLeg.draw(); } } else { this.leftLeg.draw(); this.rightLeg.draw(); } } // https://github.com/scottglz/distance-to-line-segment/blob/master/index.js function distanceSquaredToLineSegment2(lx1, ly1, ldx, ldy, lineLengthSquared, px, py) { var t; // t===0 at line pt 1 and t ===1 at line pt 2 if (!lineLengthSquared) { // 0-length line segment. Any t will return same result t = 0; } else { t = ((px - lx1) * ldx + (py - ly1) * ldy) / lineLengthSquared; if (t < 0) t = 0; else if (t > 1) t = 1; } var lx = lx1 + t * ldx, ly = ly1 + t * ldy, dx = px - lx, dy = py - ly; return dx * dx + dy * dy; } function distanceSquaredToLineSegment(lx1, ly1, lx2, ly2, px, py) { var ldx = lx2 - lx1, ldy = ly2 - ly1, lineLengthSquared = ldx * ldx + ldy * ldy; return distanceSquaredToLineSegment2(lx1, ly1, ldx, ldy, lineLengthSquared, px, py); } function distanceToLineSegment(lx1, ly1, lx2, ly2, px, py) { return Math.sqrt(distanceSquaredToLineSegment(lx1, ly1, lx2, ly2, px, py)); } var player = new Player(500,100);