Witam,
Od wakacji borykam się z napisaniem w miarę dobrego kodu chodzenia po mapie 2d, ale to do mi wychodzi nie jest tym czego oczekuję, a już na prawdę nie umiem wymyślić jakby to zrobić lepiej. Mam dwie wersje tegoż kodu w canvasie i w samym JS z jQuery.
Demo na canvasie: http://www.trzebu.glupoty.com/canvas/
Kod:
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8">
</head>
<center>
<canvas width="1100" height="700" id="can">
kjhkjhkjlh
</canvas>
</center>
<div id="kordy"></div>
<div id="kordyy"></div>
<script>
var c = document.getElementById('can').getContext('2d'); //element HMTL
var heroHeight = 48;
var heroWidth = 32;
var frameNr = 1;
var heroFramesCount = 4;
var dir = '';
var kier = 0;
var x = 0;
var y = 0;
var xx = 0;
var yy = 0;
var mx = 0;
var move = true;
window.addEventListener('keydown', function(event) {
switch (event.keyCode) {
//aswd
case 65 : dir='W'; break; //lewo
case 87 : dir='N'; break; //góra
case 68 : dir='E'; break; //prawo
case 83 : dir='S'; break; //dół
//up, down, right, left
case 37 : dir='W'; break; //lewo
case 38 : dir='N'; break; //góra
case 39 : dir='E'; break; //prawo
case 40 : dir='S'; break; //dół
}
}, false);
window.addEventListener('keyup', function(event) {
switch (event.keyCode) {
//aswd
case 65 : break; //lewo
case 87 : break; //góra
case 68 : break; //prawo
case 83 : break; //dół
//up, down, right, left
case 37 : break; //lewo
case 38 : break; //góra
case 39 : break; //prawo
case 40 : break; //dół
}
dir = '';
}, false);
function interval(){
if(dir == "E"){x++; animation(8,0); kier = 2;}
if(dir == "W"){x--; animation(-8,0); kier = 1;}
if(dir == "N"){y--; animation(0,-8); kier = 3;}
if(dir == "S"){y++; animation(0,8); kier = 0;}
}
function animation(insertX, insertY){
if(move){
move=false;
setTimeout("draw(xx+="+insertX+", yy += "+insertY+");",50);
setTimeout("draw(xx+="+insertX+", yy += "+insertY+");",100);
setTimeout("draw(xx+="+insertX+", yy += "+insertY+");",150);
setTimeout("draw(xx+="+insertX+", yy += "+insertY+");",200);
setTimeout("move = true;",199);
}
}
var bg = new Image(3072,2048); //mapa
var hero = new Image(128,192); //postać
function draw(xx,yy){
c.clearRect(0, 0, 1100, 700);
frameNr++;
if (frameNr > heroFramesCount) {
frameNr = 1;
}
var frameXpos = (frameNr-1)*heroWidth;
var frameYpos = kier*heroHeight;
//rysujemy wczytaną grafikę z tłem
c.drawImage(bg,0,0); //rysowanie tła
c.drawImage(hero, frameXpos, frameYpos, heroWidth, heroHeight, xx, yy, heroWidth, heroHeight); //rysowanie postaci
document.getElementById("kordy").innerHTML = "X: " +xx + " Y:" + yy;
document.getElementById("kordyy").innerHTML = "X: " +x + " Y:" + y;
}
bg.src = 'mapa.png';
hero.src = 'postac.gif';
hero.onload = function (){
c.drawImage(bg,0,0); //rysowanie tła
c.drawImage(hero, 0, 0, heroWidth, heroHeight, xx, yy, heroWidth, heroHeight); //rysowanie postaci
};
setInterval(interval, 100);
</script>
</html>
Jak widać w wersji demo nie wygląda to zbyt ładnie i się zacina
JS i jQuery: http://www.trzebu.glupoty.com/interval/
Kod:
this.dir = '';
var x = 0;
var y = 0;
var xx = 0;
var yy = 0;
var hx = 0;
var hy = 0;
var mX = 0;
var mY = 0;
var mx = 0;
var my = 0;
var kier = 0;
//KLIKNIĘCIE
//Dodajemy do zmiennej dir kierunek który kliknięto
window.addEventListener('keydown', function(event)
{
switch (event.keyCode)
{
//aswd
case 65 : dir='W'; break; //lewo
case 87 : dir='N'; break; //góra
case 68 : dir='E'; break; //prawo
case 83 : dir='S'; break; //dół
//up, down, right, left
case 37 : dir='W'; break; //lewo
case 38 : dir='N'; break; //góra
case 39 : dir='E'; break; //prawo
case 40 : dir='S'; break; //dół
}
//setInterval(game, 1000);
}, false);
//PUSZCZENIE
//Kasujemy zawartość zmiennej dir
window.addEventListener('keyup', function(event)
{
switch (event.keyCode)
{
//aswd
case 65 : break; //lewo
case 87 : break; //góra
case 68 : break; //prawo
case 83 : break; //dół
//up, down, right, left
case 37 : break; //lewo
case 38 : break; //góra
case 39 : break; //prawo
case 40 : break; //dół
}
dir = '';
}, false);
//Jeśli w dir pojawi się któryś z kierunków funkcja game:
//-Dodaje lub ujmuje ze zmiennej x, y 1;
//-Włącza funkcję heroAnim która animuje ruch postaci i daje jej parametr hn=8 lub hn=-8
//-Sprawdza czy y lub x zostało przekroczone i odpala mapAnim które animuje mapę
//-Odpala funkcję outAnim która ma parametr kier = 0, 1, 2 lub 3 (są to kierunki postaci)
function game(){
switch(dir)
{
case 'S' : y++;heroAnim(hy=8);if((y>8) && (y<54)){mapAnim(my=8);} outAnim(kier = 0); break;
case 'W' : if(x<18 || x>78){x--;heroAnim(hx=-8);}else{x--;heroAnim(hx=-8);mapAnim(mx=-8);}outAnim(kier = 1); break;
case 'E' : x++;heroAnim(hx=8);if((x>17) && (x<79)){mapAnim(mx=8);}outAnim(kier = 2); break;
case 'N' : if(y<9 || y>53){y--;heroAnim(hy=-8);}else{y--;heroAnim(hy=-8);mapAnim(my=-8);}outAnim(kier = 3); break;
}
//document.getElementById("coordsY").innerHTML = x;
}
//Animacja chodzenia postaci
function heroAnim()
{
//Czy kliknięto E lub W
if(dir=='E' || dir=='W')
{
//Animujemy mapę czterema timeoutami po 8 px co daje łącznie 32px
setTimeout("goX(xx+="+hx+");",65);
setTimeout("goX(xx+="+hx+");",130);
setTimeout("goX(xx+="+hx+");",185);
setTimeout("goX(xx+="+hx+");",260);
}
//Jak kliknięto W lub S
else
{
setTimeout("goY(yy+="+hy+");",65);
setTimeout("goY(yy+="+hy+");",130);
setTimeout("goY(yy+="+hy+");",185);
setTimeout("goY(yy+="+hy+");",260);
}
}
//Animacja mapy
function mapAnim()
{
if(dir=='E' || dir=='W')
{
setTimeout("mapX(mX+="+mx+");",65);
setTimeout("mapX(mX+="+mx+");",130);
setTimeout("mapX(mX+="+mx+");",185);
setTimeout("mapX(mX+="+mx+");",260);
}
else
{
//alert('ds');
setTimeout("mapY(mY+="+my+");",65);
setTimeout("mapY(mY+="+my+");",130);
setTimeout("mapY(mY+="+my+");",185);
setTimeout("mapY(mY+="+my+");",260);
}
}
//Animacja outfitu (kolejność wykonania animacji, kierunek)
function outAnim()
{
setTimeout("animation(1,"+kier+");",65);
setTimeout("animation(2,"+kier+");",139);
setTimeout("animation(3,"+kier+");",185);
setTimeout("animation(0,"+kier+");",260);
}
//Animujemy out postaci: Mnożymy klatkę przez 32 i kierunek przez 48
function animation(klatka,kierunek){
$("#gracz").css("background-position",(-klatka*32)+"px "+(-kierunek*48)+"px");
}
//Animacja elementu gracz oś X
function goX(xx)
{
$("#gracz").css("left",xx +"px");
document.getElementById("coordsX").innerHTML = xx + ' /32= '+x;
}
//Animacja elementu gracz oś Y
function goY(yy)
{
$("#gracz").css("top",yy +"px");
document.getElementById("coordsY").innerHTML = yy + ' /32= '+y;
}
//Animacja diva mapa oś X
function mapX(mX)
{
$("#mapa").css("right",mX +"px");
}
//Animacja diva mapa oś Y
function mapY(mY)
{
$("#mapa").css("bottom",mY +"px");
//document.getElementById("coordsY").innerHTML = mY;
}
//Powtarzanie głównej funkcji game() co 260 ms
setInterval(game, 260);
(Tak, wiem. Totalna porażka) Jeśli mam być szczery to w mojej opinii lepiej to działa niż ten kod w canvasie, ale mam problem z faktem iż często jest takie przymulenie po naciśnięciu strzałki zanim postać ruszy. Wiem, że to wina setIntervala bo wykonuje się co 260 ms i po prostu nie da się tego uniknąć, a nie wiem jak to inaczej załatwić.
Proszę o szczerą ocenę, czy sposób w który próbuję to napisać ma jakikolwiek sens.
Proszę także o porady jak mógłbym to napisać, co byłoby najlepsze.