如何开发出直播小游戏源码,以云豹直播源码为例
直播间小游戏是直播平台常见的功能之一,以云豹直播源码为例,主播可以在直播间内开启智勇三张和幸运转盘等游戏,游戏开始后,观众可以用钻石下注,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