This is my class
function Missile(drawX, drawY) {
this.srcX = 0;
this.srcY = 0;
this.width = 16;
this.r = this.width * 0.5;
this.height = 10;
this.drawX = drawX;
this.drawY = drawY;
this.img = planeHomingMissile;
this.rotation = -90;
}
Missile.prototype.draw = function () {
ctxHM.save();
ctxHM.translate(this.drawX, this.drawY);
ctxHM.rotate(this.rotation);
ctxHM.drawImage(this.img, -this.r, -this.r);
ctxHM.restore();
}
And this is my JavaScript logic:
function shootHomingMissile() {
//if(!missileOut) {
hMissile = new Missile(player1.drawX + 22, player1.drawY + 32);
missileOut = true;
//}
}
function updateHomingMissile() {
if(missileOut) {
var targetX = 500 - hMissile.drawX;
var targetY = 50 - hMissile.drawY;
//The atan2() method returns the arctangent of the quotient of its arguments, as a numeric value between PI and -PI radians.
//The number returned represents the counterclockwise angle in radians (not degrees) between the positive X axis and the point (x, y)
var rotations = Math.atan2(targetY, targetX) * 180 / Math.PI;
hMissile.rotation = rotations;
var vx = bulletSpd * (90 - Math.abs(rotations)) / 90;
var vy;
if (rotations < 0)
vy = -bulletSpd + Math.abs(vx);
else
vy = bulletSpd - Math.abs(vx);
hMissile.drawX += vx;
hMissile.drawY += vy;
}
}
function drawHomingMissile() {
ctxHM.clearRect(0,0,575,800);
hMissile.draw();
}
I want my missile(facing upwards) to target (500, 50) and face it while targeting.
the movement seems to work but its not facing the target its just keeps rotating but the missile is going to the target.
I'm a starting developer so my code is kind of mess, please help me :)
You are converting your angle from radians to degrees and is using that for your rotation() which require radians.
Try this in your Missile.prototype.draw:
ctxHM.rotate(this.rotation * Math.PI / 180);
(or simply keep the angle in radians at all stages)
Related
I have written some code to simulate a gravitation-free movement of a ship with a single thruster. Most of the time it works, and the ship reaches it's destination perfectly, but just sometimes it accelerates infinitively. But I can't figure out, why?
seek(target) {
var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
if (desired.mag()>0.1){
this.orientation = desired;
if (this.velocity.heading() - desired.heading() > 0.01 && this.velocity.mag() >0.01) {
this.orientation = this.velocity.copy().mult(-1);
}
if ((this.velocity.mag()*this.velocity.mag())/(2*(this.maxForce/this.mass)) > desired.mag()) {
this.orientation.mult(-1);
}
this.applyForce(this.orientation.normalize().mult(this.maxForce/this.mass));
} else {
this.velocity = createVector(0,0);
}
}
You can test the result here:
https://editor.p5js.org/Ahiru/sketches/r1rQ9-T5m
The issue of the ship object going past the target is caused by the magnitude delta being too small for the increment that the ship moves in.
In order to get the spaceship object to land on the selected point you need to modify the seek method:
seek(target) {
var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
if (desired.mag()>.01){
The object is moving in increments that can cause desired.mag to go from a number that is greater than .01 as the object approaches to another magnitude that is larger than .01 as the object passes the target and moves away.
modify
if (desired.mag() > .01)
to
if (desired.mag() > 2.0)
for example and the ship will be captured and land on the target and stay there until another target is selected.
Here is a working example with the delta set to equal the diameter of the target so that the ship appears to land on the surface of the target.
let v;
var targetDiameter = 12;
function setup() {
pixelDensity(1);
createCanvas(1000, 1000);
v = new Vehicle(width / 2, height / 2);
target = createVector(200, 200);
}
function draw() {
background(51);
// Draw an ellipse at the mouse position
fill(127);
stroke(200);
strokeWeight(2);
ellipse(target.x, target.y, targetDiameter, targetDiameter);
// Call the appropriate steering behaviors for our agents
v.seek(target);
v.update();
v.display();
}
function mouseClicked() {
target = createVector(mouseX, mouseY);
hex = find_HexCoordinates(100, target);
console.log("click " + hex.x + " " + hex.y + " " + hex.z);
}
class ThrustList {
constructor(thrust, time) {
this.thrust = createVector(thrust);
this.time = time;
}
set(thrust, time) {
this.thrust.set(thrust);
this.time = time;
}
}
class ThrustParams {
constructor (deltaPosition, deltaVelocity, maxForce, mass) {
this.deltaPosition = createVector(deltaPosition);
this.deltaVelocity = createVector(deltaVelocity);
this.maxForce = maxForce;
this.mass = mass;
}
}
class hexmetrics {
constructor (radius) {
this.outerRadius = radius;
this.innerRadius = this.outerradius * sqrt(3)/2;
}
}
function find_HexCoordinates (radius, position) {
this.innerRadius = radius;
this.outerRadius = this.innerRadius * sqrt(3)/2;
this.px = position.x - 1000/2;
this.py = position.y - 1000/2;
this.x = px / this.innerRadius * 2;
this.y = -x;
this.offset = py / this.outerRadius * 3;
this.x -= offset;
this.y -= offset;
this.iX = Math.round(x);
this.iY = Math.round(y);
this.iZ = Math.round(-x -y);
if (iX + iY + iZ != 0) {
dX = Math.abs(x-iX);
dY = Math.abs(y-iY);
dZ = Math.abs(-x -y -iZ);
if (dX > dY && dX > dZ) {
iX = -iY -iZ;
}
else if (dZ > dY) {
iZ = -iX -iY;
}
}
return createVector(this.iX, this.iY, this.iZ);
}
class Vehicle {
constructor(x, y){
this.mass = 1;
this.orientation = createVector(0,1);
this.turning_speed = 90;
this.acceleration = createVector(0, 0);
this.maxForce = .02;
this.position = createVector(x, y);
this.r = 3;
this.velocity = createVector(0, 0);
}
// Method to update location
update() {
// Update velocity
this.velocity.add(this.acceleration);
// Limit speed
this.position.add(this.velocity);
// Reset accelerationelertion to 0 each cycle
this.acceleration.mult(0);
}
applyForce(force) {
this.acceleration.add(force);
}
// A method that calculates a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
seek(target) {
var desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
if (desired.mag() > targetDiameter){
this.orientation = desired;
if (Math.abs(this.velocity.heading() - desired.heading()) > 0.01 && this.velocity.mag() >0.01) {
this.orientation = this.velocity.copy().mult(-1);
}
if ((this.velocity.mag()*this.velocity.mag())/(2*(this.maxForce/this.mass)) > desired.mag()) {
this.orientation.mult(-1);
}
this.applyForce(this.orientation.normalize().mult(this.maxForce/this.mass));
} else {
this.velocity = createVector(0,0);
}
}
display() {
// Draw a triangle rotated in the direction of velocity
var theta = this.orientation.heading() + PI / 2;
fill(127);
stroke(200);
strokeWeight(1);
push();
translate(this.position.x, this.position.y);
rotate(theta);
beginShape();
vertex(0, -this.r * 2);
vertex(-this.r, this.r * 2);
vertex(this.r, this.r * 2);
endShape(CLOSE);
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
I'm never using p5js before but I think it's because of the applyForce() , it's keep adding new force when user click.
applyForce(force) {
this.acceleration.add(force);}
i've a canvas dom element inside a div #content with transform rotateX(23deg) and #view with perspective 990px
<div id="view">
<div id="content">
<canvas></canvas>
</div>
</div>
if i draw a point (300,300) inside canvas, the projected coordinates are different (350, 250).
The real problem is when an object drawn in a canvas is interactive (click o drag and drop), the hit area is translated.
Which equation i've to use? Some kind of matrix?
Thanks for your support.
This is something I am dealing with now. Lets start out with something simple. Let's say your canvas is right up against the top left corner. If you click the mouse and make an arc on that spot it will be good.
canvasDOMObject.onmouseclick = (e) => {
const x = e.clientX;
const y = e.clientY;
}
If your canvas origin is not at client origin you would need to do something like this:
const rect = canvasDOMObject.getBoundingRect();
const x = e.clientX - rect.x;
const y = e.clientY - rect.y;
If you apply some pan, adding pan, when drawing stuff you need to un-pan it, pre-subtract the pan, when capturing the mouse point:
const panX = 30;
const panY = 40;
const rect = canvasDOMObject.getBoundingRect();
const x = e.clientX - rect.x - panX;
const y = e.clientY - rect.y - panY;
...
ctx.save();
ctx.translate(panX, panY);
ctx.beginPath();
ctx.strokeArc(x, y);
ctx.restore();
If you apply, for instance, a scale when you draw it, you would need to un-scale it when capturing the mouse point:
const panX = 30;
const panY = 40;
const scale = 1.5;
const rect = canvasDOMObject.getBoundingRect();
const x = (e.clientX - rect.x - panX) / scale;
const y = (e.clientY - rect.y - panY) / scale;
...
ctx.save();
ctx.translate(panX, panY);
ctx.scale(scale);
ctx.beginPath();
ctx.strokeArc(x, y);
ctx.restore();
The rotation I have not figured out yet but I'm getting there.
Alternative solution.
One way to solve the problem is to trace the ray from the mouse into the page and finding the point on the canvas where that ray intercepts.
You will need to transform the x and y axis of the canvas to match its transform. You will also have to project the ray from the desired point to the perspective point. (defined by x,y,z where z is perspective CSS value)
Note: I could not find much info about CSS perspective math and how it is implemented so it is just guess work from me.
There is a lot of math involved and i had to build a quick 3dpoint object to manage it all. I will warn you that it is not well designed (I dont have the time to inline it where needed) and will incur a heavy GC toll. You should rewrite the ray intercept and remove all the point clone calls and reuse points rather than create new ones each time you need them.
There are a few short cuts. The ray / face intercept assumes that the 3 points defining the face are the actual x and y axis but it does not check that this is so. If you have the wrong axis you will not get the correct pixel coordinate. Also the returned coordinate is relative to the point face.p1 (0,0) and is in the range 0-1 where 0 <= x <= 1 and 0 <= y <= 1 are points on the canvas.
Make sure the canvas resolution matches the display size. If not you will need to scale the axis and the results to fit.
DEMO
The demo project a set of points creating a cross through the center of the canvas. You will notice the radius of the projected circle will change depending on distance from the camera.
Note code is in ES6 and requires Babel to run on legacy browsers.
var divCont = document.createElement("div");
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 400;
var w = canvas.width;
var h = canvas.height;
var cw = w / 2; // center
var ch = h / 2;
var ctx = canvas.getContext("2d");
// perspectiveOrigin
var px = cw; // canvas center
var py = 50; //
// perspective
var pd = 700;
var mat;
divCont.style.perspectiveOrigin = px + "px "+py+"px";
divCont.style.perspective = pd + "px";
divCont.style.transformStyle = "preserve-3d";
divCont.style.margin = "10px";
divCont.style.border = "1px black solid";
divCont.style.width = (canvas.width+8) + "px";
divCont.style.height = (canvas.height+8) + "px";
divCont.appendChild(canvas);
document.body.appendChild(divCont);
function getMatrix(){ // get canvas matrix
if(mat === undefined){
mat = new DOMMatrix().setMatrixValue(canvas.style.transform);
}else{
mat.setMatrixValue(canvas.style.transform);
}
}
function getPoint(x,y){ // get point on canvas
var ww = canvas.width;
var hh = canvas.height;
var face = createFace(
createPoint(mat.transformPoint(new DOMPoint(-ww / 2, -hh / 2))),
createPoint(mat.transformPoint(new DOMPoint(ww / 2, -hh / 2))),
createPoint(mat.transformPoint(new DOMPoint(-ww / 2, hh / 2)))
);
var ray = createRay(
createPoint(x - ww / 2, y - hh / 2, 0),
createPoint(px - ww / 2, py - hh / 2, pd)
);
return intersectCoord3DRayFace(ray, face);
}
// draw point projected onto the canvas
function drawPoint(x,y){
var p = getPoint(x,y);
if(p !== undefined){
p.x *= canvas.width;
p.y *= canvas.height;
ctx.beginPath();
ctx.arc(p.x,p.y,8,0,Math.PI * 2);
ctx.fill();
}
}
// main update function
function update(timer){
ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.globalAlpha = 1; // reset alpha
ctx.fillStyle = "green";
ctx.fillRect(0,0,w,h);
ctx.lineWidth = 10;
ctx.strokeRect(0,0,w,h);
canvas.style.transform = "rotateX("+timer/100+"deg)" + " rotateY("+timer/50+"deg)";
getMatrix();
ctx.fillStyle = "gold";
drawPoint(cw,ch);
for(var i = -200; i <= 200; i += 40){
drawPoint(cw + i,ch);
drawPoint(cw ,ch + i);
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
// Math functions to find x,y pos on plain.
// Warning this code is not built for SPEED and will incure a lot of GC hits
const small = 1e-6;
var pointFunctions = {
add(p){
this.x += p.x;
this.y += p.y;
this.z += p.z;
return this;
},
sub(p){
this.x -= p.x;
this.y -= p.y;
this.z -= p.z;
return this;
},
mul(mag){
this.x *= mag;
this.y *= mag;
this.z *= mag;
return this;
},
mag(){ // get length
return Math.hypot(this.x,this.y,this.z);
},
cross(p){
var p1 = this.clone();
p1.x = this.y * p.z - this.z * p.y;
p1.y = this.z * p.x - this.x * p.z;
p1.z = this.x * p.y - this.y * p.x;
return p1;
},
dot(p){
return this.x * p.x + this.y * p.y + this.z * p.z;
},
isZero(){
return Math.abs(this.x) < small && Math.abs(this.y) < small && Math.abs(this.z) < small;
},
clone(){
return Object.assign({
x : this.x,
y : this.y,
z : this.z,
},pointFunctions);
}
}
function createPoint(x,y,z){
if(y === undefined){ // quick add overloaded for DOMPoint
y = x.y;
z = x.z;
x = x.x;
}
return Object.assign({
x, y, z,
}, pointFunctions);
}
function createRay(p1, p2){
return { p1, p2 };
}
function createFace(p1, p2, p3){
return { p1,p2, p3 };
}
// Returns the x,y coord of ray intercepting face
// ray is defined by two 3D points and is infinite in length
// face is 3 points on the intereceptin plane
// For correct intercept point face p1-p2 should be at 90deg to p1-p3 (x, and y Axis)
// returns unit coordinates x,y on the face with the origin at face.p1
// If there is no solution then returns undefined
function intersectCoord3DRayFace(ray, face ){
var u = face.p2.clone().sub(face.p1);
var v = face.p3.clone().sub(face.p1);
var n = u.cross(v);
if(n.isZero()){
return; // return undefined
}
var vr = ray.p2.clone().sub(ray.p1);
var b = n.dot(vr);
if (Math.abs(b) < small) { // ray is parallel face
return; // no intercept return undefined
}
var w = ray.p1.clone().sub(face.p1);
var a = -n.dot(w);
var uDist = a / b;
var intercept = ray.p1.clone().add(vr.mul(uDist)); // intersect point
var uu = u.dot(u);
var uv = u.dot(v);
var vv = v.dot(v);
var dot = uv * uv - uu * vv;
w = intercept.clone().sub(face.p1);
var wu = w.dot(u);
var wv = w.dot(v);
var x = (uv * wv - vv * wu) / dot;
var y = (uv * wu - uu * wv) / dot;
return {x,y};
}
I created an algorithm to move a particle diagonally and it works fine using an angle. Basically, this is what I do:
this.x += this.speed * Math.cos(this.angle * Math.PI / 180);
this.y += this.speed * Math.sin(this.angle * Math.PI / 180);
this.draw();
How can I combine this with a zigzag movement?
I recommend calculating the lateral deviation from the normal path or amplitude which is given by
// Triangle wave at position t with period p:
function amplitude(t, p) {
t %= p;
return t > p * 0.25 ? t < p * 0.75 ? p * 0.5 - t : t - p : t;
}
where t will be set to the length of the traveled path, and p is the period of the 'zigzag' triangle wave pattern.
Given the amplitude and the previous position, we can now easily compute the next position by moving ahead as described by your original code and then adding the lateral deviation to our position:
var amplitude = amplitude(distance, p) - this.amplitude(previous_distance, p);
this.x += amplitude * Math.sin(this.angle * Math.PI/180);
this.y -= amplitude * Math.cos(this.angle * Math.PI/180);
A complete example with two movable objects, one moving 'normally' and one following a 'zigzag' pattern:
function Movable(x, y, speed, angle, period) {
this.x = x;
this.y = y;
this.speed = speed;
this.angle = angle;
this.period = period;
this.distance = 0;
}
Movable.prototype.moveDiagonal = function() {
this.distance += this.speed;
this.x += this.speed * Math.cos(this.angle * Math.PI / 180);
this.y += this.speed * Math.sin(this.angle * Math.PI / 180);
}
Movable.prototype.amplitudeZigZag = function() {
var p = this.period, d = this.distance % p;
return d > p * 0.25 ? d < p * 0.75 ? p * 0.5 - d : d - p : d;
}
Movable.prototype.moveZigZag = function() {
var amplitude1 = this.amplitudeZigZag();
this.moveDiagonal();
var amplitude2 = this.amplitudeZigZag();
var amplitude = amplitude2 - amplitude1;
this.x -= amplitude * Math.sin(this.angle * Math.PI/180);
this.y += amplitude * Math.cos(this.angle * Math.PI/180);
}
Movable.prototype.draw = function(context) {
context.beginPath();
context.arc(this.x, this.y, 1, 0, 2 * Math.PI);
context.stroke();
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var m1 = new Movable(0, 0, 2, 0, 50);
var m2 = new Movable(0, 0, 2, 0, 50);
for (var i = 0; i < 1000; ++i) {
m1.angle += Math.cos(i * Math.PI/180);
m2.angle += Math.cos(i * Math.PI/180);
m1.moveDiagonal();
m2.moveZigZag();
m1.draw(context);
m2.draw(context);
}
<canvas id="canvas" width="600" height="200"></canvas>
So let's say that you're moving in the direction this.angle and you want to zig-zag in that direction moving side to side ±45° from that direction. All you need to do is have a variable like var zigzag = 45; and add zigzag to this.angle when calculating the new positions. And to make it zig-zag, you need to negate it every so often like this zigzag *= -1;. If you want to stop zig-zagging, set zigzag = 0;.
The trick is knowing when to alternate between ±45°. Maybe you can have the switch timed and keep a reference to the last time you switched using Date.now();. You can check the difference between the current time and the recorded time, then negate zigzag once you've surpassed a certain number of milliseconds. Just remember to record the new time of the last switch. You could also keep track of distance travelled and use the same approach, whatever works for you.
I have programed a program with JavaScript and the DOM that shows a ball bouncing in a box; it is a canvas element. The only things that do not work correctly are the angles. This is not noticeable until the angles are small, when it is clear the ball did not bounce back correctly from the box. The angle may be coming to a box gradually, and then bounce very steeply back. This seems like perhaps instead of the angle-in=angle-out, the angle that was being headed from was what was output angle. This would be equivalent of an angle in and its compliment out. The problem seems to happen with only half the types of bounces: it might not happen on one wall coming in a direction, but would on another wall coming in a direction.
: http://i.stack.imgur.com/WviEd.gif
I have posted all the code for ability for the test of the code, and a gradual angle is used, so the problem can be seen, but the angles that are the problem are in the checkAngle function.
<!doctype html>
<script src="code/chapter/15_game.js"></script>
<script src="code/game_levels.js"></script>
<script src="code/chapter/16_canvas.js"></script>
<canvas width="400" height="400"></canvas>
<script>
var cx = document.querySelector("canvas").getContext("2d");
var lastTime = null;
function frame(time) {
if (lastTime != null)
updateAnimation(Math.min(100, time - lastTime) / 1000);
lastTime = time;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
var x = y = 200//, angle = 2 * Math.PI * Math.random();
var angle = 2 * Math.PI / 40 + Math.PI;
function checkAngle(angle) {
if(x + 10 >= 400) {
if(angle <= Math.PI)
return angle = (Math.PI/2) + ((Math.PI / 2) - reduceAngle(angle));
else if(angle > Math.PI)
return angle = (3 * Math.PI / 2) - ((Math.PI / 2) - reduceAngle(angle));
}else if(x - 10 <= 0) {
if(angle <= Math.PI)
return angle = Math.PI/2 - reduceAngle(angle);
else if(angle > Math.PI)
return angle = 3* Math.PI/2 + (Math.PI/2 - reduceAngle(angle));
}else if(y - 10 <= 0) {
if(angle >= 3 * Math.PI /2)
return angle = Math.PI/2 - reduceAngle(angle);
else if(angle < 3 * Math.PI/2)
return angle = Math.PI - (Math.PI / 2 - reduceAngle(angle));
}else if(y + 10 >= 400) {
if(angle <= Math.PI/2)
return angle = 2*Math.PI - (Math.PI / 2 - reduceAngle(angle));
else if(angle > Math.PI/2)
return angle = Math.PI + (Math.PI / 2 - reduceAngle(angle));
}else
return angle;
}
function reduceAngle(angle) {
if(angle < Math.PI / 2) {
return angle;
}else{
angle = angle - (Math.PI / 2);
return reduceAngle (angle);
}
}
function updateAnimation(step) {
cx.clearRect(0, 0, 400, 400);
cx.lineWidth = 4;
cx.strokeRect(0, 0, 400, 400);
angle = checkAngle(angle);
x += Math.cos(angle) * step * 200;
y += Math.sin(angle) * step * 200;
cx.lineWidth = 2;
cx.beginPath();
cx.arc(x, y, 20, 0, 7);
cx.stroke();
}
</script>
When dealing with reflections in a non-rotated box you don't really need to deal with angles when reflecting. Just define an initial vector based on angle.
var vector = {
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
};
Then you simply check bounds for x and y separately and inverse the slope-value for each axis:
if (x - radius <= 0 || x + radius>= 400) {
vector.x = -vector.x; // reflect x
}
if (y - radius<= 0 || y + radius> 400) {
vector.y = -vector.y; // reflect y
}
You can always adjust the angle on the fly by adding another vector with the delta-angle.
If your bounce box would not be 0° rotated, then check out this answer for vector-reflection.
For example
Using your code as a basis, this would be implemented like this:
var cx = document.querySelector("canvas").getContext("2d");
var lastTime = null;
var x, y;
// calculate an initial vector
var angle = 20 / 180 * Math.PI; // angle -> radians
var speed = 5;
var vector = {
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
};
x = y = 200;
function frame(time) {
if (lastTime != null)
updateAnimation(Math.min(100, time - lastTime) / 1000);
lastTime = time;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
function checkAngle() {
var dlt = 10 + 2 + 4; //include radius and line-widths;
if (x - dlt <= 0 || x + dlt >= 400) {
vector.x = -vector.x; // reflect x
}
if (y - dlt <= 0 || y + dlt > 400) {
vector.y = -vector.y; // reflect y
}
}
function updateAnimation(step) {
cx.clearRect(0, 0, 400, 400);
cx.lineWidth = 4;
cx.strokeRect(0, 0, 400, 400);
x += vector.x; // use our vector
y += vector.y;
checkAngle(); // test for hits
cx.lineWidth = 2;
cx.beginPath();
cx.arc(x, y, 20, 0, 7);
cx.stroke();
}
<canvas width="400" height="400"></canvas>
Judging by what I've seen in your drawings and demonstrations, the angles are being taken off the wrong axis. If approaching at 20 degrees, you'd expect the ball to leave at 180-20 degrees. Instead what it's doing is leaving at 90+20 degrees.
While I can't find the precise place in your code that makes this error, I felt I had to point this out in the hopes that someone can improve upon it.
Hi I've been looking at cannonball physics and how to implement them in a game.
I'd like to apply gravity to the cannonball and x and y velocity relative to the mouse
cursor position. So that the cannonball travels toward your mouse position.
Further away the mouse cursor (from the cannon) the higher the velocity.
The angle should match the position of the cursor on the canvas.
I've hunted this out for quite a few days now, so now I'm asking.
Who knows of a nice cannonball physics using javascript and canvas?
units = 10,
pixelsPerMeter = stage.width / units,
startlaunch = Math.PI/4,
launchAngle = startlaunch;
bang = {
lastTime: 0,
gravity: 9.81,
applyGravity: function (elapsed) {
bullet1.velocityY = (this.gravity * elapsed) -
(launchVelocity * Math.sin(launchAngle));
},
updateBulletPosition: function (updateDelta) {
bullet1.left += bullet1.velocityX * (updateDelta) * pixelsPerMeter;
bullet1.top += bullet1.velocityY * (updateDelta) * pixelsPerMeter;
},
execute: function (bullet1, time) {
var updateDelta,
elapsedFlightTime;
if(bulletInFlight){
elapsedFrameTime = (time - this.lastTime)/1000;
elapsedFlightTime = (time - launchTime)/1000;
this.applyGravity(elapsedFlightTime);
this.updateBulletPosition(elapsedFrameTime);
}
this.lastTime = time;
}
}
cannon.rotation = cannon.on("tick", function(event) {
var angle = Math.atan2(stage.mouseY - cannon.y, stage.mouseX - cannon.x );
angle = angle * (180/Math.PI);
// The following if statement is optional and converts our angle from being
// -180 to +180 degrees to 0-360 degrees. It is completely optional
if(angle < 0){
angle = 360 - (-angle);}
// Atan2 results have 0 degrees point down the positive X axis, while our image is pointed up.
// Therefore we simply add 90 degrees to the rotation to orient our image
// If 0 degrees is to the right on your image, you do not need to add 90
cannon.rotation = 90 + angle;
});
var fire = false, gravity = 6, vy = 3, vx = 3;
oneback.on("click", function(e) {
bullet1.x = cannon.x;
bullet1.y = cannon.y;
scene1.addChild(bullet1);
fire = true;
//e.preventDefault();
bullet1.rotation = cannon.rotation;
if(fire == false){
bullet1.vx = Math.cos(bullet1.x-stage.mouseX) * this.vx;// used to be... this.bullet_speed'.
bullet1.vy = Math.sin(bullet1.y-stage.mouseY) * this.vy;
}
});
oneback.on("click", function(e){
e.preventDefault();
if(fire == true) {
loc = (stage.mouseX, stage.mouseY);
lastMouse.left = loc.x;
lastMouse.top = loc.y;
deltaX = Math.abs(lastMouse.left - bullet1.left);
deltaY = Math.abs(lastMouse.top - bullet1.top);
launchAngle = Math.atan(parseFloat(deltaY) / parseFloat (deltaX));
launchVelocity = 4 * deltaY / Math.sin (launchAngle) / pixelsPerMeter;
}
});
bullet1.on("tick", function(event){
if(fire == true){
bullet1.y += vy - gravity;
bullet1.x += vx - gravity;
// bullet1.y -= stage.mouseY;
//bullet1.x -= stage.mouseX;
//bullet1.x = direction - gravity;
//bullet1.y = direction - gravity;
}
});