2022年1月3日 星期一

ᐇ Week17

 Week17

1.音效

根据week3的内容加上跳跃,bgm,以及死亡音效。

import ddf.minim.*;

Minim minim;

AudioPlayer bgm,jump,gameover;

在setup设定的部分加上以下程式码,可以载入三个档案。

minim = new Minim(this);

gameover = minim.loadFile("gameover.wav");

jump = minim.loadFile("jump.mp3");

bgm = minim.loadFile("bgm.mp3");

在keyPressed的函式中加入以下程式码,能够在跳跃时发出相对音效。

jump.rewind();

jump.play();

在死亡时bgm会暂停,且发出死亡音效。

bgm.pause();

gameover.play();


2.给板子加上上下移动的速度

hboardy[i]+=md[i];

if(hboardy[i]<110) md[i]=abs(md[i]);

if(hboardy[i]>260) md[i]=-abs(md[i]);

以上程式码能让给方块y方向的速度,且控制在110-260范围内,超过范围速度方向会变。

3.跳上板子后会跟着移动

if(onhBoard==true) usery+=md[hboardID];


3.贴图

PImage img1,img2,img3,img4,img5,img6,img7;

在setup部分载入图片

img1=loadImage("bg.jpg");

img2=loadImage("gg.png");

img3=loadImage("good.png");

img4=loadImage("bg2.jpg");

img5=loadImage("bg3.png");

img6=loadImage("start.jpg");

img7=loadImage("block.png");

最后在各个需要的地方贴上贴图

image(img6,0,0,600,400);

image(img1,0,0,600,400);


4.字型处理

PFont myFont;

载入正黑体

myFont = createFont("微軟正黑體",30);

最后用text指令完成输入


5.最终程式码

import ddf.minim.*;//音效

Minim minim;//音效

AudioPlayer bgm,jump,gameover;//音效及三个音档

PImage img1,img2,img3,img4,img5,img6,img7;//贴图图片

PFont myFont;//字型

float []badx,bubblex,bubbley,boardx,boardy,boardw,hboardx,hboardy,hboardw,trix,triy,rx,ry,md,mdt;

int now,score,now2;

int boardID=0;

int hboardID=0;

int rID=0;//部分变数

void setup(){

  size(600,400);

  myFont = createFont("微軟正黑體",30);//字型

  img1=loadImage("bg.jpg");//贴上的图片

  img2=loadImage("gg.png");

  img3=loadImage("good.png");

  img4=loadImage("bg2.jpg");

  img5=loadImage("bg3.png");

  img6=loadImage("start.jpg");

  img7=loadImage("block.png");

  minim = new Minim(this);

  gameover = minim.loadFile("gameover.wav");

  jump = minim.loadFile("jump.mp3");

  bgm = minim.loadFile("BGMG.mp3");//音效

  textSize(40);

  badx=new float[1200];//陷阱x

  badx[0]=350+250;

  for(int i=1;i<1200;i++){

    if(i%5==0 || i%8==0 || i%11==0) {badx[i]=badx[i-1]+random(200,300);}//不让陷阱太密集

    else {badx[i]=badx[i-1]+random(50,55);}

  }

  boardx=new float[200];//板子x

  boardx[0]=380+250;

  for(int i=1;i<200;i++){

    boardx[i]=boardx[i-1]+random(360,440);

  }

  boardy=new float[200];//板子y

  boardy[0]=260;

  for(int i=1;i<200;i++){

    if(boardy[i-1]>=270){boardy[i]=boardy[i-1]-20;}//防止板子太高或太低

    else if(boardy[i-1]<=230){boardy[i]=boardy[i-1]+20;}

    else boardy[i]=boardy[i-1]+random(-20,10);

  }

  boardw=new float[200];//板子宽度

  boardw[0]=140;

  for(int i=1;i<200;i++){

    boardw[i]=boardw[i-1]+random(-20,10);

    if(boardw[i-1]<=80){boardw[i]=boardw[i-1]+30;}

  }

  hboardx=new float[190];//更高的板子x

  //hboardx[0]=boardx[2]+160;

  for(int i=0;i<190;i++){

    //hboardx[i]=hboardx[i-1]+random(300,380);

    hboardx[i]=boardx[i+2]+random(200,210);

  }

  trix=new float[360];//板子底下带的陷阱

  for(int i=0;i<360;i++){

   if(i%2==0) trix[i]=hboardx[i/2]+50;

   else trix[i]=hboardx[(i-1)/2]+50+50;

  }

  hboardy=new float[190];//更高的板子y

  hboardy[0]=150;

  for(int i=1;i<190;i++){

    if(hboardy[i-1]>=170){hboardy[i]=hboardy[i-1]-20;}

    else if(hboardy[i-1]<=120){hboardy[i]=hboardy[i-1]+20;}

    else hboardy[i]=hboardy[i-1]+random(-20,10);

  }

  triy=new float[360];//板子下的陷阱y

  triy[0]=150+20;

  for(int i=1;i<360;i++){

   if(i%2==0) triy[i]=hboardy[i/2]+20;//贴近板子

   else triy[i]=hboardy[(i-1)/2]+20;

  }

  hboardw=new float[190];//更高的板子宽度

  hboardw[0]=150;

  for(int i=1;i<190;i++){

    hboardw[i]=hboardw[i-1];

  }

  rx=new float[180];//距离较远时会出现的小板子x

  for(int i=0;i<180;i++){

    rx[i]=boardx[i+8]+boardw[i+8]+10;

  }

  ry=new float[280];//距离较远时会出现的小板子y

  for(int i=0;i<280;i++){

    ry[i]=170;

  }

  md=new float[190];//板子上下移动的速度

  for(int i=0;i<190;i++){

    md[i]=random(0.3,0.6);

  }

  mdt=new float[360];//陷阱上下移动的速度

  for(int i=0;i<360;i++){

    mdt[i]=(md[i/2]/0.4001)*0.1335;

  }

  bubblex=new float[10];//方块身后气泡

  bubbley=new float[10];

  for(int i=0;i<10;i++){

    bubblex[i]=0;

    bubbley[i]=300;

  }

  

}

float usery=300, vy=0, bgx=0, speed=0;

//md=0.4001,mdt=0.1335;

boolean gameOver=false;

boolean onBoard=false;

boolean onhBoard=false;

boolean onr=false;

int condition=0;

int wait=0;

void mousePressed(){///場景切換

  if (mouseButton == LEFT) condition=1;

}

void draw(){

  if(condition==0){//初始画面

    image(img6,0,0,600,400);

    fill(255);

    text("按下滑鼠左鍵開始遊戲",150,50);

    text("上鍵跳躍 下鍵無敵",170,350);

    textFont(myFont);

    wait=millis()/1000;

  }

  if(condition==1){

    if(gameOver && hacking==false) bgm.pause();//游戏结束则bgm暂停

    else bgm.play();//否则正常播放

    if(score>=0 && score<30) image(img1,0,0,600,400);//到一定阶段会更换背景

    if(score>=20 && score<40) image(img4,0,0,600,400);

    if(score>=40) image(img5,0,0,600,400);

    

    speed=(score/4)*0.3;//速度会随分数增加而增加

    bgx=bgx+3.3+speed;

    fill(#F5ADCF);

    for(int i=0;i<1200;i++){

      now=i;

      if(collision()) gameOver=true;//碰到陷阱则游戏结束

      triangle(badx[i]-bgx,310,badx[i]-25-bgx,350,badx[i]+25-bgx,350);

  }

    fill(#F5ADCF);

    for(int i=0;i<360;i++){

      now2=i;

      if(collision2()) gameOver=true;

      triangle(trix[i]+25-bgx,(triy[i]+=mdt[i])+40,trix[i]-bgx,triy[i]+=mdt[i],trix[i]+50-bgx,triy[i]+=mdt[i]);

      if(triy[i]<130) mdt[i]=abs(mdt[i]);//控制陷阱在一定范围内

      if(triy[i]>280) mdt[i]=-abs(mdt[i]);

    }

    fill(#003E6C); rect(0,350,600,400);//地板

    fill(#FFEC17);

    image(img7,150,usery,50,50);//玩家角色以及贴图

    if(jumping){//跳跃改变y以及加速度

      usery+=vy;

      vy+=0.98/2.5;

      if(usery>300){//停留在地上

        jumping=false;

        usery=300;

      }

    }

    fill(#AD0051);

    for(int i=0;i<200;i++){

      rect(boardx[i]-bgx,boardy[i],boardw[i],20);

      if(boardID==i){

        if(onBoard==true && (boardx[i]+boardw[i]<150+bgx) ){

          onBoard=false;jumping=true;

        }

      }

      if(jumping && usery+50<boardy[i] && usery+50+vy>boardy[i] && boardx[i]<150+50+bgx && 150+bgx<boardx[i]+boardw[i]){

        usery=boardy[i]-50;vy=0;jumping=false;onBoard=true;boardID=i;//方块停留在板子上

      }

    }

    fill(#AD0051);

    for(int i=0;i<190;i++){

      hboardy[i]+=md[i];//让板子上下移动

      rect(hboardx[i]-bgx,hboardy[i],hboardw[i],20);

      if(hboardy[i]<110) md[i]=abs(md[i]);

      if(hboardy[i]>260) md[i]=-abs(md[i]);//限制板子移动在一个范围内

      if(hboardID==i){

        if(onhBoard==true && (hboardx[i]+hboardw[i]<150+bgx) ){

          onhBoard=false;jumping=true;

        }

      }

      if(jumping && usery+50<hboardy[i] && usery+50+vy>hboardy[i] && hboardx[i]<150+50+bgx && 150+bgx<hboardx[i]+hboardw[i]){

        usery=hboardy[i]-50;vy=0;jumping=false;onhBoard=true;hboardID=i;

      }

    }

    if(onhBoard==true) usery+=md[hboardID];//角色能跟着板子上下移动

    fill(#AD0051);

    for(int i=0;i<180;i++){//在小板子上

      rect(rx[i]-bgx,ry[i],70,20);

      if(rID==i){

        if(onr==true && (rx[i]+70<150+bgx) ){

          onr=false;jumping=true;

        }

      }

      if(jumping && usery+50<ry[i] && usery+50+vy>ry[i] && rx[i]<150+50+bgx && 150+bgx<rx[i]+70){

        usery=ry[i]-50;vy=0;jumping=false;onr=true;rID=i;

      }

    }

    for(int i=9;i>0;i--){//身后的气泡

      bubblex[i]=bubblex[i-1];

      bubbley[i]=bubbley[i-1];

      fill(#FFF586);

      rect(bubblex[i]+150-bgx,bubbley[i]+40,10,10);

    }

    bubblex[0]=bgx;

    bubbley[0]=usery;

    if(hacking){//下键无敌

      fill(255,0,0);

      text("作弊中",150,100);

    }

    if(gameOver==false || hacking){//计分方式

    score=millis()/1000-wait;

    if(score<20) text("分數: "+score+"分  你好菜",150,50);

    else if(score<40) text("分數: "+score+"分  還不錯",150,50);

    else if(score>=40) text("分數: "+score+"分  不可思議",150,50);

    }

    else if(gameOver && hacking==false){//死亡及结束画面

      gameover.play();

      background(255);

      image(img2,0,0,600,350);

      fill(255,0,0);

      if(score<20) text("評價:你好菜",220,50);

      else if(score<40) text("評價:還不錯",220,50);

      else if(score>=40) text("評價:不可思議",220,50);

      text("最終得分: "+score+"分",200,350);

    }

  }

}

boolean jumping=false;

boolean hacking=false;

void keyPressed(){//下键开启无敌

  if(keyCode==DOWN){

    if(hacking==false){

      hacking=true;

    }

  }

  if(keyCode==UP){//上键跳跃

    jump.rewind();

    jump.play();//跳跃音效

    if(jumping==false){

      jumping=true;

      vy=-10;

    }

  }

}

boolean collision(){//前几周做的碰撞侦测

   boolean b1=insideTriangle(150,usery);

   boolean b2=insideTriangle(200,usery);

   boolean b3=insideTriangle(200,usery+50);

   boolean b4=insideTriangle(150,usery+50);

   if(b1 || b2 || b3 || b4) return true;

   else return false;

}

boolean insideTriangle(float x,float y){

    float c1=cross(x,y,badx[now]-bgx,310,badx[now]-25-bgx,350);

    float c2=cross(x,y,badx[now]-25-bgx,350,badx[now]+25-bgx,350);

    float c3=cross(x,y,badx[now]+25-bgx,350,badx[now]-bgx,310);

    if(c1>=0 && c2>=0 && c3>=0) return true;

    else return false;

}

boolean collision2(){

   boolean t1=insideTriangle2(150,usery);

   boolean t2=insideTriangle2(200,usery);

   boolean t3=insideTriangle2(200,usery+50);

   boolean t4=insideTriangle2(150,usery+50);

   if(t1 || t2 || t3 || t4) return true;

   else return false;

}

boolean insideTriangle2(float x,float y){

    float tc1=cross(x,y,trix[now2]+25-bgx,triy[now2]+40,trix[now2]-bgx,triy[now2]);

    float tc2=cross(x,y,trix[now2]-bgx,triy[now2],trix[now2]+50-bgx,triy[now2]);

    float tc3=cross(x,y,trix[now2]+50-bgx,triy[now2],trix[now2]+25-bgx,triy[now2]+40);

    if(tc1<=0 && tc2<=0 && tc3<=0) return true;

    else return false;

}

float cross(float xp,float yp,float x0,float y0,float x1,float y1){

  return (xp-x0)*(y1-y0)-(yp-y0)*(x1-x0);

}


4.游戏说明

其他组员意见:

聆聽輕快的音樂再搭配上緊張刺激的跑酷遊戲!

Geometry Dash是我很喜歡玩的遊戲

每次死掉重來都令人懊惱但又激發了玩家不服輸的性格

雖然我們的重製沒能做出像原作般與音樂的完美契合

但緊張刺激的跑酷部分還是有還原到

也搭配上原作的首關音樂

希望可以讓更多人認識這款遊戲

游戏操作:

上鍵跳跃

下鍵作弊模式(不死)


每20分換背景與更新評價 40分封頂

隨著遊戲進行速度會越來越快


遊戲影片:https://youtu.be/OqANg5hwqAw

前面是正常遊玩 後半部作弊模式看40分以上

用时半个月,每周做一点,前几周做大致的框架和基本的程式码,最后一周做细节的修改,总共用时大约1-2天。

沒有留言:

張貼留言