<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          微信云開(kāi)發(fā)被釋放了,重新寫(xiě)了個(gè)足球游戲

          共 5193字,需瀏覽 11分鐘

           ·

          2022-11-14 09:37

          背景

          不停歇的球是在2019年年底開(kāi)發(fā)上線的,詳細(xì)的技術(shù)細(xì)節(jié)見(jiàn)下面這篇文章。

          為何你的彈球如絲般順滑?不停歇的球!技術(shù)分享!源碼相送!

          0e8ddfa5dcce07b38a7564d8163dfecc.webp

          其中微信小游戲的總排行榜和用戶數(shù)據(jù)的存儲(chǔ),采用的是微信云開(kāi)發(fā)中的云函數(shù)和數(shù)據(jù)庫(kù)。但是最近微信云收費(fèi)了,無(wú)法再進(jìn)行游戲了。

          fde0ebd527bf3cf56cb617d96523e34c.webp

          剛好最近有足球比賽,于是,在網(wǎng)上體驗(yàn)了一些足球相關(guān)的小游戲,找了其中的一款并復(fù)刻!重新上線!

          2aa592330497fea465a09a8c05db24d6.webp

          實(shí)現(xiàn)

          拿到的資源都是2d資源,采用的實(shí)現(xiàn)方式是用3D物理模擬,2D圖片同步展示。

          ee73ad854895854a29cee96aae03a8a9.webp

          序列幀動(dòng)畫(huà)

          動(dòng)畫(huà)圖是一張大圖,每幀動(dòng)畫(huà)按照同一大小從左至右,從上到下排列。

          d07c531e3687c0060085d277e2fe679e.webp

          于是寫(xiě)了個(gè)腳本分割這些圖片,和播放對(duì)應(yīng)的序列幀。

          9ce51787f5ff74d9d43cc4cdfd3d62be.webp

          核心邏輯就是拆分?spriteFrame?, 重新設(shè)置裁剪區(qū)域?spriteFrame.rect?,并更新uv。直接看下面的組件代碼吧。

              import { _decorator, Component, Node, Sprite, SpriteFrame, Rect, mat4 } from 'cc';
          const { ccclass, property, requireComponent } = _decorator;

          @ccclass('SpriteSheet')
          @requireComponent(Sprite)
          export class SpriteSheet extends Component {

          private _sprite: Sprite
          private _spriteFrame: SpriteFrame
          @property
          width: number = 0
          @property
          height: number = 0

          private _rect = new Rect()
          private _row = 0;
          private _col = 0;

          onLoad() {
          this._sprite = this.getComponent(Sprite);
          this._spriteFrame = this._sprite.spriteFrame.clone();
          this._sprite.spriteFrame = this._spriteFrame
          this._row = Math.floor(this._spriteFrame.height / this.height);
          this._col = Math.floor(this._spriteFrame.width / this.width);
          this.gotoAndStop(0)
          }

          gotoAndStop(frame: number) {
          const row = frame % this._col;
          const col = Math.floor(frame / this._col) % this._row;
          // console.log("gotoAndStop ", frame, row, col)
          this._rect.set(this.width * row, this.height * col, this.width, this.height);
          this._spriteFrame.rect = this._rect;
          this._sprite['_updateUVs']();
          }

          private _curFrame: number = -1
          private _frameStart: number = -1
          private _frameEnd: number = -1
          private _aniCb: Function
          play(frameStart: number, frameEnd: number, time: number, cb: Function, loop = false) {
          console.log("SpriteSheet play", frameStart, frameEnd)

          this._aniCb = cb
          const totalFrame = frameEnd - frameStart
          this._curFrame = frameStart
          this._frameEnd = frameEnd
          this.gotoAndStop(frameStart);
          this.unschedule(this.playAni)
          this.schedule(this.playAni, time / totalFrame, totalFrame)
          }

          private playAni() {
          this._curFrame++;
          this.gotoAndStop(this._curFrame);
          if (this._curFrame == this._frameEnd) {
          this._aniCb()
          }
          }

          }


          同步2D表現(xiàn)

          位置同步

          使用相機(jī)的視圖投影矩陣,算出3d物體的NDC坐標(biāo),然后再根據(jù)Canvas的大小與UI相對(duì)位置,算出2D的位置。

              convert3dPosTo2dScreen(worldPosition: Vec3) {
          const widthHalf = Setting.CANVAS_WIDTH_HALF
          const heightHalf = Setting.CANVAS_HEIGHT_HALF
          const vector = worldPosition.clone();
          const matViewProj = this.oCamera.camera.matViewProj
          Vec3.transformMat4(vector, vector, matViewProj);

          vector.x = (vector.x * widthHalf)
          vector.y = (vector.y * heightHalf)

          return vector;
          }

          NDC 坐標(biāo)是個(gè)正方體。

          • z坐標(biāo)在 -1~1 之間, 從小到大可理解為從前到后的映射

          • y坐標(biāo)在 -1~1 之間, 從小到大可理解為從下到上的映射

          • x坐標(biāo)在 -1~1 之間, 從小到大可理解為從左到右的映射

          26ae5ce24d0086dfe8975a9c5636551b.webp

          再來(lái)一張圖一起看看。

          208ab5a3d03f2055a0734672d9265773.webp

          為了更方便看清NDC坐標(biāo),這里寫(xiě)了個(gè)腳本實(shí)時(shí)查看節(jié)點(diǎn)的NDC坐標(biāo)。

              import { _decorator, Component, Node, Camera, NodeEventType, Vec4, Vec3 } from 'cc';
          const { ccclass, property, executeInEditMode } = _decorator;

          @ccclass('ShowNodeNDC')
          export class ShowNodeNDC extends Component {

          @property(Camera)
          camera: Camera = null!

          @property({ readonly: true, displayName: "NDC坐標(biāo)" })
          ndcPos: Vec3 = new Vec3()

          start() {
          this.node.on(NodeEventType.TRANSFORM_CHANGED, this.onTransformChange, this)
          this.onTransformChange()
          }

          private onTransformChange() {
          if (!this.camera) return
          this.ndcPos = this.node.worldPosition.clone();
          const matViewProj = this.camera.camera.matViewProj
          Vec3.transformMat4(this.ndcPos, this.ndcPos, matViewProj);
          }
          }

          發(fā)球前,NDC的Z值比較大

          1ed2bddec536bf6cfb3ee956290f559f.webp

          發(fā)射至左上角時(shí),觀察x,y,z坐標(biāo)

          b4ce87039c420a47520392e8cffdf2f6.webp

          發(fā)射右下角時(shí),觀察x,y,z坐標(biāo)

          1ea0b0e0f4e669e795cbfa379cd16aa1.webp

          為什么要用相機(jī)的視圖投影矩陣?主要是為了復(fù)習(xí)鞏固知識(shí)?997de8d1de843854c1f9213f90066458.webp

          當(dāng)然也可以用相機(jī)的方法去轉(zhuǎn)換坐標(biāo)

                      /**
          * @en Convert a world position to a screen space (left-top origin) position.
          * @zh 將一個(gè)世界空間坐標(biāo)轉(zhuǎn)換為屏幕空間(左上角為原點(diǎn))坐標(biāo)。
          * @param worldPos The position in world space coordinates
          * @param out The output position in screen space coordinates.
          * @returns Return the output position object.
          */

          worldToScreen(worldPos: math.Vec3 | Readonly<math.Vec3>, out?: math.Vec3): math.Vec3;

          縮放

          原理是相似三角形!

              this.oBall.scale(this.oCamera.near / cameradis * this.oBall.getStartScale)

          8bdd655de8701b68af4efc2e20b18df7.webp

          觸摸同步

          同步觸摸與手套的位置

          • 先同步剛體3d位置

          • 再同步2D的圖片位置

          因?yàn)槭痔自谕坏腪平面移動(dòng),所以可以先計(jì)算射線在z軸的方向上的距離,然后再算其他的軸。

          576a70b341a009e1c3fed21bf0be9576.webp

          詳細(xì)見(jiàn)代碼

                  private _ray: geometry.Ray = new geometry.Ray();
          onHandKeeper(event: EventTouch) {
          // 得出射線
          const touch = event.touch!;
          this.oCamera.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);

          // 手套的3d坐標(biāo)
          const oHandKeeperBody = this.oGloves.oPhysics;
          const oHandKeeperBodyPosition = oHandKeeperBody.node.worldPosition.clone();

          // 手套的z坐標(biāo)不變,算出射線與Z軸方向的距離
          const distance = -oHandKeeperBodyPosition.z + this._ray.o.z;
          const oMouse3D = new Vec3();
          Vec3.scaleAndAdd(oMouse3D, this._ray.o, this._ray.d, distance)
          oMouse3D.z = oHandKeeperBodyPosition.z

          oHandKeeperBody.node.setWorldPosition(oMouse3D);

          // 計(jì)算2d坐標(biāo)
          var oPos2D = this.convert3dPosTo2dScreen(oMouse3D);
          this.oGloves.setPosition(oPos2D.x, oPos2D.y);

          }
          小結(jié)

          在線體驗(yàn):微信搜【不停歇的球】
          510c363e28888c40f7c3e58f57e9c2cf.webp

          代碼地址:https://store.cocos.com/app/detail/4227

          點(diǎn)擊 閱讀原文”查看完成工程

          “點(diǎn)贊“ ”在看”?鼓勵(lì)一下997de8d1de843854c1f9213f90066458.webp

          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级精品一级 | 北,麻妃无码69Xx | 亚洲成人黄色视频 | 国产精品 aa | 操逼手机视频 |