【问题标题】:How to create a camera view in canvas that will follow a players rotation and rotation?如何在画布中创建一个跟随玩家旋转和旋转的相机视图?
【发布时间】:2015-04-22 20:18:20
【问题描述】:

我正在尝试使用 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()

【问题讨论】:

  • 你是故意在 Canvas/native JS 中做这个来学习的吗?有许多用于 html5/js 游戏开发的框架,我之前使用过 Phaser.JS,它是一个非常棒的游戏开发框架。我没有你的答案,除了你想要旋转整个世界和所有物体,这将是一些工作,除非你可以将它们全部放在图层上并旋转它们,这将是一些工作要做靠自己。
  • 是的,是上课用的。

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


【解决方案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(),因为稍后会重置转换,例如参见演示)。

这使您可以移动飞船而不必担心当前的变换,当需要旋转时,使用飞船的当前位置作为平移和旋转的中心。

最后一点:您将用于旋转的角度当然是应该表示的反角(即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}
&lt;canvas&gt;&lt;/canvas&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-11
    相关资源
    最近更新 更多