View Full Version : creating views(nodes) from js?
whisperstorm
10-15-2003, 11:36 AM
I'm working on a simple tile-based game and I want to allow folks to create "levels" with just a simple ascii format (wrapped in xml). But what this would mean is I have to find a way to take some data and dynamically create views from js. Is there some example of how I might do this?
here's a possible data file:
<world>
<level>
#########
#@@@@@@@#
#@@@@@@@#
#########
</level>
<tile symbol="#" src="wall.gif" collision="true"/>
<tile symbol="@" src="grass.gif" collision="false">
</world>
to the game engine, it converts all the #'s and creates views which have wall.gif as their source.
Does this make any sense?
Perhaps theres a simpler way to do this...
whisperstorm
10-15-2003, 01:14 PM
ah, looks like I should read the Tip of the Week (http://www.laszlosystems.com/developers/community/forums/showthread.php?s=&threadid=102) more often.
antun
10-15-2003, 01:27 PM
My first recommendation would be to use an XML data source, and to avoid instantiating large numbers of views in script. The instantiative style appeals to a lot of developers at first, but we don't recommend it as a strategy for Laszlo apps. Instead One approach is to use data replication:
<canvas width="400" height="400" debug="true">
<debug x="375" />
<attribute name="g_numCols" type="number" value="9" />
<attribute name="g_hspacing" type="number"
value="$once{math.round( (canvas.width-(canvas.g_numCols-1)*2)
/canvas.g_numCols )}" />
<attribute name="g_vspacing" type="number"
value="$once{math.round( (canvas.height-(canvas.g_numCols-1)*2)
/canvas.g_numCols )}" />
<dataset name="positionInfo">
<rows>
<row>
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
</row>
<row>
<item symbol="#" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="#" />
</row>
<row>
<item symbol="#" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="@" />
<item symbol="#" />
</row>
<row>
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
<item symbol="#" />
</row>
</rows>
</dataset>
<class name="block" width="$once{canvas.g_hspacing}"
height="$once{canvas.g_vspacing}" bgcolor="0xe5e5e5">
<text name="symbol" datapath="@symbol" width="20"
align="center" valign="middle" fontsize="16" />
</class>
<view name="map" datapath="positionInfo:/rows">
<simplelayout axis="y" spacing="2" />
<view name="smelly" datapath="row">
<simplelayout axis="x" spacing="2" />
<block datapath="item" />
</view>
</view>
</canvas>
The really neat thing about this would be that you could customize the game using different XML files (and indeed images loaded at runtime from different locations).
The next problem you're faced with would be how to determine if the user, navigating across your came, collided with an object. You could have a simple algorithm for working out the datapath to check based on global coordinates (relative from the canvas or the view named "map"). You'd use the getAttributeRelative() (http://www.laszlosystems.com/developers/learn/documentation/lzxref/view.php#meth-getAttributeRelative)method to do this. Then you could run the xpath in a <datapointer> and see what kind of square there is in that field.
Now, an alternative approach is to come up with a coordinates system and build that into the XML, e.g.
<item symbol="wall.jpg" row="1" col="2" />
... so you'd only need to enter the "full" tiles, rather than both the empty and full tiles of the game. Much neater. Then, you write a class that you replicate, except you overwrite it's applyDat() method, so that rather than going down in a straigh line, it positions itself somewhere in the field of view. See here on how to overwrite the applyData() method:
http://www.laszlosystems.com/developers/community/forums/showthread.php?s=&threadid=375&highlight=applydata
If you need help using this method, let me know; it's an interesting way of working with data replication.
-Antun
whisperstorm
10-15-2003, 02:06 PM
Ok. My brain is starting to hurt a bit but I think if I reread this a few times I'll get it. My next version will include dynamic maps, loading worlds, and world linking (events). See you in a few days :)
I am thinking this might make a neat blog/web widget - where you could travel from place to place and do interesting things like pop up windows, see screens, etc. Kinda like an RPG mixed with a weatherPixie (http://weatherpixie.com/) kinda thing. I'm going to continue exploring this idea of navigating a 'game space' via xml. First off, getting the viewer to work.
-Andrew
antun
10-15-2003, 02:38 PM
That would be really cool. The owner of the blog could embed it, and customize it with an XML file that's located on his/her server (allowing the app to be hosted on mylaszlo.com).
The images could also reside on the user's server.
I'll see if I can drum up an example of the applyData() method of doing things.
-Antun
Originally posted by whisperstorm
I am thinking this might make a neat blog/web widget - where you could travel from place to place and do interesting things like pop up windows, see screens, etc.
-Andrew [/B]
antun
10-15-2003, 04:23 PM
My apologies - forget about what I said about the applyData() method in my earlier post - this only works when the datapath resolves to an attribute or node text field - since we're pointing it to an XML node, then it won't work here. This is the second strategy I suggested. A bit more elegant in my opinion:
<canvas width="400" height="400" debug="true">
<debug x="375" />
<attribute name="g_blockwidth" type="number" value="30" />
<attribute name="g_blockheight" type="number" value="30" />
<dataset name="positionInfo">
<items>
<item row="1" col="2" symbol="#" />
<item row="1" col="3" symbol="#" />
<item row="1" col="4" symbol="#" />
<item row="1" col="5" symbol="#" />
<item row="1" col="6" symbol="#" />
<item row="1" col="7" symbol="#" />
<item row="2" col="7" symbol="#" />
<item row="3" col="1" symbol="#" />
<item row="3" col="2" symbol="#" />
<item row="3" col="3" symbol="#" />
<item row="3" col="4" symbol="#" />
<item row="3" col="5" symbol="#" />
<item row="3" col="7" symbol="#" />
<item row="4" col="2" symbol="#" />
<item row="4" col="3" symbol="#" />
<item row="4" col="4" symbol="#" />
<item row="4" col="5" symbol="#" />
<item row="4" col="7" symbol="#" />
<item row="5" col="2" symbol="#" />
<item row="5" col="7" symbol="#" />
<item row="6" col="2" symbol="#" />
<item row="6" col="4" symbol="#" />
<item row="6" col="4" symbol="#" />
<item row="6" col="5" symbol="#" />
<item row="6" col="6" symbol="#" />
<item row="6" col="7" symbol="#" />
<item row="7" col="2" symbol="#" />
<item row="7" col="4" symbol="#" />
</items>
</dataset>
<class name="block" width="$once{canvas.g_blockwidth}"
height="$once{canvas.g_blockheight}" bgcolor="0xe5e5e5">
<method event="ondata">
var attribs = this.datapath.getNodeAttributes();
this.setX( (attribs['col']-1) * canvas.g_blockwidth );
this.setY( (attribs['row']-1) * canvas.g_blockheight );
this.setAttribute('symbolText', attribs['symbol']);
</method>
<text name="symbol" width="20" text="${parent.symbolText}"
align="center" valign="middle" fontsize="16" />
</class>
<view name="map" datapath="positionInfo:/items">
<block datapath="item" />
</view>
</canvas>
All the magic happens in the ondata event method (colored red) above. The view's coordinates get set, and the text field gets set. You could also have an image get set here. This would have been the applyData() method, but like I said, since we need to do a couple of things to the view, it's more appropriate to use the ondata event method. Notice also that I'm not calling setText() on the text field - the reason is that the <text> field is not created at the time that the ondata event gets sent (since the creation of the <block> instance is triggered by the data arriving).
whisperstorm
10-17-2003, 12:08 AM
I tried using this method only substituting a view for the text, and trying to set the resource attribute.
<view resource="${parent.symbolImg}"/>
This results in an error something like this:
Error: tinyworld2.lzx:31:46: file not found: ${parent.symbolImg} ; compilation aborted
It doesnt seem to be wanting to do the "substitution". I know the path "resources/foo.png" exists because I can get the symbolImg variable if I use a text node to view it.
Is this a bug? It puts a real kink in my plans :(
antun
10-17-2003, 09:45 AM
Don't try to dynamically set the resource attribute of a view - this isn't a good way of loading images. Instead set the source:
this.symbolImage( 'resources/foo.png' );
You can use an absolute or relative URL above.
-Antun
whisperstorm
10-17-2003, 10:11 AM
Oh goodnes I had no idea there was a difference between resource and source - so resource is a background and source is a foreground ?
antun
10-17-2003, 11:55 AM
No, the difference is really that resource is an art asset (image), and source is something that gets loaded at runtime (such as an image or video). There are underlying differences in the implementation, and it gets even more confusing, because you can have a resource that is an image that does get loaded at runtime.
The main thing to remember is that for now, if you want to set an image at runtime, use setSource().
-Antun
whisperstorm
10-17-2003, 03:55 PM
working like a charm :) Thanks!
vBulletin® v3.8.4, Copyright ©2000-2012, Jelsoft Enterprises Ltd.