Selainpohjaisen matopelin tekeminen
Totta kai! Selainpohjaisen matopelin tekeminen voi olla hauskaa ja opettavaista. Tässä on joitain vaiheita, jotka auttavat sinua aloittamaan:
Suunnittele peli: Peliä suunnitellessa määrittele tavoitteet, pelin säännöt, visuaalinen ilme ja pelin toiminta. Tämä auttaa sinua hahmottamaan pelin kokonaisuutena ja sen tarvitsemat ominaisuudet.
Valitse ohjelmointikieli: Valitse ohjelmointikieli, jota haluat käyttää pelin tekemisessä. Esimerkiksi JavaScript on yleisesti käytetty kieli selainpohjaisten pelien kehittämisessä.
Aloita koodaaminen: Kun olet suunnitellut pelin ja valinnut ohjelmointikielen, voit aloittaa koodaamisen. Aloita yksinkertaisista ominaisuuksista, kuten matopään liikkeestä, ja laajenna peliä vähitellen.
Testaa ja korjaa virheet: Testaa peliä säännöllisesti varmistaaksesi, että se toimii oikein. Korjaa löytyneet virheet.
Lisää ominaisuuksia: Kun perusominaisuudet ovat kunnossa, lisää peliin ominaisuuksia, kuten pisteiden seuranta, esteet ja bonusruoat.
Jaa peli: Kun peli on valmis, jaa se muiden kanssa. Voit jakaa sen esimerkiksi verkkosivuilla tai pelialustoilla.
Toivottavasti näistä vinkeistä oli hyötyä matopelin tekemisessä selaimessa!
Tässä on esimerkkikoodi HTML:lle ja JavaScriptille, joka luo 20x30 neliön ruudukon matopeliä varten:
html<!DOCTYPE html>
<html>
<head>
<title>Matopeli</title>
<style>
.cell {
width: 20px;
height: 20px;
border: 1px solid black;
float: left;
}
.clearfix::after {
content: "";
clear: both;
display: table;
}
</style>
</head>
<body>
<div id="game-board"></div>
<script>
const ROWS = 20;
const COLS = 30;
const board = document.getElementById("game-board");
// Luo ruudukko
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const cell = document.createElement("div");
cell.classList.add("cell");
board.appendChild(cell);
}
const clear = document.createElement("div");
clear.classList.add("clearfix");
board.appendChild(clear);
}
</script>
</body>
</html>
Tämä koodi luo div
-elementin nimeltä "game-board", johon se luo 20 riviä ja 30 saraketta div
-elementtejä, joille on annettu "cell" -luokka. CSS määrittää "cell" -luokalle leveyden, korkeuden, reunaviivan ja sijainnin, joka asettaa solut vierekkäin. Lisäksi koodi luo "clearfix" -elementin jokaisen rivin loppuun, joka nollaa solujen virran.
Totta kai! Tässä on esimerkkikoodi JavaScriptille, joka käyttää requestAnimationFrame-metodia pelin pääsilmukan toteuttamiseen:
javascriptconst ROWS = 20;
const COLS = 30;
let gameBoard = [];
let snake = [];
// Luo pelilauta ja käärme
function createGameBoard() {
for (let row = 0; row < ROWS; row++) {
let currentRow = [];
for (let col = 0; col < COLS; col++) {
currentRow.push(0);
}
gameBoard.push(currentRow);
}
// Alusta käärme
snake = [{ row: 10, col: 10 }];
}
// Pääsilmukka
function gameLoop() {
// Tyhjennä pelilauta
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
gameBoard[row][col] = 0;
}
}
// Päivitä käärme
let head = snake[0];
head.row++;
snake.unshift(head);
snake.pop();
// Piirrä käärme
snake.forEach((segment) => {
gameBoard[segment.row][segment.col] = 1;
});
// Piirrä pelilauta
let board = document.getElementById("game-board");
board.innerHTML = "";
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
let cell = document.createElement("div");
cell.classList.add("cell");
if (gameBoard[row][col] === 1) {
cell.classList.add("snake");
}
board.appendChild(cell);
}
let clear = document.createElement("div");
clear.classList.add("clearfix");
board.appendChild(clear);
}
// Jatka pelisilmukkaa
requestAnimationFrame(gameLoop);
}
// Aloita peli
createGameBoard();
requestAnimationFrame(gameLoop);
Tämä koodi luo gameBoard
-taulukon, joka edustaa pelilautaa, ja snake
-taulukon, joka edustaa käärmettä. createGameBoard()
-funktio luo alkutilanteen pelilaudalle ja käärmeelle. gameLoop()
-funktio päivittää pelilaudan ja käärmeen tilan, piirtää ne näytölle ja kutsuu itsensä uudelleen requestAnimationFrame
-metodin avulla.
Huomaa, että tämä koodi on vain esimerkki eikä sisällä pelin toiminnallisuutta. Pelin logiikan ja ohjauksen lisääminen on sinun vastuullasi!
Tässä on esimerkkikoodi, joka seuraa nuolinäppäimien painalluksia ja tallentaa niiden tilan globaaleihin muuttujiin key_left
, key_right
, key_up
ja key_down
:
javascriptlet key_left = false;
let key_right = false;
let key_up = false;
let key_down = false;
// Kuuntele näppäinten painalluksia
document.addEventListener("keydown", (event) => {
switch (event.keyCode) {
case 37: // nuoli vasemmalle
key_left = true;
break;
case 38: // nuoli ylös
key_up = true;
break;
case 39: // nuoli oikealle
key_right = true;
break;
case 40: // nuoli alas
key_down = true;
break;
}
});
// Kuuntele näppäinten vapautuksia
document.addEventListener("keyup", (event) => {
switch (event.keyCode) {
case 37: // nuoli vasemmalle
key_left = false;
break;
case 38: // nuoli ylös
key_up = false;
break;
case 39: // nuoli oikealle
key_right = false;
break;
case 40: // nuoli alas
key_down = false;
break;
}
});
Tämä koodi lisää keydown
- ja keyup
-tapahtumakuuntelijat dokumenttiin. Kun käyttäjä painaa nuolinäppäintä, kyseisen muuttujan tila muuttuu true
:ksi, ja kun käyttäjä vapauttaa näppäimen, tila muuttuu takaisin false
:ksi. Voit käyttää näitä muuttujia myöhemmin pelin ohjauksessa.
Tässä on esimerkkikoodi, joka liikuttaa matopelin madon päätä oikeaan suuntaan näppäimistön painalluksen mukaan, ja tarkistaa törmäykset pelialueen reunaan tai matoon itseensä. Koodi käyttää setInterval
-funktiota pelin silmukan ajastamiseen:
javascriptconst ROWS = 20;
const COLS = 30;
let snake = [{row: 10, col: 10}];
let key_left = false;
let key_right = false;
let key_up = false;
let key_down = false;
// Liikuta matoa ja piirrä ruudukko uudestaan
function update() {
// Päivitä matopään sijainti näppäinpainalluksen mukaan
if (key_left) {
snake.unshift({row: snake[0].row, col: snake[0].col - 1});
} else if (key_right) {
snake.unshift({row: snake[0].row, col: snake[0].col + 1});
} else if (key_up) {
snake.unshift({row: snake[0].row - 1, col: snake[0].col});
} else if (key_down) {
snake.unshift({row: snake[0].row + 1, col: snake[0].col});
}
// Tarkista törmäykset pelialueen reunaan tai matoon itseensä
if (snake[0].row < 0 || snake[0].row >= ROWS ||
snake[0].col < 0 || snake[0].col >= COLS ||
snake.slice(1).some(part => part.row === snake[0].row && part.col === snake[0].col)) {
// Peli päättyy, jos mato törmää
clearInterval(gameInterval);
alert("Game over!");
return;
}
// Poista hännän osa
snake.pop();
// Piirrä ruudukko uudestaan
drawGrid();
}
// Piirrä ruudukko
function drawGrid() {
// Piirrä pelialueen reunat
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (i === 0 || i === ROWS - 1 || j === 0 || j === COLS - 1) {
// Reuna
drawCell(i, j, "#555");
} else {
// Tyhjä solu
drawCell(i, j, "#eee");
}
}
}
// Piirrä madon osat
snake.forEach(part => {
drawCell(part.row, part.col, "#333");
});
}
// Piirrä yksittäinen solu
function drawCell(row, col, color) {
const cellSize = 20;
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = color;
ctx.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);
}
// Kuuntele näppäinten painalluksia
document.addEventListener("keydown", (event) => {
switch (event.keyCode) {
case
Tämä voidaan toteuttaa esimerkiksi tallentamalla viimeisin kutsuaika muuttujaan ja tarkistamalla, onko kulunut aika vähintään 0.3 sekuntia ennen funktion suoritusta. Tässä on päivitetty koodi, joka sisältää viiveen tarkistuksen:
javascriptconst ROWS = 20;
const COLS = 30;
let snake = [{row: 10, col: 10}];
let key_left = false;
let key_right = false;
let key_up = false;
let key_down = false;
let lastUpdateTime = 0;
// Liikuta matoa ja piirrä ruudukko uudestaan
function update() {
// Tarkista viive
const now = performance.now();
if (now - lastUpdateTime < 300) {
return;
}
lastUpdateTime = now;
// Päivitä matopään sijainti näppäinpainalluksen mukaan
if (key_left) {
snake.unshift({row: snake[0].row, col: snake[0].col - 1});
} else if (key_right) {
snake.unshift({row: snake[0].row, col: snake[0].col + 1});
} else if (key_up) {
snake.unshift({row: snake[0].row - 1, col: snake[0].col});
} else if (key_down) {
snake.unshift({row: snake[0].row + 1, col: snake[0].col});
}
// Tarkista törmäykset pelialueen reunaan tai matoon itseensä
if (snake[0].row < 0 || snake[0].row >= ROWS ||
snake[0].col < 0 || snake[0].col >= COLS ||
snake.slice(1).some(part => part.row === snake[0].row && part.col === snake[0].col)) {
// Peli päättyy, jos mato törmää
clearInterval(gameInterval);
alert("Game over!");
return;
}
// Poista hännän osa
snake.pop();
// Piirrä ruudukko uudestaan
drawGrid();
}
// Aseta pelisilmukka ajastimeen
const gameInterval = setInterval(update, 100);
// Piirrä ruudukko
function drawGrid() {
// Piirrä pelialueen reunat
for (let i = 0; i < ROWS; i++) {
for (let j = 0; j < COLS; j++) {
if (i === 0 || i === ROWS - 1 || j === 0 || j === COLS - 1) {
// Reuna
drawCell(i, j, "#555");
} else {
// Tyhjä solu
drawCell(i, j, "#eee");
}
}
}
// Piirrä madon osat
snake.forEach(part => {
drawCell(part.row, part.col, "#333");
});
}
// Piirrä yksittäinen solu
function drawCell(row, col, color) {
const cellSize = 20;
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
Toki! Tässä on yksi tapa toteuttaa tämä:
javascriptlet lastKeyPressed = null;
document.addEventListener("keydown", function(event) {
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
lastKeyPressed = event.key;
}
});
Tämä koodi luo muuttujan lastKeyPressed
, joka alustetaan null
:ksi. Sitten se lisää kuuntelijan keydown
-tapahtumalle, joka tarkistaa, onko painettu nuolinäppäin. Jos on, se tallentaa sen lastKeyPressed
-muuttujaan. Jos mitään nuolinäppäintä ei ole painettu, lastKeyPressed
säilyy ennallaan. Huomaa, että tämä tallentaa vain yhden nuolinäppäimen, joka on viimeksi painettu - jos käyttäjä painaa useampaa nuolinäppäintä samaan aikaan, vain viimeinen niistä tallentuu.
Tässä on yksi tapa toteuttaa matoa liikuttava koodi update
-funktion sisällä:
javascriptfunction update() {
// ...
// Liikutetaan madon päätä sen suuntaan
switch (lastKeyPressed) {
case "ArrowLeft":
snake.unshift({row: snake[0].row, col: snake[0].col - 1});
break;
case "ArrowRight":
snake.unshift({row: snake[0].row, col: snake[0].col + 1});
break;
case "ArrowUp":
snake.unshift({row: snake[0].row - 1, col: snake[0].col});
break;
case "ArrowDown":
snake.unshift({row: snake[0].row + 1, col: snake[0].col});
break;
default:
// Ei tehdä mitään, jos ei ole painettu nuolinäppäintä
break;
}
// Poistetaan hännän pala, jos mato ei ole kasvanut
if (grow === 0) {
snake.pop();
} else {
grow--;
}
// ...
}
Tässä koodi käyttää switch
-rakennetta, joka tarkistaa, mikä nuolinäppäin on tallennettu lastKeyPressed
-muuttujaan. Sitten se liikuttaa madon päätä sen suuntaan ja lisää uuden palan ensimmäiseksi taulukkoon snake.unshift()
. Jos mitään näppäintä ei ole painettu, mato liikkuu suoraan eteenpäin. Lopuksi koodi poistaa hännän palan, jos mato ei ole kasvanut, tai vähentää grow
-muuttujaa yhdellä, jos mato on kasvanut.
Totta kai! Voit käyttää tähän JavaScriptin classList
-ominaisuutta yhdessä querySelectorAll
-funktion kanssa. Tässä on yksi tapa toteuttaa se:
javascript// Värjätään madon palat mustiksi
let snakeCells = document.querySelectorAll('.snake');
snakeCells.forEach(cell => {
cell.style.backgroundColor = 'black';
});
Tämä koodi hakee kaikki sivulla olevat elementit, joilla on snake
-luokka, käyttäen querySelectorAll
-funktiota. Sitten se käy läpi jokaisen elementin forEach
-silmukassa ja asettaa sen taustaväriksi mustan käyttämällä style.backgroundColor
-ominaisuutta. Huomaa, että tämä koodi toimii olettaen, että snake
-luokan soluilla on oikea taustaväri. Jos taustaväri on muu kuin valkoinen, sinun on ehkä käytettävä style.color
-ominaisuutta sen sijaan.
Toki! Voit käyttää CSS-koodia .snake
-luokan solujen taustavärin asettamiseen mustaksi. Tässä on yksi tapa tehdä se:
css.snake {
background-color: black;
}
Tämä CSS-koodi asettaa kaikki elementit, joilla on snake
-luokka taustavärin mustaksi. Huomaa, että tämä koodi ei muuta elementtien taustaväriä, jos ne eivät ole luokkaa snake
. Jos haluat muuttaa kaikkien sivulla olevien elementtien taustaväriä mustaksi, voit käyttää seuraavaa koodia sen sijaan:
css* {
background-color: black;
}
Tämä CSS-koodi asettaa kaikkien sivulla olevien elementtien taustavärin mustaksi. Huomaa, että tämä koodi vaikuttaa kaikkiin elementteihin, mukaan lukien <html>
- ja <body>
-elementit.
Tottakai! Voit tarkistaa, onko madon päässä snake[0]
ruokaa seuraavasti:
javascriptif (snake[0].row === food.row && snake[0].col === food.col) {
// Madon päässä on ruokaa, tee jotain täällä
}
Tämä tarkistaa, ovatko madon pään (snake[0]
) row
- ja col
-ominaisuudet samat kuin ruoan row
- ja col
-ominaisuudet.
Jos haluat arpoa uuden paikan ruoalle, voit käyttää seuraavaa koodia:
javascript// Arvo uusi paikka ruoalle
food.row = Math.floor(Math.random() * ROWS);
food.col = Math.floor(Math.random() * COLS);
Tämä arpo uuden paikan ruoalle pelilaudalla. ROWS
ja COLS
ovat pelilaudan rivien ja sarakkeiden määrä. Huomaa, että tämä koodi voi arpoa ruoan sijainnin sellaiselle solulle, jossa mato jo on. Jos haluat varmistaa, että ruoka ei ilmesty matoon päälle, voit käyttää seuraavaa koodia sen sijaan:
javascript// Arvo uusi paikka ruoalle
do {
food.row = Math.floor(Math.random() * ROWS);
food.col = Math.floor(Math.random() * COLS);
} while (isInSnake(food.row, food.col));
Tämä arpo uuden sijainnin, kunnes se ei ole mato-solujen sisällä. isInSnake
-funktio on edellisessä vastauksessa esitelty funktio, joka tarkistaa, onko annettu sijainti mato-solujen sisällä.
Tottakai! isInSnake
-funktio tarkistaa, onko annettu sijainti (row
ja col
) mato-solujen sisällä. Voit toteuttaa sen esimerkiksi seuraavasti:
javascriptfunction isInSnake(row, col) {
for (let i = 0; i < snake.length; i++) {
if (snake[i].row === row && snake[i].col === col) {
return true;
}
}
return false;
}
Tämä funktio käy läpi kaikki mato-solut taulukossa snake
ja tarkistaa, ovatko niiden row
- ja col
-ominaisuudet samat kuin annetut row
ja col
. Jos löytyy solu, jonka row
ja col
ovat samat, funktio palauttaa true
. Muussa tapauksessa se palauttaa false
.
Tottakai, tässä on esimerkkikoodi uuden ruoan arpomisfunktiolle:
javascriptfunction generateFood() {
let foodRow, foodCol;
do {
foodRow = Math.floor(Math.random() * ROWS);
foodCol = Math.floor(Math.random() * COLS);
} while (isInSnake(foodRow, foodCol));
food = { row: foodRow, col: foodCol };
drawFood();
}
Tämä funktio arpoo satunnaisen sijainnin foodRow
ja foodCol
muuttujiin, kunnes se löytää sijainnin, joka ei ole mato-solujen sisällä. Tämän jälkeen se luo uuden food
-olion, joka tallennetaan globaaliin muuttujaan food
, ja piirtää ruoan käyttäen drawFood
-funktiota. Funktio voidaan kutsua esimerkiksi pelin käynnistyessä tai aina kun mato syö ruoan.
Toki, voit tehdä sen seuraavasti:
javascriptfunction drawFood() {
const foodIndex = getIndex(food.row, food.col);
squares[foodIndex].classList.add('food');
// Merkitään ruoan sijainti gameBoard-taulukkoon numerolla 2
gameBoard[food.row][food.col] = 2;
}
function removeFood() {
const foodIndex = getIndex(food.row, food.col);
squares[foodIndex].classList.remove('food');
// Poistetaan ruoan sijainnin merkintä gameBoard-taulukosta
gameBoard[food.row][food.col] = 0;
}
function generateFood() {
let foodRow, foodCol;
do {
foodRow = Math.floor(Math.random() * ROWS);
foodCol = Math.floor(Math.random() * COLS);
} while (isInSnake(foodRow, foodCol));
food = { row: foodRow, col: foodCol };
// Poistetaan vanhan ruoan merkintä ja piirretään uusi ruoka
removeFood();
drawFood();
}
Kun ruoka piirretään drawFood
-funktiolla, se merkitsee myös ruoan sijainnin gameBoard
-taulukkoon numerolla 2. Kun ruoka poistetaan removeFood
-funktiolla, se myös poistaa ruoan sijainnin merkinnän gameBoard
-taulukosta. Funktio generateFood
käyttää removeFood
- ja drawFood
-funktioita vanhan ruoan poistamiseen ja uuden ruoan piirtämiseen.
Tässä olisi yksi mahdollinen toteutus gameOver-funktiosta:
javascriptfunction gameOver() {
isGameRunning = false;
clearInterval(gameLoop);
alert(`Game over! Snake length: ${snake.length}`);
}
Tämä funktio asettaa isGameRunning
-muuttujan arvon false
:ksi, mikä pysäyttää pelin. Se myös pysäyttää gameLoop-timerin clearInterval
-funktiolla. Lopuksi se näyttää ilmoituksen, jossa kerrotaan pelin päättymisestä ja maton pituudesta.
Voit kutsua tätä funktiota esimerkiksi update
-funktion sisällä, jos mato törmää johonkin tai peli muuten päättyy:
javascriptfunction update() {
// ...
if (isCollidingWithWall() || isCollidingWithSnake()) {
gameOver();
return;
}
// ...
}
Tämä koodi tarkistaa, onko mato törmännyt seinään tai omaan häntäänsä, ja jos näin on, se kutsuu gameOver
-funktiota ja lopettaa update
-funktion suorituksen.
Toki, tässä on HTML-koodi napin lisäämiseksi:
html<button onclick="startGame()">Aloita peli</button>
Tämä luo sivulle napin, jonka klikkaaminen käynnistää pelin kutsumalla startGame-funktiota. Voit sijoittaa tämän napin esimerkiksi body-elementin sisään haluamaasi kohtaan.
Tottakai, tässä on päivitetty gameOver-funktio, joka näyttää pelin päättymisestä ilmoituksen ja tiedon madon pituudesta:
javascriptfunction gameOver() {
playing = false;
clearInterval(gameLoop);
const score = snake.length - initialLength;
const message = document.createElement("div");
message.innerHTML = `Peli päättyi! Madon pituus oli ${score}.`;
message.classList.add("game-over");
gameBoard.appendChild(message);
}
Tämä funktio luo HTML-div-elementin, joka sisältää pelin päättymisestä ilmoituksen ja tiedon madon pituudesta suomeksi. Div-elementille annetaan myös CSS-luokka "game-over", jonka avulla voit halutessasi muotoilla ilmoitusta sivullasi.
Voit sijoittaa tämän HTML-elementin esimerkiksi pelialueen alapuolelle, lisäämällä sen vaikkapa seuraavasti:
html<div id="game-board"></div>
<div id="game-info"></div>
Tämä luo kaksi div-elementtiä sivulle, joista ensimmäinen (id:llä game-board) sisältää pelialueen ja toinen (id:llä game-info) on tarkoitettu pelin tiedoille. Voit sijoittaa gameOver-funktion luoman ilmoituksen game-info-diviin esimerkiksi seuraavasti:
javascriptconst gameInfo = document.getElementById("game-info");
gameInfo.appendChild(message);
Tällöin gameOver-funktion luoma ilmoitus sijoitetaan game-info-diviin.
Tässä on yksi mahdollinen tapa muokata HTML-sivua:
php<!DOCTYPE html>
<html>
<head>
<title>Matopeli</title>
<style>
body {
background-color: #F9F7F7;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 {
font-size: 3em;
text-align: center;
margin-top: 1em;
margin-bottom: 0.5em;
}
p {
font-size: 1.2em;
margin: 0.5em 1em;
}
button {
display: block;
margin: 2em auto;
font-size: 1.5em;
padding: 0.5em 1em;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#game-board {
margin: 0 auto;
border: 5px solid #4CAF50;
width: 600px;
height: 400px;
position: relative;
}
#game-info {
font-size: 1.2em;
text-align: center;
margin-top: 1em;
margin-bottom: 2em;
}
.snake {
background-color: black;
}
.apple {
background-color: #4CAF50;
border-radius: 50%;
width: 20px;
height: 20px;
position: absolute;
}
</style>
</head>
<body>
<h1>Matopeli</h1>
<p>Matoa ohjataan nuolinäppäimillä. Kerää vihreitä omenoita, mutta älä törmää seiniin tai omaan häntään!</p>
<button onclick="startGame()">Aloita peli</button>
<div id="game-board"></div>
<div id="game-info"></div>
<script src="snake.js"></script>
</body>
</html>
CSS-tyyleissä on käytetty vihreää väriä (hex-koodi #4CAF50) pelin teeman väripaletin pääväriksi. Pelilaudan leveys on asetettu 600 pikseliin ja korkeus 400 pikseliin. Omenan koko on asetettu 20 pikseliin ja se on pyöristetty ympyrän muotoiseksi (border-radius). Koko sivun taustaväri on vaaleanharmaa (hex-koodi #F9F7F7).
HTML-sivulla on otsikkona "Matopeli" ja peliohjeina kerrotaan, että matoa ohjataan nuolinäppäimillä, ja tavoitteena on kerätä vihreitä omenoita. Peliohjeissa on myös mainittu, että seiniin tai omaan häntään ei saa törmätä. Pelin aloituspainike on erottuva ja näyttävä, ja se on keskitetty sivulle. Pelilaudan yläpuolella on tila- ja ohjetekstit, ja alla on pelin suoritus.
Voit käyttää flexboxia seuraavasti keskittääksesi <div>
-elementin sisällön horisontaalisesti ja vertikaalisesti:
html<div id="container">
<div id="game-board"></div>
</div>
css#container {
display: flex;
justify-content: center; /* Keskittää horisontaalisesti */
align-items: center; /* Keskittää vertikaalisesti */
height: 100vh; /* Vie koko näytön korkeuden */
}
#game-board {
/* Tässä voit määrittää leveyden ja korkeuden */
}
Tämä koodi keskittää <div id="game-board">
-elementin sivun keskelle horisontaalisesti ja vertikaalisesti. #container
-elementti vie koko näytön korkeuden (height: 100vh;
). Voit määrittää <div id="game-board">
-elementin leveyden ja korkeuden tarpeidesi mukaan.
Voit tyhjentää gameInfo-elementin sisällön käyttämällä innerHTML-attribuuttia ja asettamalla sen arvoksi tyhjän merkkijonon:
arduinogameInfo.innerHTML = "";
Tämä poistaa kaiken sisällön elementistä.
Voit käsitellä näppäimiä WASD seuraavasti:
vbnetif (event.key === "ArrowLeft" || event.key === "a" || event.key === "A") {
lastKeyPressed = "ArrowLeft";
} else if (event.key === "ArrowRight" || event.key === "d" || event.key === "D") {
lastKeyPressed = "ArrowRight";
} else if (event.key === "ArrowUp" || event.key === "w" || event.key === "W") {
lastKeyPressed = "ArrowUp";
} else if (event.key === "ArrowDown" || event.key === "s" || event.key === "S") {
lastKeyPressed = "ArrowDown";
}
Tämä käsittelee WASD-näppäimet samoin kuin vastaavat nuolinäppäimet ja tallentaa viimeisimmän painetun näppäimen lastKeyPressed
-muuttujaan nuolinäppäimen muodossa.
Hyvä kysymys! ChatGPT on tekoälypohjainen järjestelmä, joka ei ole yksittäinen henkilö, joten sen viittaaminen tekijänä ei ole oikein sopivaa. Voit kuitenkin mainita, että koodit on saatu apuna ChatGPT-nimiseltä tekoälyltä, joka on suorittanut pyydetyn tehtävän. Voit esimerkiksi lisätä kommentin koodin yläreunaan tai loppuun, jossa mainitset ChatGPT:n avusta, kuten seuraavasti:
// Koodi on toteutettu avulla ChatGPT-tekoälyltä // https://openai.com/ // Tekijä: [oma nimi tai käyttäjätunnus]
Tässä on yksi esimerkki, joka voisi toimia:
php<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Matopeli</title>
</head>
<body>
<h1>Matopeli</h1>
<p>Peli, jossa ohjataan matoa nuolinäppäimillä.</p>
<button onclick="startGame()">Aloita peli</button>
<div id="game-board"></div>
<div id="game-info"></div>
<footer>
<p>Tämän sivun koodi on luotu ChatGPT:n avulla.</p>
</footer>
<script src="main.js"></script>
</body>
</html>
Tämä sisältää perus-HTML-rakenteen, nappulan pelin aloittamiseen, pelialueen ja pelitiedot, sekä viittauksen koodin tekijään lopussa footer-elementissä.
Voit lisätä seuraavan koodin sivun head-osaan:
html<meta name="viewport" content="width=device-width, initial-scale=1">
Tämä kertoo selaimelle, että sivun leveys tulee olla sama kuin laitteen leveys ja sivua tulee skaalata sopivasti, jotta se näytetään kunnolla eri kokoisilla laitteilla. Tämä auttaa välttämään vierityspalkkeja mobiililaitteilla.
Tässä on yksinkertainen esimerkki taulukosta, joka sisältää nuolinäppäin-painikkeet. Kun painikkeita klikataan, ne kutsuvat JavaScript-funktiota, joka käsittelee painikkeen painamisen.
html<table>
<tr>
<td></td>
<td><button onclick="pressArrow(event, 'ArrowUp')">↑</button></td>
<td></td>
</tr>
<tr>
<td><button onclick="pressArrow(event, 'ArrowLeft')">←</button></td>
<td></td>
<td><button onclick="pressArrow(event, 'ArrowRight')">→</button></td>
</tr>
<tr>
<td></td>
<td><button onclick="pressArrow(event, 'ArrowDown')">↓</button></td>
<td></td>
</tr>
</table>
Ja tässä on esimerkkikoodi, joka käsittelee painikkeiden painamisen. Tässä esimerkissä funktio asettaa muuttujan lastKeyPressed
painettuun nuolinäppäimeen, mutta voit mukauttaa sitä vastaamaan omaa käyttötapaustasi.
javascriptfunction pressArrow(event, key) {
event.preventDefault();
lastKeyPressed = key;
}
Huomaa, että käytämme event.preventDefault()
estämään sivun vierityksen, kun painikkeita klikataan.
Voit piirtää pelilaudan canvas-elementille käyttäen JavaScriptin Canvas API:a. Voit tehdä seuraavasti:
- Luo uusi canvas-elementti HTML-sivulle, esimerkiksi näin:
html<canvas id="canvas" width="600" height="400"></canvas>
- Hae canvas-elementti JavaScriptissä ja tallenna se muuttujaan:
javascriptconst canvas = document.getElementById("canvas");
- Hae canvas-konteksti ja tallenna se muuttujaan:
javascriptconst ctx = canvas.getContext("2d");
- Käy läpi gameBoard-taulukko ja piirrä jokainen peliruutu canvasille käyttäen fillRect-metodia. Esimerkiksi tyhjä peliruutu (jossa on luku 0) voisi olla musta, mato (jossa on luku 1) voisi olla vihreä ja omena (jossa on luku 2) voisi olla punainen. Voit käyttää switch-lausetta valitaksesi oikean värin.
Tässä on koodiesimerkki, joka piirtää pelilaudan canvasille:
javascriptconst canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const BLOCK_SIZE = 20;
const COLORS = {
0: "black",
1: "green",
2: "red"
};
function drawGameBoard() {
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLS; col++) {
const x = col * BLOCK_SIZE;
const y = row * BLOCK_SIZE;
const color = COLORS[gameBoard[row][col]];
ctx.fillStyle = color;
ctx.fillRect(x, y, BLOCK_SIZE, BLOCK_SIZE);
}
}
}
Tämän jälkeen voit kutsua drawGameBoard()
-funktiota joka framella, jolloin pelilauta piirtyy canvasille joka kerta kun se päivittyy.
Kyllä, flexboxista voi olla apua canvas-elementin keskittämisessä ja kapenemisen rajoittamisessa. Tässä on esimerkki CSS-koodista, jolla canvas-elementti pysyy keskellä ruutua ja kapenee enintään selainikkunan levyiseksi:
csscanvas {
margin: auto;
max-width: 100%;
height: auto;
display: block;
}
Ensimmäinen sääntö margin: auto
keskittää canvas-elementin horisontaalisesti ruudun keskelle. Toinen sääntö max-width: 100%
rajoittaa canvas-elementin maksimileveyden selainikkunan leveyteen. Kolmas sääntö height: auto
varmistaa, että canvas-elementti säilyttää oikean suhteen leveyteen nähden. Viimeinen sääntö display: block
varmistaa, että canvas-elementti on block-elementti, joka täyttää rivin leveyden.
Jos haluat säilyttää elementin kokonaisleveyden (border, padding ja sisältö) samana, vaikka lisäisit siihen reunuksen (border), kannattaa käyttää CSS-ominaisuutta box-sizing: border-box;
. Tämä varmistaa, että reunuksen leveys lasketaan mukaan elementin kokonaisleveyteen, jolloin sen sisältö ei veny liikaa reunuksen lisäyksen seurauksena.
Tässä on esimerkkikoodi gameOver-funktiosta, joka piirtää canvas-elementille viestin pelin päättymisestä:
javascriptfunction gameOver() {
// Asetetaan gameOver-muuttujan arvoksi true, jotta peli pysähtyy
gameOver = true;
// Piirretään canvas-elementille punainen pohja
ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Asetetaan fontti ja tekstiväri
ctx.font = "40px Arial";
ctx.fillStyle = "white";
// Lasketaan madon pituus ja asetetaan viesti sen mukaan
const snakeLength = snake.length - 1;
const message = `Peli päättyi! Madon pituus oli ${snakeLength}.`;
// Asetetaan viesti keskelle canvas-elementtiä
const textWidth = ctx.measureText(message).width;
const x = (canvas.width - textWidth) / 2;
const y = canvas.height / 2;
ctx.fillText(message, x, y);
}
Tässä funktiossa asetetaan canvas-elementin taustaväriksi punainen ja piirretään siihen valkoinen teksti, joka kertoo pelin päättymisestä ja madon pituudesta. Viesti keskitetään canvas-elementtiin measureText
-funktion avulla.
Voit lisätä seuraavan koodin startGame-funktioon, joka varmistaa että sivu vierii niin, että table#arrow-keys
on näkyvissä:
javascriptwindow.scrollTo(0,document.body.scrollHeight);
Tämä koodi siirtää näkymän alareunaan, jolloin table#arrow-keys
tulee näkyviin, jos se on näkyvissä.
Voit käyttää rgba
-arvoa määrittämään väri, joka sisältää myös alpha-kanavan. Alpha-kanava määrittää läpinäkyvyyden tason, joka vaihtelee välillä 0 (täysin läpinäkymätön) ja 1 (täysin läpinäkyvä).
Esimerkiksi, jos haluat tehdä täytön puoliksi läpinäkyväksi, voit käyttää seuraavaa fillStyle-arvoa:
javascriptcontext.fillStyle = "rgba(255, 0, 0, 0.5)";
Tämä luo punaisen värin, joka on puoliksi läpinäkyvä (alpha-kanavan arvo on 0.5).
Voit tehdä tämän piirtämällä madon jokaisen osan ympärille hieman isomman suorakulmion, jolloin reunus syntyy tähän ylimääräiseen tilaan. Voit esimerkiksi lisätä jokaiseen madon osaan 2 pikseliä sekä leveyttä että korkeutta, ja piirtää suorakulmion ensin tummalla reunusvärillä, jonka jälkeen täyttää itse suorakulmion madon värillä. Tässä esimerkki koodista, joka lisää 2 pikseliä jokaisen madon osan mittoihin ja piirtää madon ympärille tumman reunuksen:
bashctx.lineWidth = 1;
ctx.strokeStyle = "black";
for (let i = 0; i < snake.length; i++) {
let x = snake[i].x * CELL_SIZE;
let y = snake[i].y * CELL_SIZE;
ctx.strokeRect(x - 1, y - 1, CELL_SIZE + 2, CELL_SIZE + 2);
ctx.fillStyle = "green";
ctx.fillRect(x, y, CELL_SIZE, CELL_SIZE);
}
Tässä koodissa lineWidth määrittää reunuksen paksuuden ja strokeStyle sen värin. strokeRect-metodi piirtää ensin suorakulmion reunuksineen, jonka jälkeen fillRect täyttää suorakulmion itse madon värillä. Huomaa, että ensin piirretään reunus ja vasta sitten täytetään suorakulmio, jotta reunus ei peitä itse matoa.