Heim  >  Artikel  >  Web-Frontend  >  Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

WBOY
WBOYOriginal
2016-05-16 16:44:221259Durchsuche

1. Einführung in den Spielhintergrund (Unsinn davor geschrieben):

Eines Tages Anfang Mai sah ich eine Website, die dieses Spiel, Pongo, empfahl. Es sah ziemlich gut aus, also habe ich es heruntergeladen und auf meinem iPad ausprobiert. Nachdem ich zwei Spiele gespielt hatte, fand ich es ziemlich unterhaltsam Jeder kennt Handheld-Spiele.

Aber nach einer Weile stellte ich fest, dass das Spiel einige Fehler aufwies. Nach einer Weile blieb es hängen und ich musste das Beenden erzwingen, und die Aufzeichnung wartete immer noch gebrochen sein.

Was tun? Der böse Gedanke, dass Spiele nicht so gut sind wie das Spielen eigener Spiele, kam wieder auf, und dann warf ich meinem Freund den Block zu. Ich kehrte schweigend zum Computer zurück und begann, mein eigenes Spiel zu schreiben, das nicht einfrieren wollte .

Es hat etwa zwei Stunden gedauert, das Grundgerüst auszuschreiben, dann habe ich es in der Sina-App ausprobiert und der Effekt war im Grunde spielbar, dann bin ich schlafen gegangen.

Als ich am nächsten Tag aufwachte, verbrachte ich einige Zeit damit, die Benutzeroberfläche zu entwerfen, da ich am Wochenende nichts zu tun hatte. Leider entdeckte ich einige schwerwiegende Fehler und verbrachte schließlich einige Zeit damit, sie zu beheben.

Am Ende hieß das Spiel „Pongo“ (klicken Sie zum Spielen auf Ihr Mobiltelefon). Die Computerversion wird derzeit nicht unterstützt, daher habe ich den Quellcode auf Github hochgeladen und das Submit-Score-Modul entfernt.

2. Website zum Testen des Spiels:

Pongo (nur mobile Version): http://mypongo.sinaapp.com/

Github Open Source (willkommen bei Fork, um das Spiel zu verbessern): https://github.com/ChenReason/pongo/blob/gh-pages/index.html

3. Spielregeln und Gameplay:

Ein Klick auf den Bildschirm ändert die Bewegungsrichtung der Lünette. Der Zweck besteht lediglich darin, die rollende Kugel zu blockieren und zu verhindern, dass sie aus dem großen Kreis herausläuft. Je länger, desto besser! Schließlich können Sie Ihre eigenen Ergebnisse für das Ranking einreichen!

4. Im Spiel verwendete Technologie:

HTML, CSS, JavaScript, Canvas, PHP

5. Spieldesign-Ideen:

a) Zeichnen Sie die Hauptoberfläche des Spiels mit einem einfarbigen Rechteck, auf dem ein kleiner Kreis und eine Blende gezeichnet sind Kreis mit einer Größe von 1 Pixel in der Mitte der Schallwand (zur Implementierung der Kollisionserkennung).

b) Es gibt 8 Bewegungsrichtungen des kleinen Kreises, nämlich oben, unten, links, rechts, oben links, unten links, oben rechts und unten rechts.

c) Es gibt nur zwei Bewegungsrichtungen der Schallwand, im Uhrzeigersinn und gegen den Uhrzeigersinn.

d) Bei der Kollisionserkennung wird kein Motor verwendet, sondern der Abstand zwischen dem kleinen Kreis und dem superkleinen Kreis in der Mitte der Schallwand bestimmt, wodurch eine einfache Kollisionserkennung erreicht wird.

e) Bestimmen Sie die Richtung des Rückpralls des Balls nach der Kollision. Listen Sie mit gesundem Menschenverstand insgesamt 8 Situationen auf.

6. Schwierigkeiten bei der Spielumsetzung:

a) Kollisionserkennung.

b) Der Zeitpunkt des Löschens des Timer-SetIntervals und ob es klar und gründlich ist.

c) Die Beziehung zwischen der Länge des Timerzeitraums und dem Spielerlebnis.

d) Probleme mit der Spielflüssigkeit, die durch unterschiedliche Leistung zwischen Android- und IOS-Geräten verursacht werden.

7. Aktuelle Probleme im Spiel:

a) Da die Kollisionserkennung den Abstand zwischen den Mittelpunkten zweier Kreise vergleicht und einen Timer verwendet, sind aufgrund des extrem kurzen Timer-Intervalls tatsächlich Dutzende Kollisionen aufgetreten, die mit bloßem Auge sichtbar sind Dies führt dazu, dass die endgültige tatsächliche Abprallrichtung des Balls vom tatsächlichen physikalischen Theorem abweicht. Nach der Optimierung wurde die Wahrscheinlichkeit des Auftretens verringert, es ist jedoch immer noch unvermeidbar, dass der Ball die Barriere nicht berührt Genau, Die Mitte des Spielbretts kann dazu führen, dass das Spiel fehlschlägt.

b) Da die Funktion zu ausführlich ist, die Laufeffizienz gering ist und der Timer verwendet wird, unterscheidet sich das Spielerlebnis auf Andorid von dem auf iOS oder anderen mobilen Endgeräten (im Großen und Ganzen ist iOS besser als Android). .

c) Die Ranglisten werden nicht automatisch in Echtzeit aktualisiert. (Ich weiß noch nicht, wie ich die Datenbank verwenden soll)

8. Vorschau der Spieloberfläche:

(Bild 1 ist die erste Version, Bild 2 hat den Button entfernt, Bild 3 ist die finale Version, Bild 4 ist die Rangliste)

Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

Bild 1

Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

Bild 2

Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

Bild 3

Verwenden von JavaScript zur Umsetzung von Pongo-Designideen und Quellcode-Sharing_Javascript-Kenntnissen für Webversionen

9. Teil des JavaScript-Quellcodes des Spiels:

Code kopieren Der Code lautet wie folgt:

var ifingame=0;
var maxgrade=0,grade=0;
var grade1,grade2;
var Spitzname;
var gamespeed=1.4;//小球速度
var linespeed=Math.PI/95; //跟踪线速度
var crashdistancefaild=-7;//碰撞检测参数
var crashdistancesucc=15
var fantanjuli=7;   
var themaxgradeline=12.1;    
function getCookie1(nickname)
{
 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;
   return unescape(document.cookie.substring(c_start,c_end));
  }
 } 
 return ""
}
function 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));
  }
 } 
 return ""
}   
function setCookie( Nickname,value,mymaxgrade,maxgrade,expiredays)
{
 var exdate=new Date()
 exdate.setDate(exdate.getDate() expiredays)
 document.cookie=nickname "=" Escape (value) "," mymaxgrade "=" escape(maxgrade) ((expiredays==null) ? "" : "; läuft ab=" exdate.toGMTString());
}
function checkCookie()
{
 nickname=getCookie1('nickname');
    maxgrade=parseInt(getCookie2 ('mymaxgrade'));
       if(isNaN(maxgrade)==true)
       {
       maxgrade=0;
      }
 if (nickname!=null && Nickname!="" ). name=prompt ('请输入你的昵称:(名字太长上榜可是会显示不完整的哦)',"")
    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()
         /*    {
                 $grade=$_GET['max_grade'];
   $nickname=$_GET['nick_name'];
   $mail = new SaeMail();
   $ ret = $mail->quickSend( 'reasonpongo@163.com' , $grade , $nickname ,'reasonpongo@163.com' , 'mypongo' );
   $mail->clean();
   ?> 🎜>var gamedirection={
 shang : 1,
 xia  : 5,
 zuo  : 7,
 you  : 3,
 zuoshang: 8,
 zuoxia : 6,
 youshang: 2,
 youxia : 4,
 clock : 0,
 anticlock: 9,
 };//方向
var canvas={
 width : 300,
 height: 300,
 };//Canvas

var bigcircle = {//Großkreisparameter
x: 0, //x-Achsen-Koordinatenwert des Mittelpunkts des Kreises
y: 0, //y- Achsenkoordinatenwert des Mittelpunkts des Kreises
      r: 150, //Der Radius des Kreises
c: 'rgb(255,255,255)',
};//Großer Kreis
var smallcircle = {//Kleiner Kreisparameter
x: 0, / /Der x-Achsen-Koordinatenwert des Mittelpunkts des Kreises
y: 0, //Der y-Achsen-Koordinatenwert des Mittelpunkts des Kreises
r: 12, //Der Radius des Kreises
c: 'rgb(204,105,106)',
Direction : gamedirection.xia,
};//Kleiner Kreis

var line = {//Die Parameter der Pralllinie
x: 0, //Der x-Achsen-Koordinatenwert des Mittelpunkts des Kreises
y : 0, //Der y-Achsen-Koordinatenwert des Mittelpunkts von der Kreis
r: 150, //Der Radius des Bogens
start:(Math.PI/2-Math.PI/16),
end: (Math .PI/2 Math.PI/ 16),
c : 'rgb(55,55,55)',
Direction: gamedirection.anticlock,
};//Verfolgungslinie
var dot = {//Tracking-Punktparameter
x: (bigcircle.r*Math.cos(line.start Math.PI/16)),//Den großen Kreis als Ursprung nehmen
y: (bigcircle.r*Math. sin(line.start Math.PI/16)),
r : 1,
}//Tracking point
function changelinedirection()
{
if(line.direction==gamedirection .clock)
{
line.direction=gamedirection.anticlock;
}
else
{
line.direction=gamedirection.clock;
}
}

function getdistance(){
var distance=Math.sqrt((smallcircle.x)*(smallcircle.x ) (smallcircle.y )*(smallcircle.y ));
return distance;
}/ /Gib den quadratischen Abstand zwischen dem kleinen Ball und der Mitte des großen Kreises zurück getdistance()

Funktion ifgameover(){//Beurteile, ob es außerhalb der Grenzen liegt
if((getdistance() - bigcircle .r)>5 )
return true;
else
return false;
} //Bestimmen Sie, ob das Spiel vorbei ist ifgameover()
function ifcrash(){ //Kollisionserkennung
var dx = dot. x-smallcircle.x;
var dy = dot.y-smallcircle.y;
var dd=Math.sqrt(dx*dx dy*dy);
if (dd< crashdistancesucc)
return true;
else
return false;
}//Kollisionserkennung ifcrash()

function randomback()
{
var x=Math.floor(Math. random()*3);
switch (smallcircle.direction){
case gamedirection.shang:
{
switch (x)
{
Fall 0:
smallcircle .direction=gamedirection.xia;
smallcircle.y=smallcircle.y fantanjuli;
break;
Fall 1:
smallcircle.direction=gamedirection.zuoxia;
                                                   smallcircle.x=smallcircle. x-fantanjuli;
break;
Fall 2 :
smallcircle.direction=gamedirection.youxia;
smallcircle le.x=smallcircle.x fantanjuli;
smallcircle.y=smallcircle.y fantanjuli;
break;
default:
break;
} break;
}
    case gamedirection.xia:
    {
     switch (x)
     {
      case 0:
      smallcircle.direction=gamedirection.shang;
      smallcircle.y=smallcircle.y -fantanjuli;
      break;
      Fall 1:
      smallcircle.direction=gamedirection.zuoshang;
      smallcircle.x=smallcircle.x-fantanjuli;
      smallcircle.y=smallcircle.y-fantanjuli ;
      break;
      Fall 2:
      smallcircle.direction=gamedirection.youshang;
      smallcircle.x=smallcircle.x fantanjuli;
      smallcircle.y=smallcircle.y-fantanjuli;
      break;
      default:
      break;     
     } break;
    }
       case gamedirection.zuo:
    {
     switch (x)
     {
      case 0:
      smallcircle.direction=gamedirection. du;
      smallcircle.x=smallcircle.x fantanjuli;
      break;
      Smallcircle.direction=gamedirection.youshang;
      smallcircle.x=smallcircle.x. fantanjuli;
      kleiner Kreis .y=smallcircle.y-fantanjuli;
      break;
      Fall 2:
      smallcircle.direction=gamedirection.youxia;
      smallcircle.x=smallcircle.x fantanjuli;
      smallcircle.y= smallcircle.y fantanjuli;
      break;
      default:
      break;
     } break;
    }
    case gamedirection.you:
    {
     switch (x)
     {
      case 0:
      smallcircle.direction=gamedirection.zuo;
      smallcircle.x=smallcircle.x-fantanjuli;
      break;
      case. 1:
      smallcircle.direction =gamedirection.zuoxia;
      smallcircle.x=smallcircle.x-fantanjuli;
      smallcircle.y=smallcircle.y fantanjuli;
      break;
      Fall 2:
      smallcircle.direction=gamedirection. zuoshang;
      smallcircle.x=smallcircle.x-fantanjuli;
      smallcircle.y=smallcircle.y-fantanjuli;
      break;
      default:
      break;
     } break;

           kleiner Kreis .x = smallcircle.x fantanjuli;
      smallcircle.y = smallcircle.y fantanjuli; .y fantanjuli;
      break;
      case 2:
      smallcircle.direction=gamedirection.you;
      smallcircle.x=smallcircle.x. fantanjuli;
      break;
      default:
      Pause;
     } Pause;

    }
    case gamedirection.zuoxia:
    {
     switch (x)
     {
      case 0:
      smallcircle.direction=gamedirection.youshang;
      smallcircle.x=smallcircle. x fantanjuli;
      smallcircle.y=smallcircle.y-fantanjuli;
      break;
      case 1:
      smallcircle.direction=gamedirection.shang;
      smallcircle.y=smallcircle.y-fantanjuli;
      break;
      case 2:
      smallcircle.direction=gamedirection.you;
      smallcircle.x=smallcircle.x. fantanjuli;
      break;
      default:
      Pause;
     } break;

    }
  Spielrichtung. zuoxia;
      smallcircle.x=smallcircle.x-fantanjuli;
      smallcircle.y=smallcircle.y fantanjuli;
      break;
      Fall 1:
      smallcircle.direction=gamedirection.zuo;
      smallcircle.x=smallcircle.x-fantanjuli;
      break;
      Smallcircle.direction=gamedirection.xia;
      smallcircle.y=smallcircle.y. fantanjuli;
      Pause ;
      default:
      break;
     } break;

    }
    case gamedirection.youxia:
    {
     switch (x)
     {
Fall 0:
      smallcircle.direction=gamedirection.zuoshang;
      smallcircle.x=smallcircle.x-fantanjuli;
      smallcircle.y=smallcircle.y-fantanjuli;
      break;
      Fall 1 :
      smallcircle.direction=gamedirection.zuo;
      smallcircle.x=smallcircle.x-fantanjuli;
      break;
      Fall 2:
      smallcircle.direction=gamedirection.shang;
smallcircle.y=smallcircle.y-fantanjuli;
      break;
      default:
      break;
     } break;

    }
    default:
    {
brechen;  
    }
   } 
}//小球随机反向 randomback()
function smallcircledirection()
{
 switch (smallcircle.direction){    //小球随机反向移动
    case gamedirection.shang:
    {
     smallcircle.y=smallcircle.y-gamespeed;
     grade. ;
     if(grade>maxgrade)
     {
                        maxgrade=note ;
                      newrecoder();
                    }
     addone();
     break;
    }
    case gamedirection.xia:
    {
     smallcircle.y=smallcircle.y gamespeed;
     grade. ;
     if(grade>maxgrade)
     {
                       maxgrade=grade;
                     newrecoder();
                       {
     smallcircle.x=smallcircle.x-gamespeed ;
     grade ;
     if(grade>maxgrade)
     {
                      maxgrade=grade;
                    .  newrecoder();
                    }
     addone();
     break;
     🎜 >                   maxgrade= grade;
                      newrecoder();
                    }
     addone();
     break;
    }
  🎜>    {
     smallcircle.x=smallcircle. x-gamespeed*0.8;
     smallcircle.y=smallcircle.y-gamespeed*0.8;
     grade ;
     if(grade>maxgrade)
     {
                        maxgrade=grade;
                      newrecoder ();
                    0,8;
     smallcircle.y=smallcircle.y gamespeed*0.8;
     grade;
     if(grade>maxgrade)
     {
                     . maxgrade=grade;
                      newrecoder();
                    }
     addone();
     break;
    }
    case gamedirection.youshang:
    {
     smallcircle.x=smallcircle.x gamespeed*0.8;
     smallcircle.y=smallcircle.y-gamespeed*0.8;
     grade ;
     if (grade>maxgrade)
     {
                        maxgrade=grade;
                    newrecoder();
                   . }
     addone();
     break;
    }
    case gamedirection.youxia :
    {
     smallcircle.x=smallcircle.x gamespeed*0.8;
     smallcircle.y=smallcircle.y gamespeed*0.8;
     grade ;
     if(grade>maxgrade)
{
                       maxgrade=grade;
                     newrecoder();
                 . ;
    }
    default:
    {
     break;  
    }
   } 
}//小球移动 smallcircledirection()
/*画出底部圆*/
ctxpane.beginPath(); //大圆
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 = Linie .c;
ctxpane.arc(line.x, line.y, line.r, line.start, line.end,false);
ctxpane.Stroke();
ctxpane.closePath();
function 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();
 }
function newrecoder()
{
 ctxpane.beginPath();
 ctxpane.fillStyle="rgb(255,0,0)";
 ctxpane.font = "18px Papyrus";
 ctxpane.fillText("Neu!",58,80);
ctxpane.closePath();
 }
function addone()
{
 grade1=(grade/150).toFixed(1);
 grade2=(maxgrade/150).toFixed( 1);
 var say1="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();
}
function movetest(){

 if(ifgameover())
 {
        ifingame=0;
        if(maxgrade>parseInt(getCookie2('mymaxgrade'))))
  {
   setCookie('nickname',nickname ,'mymaxgrade',maxgrade.toString(),365);  
  } ;
   } 
ctxpane.clearRect(-150,-150,300,300); //清屏

ctxpane.beginPath(); //大圆
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.anticlock)         //跟踪逆顺时针
{
 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();//小圆
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 timer;
function startgame(){//开始游戏

    if(ifingame==0)
    {
        ifingame=1;
        grade=0;
        var xx=Math.floor(Math.random()*8);
/*      switch(xx)
        {
            case 0:
   smallcircle.direction=gamedirection.shang;
   break;
   case 1:
   smallcircle.direction=gamedirection.xia;
   break;
   case 2:
   smallcircle.direction=gamedirection.zuo;
   break;
   case 3:
   smallcircle.direction=gamedirection.you;
   break;
   Fall 4:
   smallcircle.direction=gamedirection.zuoshang;
   break;
   Fall 5:
   smallcircle.direction=gamedirection.zuoxia;
   break;
   Fall 6:
   smallcircle.direction=gamedirection.youshang;
   break;
   Fall 7:
   smallcircle.direction=gamedirection.youxia;
   break;
   default:
   break;
        } */
    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(movetest,10);
}
 }//开始游戏 startgame()  
    function opentop()
    {
        window.location="http://pongotop.sinaapp.com";
    }

10.写在最后

这纯属又是一个自娱自乐,写完后的第三天因为开始忙着投简历找实习就没空再管,扔到朋友圈让朋友玩去了.这一个月过去了再重新看这游戏, 感觉它不该就这样死掉, 本人没什么技术, 做得很拙略, 因此发出这篇文字希望能帮到一些对pongo感兴趣的朋友, 再者就是希望如果有这方面的高手看到了能够给予赐教,一切疑惑和赐教都欢迎给我留言,谢谢!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn