Как реализовать увеличение змейки?

143
22 ноября 2019, 06:50

Всем добрый вечер. Я продолжаю писать змейку без использования canvas, игра почти готова, но осталось реализовать довольно сложный процесс - увеличение змейки при поедании яблока. Здесь же возник вопрос, как это реализовать, пока что вообще никаких идей по этому поводу нету. В коде по максимуму попытался объяснить что за что отвечает, заранее спасибо за подкинутые идеи, возможно готовые решения. Строго не судите, я еще не профи в Js) Вот и сам код: CodePen

var mainBlock = document.getElementById("mainBlock"), // Игровая область 
    snakeBlock = document.getElementById("snakeBlock"), // Змейка(белый квадрат) 
    appleBlock = document.getElementById("appleBlock"), // Яблоко(черный квадрат) 
    scoreBlock = document.getElementsByClassName("scoreBlock")[0], // Блок очков 
    score = document.getElementById("score"), // Набранные очки 
    scoreValue = Number(score.innerHTML), // Отображение набранных очков 
    playBtn = document.getElementById("playBtn"), // Кнопка PLAY 
    myConfirm = document.getElementById("myConfirm"), // Свое окно Confirm 
    okeyBtn = document.getElementById("agree"), // Кнопка OK(PLAY в confirm) 
    exitBtn = document.getElementById("desagree"), // Кнопка EXIT 
    snakeX = mainBlock.offsetWidth/2 - 10, // Начальные координаты змейки по X, центр 
    snakeY = mainBlock.offsetHeight/2 - 10, // Начальные координаты змейки по Y, центр 
    appleX, appleY, // Координаты яблока(зададим позже) 
    t, // Переменная для будущей установки/сброса setInterval 
    activeGame = false, // Игра не запущена по умолчанию 
    eatCost = 10, // Стоимость одного яблока 
    maxX = mainBlock.clientWidth - 20, // 20px - ширина головы змейки 
    maxY = mainBlock.clientHeight - 20; // 20px - высота головы змейки 
 
 
function moveUp() { 
    if (snakeX > 0) { 
        snakeX -= 20; 
        snakeBlock.style.top = snakeX + "px"; 
        eat(); 
    } else { 
        myConfirmDisplay(); 
    } 
} 
 
function moveDown() { 
    if (snakeX < maxY) { 
        snakeX += 20; 
        snakeBlock.style.top = snakeX + "px"; 
        eat(); 
    } else { 
        myConfirmDisplay(); 
    } 
} 
 
function moveLeft() { 
    if (snakeY > 0) { 
        snakeY -= 20; 
        snakeBlock.style.left = snakeY + "px"; 
        eat(); 
    } else { 
        myConfirmDisplay(); 
    } 
} 
 
function moveRight() { 
    if (snakeY < maxX) { 
        snakeY += 20; 
        snakeBlock.style.left = snakeY + "px"; 
        eat(); 
    } else { 
        myConfirmDisplay(); 
    } 
} 
 
playBtn.addEventListener('click', startGame); 
 
function startGame() { 
 
    activeGame = true; 
 
    createEat(); 
    resetParams(); 
 
    playBtn.style.display = 'none'; // Скрытие кнопки PLAY 
    snakeBlock.style.display = 'block'; // Отображение змейки 
    scoreBlock.style.display = 'block'; // Отображение очков 
 
    var activeArr; // Переменная для отслеживания направления и запрета двигатся в противоположную сторону, true - если кубик двигается вверх/вниз, false - если влево/вправо 
 
    window.addEventListener('keydown', function (e) { 
        if (e.keyCode == 37 && activeArr !== false) { 
            clearInterval(t); 
            t = setInterval(moveLeft, 50); 
            activeArr = false; 
        } 
        else if (e.keyCode == 38 && activeArr !== true) { 
            clearInterval(t); 
            t = setInterval(moveUp, 50); 
            activeArr = true; 
        } 
        else if (e.keyCode == 39 && activeArr !== false) { 
            clearInterval(t); 
            t = setInterval(moveRight, 50); 
            activeArr = false; 
        } 
        else if (e.keyCode == 40 && activeArr !== true) { 
            clearInterval(t); 
            t = setInterval(moveDown, 50); 
            activeArr = true; 
        } 
    }); 
} 
 
function resetParams() { 
    snakeX = mainBlock.offsetWidth/2 - 10, 
    snakeY = mainBlock.offsetHeight/2 - 10, 
    snakeBlock.style.top = snakeX + 'px'; 
    snakeBlock.style.left = snakeY + 'px'; 
 
    if (t !== undefined){ 
        clearInterval(t); 
    } 
 
    score.innerHTML = 0; 
    scoreValue = Number(score.innerHTML); 
} 
 
function myConfirmDisplay(){ 
    activeGame = false; 
    myConfirm.style.display = 'flex'; 
    snakeBlock.style.display = 'none'; // Скрытие змейки 
    appleBlock.style.display = 'none'; // Скрытие яблока 
    scoreBlock.style.display = 'none'; // Скрытие очков 
    okeyBtn.addEventListener('click', function(){ 
        startGame(); 
        myConfirm.style.display = 'none'; 
    }); 
    exitBtn.addEventListener('click', function(){ 
        playBtn.style.display = 'block'; // Отображение кнопки PLAY 
        snakeBlock.style.display = 'none'; // Скрытие змейки 
        scoreBlock.style.display = 'none'; // Скрытие очков 
        myConfirm.style.display = 'none'; // Скрытие окна выбора 
        resetParams(); 
    }); 
    window.addEventListener('keydown', function (e) { 
        if (e.keyCode == 13 && activeGame == false) { 
            startGame(); 
            myConfirm.style.display = 'none'; 
        } else if (e.keyCode == 27 && activeGame == false) { 
            playBtn.style.display = 'block'; // Отображение кнопки PLAY 
            snakeBlock.style.display = 'none'; // Скрытие змейки 
            scoreBlock.style.display = 'none'; // Скрытие очков 
            myConfirm.style.display = 'none'; // Скрытие окна выбора 
            resetParams(); 
        } 
    }); 
} 
 
function createEat(){ 
    appleBlock.style.display = 'block'; 
 
    appleX = Math.floor(Math.floor(Math.random()*(500 + 1)) / 20) * 20; 
    appleY = Math.floor(Math.floor(Math.random()*(500 + 1)) / 20) * 20; // Координаты яблока(промежуток от 0 до 500(ширина и высота игровой области)) 
 
    appleBlock.style.top = appleX + 'px'; 
    appleBlock.style.left = appleY + 'px'; 
} 
 
function eat() { 
    if(snakeX == appleX && snakeY == appleY){ 
        scoreValue += eatCost; 
        score.innerHTML = scoreValue; 
        appleBlock.style.display = 'none'; 
        createEat(); 
    } 
}
* { 
    overflow: hidden; 
    margin: 0; 
    padding: 0; 
} 
 
#mainBlock { 
    height: 500px; 
    width: 500px; 
    background: #fff; 
    outline: 2px solid #000; 
    box-shadow: 1px 3px 36px 5px rgba(0,0,0,0.3); 
    position: absolute; 
    top: 50%; 
    left: 50%; 
    margin-right: -50%; 
    transform: translate(-50%, -50%); 
} 
 
#playBtn { 
    position: absolute; 
    width: 200px; 
    height: 50px; 
    top: 50%; 
    left: 50%; 
    transform: translate(-50%, -50%); 
    font-family: arial, sans-serif; 
    font-size: 16px; 
    font-weight: bold; 
    color: #333; 
    border: 1px solid #000; 
    border-radius: 3px; 
    background: #f7f7f7; 
    transition: all .3s ease 0s; 
    outline: none; 
} 
#playBtn:hover { 
    border: 1px solid #000; 
    background: #e9e9e9; 
    cursor: pointer; 
} 
 
#snakeBlock { 
    display: none; 
    height: 16px; 
    width: 16px; 
    background-color: #fff; 
    border: 2px solid #000; 
    position: absolute; 
} 
#appleBlock { 
    display: none; 
    height: 20px; 
    width: 20px; 
    background-color: #000; 
    position: absolute; 
} 
 
#myConfirm { 
    position: absolute; 
    display: none; 
    flex-direction: column; 
    justify-content: center; 
    align-items: center; 
    font-family: 'PT Sans', sans-serif; 
    color: #000; 
    top: 0; 
    left: 0; 
    width: 100%; 
    height: 100%; 
    background: rgba(0,0,0,0.5); 
    z-index: 9999; 
} 
.main { 
    position: absolute; 
    height: auto; 
    width: 350px; 
    top: 50%; 
    left: 50%; 
    transform: translate(-50%, -50%); 
    display: flex; 
    align-items: center; 
    justify-content: center; 
    background: #e9e9e9; 
    padding: 50px 0 50px 0; 
    border-radius: 10px; 
    box-shadow: 0 0 30px rgba(0,0,0,0.3); 
     
} 
.main-text { 
    text-align: center; 
} 
.header { 
    font-size: 24px; 
    text-transform: uppercase; 
    margin-bottom: 20px; 
} 
#agree, 
#desagree { 
    width: 100px; 
    height: 40px; 
    margin: 0 5px; 
    font-family: arial, sans-serif; 
    font-size: 16px; 
    font-weight: bold; 
    color: #333; 
    border: 1px solid #000; 
    border-radius: 3px; 
    background: #f7f7f7; 
    transition: all .3s ease 0s; 
    outline: none; 
 
} 
#agree:hover, 
#desagree:hover { 
    border: 1px solid #000; 
    background: #e9e9e9; 
    cursor: pointer; 
} 
 
.scoreBlock { 
    display: none; 
    position: absolute; 
    top: 93%; 
    left: 20%; 
    font-family: arial, sans-serif; 
    font-size: 24px; 
} 
#score { 
    font-weight: bold; 
}
<div id="myConfirm"> 
        <div class="main"> 
            <div class="main-text"> 
                <div class="head-text"> 
                    <h4 class="header">Play again?</h4> 
                </div> 
                <div class="desc-text"> 
                    <input id="agree" type="button" value="PLAY"> 
                    <input id="desagree" type="button" value="EXIT"> 
                </div> 
            </div> 
        </div> 
    </div> 
 
    <div id="mainBlock"> 
        <input id="playBtn" type="button" value="PLAY"> 
        <div id="snakeBlock"></div> 
 
        <div id="appleBlock"></div> 
    </div> 
 
    <div class="scoreBlock"> 
        Score: 
        <span id="score">0</span> 
    </div>

Answer 1

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

READ ALSO
Получение Json с сайта

Получение Json с сайта

Как получить Json не логинясь на сайт? Если есть куки при переходе по ссылке сайт выплевывает JSON https://wwwfastgraphs

101
Таблица с датой на JavaScript

Таблица с датой на JavaScript

Как сделать так, чтобы таблица не рисовалась каждую секунду, а изменлись значения в ней?

132
Перенести данные из одной таблицы в другую

Перенести данные из одной таблицы в другую

Есть две таблицы, в обеих id_product - соответствует номеру товара

142
Появились лишние слайды

Появились лишние слайды

Использую слайдер lightSlider и одновременно magnific-popup(что бы картинка открывалась в модальном окне)И произошла такая проблема, добавил всего два...

137