Wednesday 1 September 2010

HTML5 Canvas iPhone Level Editor

So I've been working on and off on a Syndicate style birds eye view shooter, just as an excuse to mess around with AI again.

When going on to creating the actual game map, usually I'd hard-coding everything (I see things easier in code). However, this time since I had an actual artist (non-programmer artist) create the base ground texture. Placing buildings to conform to an artists texture would be a pain, especially because maths and uniformity doesn't mesh with art. So yesterday I decided to quickly mock up a level editor using everyone's favourite new buzz word 'HTML5'.

All it does is simply draw the ground texture on a webpage using the canvas tag, then allows you to draw rectangles over the image. These rectangles are then exported out as an xml file. The xml file is then read by the game, and buildings are placed in position and to proportion of the rectangles created.

It's simple, it works, and since the level editor is web based, it should be relatively easy to release it alongside the game (if it ever gets done) for gamers to produce and play maps of their own.. I'll keep you updated.



1:  <xml> 
2:   <building x="0.5006934812760055" y="0.49791955617198336" w="0.13592233009708737" h="0.130374479889043"> 
3:   </building> 
4:   <building x="0.2725381414701803" y="0.326629680998613" w="0.07350901525658807" h="0.0651872399445215"> 
5:   </building> 
6:   <building x="0.32177531206657417" y="0.573509015256588" w="0.07489597780859916" h="0.07628294036061026"> 
7:   </building> 
8:   <building x="0.6276005547850207" y="0.651872399445215" w="0.17614424410540916" h="0.022191400832177532"> 
9:   </building> 
10:   <building x="0.651872399445215" y="0.4098474341192788" w="0.027739251040221916" h="0.14008321775312066"> 
11:   </building> 
12:   <building x="0.7371705963938974" y="0.30374479889042993" w="0.04022191400832178" h="0.05547850208044383"> 
13:   </building> 
14:   <building x="0.6900138696255201" y="0.04299583911234397" w="0.3536754507628294" h="0.030513176144244106"> 
15:   </building> 
16:   <building x="0.3765603328710125" y="0.9251040221914009" w="0.05409153952843273" h="0.05547850208044383"> 
17:   </building> 
18:   <building x="0.46393897364771153" y="0.9299583911234397" w="0.04299583911234397" h="0.03467406380027739"> 
19:   </building> 
20:   <building x="0.17614424410540913" y="0.9112343966712898" w="0.04160887656033287" h="0.08599167822468794"> 
21:   </building> 
22:   <building x="0.06726768377253814" y="0.782246879334258" w="0.04854368932038835" h="0.033287101248266296"> 
23:   </building> 
24:   <building x="0.07420249653259361" y="0.8550624133148405" w="0.05409153952843273" h="0.0319001386962552"> 
25:   </building> 
26:   <building x="0.06796116504854369" y="0.934119278779473" w="0.052704576976421634" h="0.04854368932038835"> 
27:   </building> 
28:   <building x="0.07004160887656033" y="0.6761442441054092" w="0.04854368932038835" h="0.05409153952843273"> 
29:   </building> 
30:   <building x="0.07420249653259361" y="0.5235783633841886" w="0.04854368932038835" h="0.04854368932038835"> 
31:   </building> 
32:   <building x="0.12135922330097088" y="0.42718446601941745" w="0.04576976421636616" h="0.033287101248266296"> 
33:   </building> 
34:   <building x="0.13106796116504854" y="0.07420249653259361" w="0.13730929264909847" h="0.05409153952843273"> 
35:   </building> 
36:   <building x="0.9361997226074896" y="0.7281553398058253" w="0.05547850208044383" h="0.1636615811373093"> 
37:   </building> 
38:  </xml> 


1:  void Scene03Game::loadBuildings(const char *filename) 
2:  { 
3:       const float height = 10.0f; 
4:        
5:       // Parse xml config file 
6:       XMLDocument *xml = new XMLDocument(); 
7:       if( xml->load( filename ) ) 
8:       { 
9:            // Get root node 
10:            XMLNode *xmlRoot = xml->getRoot(); 
11:            if( xmlRoot != NULL ) 
12:            {      
13:                 // Parse xml data 
14:                 xmlRoot = xmlRoot->getRoot(); 
15:                 while( xmlRoot != NULL ) 
16:                 { 
17:                      if( xmlRoot->tagIs( "building" ) ) 
18:                      { 
19:                           XMLNode *xmlBuilding = xmlRoot; 
20:                           { 
21:                                float x = xmlBuilding->attributeFloat( "x", 0.0f ); 
22:                                float z = xmlBuilding->attributeFloat( "y", 0.0f ); 
23:                                float width = xmlBuilding->attributeFloat( "w", 0.0f ); 
24:                                float depth = xmlBuilding->attributeFloat( "h", 0.0f ); 
25:                                 
26:                                x *= ground->collisionBounds.x * 2.0f; 
27:                                x -= ground->collisionBounds.x; 
28:                                 
29:                                z *= ground->collisionBounds.z * 2.0f; 
30:                                z -= ground->collisionBounds.z; 
31:                                 
32:                                const float hWidth = width * ground->collisionBounds.x; 
33:                                const float hDepth = depth * ground->collisionBounds.z; 
34:                                 
35:                                const float additionalHeight = (float)( rand() % 10 ); 
36:                                const int texture = rand() % 7; 
37:                                 
38:                                ObjectBuilding *building = new ObjectBuilding( hWidth, hDepth, ( height + additionalHeight ) * 0.5f, texture_building1+texture ); 
39:                                building->setPositionXZ( x, z ); 
40:                                building->setScene( this ); 
41:                                gEngine->collideables->nodeNetwork->addCollideable( building ); 
42:                           } 
43:                      } 
44:                      xmlRoot = xmlRoot->next(); 
45:                 } 
46:            } 
47:       } 
48:       delete xml; 
49:  }  

Note, if anyone else out there thinks they might have use for a web based editor, let me know and I can try extending it to suit more than my needs.

3 comments:

  1. This is awesome Ash!
    As I said, I think you should become the next WebGL developer in Orange!

    You have both skills needed:
    - HTML and JS for you is like "panecake"
    - You see code in 3D (better than Neo that was 2D with Parallax effect :P)

    ReplyDelete
  2. Thanks Ivan, as I said, I think you should become the next .Net developer at Microsoft!

    You have both skills needed:
    - Self respect
    - Love of Internet Explorer 6

    ReplyDelete
  3. Hi,
    excellent code posted,
    Thanks for sharing such a helpfull code.

    ReplyDelete