Transparent canvas viewport

I want to make my game accessible so we can navigate the map. I tried to implement this code: https://jsfiddle.net/gfcarv/QKgHs/ , but it didn't work for me, I tried to solve it in different ways, I searched the web and couldn't find a simple viewport that can match my code ...

I just want the player to always be in the middle of the canvas, and when we click (or hold down) it moves the map, but each game object remains in its position. If it reaches either side of the map, just let it be done, it can move around the map. And I need a map, a simple image or some generated canvas rectangles or whatever.

This is my simplified code:

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> 
      

Run codeHide result


+3


source to share


1 answer


Moving the viewport to keep the player centered is pretty straightforward:

You can just use ctx.setTransform(1, 0, 0, 1, centerX - player.x, centerY - player.Y)

;

Now with your current mouse logic, you really need an object viewPort

with two properties x

and y

so that you can get the correct distance between the cursor and your player.



You also obviously need to remove the constraints you met in setPlayerTarget_and_checkPlayerPosition

.

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();
      

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>
      

Run codeHide result


+3


source







All Articles