一个画布互动,三个显示

时间:2017-10-08 18:57:37

标签: javascript canvas box2d

我正在创建一个浏览器游戏,它可以作为全息图播放。 屏幕应显示如下内容: https://www.youtube.com/watch?v=Y60mfBvXCj8

因此,我认为我必须创建4个画布(没问题),但其中三个应该只显示第一个发生的事情。 我试图让它绘制画布的图像,让它显示到另一个画布。

任何帮助将不胜感激!

游戏是用Box2D创建的。

编辑:

我希望在每个画布上绘制太空飞船,但只能控制一个。

我的代码:http://s000.tinyupload.com/index.php?file_id=68837773176112789787

问题是,它只显示在一个画布上!

我在HTML中添加的内容:

<canvas id="canvas1" width="500" height="500"></canvas>
<canvas id="canvas2"  width="500" height="500"></canvas>
<canvas id="canvas3"  width="500" height="500"></canvas>
<canvas id="canvas4"  width="500" height="500"></canvas>

是什么意思将其打印给其他人:

JS

var sourceCtx, destinationCtx, imageData;

//get the context of each canvas
sourceCtx = canvas2.getContext('2d');
canvas2Ctx = canvas3.getContext('2d');

//copy the data
imageData = sourceCtx.getImageData(0, 0, canvas2.width - 1, canvas2.height - 1);

//apply the image data
canvas3Ctx.putImageData(imageData, 0, 0);

//done

1 个答案:

答案 0 :(得分:1)

全息金字塔显示

如何渲染金字塔反射显示。

为此,请使用HTML中的单个显示画布和存储在内存中的画布进行渲染。

镜像渲染画布

渲染画布被剪裁为三角形以防止像素重叠并且镜像转换以便正确地看到最终效果。例如,文字又回到了前面。

然后将屏幕外渲染画布渲染到显示画布,从顶部开始,共制作4个副本,每个副本旋转90度。

渲染画布宽度将是显示宽度或高度的最小值,也是高度的一半,以适合显示。

需要全屏模式

要使FX工作,您需要进入全屏模式。我没有说明这是如何完成的,但我确信stackoverflow上有一个QA会引导您完成整个过程。

死区

在显示器的中心是金字塔将停留的区域(我称之为死区)由于许多这些显示器都是自制的,因此死区的大小会有所不同。在下面的演示的第一行是一个常量deadZoneSize,它将设置死区大小。它目前设置为0.1,即视图大小的10%。您可能需要调整此值以适合您的特定反射显示。

示例代码

代码示例在相关部分中充满了注释。它将创建和设置显示画布并渲染画布。创建剪辑区域并设置镜像渲染变换,以便您可以正常渲染。 mainLoop函数将调用名为renderContent的函数,第一个参数作为渲染画布的上下文。只需正常呈现您的内容(使用sizehSize获取可见渲染区域的宽度和高度(也许我应该使用更好的名称))

该演示包含一个示例渲染,只是为了它的乐趣,它全部位于底部,并且具有与问题无关的最小注释。

const deadZoneSize = 0.1; // As fraction of fitted box size

// for FX em and em4 are just custom unit size and 1/4 size
var em,em4;
// to fit all four views use the min width or height
var size = Math.min(innerWidth,innerHeight);
// half size
var hSize = size / 2 | 0;
// there is a small area where nothing should be displayed.
// This will depend on the pyrimide being used.
var deadZone = size * 0.1 | 0; // about 10% of view area

// Display canvas d for display
const dCanvas = document.createElement("canvas");

// Render canvas
const rCanvas = document.createElement("canvas");

// get rendering context for both
const dCtx = dCanvas.getContext("2d");
const rCtx = rCanvas.getContext("2d");

// Set the display canvas to fill the page
Object.assign(dCanvas.style,{
    position : "absolute",
    zIndex : 10, // place above 
    top : "0px",
    left : "0px",
    background : "black",
})

// add the display canvas to the DOM
document.body.appendChild(dCanvas);


//Size function resizes canvases when needed
function resize(){
    startTime = undefined;
    size = Math.min(innerWidth,innerHeight);
    hSize = size / 2 | 0;
    deadZone = size * deadZoneSize | 0; // about 10% of view area
    dCanvas.width = innerWidth;
    dCanvas.height = innerHeight;
    rCanvas.width = size; 
    rCanvas.height = hSize;  // half height
    em = size * 0.1 | 0; // define our own unit size
    em4 = Math.max(1,em * 0.25 | 0); // define quarter unit size min of 1    
}

// To ensure pixels do not stray outside the view area and overlap use a clip on the render canvas
// ctx the context to appy the clip path to
function defineClip(ctx){
    ctx.beginPath();
    ctx.lineTo(0,0);
    ctx.lineTo(size,0);
    ctx.lineTo(hSize + deadZone, hSize - deadZone);
    ctx.lineTo(hSize - deadZone, hSize - deadZone);
    ctx.clip();
    
    // The rendering is mirrored from the holo pyramid
    // to avoid seeing text mirrored you need to mirror the
    // rendering transform
    
    ctx.setTransform(-1,0,0,1,size,0); // x axis from right to left, origin at top right  
}

// Copying the rendered canvas to the display canvas
// ctx is the display canvas context
// image is the rendered canvas
function display(ctx,image) {
    // for each face of the pyramid render a view
    // Each image is just rotated 90 deg
    
    // first clear the canvas
    ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
    
    // top
    // use the center of the display canvas as the origin
    ctx.setTransform(1,0,0,1,ctx.canvas.width / 2 | 0, ctx.canvas.height / 2 | 0);
    // draw the image
    ctx.drawImage(image,-hSize,-hSize);

    // Right
    ctx.transform(0,1,-1,0,0,0);  // rotate 90 deg. This is better than ctx.rotate as it can have slight
                                  // problems due to floating point errors if not done correctly
    ctx.drawImage(image,-hSize,-hSize);
    // bottom
    ctx.transform(0,1,-1,0,0,0);
    ctx.drawImage(image,-hSize,-hSize);
    // left
    ctx.transform(0,1,-1,0,0,0);
    ctx.drawImage(image,-hSize,-hSize);
    
    // restore the default transform;
    ctx.setTransform(1,0,0,1,0,0);

}



// the main render loop 
var globalTime;
var startTime;
function mainLoop(time){
    // check canvas size. If not matching page then resize
    if(dCanvas.width !== innerWidth || dCanvas.height !== innerHeight) {
        resize();
    }
    if(startTime === undefined){ startTime = time }
    globalTime = time - startTime;
    
    // clear the render canvas ready for next render
    rCtx.setTransform(1,0,0,1,0,0); // reset transform
    rCtx.globalAlpha = 1;           // reset alpha
    rCtx.clearRect(0,0,size,hSize);
    
    // save the context state so that the clip can be removed
    rCtx.save();   
    defineClip(rCtx); // set the clip
    renderContent(rCtx); // call the rendering function

    // restore the context state which removes the clip
    rCtx.restore();
    
    // rendering is ready for display so render the holo view
    // on to the display canvas's context
    display(dCtx, rCanvas);


    requestAnimationFrame(mainLoop);

}
requestAnimationFrame(mainLoop);




//=====================================================================================================
// The following is just something interesting to display and is not directly related to the answer
//=====================================================================================================


// The main rendering function 
// This is where you render your content. It can be anything from a game to just plain old text
// You can even use a video element and display a video.
// The rendering context is already set up to correctly mirror the content so just render everything as normal

const randG  = (min, max , p = 2) => (max + min) / 2 + (Math.pow(Math.random(), p) * (max - min) * 0.5) * (Math.random() < 0.5 ? 1 : -1);

const bootUp = ["Power On",1,1000,"Sub system test",0.5, 3000, "Calibrating scanner",0.5, 6000, "Welcome",1,8000];
function noisyText(ctx){
    var textTime = globalTime / 8000; // 8 second boot up
    if(screenFlashDone){
        if(globalTime > screenFlashes[0]) { // play screen flash seq
            screenFlashes.shift();
            screenFlash(ctx,true,screenFlashes.shift(),screenFlashes.shift());
        }
    }else{
         screenFlash(ctx);
    }
    
    ctx.font = ((bootUp[1] * em) | 0) + "px monospace";
    ctx.textAlign = "center";
    ctx.textBaseline = "center";
    var tx = randG(-em4 * 4, em4 * 4, 64);  // G for kind of a bit like gausian. Last num controls distrubution
    var ty = randG(-em4 * 4, em4 * 4, 64);
    var xx = size / 2 + tx;
    var yy = em * 2 + ty;
    ctx.fillStyle = `hsl(${randG(160,250,32)|0},100%,50%)`;
    if(bootUp[2] < globalTime){
        bootUp.shift();
        bootUp.shift();
        bootUp.shift();
    }
    ctx.fillText(bootUp[0], xx, yy);
    ctx.save(); // need the normal non mirror transform for the noise FX
    ctx.setTransform(1,0,0,1,0,0);
    for(var y = -em/1.2|0; y < em/2; y += 1){
        if((yy+y) % 3 === 0){
            ctx.clearRect(0,yy+y,size,1);  // give scan line look
            
        }else{
            if(Math.random() < 0.1){ // only on 10% of lines.
                ctx.drawImage(ctx.canvas,0,yy + y, size, 2,randG(-em4 * 4,em4 * 4,32),yy + y, size, 2);
            }
        }
    }
    ctx.fillRect(0,((globalTime / 4000) * hSize)%hSize,size,2);
    
    ctx.filter = `blur(${randG(em4/2,em4,2)|0}px)`;
    ctx.drawImage(ctx.canvas,0,0);
    ctx.restore();
}
const screenFlashes = [0,500,3,1000,200,2,4000,100,3,6000,100,1,7500,50,1,7800,50,1, 9000];

var screenFlashStart;
var screenFlashLen;
var screenFlashDone = true;
var screenFlashLayers = 1;
function screenFlash(ctx,start,length,layers){
    if(start){
        screenFlashStart = globalTime;
        screenFlashLen = length;
        screenFlashDone = false;
        screenFlashLayers = layers;
    }
    var normTime = (globalTime - screenFlashStart) / screenFlashLen;
    if(normTime >= 1){
        screenFlashDone = true;
        normTime = 1;
    }
    for(var i = 0; i < screenFlashLayers; i++){
        var tx = randG(-em4 * 4, em4 * 4, 64);  // G for kind of a bit like gausian. Last num controls distrubution
        var ty = randG(-em4 * 4, em4 * 4, 64);
        ctx.globalAlpha = (1-normTime) * Math.random();
        ctx.fillStyle = `hsl(${randG(160,250,32)|0},100%,50%)`;
        ctx.fillRect(tx,ty,size,hSize);
    }
    ctx.globalAlpha = 1;
}

function randomBlur(ctx) {
    ctx.save(); // need the normal non mirror transform for the noise FX    
    ctx.filter = `blur(${randG(em4/2,em4,2)|0}px)`;
    ctx.drawImage(ctx.canvas,0,0);
    ctx.restore();
}

function ready(ctx) {
    ctx.fillStyle = "#0F0";
    ctx.font = em + "px monospace";
    ctx.textAlign = "center";
    ctx.textBaseline = "center";
    ctx.fillText("Holographic",hSize,em);
    ctx.font = em/2 + "px monospace";
    ctx.fillText("display ready.",hSize,em * 2);
    // draw edges
    ctx.strokeStyle = "#0F0";
    ctx.lineWidth = em4;
    ctx.beginPath();
    ctx.lineTo(0,0);
    ctx.lineTo(size,0);
    ctx.lineTo(hSize + deadZone, hSize - deadZone);
    ctx.lineTo(hSize - deadZone, hSize - deadZone);    
    ctx.closePath();
    ctx.stroke();
}
function renderContent(ctx){
    // all rendering is mirrored, but the transform takes care of that for you
    // just render as normal. Remember you can only see the
    // triangular area with the wide part at the top
    // and narrow at the bottom.
    
    // Anything below hSize - deadZone will also not appear
    if(globalTime < 8000){
        noisyText(ctx);
        randomBlur(ctx);
    }else{
        ready(ctx);
    }
    randomBlur(ctx);
    

}

快速侧面说明。我觉得你的问题符合SO要求并且不是主题,也不是要求别人编写代码。你已经证明你已经投入了大量精力进行研究。这个问题将引起其他人的兴趣。我希望这个答案有所帮助,祝你的项目好运,欢迎来到SO。