0

I want to make a box to move as a sinusoidal graph. At the point where i am now i simply can't represent the box into the canvas. At the beginning I was able to, but after working out the trigonometry part the box disappeared and a get no error...

<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
    <canvas id="canvas" width="600" height="300" style="background-color:red"></canvas>
    <script type="text/javascript">
        var canvas = document.querySelector("canvas");//isoute me document.getElementsByTagName() 
        var ctx = canvas.getContext("2d");
        var can_width = canvas.width;
        var can_height = canvas.height;
        var x,y;

        function PVector(x_,y_){
            var y = [];
            var x = [0, Math.PI/6, Math.PI/4, Math.PI/3, Math.PI/2, 2/3*Math.PI, 3/4*Math.PI, 
                        5/6*Math.PI, Math.PI, 7/6*Math.PI, 5/4*Math.PI, 4/3*Math.PI, 3/2*Math.PI,
                        5/3*Math.PI, 7/4*Math.PI, 11/6*Math.PI, 2*Math.PI];

            for (var i=0, len=x["length"]; i<len; i++){
                var A;
                A = Math.sin(x[i]);
                y.push(A);

            }console.log(y);console.log(x);
                return{
                    x:x,
                    y:y
                };
        }
        var Point = {
            location : {x:0, y: can_height/2},//initial location
            velocity : new PVector(x,y),
            display : ctx.fillRect(can_width/2,can_height/2 , 25, 25),//initial position of the box
            step : function(){ 
                    this.location.x += this.velocity.x;
                    this.location.y += this.velocity.y;

                },
            display : function(){
                        ctx.fillRect(this.location.x, this.location.y, 25, 25);
                    }   
        };              
        function update(){
            Point["step"]();
            ctx.clearRect(0,0, can_width, can_height);
            Point["display"]();
            window.setTimeout(update, 1000/30);
        }               
        function init(){
            update();
        }
        init();             

    </script>
</body>

Anamed
  • 89
  • 1
  • 7

3 Answers3

3

Problem

In your PVector object you are returning Arrays for x and y, while you use them as values in the step() method. This will cause the entire array to be added as a string.

Solution

You need something that traverse that array. Here is an example, it may not be the result you're after, but it shows the principle which you need to apply:

// first note the return type here:
function PVector(x_,y_){
    var y = [];
    var x = [0, Math.PI/6, Math.PI/4, Math.PI/3, Math.PI/2, 2/3*Math.PI, 
    ...snipped---

    return {
        x:x,  // x and y are arrays
        y:y
    };
}

var Point = {
    location: {
        x: 0,
        y: can_height / 2,
        step: 0                    // some counter to keep track of array position
    }, //initial location
    velocity: new PVector(x, y),
    step: function () {
        
        this.location.step++;     // increase step for arrays

        // using modulo will keep the step as a valid value within the array length:
        // if step = 7 and length = 5, index will become 2 (sort of "wrap around")
        var indexX = this.location.step % this.velocity.x.length;
        var indexY = this.location.step % this.velocity.y.length
        this.location.x += this.velocity.x[indexX];
        this.location.y += this.velocity.y[indexY];

    },
    ...

Updated fiddle

Tip: I would as Robin in his answer, recommend to simplify the sinus calculation. Sinus-tables are good when performance is needed and the browser can't keep up (ie. will thousands of objects), but in simpler scenario, direct calculation will work too.

Community
  • 1
  • 1
  • I am not familiar with % sign. what does it do in: this.location.x += this.velocity.x[this.location.step % this.velocity.x.length]; – Anamed Apr 15 '15 at 11:55
  • @Anamed it's a modulo operator: http://stackoverflow.com/questions/8900652/what-does-do-in-javascript –  Apr 15 '15 at 11:56
  • @Anamed I simplified the example with some more details –  Apr 15 '15 at 12:18
  • Ken the part that i'm getting confused is this: isn't velocity.x.length and velocity.y.length constant? I mean the length of array x is 17, thus this.location.step % this.velocity.x.length will be equal to zero until step will count to 17... Right? or not? – Anamed Apr 16 '15 at 08:48
  • @Anamed length is constant, step is not, so step will be in [0, length> range all the time. Modulo will not make it 0, just fit within that range (it returns a remainder). F.ex `0 % 17 = 0, 1 % 17 = 1 ... 16 % 17 = 16, 17 % 17 = 0, 18 % 17 = 1` etc. –  Apr 16 '15 at 09:56
1

If your goal is just to have a box moving in a sinusoidal graph, it can be done simpler.

This jsfiddle shows a slightly simpler example of a box moving in a sinusoidal graph where I just removed parts of your code and calculate the path with Math.sin and use time instead of precalculated values for x.

function update(){
    time += 0.1;
    ctx.clearRect(0,0, can_width, can_height);
    x = time;
    y = (can_height/2)+(can_height/2)*Math.sin(time);
    console.log(x, y);
    ctx.fillRect(x*16, y, 25, 25);
    window.setTimeout(update, 1000/30);
}  

The variables are modified to make it look ok on the canvas. You can edit the addition to time, and the altitude and base line for y, to fit your needs.

If you need to follow the specification in your code, look at the answer by Ken.

Robin
  • 1,111
  • 8
  • 18
-1

Since you want a sinusoidal move, it makes sense to use... the sin function.

The formula for a sinusoidal move is :

y = maxValue * sin ( 2 * PI * frequency * time ) ;

where the frequency is in Herz (== 'number of times per second') and time is in second.

Most likely you'll use Date.now(), so you'll have a time in millisecond, that you need to convert. Since the value of PI should not change in the near future, you can compute once the magic number

k = 2 * PI / 1000 = 0.006283185307179587

and the formula becomes :

 y = sin( k * frequency * Date.now() );

Here's a simple example on how to use the formula :

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var can_width = canvas.width;
var can_height = canvas.height;


// magic number
var k = 0.006283185307179587;
// oscillations per second
var frequency = 1/5;
// ...
var amplitude = can_width / 8; 


function animate() {
   ctx.clearRect(0,0,can_width, can_height);
   ctx.fillStyle= '#000';
   var y = amplitude * Math.sin ( k * frequency * Date.now() );
   ctx.fillRect(can_width/2, can_height/2 + y, 20, 20 );
}

setInterval(animate, 30);
<canvas id="canvas" width="400" height="200" style="background-color:red"></canvas>
GameAlchemist
  • 17,761
  • 6
  • 28
  • 54