Анимация HTML5 поверх постоянно обновляющегося холста

#html #animation #canvas

#HTML #Анимация #холст

Вопрос:

Всем привет!

Я уже некоторое время работаю над игровым движком с изометрическими плитками в HTML5 / Canvas, и у меня есть полностью работающая игра. Ранее сегодня я просмотрел свой код и подумал: «хм, давайте попробуем сделать эту анимацию плавной …»

И с тех пор это все, что я пытался сделать.

Проблема
Я бы хотел, чтобы персонаж действительно «скользил» с плитки на плитку — но перерисовка холста не позволяет этого — у кого-нибудь есть какие-нибудь идеи ….? Ниже приведен код и скрипты…

Поработайте с этим! http://jsfiddle.net/neuroflux/n7VAu /

 <html>  
<head>
<title>tileEngine - Isometric</title>
<style type="text/css">
* { margin: 0px; padding: 0px; font-family: arial, helvetica, sans-serif; font-size: 12px; cursor: defau< }
</style>
<script type="text/javascript">
var map = Array( //land
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],
    [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]
);
var tileDict = Array("http://www.wikiword.co.uk/release-candidate/canvas/tileEngine/land.png");
var charDict = Array("http://www.wikiword.co.uk/release-candidate/canvas/tileEngine/mario.png");
var objectDict = Array("http://www.wikiword.co.uk/release-candidate/canvas/tileEngine/rock.png"); //last is one more
var objectImg = new Array();

var charImg = new Array();
var tileImg = new Array();

var loaded = 0;
var loadTimer;
var ymouse;
var xmouse;
var eventUpdate = 0;

var playerX = 0;
var playerY = 0;

function loadImg(){ //preload images and calculate the total loading time
    for(var i=0;i<tileDict.length;i  ){ 
        tileImg[i] = new Image();
        tileImg[i].src = tileDict[i];
        tileImg[i].onload = function(){
            loaded  ;
        }
    }
    i = 0;
    for(var i=0;i<charDict.length;i  ){
        charImg[i] = new Image();
        charImg[i].src = charDict[i];
        charImg[i].onload = function(){
            loaded  ;
        }
    }
    i = 0;
    for(var i=0;i<objectDict.length;i  ){
        objectImg[i] = new Image();
        objectImg[i].src = objectDict[i];
        objectImg[i].onload = function(){
            loaded  ;
        }
    }
}

function checkKeycode(event) { //key pressed
    var keycode;
    if(event == null) {
        keyCode = window.event.keyCode;
    } else {
        keyCode = event.keyCode;
    }
    switch(keyCode) {
        case 38: //left
            if(!map[playerX-1][playerY][1] > 0){
                playerX--;
            }
            break;
        case 40: //right
            if(!map[playerX 1][playerY][1]  > 0){
                playerX  ;
            }
            break;
        case 39: //up
            if(!map[playerX][playerY-1][1]  > 0){
                playerY--;
            }
            break;
        case 37: //down
            if(!map[playerX][playerY 1][1]  > 0){
                playerY  ;
            }
            break;
        default:
            break;
    }
}

function loadAll(){ //load the game
    if(loaded == tileDict.length   charDict.length   objectDict.length){
        clearInterval(loadTimer);
        loadTimer = setInterval(gameUpdate,100);
    }
}

function drawMap(){ //draw the map (in intervals)
    var tileH = 25;
    var tileW = 50;
    mapX = 80;
    mapY = 10;
    for(i=0;i<map.length;i  ){
        for(j=0;j<map[i].length;j  ){
            var drawTile= map[i][j][0];
            var xpos = (i-j)*tileH   mapX*4.5;
            var ypos = (i j)*tileH/2  mapY*3.0;
            ctx.drawImage(tileImg[drawTile],xpos,ypos);

            if(i == playerX amp;amp; j == playerY){
                you = ctx.drawImage(charImg[0],xpos,ypos-(charImg[0].height/2));
            }
        }
    }
}

function init(){ //initialise the main functions and even handlers
    ctx = document.getElementById('main').getContext('2d');
    loadImg();
    loadTimer = setInterval(loadAll,10);
    document.onkeydown = checkKeycode;
}

function gameUpdate() { //update the game, clear canvas etc
    ctx.clearRect(0,0,904,460); 
    ctx.fillStyle = "rgba(255, 255, 255, 1.0)"; //assign color
    drawMap();
}
</script>
</head> 
<body align="center" style="text-align: center;" onload="init()">   
    <canvas id="main" width="904" height="465">
        <h1 style="color: white; font-size: 24px;">I'll be damned, there be no HTML5 amp;amp; canvas support on this 'ere electronic machine!<sub>This game, jus' plain ol' won't work!</sub></h1>
    </canvas>
</body> 
</html>  
  

Редактировать:
Пожалуйста …?

Комментарии:

1. Вы бы настоятельно рекомендовали переделать все приложение для использования одного элемента canvas, если только у вас нет очень веских причин не делать этого. Вероятно, это избавит вас от дополнительной головной боли в долгосрочной перспективе.

2. Мое приложение действительно использует один canvas — я говорил, что наличие двух canvas ‘ было единственным способом, который я мог придумать для этого. Есть идеи? 🙁

3. Эй, я попробую это, когда у меня будет свободная минутка

4. Мне удалось заставить это работать, но с DIV над canvas с анимацией персонажа с помощью jQuery — я бы предпочел, чтобы все это было на canvas: jsfiddle.net/neuroflux/tTyFB

Ответ №1:

Чтобы анимировать с помощью canvas, вы должны перерисовывать весь затронутый участок в каждом кадре, иначе ваши объекты оставят за собой след. В каждом кадре анимации, перед перемещением спрайта, вы должны перерисовать три или четыре плитки сразу за ним.

Я бы предложил добавить некоторые дополнительные состояния в вашу функцию рисования, чтобы для каждого кадра обновлялись некоторые временные расстояния и перерисовывались соответствующие плитки и спрайты. Глобальная переменная блокировала бы ввод ключа во время выполнения анимации.

Я слишком ленив, чтобы писать это самому, но с вами все должно быть в порядке. Получайте удовольствие!

Комментарии:

1. ах, я думаю, я понимаю — есть ли шанс, что я мог бы умолять вас пересмотреть свою лень? ^_^

2. Извините, но у меня нет времени писать это.

Ответ №2:

Вот пример.Это не слишком точно, потому что я сделал это очень быстро.

По сути, когда пользователь нажимает кнопку, вы хотите начать обратный отсчет, где каждый последующий тик часов перемещает его ( 1, 2) и т.д. К своей цели. После некоторого количества тактов он перестает двигаться.

Отредактировано для использования измененного примера Ника. Смотрите комментарии.

Ответ №3: