pixi-老虎机实现

js

import cloud from '@tbmp/mp-cloud-sdk';
import * as PIXI from "@tbminiapp/pixi-miniprogram-engine";
const { registerCanvas, devicePixelRatio } = PIXI.miniprogram;

cloud.init({
  env: 'test'
});
const resource = require('./resource.json');//资源
let resourceCopy = JSON.parse(JSON.stringify(resource));//重置资源
let Application = PIXI.Application,
  Container = PIXI.Container,
  loader = PIXI.loader,
  Rectangle = PIXI.Rectangle,
  TextureCache = PIXI.utils.TextureCache,
  resources = PIXI.loader.resources,
  TilingSprite = PIXI.extras.TilingSprite,
  Sprite = PIXI.Sprite;
let application = null;//舞台
let gameTicker = null;//定时器
const reels = []; // 建立转盘
let REEL_WIDTH = 122;
let SYMBOL_SIZE = 143;
let running = false;
const tweening = [];
Component({
  app: null,
  pixiCanvas: null,
  stageSize: null,
  systemInfo: null,
  contextType: '2d',
  props: {
    options: {
      // 手动指定application的尺寸
      // 全屏-以窗口宽高作为application的尺寸,当设置此选项后,手动设置的width\height会失效
      isFullScreen: false,
      // application是否背景透明
      transparent: true,
      // 背景颜色
      backgroundColor: 0x111,
      // 是否强制用2d上下文渲染,如果为false,则优先使用webgl渲染
      forceCanvas: true
    }
  },
  data: {
    // 模块宽|高
    moduleWidth: 726,
    moduleHeight: 826,
    moduleBg: "https://img.alicdn.com/imgextra/i4/39767794/O1CN01AOvG4T27RhdblKAbL_!!39767794.png",//背景图片
    // 奖品数组
    prizeData: [
      {
        "prizeName": "优惠卷",
        "name": "prize_1",
        "url": "https://img.alicdn.com/imgextra/i3/39767794/O1CN010T3TJZ27RhdUnHn1p_!!39767794.png",
      },
      {
        "prizeName": "谢谢参与",
        "name": "prize_2",
        "url": "https://img.alicdn.com/imgextra/i2/39767794/O1CN013nYFLi27RhdZ4yi34_!!39767794.png",
      },
      {
        "prizeName": "会员积分",
        "name": "prize_3",
        "url": "https://img.alicdn.com/imgextra/i1/39767794/O1CN01f5FSOF27RhdYa7dxN_!!39767794.png",
      }
    ]
  },
  onInit() {
    this.turnNum = 5; // 抽奖转圈数(必须大于1)
    this.prevIndex = 0; // 上次摇到的编号
    this.rollIndex = 2; // 抽中的编号 +1红包 +2积分 +3手机 +4耳机
    this.prizeLes = this.data.prizeData.length;
    this.firstIndexArr = [0, 1, 2];//刚开始随机数组
    this.prevRIndexArr = [0, 0, 0]; // 上次摇到的随机数组
    // 奖品数组
    this.data.prizeData.map((item, index) => {
      resourceCopy.texture.push(item)
    });
    this.setData({
      resourceCopy: resourceCopy,
    });
  },
  didMount() {
    console.log("[Api-Test] didMount")
  },
  didUpdate() { },
  didUnmount() { },
  methods: {
    onCanvasReady() {
      // 建立canvas引用
      my.createCanvas({
        id: "canvas",
        success: (canvas) => {
          const { options } = this.props;
          if (!options) {
            console.warn('pixi-canvas 缺少options');
            this.props.onError && this.props.onError.call(this, { code: -1, msg: 'pixi-canvas 缺少options' });
            return;
          }
          this.pixiCanvas = canvas;
          const systemInfo = this.systemInfo || my.getSystemInfoSync();
          const { windowWidth } = systemInfo;
          const contextType = options.forceCanvas ? '2d' : 'webgl';
          const context = canvas.getContext(contextType);
          let baseSize = { width: this.data.moduleWidth, height: this.data.moduleWidth };
          const resolution = windowWidth / (baseSize.width / 2) * (devicePixelRatio / 2);
          options.resolution = resolution;
          options.width = baseSize.width;
          options.height = baseSize.height;
          registerCanvas(canvas);
          this.mainCanvas = canvas;
          this.app = new PIXI.Application({
            view: canvas,
            context: context,
            ...options
          });
          //  资源加载
          this.initLoad();
        },
      });
    },
    // 初始化加载
    initLoad() {
      loader
        .add(resourceCopy.texture)
        .on("progress", (event, resources) => {
          // this.progress(event.progress);
        })
        .load((event, resources) => {
          this.initConfig();
          this.app.ticker.add(delta => this.gameLoop(delta));
        });
    },
    // 初始化样式
    initConfig() {
      const { stage } = this.app;
      // 老虎机背景
      this.bgContainer = new Container();
      this.bgContainer.width = 589;
      this.bgContainer.height = 438;
      stage.addChild(this.bgContainer);
      // 中层
      this.middleContainer = new Container();
      stage.addChild(this.middleContainer);
      this.upperContainer = new Container();
      // 资源
      let slotTextures = [];
      Object.keys(resources).map((item) => {
        let sprite = new Sprite(resources[item].texture);
        if (item.includes('老虎机')) {
          this.addSprite(sprite, item, this.bgContainer, (this.data.moduleWidth - 589) / 2, 280);
        } else if (item.includes('左箭头')) {
          this.addSprite(sprite, item, this.upperContainer, 120, 520);
        } else if (item.includes('右箭头')) {
          this.addSprite(sprite, item, this.upperContainer, 556, 520);
        } else if (item.includes('prize')) {
          // this.addSprite(sprite, item, this.bgContainer, 0, 0);
          // 添加奖品纹理
          slotTextures.push(PIXI.Texture.fromFrame(item));
        }
        else if (item.includes('抽奖按钮')) {
          this.addSprite(sprite, item, this.upperContainer, (this.data.moduleWidth - 244) / 2, 630);
        }
      });
      // 滚动容器
      const reelContainer = new Container();
      reelContainer.width = 467;
      reelContainer.height = 260;
      reelContainer.position.x = (this.data.moduleWidth - 465) / 2;
      reelContainer.position.y = 310;
      // 滚动遮罩
      const thing = new PIXI.Graphics();
      stage.addChild(thing);
      thing.drawRoundedRect(0, 0, 467, 255, 20);
      thing.x = (this.data.moduleWidth - 430) / 2;
      thing.y = 406;
      reelContainer.mask = thing;
      for (let i = 0; i < 3; i++) {
        const rc = new PIXI.Container();
        rc.x = i * (REEL_WIDTH + 30) + 10;
        reelContainer.addChild(rc);
        const reel = {
          container: rc,
          symbols: [],
          position: 0,
          previousPosition: 0,
          blur: new PIXI.filters.BlurFilter(),
        };
        reel.blur.blurX = 0;
        reel.blur.blurY = 0;
        rc.filters = [reel.blur];

        // 建立symbol
        for (let j = 0; j < slotTextures.length; j++) {
          // 初始化位置
          let index = (this.firstIndexArr[i] + j) > (this.prizeLes - 1) ? ((this.firstIndexArr[i] + j) - (this.prizeLes)) : (this.firstIndexArr[i] + j);
          const symbol = new PIXI.Sprite(slotTextures[index]);
          // const symbol = new PIXI.Sprite(slotTextures[j]);
          // 缩放symbol以适合symbol区域。
          symbol.y = j * (SYMBOL_SIZE);
          symbol.scale.x = symbol.scale.y = Math.min(SYMBOL_SIZE / symbol.width, SYMBOL_SIZE / symbol.height);
          symbol.x = Math.round((SYMBOL_SIZE - symbol.width) / 2);
          reel.symbols.push(symbol);
          rc.addChild(symbol);
        }
        reels.push(reel);
      }
      stage.addChild(reelContainer);
      // 上层
      stage.addChild(this.upperContainer);
      this.upperContainer.interactive = true;
      this.upperContainer.buttonMode = true;
      this.upperContainer.on('pointerup', () => {
        if (running) return;
        // if (this.data.rollCount > 0) {
        //   this.startPlay();
        // } else {
        //   my.alert({ title: '抽奖次数不足' });
        // }
        this.startPlay();
      });
      // 
      this.app.ticker.add((delta) => {
        // Update the slots.
        for (let i = 0; i < reels.length; i++) {
          const r = reels[i];
          // Update blur filter y amount based on speed.
          // This would be better if calculated with time in mind also. Now blur depends on frame rate.
          r.blur.blurY = (r.position - r.previousPosition) * 8;
          r.previousPosition = r.position;

          // Update symbol positions on reel.
          for (let j = 0; j < r.symbols.length; j++) {
            const s = r.symbols[j];
            const prevy = s.y;
            s.y = ((r.position + j) % r.symbols.length) * (SYMBOL_SIZE + 10);
            if (s.y < 0 && prevy > SYMBOL_SIZE) {
              // 检测外部并交换纹理。
              // 随机添加
              // s.texture = slotTextures[Math.floor(Math.random() * slotTextures.length)];
              // 顺序添加
              s.texture = slotTextures[j];
              s.scale.x = s.scale.y = Math.min(SYMBOL_SIZE / s.texture.width, SYMBOL_SIZE / s.texture.height);
              s.x = Math.round((SYMBOL_SIZE - s.width) / 2);
            }
          }
        }
      });

    },
    // 开始
    startPlay() {
      if (running) return;
      running = true;
      this.rIndexArr = [0, 0, 1];
      for (let i = 0; i < reels.length; i++) {
        const r = reels[i];
        const extra = Math.floor(Math.random() * 3);
        const target = r.position + (this.prizeLes * this.turnNum) + this.rIndexArr[i] + this.firstIndexArr[i]+1 + (this.prizeLes - this.prevRIndexArr[i]);
        // const target = r.position + 10 + i * 5 + extra;
        const time = 2500 + i * 600;
        // const time = 2500 + i * 600 + extra * 600;
        this.tweenTo(r, 'position', target, time, this.backout(0.5), null, i === reels.length - 1 ? this.reelsComplete : null);
        this.prevRIndexArr[i] = this.rIndexArr[i] + this.firstIndexArr[i]+1;
      }
      this.prevIndex = this.rollIndex;
    },
    // 过渡结束
    reelsComplete() {
      running = false;
    },
    // 时间
    backout(amount) {
      return (t) => (--t * t * ((amount + 1) * t + amount) + 1);
    },
    tweenTo(object, property, target, time, easing, onchange, oncomplete) {
      const tween = {
        object,
        property,
        propertyBeginValue: object[property],
        target,
        easing,
        time,
        change: onchange,
        complete: oncomplete,
        start: Date.now(),
      };

      tweening.push(tween);
      return tween;
    },
    randomArr(max, min, len) {
      let rIndexArr = [];
      for (let i = 0; i < len; i++) {
        let rNum = Math.floor(Math.random() * max + min);
        if (rIndexArr.indexOf(rNum) == -1) {
          rIndexArr.push(rNum)
        } else {
          i--;
        }
      }
      return rIndexArr;
    },
    lerp(a1, a2, t) {
      return a1 * (1 - t) + a2 * t;
    },
    //添加精灵到容器
    addSprite(sprite, name, stage, x, y) {
      const { posConfig } = resourceCopy;
      this[name] = sprite;
      sprite.x = x;
      sprite.y = y;
      sprite.name = name;
      stage && stage.addChild(sprite);
    },
    // 游戏循环
    gameLoop(delta) {
      const now = Date.now();
      const remove = [];
      for (let i = 0; i < tweening.length; i++) {
        const t = tweening[i];
        const phase = Math.min(1, (now - t.start) / t.time);

        t.object[t.property] = this.lerp(t.propertyBeginValue, t.target, t.easing(phase));
        if (t.change) t.change(t);
        if (phase === 1) {
          t.object[t.property] = t.target;
          if (t.complete) t.complete(t);
          remove.push(t);
        }
      }
      for (let i = 0; i < remove.length; i++) {
        tweening.splice(tweening.indexOf(remove[i]), 1);
      }
    },
    // 点击触发
    onTouchHandle(event) {
      if (this.pixiCanvas && event.changedTouches && event.changedTouches.length) {
        this.pixiCanvas.dispatchEvent(event);
      }
    },
    // 云函数
    invokeHelloWord() {
      cloud.function.invoke('helloworld').then(res => {
        my.alert({
          content: res
        })
      })
    }
  },
});

axml

<view style="width:{{moduleWidth}}rpx;height:{{moduleHeight}}rpx;position:relative;margin:0rpx auto;">
  <!-- 背景图 -->
  <view style="width:{{moduleWidth}}rpx;height:{{moduleHeight}}rpx;">
    <image mode="scaleToFill" src="{{moduleBg}}" style="width:{{moduleWidth}}rpx;height:{{moduleHeight}}rpx;"/>
  </view>
  <!-- 老虎机 -->
  <view style="position:absolute;top:0rpx;left:0rpx;width:{{moduleWidth}}rpx;height:{{moduleHeight}}rpx;">
    <canvas id="canvas" style="width:{{moduleWidth}}rpx;height:{{moduleHeight}}rpx;" type="webgl" onTouchStart="onTouchHandle" onTouchEnd="onTouchHandle" onTouchMove="onTouchHandle" onTouchCancel="onTouchHandle" onReady="onCanvasReady"></canvas>
  </view>
</view>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值