如何在画布中创建一个跟随玩家轮换和旋转的摄影机视图?

时间:2015-04-22 20:18:21

标签: javascript html5 canvas html5-canvas game-physics

我尝试使用javascript在画布上创建一个游戏,你可以控制太空飞船并让它进行平移和旋转,使其看起来就像宇宙飞船保持静止而不是旋转。

非常感谢任何帮助。

window.addEventListener("load",eventWindowLoaded, false);

function eventWindowLoaded() {
canvasApp();    
}

function canvasSupport() {
return Modernizr.canvas;    
}

function canvasApp() {
if (!canvasSupport()) {
    return;
}

var theCanvas = document.getElementById("myCanvas");
var height = theCanvas.height; //get the heigth of the canvas
var width = theCanvas.width;  //get the width of the canvas
var context = theCanvas.getContext("2d");  //get the context

var then = Date.now();

var bgImage = new Image();

var stars = new Array;

bgImage.onload = function() {
    context.translate(width/2,height/2);
    main();
}



var rocket = {
    xLoc: 0,
    yLoc: 0,
    score : 0,
    damage : 0,
    speed : 20,
    angle : 0,
    rotSpeed : 1,
    rotChange: 0,
    pointX: 0,
    pointY: 0,

    setScore : function(newScore){
        this.score = newScore;
    }
}

function Star(){
    var dLoc = 100;
    this.xLoc = rocket.pointX+ dLoc - Math.random()*2*dLoc;
    this.yLoc = rocket.pointY + dLoc - Math.random()*2*dLoc;
    //console.log(rocket.xLoc+" "+rocket.yLoc);
    this.draw = function(){
        drawStar(this.xLoc,this.yLoc,20,5,.5);
    }
}

//var stars = new Array;

var drawStars = function(){
    context.fillStyle = "yellow";
    if (typeof stars !== 'undefined'){
        //console.log("working");
        for(var i=0;i< stars.length ;i++){
            stars[i].draw();
        }
    }


}

var getDistance = function(x1,y1,x2,y2){
    var distance = Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2));
    return distance;
}

var updateStars = function(){
    var numStars = 10;
    while(stars.length<numStars){
        stars[stars.length] = new Star();
    }
    for(var i=0; i<stars.length; i++){
        var tempDist = getDistance(rocket.pointX,rocket.pointY,stars[i].xLoc,stars[i].yLoc);
        if(i == 0){
            //console.log(tempDist);
        }
        if(tempDist > 100){
            stars[i] = new Star();
        }
    }
}

function drawRocket(xLoc,yLoc, rWidth, rHeight){
    var angle = rocket.angle;

    var xVals = [xLoc,xLoc+(rWidth/2),xLoc+(rWidth/2),xLoc-(rWidth/2),xLoc-(rWidth/2),xLoc];
    var yVals = [yLoc,yLoc+(rHeight/3),yLoc+rHeight,yLoc+rHeight,yLoc+(rHeight/3),yLoc];


    for(var i = 0; i < xVals.length; i++){
        xVals[i] -= xLoc;
        yVals[i] -= yLoc+rHeight;
        if(i == 0){
            console.log(yVals[i]);
        }
        var tempXVal = xVals[i]*Math.cos(angle) - yVals[i]*Math.sin(angle);
        var tempYVal = xVals[i]*Math.sin(angle) + yVals[i]*Math.cos(angle);
        xVals[i] = tempXVal + xLoc;
        yVals[i] = tempYVal+(yLoc+rHeight);
    }

    rocket.pointX = xVals[0];
    rocket.pointY = yVals[0];
    //rocket.yLoc = yVals[0];
    //next rotate

    context.beginPath();
    context.moveTo(xVals[0],yVals[0])
    for(var i = 1; i < xVals.length; i++){
        context.lineTo(xVals[i],yVals[i]);
    }
    context.closePath();
    context.lineWidth = 5;
    context.strokeStyle = 'blue';
    context.stroke();

}

var world = {
    //pixels per second
    startTime: Date.now(),
    speed: 50,
    startX:width/2,
    startY:height/2,
    originX: 0,
    originY: 0,
    xDist: 0,
    yDist: 0,
    rotationSpeed: 20,
    angle: 0,
    distance: 0,
    calcOrigins : function(){
        world.originX = -world.distance*Math.sin(world.angle*Math.PI/180);
        world.originY = -world.distance*Math.cos(world.angle*Math.PI/180);
    }
};

var keysDown = {};

addEventListener("keydown", function (e) {
   keysDown[e.keyCode] = true;
}, false);

addEventListener("keyup", function (e) {
   delete keysDown[e.keyCode];
}, false);

var update = function(modifier) {
    if (37 in keysDown) { // Player holding left
        rocket.angle -= rocket.rotSpeed* modifier;
        rocket.rotChange = - rocket.rotSpeed* modifier;
        //console.log("left");
    }
    if (39 in keysDown) { // Player holding right
        rocket.angle += rocket.rotSpeed* modifier;
        rocket.rotChange = rocket.rotSpeed* modifier;
        //console.log("right");


    }


};



var render = function (modifier) {
    context.clearRect(-width*10,-height*10,width*20,height*20);

    var dX = (rocket.speed*modifier)*Math.sin(rocket.angle);
    var dY = (rocket.speed*modifier)*Math.cos(rocket.angle);

    rocket.xLoc += dX;
    rocket.yLoc -= dY;

    updateStars();
    drawStars();
    context.translate(-dX,dY);
    context.save();
    context.translate(-rocket.pointX,-rocket.pointY);




    context.translate(rocket.pointX,rocket.pointY);
    drawRocket(rocket.xLoc,rocket.yLoc,50,200);
    context.fillStyle = "red";
    context.fillRect(rocket.pointX,rocket.pointY,15,5);

    //context.restore(); // restores the coordinate system back to (0,0)

    context.fillStyle = "green";
    context.fillRect(0,0,10,10);
    context.rotate(rocket.angle);
    context.restore();











};

function drawStar(x, y, r, p, m)
{
    context.save();
    context.beginPath();
    context.translate(x, y);
    context.moveTo(0,0-r);
    for (var i = 0; i < p; i++)
    {
        context.rotate(Math.PI / p);
        context.lineTo(0, 0 - (r*m));
        context.rotate(Math.PI / p);
        context.lineTo(0, 0 - r);
    }
    context.fill();
    context.restore();
}



// the game loop

function main(){
    requestAnimationFrame(main);


    var now = Date.now();
    var delta = now - then;

   update(delta / 1000);
    //now = Date.now();
    //delta = now - then;
   render(delta / 1000);

   then = now;

// Request to do this again ASAP


}

var w = window;
var requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame ||    w.mozRequestAnimationFrame;
//start the game loop
//gameLoop();

//event listenters
bgImage.src = "images/background.jpg";



} //canvasApp()

1 个答案:

答案 0 :(得分:1)

来源

如果您需要在画布上旋转某些内容,它将始终围绕原点旋转,或者如果您喜欢x和y轴交叉的位置,则会围绕网格旋转。

您可能会发现 answer here 也很有用

默认情况下,原点位于位图的(0,0)左上角。

因此,为了围绕(x,y)点旋转内容,必须首先将原点转换为该点,然后旋转并最终(通常)平移回原点。现在可以按正常顺序绘制事物,并且它们都将相对于该旋转点旋转绘制:

ctx.translate(rotateCenterX, rotateCenterY);
ctx.rotate(angleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);

绝对角度和位置

如果使用绝对角度而不是使用随时间积累的角度,有时更容易跟踪。

translate()transform()rotate()等是累积方法;他们添加到以前的转换。我们可以使用setTransform()设置绝对变换(最后两个参数用于翻译):

ctx.setTransform(1, 0, 0, 1, rotateCenterX, rotateCenterY);  // absolute
ctx.rotate(absoluteAngleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);

rotateCenterX / Y将表示未转换绘制的船舶位置。此外,绝对变换可以是更好的选择,因为您可以使用绝对角度进行旋转,绘制背景,重置变换,然后在rotateCenterX / Y处在船上绘制:

ctx.setTransform(1, 0, 0, 1, rotateCenterX, rotateCenterY);
ctx.rotate(absoluteAngleInRadians);
ctx.translate(-rotateCenterX, -rotateCenterY);

// update scene/background etc.

ctx.setTransform(1, 0, 0, 1, 0, 0);   // reset transforms
ctx.drawImage(ship, rotateCenterX, rotateCenterY);

(根据事物的顺序,你可以用translate()代替第一行,因为稍后会重置变换,例如见demo。)

这使您可以在不需要担心当前变换的情况下移动船只,当需要旋转时,使用船舶的当前位置作为平移和旋转的中心。

最后一点:你用来旋转的角度当然应该是应该表示的反角(即ctx.rotate(-angle);)。

太空演示(“随机”运动和旋转)

红色“流星”在一个方向(从顶部)下降,但随着船“导航”,它们将相对于我们的顶视角改变方向。相机将固定在船的位置上。

(忽略凌乱的部分 - 它只是用于演示设置,我讨厌滚动条......专注于中心部分:))

var img = new Image();
img.onload = function() {
  var ctx = document.querySelector("canvas").getContext("2d"),
      w = 600, h = 400, meteors = [], count = 35, i = 0, x = w * 0.5, y, a = 0, a2 = 0;
  ctx.canvas.width = w; ctx.canvas.height = h; ctx.fillStyle = "#555";
  while(i++ < count) meteors.push(new Meteor());
  (function loop() {
    ctx.clearRect(0, 0, w, h);
    
    y = h * 0.5 + 30 + Math.sin((a+=0.01) % Math.PI*2) * 60; // ship's y and origin's y

    // translate to center of ship, rotate, translate back, render bg, reset, draw ship
    ctx.translate(x, y);                 // translate to origin
    ctx.rotate(Math.sin((a2+=0.005) % Math.PI) - Math.PI*0.25);  // rotate some angle
    ctx.translate(-x, -y);               // translate back
   
    ctx.beginPath();  // render some moving meteors for the demo
    for(var i = 0; i < count; i++) meteors[i].update(ctx); ctx.fill();
    
    ctx.setTransform(1, 0, 0, 1, 0, 0);  // reset transforms
    ctx.drawImage(img, x - 32, y);       // draw ship as normal
    
    requestAnimationFrame(loop);         // loop animation
  })();
};

function Meteor() {    // just some moving object..
  var size = 5 + 35 * Math.random(), x = Math.random() * 600, y = -200;
  this.update = function(ctx) {
    ctx.moveTo(x + size, y);  ctx.arc(x, y, size, 0, 6.28);
    y += size * 0.5; if (y > 600) y = -200;
  };
}
img.src = "http://i.imgur.com/67KQykW.png?1";
body {background:#333} canvas {background:#000}
<canvas></canvas>