HTML5 Game (Canvas) - UI Techniques? - javascript

I'm in the process of building a JavaScript / HTML5 game (using Canvas) for mobile (Android / iPhone/ WebOS) with PhoneGap. I'm currently trying to design out how the UI and playing board should be built and how they should interact but I'm not sure what the best solution is. Here's what I can think of -
Build the UI right into the canvas using things like drawImage and fillText
Build parts of the UI outside of the canvas using regular DOM objects and then float a div over the canvas when UI elements need to overlap the playing board canvas.
Are there any other possible techniques I can use for building the game UI that I haven't thought of? Also, which of these would be considered the "standard" way (I know HTML5 games are not very popular so there probably isn't a "standard" way yet)? And finally, which way would YOU recommend / use?
Many thanks in advance!
EDIT
I've moved this question over to gamedev.stackoverflow.com. You can find the new question here: https://gamedev.stackexchange.com/questions/7090/html5-game-canvas-ui-techniques/7115#7115

You can do it a million ways. However you feel most comfortable and your engineers feel most confident.
If you're looking for inspiration or a code example, here's one way that I do it. I have a function that repeatedly draws a menu until a button is pressed. When the button is pressed, the game loads and the old menu click event listeners are removed and new game click event listeners are added. I also end the old draw loop of the menu and start a new game draw loop. Here's some selected snippets to give you the idea of how its done:
Game.prototype.loadMenu = function() {
var game = this;
var can = this.canvas;
// now we can use the mouse for the menu
can.addEventListener('click', game.menuClickEvent, false);
can.addEventListener('touchstart', game.menuClickEvent, false);
// draw menu
this.loop = setInterval(function() { game.drawMenu() }, 30);
};
Game.prototype.drawMenu = function() {
// ... draw the menu
}
Game.prototype.loadLevel = function(levelstring) {
// unload menu
var can = this.canvas;
var game = this;
can.removeEventListener('click', game.menuClickEvent, false);
can.removeEventListener('touchstart', game.menuClickEvent, false);
if (this.loop) clearInterval(this.loop);
// ... other level init stuff
// now we can press keys for the game
//can.addEventListener('click', game.gameClickEvent, false);
can.addEventListener('touchstart', game.gameClickEvent, false);
can.addEventListener('keydown', game.gameKeyDownEvent, false);
this.loop = setInterval(function() { game.tick() }, 30);
}
// called from tick()
Game.prototype.draw = function(advanceFrame) {
// ...
}
This way I'm able to separate out game drawing and game events from menu drawing and menu events. It also gives me leeway to use game/animation elements in my menus should I want to make them look real pretty.
(I posted this at the twin gamedev discussion too)

I do not think that there is a "standard" for this. It highly depends on your UI. I think using the DOM elements is better in most cases, since you do not need to build all of the UI components, events, etc. yourself. They can be styled with CSS to achieve the desired look. If this is not enough, you'll probably need to build the interface elements yourself, but you should make sure that this is really needed. It is probably a huge amount of work to roll your own solution.

Try this :
With Visual js you can setup page like this :
Visual-JS multiplatform game engine windows GUI - source editor
OnPage editor - for design
You will get :
*99% canvas 2d
Add new object
Create webcam component (nui or normal)
Create coallision (basic - rect)
Create textBox (virtual keyboard for mobile)
Create particle
Atach player (basic movement)
MultipEER (Networking)*
localStarage
App created from visual js always work on all browsers(mobile / desktop). Networking - webRTC - multipeer
Try online at :
https://jsfiddle.net/user/zlatnaspirala/fiddles/
Api look like this :
Application Programming Interface Documentation for Visual JS 0.5 >
GAME_OBJECT is main object in this framework.
1) Adding new game object (name will be 'GO' ):
HELLO_WORLD.ENGINE.MODULES.ACCESS_MODULE("STARTER").NEW_OBJECT("GO" ,
x , y , w , h , speed )
HELLO_WORLD.ENGINE.MODULES.ACCESS_MODULE("STARTER").NEW_OBJECT( "GO" ,
45 , 45 , 10 , 10 , 10)
// 2) Adding image or animation :
// DRAW TYPE can be // 'DRAW_FRAME' no animation // 'LOOP' playing
animation // this number '1111123123' is ID can be any number
//ANIMATION ( surf ,TYPE_, FrameIndex ,source , PARENT , ID , blink_
, min_ , max_ , step , speed_ , opacity_ )
HELLO_WORLD.ENGINE.MODULES.ACCESS_MODULE("STARTER").GAME_OBJECTS.ACCESS("GO").CREATE_ANIMATION(
SURF , "DRAW_FRAME" , 6 , RESOURCE.Tiles , 1111123123 , "no" ,
1,11,1,1,1)
3)Disable draging GO.DRAG = false;
// RESOURCE.NAMEOFFOLDERANIMATION
add folder "Tiles" with images in folder /res/ and run node res.js
// refresh page and you will get
RESOURCE.Tiles ready for use !
// MAKE MODULE ACCESS EASY var
STARTER = HELLO_WORLD.ENGINE.MODULES.ACCESS_MODULE("STARTER");
STARTER.GAME_OBJECTS.ACCESS("GO").CREATE_ANIMATION( SURF ,
"DRAW_FRAME" , 6 , RESOURCE.Tiles , 1111123123 , "no" , 1,11,1,1,1)
//DRAG initial value is true GO.DRAG = false;
//setup quard height = width GO.POSITION.DIMENSION.H = GO.POSITION.DIMENSION.W;
4) EVENTS FOR MOUSE AND MOBILE TOUCH HANDLED
//CLICK OR TOUCH START GO.TAP = function(){
//this make point directing to the game object instance
// this.NAME or this.ANIMATION.CURRENT_FRAME };
GO.TOUCH_DOWN = function(){
STARTER.DESTROY_OBJECT("GO") console.log("THIS MUST BE TERMINATED
ON MOUSE DOWN or TOUCH_DOWN : " + this.NAME);
//this.DESTROY_ME_AFTER_X_SECUND( 100 ); //console.log("THIS MUST BE
TERMINATED ON CLICK : " + this.NAME); };
GO.TOUCH_MOVE = function(){
console.log("HOVER ON OBJECT OR MOBILE TOUCH_MOVE : " + this.NAME); };
GO.TOUCH_UP = function(){
console.log("MOUSE UP ON OBJECT OR MOBILE TOUCH_UP : " + this.NAME); };*
Download git

Related

Does have instagram masks specified UI to chage the 3d objects instead changing textures only?

So i have 3 different, which contains different 3d objects with special animations.
First is 3d objects rotating above the head and change the angle of orbit with our head shakes. The second one is falling 2d sprites all around character calling by eye closing. And the third one is simple facemesh with grid texture on it. Im draw special UI and code it, so in ArPlayer it works perfects, but when im try to upload it to facebook this UI not working and i have only mask number 1.
So im try to search the solution on Youtube and have only this, but this works only with texture changing i think. So my question is: Can i use instagram changing ui with my effects and if yes, how i can do this. Thaks a lot!
P.S: All images u can find.
Effects must not use custom buttons, keyboards, pickers or sliders - effects may use the native UI picker and slider only. (Spark AR Review Policies 2.6)
Using the Native UI picker, you can not only change textures, but also the visibility of objects.
Example:
Create a new project
Create several plane objects on the scene (for example 3 pieces) and name them obj0,
obj1, obj2 and make them invisible
In Capabilities add Native UI -> Picker
Add 3 textures to the project and name them icon_1, icon_2, icon_3 and check the "No compression" option for everyone
Add such a script
const NativeUI = require('NativeUI');
const Textures = require('Textures');
const Scene = require('Scene');
Promise.all([
Textures.findFirst('icon_1'),
Textures.findFirst('icon_2'),
Textures.findFirst('icon_3'),
Scene.root.findFirst('obj0'),
Scene.root.findFirst('obj1'),
Scene.root.findFirst('obj2')
]).then(onReady);
function onReady(assets) {
const texture0 = assets[0];
const texture1 = assets[1];
const texture2 = assets[2];
const objects = [assets[3],assets[4],assets[5]];
const picker = NativeUI.picker;
const index = 0;
const configuration = {
selectedIndex: index,
items: [
{image_texture: texture0},
{image_texture: texture1},
{image_texture: texture2}
]
};
picker.configure(configuration);
picker.visible = true;
picker.selectedIndex.monitor({fireOnInitialValue:true}).subscribe(function(index) {
objects[index.newValue].hidden = false;
if(index.oldValue != undefined)
{
objects[index.oldValue].hidden = true;
}
});
}
A similar official example is from developers, there they used Native UI picker (script) + patch to hide objects. Launch Spark AR Studio and create new project from template "3D Stickers" and watch how they did it. If you don’t have such a project template, update Spark AR Studio.

ThreeJS, Websockets, and NodeJS Client/Server Experiment

I was toying with socket.io, ThreeJS, Javascript, and NodeJS to create a simple client/server using ThreeJS's graphics. I wasn't sure if all of these frameworks would even work together, but I decided to give it a shot since I've seen similar examples online before even though I cannot find a simple one to dissect or experiment with. It's mainly to experiment with, but I also wanted to make a small little concept-game as proof of what I've learned so far.
I posted my code here: https://gist.github.com/netsider/63c414d83bd806b4e7eb
Sorry if it's a little untidy, but I did my best to make it as readable as possible.
Basically, right now the server-side NodeJS script seems to run fine (Run with "node server-alpha.js"), and the client script (client-alpha.html, which you can just open in a browser) connects to the server, and displays a list of users (who are also connected). However, my intention was for each user to be able to move his/her own cube around, and right now each cube only gets added to the screen (rather than being added, subtracted, and then added again - to give the illusion of movement). If you run both pieces of code and connected one or two users and move the arrow keys a few times for each, you'll see what I'm talking about.
Can anybody help me with this? I tried several different ways to remove the cube (and remembered to call render(), after each)... but everything I tried didn't seem to work. It always resulted in the cubes just being added to the screen, and never subtracted.
I added comments in the code to make things a little easier, as I know this is quite a bit of code to go through (if it's not your own, anyway).
Thanks, any help would be greatly appreciated... as I'm really stuck trying to make the cubes just move.
Also, I'm having trouble adding the Fly-Controls (FlyControls.js - it's commented out ATM), so if someone could tell me where I went wrong I'd appreciate that a lot also.
Ok so you don't want to keep remaking the cubes, all you need to do is change the position.
Also in game development, it is almost a requirement to use object oriented design, a good way to go about this would be to make a player object, so..
CPlayerList = new Array(); // an array of player objects
function ClientPlayer()
{
this.Cube;
this.Name = "unnamed";
this.Id = 0;
this.Create = function(name,pos,id)
{
this.Name = name;
this.Id = id;
var cubeGeometry = new THREE.BoxGeometry(10, 10, 10);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 'red', transparent:false, opacity:1.0});
this.Cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
this.Cube.position.x = pos.x;
this.Cube.position.y = pos.y;
this.Cube.position.z = 20; // don't know why this is 20, remember y axis is up & down in opengl/threejs
scene.add(this.Cube);
}
this.Move = function(vector)
{
this.Cube.position.set(this.Cube.position.x + vector.x, this.Cube.position.y + vector.y, 20);
}
}
So on the server you need a ServerPlayer object which holds similar data, and assign ids on the server before sending them to the clients. So when you send it to the client you want to make a new ClientPlayer, call player.Create() and then push it to the CPlayerList, like so:
function newCPlayer(data)
{
var newPly = new ClientPlayer();
newPly.Create(data.name,data.pos,data.id);
CPlayerList.push(newPly);
}
Then when you call your movePlayer() function, you can simply loop through your players array
function movePlayer(keyStroke, clientID)
{
if (keyStroke == 39)
{
CPlayerList.forEach(function(player,i,a)
{
if(player.Id === clientID)
{
player.Move(new THREE.Vector3(1,0,0));
}
}
}
}
This is just the client code, but this should help you get started, let me know if there's anything you're unclear on.
Also here's an example of a game using a similar design: http://82.199.155.77:3000/ (ctrl+shift+j in chrome to view client sources) and server code: http://pastebin.com/PRPaimG9

Why cocos2d-js + chipmunk, only works with web build

I've implemented simple example based on this
My example uses chipmunk along with cocos2d-js.
The problem is that physic only works with web builds. With the other builds (native ones - ios, mac, win32) all object are shown but they just hang - no animation.
My update method is called with specified intervals, where I execute "step" method on space object.
All my sprites are loaded using PhysicSprite class.
PS: I'm using cocos2d-js v3.0alpha
Use this tutorial:
http://www.cocos2d-x.org/docs/tutorial/framework/html5/parkour-game-with-javascript-v3.0/chapter6/en
I tried it both in the browser and in the iphone simulator and it worked just fine.
you should apply impulse on your physics body, they will move surely but if you would try to move the body with schedular by changing its coordinate on every call they will work on web but not on native ones like iOS or mac .
for example:-
var mass = 1;
var width = 1, height = 1;
playerBody = new cp.Body(mass , cp.momentForBox(mass, width, height));
playerBody.applyImpulse(cp.v(200, 300), cp.v(0, 0));// now you can move your playerBody
it will work well on all the platform but if you try my alternate solution
ie:-
init: function{
var mass = 1;
var width = 1, height = 1;
this.playerBody = new cp.Body(mass , cp.momentForBox(mass, width, height));
this.schedule(this.move);
},
move: function(dt){
this.playerBody.getPos().x += 2 * dt;
this.playerBody.getPos().y += 2 * dt;
}
this will work on web but on native platform like iOS or mac it will not move the playerBody at all. i don't know the reason yet if i got one i will let you know

Multitouch Pinch, Pan, Zoom in HTML 5 Canvas

I have most of a module written to handle multitouch pinch, pan and zoom on an HTML 5 canvas element. I will share it below. I've been developing in JavaScript for some time now, and this one continues to boggle me. If anybody has any insights, I will post the final version up on stack for everybody to share once it is confirmed working on my iPad.
Here is what I am doing:
touchmove events trigger the changing of variables. I use these variables to change the way in which my image is painted onto the canvas. I have eight variables, each corresponding to the options that can be put into the drawImage() function. These eight variables get updated through functions that increment/decrement their values and keep them within a certain range. The variables are closure variables, so they are global throughout my module. To prevent over-processing, I make a call to this drawImage() function once every 40ms while the user has their finger pressed to the screen using a setInterval().
Here is the problem:
touchmove events seem to be causing a race condition where my variables get updated by many different instances of that same event. I can somewhat confirm this through my console output, that tracks one variable that is bounded to never reach below 20. When I swipe in one direction quickly, that variable dips down far below 20. Then when I release my finger, swipe slowly, it returns to 20. Another thing that points me in this direction, when I look at these variables while stepping through my program, they differ from what my console.log() pumps out.
Note: The code successfully draws the image the first time, but not anytime thereafter. A basic rendition of my code is below... The full version is on GitHub inside the Scripts folder. It is a Sencha Touch v1.1 app at heart
function PinchPanZoomFile(config)
{
/*
* Closure variable declaration here...
* Canvas Declaration here...
*/
function handleTouchStart(e) {
whatDown.oneDown = (e.originalEvent.targetTouches.length == 1) ? true : false;
whatDown.twoDown = (e.originalEvent.targetTouches.length >= 2) ? true : false;
drawInterval = setInterval(draw, 100);
}
function handleTouchEnd(e) {
whatDown.oneDown = (e.originalEvent.targetTouches.length == 1) ? true : false;
whatDown.twoDown = (e.originalEvent.targetTouches.length >= 2) ? true : false;
clearInterval(drawInterval);
}
function handleTouchMove(e) {
if(whatDown.twoDown) {
/*
* Do Panning & Zooming
*/
changeWindowXBy(deltaDistance); //deltaDistance
changeWindowYBy(deltaDistance); //deltaDistance
changeCanvasXBy(deltaX); //Pan
changeCanvasYBy(deltaY); //Pan
changeWindowDimsBy(deltaDistance*-1,deltaDistance*-1); //(deltaDistance)*-1 -- get smaller when zooming in.
changeCanvasWindowDimsBy(deltaDistance,deltaDistance); //deltaDistance -- get bigger when zooming in
} else if(whatDown.oneDown) {
/*
* Do Panning
*/
changeWindowXBy(0);
changeWindowYBy(0);
changeCanvasXBy(deltaX);
changeCanvasYBy(deltaY);
changeWindowDimsBy(0,0);
changeCanvasWindowDimsBy(0,0);
}
}
function draw() {
//Draw Image Off Screen
var offScreenCtx = offScreenCanvas[0].getContext('2d');
offScreenCtx.save();
offScreenCtx.clearRect(0, 0, canvasWidth, canvasHeight);
offScreenCtx.restore();
offScreenCtx.drawImage(base64Image,
parseInt(windowX),
parseInt(windowY),
parseInt(windowWidth),
parseInt(windowHeight),
parseInt(canvasX),
parseInt(canvasY),
parseInt(canvasWindowWidth),
parseInt(canvasWindowHeight)
);
//Draw Image On Screen
var offScreenImageData = offScreenCtx.getImageData(0, 0, canvasWidth, canvasHeight);
var onScreenCtx = canvas[0].getContext('2d');
onScreenCtx.putImageData(offScreenImageData, 0, 0);
}
}
I strongly recommend using Sencha Touch 2.0.1, as it supports a lot of the touch events you need. See http://dev.sencha.com/deploy/touch/examples/production/kitchensink/#demo/touchevents for examples.

KeyDown/KeyUp 70-120ms delay. How to reduce?

We're developing arcade (a lot of action and speed) browser 2d-game using canvas.
Sometimes our testing players report us that there is a delay: player still moving 5-10 pixels away after keyup.
I've digged this issue, you can see yourself delay http://jsfiddle.net/C4ev3/7/ (try keydown/up any key as fast as you can). My results is from 70 to 120ms. And i think that's a lot. (FYI, our network latency is 10-20ms).
Any ideas how to reduce this delay?
upd i've noticed that on good hardware this delay is under 30-40ms. But i'm testing on core2duo, winxp, chrome 19 - it's not a P4 with IE6 :)
Hi one thing you could do is instead of using an anonymous function try using defined functions,
http://jsfiddle.net/C4ev3/10/ - for me this reported at 50-100 MS
However i would not recommend jQuery for Canvas Applications it's very big for the very little you using, you should try using native Javascript
http://jsfiddle.net/C4ev3/11/ - for me this reported 30-70 MS
Javascript Threading
One thing i noticed in the comments Javascript is not Multi-Threaded Well Urm-Arr,
it sort of is setInterval is Async not Sync, however affecting the window is a single thread E.G if you have a Class that has some number is it using a setInteval will use another thread and not have a problem altering the math however in the Task then requires a Draw on the page it will enter the bottom of the JS handle Que,
Certain parts of Javascript are on a different thread how ever any thing changing the page has to run on the Main Thread same as any Windows application if your thread want to change the Form your have to invoke the main thread to do it for you
however it is not multi-threaded like any thing else you cant just handle or abort at a given Wim like windows,
Other ASync Tasks include AJAX has the option to be both Async and Sync
Updated to show my comment about FPS limiting:
Please bear with me. This is linking to a project that is allready built to show the example:
so my Game is Completely OOP
var elem = document.getElementById('myCanvas');
var context = elem.getContext("2d");
context.fillStyle = '#888';
context.lineWidth = 4;
// Draw some rectangles.
context.fillRect(0, 0, 800, 600);
context.fillStyle = '#f00';
var ball = new Ball();
var leftPadel = new Padel(10, 60, 40, 120);
var rightPadel = new Padel(750, 520, 40, 120);
pong = new Pong();
pong.draw();
setTimeout("ball.move()", pong.redrawTime());
Inside my pong class is where all the main workings of the game goes but here are the FPS bit you need to see
this.fps = 30;
this.maxFPS = 60;
this.redrawTime = function(){
return (1000 / this.fps)
}
this.lastDraw = (new Date)*1 - 1;
Then as you can see my Interval is on ball.move this calls the main pong class again on redraw at the End of the redraw i have the FPS checking and limiting code
this.fps = ((now=new Date) - this.lastDraw);
if(this.fps > this.maxFPS){
this.fps = this.maxFPS;
}
this.lastDraw = (new Date)*1 - 1;
if(this.reporting = true){
console.clear();
console.log("FPS: "+this.fps.toFixed(1))
}
setTimeout("ball.move()", pong.redrawTime());
This then forces you to get the Best Possible FPS without queuing the Main Thread
Try this:
e.stopPropagation()
Stops the bubbling of an event to parent elements, preventing any
parent handlers from being notified of the event.
e.preventDefault()
Prevents the browser from executing the default action. Use the method
isDefaultPrevented to know whether this method was ever called (on
that event object).
My min. results in Google chrome: 7ms

Categories