在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:PubNubDevelopers/Ninja-Multiplayer-Platformer开源软件地址:https://github.com/PubNubDevelopers/Ninja-Multiplayer-Platformer开源编程语言:JavaScript 92.4%开源软件介绍:Ninja Multiplayer Platformer Game in Real Timehttps://pubnubdevelopers.github.io/Ninja-Multiplayer-Platformer/Play Now:
A step by step tutorial of how to create this multiplayer game is available here: https://www.pubnub.com/tutorials/javascript/multiplayer-game/ Table of Contents
SynopsisCreating a real time multiplayer game can be a daunting task to take on alone. When I stumbled upon Mozilla’s game development workshop, I decided to take on the challenge to turn Belén Albeza's workshop into a real time game. This Ninja Platformer Multiplayer Game uses PubNub’s real time data stream network to manage network traffic between players, and also uses PubNub Blocks to manage game state between devices. PubNub made the development process incredibly simple and allowed the entire demo to be written in less than a 1000 lines of code!!! This feat is incredible for the amount of functionality this game has and is an excellent showcase of both Phaser and PubNub’s capabilities. This Ninja Platformer Multiplayer Game is written in javascript and the levels are generated via JSON files with information on the position of the platforms and game objects. This real time multiplayer game is a collaborative puzzle game that encourages you to work with your friends to collect the keys in clever ways. Using Phasers Arcade Physics Library, each character and object has its own physics body with its own set of physics properties. Open up a few browser windows to test out the real time functionality of the application. Don’t forget to give it a star and a fork. It will be exciting to see what you guys can make from this example since it has so much room for expansion. PhaserPhaser is a fast, free, and fun open source HTML5 game framework. It uses a custom build of Pixi.js for WebGL and Canvas rendering, and supports desktop and mobile web browsers. Games can be compiled to iOS, Android and native desktop apps via 3rd party tools. You can use JavaScript or TypeScript for development. Learn More PubNubPubNub is a global Data Stream Network (DSN) that allows developers to build realtime web, mobile, IoT applications and real time games. PubNub API's include a Publish/Subscribe messaging service. Clients subscribe to a channel name, and any clients that are connected will receive any publish messages sent on that channel. In addition PubNub offers online presence detection that tracks the online and offline statues of users and devices in realtime. Furthermore, PubNub offers a service called PubNub Blocks which allows developers to customize the data stream in Javascript. PubNub’s Pub/Sub and Presence is used in this demo to send information on player movements and occupancy in each level. PubNub Blocks is used as a state machine to detect if the coins of been collected by a player in each level. PubNub Blocks updates the JSON level object depending upon what actions the players take in the game. Learn More Getting StartedIn order to start the development process, you are going to need a few things:
Create a new folder anywhere you wish, for simplicity create it on your Desktop. If you have Mac OS or Linux (or have Python installed), open up your Terminal Application and type in: python -m SimpleHTTPServer 8000 If you are using Windows download XAMPP. There are some great tutorials out there on how to setup XAMPP on your machine. Once you have your server up and running, go to Now in order to get you setup with PubNub, navigate to the PubNub Website and create an account with your Google login. Once you are in the dashboard, name your application whatever you wish, and click the Create New App button. Once you create the application, click on the application to few the key information. You should see that you have two keys, a Publish Key, and a Subscribe Key. Click on the demo keyset, and it should load up a page that shows your keys in addition to Application Add-Ons. In the Application Add-Ons section, turn ON Presence and check Generate Leave on TCP FIN or RST and Global Here Now. Also turn ON PubNub Blocks. Make sure to have access manager turned off or else the sample code won't work since you need to include a secret key. Leave the page open for future reference once we start writing our code, we are going to need those PubNub keys! Code LayoutThis game is split up into four main documents, Main.js
window.syncOtherPlayerFrameDelay = 0; //30 frames allows for 500ms of network jitter, to prevent late frames
window.currentChannelName; // Global variable for the current channel that your player character is on
window.currentFireChannelName; // Global variable that checks the current stage you are on to send the correct information to the PubNub Block
window.globalCurrentLevel = 0; // Global variable for the current level (index starts at 0)
window.UniqueID = window.PubNub.generateUUID(); // Generate a unique id for the player. Generated by the PubNub Network
window.globalLevelState = null; // Sets the globalLevelState to null if you aren't connected to the network. Once connected, the level will generate to the info that was on the block.
window.globalWasHeroMoving = true;
window.text1 = 'Level 1 Occupancy: 0'; // Global text objects for occupancy count
window.text2 = 'Level 2 Occupancy: 0';
window.text3 = 'Level 3 Occupancy: 0';
let textResponse1;
let textResponse2;
let textResponse3;
window.updateOccupancyCounter = false; // Occupancy Counter variable to check if the timer has already been called in that scene
window.keyMessages = []; Then we load the external Javascript files: // Load External Javascript files
const loadHeroScript = document.createElement('script');
loadHeroScript.src = './js/heroScript.js';
document.head.appendChild(loadHeroScript);
const loadLoadingState = document.createElement('script');
loadLoadingState.src = './js/loadingState.js';
document.head.appendChild(loadLoadingState);
const loadPlaystate = document.createElement('script');
loadPlaystate.src = './js/playState.js';
document.head.appendChild(loadPlaystate); After the other javascript files have been loaded, we call the function (promise) window.addEventListener('load', () => {
const game = new window.Phaser.Game(960, 600, window.Phaser.AUTO, 'game');
game.state.disableVisibilityChange = true; // This allows two windows to be open at the same time and allow both windows to run the update function
game.state.add('play', window.PlayState);
game.state.add('loading', window.LoadingState);
window.createMyPubNub(0); // Connect to the pubnub network and run level code 0
window.StartLoading = function () {
game.state.start('loading'); // Run the loading function once you successfully connect to the pubnub network
};
}); Now we create the global variables for what level the device is on and also generate the channel names according to the current level the user is loaded into. Next, you need to go into your PubNub admin console and get your Pub/Sub keys and replace them with the demo keys here. After the PubNub API is initialized, we subscribe to messages sent on whatever level we are currently on. The first part of the function window.createMyPubNub = function (currentLevel) {
window.globalCurrentLevel = currentLevel; // Get the current level and set it to the global level
window.currentFireChannelName = 'realtimephaserFire2';
window.currentChannelName = `realtimephaser${currentLevel}`; // Create the channel name + the current level. This way each level is on its own channel.
let checkIfJoined = false; // If player has joined the channel
// Setup your PubNub Keys
window.pubnub = new window.PubNub({
publishKey: 'demo',
subscribeKey: 'demo',
uuid: window.UniqueID,
});
// Subscribe to the two PubNub Channels
window.pubnub.subscribe({
channels: [window.currentChannelName, window.currentFireChannelName],
withPresence: true,
}); There is plenty of more code in the // If person leaves or refreshes the window, run the unsubscribe function
window.addEventListener('beforeunload', () => {
navigator.sendBeacon(`https://pubsub.pubnub.com/v2/presence/sub_key/mySubKey/channel/ch1/leave?uuid=${window.UniqueID}`); // pub
window.globalUnsubscribe();
}); We then create the // Unsubscribe people from PubNub network
window.globalUnsubscribe = function () {
try {
window.pubnub.unsubscribe({
channels: [window.currentChannelName, window.currentFireChannelName],
withPresence: true
});
window.pubnub.removeListener(window.listener);
} catch (err) {
// console.log(err);
}
};
window.pubnub.addListener(window.listener);
}; Next we are going to create the window.sendKeyMessage = (keyMessage) => {
try {
if (window.globalMyHero) {
window.pubnub.publish({
message: {
uuid: window.UniqueID,
keyMessage,
position: window.globalMyHero.body.position,
frameCounter: window.frameCounter
},
channel: window.currentChannelName,
sendByPost: false, // true to send via posts
});
}
} catch (err) {
console.log(err);
}
};
window.fireCoins = () => {
const message = {
uuid: window.UniqueID,
coinCache: window.globalLevelState.coinCache,
currentLevel: window.globalCurrentLevel,
time: window.globalLastTime
};
window.pubnub.fire(
{
message,
channel: window.currentFireChannelName,
sendByPost: false, // true to send via posts
});
}; After this code has been executed, the loadingState.jsAll the window.LoadingState = { // Create an object with all of the loading information inside of it
init() {
// keep crispy-looking pixels
this.game.renderer.renderSession.roundPixels = true; // Make the phaser sprites look smoother
},
preload() {
this.game.stage.disableVisibilityChange = true;
// Load JSON levels
this.game.load.json('level:0', 'data/level00.json');
this.game.load.json('level:1', 'data/level01.json');
this.game.load.json('level:2', 'data/level02.json');
this.game.load.image('font:numbers', 'images/numbers.png');
this.game.load.image('icon:coin', 'images/coin_icon.png');
this.game.load.image('background', 'images/bg.png');
this.game.load.image('invisible-wall', 'images/invisible_wall.png');
this.game.load.image('ground', 'images/ground.png');
this.game.load.image('grass:8x1', 'images/grass_8x1.png');
this.game.load.image('grass:6x1', 'images/grass_6x1.png');
this.game.load.image('grass:4x1', 'images/grass_4x1.png');
this.game.load.image('grass:2x1', 'images/grass_2x1.png');
this.game.load.image('grass:1x1', 'images/grass_1x1.png');
this.game.load.image('key', 'images/key.png');
this.game.load.spritesheet('decoration', 'images/decor.png', 42, 42);
this.game.load.spritesheet('herodude', 'images/hero.png', 36, 42);
this.game.load.spritesheet('hero', 'images/gameSmall.png', 36, 42);
this.game.load.spritesheet('coin', 'images/coin_animated.png', 22, 22);
this.game.load.spritesheet('door', 'images/door.png', 42, 66);
this.game.load.spritesheet('icon:key', 'images/key_icon.png', 34, 30);
this.game.load.audio('sfx:jump', 'audio/jump.wav');
this.game.load.audio('sfx:coin', 'audio/coin.wav');
this.game.load.audio('sfx:key', 'audio/key.wav');
this.game.load.audio('sfx:stomp', 'audio/stomp.wav');
this.game.load.audio('sfx:door', 'audio/door.wav');
this.game.load.audio('bgm', ['audio/bgm.mp3', 'audio/bgm.ogg']);
},
create() {
this.game.state.start('play', true, false, { level: window.globalCurrentLevel }); // Start Game
}
}; playState.js
const keyStates = {};
let keyCollected = false;
window.frameCounter = 0;
function logCurrentStateCoin(game, coin) {
// Log Current Game State of Collected Coins
for (const value of window.globalLevelState.coinCache.coins) {
if (coin.x === value.x) {
window.globalLevelState.coinCache.coins.splice(window.globalLevelState.coinCache.coins.indexOf(value), 1);
// console.log(value)
}
}
window.fireCoins();
// console.log(window.globalLevelState.coinCache.coins)
} The |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论