1。ゲームの背景の紹介(前面に書かれたナンセンス):
5月上旬のある日、私は特定のウェブサイトがこのゲーム、ポンゴを推奨しているのを見ました。私はかなり良く見え、iPadで試してみました。 2つのゲームをプレイした後、私はそれが良いことだと感じました、そしてそれは非常に満足していました。誰もがそれを知っています。
しかし、しばらくして、私はゲームにiPadにいくつかのバグがあるように見えることがわかりました。私はしばらくプレイした後に立ち往生し、それを強制することしか退却できませんでした。それは本当に悲痛であり、記録はまだ壊れるのを待っていました。
何をするか?自分のゲームをプレイするよりもゲームをプレイする方が良いという考えは、再び激しく見え、それから私は友人の悲痛なものにパッドを投げました。私は静かにコンピューターに戻り、立ち往生することができなかったものを書き始めました。
基本的なフレームワークを書き留めるのに約2時間かかり、それをSinaAppに投げて試しました。基本的に遊んでからシャワーを浴びて寝るのが最善でした。
翌日目が覚めたとき、週末に何もすることがなかったので、インターフェイスのデザインに時間を費やしました。残念ながら、私はいくつかの深刻なバグを自分で見つけ、最終的にそれらを修正するのに少し時間がかかりました。
最後に、ゲームの名前は「Pongo+」と名付けられました(私をクリックして携帯電話で再生します)。コンピューターは当面はサポートされていません。ちなみに、ソースコードはGitHubにアップロードされ、提出スコアモジュールが削除されました。
2。ゲームトライアルWebサイト:
Pongo+(モバイルのみ):http://mypongo.sinaapp.com/
Github Open Source(Forkはゲームをより良くすることを歓迎します):https://github.com/chenreason/pongo/blob/gh-pages/index.html
3。ゲームルールとゲームプレイ:
画面をクリックすると、ベゼルの動きの方向が変わります。ベゼルをクリックすると、ベゼルの方向が一度変更され、小さなボールが転がり、大きな円から逃げないようにするだけで、ベゼルの方向が変わります。時間が長ければ長いほど良い!最後に、ランキングのために独自のスコアを送信できます!
4。ゲームで使用されるテクノロジー:
HTML、CSS、JavaScript、Canvas、Php
5。ゲームデザインのアイデア:
a)キャンバスを使用して、ゲームのメインインターフェイスを描画します。底は、大きな円で覆われたモノクロ長方形で、小さな円とバッフルが大きな円に描かれています。また、バッフルの中央に1pxのサイズがある超小さな円があります(衝突検出用)。
b)小さな円の移動には8つの方向があります:上、下、左、右、左上、左下、右下、右下。
c)時計回りと反時計回りのバッフルの動きの方向は2つあります。
d)衝突検出は、エンジンの使用を伴うものではなく、バッフルの中央にある小さな円とスーパーサークルに基づいた距離判断を行い、それにより単純な衝突検出を達成します。
e)ボールが衝突した後のリバウンドの方向が決定され、一般的な知識がそれをリストするために使用され、合計8つの状況があります。
6。ゲームの実装の難しさ:
a)衝突検出。
b)タイマーセットインテーバルクリアランスのタイミングと、それが明確で徹底しているかどうか。
c)タイマーサイクルの長さとゲームエクスペリエンスの関係。
d)AndroidデバイスとiOSデバイスの異なるパフォーマンスによって引き起こされるゲームの流ency性の問題。
7。ゲームの既存の問題:
a)衝突検出は、タイマー間隔が非常に短いため、2つの円間の中心距離を比較し、タイマーの使用を伴うため、肉眼で見られる衝突の背後に数十の衝突が発生しました。これにより、ボールの実際のリバウンド方向が実際の物理定理とは異なります。最適化後、発生の可能性は低くなりますが、回避されていません。したがって、一部のプレイヤーは、サークルがバッフルの中心に正確にヒットしない場合、ゲームが失敗する可能性があることがわかります。
b)機能はあまりにも冗長であり、低効率であり、タイマーの使用であるため、AndroidでのゲームエクスペリエンスはiOSまたは他のモバイルデバイスとは異なります(一般に、iOSはAndroidによるものです)。
c)ランキングリストは、自動リアルタイムの更新を達成していません。 (データベースはまだ使用されていません)
8。ゲームインターフェイスプレビュー:
(図1は初版で、図2がボタンを削除し、図3が最終版、図4はランキングリストです)
図1
図2
図3
9。ゲームのソースコードの一部JavaScript:
コードコピーは次のとおりです。
var ifingame = 0;
var maxgrade = 0、grade = 0;
var grade1、grade2;
var nickname;
var gamespeed = 1.4; //ボール速度
var linespeed = math.pi/95; //トラックライン速度
VAR CrashDistanceFaild = -7; //衝突検出パラメーター
var CrashDistancesucc = 15
var fantanjuli = 7;
var themaxgradyline = 12.1;
関数getCookie1(ニックネーム)
{
if(document.cookie.length> 0)
{
c_start = document.cookie.indexof(nickname + "=")
if(c_start!= -1)
{
c_start = c_start + nickname.length + 1;
c_end = document.cookie.indexof( "、"、c_start);
if(c_end == -1)
c_end = document.cookie.length;
unescape(document.cookie.substring(c_start、c_end))を返します。
}
}
戻る ""
}
関数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;
unescape(document.cookie.substring(c_start、c_end))を返します。
}
}
戻る ""
}
function setcookie(ニックネーム、値、mymaxgrade、maxgrade、expedays)
{
var exdate = new date()
exdate.setdate(exdate.getDate()+expedays)
document.cookie = nickname + "=" + escape(value) + "、" + mymaxgrade + "=" + escase(maxgrade) +((expeardays == null)? "": "; expires =" + exdate.togmtstring());
}
関数checkcookie()
{
nickname = getcookie1( 'nickname');
maxgrade = parseint(getcookie2( 'mymaxgrade'));
if(isnan(maxgrade)== true)
{
maxgrade = 0;
}
if(nickname!= null && nickname!= "")
{
Alert( 'Welcome'+nickname+'back!'+'/n'+"あなたがそれを気に入ったら、それを共有してください〜");
}
それ以外
{
ニックネーム=プロンプト( 'ニックネームを入力してください:(名前が長すぎて、不完全に表示されます)'、 ""
if(nickname!= null && nickname!= "")
{
var maxgradestring = maxgrade.toString();
SetCookie( 'nickname'、nickname、 'mymaxgrade'、maxgradestring、365);
}
}
}
var objpane = document.getElementById( "Pane");
var ctxpane = objpane.getContext( "2d");
ctxpane.translate(150,150); //必要なキャンバスセンターポイント翻訳
function sendmail()
{
if(grade2> themaxgradyline)
var max_grade = grade2;
window.location.href = 'index.php?max_grade ='+max_grade+'&nick_name ='+nickname;
/* {
<?php
$ grade = $ _ get ['max_grade'];
$ nickname = $ _ get ['nick_name'];
$ mail = new SaeMail();
$ ret = $ mail-> quicksend( '[email protected]'、$ grade、$ nickname、 '[email protected]'、 'mypongo');
$ mail-> clean();
?>
}*/
Alert(nickname+"your grade is:"+grade2+"が正常に送信〜");
}
var gamedirection = {
シャン:1、
Xia:5、
Zuo:7、
あなた:3、
Zuoshang:8、
Zuoxia:6、
Youshang:2、
Youxia:4、
時計:0、
アンチクラック:9
};//方向
var canvas = {
幅:300、
高さ:300、
};//キャンバス
var bigcircle = {// Big Circleパラメーター
x:0、//円の中心のx軸座標値
y:0、//円の中心のy軸座標値
R:150、//円の半径
C: 'RGB(255,255,255)'、
}; // dayuan
var smallcircle = {// smallcircleパラメーター
x:0、//円の中心のx軸座標値
y:0、//円の中心のy軸座標値
R:12、//円の半径
C: 'RGB(204,105,106)'、
方向:gamedirection.xia、
}; //小さな円
var Line = {//バッフルラインのパラメーター
x:0、//円の中心のx軸座標値
y:0、//円の中心のy軸座標値
R:150、//アークの半径
開始:( math.pi/2-math.pi/16)、
終了:(Math.Pi/2+Math.Pi/16)、
C: 'RGB(55,55,55)'、
方向:gamedirection.antylock、
}; //トラッキングライン
var dot = {//トラッキングポイントパラメーター
x :( bigcircle.r*math.cos(line.start+math.pi/16))、//大きな円を原点として使用します
y:(bigcircle.r*math.sin(line.start+math.pi/16))、
R:1、
} //追跡点
function changelinedirection()
{
if(line.direction == gamedirection.clock)
{
line.direction = gamedirection.antylock;
}
それ以外
{
line.direction = gamedirection.clock;
}
}
関数getDistance(){
var distance = math.sqrt((smallcircle.x)*(smallcircle.x)+(smallcircle.y)*(smallcircle.y));
戻り距離;
} //小さなボールと大きな円中心の間の平方距離に戻りますgetDistance()
function ifgameover(){//それが範囲外であるかどうかを判断します
if((getDistance() - bigcircle.r)> 5)
trueを返します。
それ以外
falseを返します。
} //ゲームがifgameover()を終了するかどうかを判断します
関数ifcrash(){//衝突検出
var dx = dot.x-smallcircle.x;
var dy = dot.y-smallcircle.y;
var dd = math.sqrt(dx*dx+dy*dy);
if(dd <crashdistancesucc)
trueを返します。
それ以外
falseを返します。
} //衝突検出ifcrash()
function randomback()
{
var x = math.floor(math.random()*3);
switch(smallcircle.direction){
case gamedirection.shang:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
case gamedirection.xia:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
case gamedirection.zuo:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
case gamedirection.you:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
case gamedirection.zuoshang:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.youxia;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
case gamedirection.zuoxia:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.youshang;
smallcircle.x = smallcircle.x+fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.you;
smallcircle.x = smallcircle.x+fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
ケースgamedirection.youshang:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.zuoxia;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.xia;
smallcircle.y = smallcircle.y+fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
ケースGAMEDIRECTION.YOXIA:
{
switch(x)
{
ケース0:
smallcircle.direction = gamedirection.zuoshang;
smallcircle.x = smallcircle.x-fantanjuli;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
ケース1:
smallcircle.direction = gamedirection.zuo;
smallcircle.x = smallcircle.x-fantanjuli;
壊す;
ケース2:
smallcircle.direction = gamedirection.shang;
smallcircle.y = smallcircle.y-fantanjuli;
壊す;
デフォルト:
壊す;
}壊す;
}
デフォルト:
{
壊す;
}
}
} //ランダムバック()をランダムに逆転させたボール
機能smallcircledirection()
{
switch(smallcircle.direction){//ボールの方向に従って移動します
case gamedirection.shang:
{
smallcircle.y = smallcircle.y-gamespeed;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
case gamedirection.xia:
{
smallcircle.y = smallcircle.y+gamespeed;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
case gamedirection.zuo:
{
smallcircle.x = smallcircle.x-gamespeed;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
case gamedirection.you:
{
smallcircle.x = smallcircle.x+gamespeed;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
case gamedirection.zuoshang:
{
smallcircle.x = smallcircle.x-gamespeed*0.8;
smallcircle.y = smallcircle.y-gamespeed*0.8;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
case gamedirection.zuoxia:
{
smallcircle.x = smallcircle.x-gamespeed*0.8;
smallcircle.y = smallcircle.y+gamespeed*0.8;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
ケースgamedirection.youshang:
{
smallcircle.x = smallcircle.x+gamespeed*0.8;
smallcircle.y = smallcircle.y-gamespeed*0.8;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
ケースGAMEDIRECTION.YOXIA:
{
smallcircle.x = smallcircle.x+gamespeed*0.8;
smallcircle.y = smallcircle.y+gamespeed*0.8;
グレード++;
if(grade> maxgrade)
{
maxgrade = grade;
newRecoder();
}
addone();
壊す;
}
デフォルト:
{
壊す;
}
}
} //ボールはsmallcircledirection()を移動します
/*下の円を描く*/
ctxpane.beginpath(); // dayuan
ctxpane.arc(bigcircle.x、bigcircle.y、bigcircle.r、0、math.pi*2、true);
ctxpane.fillstyle = bigcircle.c;
ctxpane.fill();
ctxpane.closepath();
/*底部追跡線を描画*/
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();
関数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();
}
機能newRecoder()
{
ctxpane.beginpath();
ctxpane.fillstyle = "rgb(255,0,0)";
ctxpane.font = "18px papyrus";
ctxpane.filltext( "new!"、58,80);
ctxpane.closepath();
}
関数addone()
{
grade1 =(grade/150).tofixed(1);
grade2 =(maxgrade/150).tofixed(1);
var says1 = "now";
var say2 = "best"
ctxpane.beginpath();
ctxpane.strokestyle = "rgb(250,222,185)";
ctxpane.font = "60px papyrus";
ctxpane.strokeText(grade1、-45、-60);
ctxpane.strokeText(grade2、-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();
}
関数movetest(){
if(ifgameover())
{
ifingame = 0;
if(maxgrade> parseint(getcookie2( 'mymaxgrade')))
{
setCookie( 'nickname'、nickname、 'mymaxgrade'、maxgrade.tostring()、365);
}
ClearInterval(タイマー);
tapme();
}
それ以外
{
if(ifcrash())
{
ランダムバック();
}
ctxpane.ClearRect(-150、-150,300,300); //画面をクリアします
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)//ラインの追跡時計回り
{
line.start = line.start + linespeed;
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();
}
if(line.direction == gamedirection.anttylock)//カウンタークロックワイズに追跡します
{
line.start = line.start- linespeed;
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)//トラッキングポイント
dot.y = bigcircle.r*math.sin(line.start+math.pi/32)
ctxpane.beginPath(); //オンライン追跡ポイント
ctxpane.arc(dot.x、dot.y、dot.r、0、math.pi*2、true);
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();
}
} //メイン関数
/////////////////////////////////
tapme();
varタイマー;
function startgame(){//ゲームを開始します
if(ifingame == 0)
{
ifingame = 1;
グレード= 0;
var xx = math.floor(math.random()*8);
/* switch(xx)
{
ケース0:
smallcircle.direction = gamedirection.shang;
壊す;
ケース1:
smallcircle.direction = gamedirection.xia;
壊す;
ケース2:
smallcircle.direction = gamedirection.zuo;
壊す;
ケース3:
smallcircle.direction = gamedirection.you;
壊す;
ケース4:
smallcircle.direction = gamedirection.zuoshang;
壊す;
ケース5:
smallcircle.direction = gamedirection.zuoxia;
壊す;
ケース6:
smallcircle.direction = gamedirection.youshang;
壊す;
ケース7:
smallcircle.direction = gamedirection.youxia;
壊す;
デフォルト:
壊す;
}*/
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.antylock;
ClearInterval(タイマー);
Timer = setInterval(Movtest、10);
}
} //ゲームstartgame()を開始します
function opentop()
{
window.location = "http://pongotop.sinaapp.com";
}
10.最後に書かれています
これは純粋に自己検証です。執筆後3日目に、私はインターンシップを見つけるために履歴書を提出するのに忙しく、それを世話する時間がありませんでした。私はそれを友達の輪に投げ入れて、友達が遊ぶために。今月は過ぎ去り、このゲームをもう一度見ています。このように死んではいけないと感じています。スキルはありませんし、それをうまくやります。したがって、この記事がポンゴに興味のある友人を助けることができることを願っています。さらに、この分野の専門家が私にアドバイスを与えてくれたら、彼がすべての疑問やアドバイスにメッセージを残すことを歓迎してくれることを願っています。ありがとう!