iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 2
3

前言

整個路邊賭場最主要的還是遊戲,因此平台部分我們日後再來做,其實我已經大概寫過一些部分,大概已經有一個規劃的雛型。

初始化

以下為初始化遊戲部分的專案架構
內容是基本Typescript設定以及相關套件

2019-IT30-Game
│  .gitignore
│  index.html
│  package.json
│  README.md
│  tsconfig.json
│  webpack.config.js
├─assets
└─src
   App.ts

架構物件

再來我們思考一下我們src內的架構會是如何呢?我們依照自己的專案要進行Pixijs封裝,要如何封裝會比較優呢?

我們新增幾層資料夾以及相關class,這是src下的資料夾結構

└─src
    │ App.ts
    └─components
        └─elements
            Wrapper.ts
            WrapperType.ts

基礎物件介面

概念是,我們只要在畫面顯示的物件,基本都是Wrapper,擁有可以縮放、移動、放大等等自訂的方法,WrapperType為一些Wrapper會用到的引數型態。

import * as PIXI from "pixi.js"
import * as WrapperType from '@/components/elements/WrapperType'

export default interface Wrapper {
  /**
   * 座標
   */
  readonly x: number;
  readonly y: number

  /**
   * 大小
   */
  readonly width: number
  readonly height: number

  /**
   * 
   * @param animationOpt 動畫? 
   * @param x 位置
   * @param y 位置
   */

  setPosition(animationOpt: WrapperType.animationOpt, x: number, y: number): void
  /**
   * 設定長寬
   * @param animation 動畫?
   * @param width 寬度
   * @param height 高度
   */
  setSize(animation: boolean, width: number, height: number): void

  /**
   * 添加Container到此Wrapper內
   * @param child 要添加的
   */
  addChild(child: Wrapper): void

  /**
   * 添加Container到此Wrapper內
   * @param child 要添加的
   */
  addContainer(child: any): void

  /**
   * 取得pixi container
   */
  getContainer(): PIXI.Container

  /**
   * 縮放
   * @param animation boolean是否要使用動畫
   * @param scale_x x縮放
   * @param scale_y y縮放
   */
  setScale(animation: boolean, scale_x: number, scale_y: number): void

  /**
   * interactive
   * @param interactive 是否要可以互動
   */
  setInteractive(interactive: boolean): void

  /**
   * Rotation
   * @param animation boolean是否要使用動畫
   * @param rotation 旋轉角度
   */
  setRotation(animation: boolean, rotation: number): void

  /**
   * Alpha
   * @param animation boolean是否要使用動畫
   * @param alpha 透明度
   */
  setAlpha(animation: boolean, alpha: number): void

  /**
   * interactive
   */
  removeChildren(): void

  /**
   * 監聽此Container
   * @param event 監聽
   * @param listener 事件
   */
  on(event: string, listener: any): void

  /**
   * 統一各種手機PC方法
   * @param listener 監聽方法
   */
  onClick(listener: any): void

  /**
   * 統一各種手機PC方法
   * @param listener 監聽方法
   */
  onHover(listener: any): void
}

其中有getContainer或是addChild、addContainer,是因為物件跟物件之間如果要放置在對方內部,必須要直接放進對方的Pixijs container,因次需要一個口讓物件們互相取用,因此有時候還是會使用到Pixijs的操作。

基礎容器

這時我們基礎還需要甚麼呢?早些年我寫過Flash,可以有Group群組的概念,我想了想我應該日後也有群組的需求,但這種多物件互動下,一定會有z-index問題,但似乎是沒有z-index可以使用,決定層級是由addChild的順序,因此我們必須要有規劃的addChild。

於是新增兩個檔案

└─src
    │  App.ts
    └─components
        └─elements
              Wrapper.ts
              WrapperContainer.ts
              WrapperContainerCenter.ts
              WrapperType.ts

這兩個WrapperContainer、WrapperContainerCenter作用為何呢?
都是一種容器的概念,可以做為包裝Group的容器或是圖層概念的容器,用來裝更多的Wrapper物件。

WrapperContainerCenter是置中的容器,裝的物件在裡面setScale或是setRotation都會從中間轉動,那這怎麼做到的呢?就靠以下

this._centerContainer = new WrapperContainer()
this._centerContainer.getContainer().pivot.set(this._centerContainer.width / 2, this._centerContainer.height / 2)
this._centerContainer.setPosition({ animation: false }, this._centerContainer.width / 2, this._centerContainer.height / 2)

其實內部分有多包一個Wrapper把他的pivot移動到中心,再把他的position推到中心。

並且透過我們把各種方法,像是setScale要針對中心,就把setScale指定操作內部中心容器,如果像是setPosition,要是原始左上角的,就操作外部普通容器,這樣達到中間旋轉縮放等等。

基礎物件

再來進入我們基本的pixijs物件囉!

└─src
    │  App.ts
    └─components
        └─elements
            Animation.ts
            Sprite.ts
            Texture.ts
            Wrapper.ts
            WrapperContainer.ts
            WrapperContainerCenter.ts
            WrapperType.ts

新增Animation、Sprite、Texture
Animation:多張連續圖,藉此達成動畫效果。
Sprite:一堆圖壓在同一張圖上,會以對應大小位置找到圖,CSS Sprite就是這種概念。
Texture:單張大圖

Texture.ts

export default class Texture implements Wrapper {
  private _container: PIXI.Container
  /**
   * @param targetPath 要產生甚麼圖
   */
  constructor(targetPath: string) {
    let sprite = new PIXI.Sprite(PIXI.utils.TextureCache[targetPath])
    this._container = new PIXI.Container()
    this._container.addChild(sprite)
  }
  ...以下省略
  
  
  public setSize(animation: boolean, width: number, height: number) {
    if (animation) {
      TweenMax.to(this._container, 0.6, { width: width, height: height });
    } else {
      this._container.width = width
      this._container.height = height
    }
  }

  ...以下省略
}

以上為Texture使用constructor指定path來決定圖片,且搭配GSAP TweenMax達到漸變效果。
其他兩種差異不大,頂多為傳入參數不同。如果要看整個架構請至Repositories看囉!

結尾

其實這遊戲專案我已經重寫寫過兩三次,大意都差不多,但都在規劃上出了些問題,因沒考慮到某些狀況,而最後的資料websocket串接會是最麻煩的!

實際預覽發現頁面有夠難閱讀,建議直接看Github Repositories,直接看比較容易理解

連結

GSAP
Pixijs
Github Repositories


上一篇
DAY01 賭場情境概述、技術選用
下一篇
DAY03 產出Sprite圖、載入圖片
系列文
三十天路邊賭場上線了!30

尚未有邦友留言

立即登入留言