帆布简单的游戏视口

时间:2017-07-24 10:04:41

标签: javascript canvas

我想让我的游戏可以探索,我们可以在地图上移动。我尽力实现这个代码:https://jsfiddle.net/gfcarv/QKgHs/但它对我不起作用,我试图在很多方面解决这个问题,我搜索了互联网,找不到任何适合我代码的简单视口。

我只想让玩家始终位于画布中间,当我们点击(或按住点击)时,它会移动地图,但每个游戏对象都会保持在他们的位置。如果它到达地图的任何一侧,只要让它做,它就可以越过地图。 我想要地图,简单图像或一些生成的画布矩形等等。

这是我的简化代码:

function randomNumberFromRange( min, max ) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function testCollisionRectRect( rectangle1, rectangle2 ) {
    return rectangle1.x - rectangle1.width/2 <= rectangle2.x - rectangle2.width/2 + rectangle2.width
        && rectangle2.x - rectangle2.width/2 <= rectangle1.x - rectangle1.width/2 + rectangle1.width
        && rectangle1.y - rectangle1.height/2 <= rectangle2.y - rectangle2.height/2 + rectangle2.height
        && rectangle2.y - rectangle2.height/2 <= rectangle1.y - rectangle1.height/2 + rectangle1.height;
}

Array.prototype.remove = function() {
    var what, a = arguments, L = a.length, ax;
    while (L && this.length) {
        what = a[--L];
        while ((ax = this.indexOf(what)) !== -1) {
            this.splice(ax, 1);
        }
    }
    return this;
}; // Function to pop specific element drom array by value


function drawLine( startX, startY, endX, endY, color, width ) {
    ctx.save();
    ctx.strokeStyle = color;
    ctx.lineWidth = width;
    ctx.beginPath();
    ctx.moveTo(startX,startY);
    ctx.lineTo(endX,endY);
    ctx.stroke();
    ctx.restore();
}

function drawBorder( x, y, width, height, lineWidth, strokeColor ) {
    ctx.save();
    ctx.lineWidth = lineWidth;
    ctx.strokeStyle = strokeColor;
    ctx.strokeRect( x, y, width, height);
    ctx.restore();
}

function drawRect( x, y, width, height, fillColor ) {
    ctx.save();
    ctx.fillStyle = fillColor;
    ctx.fillRect( x, y, width, height );
    ctx.restore();
}


// ====================
//   Global variables
// ====================

var ctx = $("#canvas")[0].getContext('2d'),
canvas = document.getElementById('canvas'),
    cHeight = canvas.height = 500,
    cWidth = canvas.width = 500,
    canvasOffset = $('#canvas').offset(),
    offsetX = canvasOffset.left,
    offsetY = canvasOffset.top,
    frameCounter = 0,
    enemyList = [],
    spawningEnemies_FLAG = true,
    isLeftMouseButtonHeld_FLAG = false,
    cursors = ['default', 'pointer'],
    enemiesOnMap = 100,
    fps = 120,
    mouseX,
    mouseY;


// canvas settings
ctx.font = '22px Arial';


var sharedBehaviour = {
    x: cWidth / 2,
    y: cHeight / 2,
    id: undefined,
    type: 'entity',
    width: 15,
    height: 15,
    fillColor: '#E15258',
    targetX: null,
    targetY: null,
    bulletSpeed: 1,
    speed: 1,

    update( type ) {
        // if there is target
        if( this.targetX !== null ) {
            // Find out distance to target
            var distanceX = this.targetX - this.x; // distance on X axis
            var distanceY = this.targetY - this.y; // distance on Y axis
            var distanceToTarget = Math.sqrt( distanceX*distanceX + distanceY*distanceY ); // distance

            // If distance is smaller or equal speed, then just set position
            if( distanceToTarget <= this.speed ) {
                this.x = this.targetX;
                this.y = this.targetY;
                // Then reset
                this.targetX = this.targetY = null;
            } else { // If distance is bigger than speed, so we want to move with speed
                distanceX = distanceX / distanceToTarget;
                distanceY = distanceY / distanceToTarget;
                distanceX = distanceX * this.speed;
                distanceY = distanceY * this.speed;
                this.x += distanceX;
                this.y += distanceY;
            }
        }
    },
    draw( type ) {
        drawRect( this.x - this.width/2, this.y - this.height/2, this.width, this.height, this.fillColor );
    },
    isColliding( entity ) {
        return testCollisionRectRect( this, entity );
    }
};


var player = Object.assign({}, sharedBehaviour, {
    x: cWidth/2 - 12.5,
    y: cHeight/2 - 12.5,
    id: 980722,
    type: 'player',
    width: 25,
    height: 25,
    fillColor: '#82d877',
    speed: 2.5,
    isWithinRange( entity, val ) {
        // Check if enemy is on player
        var distanceX = this.x - entity.x;
        var distanceY = this.y - entity.y;
        return Math.sqrt( distanceX*distanceX + distanceY*distanceY ) < val;
    }
});


function createEnemy( x, y, type, width, height, fillColor, speed, name ) {
    var newEnemy = Object.assign({}, sharedBehaviour, {
        x,
        y,
        type,
        width,
        height,
        name,
        fillColor,
        speed,
        setTarget( entity ) {
            this.targetX = entity.x + randomNumberFromRange(-50, 50); // Set X with some random number
            this.targetY = entity.y + randomNumberFromRange(-50, 50); // Set Y with some random number
        },
        isOnPlayer( val ) {
            // Check if enemy is on player
            var distanceX = player.x - this.x;
            var distanceY = player.y - this.y;
            return Math.sqrt( distanceX*distanceX + distanceY*distanceY ) < val;
        },
        isMouseOver( ) {
            return (this.mouseX + this.width/2 >= this.x && this.mouseX + this.width/2 <= this.x + this.width && this.mouseY + this.height/2 >= this.y && this.mouseY + this.height/2 <= this.y + this.height);
        }
    });

    enemyList.push( newEnemy );
}

function newGame( ) {
    player.x = cWidth/2 - 12.5;
    player.y = cHeight/2 - 12.5;
    frameCounter = 0;
    enemyList = [];
    spawningEnemies_FLAG = true;
    isLeftMouseButtonHeld_FLAG = false;

    // Spawning enemies
    for( i=0; i < randomNumberFromRange(15, 25); i++ ) {
        createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'passive', randomNumberFromRange(12, 18), randomNumberFromRange(12, 18), 'red', 1, 's' );
        createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'agressive', randomNumberFromRange(10, 16), randomNumberFromRange(10, 16), 'lightblue', 1.5, 'l' ); 
    }

    update();
}


function update( ) {
    frameCounter++;
    ctx.clearRect(0,0,cWidth,cHeight);

    // ========== Update ==========
        // Player
        player.update('player');
        // Enemies
        enemyList.forEach( enemy => { enemy.update(); });


    // ========== Draw ==========
        // Enemies
        enemyList.forEach( enemy => { enemy.draw(); });
        // Player
        player.draw('player');


    // ========== Conditions ==========
        // Enemies
            // Behaviour
            enemyList.forEach( enemy => {
                if ( Math.random() < ( 1 / 15 ) ) {
                    if ( enemy.isOnPlayer( player.circleRadius ) ) {
                        if ( ! (enemy.isOnPlayer( 50 )) ) {
                            enemy.setTarget( player );
                        } 
                    }
                }

                if ( Math.random() < ( 1 / 800 )) {
                    if ( ! (enemy.isOnPlayer( player.circleRadius )) ) enemy.setTarget( enemy );
                }

                if ( enemy.isOnPlayer(player.circleRadius/2 - 25 ) ) {
                    enemy.targetX = enemy.targetY = null;
                }

                ( enemyList.length === enemiesOnMap ) ? spawningEnemies_FLAG = false : spawningEnemies_FLAG = true;
            });

    setTimeout(function() { requestAnimationFrame(update); }, 1000 / fps);
}


function setPlayerTarget_and_checkPlayerPosition( mouse ) {
    player.targetX = mouseX;
    player.targetY = mouseY;

    if (player.targetX < player.width/2)   player.targetX = player.width/2; 
    if (player.targetX > cWidth - player.width/2)   player.targetX = cWidth - player.width/2;
    if (player.targetY < player.height/2)   player.targetY = player.height/2; 
    if (player.targetY > cHeight - player.height/2)   player.targetY = cHeight - player.height/2;
}

canvas.addEventListener('mousedown', function( mouse ) {
    isLeftMouseButtonHeld_FLAG = true;
    setPlayerTarget_and_checkPlayerPosition(mouse);
});

canvas.addEventListener('mouseup', function( mouse ) {
    isLeftMouseButtonHeld_FLAG = false;
});

canvas.addEventListener('mousemove', function( mouse ) {
    if( isLeftMouseButtonHeld_FLAG ) {
        setPlayerTarget_and_checkPlayerPosition(mouse);
    }
});

canvas.addEventListener('mousemove', function( mouse ) {
    mouseX = parseInt(mouse.clientX - offsetX);
    mouseY = parseInt(mouse.clientY - offsetY);
});

newGame();
canvas { border: 1px solid black; background-color: white; }
<canvas id="canvas"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 

1 个答案:

答案 0 :(得分:3)

移动视口以使玩家保持在中心位置非常简单:

您只需使用ctx.setTransform(1, 0, 0, 1, centerX - player.x, centerY - player.Y);

即可

现在,使用您当前的鼠标逻辑,您实际上需要一个viewPort对象,只有两个属性xy,这样您仍然可以获得光标和你的球员。

您显然还需要删除在setPlayerTarget_and_checkPlayerPosition函数中执行的边界检查。

&#13;
&#13;
function randomNumberFromRange( min, max ) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function testCollisionRectRect( rectangle1, rectangle2 ) {
    return rectangle1.x - rectangle1.width/2 <= rectangle2.x - rectangle2.width/2 + rectangle2.width
        && rectangle2.x - rectangle2.width/2 <= rectangle1.x - rectangle1.width/2 + rectangle1.width
        && rectangle1.y - rectangle1.height/2 <= rectangle2.y - rectangle2.height/2 + rectangle2.height
        && rectangle2.y - rectangle2.height/2 <= rectangle1.y - rectangle1.height/2 + rectangle1.height;
}

Array.prototype.remove = function() {
    var what, a = arguments, L = a.length, ax;
    while (L && this.length) {
        what = a[--L];
        while ((ax = this.indexOf(what)) !== -1) {
            this.splice(ax, 1);
        }
    }
    return this;
}; // Function to pop specific element drom array by value


function drawLine( startX, startY, endX, endY, color, width ) {
    ctx.save();
    ctx.strokeStyle = color;
    ctx.lineWidth = width;
    ctx.beginPath();
    ctx.moveTo(startX,startY);
    ctx.lineTo(endX,endY);
    ctx.stroke();
    ctx.restore();
}

function drawBorder( x, y, width, height, lineWidth, strokeColor ) {
    ctx.save();
    ctx.lineWidth = lineWidth;
    ctx.strokeStyle = strokeColor;
    ctx.strokeRect( x, y, width, height);
    ctx.restore();
}

function drawRect( x, y, width, height, fillColor ) {
    ctx.save();
    ctx.fillStyle = fillColor;
    ctx.fillRect( x, y, width, height );
    ctx.restore();
}


// ====================
//   Global variables
// ====================

var ctx = $("#canvas")[0].getContext('2d'),
canvas = document.getElementById('canvas'),
    cHeight = canvas.height = 500,
    cWidth = canvas.width = 500,
    canvasOffset = $('#canvas').offset(),
    offsetX = canvasOffset.left,
    offsetY = canvasOffset.top,
    frameCounter = 0,
    enemyList = [],
    spawningEnemies_FLAG = true,
    isLeftMouseButtonHeld_FLAG = false,
    cursors = ['default', 'pointer'],
    enemiesOnMap = 100,
    fps = 120,
    mouseX,
    mouseY;


// canvas settings
ctx.font = '22px Arial';

var viewPort = {
  x: cWidth/2,
  y: cHeight/2,
  update() {
    this.x = cWidth / 2 - player.x;
    this.y = cHeight / 2 - player.y;
  }
};
var sharedBehaviour = {
    x: cWidth / 2,
    y: cHeight / 2,
    id: undefined,
    type: 'entity',
    width: 15,
    height: 15,
    fillColor: '#E15258',
    targetX: null,
    targetY: null,
    bulletSpeed: 1,
    speed: 1,

    update( type ) {
        // if there is target
        if( this.targetX !== null ) {
            // Find out distance to target
            var distanceX = this.targetX - this.x; // distance on X axis
            var distanceY = this.targetY - this.y; // distance on Y axis
            var distanceToTarget = Math.sqrt( distanceX*distanceX + distanceY*distanceY ); // distance

            // If distance is smaller or equal speed, then just set position
            if( distanceToTarget <= this.speed ) {
                this.x = this.targetX;
                this.y = this.targetY;
                // Then reset
                this.targetX = this.targetY = null;
            } else { // If distance is bigger than speed, so we want to move with speed
                distanceX = distanceX / distanceToTarget;
                distanceY = distanceY / distanceToTarget;
                distanceX = distanceX * this.speed;
                distanceY = distanceY * this.speed;
                this.x += distanceX;
                this.y += distanceY;
            }
        }
    },
    draw( type ) {
        drawRect( this.x - this.width/2, this.y - this.height/2, this.width, this.height, this.fillColor );
    },
    isColliding( entity ) {
        return testCollisionRectRect( this, entity );
    }
};


var player = Object.assign({}, sharedBehaviour, {
    x: cWidth/2 - 12.5,
    y: cHeight/2 - 12.5,
    id: 980722,
    type: 'player',
    width: 25,
    height: 25,
    fillColor: '#82d877',
    speed: 2.5,
    isWithinRange( entity, val ) {
        // Check if enemy is on player
        var distanceX = this.x - entity.x;
        var distanceY = this.y - entity.y;
        return Math.sqrt( distanceX*distanceX + distanceY*distanceY ) < val;
    }
});


function createEnemy( x, y, type, width, height, fillColor, speed, name ) {
    var newEnemy = Object.assign({}, sharedBehaviour, {
        x,
        y,
        type,
        width,
        height,
        name,
        fillColor,
        speed,
        setTarget( entity ) {
            this.targetX = entity.x + randomNumberFromRange(-50, 50); // Set X with some random number
            this.targetY = entity.y + randomNumberFromRange(-50, 50); // Set Y with some random number
        },
        isOnPlayer( val ) {
            // Check if enemy is on player
            var distanceX = player.x - this.x;
            var distanceY = player.y - this.y;
            return Math.sqrt( distanceX*distanceX + distanceY*distanceY ) < val;
        },
        isMouseOver( ) {
            return (this.mouseX + this.width/2 >= this.x && this.mouseX + this.width/2 <= this.x + this.width && this.mouseY + this.height/2 >= this.y && this.mouseY + this.height/2 <= this.y + this.height);
        }
    });

    enemyList.push( newEnemy );
}

function newGame( ) {
    player.x = cWidth/2 - 12.5;
    player.y = cHeight/2 - 12.5;
    frameCounter = 0;
    enemyList = [];
    spawningEnemies_FLAG = true;
    isLeftMouseButtonHeld_FLAG = false;

    // Spawning enemies
    for( i=0; i < randomNumberFromRange(15, 25); i++ ) {
        createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'passive', randomNumberFromRange(12, 18), randomNumberFromRange(12, 18), 'red', 1, 's' );
        createEnemy( randomNumberFromRange(0, cWidth), randomNumberFromRange(0, cHeight), 'agressive', randomNumberFromRange(10, 16), randomNumberFromRange(10, 16), 'lightblue', 1.5, 'l' ); 
    }

    update();
}


function update( ) {
    frameCounter++;
    
    ctx.setTransform(1,0,0,1,0,0); // reset before clearing
    ctx.clearRect(0,0,cWidth,cHeight);

    // ========== Update ==========
        // Player
        player.update('player');
        // Enemies
        enemyList.forEach( enemy => { enemy.update(); });
        // viewPort
        viewPort.update()
    // ========== Draw ==========
        // viewPort
        ctx.setTransform(1,0,0,1, viewPort.x, viewPort.y);
        // Enemies
        enemyList.forEach( enemy => { enemy.draw(); });
        // Player
        player.draw('player');


    // ========== Conditions ==========
        // Enemies
            // Behaviour
            enemyList.forEach( enemy => {
                if ( Math.random() < ( 1 / 15 ) ) {
                    if ( enemy.isOnPlayer( player.circleRadius ) ) {
                        if ( ! (enemy.isOnPlayer( 50 )) ) {
                            enemy.setTarget( player );
                        } 
                    }
                }

                if ( Math.random() < ( 1 / 800 )) {
                    if ( ! (enemy.isOnPlayer( player.circleRadius )) ) enemy.setTarget( enemy );
                }

                if ( enemy.isOnPlayer(player.circleRadius/2 - 25 ) ) {
                    enemy.targetX = enemy.targetY = null;
                }

                ( enemyList.length === enemiesOnMap ) ? spawningEnemies_FLAG = false : spawningEnemies_FLAG = true;
            });
// this is bad vvv
//    setTimeout(function() {
requestAnimationFrame(update);
//}, 1000 / fps);
}


function setPlayerTarget_and_checkPlayerPosition( mouse ) {
    player.targetX = mouseX;
    player.targetY = mouseY;
// a few lines are gone here...
}

canvas.addEventListener('mousedown', function( mouse ) {
    isLeftMouseButtonHeld_FLAG = true;
    setPlayerTarget_and_checkPlayerPosition(mouse);
});

canvas.addEventListener('mouseup', function( mouse ) {
    isLeftMouseButtonHeld_FLAG = false;
});

canvas.addEventListener('mousemove', function( mouse ) {
    if( isLeftMouseButtonHeld_FLAG ) {
        setPlayerTarget_and_checkPlayerPosition(mouse);
    }
});

canvas.addEventListener('mousemove', function( mouse ) {
    var rect = canvas.getBoundingClientRect(); // offset may change in snippets
    mouseX = parseInt(mouse.clientX - rect.left - viewPort.x);
    mouseY = parseInt(mouse.clientY - rect.top - viewPort.y);
});

newGame();
&#13;
canvas { border: 1px solid black; background-color: white; }
&#13;
<canvas id="canvas"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
&#13;
&#13;
&#13;