I am building an asset loader for a simple Object-Oriented game engine in HTML5. Right now I know of two ways to make the asset loader (summarized below) and I prefer the second approach. My question is, is the second way guaranteed to always work for all browsers?
For clarity:
the name of the class in question is AssetLoader,
the method to load all assets is called loadAssets(),
the main class is Game,
and the main game loop is runGameloop().
Approach 1
Create an instance of AssetLoader that will persist throughout the entire game. When loadAssets() is called at game start, it will create a dictionary that will hold key/value pairs of all the assets for the duration of playtime.
When a sprite requires an image, it will query AssetLoader with a given name (ex. "Archer"), and the instance will return the appropriate image for the sprite to use.
Approach 2
Create an instance of AssetLoader that will not persist throughout the game (it will be called once and not be assigned to any instance variables).
The instance's responsibility will be to query the server for each asset which will cause the browser to cache the assets; much like:
function AssetLoader()
{
...
self.loadAssets = function(runGameloop)
{
self.tempImage = new Image();
$(self.tempImage).load(function()
{
self.assetsLoadedSoFar += 1;
if(self.assetsLoadedSoFar === self.totalAssets)
{
self.runGameloop();
}
});
self.tempImage.src = "assets/sprites/archer/archerSpriteSheet.png";
}
...
}
Now whenever a sprite needs an image, that image should now be cached in the browser and it just loads it with a new Image() object without going through AssetLoader.
Why I prefer approach 2
1.) I want to avoid introducing unnecessary layers of abstraction to the engine, I don't want to have to go through AssetLoader everytime I want to load an asset.
2.) If I have alot of assets in the game, I don't want them all to be simultaneously loaded in a single instance of AssetLoader. Perhaps someone can correct me but wouldn't having all those resources loaded at once unnecessarily strain the game?
So right now I have a working version of Approach 2 here and am mostly happy with it but what I need to know is: "is the browser guaranteed to always cache a given image using approach two?" or is that something I can't rely on? Are there certain configurations in which automatic caching might be turned off? (is that even possible?). Do you have any other approaches you think are better? Thanks alot for your time!
I don't think you can rely on the browser cache. It is possible to disable automatic caching and I imagine it is reasonably common for people to do just that.
I've done exactly this in the past for two reasons:
Low disk space on a computer shared by the family (multiple separate accounts)
When developing, in order to ensure that the latest changes are always visible on page refresh
Also, caching is disabled in incognito / private browsing modes of Chrome / Firefox.
Related
I am working on a Wysiwyg Editor for CesiumJS content.
The user will be able to create many points, lines and other graphics, connect them according to definable relations and group them in separate Groups.
Now I am wondering what the best practises are in terms of performance.
At the moment I create one PointPrimitiveCollection for each Group
and then add points:
group.points = scene.primitives.add(new Cesium.PointPrimitiveCollection());
and then
group.points.add({
position : cartesian,
...
});
for each new point.
Polygons are created using:
network.hull_polygon = viewer.entities.add({
name : 'xxx',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray(points_array),
material : color,
...
}
});
polylines similarly.
Now since the Objects can also be dragged around / animated, I was wondering where Cesiums entity logic would come in?
Thanks for all help!
Cesium's Entity logic is useful primarily for objects that move along a known path over time, for example the flight plan of an aircraft in the future, or a GPS recording of the route taken by a vehicle in the past. Such routes can be loaded into the Entity system (often via CZML), and the user can run the simulation time forwards and backwards at arbitrary speeds, to review the routes of all the vehicles. The Entity system owns the logic for updating graphics primitive positions based on simulation time changes.
Entities are also often used as a quick way to make some disparate graphics primitives associate with each other. For example, a polygon, a point, and a label can all be created as a single Entity even if they are three separate graphics primitives at the same location. This saves a bit of effort on the part of the application developer, and doesn't hurt performance too much since the properties involved are all marked as constants, so the Entity layer knows not to update them with simulation time.
But, it sounds like you may have a case where paths are not known in advance. For things like user interactive edits or real-time telemetry being received, the Entity system can't know what's coming up next, so its whole system for updating positions from simulation times is not doing you any good. In that case it may be better to skip the Entities, and deal exclusively with graphics primitives for this. This would mean you need to write your own update function to alter graphics positions as new information is being received, similar to the Entity layer's update functions, but based on your own live inputs instead of recorded paths.
Note that the public "Sandcastle" demos only include Entity demos. But, if you download and build the source for Cesium and run Sandcastle locally from a dev build, a separate tab appears in the Sandcastle Gallery called Development that shows a whole set of demos based on graphics primitives as opposed to Entities. This can be useful for seeing examples of how to control things at this layer.
Hopefully this is helpful in understanding how the different layers of Cesium interact.
I'm fairly new to multiplayer design and am struggling to find the information i need to continue in my synchronous (you cannot disconnect and continue at a later time similar to hearthstone), turn-based, pvp "card" game. I'm using AS3 (flash) as my client side and node.js with javascript + mysql for the server-side processing.
In this game, the cards are created by the players themselves. It's importnat to note that these "cards" are assembled from individual building blocks (library swf files); The database keeps track of how these cards are made/assembled. Because there can be hundreds of uniqely made cards per player, i need a good way to load information about these on demand for pvp battles or for modding/deck building purposes.
What i've accomplished so far:
i have successfully sent data to server and sent data back to flash over an XMLSocket.
I have successfully assembled a single "card" from database information.
What questions i really need to answer:
Flash asynchronously loads content so i'm not sure how to approach making multiple data requests for (sometimes simultaneous) battle actions, card information, or card assembly (THere can potentially be a lot of cards and card building blocks so i feel it would be inefficient to load all data with a single request). I can either have the classes responsible make those calls OR create a messenger class to handle all requests/disconnects/reconnects/messages for the entire game.
For the global messenger class approach, I am not sure how to retrieve the fully loaded data from the messenger by upstream code (as3 continues execution even if data isnt there) or how to ensure that the request pertains to the appropriate call
i could use a ID request system to uniquely identify the socket request
i could develop a custom event driven system
I could spawn multiple messenger objects in each class that i need one. <- im leaning towards this option.
On a similar note, perhaps i should handle database requests within card objects or preload all data prior to game start (This would limit me to only query for opponent card and battle data on the fly). With the one call per card object approach I was unsure if #requests per card per player will overwhelm my server or not. Node.js scales very well but i dont have the networking knowledge to understand whether all these simultaneous request on a single port would be too much.
EDIT:
I'm strongly leaning towards using a singleton XMLSocket Wrapper or an extended class of some sort to deal with all networking transactions since that seems intuitive to me. I would highly appreciate your feedback on the best approach to notify my code that the messenger received and parsed the message it asked for (since flash will proceed with execution even if data isnt there i need a good way to do this.). I read that using custom events isnt all that terrific and there are better ways... but this is how i'd approach the problem.
For example i can do (pseudocode).
m:Messenger = new Messenger(); //this is my wrapper
m.addEventListener(new CustomEvent(CustomEvent.EVENTSTRING, parseData));
m.sendData(DataObject); //calls
function parseData(e:CustomEvent) {
xml(e.data);
}
import flash.net.XMLSocket;
import globals.*;
public class Messenger
{
public static var _Socket:XMLSocket;
public var xml:XML;
public function Messenger()
{
_Socket = new XMLSocket(vars._Server, vars._Port);
_Socket.addEventListener(Event.CONNECT, onConnect);
_Socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
}
private function onConnect(evt:Event):void {
trace("Connected");
_Socket.removeEventListener(Event.CONNECT, onConnect);
_Socket.removeEventListener(IOErrorEvent.IO_ERROR, onError);
_Socket.addEventListener(DataEvent.DATA, onDataReceived);
_Socket.addEventListener(Event.CLOSE, onSocketClose);
}
private function onDataReceived(evt:DataEvent):void {
//trigger correct event here based on data identifier w/ dispatchEvent(EVENTSTRING);
}
}
About card assembly - you should store data in database that does not require recalculation, so if a card is built out of several "building blocks", you could, for example, store a sequence of blocks in a single line of database, so that when a card info for the opponent is retrieved, you just select from player_cards where player_id=... and deck_id=... and then assemble the gathered data on AS3 side. You should definitely not put this load on server.
About asynchronous loading - make sure your PVP handshake waits for both sides to successfully process cards for both own side and enemy side. You can load data asynchronously, but you'd better do a full preload while displaying a "Loading bla-bla" screen to the player, then operate with received data. Yes, you can do multiple requests to your server, and yes, you can wait for all of them to success prior to displaying a "Battle start" screen, in the meantime AS3 will wait for the loading to complete. But, about single vs multiple request - I say go with as few as possible, because every added request at the init stage is a potential to add a thousand or so requests to a single server, and a potential to put just too much strain on your server side, resulting in a self-initiated DDoS. Make sure your database structure allows streamlining of data reading operation right into the client side, so that your server is not under a heavy load from preparing the data. But also make sure to double check whatever clients report to the server, as the primary rule of client-server games is "client always lies" assumption.
Since you are planning to make server process player actions mid-battle, you can create either temporary tables on the server (SQL-based) or state objects (process-based) that will contain current game state with links to whatever abilities the cards have and their state (in hand, discarded, in play, destroyed, etc), so that when an action from the player comes, saying "this card changes state from A to B" you can easily verify if that card is in A state, then switch it into B state, performing any actions that result from this state change on both server and client sides. Make sure to clean up this set of data once the battle is over. This requires thorough planning of your server side, so that your game engine will not stall the server while running some action sequence due to excess SQL requests, for example.
About messengers - probably you should use a session approach, together with login/password authentication this way you will have sessions available as keys to determine which battle does this data packet belongs. I think also make AS3 side periodically send pull requests to the server, which should be quickly parsed by the server and the submitted enemy/server actions returned as quickly as possible, this will also ensure that disconnects will be handled and reconnects allowed.
Overall, the question is very broad, and only tips can be given, not even examples.
What are the pros and cons of using a singleton class for sound management?
I am concerned that it's very anti-OOP in structure and don't want to potentially get caught up going down the wrong path, but what is a better alternative?
It's an awkward topic but I'd say that a sound manager style class is a good candidate for a class that should not be initialized.
Similarly, I would find it OK if a keyboard input manager style class was a completely static class.
Some notes for my reasoning:
You would not expect more than one instance that deals with all sounds.
It's easily accessible, which is a good thing in this case because sound seems more like an application-level utility rather than something that should only be accessed by certain objects. Making the Player class for a game static for example would be a very poor design choice, because almost no other classes in a game need reference directly to the Player.
In the context of a game for example, imagine the amount of classes that would need a reference to an instance of a sound manager; enemies, effects, items, the UI, the environment. What a nightmare - having a static sound manager class eliminates this requirement.
There aren't many cases that I can think of where it makes no sense at all to have access to sounds. A sound can be triggered relevantly by almost anything - the move of the mouse, an explosion effect, the loading of a dialogue, etc. Static classes are bad when they have almost no relevance or use to the majority of the other classes in your application - sound does.
Anyways; that's my point of view to offset the likely opposing answers that will appear here.
They are bad because of the same reasons why globals are bad, some useful reading :
http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx
A better alternative is to have it as a member of your application class and pass references of it to only modules that need to deal with sound.
"Managers" are usually classes that are very complex in nature, and thus likely violate the Single Responsibility Principle. To paraphrase Uncle Bob Martin: Any time you feel yourself tempted to call a class "Manager" of something - that's a code smell.
In your case, you are dealing with at least three different responsibilities:
Loading and storing the sounds.
Playing the sounds when needed.
Controlling output parameters, such as volume and panning.
Of these, two might be implemented as singletons, but you should always be very careful with this pattern, because in itself, it violates the SRP, and if used the wrong way, it causes your code to be tightly coupled (instead, you should use the Dependency Injection pattern, possibly by means of a framework, such as SwiftSuspenders, but not necessarily):
Loading and storing sounds is essentially a strictly data related task, and should thus be handled by the SoundModel, of which you only need one instance per application.
Controlling output parameters is something that you probably want to handle in a central place, to be able to change global volume settings, etc. This may be implemented as a singleton, but more likely is a tree-like structure, where a master SoundController handles global settings, and several child SoundControllers are responsible for more specific contexts, such as UI sound effects, game sounds, music, etc.
Playing the sound is something, which will occur in many places, and in many different ways: There may be loops (to which you need to keep references to be able to stop them later), or effect sounds (which are usually short and play only once), or music (where each song is usually played once, but needs subsequent songs to be started automatically, when the end is reached). For each of those variations (and whichever ones you come up with), you should create a different class, which implements a common SoundPlayer interface, e.g. LoopSoundPlayerImpl, SequentialSoundPlayerImpl, EFXSoundPlayerImpl, etc. The interface should be as simple as play(),pause(), rewind() - you can easily exchange those later, and will not have any problems with tightly coupled libraries.
Each SoundPlayer can hold a reference to both the master SoundController an its content-specific one, as well as - possibly - the SoundModel. These, then can be static references: Since they are all parts of your own sound plugin, they will usually be deployed as a package, and therefore tight coupling won't do much damage here - it is important, though, not to cross the boundary of the plugin: Instantiate everything within your Main partition, and pass on the instances to all classes, which need them; only have the SoundPlayer interface show up within your game logic, etc.
I am creating an interactive flash application where I need to use many sound files and images. I am currently loading resources (both images and sound files) as I need them. When I run it on my computer everything works fine and I see no delay. Running it on an offsite computer shows pauses and delays. I know this is due to the time it takes to load the resources.
I want to know what the best practice for loading resources is. Should I preload everything in the beginning (which will create a considerable pause)? Is it better to have a short pause multiple times throughout when a new resource is needed? Or is there a better solution (I hope this is the case)?
I have been programming in AS3 for about 3 months so I am relatively new. I'm sorry if this question is really noob, but I do need to figure out what to do about the delays.
It depends on what kind of application it is:
If you expect a user to go through your whole application anyway (like a game for example) you should do preload the resources. If your application is more like a media player or an image gallery where most users will only see a few resources, you should load resources on demand.
It also depends on how large the resources are. You shouldn't let users wait to long or create to much traffic. On the other hand it may be easier to do a single preload than loading each tiny resources in a single request. Maybe you coulddefine larger sets to in a single step to avoid this. You may even combine both methods: preload some common resources and load some other stuff in the background.
I agree with #kapep that you should pre-load commonly used resources at the beginning. If there are large resources that the user may not need you could load those on demand.
If this test is sequential you could load "test question 2" material right after "test question 1" starts. You can load asynchronously so the application is still interactive (user can interact with test question 1) while more material is being loaded (test question 2 resources).
For preloading the resources I strongly recommend using Greensock library. Actually by using LoaderMax you can queue the content to be loaded and then attach the loaded content to the containers (movieclips, sprites etc.)
Here is a sample code for loading multiple resources:
var queue:LoaderMax = new LoaderMaxVars()
.maxConnections(1)
.onProgress(onContentProgress)
.onIOError(onIOErrorHandler)
.onComplete(onContentLoaded));
queue.append(new SWFLoader(contentTobeLoaded,new SWFLoaderVars().name(loaderName)));
....
private function onEmployeeContentLoaded(event:LoaderEvent):void {
var loadedContent:Array = (event.target as LoaderMax).content;
....
I'd like to start developing a "simple" game with HTML5 and I'm quite confused by the many resources I found online. I have a solid background in development, but in completely different environments (ironically, I started programming because I wanted to become a game developer, and it's the only thing I've never done in 13 years...).
The confusion derives from the fact that, although I know JavaScript very well and I have some knowledge of HTML5, I can't figure out how to mix what I know with all this new stuff. For example, here's what I was thinking of:
The game would be an implementation of chess. I have some simple "ready made" AI algorithm that I can reuse for single player; the purpose here is to learn HTML5 game development, so this part is not very important at the moment.
I'd like build a website around the game. For this I'd use a "regular" CMS, as I know many of them already and it would be faster to put it up.
Then I'd have the game itself, which, in its "offline" version, has nothing to do with the website, as, as far as I understand, it would live in a page by itself. This is the first question: how to make the Game aware of User's session? The login would be handled by the CMS (it should be much easier this way, as User Managememt is already implemented).
As a further step, I'd like to move the AI to the server. This is the second question: how do I make the game send player's actions to the Server, and how do I get the answer back?
Later on, I'd like to bring a PVP element to the game, i.e. one-against-one multiplayer (like the good old chess). This is the third question: how to send information from a client to another, and keep the conversation going on. For this, people recommended me to have a look at Node.js, but it's one more element that I can't figure out how to "glue" to the rest.
Here's an example of a single action in a PVP session, which already gives me a headache: Player 1 sends his move to the Server (how does the game talk to Node.js?). I'd need to identify the Game Id (where and how should I store it?), and make sure the player hasn't manually modified it, so it won't interfere with someone else's game (how?).
I'm aware that the whole thing, as I wrote it, is very messy, but that's precisely how I feel at the moment. I can't figure out where to start, therefore any suggestion is extremely welcome.
Too many things and probably in the wrong order.
A lot of the issues don't seem to me to be particularly related to HTML5 in the first instance.
Start with the obvious thing - you want a single page (basically a javascript application) that plays chess, so build that. If you can't build that then the rest is substantially irrelevant, if you can build (and I don't doubt that you can) then the rest is about building on that capability.
So we get to your first question - well at the point at which you load the page you will have the session, its a web page, like any other web page, so that's how you get the session. If you're offline then you've persisted that from when you were online by whatever means - presumably local storage.
You want to move the AI to the server? Ok, so make sure that the front end user interaction talks to an "interface" to record the player moves and retrieve the AI moves. Given this separation you can replaces the AI on the client with an ajax (although I'd expect the x to be json!) call to the server with the same parameters.
This gets better, if you want to do player to player you're just talking about routing through the server from one user/player to another user/player - the front end code doesn't have to change, just what the server does at the far end of the ajax call.
But for all this, take a step back and solve the problems one at a time - if you do that you should arrive where you want to go without driving yourself nuts trying to worry about a bucket full of problems that seem scary that you can probably easily solve one at a time and I'd start by getting your game to run, all on its own, in the browser.
About question one: You could maybe give the user a signed cookie. E.g. create a cookie that contains his userid or so and the SHA2 hash of his userid plus a secret, long salt (e.g. 32 bytes salt or so).
About question two: For exchanging stuff and calling remote functions, I'd use the RPC library dnode.
About question three: Use the same thing for calling methods between clients.
Client code (just an example):
DNode.connect(function (remote) {
this.newPeer = function(peer) {
peer.sendChatMessage("Hello!");
};
});
You don't have to use game IDs if you use dnode - just hand functions to the browser that are bound to the game. If you need IDs for some reason, use a UUID module to create long, random ones - they're unguessable.