According to wechat official public news, the pace of wechat small games is getting closer and closer. Its developer qualification threshold and user threshold are very low, will set off a wave of “national development of small games”.
Official development tools to create projects can be obtained dozen aircraft source, this is a very small but five viscera complete 2D game, I believe that most of the sense of smell programmers have been experienced and personally transformed.
But if you want to use the platform of wechat, do an interactive, playable strong online game, there is a certain difficulty. Don’t worry, with the help of Bmob’s latest game SDK, you can easily capture the first wave of traffic dividends! This tutorial we will discuss how to do a real-time Internet battle wechat game (Internet aircraft war) in the case of complete ignorance of server development.
preface
In order to read through this article, you’d better:
- Have mastered the development of simple micro channel games, can understand the official
Play the plane
Source code is ok, even can useJavascript
You can also print HelloWorld - A little understanding of Java, in fact, do not understand the line, on the basis of JS is very easy to extend, mainly to have the idea of object-oriented
The following focuses on how to quickly get started to develop small wechat games online, but if you know some U3D development, Bmob official also provides Unity3D version of Demo+SDK, both can play cross-platform intercommunication, and the interface specification is highly consistent, basically covering all the mainstream terminals on the market
PS: wechat mini games and SDK of Unity3D are open source, welcome to correct mistakes
The simplest step
- To obtainCloud gaming services(hereinafter referred to as
website
), there are ways to get it at the bottom of the article; - in
website
downloadWechat small game Demo+SDK
And imported into theWechat developer tools
(hereinafter referred to astool
) and modifyAppKey
; - in
website
Configure the player synchronization attribute andrelease
Download theThe cloud code
And then inwebsite
Select a cloud server to start *(PS: cloud server is free)*; - A test run
Demo
If theconsole
If no error is reported, clicktool
thepreview
, scan the QR code with wechat; - Now, it’s available in the game
Create a room
.Experience computer and mobile phone network battle;
Next, I will introduce the key points of wechat mini game project development, and the detailed explanation of cloud code and the TUTORIAL of U3D version will be introduced successively
Running effect
On the left is the game page of wechat mini-game – developer tools, and on the right is the cross-platform play of Unity3D-Macos-Editor
Demo test running video (no AD portal in station B)
Super HD /720P mode is a better viewing experience
I have to say that the programmer to make their own UI is really ugly, that “room” interface is really weak to ridicule
The Demo currently has a few minor issues with cross-platform play, such as different movement speeds between players and monsters. But platforming is highly consistent. This problem has nothing to do with SDK, it is all parameter Settings of local Demo projects, mainly because Unity projects use absolute value, wechat small game projects are relative value, Unity will also use relative value later to improve the Demo.
How to develop from scratch
In terms of experience in game development, I believe there are many readers who are better than me. I here according to my personal development process, around the network of aircraft war this project, talk about the steps from zero development of the game. (Don’t bother to read this one.)
- Determine the theme and gameplay of the game;
- Clarify the properties that need to be synchronized between multiple clients and the events that need to be notified to each other;
- Analyze the events that the client and server need to interact with;
- Create/collect pictures, animations, sound effects;
- Develop/copy the physics engine of the game world, including object rendering, movement, collision detection (and memory management), etc.
- Develop server-side game logic (Java cloud code) first, which helps clarify the logic of the entire game;
- Develop client game logic and access SDK;
- Test, release;
Here’s how to expand (see the bottom of the article for the full source code for Demo and SDK)
-
Gameplay: This project is ready to be made into a plane war that can accommodate more than one person online at the same time. All Settings are basically the same as the official Demo of wechat small game, with several Settings added:
- There are four types of bots with different shapes and levels (some people prefer to call them 'computers' or' aircraft NPCS ') - Bots at level 3 and level 4 can Fire, bullets fly at the same speed as the player, bots at level 4 Fire more frequently - Bots have health (no longer die on touch), - Player(Player) and Bot are divided into two camps, and there is no teammate damage. - Player's camp is randomly divided by the server, or can be changed to Player's own decision. - Spawn logic is placed in the cloud. - Player will be disabled if it takes damage, and Fire will disappear if it hits any object. - Players will be destroyed if they collide with bots, players will be destroyed if they collide with bots. - Player firing is temporarily automatic, - Player firing events (firing coordinates) are sent directly to other clients, without cloud code - Player elimination is processed by the cloud, after the cloud verification, Then distribute the event and decision - the elimination decision of Bot is processed and distributed by the cloud - when all players of one party die, the other party wins; If both sides are left with one player each, the game ends in a drawCopy the code
-
Attribute synchronization and event notification between clients: only two attributes of players need to be automatically synchronized and distributed, one is location and the other is score; The only events that are directly synchronized are firing
- position: This is a 2D game, so the player position can be expressed as float[2], but for consistency, the Demo uses int[2]. The values range from 0 to 65535, representing 0% to 100%. Only the cloud code has the permission to modify, according to the Player, Bot shot down events bonus points can be at the end of the game, settlement into experience value, save to the Bmob database - fire: Direct notification to other clients, just record the starting coordinates of Fire, i.e. [0-65535,0-65535] expressed as byte[], a 0-65535 int can become two 0-255 digits together with the event type to mark the notification (Fire), The flag is set to 50, which means to send [50, 0-255, 0-255, 0-255, 0-255] to other players when firing.Copy the code
-
Client-cloud interaction events: the server needs to do the following things: save room information; Assign teams; Officially notify the game to start; Brush logic; Decision Bot elimination; Select * from Player; Add Player score; To determine the outcome; Record record
- Team allocation: notify the server after the client scene. OnLoad, the server will allocate the team and randomly and evenly divide the players into two teams, and then deliver the team, and notify the server after the client finishes processing. - Official start: After the server confirms that all clients have processed the team information, it notifies all clients to start the game - Spawns logic: random Bot faction, X-axis position, type, name, next send to the client for processing - Bot elimination: When any client reports that it 'witnessed' a Bot being destroyed, the cloud will pick up the report, deliver the report and score the so-called 'witnessed', which means that the client will conduct collision detection during rendering and find that the Bot's HP is 0 - Player eliminated: When n clients' see 'a Player is destroyed and n>=m for a short period of time, the cloud only accepts, delivers, and scores when there are only 2 or 3 players, m is 1, that is, reporting is accepted. When there are 4, 5, and 6 players, M is 2, not reporting is accepted. When there are more than 6 players, M is 3. That is, at least 3 people report to accept the 'short time' is currently set as 2000ms, that is, the validity period of the report information is 2 seconds - to determine the outcome: the last person of the two teams eliminated at the same time when the tie; A team loses when all its members are eliminated ahead of the opposing teamCopy the code
- Assets: From the Artist/Unity Assets store
-
Physics engine: from wechat official Demo(sprite.js)/Imagination + Make wheels/third party download
IsCollideWith (sp) {if (this.visible && sp.visible) {let dis = sp.x - this.x; if (-sp.width < dis && dis < this.width) { dis = sp.y - this.y; if (-sp.height < dis && dis < this.height) return true; } } return false; }Copy the code
- Java Cloud code: As explained in point 3 above, here are a few pieces of code:
Room. Java:
Public class Room extends RoomBase public String mObjectId = null; // Assign teams first, then start the game. Public Boolean isNotReallyStart; // The spawn interval (milliseconds) determines the spawn frequency, depending on the number of players. The more people, the faster spawnspan. Private Long lastBotSpawnTime = 0; Private long botCount = 0; // Confidence interval: When the logic of calculating hits is put into the client, the event of hitting enemies/monsters cannot be completely trusted by one of the clients. It is relatively unimportant to prevent ping differential kills and plug-ins // monsters. If a certain client reports it, it will choose to trust him // but the elimination of players affects the experience. When multiple players are required to authenticate at the same time // then agree: If there are 2, 3 people room, can be a person in charge (so as not to drop the player invincible) / / if you have four people to play games, need two people in a short period of time "to see" the death of a player, the player is the true death / / under the condition of more people, as long as the most three people died in a short period of time that a player, Public int confidenceInterval = 1 public int confidenceInterval = 1 public int confidenceInterval = 1; private final Set<String> dieBotsNames = new HashSet<String>(); public static final byte// NotifyType_AssignTeam = 1,// NotifyType_BotSpawn = 2,// NotifyType_ReallyStart = 3,// NotifyType_PlayerCrash = 4,// NotifyType_BotDie = 5,// NotifyType_GameOver = 6// ; @override public void onCreate() {Override public void onCreate() { // botSpawnSpan = (1000/2)/(playerCount / 2); botSpawnSpan = (2000) / (playerCount / 2); If (playerCount > 3) confidenceInterval = 2; else if (playerCount > 5) confidenceInterval = 3; HttpResponse response = Bmob.getInstance().insert("Room", JSON.toJson(// "roomId", roomId,// "master", masterId,// "masterKey", masterKey,// "joinKey", joinKey,// "playerCount", playerCount,// "address", Address,// "tcpPort", tcpPort,// "udpPort", udpPort,// "websocketPort", websocketPort,// "status", 0// 0: open, 1: in game, 2: // Room closed)); mObjectId = response.jsonData.getString("objectId"); } @Override public void onGameStart() { if (! Functions.isStrEmpty(mObjectId)) Bmob.getInstance().update("Room", mObjectId, JSON.toJson("status", 1)); dieBotsNames.clear(); isNotReallyStart = true; lastBotSpawnTime = 0; botCount = 0; } @Override public void onDestroy() { if (! Functions.isStrEmpty(mObjectId)) Bmob.getInstance().update("Room", mObjectId, JSON.toJson("status", 2)); } @Override @BmobGameSDKHook public void onTick() { if (isNotReallyStart) return; long curTime = getTime(); if (curTime > lastBotSpawnTime + botSpawnSpan) { spawnBot(); lastBotSpawnTime = curTime; Public void assignTeam() {// The server sends a notification to the client when all players are in position. For (Player p: players) p.teamid = 0; // If [1]=1, players[0] =1; Byte [] team = new byte[playerCount + 1]; Team [0] = NotifyType_AssignTeam; Int team1Count = playerCount / 2; while (team1Count ! = 0) { int id = ((int) (Math.random() * 100000) % playerCount) + 1; if (team[id] ! = 1) { players[id - 1].teamId = 1; team[id] = 1; team1Count--; } } sendToAll(team); } // spawnBot() private void spawnBot() {botCount++; // The position (mainly x axis) is random, denoted by byte, 0-255, denoting from the left to the right, 128 is in the screen key // [0], denoting flag, This notification is a spawn event // [1] indicates the team code, // [2] indicates the position of the spawns on the x axis. // [3] indicates the monster Type. // [4-] indicates the monster name. (Math.random() * 100)) % 2); byte botPositionX = (byte) (((int) (Math.random() * 0xffff)) & 0xff); byte botType = (byte) (Math.random() * 10); // 0-9 if (botType == 9) // 9 botType = 3; Else if (botType > 6) // 7, 8 botType = 2; Else if (botType > 3) // 4, 5, 6 botType = 1; else botType = 0; Byte [] botName = ("Bot" + botType + "_" + Long. ToHexString (botCount)).getBytes(); byte[] botName = ("Bot" + botType + "_" + Long. byte[] botInfo = new byte[4 + botName.length]; BotInfo [0] = NotifyType_BotSpawn; // (flag)2 botInfo[1] = botTeam; botInfo[2] = botPositionX; botInfo[3] = botType; arraycopy(botName, 0, botInfo, 4, botName.length); sendToAll(botInfo); }Copy the code
—
Player. Java:
// public class Player extends PlayerBase public int teamId = 0; private boolean isDead = false; private boolean isLoadOk = false, isTeamClear = false; private long[] dieReports; @bmobgamesdkhook public native void setIsDead(Boolean isDead); @Override public void onGameStart() { dieReports = new long[room.playerCount]; isLoadOk = false; isDead = false; setIsDead(isDead); syncToClient(); } @bmobgamesdkhook public strictfp void onAction_OnGameLoad(byte[] bs) {this.isLoadOk = true; // Check if everything is ready for (Player p: communication) if (! p.isLoadOk) return; // Start assigning teams room.assignTeam(); } @bmobgamesdkhook public strictfp void onAction_OnTeamInfoGet(byte[] bs) {this.isTeamClear = true; // Check if everything is ready for (Player p: communication) if (! p.isTeamClear) return; // Make the room work room.reallyPlaying(); } // There is a player report, One player was found dead @ BmobGameSDKHook public strictfp void onAction_PlayerCrash (byte [] infos) {if (room. IsNotReallyStart | | // if the player isDead, return will not be accepted; // 0: the object of the crash is no, expressed in byte, which is compatible with up to 256 large room // 1: the type of injured person (0: Enemy player (direct collision); 1. enemy shells. Int dieNo = (int) infos[0]; int dieNo = (int) infos[0]; If (dieNo < 0 | | dieNo > room. PlayerCount) {/ / if it is more than 128 rooms, dieNo is likely to be - 127-1, want to consider compatible kick (); // Invalid report, kick out the player return; } int murdererNo = -1; if (infos[1] == 0) { murdererNo = (int) infos[2]; if (murdererNo < 0 || murdererNo > room.playerCount) { kick(); // Invalid report, kick out the player return; }} the if (dieNo = = no | | murdererNo = = no) {/ / add a death report to another player if (dieNo = = no) {if (murdererNo! = -1) roommates[murdererNo].reportDie(this); } else roommates[dieNo].reportDie(this); die(); [dieNo].reportdie (this); {}} void reportDie (Player reporter) if (room) isNotReallyStart | | isDead) / / dead pig is not afraid of scalding water return; long curTime = getTime(); dieReports[reporter.no] = curTime; int dieCount = 0; long reportExpired = curTime - 2000; for (long time : dieReports) if (time > reportExpired) dieCount++; if (dieCount < room.confidenceInterval) return; die(); } void die() { isDead = true; setIsDead(isDead); syncToClient(); sendToAll(new byte[] { Room.NotifyType_PlayerCrash, (byte) no }); int[] teamAliveCounts = new int[] { 0, 0 }; String msg = String.format("Player[%d][%s] die\n", no, getUserId()); for (Player p : roommates) { if (p.isDead) { msg += p.no + " is dead, team " + p.teamId + "\n"; continue; } teamAliveCounts[p.teamId]++; msg += p.no + " is alive, team " + p.teamId + "\n"; } msg += String.format("team_0 has alive[%d] and team_1 is [%d]", no, teamAliveCounts[0], teamAliveCounts[1]); If (teamAliveCounts [0] = = 0 | | teamAliveCounts [1] = = 0) {/ / a team no one / / prepare send GameOver, 0: draw, 1: victory, Byte [] toTeam0 = new byte[] {room.notifyType_gameover, 0}, // toTeam1 = new byte[] {room.notifyType_gameover, 0} 0}; If (teamAliveCounts[0] == teamAliveCounts[1]) {else if (teamAliveCounts[0] == 0) {// Team 1 wins toTeam0[1] = 2; toTeam1[1] = 1; } else { toTeam0[1] = 1; toTeam1[1] = 2; } for (Player p : roommates) p.send(p.teamId == 0 ? toTeam0 : toTeam1); room.gameOver(); // Game over}} // a player reports, @bmobgamesdkhook public strictfp void onAction_BotDie(byte[] infos) {if (room.isNotreallyStart) return; // cn.bmob.gamesdk.server.Main.l("BotDie: (" + // java.util.Arrays.toString(infos) + ") : " + infos.length); If (room.isbotDienow (new String(infos))) {// Non-duplicate byte[] sendInfos = new byte[1 + infos.length]; sendInfos[0] = Room.NotifyType_BotDie; arraycopy(infos, 0, sendInfos, 1, infos.length); sendToAll(sendInfos); @override public void onOffline() {if (room.isnotreallyStart) return; die(); } @override public void onLeave() {if (room.isnotreallyStart) return; die(); }Copy the code
-
Access to the SDK:
// PlayerMaxSpeed = screenHeight / 2000; // PlayerMaxSpeed = screenHeight / 2000; // screenHeight = screenHeight / 2000; // px per sec const BotSpeed = screenHeight / 8000; // px per sec const EnemyFireSpeed = screenHeight / 3000; // px per sec const FriendFireSpeed = -EnemyFireSpeed; OnOthersStatus (no, changedAttr, hisStatus) {if (ChangeDattr. position) {let y = hisStatus.position[1]; let gameObj = this.players[no].gameObject; if (gameObj.isTeammate) y = 65535 - y; gameObj.x = hisStatus.position[0] / WidthRatio - PlayerWidth / 2; gameObj.y = y / HeightRatio - PlayerHeight / 2; }} // Other players send onTransfer(no, body) {switch (body.shift()) {case 50: console.log('Fire from: ', this.players[no]); let isTeammate = this.players[no].gameObject.isTeammate, x = (body[0] << 8) | body[1], y = (body[2] << 8) | body[3]; if (isTeammate) y = 65535 - y; let fire = new Sprite( isTeammate ? ImgSrc_Fire_Friend : ImgSrc_Fire_Enemy, FireWidth, FireHeight, x / WidthRatio, y / HeightRatio ); fire.objType = 3; // 0: sundries; 1: player; 2: bot; 3: fire fire.velocity = isTeammate ? FriendFireSpeed : EnemyFireSpeed; fire.teamId = isTeammate ? this.mTeamId : (1 - this.mTeamId); this.gameObjArr.push(fire); break; }} // onCloudNotify(notify) {switch (notify.shift()) {case NotifyType_AssignTeam: this.assignTeam(notify); break; case NotifyType_BotSpawn: this.botSpawn( notify[0] == this.mTeamId, (notify[1]) * screenWidth / 255, notify[2], model.bytesToString(notify, 3, notify.length) ); break; case NotifyType_ReallyStart: this.startGame(); break; case NotifyType_PlayerCrash: this.renderPlayerDie(notify[0]); break; case NotifyType_BotDie: this.botDie(model.bytesToString(notify, 0, notify.length)); break; case NotifyType_GameOver: this.isGameStart = false; switch (notify[0]) { case 0: this.gameDraw(); break; case 1: this.gameWin(); break; case 2: this.gameLose(); break; } break; }}Copy the code
-
Test, release: Ash often fun, the next stage is ready to make four camps of gameplay
Development experience
It took less than two hours to transform a stand-alone game into a networked game with sufficient preparation of basic materials, components (physics engine), and the logic was robust enough, and the effect was cool. Plus, the SDK is open source, so it’s easy to spot problems.
In general, THE Bmob Game SDK really pulls down the threshold of online Game development, completely eliminating the huge and complicated back-end development and server operation and maintenance work before, giving many limited resources, can only develop standalone Game teams and projects a new way ~
Obtain Demo, SDK complete source code:
Plus official customer service, small qi QQ: 2967459363
Other tutorial
Fall into a box? Bmob helps you develop your own online chicken eating game
Unity networking game small Demo
How to realize the miscellaneous thinking of various games