pixi 平鋪精靈 demo (二)

引言

上篇主要講述了 pixi 平鋪精靈的創(chuàng)建與使用及視差滾動,這篇主要講述的是基于上篇 demo 的優(yōu)化與新增的功能笼痹。


目錄

  1. 新增功能

    1.1 分數(shù)&&速度

    1.2 上方障礙

    1.3 碰撞檢測

    1.4 二段跳

    1.5 血量

    1.6 配樂

  2. setup代碼

  3. 總結(jié)

  4. 了解更多


1负懦、新增功能

1.1 分數(shù)&&速度

分數(shù)這里是偷了個小懶陪捷,這里是直接在 ticker 中做了個累加 1 的操作踩窖,想的是通過分數(shù)達到多少分,游戲整體速度會提升一個階段帜羊,當然也可以是避開障礙物獲得分數(shù)咒程,后續(xù)如果有金幣之類的可以做進一步的優(yōu)化。

app.ticker.add(() => {
  // 累加得分
  $('.score-ctn').text(`分數(shù):${score += 1}`);
  
  // 提升速度
  score > 10000 && score < 20000 && (speed = 11);
  score > 20000 && score < 30000 && (speed = 12);
  score > 30000 && score < 40000 && (speed = 13);
  score > 40000 && (speed = 14);

  // 無限滾動
  bgSpr.tilePosition.x -= 1;
  bgSpr.tilePosition.x %= PIXI.Loader.shared.resources['bg2_2'].texture.width;
  
  // 碰撞
  bump(role, monster) && (roleSmoothie.update = inverted.bind(this, 3));
});


1.2 上方障礙

上方障礙跟怪物是一樣的讼育,只不過位置不同帐姻,在做碰撞檢測的時候改變一下碰撞的反饋。setup() 新增代碼:

let column = new PIXI.Sprite(PIXI.Loader.shared.resources['column'].texture);

let columnSmoothie = null; // 上方障礙移動

column.position.set(7700, 0);

app.stage.addChild(column);

// 前景移動
columnSmoothie = new Smoothie({
  engine: PIXI,
  renderer: app.renderer,
  root: app.stage,
  update: translate.bind(this, column, speed)
});
columnSmoothie.start();


1.3 碰撞檢測

碰撞檢測這里與碰撞到陸地障礙物反饋不同窥淆,當碰撞到陸地障礙是直接扣除一點生命值卖宠,在碰撞到上方障礙物則不會直接扣除生命值,而是會隨著上方障礙物的移動把人物推出屏幕才會扣除生命值忧饭,這里與碰撞到陸地障礙不同的是上方障礙物不能直接穿過扛伍,后者可以穿過,但會直接扣除生命值词裤。

這里的碰撞檢測思路也比較簡單刺洒,陸地障礙物只要人物的 x,y 軸位置與障礙物的 x,y 軸相交則返回 true 相交的點需要注意的是現(xiàn)在精靈的中心點在正下方在做碰撞檢測點時候需要加上精靈的 width / 2 , 在做跳躍碰撞檢測的時候障礙物的 y 值則需要減去高度。 如果 x 軸減去障礙物 x 軸 大于等于 障礙物負的寬度的一半并且小于障礙物寬度的一半并且 y 值減去障礙物的 y 值減去障礙物的高度大于等于 20 則返回 true 吼砂。

由于精靈貼圖都是矩形的逆航,在跳躍的過程中可能會碰到貼圖多余的直角出現(xiàn)誤判,這里直接粗暴的減去了 20 按理來說大于等于 0 就算觸碰了渔肩。也可以做圓形碰撞檢測可以避免直角誤判因俐。

// 陸地障礙
function bottombump (spr1, spr2) {
  let spr1X = spr1.x + spr1.width / 2;
  let spr2Y = spr2.y - spr2.height;

  return spr1X - spr2.x <= spr2.width / 2 && spr1X - spr2.x >= -spr2.width / 2 && spr1.y -                   spr2Y >= 20? true: false;
}

// 上方障礙
function topbump (spr1, spr2) {
  return spr1.x - spr2.x < 30 && spr1.x - spr2.x > -30 && (spr1.y - spr1.height) - (spr2.y +                    spr2.height) <= 0? true: false;
}

效果預(yù)覽:

pixikp_1


1.4 二段跳

二段跳是在一段跳的起跳完成且下落幀前再次按跳躍鍵觸發(fā),其余期間無法觸發(fā)周偎,跳躍動畫配置在最上方定義好了

一段跳思路是預(yù)先定義好一個動畫幀下標從 0 開始抹剩,起跳完成至最高點是 4 幀圖片。判斷下標小于 4 并且起跳的高度不超過一定值情況下下標累加蓉坎,人物 y 軸遞減 在下標大于 4 時做 y 值遞增下落澳眷,在最后一幀時將下標復(fù)原至 0 切換奔跑狀態(tài)。

二段跳需要兩個變量做判斷蛉艾,一個用于記錄點擊跳躍次數(shù)钳踊,一個用于判斷是否二段跳,連續(xù)兩次跳躍人物剛好在一段跳下落前勿侯,這里設(shè)定第二段跳的高度要比一段跳的高度低拓瞪,在完成二段跳動作之后人物處于至高點,然后接入一段跳的第 5 幀動畫繼續(xù)做一段跳的下落動作助琐。

let roleSprJumpIndex = 0吴藻; // 一段跳動畫下標

// 跳躍
$('.jump').on('touchstart', (e) => {
  if (jumpNum < 2) { // 禁止多次跳躍
    if (!isJump) {
      roleSmoothie.update = jump.bind(this); // 一段跳
      isJump = true;
    } else {
      roleSmoothie.update = jump2.bind(this); // 二段跳
      isJump = false;
    }
  }
  jumpNum++;
})
// 一段跳
function jump () {
  role.texture = PIXI.Loader.shared.resources[config.jump[roleSprJumpIndex]].texture;
  // 起跳
  if (roleSprJumpIndex <= 4 && role.position.y > 285) {
    roleSprJumpIndex++;
    role.position.y -= 40;
    isAction = false;
  }
  // 下落
  if (roleSprJumpIndex > 4 ) {
    if (role.position.y < 465) {
      role.position.y += 35;
    }
    roleSprJumpIndex++;
    isAction = true;
  }
  // 落地
  if (roleSprJumpIndex > 8) {
    roleSprJumpIndex = 0;
    role.position.y = 465;
    isAction = true;
    jumpNum = 0; // 重置跳躍次數(shù)
    isJump = false;
    roleSmoothie.update = go.bind(this); // 奔跑狀態(tài)
  }
}

// 二段跳
function jump2(){
  role.texture = PIXI.Loader.shared.resources[config.jump2[roleSprJumpIndex2]].texture;
  if (roleSprJumpIndex2 < 6) {
    roleSprJumpIndex2++;
    role.position.y -= 15;
  } else {
    roleSprJumpIndex = 5;
    roleSprJumpIndex2 = 0;
    roleSmoothie.update = jump.bind(this);
  }
}

效果圖:


屏幕錄制2021-04-01下午10 (2)


<font id="catalog1_5">1.5 血量</font>

血量在每次碰撞是扣除一點,ticker 碰撞反饋新增代碼:

這里在被上方障礙物推出屏幕之后會被扣除一點血弓柱,人物直接復(fù)原到原來的位置沟堡,如果在推出屏幕前下滑躲過上方障礙物則人物 x 軸慢慢遞增到原來位置侧但。

// 陸地障礙物反饋
if (isBottomBump || isBottomBump2) {
  role.tint = 0xFFFF660;
  if (isBlood && bloodNum >= 0) {
    bloodArr[bloodNum].style.display = 'none';
    bloodNum--;
    isBlood = false;
  }
} else {
  role.tint = 0xFFFFFF;
  isBlood = true;
}

// 上方障礙物反饋
if (topBupm) {
  role.x = column.x - 30;
  if (role.x < -100) {
    bloodArr[bloodNum].style.display = 'none';
    role.x = 400;
    bloodNum--;
  }
}
// 遞增到原來位置
if (role.x < 400) {
  role.x = role.x + 1;
}

效果圖:

屏幕錄制2021-04-01下午9


1.6 配樂

網(wǎng)上找了兩個音效,一個背景音樂航罗,一個按鍵音效禀横,加上音效讓能體驗不那么平淡。

這里是用了一個 audio 的插件 howler.js 使用非常簡單:

// 背景音樂
let bgBgm = new Howl({
  src: './demo_bg.mp3',
  loop: true // 是否循環(huán)
});
bgBgm.play(); // 播放

// 按鈕音效
let btnBgm = new Howl({
  src: './demo2.mp3',
  loop: false
});

在按鈕事件觸發(fā)播放即可粥血。


2柏锄、setup 代碼

function setup () {
  // 背景
  let bgSpr = new PIXI.extras.TilingSprite(PIXI.Loader.shared.resources['bg'].texture, app.renderer.width, app.renderer.height);
  // 前景
  let bridge = new PIXI.extras.TilingSprite(PIXI.Loader.shared.resources['bridge'].texture, 1600, 437);
  // 人物
  let role = new PIXI.Sprite(PIXI.Loader.shared.resources['role'].texture);
  // 怪物
  let monster = new PIXI.Sprite(PIXI.Loader.shared.resources['monster'].texture);
  let monster2 = new PIXI.Sprite(PIXI.Loader.shared.resources['monster2'].texture);
  // 上方障礙物
  let column = new PIXI.Sprite(PIXI.Loader.shared.resources['column'].texture);

  let roleSmoothie = null; // 人物動畫
  let monsterSmoothie = null; // 怪物動畫
  let monster2Smoothie = null;
  let bridgeSmoothie = null; // 前景動畫
  let columnSmoothie = null; // 上方障礙物動畫

  let roleSprGoIndex = 0; // 走路動作圖片下標
  let roleSprRunIndex = 0; // 跑動作圖片下標
  let roleSprJumpIndex = 0; // 跳動作圖片下標
  let roleSprJumpIndex2 = 0;
  let roleSprInverIndex = 0; // 倒動作圖片下標

  let speed = 10; // 滾動速度
  
  let jumpNum = 0; // 跳躍次數(shù)
  let isJump = false; // 跳躍狀態(tài)
  
  let isBlood = true; 
  let bloodNum = 2; // 血量下標
  let bloodArr = $('.blood-ctn').children(); // 血量數(shù)組
  
  let score = 0; // 分數(shù)

  let isAction = true; // 動作狀態(tài)
  
  // 背景音樂
  let bgBgm = new Howl({
    src: './demo_bg.mp3',
    loop: true // 是否循環(huán)
  });
  bgBgm.play(); // 播放

  // 按鈕音效
  let btnBgm = new Howl({
    src: './demo2.mp3',
    loop: false
  });
  
  // 中心點
  role.anchor.set(0.5, 1);
  monster.anchor.set(0.5, 1);
  monster2.anchor.set(0.5, 1);

  // 縮放比例
  role.scale.set(1.5, 1.5);
  monster2.scale.set(0.9, 0.9);

  // 位置
  role.position.set(400, 465);
  monster.position.set(2000, 465);
  monster2.position.set(3200, 465);
  bridge.position.set(0, 440);
  column.position.set(7700, 0);

  // 添加到舞臺
  app.stage.addChild(bgSpr, bridge, role, monster, monster2, column);
  
  // 平移
  function translate (spr, num) {
    spr.tilePosition.x -= num;
    spr.tilePosition.x %= PIXI.Loader.shared.resources['prospect'].texture.width;
  };

  // 怪物移動
  function monsterTranslate (spr, num, x) {
    spr.position.x -= num;
    spr.position.x < -x && (spr.position.x = 1600);
  };
 
  // 跑
  function go () {
    role.texture = PIXI.Loader.shared.resources[config.go[roleSprGoIndex]].texture;
    roleSprGoIndex < 6? roleSprGoIndex++ : roleSprGoIndex = 0;
  };

  // 跳
  function jump () {
    role.texture = PIXI.Loader.shared.resources[config.jump[roleSprJumpIndex]].texture;
    if (roleSprJumpIndex <= 4 && role.position.y > 285) {
      roleSprJumpIndex++;
      role.position.y -= 40;
      isAction = false;
    }
    if (roleSprJumpIndex > 4 ) {
      if (role.position.y < 465) {
        role.position.y += 35;
      }
      roleSprJumpIndex++;
      isAction = true;
    }
    if (roleSprJumpIndex > 8) {
      roleSprJumpIndex = 0;
      role.position.y = 465;
      isAction = true;
      jumpNum = 0;
      isJump = false;
      roleSmoothie.update = go.bind(this);
    }
  }

  // 二段跳
  function jump2(){
    role.texture = PIXI.Loader.shared.resources[config.jump2[roleSprJumpIndex2]].texture;
    if (roleSprJumpIndex2 < 6) {
      roleSprJumpIndex2++;
      role.position.y -= 15;
    } else {
      roleSprJumpIndex = 5;
      roleSprJumpIndex2 = 0;
      roleSmoothie.update = jump.bind(this);
    }
  }

  // 滑
  function slip (num) {
    role.texture = PIXI.Loader.shared.resources['sprite4_0'].texture;
  }
  // 人物移動
  roleSmoothie = new Smoothie({
    engine: PIXI,
    renderer: app.renderer,
    root: app.stage,
    fps: 8,
    update: go.bind(this)
  });
  roleSmoothie.start();

  // 怪物移動
  monsterSmoothie = new Smoothie({
    engine: PIXI,
    renderer: app.renderer,
    root: app.stage,
    update: monsterTranslate.bind(this, monster, 7, 100)
  });
  monsterSmoothie.start();

  // 前景移動
  prospectSmoothie = new Smoothie({
    engine: PIXI,
    renderer: app.renderer,
    root: app.stage,
    update: translate.bind(this, prospectSpr, 3)
  });
  prospectSmoothie.start();
  
  // 柱子移動
  columnSmoothie = new Smoothie({
    engine: PIXI,
    renderer: app.renderer,
    root: app.stage,
    update: monsterTranslate.bind(this, column, speed)
  });
  columnSmoothie.start();

  // 跳躍事件
  $('.jump').on('touchstart', (e) => {
    if (jumpNum < 2) {
      if (!isJump) {
        roleSmoothie.update = jump.bind(this);
        isJump = true;
      } else {
        roleSmoothie.update = jump2.bind(this);
        isJump = false;
      }
    }
    jumpNum++;
    btnBgm.play();
  });
  
  // 下滑事件
  $('.slip').on('touchstart', (e) => {
    roleSmoothie.update = slip.bind(this);
    roleSprJumpIndex = 0;
    roleSprJumpIndex2 = 0;
    jumpNum = 0;
    isJump = false;
    
    btnBgm.play();
  });
  
  // 下滑結(jié)束
  $('.slip').on('touchend', (e) => {
    roleSmoothie.update = go.bind(this);
  });
  
  app.ticker.add(() => {
    $('.score-ctn').text(`分數(shù):${score += 1}`);

    // 提升速度
    score > 10000 && score < 20000 && (speed = 11);
    score > 20000 && score < 30000 && (speed = 12);
    score > 30000 && score < 40000 && (speed = 13);
    score > 40000 && (speed = 14);

    // 無限滾動
    bgSpr.tilePosition.x -= 1;
    bgSpr.tilePosition.x %= PIXI.Loader.shared.resources['bg2_2'].texture.width;

    isBottomBump = bottombump(role, monster);
    isBottomBump2 = bottombump(role, monster2);
    topBupm = topbump(role, column);

    // 怪物碰撞
    if (isBottomBump || isBottomBump2) {
      role.tint = 0xFFFF660;
      if (isBlood && bloodNum >= 0) {
        bloodArr[bloodNum].style.display = 'none';
        bloodNum--;
        isBlood = false;
      }
    } else {
      role.tint = 0xFFFFFF;
      isBlood = true;
    }

    // 柱子碰撞
    if (topBupm) {
      role.x = column.x - 30;
      if (role.x < -100) {
        bloodArr[bloodNum].style.display = 'none';
        role.x = 400;
        bloodNum--;
      }
    }

    if (role.x < 400) {
      role.x = role.x + 1;
    }
  })
  });
  
 // 怪物碰撞
  function bottombump (spr1, spr2) {
    let spr1X = spr1.x + spr1.width / 2;
    let spr2Y = spr2.y - spr2.height;

    return spr1X - spr2.x <= spr2.width / 2 && spr1X - spr2.x >= -spr2.width / 2 && spr1.y - spr2Y >= 20? true: false;
  }
  
  // 柱子碰撞
  function topbump (spr1, spr2) {
    return spr1.x - spr2.x < 30 && spr1.x - spr2.x > -30 && (spr1.y - spr1.height) - (spr2.y + spr2.height) <= 0? true: false;
  }

項目鏈接:demo


3、總結(jié)

這個 demo 目前看來雖然沒什么比較難的點复亏,但目前還只是屬于能跑起來趾娃,比較粗糙,很多細節(jié)還是需要優(yōu)化的缔御,當然再繼續(xù)往下做肯定會有挑戰(zhàn)的抬闷,比如目前怪物出現(xiàn)都是定死的,需要改成隨機出現(xiàn)耕突,并且柱子與怪物不能再一個 Y 軸上,還有新增像金幣眷茁、飛行、斷橋等一些進階的功能上祈。


4、了解更多

原文鏈接:pixi 平鋪精靈 demo (二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末登刺,一起剝皮案震驚了整個濱河市籽腕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖晤锥,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異矾瘾,居然都是意外死亡女轿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門壕翩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人放妈,你說我怎么就攤上這事荐操≌洳撸” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵攘宙,是天一觀的道長。 經(jīng)常有香客問我蹭劈,道長,這世上最難降的妖魔是什么多矮? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任祟蚀,我火速辦了婚禮,結(jié)果婚禮上前酿,老公的妹妹穿的比我還像新娘。我一直安慰自己罢维,他們只是感情好,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布匀借。 她就那樣靜靜地躺著平窘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瑰艘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天紫新,我揣著相機與錄音,去河邊找鬼芒率。 笑死,一個胖子當著我的面吹牛充择,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播聪铺,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撒桨!你這毒婦竟也來了键兜?” 一聲冷哼從身側(cè)響起凤类,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谜疤,失蹤者是張志新(化名)和其女友劉穎现诀,沒想到半個月后夷磕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仔沿,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡封锉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了成福。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡净当,死狀恐怖蕴潦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情品擎,我是刑警寧澤备徐,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布拓春,位于F島的核電站憔鬼,受9級特大地震影響蘸吓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赶么,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一脊串、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧放闺,春花似錦、人聲如沸怖侦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荷腊。三九已至,卻和暖如春很钓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背码倦。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工锭碳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擒抛。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像歹撒,于是被迫代替她去往敵國和親诊胞。 傳聞我的和親對象是個殘疾皇子暖夭,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355