1. Introdução ao fundo do jogo (sem sentido escrito na frente):
Um dia, no início de maio, vi um certo site recomendando este jogo, Pongo. Eu parecia muito bom e tentei com o iPad. Depois de jogar dois jogos, senti que era uma coisa boa, e foi bastante gratificante, porque era um jogo que era um tipo de mão devida. Todo mundo sabe disso.
Mas depois de um tempo, descobri que o jogo parecia ter alguns insetos no iPad. Eu ficava preso depois de jogar por um tempo e só conseguia forçar a recuar. Foi realmente comovente, e o disco ainda estava esperando para ser quebrado.
O que fazer? A ideia de que é melhor jogar do que jogar seus próprios jogos parecia maluco novamente, e então joguei o bloco para o coração da minha amiga. Voltei silenciosamente ao computador e comecei a escrever algo que não pude ficar preso.
Demorou cerca de duas horas para escrever a estrutura básica e depois jogou -a em Sinaapp e tentou. Foi basicamente o melhor para jogar e depois tomar um banho e ir para a cama.
Quando acordei no dia seguinte, passei algum tempo projetando a interface porque não tinha nada para fazer no fim de semana. Infelizmente, eu mesmo encontrei alguns insetos sérios e finalmente levei algum tempo para corrigi -los.
Finalmente, o jogo foi nomeado "Pongo+" (clique em mim para jogar em telefones celulares). O computador não é suportado por enquanto. A propósito, o código -fonte foi enviado no GitHub e o módulo de pontuação de envio foi removido.
2. Site de teste de jogo:
Pongo+ (somente móvel): http://mypongo.sinaapp.com/
Github Open Source (Fork é bem-vindo para melhorar o jogo): https://github.com/chenroason/pongo/blob/gh-pages/index.html
3. Regras de jogo e jogabilidade:
Clicar na tela alterará a direção do movimento do painel. Clicar no painel alterará a direção do painel uma vez, com o objetivo de apenas bloquear as pequenas bolas rolando e impedindo -as de sair do grande círculo. Quanto mais tempo o tempo, melhor! Finalmente, você pode enviar suas próprias pontuações para a classificação!
4. A tecnologia usada no jogo:
HTML, CSS, JavaScript, Canvas, PHP
5. Idéias de design de jogos:
a) Use tela para desenhar a interface principal do jogo. O fundo é um retângulo monocromático, coberto com um círculo grande, e um pequeno círculo e um defletor são desenhados no círculo grande. Há também um círculo super pequeno com um tamanho de 1px no meio do defletor (para detecção de colisão).
b) Existem 8 direções de movimento de pequenos círculos: superior, inferior, esquerda, direita, superior esquerda, inferior esquerdo, superior direito e inferior direito.
c) Existem apenas duas direções de movimento do defletor, no sentido horário e no sentido anti -horário.
d) A detecção de colisão não envolve o uso do motor, mas faz o julgamento da distância com base no pequeno círculo e no super círculo no meio do defletor, alcançando assim uma detecção simples de colisão.
e) A direção de rebote depois que a bola colidiu é determinada e o conhecimento geral é usado para listá -la, e existem 8 situações no total.
6. Dificuldades na implementação do jogo:
a) Detecção de colisão.
b) Tempo de liberação do conjunto do timer e se é claro e completo.
c) A relação entre a duração do ciclo do timer e a experiência de jogo.
d) Problemas de fluência do jogo causados pelo desempenho diferente dos dispositivos Android e iOS.
7. Problemas existentes com o jogo:
a) Como a detecção de colisão é comparar a distância central entre dois círculos e envolver o uso de temporizadores, devido ao intervalo de timer extremamente curto, dezenas de colisões ocorreram atrás de uma colisão vista pelo olho nu. Isso fará com que a direção real da bola seja diferente do teorema físico real. Após a otimização, a probabilidade de ocorrência é baixa, mas não foi evitada. Portanto, alguns jogadores descobrirão que, se o círculo não atingir o centro do defletor com precisão, poderá fazer com que o jogo falhe.
b) Como as funções são muito detalhadas, de baixa eficiência e o uso de temporizadores, a experiência de jogo no Android é diferente do iOS ou de outros dispositivos móveis (em geral, o iOS é devido ao Android).
c) A lista de classificação não alcançou atualizações automáticas em tempo real. (O banco de dados ainda não será usado)
8. Visualização da interface do jogo:
(A Figura 1 é a primeira edição, a Figura 2 removeu o botão, a Figura 3 é a edição final e a Figura 4 é a lista de classificação)
Figura 1
Figura 2
Figura 3
9. Parte do código -fonte do jogo JavaScript:
A cópia do código é a seguinte:
var ifingame = 0;
var maxgrade = 0, grau = 0;
var grau1, grau2;
var apelido;
var gamespeed = 1,4; // velocidade da bola
var linepeed = math.pi/95; // velocidade da linha de rastreamento
var crashDistanceFaild = -7; // parâmetros de detecção de colisão
var crashDistancesucc = 15
var fantanjuli = 7;
var theraxgradLeline = 12.1;
função getcookie1 (apelido)
{
if (document.cookie.length> 0)
{
c_start = document.cookie.indexof (apelido + "=")
if (c_start! =-1)
{
c_start = c_start + apelido.length + 1;
c_end = document.cookie.indexof (",", c_start);
if (c_end ==-1)
c_end = document.cookie.length;
return unescape (document.cookie.substring (c_start, c_end));
}
}
retornar ""
}
função getcookie2 (mymaxgrade)
{
if (document.cookie.length> 0)
{
c_start = document.cookie.indexof (mymaxgrade + "=")
if (c_start! =-1)
{
c_start = c_start + mymaxgrade.length + 1;
c_end = document.cookie.indexof (";", c_start);
if (c_end ==-1)
c_end = document.cookie.length;
return unescape (document.cookie.substring (c_start, c_end));
}
}
retornar ""
}
função setcookie (apelido, valor, mymaxgrade, maxgrade, expireays)
{
var exdate = new Date ()
exdate.setDate (exdate.getdate ()+expireays)
document.cookie = apelido + "=" + escape (valor) + "," + mymaxgrade + "=" + escape (maxgr) + ((expireays == null)? "": "; expires =" + exdate.togmtString ());
}
função checkcookie ()
{
apelido = getCookie1 ('apelido');
maxgrade = parseint (getCookie2 ('mymaxgrade'));
if (isnan (maxgrade) == true)
{
maxgrade = 0;
}
if (apelido! = null && apelido! = "")
{
Alert ('Welcome'+apelido+'de volta!'+'/n'+"Se você gosta, compartilhe ~");
}
outro
{
Apelido = Prompt ('Por favor, digite seu apelido: (o nome é muito longo e será exibido incompleto)', "")
if (apelido! = null && apelido! = "")
{
var maxGreDestring = maxgrade.toString ();
setcookie ('apelido', apelido, 'mymaxgrade', maxGradEstring, 365);
}
}
}
var objpane = document.getElementById ("painel");
var ctxpane = objpane.getContext ("2D");
ctxpane.Translate (150.150); // Tradução de ponto central de tela necessária
função sendmail ()
{
if (grau2> temaxgradiline)
var max_grade = grau2;
window.Location.href = 'index.php? max_grade ='+max_grade+'& nick_name ='+apelido;
/* {
<? php
$ grau = $ _ get ['max_grade'];
$ apelido = $ _ get ['nick_name'];
$ Mail = new Saemail ();
$ ret = $ Mail-> Quicksend ('[email protected]', $ GRADE, $ NENHAMENTO, '[email protected]', 'MyPongo');
$ Mail-> limpo ();
?>
}*/
alerta (apelido+"Sua nota é:"+grau2+"enviado com sucesso ~");
}
var gamedirection = {
Shang: 1,
xia: 5,
Zuo: 7,
você: 3,
Zuoshang: 8,
Zuoxia: 6,
YouShang: 2,
youxia: 4,
relógio: 0,
anticlock: 9,
};//direção
var tela = {
Largura: 300,
Altura: 300,
};//tela
var bigcircle = {// parâmetro de círculo grande
x: 0, // o valor de coordenadas do X-AXIS do centro do círculo
y: 0, // o valor de coordenadas do Y-AXIS do centro do círculo
r: 150, // o raio do círculo
C: 'RGB (255.255.255)',
}; // Dayuan
var smallcircle = {// parâmetro smallcircle
x: 0, // o valor de coordenadas do X-AXIS do centro do círculo
y: 0, // o valor de coordenadas do Y-AXIS do centro do círculo
r: 12, // o raio do círculo
C: 'RGB (204.105.106)',
direção: gamedirection.xia,
}; // pequeno círculo
var linha = {// parâmetros da linha do defletor
x: 0, // o valor de coordenadas do X-AXIS do centro do círculo
y: 0, // o valor de coordenadas do Y-AXIS do centro do círculo
r: 150, // o raio do arco
Iniciar: (Math.pi/2-math.pi/16),
Fim: (Math.pi/2+Math.pi/16),
C: 'RGB (55,55,55)',
direção: gamedirection.anticlock,
}; // linha de rastreamento
var dot = {// parâmetros do ponto de rastreamento
x: (bigcircle.r*math.cos (line.start+math.pi/16)), // use o grande círculo como a origem
y: (bigcircle.r*math.sin (line.start+math.pi/16)),
R: 1,
} // ponto de rastreamento
função changelinedirection ()
{
if (line.direction == gamedirection.clock)
{
line.direction = gamedirection.anticlock;
}
outro
{
line.direction = gamedirection.clock;
}
}
função getDistance () {
var distase = math.sqrt ((smallcircle.x)*(smallcircle.x)+(smallcircle.y)*(smallcircle.y));
distância de retorno;
} // retorna à distância quadrada entre a pequena bola e o grande centro de círculo getDistance ()
função ifgameover () {// julga se está fora dos limites
if ((getDistance () - bigcircle.r)> 5)
retornar true;
outro
retornar falso;
} // julgue se o jogo termina Ifgameover ()
função ifcrash () {// detecção de colisão
var dx = dot.x-smallcircle.x;
var dy = dot.y-smallcircle.y;
var dd = math.sqrt (dx*dx+dy*dy);
if (dd <crashDistancesucc)
retornar true;
outro
retornar falso;
} // Detecção de colisão ifcrash ()
função randomback ()
{
var x = math.floor (Math.random ()*3);
switch (smallcircle.direction) {
case gamedirection.shang:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
case gamedirection.xia:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
case gamedirection.zuo:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
caso gamedirection.you:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
case gamedirection.zuoshang:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
case gamedirection.zuoxia:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
caso gamedirection.youshang:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
caso gamedirection.youxia:
{
Switch (x)
{
Caso 0:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
quebrar;
padrão:
quebrar;
}quebrar;
}
padrão:
{
quebrar;
}
}
} // A bola reverteu aleatoriamente o Randomback ()
função smallcircledirection ()
{
switch (smallcircle.direction) {// mova -se de acordo com a direção da bola
case gamedirection.shang:
{
smallcircle.y = smallcircle.y-gamespeed;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
case gamedirection.xia:
{
smallcircle.y = smallcircle.y+gamespeed;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
case gamedirection.zuo:
{
smallcircle.x = smallcircle.x-gamespeed;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
caso gamedirection.you:
{
smallcircle.x = smallcircle.x+gamespeed;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
case gamedirection.zuoshang:
{
smallcircle.x = smallcircle.x-gamespeed*0,8;
smallcircle.y = smallcircle.y-gamespeed*0,8;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
case gamedirection.zuoxia:
{
smallcircle.x = smallcircle.x-gamespeed*0,8;
smallcircle.y = smallcircle.y+gamespeed*0,8;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
caso gamedirection.youshang:
{
smallcircle.x = smallcircle.x+gamespeed*0,8;
smallcircle.y = smallcircle.y-gamespeed*0,8;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
caso gamedirection.youxia:
{
smallcircle.x = smallcircle.x+gamespeed*0,8;
smallcircle.y = smallcircle.y+gamespeed*0,8;
grau ++;
if (grau> maxgrade)
{
maxgrade = grau;
newrecoder ();
}
addone ();
quebrar;
}
padrão:
{
quebrar;
}
}
} // A bola move SmallCircledirection ()
/*Desenhe o círculo inferior*/
ctxpane.BeginPath (); // Dayuan
ctxpane.arc (bigcircle.x, bigcircle.y, bigcircle.r, 0, math.pi*2, true);
ctxpane.fillstyle = bigcircle.c;
ctxpane.fill ();
ctxpane.closePath ();
/*Desenhe a linha de rastreamento inferior*/
ctxpane.BeginPath ();
ctxpane.LineWidth = 6;
ctxpane.strokestyle = line.c;
ctxpane.arc (line.x, line.y, line.r, line.start, line.end, false);
ctxpane.stroke ();
ctxpane.closePath ();
função tapme () // tapme
{
ctxpane.BeginPath ();
ctxpane.strokestyle = "rgb (255.222.195)";
ctxpane.font = "80px Papyrus";
ctxpane.strokeText ('TAP',-95,30);
ctxpane.fillstyle = "rgb (255.205.105)";
ctxpane.font = "35px Papyrus";
ctxpane.fillText ('me', 70,30);
ctxpane.closePath ();
}
função newrecoder ()
{
ctxpane.BeginPath ();
ctxpane.fillstyle = "rgb (255,0,0)";
ctxpane.font = "18px Papyrus";
ctxpane.fillText ("novo!", 58,80);
ctxpane.closePath ();
}
função addone ()
{
grau1 = (grau/150) .tofixado (1);
grau2 = (maxgrade/150) .tofixado (1);
var diz1 = "agora";
var diz2 = "melhor"
ctxpane.BeginPath ();
ctxpane.strokestyle = "rgb (250.222.185)";
ctxpane.font = "60px Papyrus";
ctxpane.stroketext (grau1, -45, -60);
ctxpane.strokeText (grau2, -45.100);
ctxpane.fillstyle = "rgb (255,0,100)";
ctxpane.font = "15px Papyrus";
ctxpane.fillText (Say1,58, -60);
ctxpane.fillstyle = "rgb (255,0,100)";
ctxpane.font = "15px Papyrus";
ctxpane.fillText (SAY2,58,100);
ctxpane.closePath ();
}
função moveTest () {
if (ifgameover ())
{
ifingame = 0;
if (maxgrade> parseint (getcookie2 ('mymaxgrade'))))
{
setcookie ('apelido', apelido, 'mymaxgrade', maxgrade.toString (), 365);
}
ClearInterval (timer);
tapme ();
}
outro
{
if (ifcrash ())
{
Randomback ();
}
ctxpane.clearrect (-150, -150.300.300); // limpe a tela
ctxpane.BeginPath (); // Dayuan
ctxpane.arc (bigcircle.x, bigcircle.y, bigcircle.r, 0, math.pi*2, true);
ctxpane.fillstyle = bigcircle.c;
ctxpane.fill ();
ctxpane.closePath ();
if (line.direction == gamedirection.clock) // rastreando a linha no sentido horário
{
line.start = line.start + linepeed;
line.end = line.end +linepeed;
ctxpane.BeginPath ();
ctxpane.LineWidth = 4;
ctxpane.strokestyle = line.c;
ctxpane.arc (line.x, line.y, line.r, line.start, line.end, false);
ctxpane.stroke ();
ctxpane.closePath ();
}
if (line.direction == gamedirection.anticlock) // rastreando no sentido anti -horário
{
line.start = line.start - linepeed;
line.end = line.end -LinesPeed;
ctxpane.BeginPath ();
ctxpane.LineWidth = 4;
ctxpane.strokestyle = line.c;
ctxpane.arc (line.x, line.y, line.r, line.start, line.end, false);
ctxpane.stroke ();
ctxpane.closePath ();
}
dot.x = bigcircle.r*math.cos (line.start+math.pi/32) // ponto de rastreamento
Dot.Y = bigcircle.r*Math.sin (line.start+math.pi/32)
ctxpane.BeginPath (); // Ponto de rastreamento online
ctxpane.arc (Dot.x, Dot.y, Dot.r, 0, Math.pi*2, verdadeiro);
ctxpane.fillstyle = smallcircle.c;
ctxpane.fill ();
ctxpane.closePath ();
smallcircledirection (); // smallcircledirection (); //
ctxpane.save ();
ctxpane.BeginPath ();
ctxpane.arc (smallcircle.x, smallcircle.y, smallcircle.r, 0, math.pi*2, true);
ctxpane.fillstyle = smallcircle.c;
ctxpane.fill ();
ctxpane.closePath ();
ctxpane.restore ();
}
} // Função principal
///////////////////////////////////////////////
tapme ();
Var Timer;
função startgame () {// iniciar o jogo
if (ifingame == 0)
{
ifingame = 1;
grau = 0;
var xx = Math.Floor (Math.random ()*8);
/* switch (xx)
{
Caso 0:
smallcircle.direction = gamedirection.shang;
quebrar;
Caso 1:
smallcircle.direction = gamedirection.xia;
quebrar;
Caso 2:
smallcircle.direction = gamedirection.zuo;
quebrar;
Caso 3:
smallcircle.direction = gamedirection.you;
quebrar;
Caso 4:
smallcircle.direction = gamedirection.zuoshang;
quebrar;
Caso 5:
smallcircle.direction = gamedirection.zuoxia;
quebrar;
Caso 6:
smallcircle.direction = gamedirection.youshang;
quebrar;
Caso 7:
smallcircle.direction = gamedirection.youxia;
quebrar;
padrão:
quebrar;
}*/
smallcircle.direction = gamedirection.xia;
smallcircle.x = smallcircle.y = 0;
line.start = math.pi/2-math.pi/26;
line.end = math.pi/2+math.pi/26;
line.direction = gamedirection.anticlock;
ClearInterval (timer);
timer = setInterval (movTest, 10);
}
} // Inicie o jogo StartGame ()
função opentop ()
{
window.Location = "http://pontontop.sinaapp.com";
}
10. Escrito no final
Isso é puramente uma auto-entretenimento. No terceiro dia após escrever, eu estava ocupado enviando currículos para encontrar um estágio e não tive tempo de cuidar disso. Joguei -o no meu círculo de amigos para meus amigos brincarem. Este mês se passou e eu assisto a este jogo novamente. Eu sinto que não deveria ter morrido assim. Não tenho habilidades e faço muito bem. Portanto, espero que este artigo possa ajudar alguns amigos interessados em Pongo. Além disso, espero que, se algum especialista nesse campo possa me dar conselhos se ele vir, ele me recebe para deixar uma mensagem para todas as dúvidas e conselhos. Obrigado!