views:

63

answers:

2

I have a simple Javascript program that displays a small rectangle in a canvas. The rectangle moves towards the mouse position. When it changes direction, it does so with sharp corners. As in, if the rectangle left a line behind, when I move my mouse in a circle, the rectangle would draw a tilted square.

What I'd want to happen, is that it would draw a circle. No sharp corners.

Here's the code I am using for changing the direction:

function changeDir()
{
if(mouseXCoord-5<x && x<mouseXCoord+5)
{
    xDirection = 0;//stop moving if close to mouse
}
else if(x>mouseXCoord)
{
    xDirection = -1;
}
else if(x<mouseXCoord)
{
    xDirection = 1;
}

if(mouseYCoord-5<y && y<mouseYCoord+5)
{
    yDirection = 0;//stop moving if close to mouse
}
else if(y>mouseYCoord)
{
    yDirection = -1;
}
else if(y<mouseYCoord)
{
    yDirection = 1;
}
}

The draw function:

function draw()
{
    context2D.clearRect(0, 0, canvas.width, canvas.height);
    fillwith = context2D.fillStyle='red';
    context2D.fillRect(x,y,10,10);
    changeDir();
    x = x + (thrust * xDirection);
    y = y + (thrust * yDirection);
    console.log(x,y,xDirection, yDirection,mouseXCoord,mouseYCoord);
}

So, how do I do that?

Update: I changed the changeDir() function so that it makes the corners of the tilted square rounded.

function changeDir()
{
    if(mouseXCoord-5<x && x<mouseXCoord+5)
    {
        xstop = true;//stop moving if close to mouse
    }
    else if(x>mouseXCoord)
    {
        if(Math.abs(xthrust)==mainThrust)
        {
            xthrust = -1*mainThrust;
        }
        else
        {
            xthrust--;
        }
        xstop = false;//make sure it moves
    }
    else if(x<mouseXCoord)
    {
        if(xthrust==mainThrust)
        {
            xthrust = mainThrust;
        }
        else
        {
            xthrust++;
        }
        xstop = false;//make sure it moves
    }

    if(mouseYCoord-5<y && y<mouseYCoord+5)
    {
        ystop = true;//stop moving if close to mouse
    }
    else if(y>mouseYCoord)
    {
        if(Math.abs(ythrust)==mainThrust)
        {
            ythrust = -1*mainThrust;
        }
        else
        {
            ythrust--;
        }
        ystop = false;//make sure it moves
    }
    else if(y<mouseYCoord)
    {
        if(ythrust==mainThrust)
        {
            ythrust = mainThrust;
        }
        else
        {
            ythrust++;
        }
        ystop = false;//make sure it moves
    }
    }

Here's the variables I declare:

const FPS = 5;
var x = 300;
var y = 200;
var xDirection = 1;
var yDirection = 1;
var image = new Image();
var canvas = null;
var context2D = null;
var mouseXCoord = 0;
var mouseYCoord = 0;
var mainThrust = 5;
var xthrust = mainThrust;
var ythrust = mainThrust;
var xstop = false;
var ystop = false;

Where it actualy moves:

changeDir();
if(!xstop)
 x = x + (xthrust);
if(!ystop)
 y = y + (ythrust);

Ok, here's my new code thanks to cape1232. I actually started over entirely. I get smooth turning, but the speed the block moves at changes. Demo at: http://develzone.davidreagan.net/jsMoveTesting/index.html

var gameVars = {
    fps: 30
}

var object = {
    name: 'default',
    xpos: 200,
    ypos: 200,
    xVect: 1,
    yVect: 1,
    thrust: 15
}
ctx = null;
canvas = null;
xMousePos = 0;
yMousePos = 0;
runGame = null;


function init()
{
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');
    $('#canvas').mousemove(getMousePos);
    $('#canvas').click(stop);

    //setTimeout('clearInterval(runGame);',30000);
}
function start()
{
    runGame = setInterval('run();',1000/gameVars.fps);
}
function run()
{
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    moveBlock();
    //ctx.translate(object.xpos,object.ypos);
    drawBlock();
    showMousePos = 'X: ' + xMousePos + ' Y: ' + yMousePos;
    ctx.fillText(showMousePos, 215,50);
}
function stop()
{
    //alert('hit stop');
    console.log('clicked');
    //if(e.keyCode == 113)
    if(runGame)
    {
        clearInterval(runGame);
        runGame = false;
        //console.log('stop true');
    }
    else
        start();
}
function drawBlock()
{
    ctx.fillRect(object.xpos,object.ypos,10,10);
}

function moveBlock()
{

    xDiff = xMousePos - object.xpos;
    yDiff = yMousePos - object.ypos;
    minDiff = Math.max(Math.min(xDiff, yDiff), 1);
    deltaX = xDiff / minDiff;
    deltaY = yDiff / minDiff;
    // Scale the deltas to limit the largest to mainThrust
    maxDelta = Math.max(Math.max(deltaX, deltaY), 1)
    if (maxDelta>object.thrust)
    {
        deltaX = deltaX * object.thrust / maxDelta;
        deltaY = deltaY * object.thrust / maxDelta;
    }


    if(object.xpos >= canvas.width)
    {
        object.xpos = 0;        
    }
    else
    {
        object.xpos += deltaX;
        //console.log('moveBlock xpos else: '+object.xpos);
    }
    if(object.ypos >= canvas.height)
    {
        object.ypos = 0;
    }
    else
    {
        object.ypos += deltaY;
        //console.log('moveBlock ypos else: '+object.ypos);
    }
    console.log('xpos: '+object.xpos);
    console.log('ypos: '+object.ypos);
    console.log('xMousePos: '+xMousePos);
    console.log('yMousePos: '+yMousePos);
    console.log('xDiff: '+xDiff);
    console.log('yDiff: '+yDiff);
    console.log('minDiff: '+minDiff);
    console.log('deltaX: '+xDiff+'/'+minDiff+ ' = '+ deltaX);
    console.log('deltaY: '+yDiff+'/'+minDiff+ ' = '+ deltaY);
    console.log('maxDelta: '+maxDelta);
}

function getMousePos(e)
{
    xMousePos = e.pageX;
    yMousePos = e.pageY;
    //console.log('Mouse Moved');
}
window.onload = init;
+2  A: 

You don't want your xDirection and yDirection to be only 1 or -1. They need to be proportional to the difference between the mouse and the rectangle position.

Edited to take comments into account.

function changeDir()
{
  xDiff = mouseXCoord - x;
  yDiff = mouseYCoord - y;
  // Scale the smallest diff to be 1 (or less)
  minDiff = max(min(xDiff, yDiff), 1);
  deltaX = xDiff / minDiff;
  deltaY = yDiff / minDiff;
  // Scale the deltas to limit the largest to mainThrust
  maxDelta = max(max(deltaX, deltaY), 1)
  if (maxDelta>mainThrust) 
  {
    deltaX = deltaX * mainThrust / maxDelta;
    deltaY = deltaY * mainThrust / maxDelta;
  }

  if(mouseXCoord-5<x && x<mouseXCoord+5)
  {
    xDirection = 0;//stop moving if close to mouse
  }
  else 
  {
    xDirection = deltaX;
  }

  if(mouseYCoord-5<y && y<mouseYCoord+5)
  {
    yDirection = 0;//stop moving if close to mouse
  }
  else 
  {
    yDirection = deltaY;
  }
}
cape1232
@Alex Martelli. Good point about not changing your current direction too abruptly. In my solution, if you don't track the mouse often enough, you will still get abrupt direction changes (when the mouse used to be way over "here" and is suddenly way over "there"), because it always tries to go straight at the mouse.I can quickly think of a hack that will smooth that out (e.g. use a weighted sum of the current direction and the new direction), but the real solution is a control theory problem I'm not an expert on. I think a PID controller would work, but I'm just guessing.
cape1232
PID Controller looks like the way to go: http://en.wikipedia.org/wiki/PID_controller
cape1232
Tried this. The rectangle just shot out of the canvas, and totally ignored my mouse position.You can't declare floats in javascript. So I had to take that part out.
David R.
I didn't pay attention to the javascript tag, and anyway wasn't aware that javascript doesn't have floats. So sorry for the dead end. The idea behind what I proposed was just to take a step along the line between the current position and the mouse's position at each step. You might be able to do that discretely using http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
cape1232
It still seems like it should work, but I can see why it shoots off the canvas. If your mouse is horizontally or vertically displaced from the rectangle, minDiff will be very small, like 1 or even smaller, like 0. Then the horizontal or vertical delta will be very large. I edited the answer to limit the deltas to your mainThrust value, and to use ints (which I think will work).
cape1232
OK, edits done. At this point, my suggestions are teetering on the border of helping vs. not helping, so I'll quit while I'm (hopefully) ahead.
cape1232
Hey, it works a lot better now. Though there's some funky speed stuff. Check: http://develzone.davidreagan.net/jsMoveTesting/Also, the Javascript max and min functions are Math.max, and Math.min.
David R.
ok, I set minDiff and maxDelta to a constant in order to get rid of the funky stuff. Thanks for the help!
David R.
A: 

Instead of having xDirection and yDirection (the sine and cosine of your direction, actually) sharply defined as 0, 1, or -1, you need to define more precisely the direction you should eventually be heading in, and recall what direction you were last moving in and how many "angular steps" you've done in changing the direction from what was to what it should be.

How many such angular steps you want to take for a change of direction, and whether each step should be of the same size or depend on how fast you're moving and/or how brusquely you're swerving, etc, is something you should adapt by trial and error, since it appears that what you're mostly after is to have things "look" right, so it's hard to give a precise prescription (for what looks right to you;-).

Alex Martelli
I did try something like that. See the updated code.
David R.