如何开发出直播小游戏源码,以云豹直播源码为例

发布来源:云豹科技
发布人:云豹科技
2021-09-27 10:10:08

图片1.png图片2.png图片3.png


直播间小游戏是直播平台常见的功能之一,以云豹直播源码为例,主播可以在直播间内开启智勇三张和幸运转盘等游戏,游戏开始后,观众可以用钻石下注,30秒倒计时后开启游戏结果,如果下注的角色牌数最大,则观众获得钻石奖励,否则输掉下注的钻石。

为规避法律问题,钻石仅可以用来送礼物等其他消费,不足时可以使用余额充值的方式获得,但不能直接提现。

 直播源码开发小游戏的部分代码如下:

public class GameZjhViewHolder extends AbsGameViewHolder {
 
    private static final int WHAT_READY_END = 101;//准备倒计时结束
    private static final int WHAT_CARD_ANIM_START = 102;//角色缩小,播放发牌动画
    private static final int WHAT_BET_ANIM_DISMISS = 103;//开始下注横条消失
    private static final int WHAT_BET_COUNT_DOWN = 104;//下注倒计时
    private static final int WHAT_GAME_RESULT = 105;//揭晓游戏结果
    private static final int WHAT_GAME_NEXT = 106;//开始下次游戏
    private static final int MAX_REPEAT_COUNT = 6;
    private TextView mTip;//提示的横条
    private TextView mReadyCountDown;//准备开始倒计时的TextView
    private View mRoleGroup;
    private int mRepeatCount;
    private Animation mResultAnim;
    private int mSceneHeight;//场景高度
    private int mRoleHeight;//角色高度
    private View mPokerGroup;
    private PokerView[] mPokerViews;
    private View[] mRoles;
    private View[] mRoleNames;
    private TextView mBetCountDown;//下注倒计时的TextView
    private TextView mCoinTextView;//显示用户余额的TextView
    private GameBetCoinView[] mBetCoinViews;
    private ImageView[] mResults;
    private ImageView mCoverImg;//结束时的遮罩
    private Animation mReadyAnim;//准备开始倒计时的动画
    private Animation mTipHideAnim;//提示横条隐藏的动画
    private Animation mTipShowAnim;//提示横条显示的动画
    private Animation mRoleIdleAnim; //角色待机动画
    private ValueAnimator mRoleScaleAnim;//角色缩小的动画
    private Handler mHandler;
    private int mBetCount;
    private int mWinIndex;//哪个角色获胜了
    private String mWinString;
 
    public GameZjhViewHolder(GameParam param, GameSoundPool gameSoundPool) {
        super(param, gameSoundPool);
        boolean anchor = param.isAnchor();
        mGameViewHeight = anchor ? DpUtil.dp2px(150) : DpUtil.dp2px(190);
        if (!anchor) {
            ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
            View view = viewStub.inflate();
            view.findViewById(R.id.btn_bet_shi).setOnClickListener(this);
            view.findViewById(R.id.btn_bet_bai).setOnClickListener(this);
            view.findViewById(R.id.btn_bet_qian).setOnClickListener(this);
            view.findViewById(R.id.btn_bet_wan).setOnClickListener(this);
            mCoinTextView = (TextView) view.findViewById(R.id.coin);
            mCoinTextView.setOnClickListener(this);
            for (View v : mBetCoinViews) {
                v.setOnClickListener(this);
            }
            mBetMoney = 10;
            GameHttpUtil.getCoin(new HttpCallback() {
                @Override
                public void onSuccess(int code, String msg, String[] info) {
                    if (code == 0 && info.length > 0) {
                        setLastCoin(JSONObject.parseObject(info[0]).getString("coin"));
                    }
                }
            });
        }
    }
 
 
    @Override
    protected int getLayoutId() {
        return R.layout.game_view_zjh;
    }
 
 
    @Override
    public void init() {
        mTip = (TextView) findViewById(R.id.tip);
        mReadyCountDown = (TextView) findViewById(R.id.count_down_1);
        mRoleGroup = findViewById(R.id.role_group);
        mSceneHeight = DpUtil.dp2px(150);
        mRoleHeight = DpUtil.dp2px(90);
        mPokerGroup = findViewById(R.id.pokers_group);
        mPokerViews = new PokerView[3];
        mPokerViews[0] = (PokerView) findViewById(R.id.pokers_1);
        mPokerViews[1] = (PokerView) findViewById(R.id.pokers_2);
        mPokerViews[2] = (PokerView) findViewById(R.id.pokers_3);
        mRoles = new View[3];
        mRoles[0] = findViewById(R.id.role_1);
        mRoles[1] = findViewById(R.id.role_2);
        mRoles[2] = findViewById(R.id.role_3);
        mRoleNames = new View[3];
        mRoleNames[0] = findViewById(R.id.name_1);
        mRoleNames[1] = findViewById(R.id.name_2);
        mRoleNames[2] = findViewById(R.id.name_3);
        mBetCountDown = (TextView) findViewById(R.id.count_down_2);
        mBetCoinViews = new GameBetCoinView[3];
        mBetCoinViews[0] = (GameBetCoinView) findViewById(R.id.score_1);
        mBetCoinViews[1] = (GameBetCoinView) findViewById(R.id.score_2);
        mBetCoinViews[2] = (GameBetCoinView) findViewById(R.id.score_3);
        mResults = new ImageView[3];
        mResults[0] = (ImageView) findViewById(R.id.result_1);
        mResults[1] = (ImageView) findViewById(R.id.result_2);
        mResults[2] = (ImageView) findViewById(R.id.result_3);
        mCoverImg = (ImageView) findViewById(R.id.cover);
        //角色缩小的动画
        mRoleScaleAnim = ValueAnimator.ofFloat(mSceneHeight, mRoleHeight);
        mRoleScaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float v = (float) animation.getAnimatedValue();
                changeRoleHeight((int) v);
            }
        });
        mRoleScaleAnim.setDuration(1000);
        mResultAnim = new ScaleAnimation(0.2f, 1, 0.2f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mResultAnim.setDuration(300);
 
        mRoleIdleAnim = new ScaleAnimation(1f, 1.04f, 1f, 1.04f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1f);
        mRoleIdleAnim.setRepeatCount(-1);
        mRoleIdleAnim.setRepeatMode(Animation.REVERSE);
        mRoleIdleAnim.setDuration(800);
 
        mReadyAnim = new ScaleAnimation(4, 1, 4, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mReadyAnim.setDuration(1000);
        mReadyAnim.setRepeatCount(MAX_REPEAT_COUNT);
        mReadyAnim.setRepeatMode(Animation.RESTART);
        mReadyAnim.setInterpolator(new AccelerateInterpolator());
        mReadyAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
 
            }
 
            @Override
            public void onAnimationEnd(Animation animation) {
                if (mReadyCountDown != null && mReadyCountDown.getVisibility() == View.VISIBLE) {
                    mReadyCountDown.setVisibility(View.INVISIBLE);//隐藏准备倒计时
                }
            }
 
            @Override
            public void onAnimationRepeat(Animation animation) {
                mReadyCountDown.setText(String.valueOf(mRepeatCount));
                mRepeatCount--;
            }
        });
 
        mTipShowAnim = new ScaleAnimation(0.2f, 1, 0.2f, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mTipShowAnim.setDuration(500);
        mTipHideAnim = new ScaleAnimation(1, 0.2f, 1, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        mTipHideAnim.setDuration(500);
        mTipHideAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
 
            }
 
            @Override
            public void onAnimationEnd(Animation animation) {
                if (mTip != null && mTip.getVisibility() == View.VISIBLE) {
                    mTip.setVisibility(View.INVISIBLE);
                }
            }
 
            @Override
            public void onAnimationRepeat(Animation animation) {
 
            }
        });
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case WHAT_READY_END://准备倒计时结束
                        anchorCreateGame();
                        break;
                    case WHAT_CARD_ANIM_START://角色缩小,播放发牌动画
                        playCardAnim();
                        break;
                    case WHAT_BET_ANIM_DISMISS:
                        if (mTip != null) {
                            mTip.startAnimation(mTipHideAnim);
                        }
                        break;
                    case WHAT_BET_COUNT_DOWN://下注倒计时
                        betCountDown();
                        break;
                    case WHAT_GAME_RESULT://揭晓游戏结果
                        showGameResult(msg.arg1, (String[]) msg.obj);
                        break;
                    case WHAT_GAME_NEXT:
                        nextGame();
                        break;
                }
            }
        };
        mWinString = WordUtil.getString(R.string.game_win);
    }
 
    /**
     * 改变角色的高度
     */
    private void changeRoleHeight(int height) {
        ViewGroup.LayoutParams params = mRoleGroup.getLayoutParams();
        params.height = height;
        mRoleGroup.setLayoutParams(params);
    }
 
    /**
     * 显示观众的余额
     */
    @Override
    public void setLastCoin(String coin) {
        if (mCoinTextView != null) {
            mCoinTextView.setText(StringUtil.contact(mChargeString, " ", coin,"  "));
        }
    }
 
    /**
     * 处理socket回调的数据
     */
    public void handleSocket(int action, JSONObject obj) {
        if (mEnd) {
            return;
        }
        L.e(mTag, "-----handleSocket--------->" + obj.toJSONString());
        switch (action) {
            case GameConsts.GAME_ACTION_OPEN_WINDOW://打开游戏窗口
                onGameWindowShow();
                break;
            case GameConsts.GAME_ACTION_CREATE://游戏被创建
                onGameCreate();
                break;
            case GameConsts.GAME_ACTION_CLOSE://主播关闭游戏
                onGameClose();
                break;
            case GameConsts.GAME_ACTION_NOTIFY_BET://开始下注
                onGameBetStart(obj);
                break;
            case GameConsts.GAME_ACTION_BROADCAST_BET://收到下注消息
                onGameBetChanged(obj);
                break;
            case GameConsts.GAME_ACTION_RESULT://收到游戏结果揭晓的的消息
                onGameResult(obj);
                break;
        }
    }
 
 
    /**
     * 所有人收到 打开游戏窗口的socket后,   打开游戏窗口,启动角色待机动画,进入8秒准备倒计时,
     */
    private void onGameWindowShow() {
        if (!mShowed) {
            showGameWindow();
            mBetStarted = false;
            mRepeatCount = MAX_REPEAT_COUNT;
            mReadyCountDown.setText(String.valueOf(mRepeatCount + 1));
            mReadyCountDown.startAnimation(mReadyAnim);
            if (mAnchor && mHandler != null) {
                mHandler.sendEmptyMessageDelayed(WHAT_READY_END, 7000);
            }
            if (mRoles != null) {
                for (View v : mRoles) {
                    if (v != null) {
                        v.startAnimation(mRoleIdleAnim);
                    }
                }
            }
        }
    }
 
 
    /**
     * 主播在8秒准备时间结束后,请求接口,创建游戏
     */
    @Override
    public void anchorCreateGame() {
        if (!mAnchor) {
            return;
        }
        GameHttpUtil.gameJinhuaCreate(mStream, new HttpCallback() {
            @Override
            public void onSuccess(int code, String msg, String[] info) {
                if (code == 0) {
                    JSONObject obj = JSON.parseObject(info[0]);
                    mGameID = obj.getString("gameid");
                    mGameToken = obj.getString("token");
                    mBetTime = obj.getIntValue("time");
                    if (mGameActionListener != null) {
                        mGameActionListener.zjhAnchorCreateGame(mGameID);
                    }
                } else {
                    ToastUtil.show(msg);
                }
            }
        });
    }
 
 
    /**
     * 所有人收到游戏被创建的socket后,开始执行发牌动画
     */
    private void onGameCreate() {
        if (!mShowed) {
            showGameWindow();
            if (mTip != null && mTip.getVisibility() == View.VISIBLE) {
                mTip.setVisibility(View.INVISIBLE);
            }
            if (mRoles != null) {
                for (View v : mRoles) {
                    if (v != null) {
                        v.startAnimation(mRoleIdleAnim);
                    }
                }
            }
        }
        if (mRoleNames != null) {
            for (View name : mRoleNames) {//隐藏角色名字
                if (name != null && name.getVisibility() == View.VISIBLE) {
                    name.setVisibility(View.INVISIBLE);
                }
            }
        }
        if (mTip != null && mTipHideAnim != null && mTip.getVisibility() == View.VISIBLE) {
            mTip.startAnimation(mTipHideAnim);//横条消失
        }
        if (mRoleScaleAnim != null) {
            mRoleScaleAnim.start();//执行角色缩小动画
        }
        if (mHandler != null) {
            mHandler.sendEmptyMessageDelayed(WHAT_CARD_ANIM_START, 1000);
        }
    }
 
 
    /**
     * 角色缩小后,播放发牌动画,主播通知所有人下注
     */
    private void playCardAnim() {
        //角色靠右
        if (mBetCoinViews != null) {
            for (View v : mBetCoinViews) {
                if (v != null && v.getVisibility() == View.GONE) {
                    v.setVisibility(View.INVISIBLE);
                }
            }
        }
        //显示摆放扑克牌的外框,开始执行发牌动画
        if (mPokerGroup != null && mPokerGroup.getVisibility() != View.VISIBLE) {
            mPokerGroup.setVisibility(View.VISIBLE);
        }
        if (mPokerViews != null) {
            for (PokerView pv : mPokerViews) {
                if (pv != null) {
                    pv.sendCard();
                }
            }
        }
        //主播通知所有人下注
        if (mAnchor && mGameActionListener != null) {
            mGameActionListener.zjhAnchorNotifyGameBet(mLiveUid, mGameID, mGameToken, mBetTime);
        }
    }
 
    /**
     * 收到主播通知下注的socket,播放动画,开始下注倒计时
     */
    private void onGameBetStart(JSONObject obj) {
        mBetStarted = true;
        if (!mAnchor) {
            mGameID = obj.getString("gameid");
            mGameToken = obj.getString("token");
            mBetTime = obj.getIntValue("time");
        }
        mBetCount = mBetTime - 1;
        if (mBetCountDown != null) {
            if (mBetCountDown.getVisibility() != View.VISIBLE) {
                mBetCountDown.setVisibility(View.VISIBLE);
            }
            mBetCountDown.setText(String.valueOf(mBetCount));
        }
        if (mTip != null) {
            if (mTip.getVisibility() != View.VISIBLE) {
                mTip.setVisibility(View.VISIBLE);
            }
            mTip.setText(R.string.game_start_support);
            mTip.startAnimation(mTipShowAnim);
        }
        if (mHandler != null) {
            mHandler.sendEmptyMessageDelayed(WHAT_BET_COUNT_DOWN, 1000);
            mHandler.sendEmptyMessageDelayed(WHAT_BET_ANIM_DISMISS, 1500);
        }
        //显示下注牌
        if (mBetCoinViews != null) {
            for (View v : mBetCoinViews) {
                if (v != null && v.getVisibility() != View.VISIBLE) {
                    v.setVisibility(View.VISIBLE);
                }
            }
        }
        playGameSound(GameSoundPool.GAME_SOUND_BET_START);
    }
 
    /**
     * 下注倒计时
     */
    private void betCountDown() {
        mBetCount--;
        if (mBetCount > 0) {
            mBetCountDown.setText(String.valueOf(mBetCount));
            if (mHandler != null) {
                mHandler.sendEmptyMessageDelayed(WHAT_BET_COUNT_DOWN, 1000);
            }
        } else {
            mBetCountDown.setVisibility(View.INVISIBLE);
        }
    }
 
 
    /**
     * 观众下注
     */
    private void audienceBetGame(final int index) {
        GameHttpUtil.gameJinhuaBet(mGameID, mBetMoney, index, new HttpCallback() {
            @Override
            public void onSuccess(int code, String msg, String[] info) {
                if (code == 0 && info.length > 0) {
                    setLastCoin(JSON.parseObject(info[0]).getString("coin"));
                    if (mGameActionListener != null) {
                        mGameActionListener.zjhAudienceBetGame(mBetMoney, index);
                    }
                } else {
                    ToastUtil.show(msg);
                }
            }
        });
    }
 
    /**
     * 所有人收到下注的观众socket,更新下注金额
     */
    private void onGameBetChanged(JSONObject obj) {
        String uid = obj.getString("uid");
        int money = obj.getIntValue("money");
        int index = obj.getIntValue("type") - 1;
        boolean isSelf = uid.equals(CommonAppConfig.getInstance().getUid());
        if (isSelf) {//自己下的注
            playGameSound(GameSoundPool.GAME_SOUND_BET_SUCCESS);
        }
        if (mBetCoinViews != null) {
            if (index >= 0 && index < 3) {
                if (mBetCoinViews[index] != null) {
                    mBetCoinViews[index].updateBetVal(money, isSelf);
                }
            }
        }
    }
 
    /**
     * 收到游戏结果揭晓的的消息
     */
    private void onGameResult(JSONObject obj) {
        mWinIndex = -1;
        if (mTip != null) {
            if (mTip.getVisibility() != View.VISIBLE) {
                mTip.setVisibility(View.VISIBLE);
            }
            mTip.setText(R.string.game_show_result);//揭晓结果
            mTip.startAnimation(mTipShowAnim);
            if (mHandler != null) {
                mHandler.sendEmptyMessageDelayed(WHAT_BET_ANIM_DISMISS, 1500);
            }
        }
        String[][] result = JSON.parseObject(obj.getString("ct"), String[][].class);
        for (int i = 0, length = result.length; i < length; i++) {
            Message msg = Message.obtain();
            msg.what = WHAT_GAME_RESULT;
            msg.arg1 = i;
            msg.obj = result[i];
            if (mHandler != null) {
                mHandler.sendMessageDelayed(msg, i * 2000);
            }
        }
    }
 
    /**
     * 揭晓游戏结果
     */
    private void showGameResult(int i, String[] result) {
        if (mPokerViews[i] != null) {
            mPokerViews[i].showResult(GameIconUtil.getPoker(result[0]), GameIconUtil.getPoker(result[1]), GameIconUtil.getPoker(result[2]));
        }
        if (mResults[i] != null) {
            mResults[i].setVisibility(View.VISIBLE);
            mResults[i].setImageResource(GameIconUtil.getJinHuaResult(result[6]));
            mResults[i].startAnimation(mResultAnim);
        }
        if (mWinIndex == -1) {
            if ("1".equals(result[3])) {
                mWinIndex = i;
            }
        }
        if (i == 2) {
            if (mWinIndex >= 0) {
                int coverRes = 0;
                switch (mWinIndex) {
                    case 0:
                        coverRes = R.mipmap.bg_game_win_left;
                        break;
                    case 1:
                        coverRes = R.mipmap.bg_game_win_middle;
                        break;
                    case 2:
                        coverRes = R.mipmap.bg_game_win_right;
                        break;
                }
                mCoverImg.setVisibility(View.VISIBLE);
                mCoverImg.setImageResource(coverRes);
            }
            if (mHandler != null) {
                mHandler.sendEmptyMessageDelayed(WHAT_GAME_NEXT, 7000);//7秒后重新开始游戏
            }
            if (!mAnchor) {
                getGameResult();
            }
        }
        playGameSound(GameSoundPool.GAME_SOUND_RESULT);
    }
 
 
    @Override
    protected void getGameResult() {
        GameHttpUtil.gameSettle(mGameID, new HttpCallback() {
            @Override
            public void onSuccess(int code, String msg, String[] info) {
                if (code == 0) {
                    JSONObject obj = JSON.parseObject(info[0]);
                    setLastCoin(obj.getString("coin"));
                    int winCoin = obj.getIntValue("gamecoin");
                    if (winCoin > 0) {
                        DialogUitl.showSimpleTipDialog(mContext, mWinString, "+"+winCoin + mCoinName);
                    }else{
                        ToastUtil.show(R.string.game_lose_tip);
                    }
                } else {
                    ToastUtil.show(msg);
                }
            }
        });
    }
 
    /**
     * 游戏中途进入直播间的打开游戏窗口
     */
    @Override
    public void enterRoomOpenGameWindow() {
        if (!mShowed) {
            showGameWindow();
            //隐藏角色名字
            if (mRoleNames != null) {
                for (View name : mRoleNames) {
                    if (name != null && name.getVisibility() == View.VISIBLE) {
                        name.setVisibility(View.INVISIBLE);
                    }
                }
            }
            changeRoleHeight(mRoleHeight);
            mBetCount = mBetTime - 1;
            if (mBetCount > 0 && mBetCountDown != null) {
                if (mBetCountDown.getVisibility() != View.VISIBLE) {
                    mBetCountDown.setVisibility(View.VISIBLE);
                }
                mBetCountDown.setText(String.valueOf(mBetCount));
            }
            //显示下注牌
            if (mBetCoinViews != null) {
                for (int i = 0, length = mBetCoinViews.length; i < length; i++) {
                    GameBetCoinView gameBetCoinView = mBetCoinViews[i];
                    if (gameBetCoinView != null && gameBetCoinView.getVisibility() != View.VISIBLE) {
                        gameBetCoinView.setVisibility(View.VISIBLE);
                        gameBetCoinView.setBetVal(mTotalBet[i], mMyBet[i]);
                    }
                }
            }
            //显示摆放扑克牌的外框,开始执行发牌动画
            if (mPokerGroup != null && mPokerGroup.getVisibility() != View.VISIBLE) {
                mPokerGroup.setVisibility(View.VISIBLE);
            }
            if (mPokerViews != null) {
                for (PokerView pv : mPokerViews) {
                    if (pv != null) {
                        pv.sendCard();
                    }
                }
            }
            //启动角色待机动画
            if (mRoles != null) {
                for (View v : mRoles) {
                    if (v != null) {
                        v.startAnimation(mRoleIdleAnim);
                    }
                }
            }
            if (mTip != null) {
                if (mTip.getVisibility() != View.VISIBLE) {
                    mTip.setVisibility(View.VISIBLE);
                }
                mTip.setText(R.string.game_start_support);
                mTip.startAnimation(mTipShowAnim);
            }
            if (mHandler != null) {
                mHandler.sendEmptyMessageDelayed(WHAT_BET_COUNT_DOWN, 1000);
                mHandler.sendEmptyMessageDelayed(WHAT_BET_ANIM_DISMISS, 1500);
            }
            playGameSound(GameSoundPool.GAME_SOUND_BET_START);
        }
    }


这样,就实现了在直播APP源码中开发小游戏的操作,事实上,随着国家管控越来越严格,国内各大平台纷纷对游戏功能做出限制,如“钻石”等虚拟币不允许直接提现,或只能用于购买会员、坐骑等不会牵扯到现金交易的产品上,在开发直播源码的过程中,请大家注意这一问题。

 声明:以上内容为云豹科技作者本人原创,未经作者本人同意,禁止转载,否则将追究相关法律责任www.yunbaokj.com

声明:
以上内容为云豹科技作者本人原创,未经作者本人同意,禁止转载,否则将追究相关法律责任