uni-app中使用pixijs绘制兼容H5和微信小程序大转盘游戏

javascript 复制代码
<template>
	<view class="content">
        <!-- #ifdef MP-WEIXIN -->
		<canvas type="webgl" @touchstart="touchEvent" @touchmove="touchEvent" @touchend="touchEvent" @touchcancel="touchEvent" id="croplandCanvas" class="cropland_canvas"></canvas>
        <!-- #endif -->
        <!-- #ifdef H5 -->
        <div ref="game"></div>
        <!-- #endif -->
        <div @click="reset">重置转盘数据</div>
    </view>
</template>

<script>
//#ifdef MP-WEIXIN 
import {
    createPIXI
} from "@/libs/pixi.miniprogram";
const unsafeEval = require("@/libs/unsafeEval");
const installSpine = require("@/libs/pixi-spine");
const installAnimate = require("@/libs/pixi-animate");
//#endif 
//#ifdef H5 
import * as PIXI from 'pixi.js'
//#endif 
import {detailRes,getP} from './data';
let detailData=JSON.parse(detailRes.content);//游戏活动
let zpbg='https://*****/test/material/20231206/TZBz2gpN.png';//大转盘背景图片
let lipin='https://***/test/material/20231206/KuHdLruy.png';//礼品图片
let btn='https://****/test/material/20231206/1tuBp4zX.png';//按钮图片
let imgbg='https://***/test/material/20231206/n3bf2zW4.jpg';//背景图片
let successPri=JSON.parse(getP.content);//获奖信息

//#ifdef MP-WEIXIN 
var PIXI={};
// let selfThis;
let canvasObj;
let animationFrame;
//#endif 

var app ={}
var info = wx.getSystemInfoSync();
var sw = info.screenWidth;//获取屏幕宽高
var sh = info.windowHeight;//获取屏幕宽高
var ratio=info.devicePixelRatio;
var devicePixelRatio=sw/375;
let zIndex=20;
console.log(devicePixelRatio,"===devicePixelRatio")

//#ifdef H5 
app = new PIXI.Application({
    backgroundAlpha: 0 ,
	antialias: true,
    autoDensity:true,
    width:sw,
    height:sh,
    resolution:info.devicePixelRatio,
});
//#endif 

/* 创建container */
let containerObj={
    container:{} ,
    container2:{} ,
    container3:{} ,
    container4:{} ,
}
function createContainerCom(
    con,
    x=app.screen.width / 2,
    y=app.screen.height / 2
){
    containerObj[con] = new PIXI.Container();
    containerObj[con].x = x;
    containerObj[con].y = y;
	containerObj[con].sortableChildren =true;
    //#ifdef H5
    app.stage.addChild(containerObj[con]);
    //#endif  
}

/* 创建背景 */
function createBg(){
    // 创建背景精灵
    const background = PIXI.Sprite.from(imgbg);
    // 将背景精灵添加到舞台上
    containerObj['container2'].addChild(background);
    // 设置背景图片的宽高
    background.width = sw;
    background.height = sh;
}
/* 创建转盘 */
function createZp(){ 
    const zpbgAprite = PIXI.Sprite.from(zpbg);
    containerObj['container3'].addChild(zpbgAprite);
    zpbgAprite.anchor.set(0.5);
    zpbgAprite.x = 0;
    zpbgAprite.y = 0;
    let ratio=(devicePixelRatio/2);
    zpbgAprite.scale.x=ratio;
    zpbgAprite.scale.y=ratio;
    zpbgAprite.zIndex=zIndex;
}
/* 转盘转动数据 */
let acceleration = 0.01; // 加速度
let speed=0.1;//初始速度
let playStart=false;//转盘是否转动
let angleSuccess=0;//转动角度
/* 重置转盘数据 */
function reset(){
    acceleration = 0.01; // 加速度
    speed=0.1;
    playStart=false;
    angleSuccess=0;
    containerObj.container.angle =0;
}
/* 放置按钮图片 */
function createBtn(){
    const btnAprite = PIXI.Sprite.from(btn);
    btnAprite.interactive = true; // 启用交互
    btnAprite.eventMode  = 'static';
    btnAprite.anchor.set(0.5);
    containerObj['container4'].addChild(btnAprite);
    btnAprite.x =0;// sw / 2;
    btnAprite.y = 0;//sh / 2 -8*1/devicePixelRatio;
    console.log(btnAprite,"====btnAprite")
    let scale=(devicePixelRatio/2);
    btnAprite.scale.x=scale;
    btnAprite.scale.y=scale;
    btnAprite.zIndex=5000;
    btnAprite.on('tap',function(event){//手机端用tap,pc用click
        console.log("按钮点击事件")
        if(playStart){
            return;
        }
        event.stopPropagation(); // 阻止事件继续冒泡
        let findIndex=detailData.prizes.findIndex((item)=>item.id==successPri.prizeId);
        let angle=(Math.PI * 2)/detailData.prizes.length;
        //转6圈
        angleSuccess=360*6-(findIndex*angle*180/Math.PI+90+angle*90/Math.PI);
        console.log(app,"====appp")
        // #ifdef H5
        app.ticker.add(animate2);
        //#endif
        //#ifdef MP-WEIXIN
        function test(){
            animate2();
            animationFrame=canvasObj.requestAnimationFrame(test);
            app.render(containerObj.container2);
        }
        test()
        //#endif

	})
}
/* 转动 */
let mxSpeed=0;
function animate2() {   
    // 可选:当速度达到一定阈值时,减小加速度,实现变速效果
    if (containerObj.container.angle>(angleSuccess/2)) {
        mxSpeed=speed>mxSpeed?speed:mxSpeed;
        acceleration = -0.015;
        if(speed<mxSpeed/1.5){
            acceleration=-0.007
        }
    } 
    if (speed <= 0.01&&acceleration<0) {
        acceleration = 0;
        speed=0.01
    }
    speed=speed+acceleration;
    if((containerObj.container.angle+speed)>angleSuccess){
        playStart=false;
        //#ifdef MP-WEIXIN
        animationFrame && canvasObj.cancelAnimationFrame(animationFrame);
        //#endif
        //#ifdef H5
        app.ticker.remove(animate2);
        //#endif
        return;
    }
    containerObj.container.angle += speed;
}
/* 创建奖项 */
let startAngle=0,endAngle=0;
function createPrizes(){
    let prizes=detailData.prizes;
    let angle=(Math.PI * 2)/prizes.length;//弧度
    prizes.map((item,index)=>{
        if(index<10){
        let name=item.name;
        let pic=item.pic;
        let id=item.id;

        startAngle = endAngle;
        endAngle = startAngle + angle;

        //扇形背景
        let ctx = new PIXI.Graphics();
        let color=(index%2===0)?'0xFFF4D6':'0xFFFFFF';
        ctx.beginFill(color);
        console.log(280*(devicePixelRatio/2))
        ctx.arc(0, 0, 280*(devicePixelRatio/2),  startAngle, endAngle);
        ctx.lineTo(0, 0);
        ctx.endFill();
        containerObj.container.addChild(ctx);
        ctx.zIndex=20+index;

        //文字
        const text = new PIXI.Text(name, {
            fontFamily: 'Arial',
            fontSize: 14,
            fill:0xE5302F,
            autoDensity:true,
            antialias:true
        });
        text.anchor.set(0.5);
        text.angle=(180*((angle/2)+startAngle))/ Math.PI+90;//文字旋转角度
        containerObj.container.addChild(text);
        text.zIndex=2*zIndex+index;//文字层级
        //文字位置
		let centerX = (200*(devicePixelRatio/2)) * Math.cos(((endAngle-startAngle)/2)+startAngle);
		let centerY = (200*(devicePixelRatio/2)) * Math.sin( ((endAngle-startAngle)/2)+startAngle);
        text.x=centerX;
        text.y=centerY;

        //礼物图片
        const liwuAprite = PIXI.Sprite.from(lipin);
        containerObj.container.addChild(liwuAprite);
        liwuAprite.anchor.set(0.5);
        liwuAprite.angle=(180*((angle/2)+startAngle))/ Math.PI+90
        let liwuX = (240*(devicePixelRatio/2)) * Math.cos((angle/2)+startAngle);
		let liwuY = (240*(devicePixelRatio/2)) * Math.sin( (angle/2)+startAngle);
        liwuAprite.x = liwuX;
        liwuAprite.y = liwuY;
        liwuAprite.scale.x=devicePixelRatio/2.5;
        liwuAprite.scale.y=devicePixelRatio/2.5;
        liwuAprite.zIndex=3*zIndex+index;
    }
    })

}

export default {
    methods:{
        //#ifdef MP-WEIXIN
        initMp(){
            // 获取 canvas
			wx.createSelectorQuery().select('#croplandCanvas').fields({
				node: true,
				size: true
			}).exec((res) => {
                const canvas = res[0].node;
                canvasObj=canvas;
                // canvasInstance = canvas;
                // 设置canvas实际宽高
                canvas.width = sw/ratio;
                canvas.height = sh/ratio;
				// PIXI 初始化 -----start
				PIXI = createPIXI(canvas, sw)

				unsafeEval(PIXI); //适配PIXI里面使用的eval函数
				installSpine(PIXI); //注入Spine库
				installAnimate(PIXI); //注入Animate库

				// 通过view把小程序的canvas传入
				app = PIXI.autoDetectRenderer({
					width: sw,
					height: sh,
					'view': canvas,
					antialias: true,
                    autoDensity:true,
                    resolution:ratio,
                    backgroundAlpha:0
				});
                createContainerCom('container2',0,0);
                createContainerCom('container3')
                createContainerCom('container',sw / 2,sh / 2 -8*1/devicePixelRatio)
                createContainerCom('container4')
                createBg();
                createZp();
                createPrizes();
                createBtn();
                containerObj.container2.addChild(containerObj.container3);
                containerObj.container2.addChild(containerObj.container);
                containerObj.container2.addChild(containerObj.container4);
                function animate() {
                    canvas.requestAnimationFrame(animate);
                    app.render(containerObj.container2);
                }
                animate();
            })
        },
        //#endif
        //#ifdef H5
        initH5(){
            this.$nextTick(()=>{
                //开始
                this.$refs.game.appendChild(app.view);
                createContainerCom('container2',0,0)
                createContainerCom('container3')
                createContainerCom('container',sw / 2,sh / 2 -8*1/devicePixelRatio)
                createContainerCom('container4')
                createBg();
                createZp();
                createPrizes();
                createBtn();
            })
        },
        //#endif
        //#ifdef MP-WEIXIN
        // 小程序事件绑定至pixi
		touchEvent(e) {
			PIXI.dispatchEvent(e)
		},
        //#endif
        /* 重置转盘数据 */
        reset(){
            acceleration = 0.01; // 加速度
            speed=0.1;
            playStart=false;
            angleSuccess=0;
            containerObj.container.angle =0;
        }
    },
    mounted(){
        //#ifdef MP-WEIXIN
        this.initMp();
        //#endif
        //#ifdef H5
        this.initH5();
        //#endif
        // selfThis=this;
    }
}

</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin: 200rpx auto 50rpx auto;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
	 #croplandCanvas{width:100vw;height:100vh;background:#fff;}
	/*#canvs2d{position:absolute;left:-10000px;top:-10000px;width:16px;height:16px;} */
</style>
javascript 复制代码
import {
    createPIXI
} from "@/libs/pixi.miniprogram";
const unsafeEval = require("@/libs/unsafeEval");
const installSpine = require("@/libs/pixi-spine");
const installAnimate = require("@/libs/pixi-animate");

上边的文件是使用的pixi-miniprogram

GitHub - skyfish-qc/pixi-miniprogram: 一个可运行于微信小程序的PIXI引擎,通过模拟window环境,有些功能小程序无法模拟,就直接修改了PIXI引擎代码,最终使得PIXI引擎正常运行在小程序上

代码中的data.js为mock数据如下

javascript 复制代码
export let detailRes={"code":"200","content":"{\"backGroundImg\":\"/pic/20231121/170054609830040B1RH7N_1700546098300_associationbg.jpg\",\"backGroundMusic\":\"/pic/20210202/16122355616909ZTQMPFK_1612235561690_抽奖背景音乐.mp3\",\"days\":null,\"description\":\"游戏说明\",\"endDate\":\"2024-01-04 23:59:59\",\"freeMaxCount\":100,\"isFree\":1,\"isJoinNum\":1,\"isQrCodePic\":1,\"isScore\":1,\"isShare\":1,\"isTimeFrame\":0,\"isTimeLimitType\":0,\"joinNum\":21,\"lotteryMusic\":\"/pic/20210310/1615346550064W01KTU1L_1615346550064_转盘转动音效.mp3\",\"name\":\"llj查看大转盘4\",\"prizes\":[{\"awardId\":null,\"awardName\":null,\"awardType\":2,\"couponNum\":10,\"id\":\"1000154524\",\"level\":1,\"name\":\"1111\",\"num\":0,\"pic\":\"/pic/20231121/1700545276964S3B0C8MG_1700545276964_associationtitle.png\",\"scoreValue\":4.00},{\"awardId\":null,\"awardName\":null,\"awardType\":2,\"couponNum\":1,\"id\":\"1000154530\",\"level\":2,\"name\":\"2222\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":4.00},{\"awardId\":\"1000132326\",\"awardName\":\"赠品券\",\"awardType\":2,\"couponNum\":1,\"id\":\"1000154531\",\"level\":3,\"name\":\"3333\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":4.00},{\"awardId\":null,\"awardName\":null,\"awardType\":2,\"couponNum\":1,\"id\":\"1000154532\",\"level\":4,\"name\":\"4444\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":3.00},{\"awardId\":\"1000132398\",\"awardName\":\"凉拌茄子商品\",\"awardType\":2,\"couponNum\":1,\"id\":\"1000154538\",\"level\":5,\"name\":\"5555\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":1.00},{\"awardId\":\"1000132334\",\"awardName\":\"童商品\",\"awardType\":2,\"couponNum\":1,\"id\":\"1000154539\",\"level\":6,\"name\":\"6666\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":5.00},{\"awardId\":null,\"awardName\":null,\"awardType\":null,\"couponNum\":null,\"id\":\"100000\",\"level\":null,\"name\":\"谢谢参与\",\"num\":0,\"pic\":null,\"scoreValue\":null},{\"awardId\":null,\"awardName\":null,\"awardType\":2,\"couponNum\":1,\"id\":\"1000154532\",\"level\":4,\"name\":\"4444\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":3.00},{\"awardId\":\"1000132398\",\"awardName\":\"凉拌茄子商品\",\"awardType\":2,\"couponNum\":1,\"id\":\"1000154538\",\"level\":5,\"name\":\"5555\",\"num\":0,\"pic\":\"/pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":1.00},{\"awardId\":\"1000132334\",\"awardName\":\"童商品\",\"awardType\":2,\"couponNum\":1,\"id\":\"1000154539\",\"level\":6,\"name\":\"6666\",\"num\":0,\"pic\":\"pic/20210220/1613801467673IW4LJEFH_1613801467673_defaultAwards.png\",\"scoreValue\":5.00}],\"qrCodePic\":\"/pic/20231121/1700545199936Q3AC6SQA_1700545199936_eqDiamondS.png\",\"scoreDeduction\":\"1\",\"scoreMaxCount\":10,\"sharePic\":\"/pic/20210305/1614934733055AQC0IF4B_1614934733055_分享图标.jpg\",\"shareTitle\":\"参与活动赢大奖\",\"startDate\":\"2023-12-04 00:00:00\",\"times\":null,\"weeks\":null}","msg":"success"};

export let getP={"code":"200","content":"{\"couponMemberCountId\":null,\"couponNum\":null,\"couponType\":null,\"freeTimes\":98,\"haveScore\":4.00,\"merchantFlg\":null,\"payTimes\":10,\"prizeAwardId\":null,\"prizeId\":\"1000154530\",\"prizeName\":\"2222\",\"prizeType\":2,\"prizesAwardDes\":\"与他人有人提议他弱由他弱\",\"prizesAwardDesFlg\":1,\"prizesAwardName\":null,\"score\":15.00}","msg":"success"};
代码中的pixi使用版本为7.2.4
代码依托于uni-app创建的项目 uni-app官网
相关推荐
断墨先生1 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
guai_guai_guai3 小时前
uniapp
前端·javascript·vue.js·uni-app
阿伟来咯~8 小时前
一些 uniapp相关bug
uni-app·bug
Footprint_Analytics9 小时前
Footprint Analytics 助力 Sei 游戏生态增长
游戏·web3·区块链
丁总学Java11 小时前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
瑶琴AI前端12 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
mosen86812 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq229511650213 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
半盏茶香13 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
尚梦20 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app